diff --git a/README.rst b/README.rst index e99640c..3afd275 100644 --- a/README.rst +++ b/README.rst @@ -164,8 +164,9 @@ and regular ``tox`` runs (without the flag). If you ever need to do this, use tox's ``--recreate/-r`` flag to clear the cache. The plugin should abort with a meaningful error message if this is detected, -but in some cases (such as running ``tox --current-env``, uninstalling the -plugin, and running ``tox``), you will get undefined results +but in some corner cases (such as running ``tox --current-env``, +forcefully killing it before it finished, uninstalling the plugin, +and running ``tox``), you will get undefined results (such as installing packages from PyPI into your current environment). Environment variables are not passed by default diff --git a/src/tox_current_env/hooks.py b/src/tox_current_env/hooks.py index 14607fe..93c13f3 100644 --- a/src/tox_current_env/hooks.py +++ b/src/tox_current_env/hooks.py @@ -75,13 +75,19 @@ def is_any_env(venv): return python +def rm_venv(venv): + link = venv.envconfig.get_envpython() + shutil.rmtree(os.path.dirname(os.path.dirname(link)), ignore_errors=True) + + def unsupported_raise(config, venv): if config.option.recreate: return regular = not (config.option.current_env or config.option.print_deps_only) if regular and is_current_env_link(venv): raise tox.exception.ConfigError( - "Regular tox run after --current-env or --print-deps-only tox run is not supported without --recreate (-r)." + "Looks like previous --current-env or --print-deps-only tox run didn't finish the cleanup. " + "Run tox run with --recreate (-r) or manually remove the environment in .tox." ) elif config.option.current_env and is_proper_venv(venv): raise tox.exception.ConfigError( @@ -126,8 +132,7 @@ def tox_testenv_create(venv, action): os.symlink(target, link) return True else: - link = venv.envconfig.get_envpython() - shutil.rmtree(os.path.dirname(os.path.dirname(link)), ignore_errors=True) + rm_venv(venv) return None # let tox handle the rest @@ -159,3 +164,13 @@ def tox_runtest(venv, redirect): if config.option.print_deps_only: print(*venv.get_resolved_dependencies(), sep="\n") return True + + +@tox.hookimpl +def tox_cleanup(session): + """Remove the fake virtualenv not to collide with regular tox + Collisions can happen anyway (when tox is killed forcefully before this happens) + Note that we don't remove real venvs, as recreating them is expensive""" + for venv in session.venv_dict.values(): + if is_current_env_link(venv): + rm_venv(venv) diff --git a/tests/test_integration.py b/tests/test_integration.py index 3f74ca4..85199fe 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -195,20 +195,32 @@ def test_regular_run_native_toxenv(): assert len(list(sitelib.glob(f"{pkg}-*.dist-info"))) == 1 -def test_regular_after_current_is_not_supported(): +def test_regular_after_current_is_supported(): result = tox("-e", NATIVE_TOXENV, "--current-env") assert result.stdout.splitlines()[0] == NATIVE_EXECUTABLE + result = tox("-e", NATIVE_TOXENV, prune=False) + assert f"/.tox/{NATIVE_TOXENV}/bin/python" in result.stdout + assert "--recreate" not in result.stderr + + +def test_regular_after_killed_current_is_not_supported(): + # fake broken tox run + shutil.rmtree(DOT_TOX, ignore_errors=True) + (DOT_TOX / NATIVE_TOXENV / "bin").mkdir(parents=True) + (DOT_TOX / NATIVE_TOXENV / "bin" / "python").symlink_to(NATIVE_EXECUTABLE) + result = tox("-e", NATIVE_TOXENV, prune=False, check=False) assert result.returncode > 0 - assert "not supported" in result.stderr + assert "--recreate" in result.stderr -def test_regular_after_first_deps_only_is_not_supported(): +def test_regular_after_first_deps_only_is_supported(): result = tox("-e", NATIVE_TOXENV, "--print-deps-only") assert result.stdout.splitlines()[0] == "six" - result = tox("-e", NATIVE_TOXENV, prune=False, check=False) - assert result.returncode > 0 - assert "not supported" in result.stderr + result = tox("-e", NATIVE_TOXENV, prune=False) + lines = sorted(result.stdout.splitlines()[:1]) + assert "--recreate" not in result.stderr + assert f"/.tox/{NATIVE_TOXENV}/bin/python" in lines[0] # check that "test" was not installed to current environment pip_freeze = subprocess.run( @@ -225,6 +237,7 @@ def test_regular_recreate_after_current(): result = tox("-re", NATIVE_TOXENV, prune=False) assert f"/.tox/{NATIVE_TOXENV}/bin/python" in result.stdout assert "not supported" not in result.stderr + assert "--recreate" not in result.stderr def test_current_after_regular_is_not_supported():