shape up removal and lock destruction
This commit is contained in:
parent
b3a5b0ebe1
commit
642cd86dd1
|
@ -111,7 +111,7 @@ def register_cleanup_lock_removal(lock_path, register=atexit.register):
|
||||||
return register(cleanup_on_exit)
|
return register(cleanup_on_exit)
|
||||||
|
|
||||||
|
|
||||||
def delete_a_numbered_dir(path, consider_lock_dead_after):
|
def delete_a_numbered_dir(path):
|
||||||
create_cleanup_lock(path)
|
create_cleanup_lock(path)
|
||||||
parent = path.parent
|
parent = path.parent
|
||||||
|
|
||||||
|
@ -120,24 +120,47 @@ def delete_a_numbered_dir(path, consider_lock_dead_after):
|
||||||
shutil.rmtree(str(garbage))
|
shutil.rmtree(str(garbage))
|
||||||
|
|
||||||
|
|
||||||
def is_deletable(path, consider_lock_dead_after):
|
def ensure_deletable(path, consider_lock_dead_after):
|
||||||
lock = get_lock_path(path)
|
lock = get_lock_path(path)
|
||||||
if not lock.exists():
|
if not lock.exists():
|
||||||
return True
|
return True
|
||||||
|
try:
|
||||||
|
lock_time = lock.stat().st_mtime
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if lock_time > consider_lock_dead_after:
|
||||||
|
lock.unlink()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def cleanup_numbered_dir(root, prefix, keep, consider_lock_dead_after):
|
def try_cleanup(path, consider_lock_dead_after):
|
||||||
|
if ensure_deletable(path, consider_lock_dead_after):
|
||||||
|
delete_a_numbered_dir(path)
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup_candidates(root, prefix, keep):
|
||||||
max_existing = _max(map(parse_num, find_suffixes(root, prefix)), -1)
|
max_existing = _max(map(parse_num, find_suffixes(root, prefix)), -1)
|
||||||
max_delete = max_existing - keep
|
max_delete = max_existing - keep
|
||||||
paths = find_prefixed(root, prefix)
|
paths = find_prefixed(root, prefix)
|
||||||
paths, paths2 = itertools.tee(paths)
|
paths, paths2 = itertools.tee(paths)
|
||||||
numbers = map(parse_num, extract_suffixes(paths2, prefix))
|
numbers = map(parse_num, extract_suffixes(paths2, prefix))
|
||||||
for path, number in zip(paths, numbers):
|
for path, number in zip(paths, numbers):
|
||||||
if number <= max_delete and is_deletable(path, consider_lock_dead_after):
|
if number <= max_delete:
|
||||||
delete_a_numbered_dir(path, consider_lock_dead_after)
|
yield path
|
||||||
|
|
||||||
|
|
||||||
def make_numbered_dir_with_cleanup(root, prefix, keep, consider_lock_dead_after):
|
def cleanup_numbered_dir(root, prefix, keep, consider_lock_dead_after):
|
||||||
|
for path in cleanup_candidates(root, prefix, keep):
|
||||||
|
try_cleanup(path, consider_lock_dead_after)
|
||||||
|
known_garbage = list(root.glob("garbage-*"))
|
||||||
|
for path in known_garbage:
|
||||||
|
try_cleanup(path, consider_lock_dead_after)
|
||||||
|
|
||||||
|
|
||||||
|
def make_numbered_dir_with_cleanup(root, prefix, keep, lock_timeout):
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
try:
|
try:
|
||||||
p = make_numbered_dir(root, prefix)
|
p = make_numbered_dir(root, prefix)
|
||||||
|
@ -146,6 +169,7 @@ def make_numbered_dir_with_cleanup(root, prefix, keep, consider_lock_dead_after)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
|
consider_lock_dead_after = p.stat().st_mtime + lock_timeout
|
||||||
cleanup_numbered_dir(
|
cleanup_numbered_dir(
|
||||||
root=root,
|
root=root,
|
||||||
prefix=prefix,
|
prefix=prefix,
|
||||||
|
@ -188,19 +212,13 @@ class TempPathFactory(object):
|
||||||
basetemp.mkdir()
|
basetemp.mkdir()
|
||||||
else:
|
else:
|
||||||
temproot = Path(tempfile.gettempdir())
|
temproot = Path(tempfile.gettempdir())
|
||||||
user = get_user()
|
user = get_user() or "unknown"
|
||||||
if user:
|
|
||||||
# use a sub-directory in the temproot to speed-up
|
# use a sub-directory in the temproot to speed-up
|
||||||
# make_numbered_dir() call
|
# make_numbered_dir() call
|
||||||
rootdir = temproot.joinpath("pytest-of-{}".format(user))
|
rootdir = temproot.joinpath("pytest-of-{}".format(user))
|
||||||
else:
|
|
||||||
rootdir = temproot
|
|
||||||
rootdir.mkdir(exist_ok=True)
|
rootdir.mkdir(exist_ok=True)
|
||||||
basetemp = make_numbered_dir_with_cleanup(
|
basetemp = make_numbered_dir_with_cleanup(
|
||||||
prefix="pytest-",
|
prefix="pytest-", root=rootdir, keep=3, lock_timeout=10000
|
||||||
root=rootdir,
|
|
||||||
keep=3,
|
|
||||||
consider_lock_dead_after=10000,
|
|
||||||
)
|
)
|
||||||
assert basetemp is not None
|
assert basetemp is not None
|
||||||
self._basetemp = t = basetemp
|
self._basetemp = t = basetemp
|
||||||
|
|
|
@ -143,6 +143,7 @@ def break_getuser(monkeypatch):
|
||||||
monkeypatch.delenv(envvar, raising=False)
|
monkeypatch.delenv(envvar, raising=False)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason="creates random tmpdirs as part of a system level test")
|
||||||
@pytest.mark.usefixtures("break_getuser")
|
@pytest.mark.usefixtures("break_getuser")
|
||||||
@pytest.mark.skipif(sys.platform.startswith("win"), reason="no os.getuid on windows")
|
@pytest.mark.skipif(sys.platform.startswith("win"), reason="no os.getuid on windows")
|
||||||
def test_tmpdir_fallback_uid_not_found(testdir):
|
def test_tmpdir_fallback_uid_not_found(testdir):
|
||||||
|
@ -161,6 +162,7 @@ def test_tmpdir_fallback_uid_not_found(testdir):
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason="creates random tmpdirs as part of a system level test")
|
||||||
@pytest.mark.usefixtures("break_getuser")
|
@pytest.mark.usefixtures("break_getuser")
|
||||||
@pytest.mark.skipif(sys.platform.startswith("win"), reason="no os.getuid on windows")
|
@pytest.mark.skipif(sys.platform.startswith("win"), reason="no os.getuid on windows")
|
||||||
def test_get_user_uid_not_found():
|
def test_get_user_uid_not_found():
|
||||||
|
@ -241,3 +243,13 @@ class TestNumberedDir(object):
|
||||||
)
|
)
|
||||||
a, b = tmp_path.iterdir()
|
a, b = tmp_path.iterdir()
|
||||||
print(a, b)
|
print(a, b)
|
||||||
|
|
||||||
|
def test_cleanup_locked(self, tmp_path):
|
||||||
|
|
||||||
|
from _pytest import tmpdir
|
||||||
|
|
||||||
|
p = tmpdir.make_numbered_dir(root=tmp_path, prefix=self.PREFIX)
|
||||||
|
|
||||||
|
tmpdir.create_cleanup_lock(p)
|
||||||
|
assert not tmpdir.ensure_deletable(p, p.stat().st_mtime + 1)
|
||||||
|
assert tmpdir.ensure_deletable(p, p.stat().st_mtime - 1)
|
||||||
|
|
Loading…
Reference in New Issue