diff --git a/CHANGES b/CHANGES index d9ba0e1..e2f3ea9 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,11 @@ Nodeenv changelog Version [unreleased] -------------------- +- `activate.fish` no longer puts a literal `^/dev/null` on `PATH`: fish 3.1+ + defaults to `stderr-nocaret`, so the old caret redirect was one more path + entry; existing environments keep the old `activate.fish` until recreated + with `--force` + `#400 `_ - `activate.bat` and `Activate.ps1` now set `npm_config_prefix` to the environment and restore it on deactivate: `npx` exports the outer prefix, and `npm.cmd` runs the npm it finds there instead of its own diff --git a/nodeenv.py b/nodeenv.py index 7ee2a0b..bbcfcd0 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -2166,9 +2166,7 @@ def main(): end set -gx _OLD_NODE_VIRTUAL_PATH $PATH -# The node_modules/.bin path doesn't exists and it will print a warning, and -# that's why we redirect stderr to /dev/null :) -set -gx PATH "$NODE_VIRTUAL_ENV/lib/node_modules/.bin" "$NODE_VIRTUAL_ENV/__BIN_NAME__" $PATH ^/dev/null +set -gx PATH "$NODE_VIRTUAL_ENV/__MOD_NAME__/.bin" "$NODE_VIRTUAL_ENV/__BIN_NAME__" $PATH if set -q NODE_PATH set -gx _OLD_NODE_PATH $NODE_PATH diff --git a/tests/test_activate_shells.py b/tests/test_activate_shells.py index b8033ba..9e83447 100644 --- a/tests/test_activate_shells.py +++ b/tests/test_activate_shells.py @@ -126,11 +126,6 @@ 'and are equally unrestored; the test only reports NODE_PATH because ' 'it is asserted first') -FISH_CARET_REDIRECT = ( - 'the PATH line in activate.fish ends with `^/dev/null`, but fish 3.0 ' - 'turned on stderr-nocaret and `^` is no longer a stderr redirect, so ' - 'the token lands in PATH as a literal entry') - class Shell(object): def __init__(self, name, script='activate', source='.', prelude=()): @@ -183,8 +178,6 @@ def _params(xfail): every_shell = pytest.mark.parametrize('shell', _params({})) restoring_shell = pytest.mark.parametrize( 'shell', _params({'fish': FISH_NODE_PATH_CLOBBER})) -path_shell = pytest.mark.parametrize( - 'shell', _params({'fish': FISH_CARET_REDIRECT})) def _binary(shell): @@ -299,7 +292,7 @@ def test_syntax(shell, env): subprocess.check_call([_binary(shell), '-n', env.script(shell)]) -@path_shell +@every_shell def test_activate_sets_env(shell, env): dump = run(shell, env) baseline = run(shell, env, source=False) @@ -313,8 +306,7 @@ def test_activate_sets_env(shell, env): ] + [_real(p) for p in baseline['PATH'].split(os.pathsep)] # only the first component: activate.fish prepends when NODE_PATH is # set and, while FISH_NODE_PATH_CLOBBER stands, it never sees one, so - # fish replaces just like the POSIX script. FISH_CARET_REDIRECT keeps - # this test xfail under fish anyway, so the tolerance is for later + # fish replaces just like the POSIX script assert _real(dump['NODE_PATH'].split(os.pathsep)[0]) == \ _real(os.path.join(env.path, 'lib', 'node_modules')) assert _real(dump['NPM_CONFIG_PREFIX']) == _real(env.path) diff --git a/tests/test_install_activate.py b/tests/test_install_activate.py index 3f1efe4..8595941 100644 --- a/tests/test_install_activate.py +++ b/tests/test_install_activate.py @@ -65,6 +65,33 @@ def test_write(tmpdir, name, content_var): assert bin_dir.join(name).read() == fix_content(content, tmpdir) +@pytest.mark.skipif(nodeenv.is_WIN, reason='activate.fish is POSIX only') +def test_activate_fish_has_no_caret_redirect(tmpdir): + """Generated activate.fish must not contain caret stderr redirects. + + fish 3.1+ treats ^ as a normal character (stderr-nocaret default), so a + trailing ^/dev/null on the PATH set line would land in PATH as a literal + entry (#400). This check does not need fish installed. + """ + bin_dir = tmpdir.join('bin') + bin_dir.mkdir() + for n in FILES: + bin_dir.join(n).write(n) + + with mock.patch.object(sys, 'argv', ['nodeenv', str(tmpdir)]): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + content = bin_dir.join('activate.fish').read() + assert '^/dev/null' not in content + path_lines = [ln for ln in content.splitlines() + if ln.lstrip().startswith('set -gx PATH')] + assert path_lines, 'expected a set -gx PATH line in activate.fish' + assert all('2>/dev/null' not in ln and '^/dev/null' not in ln + for ln in path_lines) + assert '$NODE_VIRTUAL_ENV/lib/node_modules/.bin' in content + + @pytest.mark.parametrize('name, content_var', FILES.items()) def test_python_virtualenv(tmpdir, name, content_var): if nodeenv.is_WIN: