Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog/1340.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Refuse to delete ``envdir`` if it doesn't look like a virtualenv - by :user:`asottile`.
27 changes: 26 additions & 1 deletion src/tox/venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/test_z_cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down