From 3eb1896a98f28fbc5b36837da54faa20f46b850d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 8 Jun 2019 17:57:21 -0700 Subject: [PATCH] cowardly refuse to delete a directory if it isn't a venv --- docs/changelog/1340.feature.rst | 1 + src/tox/venv.py | 27 ++++++++++++++++++++++++++- tests/unit/test_z_cmdline.py | 20 ++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 docs/changelog/1340.feature.rst diff --git a/docs/changelog/1340.feature.rst b/docs/changelog/1340.feature.rst new file mode 100644 index 000000000..3c37d416a --- /dev/null +++ b/docs/changelog/1340.feature.rst @@ -0,0 +1 @@ +Refuse to delete ``envdir`` if it doesn't look like a virtualenv - by :user:`asottile`. diff --git a/src/tox/venv.py b/src/tox/venv.py index 72b0b737f..1bd71e6db 100644 --- a/src/tox/venv.py +++ b/src/tox/venv.py @@ -12,7 +12,7 @@ from tox import reporter from tox.action import Action from tox.config.parallel import ENV_VAR_KEY as PARALLEL_ENV_VAR_KEY -from tox.constants import PARALLEL_RESULT_JSON_PREFIX, PARALLEL_RESULT_JSON_SUFFIX +from tox.constants import INFO, PARALLEL_RESULT_JSON_PREFIX, PARALLEL_RESULT_JSON_SUFFIX from tox.package.local import resolve_package from tox.util.lock import get_unique_file from tox.util.path import ensure_empty_dir @@ -694,6 +694,31 @@ def tox_testenv_create(venv, action): def cleanup_for_venv(venv): within_parallel = PARALLEL_ENV_VAR_KEY in os.environ + # if the directory exists and it doesn't look like a virtualenv, produce + # an error + if venv.path.exists(): + dir_items = set(os.listdir(str(venv.path))) - {".lock", "log"} + dir_items = {p for p in dir_items if not p.startswith(".tox-")} + else: + dir_items = set() + + if not ( + # doesn't exist => OK + not venv.path.exists() + # does exist, but it's empty => OK + or not dir_items + # it exists and we're on windows with Lib and Scripts => OK + or (INFO.IS_WIN and dir_items > {"Scripts", "Lib"}) + # non-windows, with lib and bin => OK + or dir_items > {"bin", "lib"} + ): + venv.status = "error" + reporter.error( + "cowardly refusing to delete `envdir` (it does not look like a virtualenv): " + "{}".format(venv.path) + ) + raise SystemExit(2) + if within_parallel: if venv.path.exists(): # do not delete the log folder as that's used by parent diff --git a/tests/unit/test_z_cmdline.py b/tests/unit/test_z_cmdline.py index 53a4e50c6..ce34a07dc 100644 --- a/tests/unit/test_z_cmdline.py +++ b/tests/unit/test_z_cmdline.py @@ -115,6 +115,26 @@ def test_envdir_equals_toxini_errors_out(cmd, initproj): result.assert_fail() +def test_envdir_would_delete_some_directory(cmd, initproj): + projdir = initproj( + "example-123", + filedefs={ + "tox.ini": """\ + [tox] + + [testenv:venv] + envdir=example + commands= + """ + }, + ) + + result = cmd("-e", "venv") + assert projdir.join("example/__init__.py").exists() + result.assert_fail() + assert "cowardly refusing to delete `envdir`" in result.out + + def test_run_custom_install_command_error(cmd, initproj): initproj( "interp123-0.5",