diff options
author | Brian Skinn <brian.skinn@gmail.com> | 2019-04-10 09:38:28 -0400 |
---|---|---|
committer | Bernát Gábor <gaborjbernat@gmail.com> | 2019-04-10 09:38:28 -0400 |
commit | c787671ec455e3212fd78126cea558b318f48806 (patch) | |
tree | ef62de3e986e33b8c79738640e8ed56aa4202def | |
parent | 124d0eda3f376e0a34544f0dc07f7b557eb69e34 (diff) | |
download | virtualenv-c787671ec455e3212fd78126cea558b318f48806.tar.gz |
Implement prompt consistency tests and harmonize all activate scripts (#1330)
See history of [bskinn/virtualenv:all-prompts branch](https://github.com/bskinn/virtualenv/commits/all-prompts), tip at
bskinn/virtualenv@67cda5f, for the actual sequence of
development of the prompt tests, leading to the first commit of the PR (e6a2b99)
-rw-r--r-- | CONTRIBUTING.rst | 9 | ||||
-rw-r--r-- | docs/changelog/1330.bugfix.rst | 2 | ||||
-rw-r--r-- | docs/development.rst | 7 | ||||
-rw-r--r-- | docs/reference.rst | 6 | ||||
-rw-r--r-- | tests/activation/test_prompts.py | 440 | ||||
-rwxr-xr-x | virtualenv.py | 74 | ||||
-rw-r--r-- | virtualenv_embedded/activate.bat | 9 | ||||
-rw-r--r-- | virtualenv_embedded/activate.csh | 31 | ||||
-rw-r--r-- | virtualenv_embedded/activate.ps1 | 22 | ||||
-rw-r--r-- | virtualenv_embedded/activate.xsh | 7 |
10 files changed, 550 insertions, 57 deletions
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 29c52c2..cd53c35 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -13,8 +13,13 @@ Contributor notes * Pull requests should be made against ``master`` branch, which is also our latest stable version. -* All changes to files inside virtualenv_embedded should be integrated to - ``virtualenv.py`` with ``tox -e embed`` +* All changes to files inside virtualenv_embedded must be integrated to + ``virtualenv.py`` with ``tox -e embed``. The tox run will report failure + when changes are integrated, as a flag for CI. + +* The codebase must be linted with ``tox -e fix_lint`` before being merged. + The tox run will report failure when the linters revise code, as a flag + for CI. .. _git-flow: https://github.com/nvie/gitflow .. _coordinate development: http://nvie.com/posts/a-successful-git-branching-model/ diff --git a/docs/changelog/1330.bugfix.rst b/docs/changelog/1330.bugfix.rst new file mode 100644 index 0000000..0d7072b --- /dev/null +++ b/docs/changelog/1330.bugfix.rst @@ -0,0 +1,2 @@ +Add tests covering prompt manipulation during activation/deactivation, +and harmonize behavior of all supported shells - by ``bskinn`` diff --git a/docs/development.rst b/docs/development.rst index 6eee7d3..a7d72d1 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -17,7 +17,12 @@ Files in the ``virtualenv_embedded/`` subdirectory are embedded into single-file use of ``virtualenv.py`` without installing it). If your patch changes any file in ``virtualenv_embedded/``, run ``tox -e embed`` to update the embedded version of that file in ``virtualenv.py``; commit that and submit -it as part of your patch / pull request. +it as part of your patch / pull request. The tox run will report failure +when changes are embedded, as a flag for CI. + +The codebase should be linted before a pull request is merged by running +``tox -e fix_lint``. The tox run will report failure when any linting +revisions are required, as a flag for CI. .. _pip development: https://pip.pypa.io/en/latest/development/ .. _virtualenv repo: https://github.com/pypa/virtualenv/ diff --git a/docs/reference.rst b/docs/reference.rst index e623a91..deec504 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -148,8 +148,10 @@ is the same as calling:: .. envvar:: VIRTUAL_ENV_DISABLE_PROMPT - Any virtualenv created when this is set to a non-empty value will not have - it's :ref:`activate` modify the shell prompt. + Any virtualenv *activated* when this is set to a non-empty value will leave + the shell prompt unchanged during processing of the + :ref:`activate script <activate>`, rather than modifying it to indicate + the newly activated environment. Configuration File diff --git a/tests/activation/test_prompts.py b/tests/activation/test_prompts.py new file mode 100644 index 0000000..8db4662 --- /dev/null +++ b/tests/activation/test_prompts.py @@ -0,0 +1,440 @@ +"""test that prompt behavior is correct in supported shells""" +from __future__ import absolute_import, unicode_literals + +import os +import subprocess +import sys +from textwrap import dedent + +import pytest + +import virtualenv +from virtualenv import IS_DARWIN, IS_WIN + +try: + from pathlib import Path +except ImportError: + from pathlib2 import Path + +VIRTUAL_ENV_DISABLE_PROMPT = "VIRTUAL_ENV_DISABLE_PROMPT" + +# This must match the DEST_DIR provided in the ../conftest.py:clean_python fixture +ENV_DEFAULT = "env" + +# This can be anything +ENV_CUSTOM = "env_custom" + +# Standard prefix, surround the env name in parentheses and separate by a space +PREFIX_DEFAULT = "({}) ".format(ENV_DEFAULT) + +# Arbitrary prefix for the environment that's provided a 'prompt' arg +PREFIX_CUSTOM = "---ENV---" + +# Temp script filename template: {shell}.script.(normal|suppress).(default|custom)[extension] +SCRIPT_TEMPLATE = "{}.script.{}.{}{}" + +# Temp output filename template: {shell}.out.(normal|suppress).(default|custom) +OUTPUT_TEMPLATE = "{}.out.{}.{}" + +# For skipping shells not installed by default if absent on a contributor's system +IS_INSIDE_CI = "CI_RUN" in os.environ + + +# Py2 doesn't like unicode in the environment +def env_compat(string): + return string.encode("utf-8") if sys.version_info.major < 3 else string + + +class ShellInfo(object): + """Parent class for shell information for prompt testing.""" + + # Typo insurance + __slots__ = [] + + # Equality check based on .name, but only if both are not None + def __eq__(self, other): + if type(self) != type(other): + return False + if self.name is None or other.name is None: + return False + return self.name == other.name + + # Helper formatting string + @property + def platform_incompat_msg(self): + return "No sane provision for {} on {{}} yet".format(self.name) + + # Each shell must specify + name = None + avail_cmd = None + execute_cmd = None + prompt_cmd = None + activate_script = None + + # Default values defined here + # 'preamble_cmd' *MUST NOT* emit anything to stdout! + testscript_extension = "" + preamble_cmd = "" + activate_cmd = "source " + deactivate_cmd = "deactivate" + clean_env_update = {} + + # Skip check function; must be specified per-shell + platform_check_skip = None + + # Test assert method for comparing activated prompt to deactivated. + # Default defined, but can be overridden per-shell. Takes the captured + # lines of output as the lone argument. + def overall_prompt_test(self, lines, prefix): + """Perform all tests on (de)activated prompts. + + From a Python 3 perspective, 'lines' is expected to be *bytes*, + and 'prefix' is expected to be *str*. + + Happily, this all seems to translate smoothly enough to 2.7. + + """ + # Prompts before activation and after deactivation should be identical. + assert lines[1] == lines[3], lines + + # The .partition here operates on the environment marker text expected to occur + # in the prompt. A non-empty 'env_marker' thus tests that the correct marker text + # has been applied into the prompt string. + before, env_marker, after = lines[2].partition(prefix.encode("utf-8")) + assert env_marker != b"", lines + + # Some shells need custom activated-prompt tests, so this is split into + # its own submethod. + self.activated_prompt_test(lines, after) + + def activated_prompt_test(self, lines, after): + """Perform just the check for the deactivated prompt contents in the activated prompt text. + + The default is a strict requirement that the portion of the activated prompt following the environment + marker must exactly match the non-activated prompt. + + Some shells require weaker tests, due to idiosyncrasies. + + """ + assert after == lines[1], lines + + +class BashInfo(ShellInfo): + name = "bash" + avail_cmd = "bash -c 'echo foo'" + execute_cmd = "bash" + prompt_cmd = 'echo "$PS1"' + activate_script = "activate" + + def platform_check_skip(self): + if IS_WIN: + return self.platform_incompat_msg.format(sys.platform) + + +class FishInfo(ShellInfo): + name = "fish" + avail_cmd = "fish -c 'echo foo'" + execute_cmd = "fish" + prompt_cmd = "fish_prompt; echo ' '" + activate_script = "activate.fish" + + # Azure Devops doesn't set a terminal type, which breaks fish's colorization + # machinery in a way that spuriously fouls the activation script. + clean_env_update = {"TERM": "linux"} + + def platform_check_skip(self): + if IS_WIN: + return self.platform_incompat_msg.format(sys.platform) + + def activated_prompt_test(self, lines, after): + """Require a looser match here, due to interposed ANSI color codes. + + This construction allows coping with the messiness of fish's ANSI codes for colorizing. + It's not as rigorous as I would like---it doesn't ensure no space is inserted between + a custom env prompt (argument to --prompt) and the base prompt---but it does provide assurance as + to the key pieces of content that should be present. + + """ + assert lines[1] in after, lines + + +class CshInfo(ShellInfo): + name = "csh" + avail_cmd = "csh -c 'echo foo'" + execute_cmd = "csh" + prompt_cmd = r"set | grep -E 'prompt\s' | sed -E 's/^prompt\s+(.*)$/\1/'" + activate_script = "activate.csh" + + # csh defaults to an unset 'prompt' in non-interactive shells + preamble_cmd = "set prompt=%" + + def platform_check_skip(self): + if IS_WIN: + return self.platform_incompat_msg.format(sys.platform) + + def activated_prompt_test(self, lines, after): + """Test with special handling on MacOS, which does funny things to stdout under (t)csh.""" + if IS_DARWIN: + # Looser assert for (t)csh on MacOS, which prepends extra text to + # what gets sent to stdout + assert lines[1].endswith(after), lines + else: + # Otherwise, use the rigorous default + # Full 2-arg form for super() used for 2.7 compat + super(CshInfo, self).activated_prompt_test(lines, after) + + +class XonshInfo(ShellInfo): + name = "xonsh" + avail_cmd = "xonsh -c 'echo foo'" + execute_cmd = "xonsh" + prompt_cmd = "print(__xonsh__.shell.prompt)" + activate_script = "activate.xsh" + + # Sets consistent initial state + preamble_cmd = ( + "$VIRTUAL_ENV = ''; $PROMPT = '{env_name}$ '; " + "$PROMPT_FIELDS['env_prefix'] = '('; $PROMPT_FIELDS['env_postfix'] = ') '" + ) + + def platform_check_skip(self): + if IS_WIN: + return "Provisioning xonsh on windows is unreliable" + + if sys.version_info < (3, 4): + return "xonsh requires Python 3.4 at least" + + +class CmdInfo(ShellInfo): + name = "cmd" + avail_cmd = "echo foo" + execute_cmd = "" + prompt_cmd = "echo %PROMPT%" + activate_script = "activate.bat" + + testscript_extension = ".bat" + preamble_cmd = "@echo off & set PROMPT=$P$G" # For consistent initial state + activate_cmd = "call " + deactivate_cmd = "call deactivate" + + def platform_check_skip(self): + if not IS_WIN: + return self.platform_incompat_msg.format(sys.platform) + + +class PoshInfo(ShellInfo): + name = "posh" + avail_cmd = "powershell 'echo foo'" + execute_cmd = "powershell -File " + prompt_cmd = "prompt" + activate_script = "activate.ps1" + + testscript_extension = ".ps1" + activate_cmd = ". " + + def platform_check_skip(self): + if not IS_WIN: + return self.platform_incompat_msg.format(sys.platform) + + +SHELLINFO_LIST = [BashInfo(), FishInfo(), CshInfo(), XonshInfo(), CmdInfo(), PoshInfo()] + + +@pytest.fixture(scope="module") +def posh_execute_enabled(tmp_path_factory): + """Return check value for whether Powershell script execution is enabled. + + Posh may be available interactively, but the security settings may not allow + execution of script files. + + # Enable with: PS> Set-ExecutionPolicy -scope currentuser -ExecutionPolicy Bypass -Force; + # Disable with: PS> Set-ExecutionPolicy -scope currentuser -ExecutionPolicy Restricted -Force; + + """ + if not IS_WIN: + return False + + test_ps1 = tmp_path_factory.mktemp("posh_test") / "test.ps1" + with open(str(test_ps1), "w") as f: + f.write("echo 'foo bar baz'\n") + + out = subprocess.check_output(["powershell", "-File", "{}".format(str(test_ps1))], shell=True) + return b"foo bar baz" in out + + +@pytest.fixture(scope="module") +def shell_avail(posh_execute_enabled): + """Generate mapping of ShellInfo.name strings to bools of shell availability.""" + retvals = {si.name: subprocess.call(si.avail_cmd, shell=True) for si in SHELLINFO_LIST} + avails = {si.name: retvals[si.name] == 0 for si in SHELLINFO_LIST} + + # Extra check for whether powershell scripts are enabled + avails[PoshInfo().name] = avails[PoshInfo().name] and posh_execute_enabled + + return avails + + +@pytest.fixture(scope="module") +def custom_prompt_root(tmp_path_factory): + """Provide Path to root with default and custom venvs created.""" + root = tmp_path_factory.mktemp("custom_prompt") + virtualenv.create_environment( + str(root / ENV_CUSTOM), prompt=PREFIX_CUSTOM, no_setuptools=True, no_pip=True, no_wheel=True + ) + + _, _, _, bin_dir = virtualenv.path_locations(str(root / ENV_DEFAULT)) + + bin_dir_name = os.path.split(bin_dir)[-1] + + return root, bin_dir_name + + +@pytest.fixture(scope="module") +def clean_python_root(clean_python): + root = Path(clean_python[0]).resolve().parent + bin_dir_name = os.path.split(clean_python[1])[-1] + + return root, bin_dir_name + + +@pytest.fixture(scope="module") +def get_work_root(clean_python_root, custom_prompt_root): + def pick_root(env): + if env == ENV_DEFAULT: + return clean_python_root + elif env == ENV_CUSTOM: + return custom_prompt_root + else: + raise ValueError("Invalid test virtualenv") + + return pick_root + + +@pytest.fixture(scope="function") +def clean_env(): + """Provide a fresh copy of the shell environment. + + VIRTUAL_ENV_DISABLE_PROMPT is always removed, if present, because + the prompt tests assume it to be unset. + + """ + clean_env = os.environ.copy() + clean_env.pop(env_compat(VIRTUAL_ENV_DISABLE_PROMPT), None) + return clean_env + + +SHELLINFO_LIST = [BashInfo(), FishInfo(), CshInfo(), XonshInfo(), CmdInfo(), PoshInfo()] + + +@pytest.mark.parametrize("shell_info", SHELLINFO_LIST, ids=(lambda si: si.name)) +@pytest.mark.parametrize("env", [ENV_DEFAULT, ENV_CUSTOM]) +@pytest.mark.parametrize(("value", "disable"), [("", False), ("0", True), ("1", True)]) +def test_suppressed_prompt(shell_info, shell_avail, env, value, disable, get_work_root, clean_env): + """Confirm non-empty VIRTUAL_ENV_DISABLE_PROMPT suppresses prompt changes on activate.""" + skip_test = shell_info.platform_check_skip() + if skip_test: + pytest.skip(skip_test) + + if not IS_INSIDE_CI and not shell_avail[shell_info.name]: + pytest.skip( + "Shell '{}' not provisioned".format(shell_info.name) + + (" - is Powershell script execution disabled?" if shell_info == PoshInfo() else "") + ) + + script_name = SCRIPT_TEMPLATE.format(shell_info.name, "suppress", env, shell_info.testscript_extension) + output_name = OUTPUT_TEMPLATE.format(shell_info.name, "suppress", env) + + clean_env.update({env_compat(VIRTUAL_ENV_DISABLE_PROMPT): env_compat(value)}) + + work_root = get_work_root(env) + + # The extra "{prompt}" here copes with some oddity of xonsh in certain emulated terminal + # contexts: xonsh can dump stuff into the first line of the recorded script output, + # so we have to include a dummy line of output that can get munged w/o consequence. + with open(str(work_root[0] / script_name), "w") as f: + f.write( + dedent( + """\ + {preamble} + {prompt} + {prompt} + {act_cmd}{env}/{bindir}/{act_script} + {prompt} + """.format( + env=env, + act_cmd=shell_info.activate_cmd, + preamble=shell_info.preamble_cmd, + prompt=shell_info.prompt_cmd, + act_script=shell_info.activate_script, + bindir=work_root[1], + ) + ) + ) + + command = "{} {} > {}".format(shell_info.execute_cmd, script_name, output_name) + + assert 0 == subprocess.call(command, cwd=str(work_root[0]), shell=True, env=clean_env) + + with open(str(work_root[0] / output_name), "rb") as f: + lines = f.read().split(b"\n") + + # Is the prompt suppressed based on the env var value? + assert (lines[1] == lines[2]) == disable, lines + + +@pytest.mark.parametrize("shell_info", SHELLINFO_LIST, ids=(lambda si: si.name)) +@pytest.mark.parametrize(["env", "prefix"], [(ENV_DEFAULT, PREFIX_DEFAULT), (ENV_CUSTOM, PREFIX_CUSTOM)]) +def test_activated_prompt(shell_info, shell_avail, env, prefix, get_work_root, clean_env): + """Confirm prompt modification behavior with and without --prompt specified.""" + skip_test = shell_info.platform_check_skip() + if skip_test: + pytest.skip(skip_test) + + if not IS_INSIDE_CI and not shell_avail[shell_info.name]: + pytest.skip( + "Shell '{}' not provisioned".format(shell_info.name) + + (" - is Powershell script execution disabled?" if shell_info == PoshInfo() else "") + ) + + for k, v in shell_info.clean_env_update.items(): + clean_env.update({env_compat(k): env_compat(v)}) + + script_name = SCRIPT_TEMPLATE.format(shell_info.name, "normal", env, shell_info.testscript_extension) + output_name = OUTPUT_TEMPLATE.format(shell_info.name, "normal", env) + + work_root = get_work_root(env) + + # The extra "{prompt}" here copes with some oddity of xonsh in certain emulated terminal + # contexts: xonsh can dump stuff into the first line of the recorded script output, + # so we have to include a dummy line of output that can get munged w/o consequence. + with open(str(work_root[0] / script_name), "w") as f: + f.write( + dedent( + """\ + {preamble} + {prompt} + {prompt} + {act_cmd}{env}/{bindir}/{act_script} + {prompt} + {deactivate} + {prompt} + """.format( + env=env, + act_cmd=shell_info.activate_cmd, + deactivate=shell_info.deactivate_cmd, + preamble=shell_info.preamble_cmd, + prompt=shell_info.prompt_cmd, + act_script=shell_info.activate_script, + bindir=work_root[1], + ) + ) + ) + + command = "{} {} > {}".format(shell_info.execute_cmd, script_name, output_name) + + assert 0 == subprocess.call(command, cwd=str(work_root[0]), shell=True, env=clean_env) + + with open(str(work_root[0] / output_name), "rb") as f: + lines = f.read().split(b"\n") + + shell_info.overall_prompt_test(lines, prefix) diff --git a/virtualenv.py b/virtualenv.py index 061e0d5..8184e86 100755 --- a/virtualenv.py +++ b/virtualenv.py @@ -1698,7 +1698,7 @@ def install_files(home_dir, bin_dir, prompt, files): virtualenv_name = os.path.basename(home_dir) for name, content in files.items(): content = content.replace("__VIRTUAL_PROMPT__", prompt or "") - content = content.replace("__VIRTUAL_WINPROMPT__", prompt or "({})".format(virtualenv_name)) + content = content.replace("__VIRTUAL_WINPROMPT__", prompt or "({}) ".format(virtualenv_name)) content = content.replace("__VIRTUAL_ENV__", home_dir) content = content.replace("__VIRTUAL_NAME__", virtualenv_name) content = content.replace("__BIN_NAME__", os.path.basename(bin_dir)) @@ -2282,42 +2282,43 @@ a6FOZy1jZzukdvvqN1kPccDLjbwGdtJ8m72rgeki+xOnXcf/CzFcuJM= # file activate.csh ACTIVATE_CSH = convert( """ -eJx9k9tq20AQhu/3Kf7IJm5N4vRarts6caCBxAnBCZSmLCtpXC1IK2e1svFNn72zklzkA9WFkOb0 -z34708Mi1SWWOiPkVekQEaqSEmy0SxGURWVjQqTNlYqdXitHo7hMAwyXtsjBn8OR6OFHUSFWxhQO -tjLQDom2FLts6703ljgvQbTFTK11QphpXGeq1Pic1IYk+vY7VzobxUX+ZSRESQ6GNpk2NBm8iYEQ -KtOqREK7LjBwxN32v8rH+5l8vXtevEzv5dN08R1nE3zC+Tm4CJk1alvQP4oL3wMfVRkvduQdw1Kq -ynSMkzrPjw9Pi64SVsxj5SaHQnXgf6Rq/7hx+W53jtv5aysdvJ2Fw8BrBaYwCZts5SFQW/OITMe6 -2iZFzPR6eKm1tbWU0VoZh7WyWkUZlSPRyd1XqC/ioCsEUnZ+pQya6zoiyChazGL/JjrZ4fuVlNd3 -czmfPtxKGf7L4Ecv8aGj1ZBiuZpE8BEuJSPAj1fn8tKonDDBqRxBWUkng/e6cV6aTKKXHtlNUWWJ -3wdtoDyZS20c2ZoV+SLaFiYn4y44mGM2qY5TXoOSLtBvxgG8WhUTXfIgJ1CG14qw8XXNwHFWrCxB -RUXl/HHaGeK47Ubx5ngCPHmt9eDEJ8aIiTex/hh1cseAyR8Mg367VWwYdiuG+4RaSebzs7+jFb7/ -Qqd+g6mF1Uz2LnK3rfX08dulhcFl3vwL0SyW+At+C2qe +eJx9VNtO4zAQffdXDKEiUEFhX8t22bJFWqRyEVuQVkKy3Hi6sZQ44Dit+sK379hJittG5KGqPZdz +fOZyCLNUlbBQGUJelRbmCFWJElbKphCVRWUShLnS5yKxaiksDpIyjaC/MEUO9Lc/YIfwt6ggEVoX +FkylQVmQymBis7Wz/jJIcRLma5iIpZIIEwXXmSgVfJf+Qs5//suFygZJkf8YMFaiBY2rTGkcxa8s +ZkxkSpQgsWUBsUVi27viD9MJf7l9mj2Pp/xxPPsNByO4gKMjoCSol+Dvot6e3/A9cl6VdmB71ksw +mIoyvYROnKeHu8dZiARvpMebHe0CeccvoLz9sjY5tq3h5v6lgY5eD4b9yGFFutCSrkzlRMAm554y +we3bWhYJqXcIzx5bGYMZLoW2sBRGiXmG5YAFsdsIvhA7rCDiPDhyHtXl2lOQpGhkZtuVCKKH7+ec +X9/e8/vx3Q3nw00EfWoBxwFWrRTBeSWiE7Apagb0OXRKz7XIEUbQFcMwK7HLOT6OtwlZQo9PIGao +pVrULKj64Ysnt3/G19ObtgkCJrXzF74jRz2MaCnJgtcN5B7wLfK2DedOp4vGydPcet5urq2XBEZv +DcnQpBZVJt0KUBqEa4YzpS0a3x7odFOm0Dlqe9oEkN8qVUlK01/iKfSa3LRRKmqkBc2vBKFpmyCs +XG4d2yYyEQZBzIvKOgLN+JDveiVoaXyqedVYOkTrmCRqutrfNVHr6xMFBhh9QD/qNQuGLvq72d03 +3Jy2CtGCf0rca/tp+N4BXqsflKquRr0L2sjmuClOu+/8/NKvTQsNZ3l9ZqxeTew//1a6EA== """ ) # file activate.xsh ACTIVATE_XSH = convert( """ -eJyFU11rwjAUfc+vuIt9sMz1Bwg+OCYoaB2bkw2RkNlbLdSkJLFsjP33JdV+aN2Wh5L7eW7PuaGU -vkqhd8A3Jsm5QdAblWQGYqkgT5Q58BRFTiklsZJ7+HDJgZEy1ZDsM6kMbNEwjRlwDex0JyTCGFiE -ZdcuV1vt9wnYk8RAs89IbigkAniacI36GHInwrR0rk55a1IWel9BEHwHFqZL2Xz6wJaTp8XLcMoe -h4sx7QGlft3Jc04YgNfKPAO7Ev4f7m0xnofj+WzUBq1Cbegq9NcAdVJFVxkbhcuCtONc55x5jaS6 -UkgRoTbq4IRACkKagnUrR13egWdMYygTb65rUavpBCEdOAiNtptSmGLOhYGcq4S/p6hJU/rV5RBr -n1xtavlq1BHS/CMbU5SxhocxalNa2jnSCw29prXqr4+OgEdR96zxbbW1Xd8aFuR+ErJwOBtZhB7Y -rRdmsFAH7IHCLOUbLCyfkIsFub4TJU2NtbB11lNEf5O+mPt8WwqNm8tx+UhsjbubnRRugLu9+5YP -6AcvDiI9 +eJyNU11PwjAUfe+vuNY9sIj7ASQ+YCSBRD6i02gIaSq7gyWjXdqyaIz/3XYwVmB+9GFZ78c57T2n +lNIXKfQa+NJkJTcIeqmywkAqFZSZMlueoygppSRVcgPvrjgyUuYask0hlYEVGqaxAK6B7f8JSTAF +lmCN2uFqpcMeAbuyFGjxkcglhUwAzzOuUe9SbiWY18H5vm5B6sbgM4qir8jSdCib3t+x59FD/NS/ +Z7N+PKRdoDRskAIXhBsIziqPyFrSf9O9xsPpZDgdD85JD6lz6kPqtwM0RYdx1bnB5Lka2u5cxzML +vKLWTjZ7mI5n8b8A9rUNjpAiQW3U1gmKFIQ0lXpW1gblEh4xT6EuvGjXtHGFE5ZcwlZotGhKYY4l +FwZKrjL+lqMmvoXmp4dYhKQV1M7d6yPEv5jNKcqYf1VGbcmZB5x4lRcCfzfvLXaBiCdJ5wj46uD+ +Tmg3luR2NGGT/nhgGbpgX48wN7HaYhcUFjlfYrULCTkxWru36jF59rJ9NlJlf7JQde5j11VS+yZr +0d22eUPaxdycLKMTvqWjR3610emDtgTu36ylcJe83rhv/di/AYN1UZY= """ ) # file activate.bat ACTIVATE_BAT = convert( """ -eJx9Ul9LhEAQfxf8DoOclI/dYyFkaCmcq4gZQTBUrincuZFbff12T133TM+nnd35/Zvxlr7XDFhV -mUZHOVhFlOWP3g4DUriIWoVomYZpNBWUtGpaWgImO191pFkSpzlcmgaI70jVX7n2Qp8tuByg+46O -CMHbMq64T+nmlJt082D1T44muCDk2prgEHF4mdI9RaS/QwSt3zSyIAaftRccvqVTBziD1x/WlPD5 -xd729NDBb8Nr4DU9QNMKsJeH9pkhPedhQsIkDuCDCa6A+NF9IevVFAohkqizdHetg/tkWvPoftWJ -MCqnOxv7/x7Np6yv9P2Ker5dmX8yNyCkkWnbZy3N5LarczlqL8htx2EM9rQ/2H5BvIsIEi8OEG8U -+g8CsNTr +eJyVk1FLhEAUhd8X/A8XWSkf28dCyMUpBR3FzAiCS+WYwq4TOdXfb0Z3dTJdyCfveO85n8frNXut +OPCyNFbGqmUCzDxIs3s3REJzB1GrEE3VVJdQsLJuWAEYh97QkaRxlGRwbqxAXp1Uf+RYM32W1LKB +7Vp2nJC6DReD9m+5qeQ6Wd+a/SN7dlzn9oI7dxsSXJCcoXOskfLgYXdv/j8LnXiM8iGg/RmiZmOr +bFMSgcebMwGfKhgbBIfnL14X8P7BX3Zs38J3LSoQFdtD3YCVuJlvnfgmj5kfUz+OCLxxqUWoF9zk +qtYAFyZkBsO9ArzUh/td0ZqP9IskElTFMsnwb4/GqeoLPUlZT5dJvf8Id5hQIONynUSa2G0Wc+m8 +Z+w2w4/Tt2hbYT0hbgOK1I0I4tUw/QOTZfLE """ ) @@ -2334,17 +2335,18 @@ pk+k4fAba/wd0Pr4P2CqyLeOlJ4iKfkJo6v/iaH9YzfPMEoeMG2RUA== # file activate.ps1 ACTIVATE_PS = convert( """ -eJyNVMtu2zAQvOsrNrLQ2miloFcXPdiwgRhwHCN2c2kLgqZWMQGKFEhKqVHky3LoJ/UXSlqWX3LS -8ibtzHJ2d5Z/Xn53YLnmBjIuEPLSWFghpMqCUaVmmEKmVQ5ztVh/ho0qgVEpXVSXEriFlGtkVmwS -GCmwLk8fEkiuKbO8ohaTwnwKgsgwzQvbX95MFmQ+WN7AF4jyDZeVYtRyJZN8w1SeU5kmBbXrPWE4 -WIzJaHLv8KYQ3MY+Cl2NRokK668w2qe9TpKwB/GcapQ2CLJSMp8dHoVaUdFPsZHV/WaeuGXrHxDN -lByhsbr0IewFvwJwh2fQte53fUVFNacrgX1yNx2Rh8n98utgur2xt0XXHH8ilFW/qfB12h6vMVeu -kAYJYQsaQmyYKnBXxJb5HFwQ2VTbJ0qkpOLallSQwg2vsC2Ze3Ad92rf4p/r5Rbzw4XfX2Mc6dw2 -pqlrPHtoKfIpHOZ00ucsiAXS7KKaFhK1VprWBjDO29K5lClpuSzxXN1Vywan6jqwQJFBukNcvd2P -g8/exhWbVLGdlOe2XetwLaLY2LWLxDls/0JE9aPxpA6U0qAFrjUKrKi0e7ea4CAEYqlkeijQ7eRx -s9z4m1ULWj13waNPx9zpa1nVIxv/B8ebEJ7nvCZkOJmR2eB2TNzxMLIYzwkJ4cNRjno0Z1wncjEY -Tsdkfn93O182G3vevdc8eRhqGO56f7oRF4gn63GUqzWxS9d0YJCmQKHQmPGfYP0zicBK7R8pqCkf -YVW6t1TJ9/5FNYzq1D2uyT7Hk3bOidfKPc5hN+r+e0Wg14NwO3R8ElwejPjuPxbdu/EvkRDrCw== +eJytVcFu2zAMvfsrWNfYEmx2sWuGHVIkQAO0adBkvWyDoMh0I0CWDElOGwz598p2HDt20w3YdLP5 +SD2Sj9QlrDbcQMIFQpobC2uEWFkwKtcMY0i0SmGhlpuvsFM5MCqls+pcArcQc43Mil0EEwXWxRlB +BNEVZZZvqcUoM188LzBM88yOVjezJVmMVzfwDYJ0x+VWMWq5klG6YypNqYyjjNrN0eF6vJySyezB +4U0muA0LKww0GiW2WH35wTHsVRT5QwgXVKO0npfkkhXR4UmoNRWjGGtagx/mmVu2+QXBXMkJGqvz +woRD77cH7vAEBtb9rq7YUs3pWuCI3N9OyOPsYfV9fFveOCzRlU9xApTbUZ3hebcjXmOqXCI1Evwe +1IfQMJXhIYnSc++9QbLOdkSUiMmWa5tTQTLXvMz2aB7Blb1g+55/ly+3mDYX/jzn0eJZFqbOazp/ +7DEqQjjMaae7XhAKpMmbbHpI1FppWgnAOG1Lp1KmpOUyxy67i54MTtldwhJFAvEBcfF+PRqdvY/L +drFiByr7vlwrc0Ui29mNs4QplH8hoPrJFE6XkEuDFrjWKHBLpT2q1XgNEQilknGToJvJdrFc++tR +83o1d8bWp/M88OtJtUDW+vfak+B3Y14Rcj2bk/n4bkrcKWBkOV0Q4sOnVoyqNR1fR3I5vr6dksXD +/d1iVU9st3rnNNk01fcPtT+diDccT8ajFavg55OmBiWhIolQulH2uyrqNfh0thpgJblxHLuNisDc +TnYbONOY8BewqvyJL9w4KT9BJ0hxnrXTWbhRbpWfYackPgsu8cTtw1/ugH2rbCgM/nuWtJMcy3Wx +wQ+5fYZ17h4aJT8Wz41hVMfu5YnOpjwIBn/eITAcwn+rxN57BRHvOEk= """ ) diff --git a/virtualenv_embedded/activate.bat b/virtualenv_embedded/activate.bat index ed42021..9c5d372 100644 --- a/virtualenv_embedded/activate.bat +++ b/virtualenv_embedded/activate.bat @@ -1,4 +1,5 @@ @echo off + set "VIRTUAL_ENV=__VIRTUAL_ENV__" if defined _OLD_VIRTUAL_PROMPT ( @@ -7,9 +8,13 @@ if defined _OLD_VIRTUAL_PROMPT ( if not defined PROMPT ( set "PROMPT=$P$G" ) - set "_OLD_VIRTUAL_PROMPT=%PROMPT%" + if not defined VIRTUAL_ENV_DISABLE_PROMPT ( + set "_OLD_VIRTUAL_PROMPT=%PROMPT%" + ) +) +if not defined VIRTUAL_ENV_DISABLE_PROMPT ( + set "PROMPT=__VIRTUAL_WINPROMPT__%PROMPT%" ) -set "PROMPT=__VIRTUAL_WINPROMPT__ %PROMPT%" REM Don't use () to avoid problems with them in %PATH% if defined _OLD_VIRTUAL_PYTHONHOME goto ENDIFVHOME diff --git a/virtualenv_embedded/activate.csh b/virtualenv_embedded/activate.csh index e3dc553..c4a6d58 100644 --- a/virtualenv_embedded/activate.csh +++ b/virtualenv_embedded/activate.csh @@ -20,22 +20,35 @@ setenv PATH "$VIRTUAL_ENV:q/__BIN_NAME__:$PATH:q" if ("__VIRTUAL_PROMPT__" != "") then set env_name = "__VIRTUAL_PROMPT__" else - set env_name = "$VIRTUAL_ENV:t:q" + set env_name = '('"$VIRTUAL_ENV:t:q"') ' endif -# Could be in a non-interactive environment, -# in which case, $prompt is undefined and we wouldn't -# care about the prompt anyway. -if ( $?prompt ) then - set _OLD_VIRTUAL_PROMPT="$prompt:q" -if ( "$prompt:q" =~ *"$newline:q"* ) then - : +if ( $?VIRTUAL_ENV_DISABLE_PROMPT ) then + if ( $VIRTUAL_ENV_DISABLE_PROMPT == "" ) then + set do_prompt = "1" + else + set do_prompt = "0" + endif else - set prompt = "[$env_name:q] $prompt:q" + set do_prompt = "1" endif + +if ( $do_prompt == "1" ) then + # Could be in a non-interactive environment, + # in which case, $prompt is undefined and we wouldn't + # care about the prompt anyway. + if ( $?prompt ) then + set _OLD_VIRTUAL_PROMPT="$prompt:q" + if ( "$prompt:q" =~ *"$newline:q"* ) then + : + else + set prompt = "$env_name:q$prompt:q" + endif + endif endif unset env_name +unset do_prompt alias pydoc python -m pydoc diff --git a/virtualenv_embedded/activate.ps1 b/virtualenv_embedded/activate.ps1 index 48b947d..3bbf9a6 100644 --- a/virtualenv_embedded/activate.ps1 +++ b/virtualenv_embedded/activate.ps1 @@ -1,4 +1,4 @@ -# This file must be dot sourced from PoSh; you cannot run it directly. Do this: . ./activate.ps1
+# This file must be dot sourced from PoSh; you cannot run it directly. Do this: . ./activate.ps1
$script:THIS_PATH = $myinvocation.mycommand.path
$script:BASE_DIR = split-path (resolve-path "$THIS_PATH/..") -Parent
@@ -51,10 +51,22 @@ if (!$env:VIRTUAL_ENV_DISABLE_PROMPT) ""
}
$function:_old_virtual_prompt = $function:prompt
- function global:prompt
+ if ("__VIRTUAL_PROMPT__" -ne "")
{
- # Add a prefix to the current prompt, but don't discard it.
- write-host "($( split-path $env:VIRTUAL_ENV -leaf )) " -nonewline
- & $function:_old_virtual_prompt
+ function global:prompt
+ {
+ # Add the custom prefix to the existing prompt
+ write-host "__VIRTUAL_PROMPT__" -nonewline
+ & $function:_old_virtual_prompt
+ }
+ }
+ else
+ {
+ function global:prompt
+ {
+ # Add a prefix to the current prompt, but don't discard it.
+ write-host "($( split-path $env:VIRTUAL_ENV -leaf )) " -nonewline
+ & $function:_old_virtual_prompt
+ }
}
}
diff --git a/virtualenv_embedded/activate.xsh b/virtualenv_embedded/activate.xsh index 6eb0d59..c77ea62 100644 --- a/virtualenv_embedded/activate.xsh +++ b/virtualenv_embedded/activate.xsh @@ -16,6 +16,9 @@ def _deactivate(args): if "VIRTUAL_ENV" in ${...}: del $VIRTUAL_ENV + if "VIRTUAL_ENV_PROMPT" in ${...}: + del $VIRTUAL_ENV_PROMPT + if "nondestructive" not in args: # Self destruct! del aliases["deactivate"] @@ -36,4 +39,8 @@ if ${...}.get("PYTHONHOME", ""): $_OLD_VIRTUAL_PYTHONHOME = $PYTHONHOME del $PYTHONHOME +$VIRTUAL_ENV_PROMPT = "__VIRTUAL_PROMPT__" +if not $VIRTUAL_ENV_PROMPT: + del $VIRTUAL_ENV_PROMPT + aliases["pydoc"] = ["python", "-m", "pydoc"] |