@@ -412,6 +412,114 @@ def test_isolate_npm_shim_content(tmpdir):
412412 assert content .index ('npm_config_cache' ) < content .index ('exec ' )
413413
414414
415+ # Windows also gets the posix `activate`, for git-bash and friends.
416+ # https://github.com/ekalinin/nodeenv/issues/226
417+ #
418+ # These run on every platform: is_WIN is faked so the Scripts/ layout can
419+ # be checked without a Windows host.
420+
421+
422+ @pytest .fixture
423+ def fake_win ():
424+ """
425+ Pretend the host is Windows. install_activate() links nodejs.exe with
426+ mklink there, which exists on Windows only, so callit() is stubbed too.
427+ """
428+ with mock .patch .object (nodeenv , 'is_WIN' , True ):
429+ with mock .patch .object (nodeenv , 'callit' ):
430+ yield
431+
432+
433+ def _install_win (tmpdir , * extra_args ):
434+ bin_dir = tmpdir .join ('Scripts' )
435+ if not bin_dir .check ():
436+ bin_dir .mkdir ()
437+
438+ argv = ['nodeenv' ] + list (extra_args ) + [str (tmpdir )]
439+ with mock .patch .object (sys , 'argv' , argv ):
440+ opts = nodeenv .parse_args ()
441+ nodeenv .install_activate (str (tmpdir ), opts )
442+ return bin_dir
443+
444+
445+ def test_win_writes_posix_activate (tmpdir , fake_win ):
446+ bin_dir = _install_win (tmpdir )
447+
448+ assert sorted (p .basename for p in bin_dir .listdir ()) == [
449+ 'Activate.ps1' , 'activate' , 'activate.bat' , 'deactivate.bat' ]
450+
451+
452+ def test_win_activate_puts_scripts_on_path (tmpdir , fake_win ):
453+ content = _install_win (tmpdir ).join ('activate' ).read ()
454+
455+ assert ('PATH="$NODE_VIRTUAL_ENV/Scripts/node_modules/.bin:'
456+ '$NODE_VIRTUAL_ENV/Scripts:$PATH"' ) in content
457+
458+
459+ def test_win_activate_points_node_at_scripts (tmpdir , fake_win ):
460+ # npm keeps the global modules next to node.exe on Windows, there is
461+ # no lib/node_modules there
462+ content = _install_win (tmpdir ).join ('activate' ).read ()
463+
464+ assert 'NODE_PATH="$NODE_VIRTUAL_ENV/Scripts/node_modules"' in content
465+ assert 'NPM_CONFIG_PREFIX="$NODE_VIRTUAL_ENV/Scripts"' in content
466+ assert 'npm_config_prefix="$NODE_VIRTUAL_ENV/Scripts"' in content
467+
468+
469+ def test_win_activate_has_no_placeholders_left (tmpdir , fake_win ):
470+ content = _install_win (tmpdir ).join ('activate' ).read ()
471+
472+ for placeholder in ('__NODE_VIRTUAL_PROMPT__' , '__NODE_VIRTUAL_ENV__' ,
473+ '__SHIM_NODE__' , '__BIN_NAME__' , '__MOD_NAME__' ,
474+ '__NPM_ISOLATE__' , '__NPM_UNISOLATE__' ,
475+ '__NPM_CONFIG_PREFIX__' ):
476+ assert placeholder not in content
477+
478+
479+ def test_win_activate_converts_paths_for_node_exe (tmpdir , fake_win ):
480+ # node.exe is a native binary: it cannot read the /c/... paths a
481+ # Windows shell hands out, so the script converts them back
482+ content = _install_win (tmpdir ).join ('activate' ).read ()
483+
484+ assert 'CYGWIN*|MSYS*|MINGW*)' in content
485+ assert 'NODE_PATH="$(cygpath -w "$NODE_PATH")"' in content
486+ assert 'NPM_CONFIG_PREFIX="$(cygpath -w "$NPM_CONFIG_PREFIX")"' in content
487+ # the conversion must come after the variables are built
488+ assert content .index ('NODE_PATH="$NODE_VIRTUAL_ENV' ) < \
489+ content .index ('cygpath -w' )
490+
491+
492+ def test_win_activate_is_valid_sh (tmpdir , fake_win ):
493+ activate = _install_win (tmpdir ).join ('activate' )
494+
495+ subprocess .check_call (['sh' , '-n' , str (activate )])
496+
497+
498+ def test_win_activate_refuses_to_be_run_directly (tmpdir , fake_win ):
499+ activate = str (_install_win (tmpdir ).join ('activate' ))
500+
501+ proc = subprocess .Popen (
502+ ['sh' , activate ], stdout = subprocess .PIPE , stderr = subprocess .STDOUT )
503+ out , _ = proc .communicate ()
504+
505+ assert proc .returncode == 1
506+ assert b'Do not call' in out
507+
508+
509+ def test_win_python_virtualenv_appends_to_activate (tmpdir , fake_win ):
510+ # nodeenv -p inside a python venv: venv wrote Scripts/activate for
511+ # git-bash already, nodeenv has to extend it, not replace it
512+ bin_dir = tmpdir .join ('Scripts' )
513+ bin_dir .mkdir ()
514+ bin_dir .join ('activate' ).write ('# python venv activate\n ' )
515+
516+ _install_win (tmpdir , '-p' )
517+
518+ content = bin_dir .join ('activate' ).read ()
519+ assert content .startswith ('# python venv activate\n ' )
520+ assert 'NODE_VIRTUAL_ENV_DISABLE_PROMPT=1' in content
521+
522+
415523@pytest .mark .skipif (nodeenv .is_WIN , reason = 'system node is POSIX only' )
416524def test_isolate_npm_node_system_shim_exports (tmpdir ):
417525 bin_dir = tmpdir .join ('bin' )
0 commit comments