Skip to content

Commit

Permalink
Provision lock (#2516)
Browse files Browse the repository at this point in the history
  • Loading branch information
masenf committed Oct 25, 2022
1 parent d41bd62 commit e378131
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 2 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS
Expand Up @@ -80,6 +80,7 @@ Marc Schlaich
Marius Gedminas
Mariusz Rusiniak
Mark Hirota
Masen Furer
Matt Good
Matt Jeffery
Matthew Kenigsberg
Expand Down
2 changes: 2 additions & 0 deletions docs/changelog/2515.bugfix.rst
@@ -0,0 +1,2 @@
Multiple tox instances no longer clobber the ``.tox`` directory when
``provision_tox_env`` is used. - by :user:`masenf`
5 changes: 5 additions & 0 deletions docs/config.rst
Expand Up @@ -76,6 +76,11 @@ Global settings are defined under the ``tox`` section as:
When tox is invoked with the ``--no-provision`` flag,
the provision won't be attempted, tox will fail instead.

.. versionchanged:: 3.27.0

When provisioning, tox will take a lock to ensure exclusive access to the
`provision_tox_env` and avoid clobbering by other tox instances.

.. warning::

The new virtual environment will only contain dependencies specified by the :conf:`requires` keyword.
Expand Down
10 changes: 8 additions & 2 deletions src/tox/session/commands/provision.py
Expand Up @@ -4,6 +4,8 @@
import os

from tox.exception import InvocationError
from tox.reporter import verbosity0
from tox.util.lock import hold_lock


def provision_tox(provision_venv, args):
Expand All @@ -21,5 +23,9 @@ def provision_tox(provision_venv, args):


def ensure_meta_env_up_to_date(provision_venv):
if provision_venv.setupenv():
provision_venv.finishvenv()
config = provision_venv.envconfig.config
lock_file = config.toxworkdir.join("{}.lock".format(config.provision_tox_env))

with hold_lock(lock_file, verbosity0):
if provision_venv.setupenv():
provision_venv.finishvenv()
31 changes: 31 additions & 0 deletions tests/integration/test_provision_int.py
Expand Up @@ -134,3 +134,34 @@ def test_provision_interrupt_child(initproj, monkeypatch, capfd, signal_type):
out,
"\n".join(repr(i) for i in all_process),
)


@pytest.mark.skipif("sys.platform == 'win32'", reason="pyenv does not exists on Windows")
def test_provision_race(initproj, cmd, monkeypatch):
initproj(
"pkg123-0.7",
filedefs={
"tox.ini": """\
[tox]
skipsdist=True
minversion = 3.7.0
requires =
setuptools == 40.6.3
[testenv]
commands=python -c "import sys; print(sys.executable); raise SystemExit(1)"
[testenv:x2]
""",
},
)

procs = [
subprocess.Popen(
[sys.executable, "-m", "tox", "-e", "py", "-vv"],
stdout=subprocess.PIPE,
)
for _ in range(2)
]
for proc in procs:
stdout, stderr = proc.communicate()
assert proc.returncode != 0
assert b".tox/.tox/bin/python -m virtualenv" in stdout

0 comments on commit e378131

Please sign in to comment.