mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-04-07 19:03:38 +00:00
restore wrapper around filelock
This commit is contained in:
@@ -20,7 +20,6 @@
|
|||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
from filelock import FileLock
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
@@ -28,7 +27,7 @@ from ahriman.core.build_tools.package_archive import PackageArchive
|
|||||||
from ahriman.core.build_tools.task import Task
|
from ahriman.core.build_tools.task import Task
|
||||||
from ahriman.core.repository.cleaner import Cleaner
|
from ahriman.core.repository.cleaner import Cleaner
|
||||||
from ahriman.core.repository.package_info import PackageInfo
|
from ahriman.core.repository.package_info import PackageInfo
|
||||||
from ahriman.core.utils import atomic_move, list_flatmap, package_like, safe_filename, symlink_relative
|
from ahriman.core.utils import atomic_move, filelock, list_flatmap, package_like, safe_filename, symlink_relative
|
||||||
from ahriman.models.changes import Changes
|
from ahriman.models.changes import Changes
|
||||||
from ahriman.models.event import EventType
|
from ahriman.models.event import EventType
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
@@ -112,7 +111,7 @@ class Executor(PackageInfo, Cleaner):
|
|||||||
self.logger.info("using prebuilt packages for %s-%s", loaded_package.base, loaded_package.version)
|
self.logger.info("using prebuilt packages for %s-%s", loaded_package.base, loaded_package.version)
|
||||||
built = []
|
built = []
|
||||||
for artifact in prebuilt:
|
for artifact in prebuilt:
|
||||||
with FileLock(artifact.with_name(f".{artifact.name}.lock")):
|
with filelock(artifact):
|
||||||
shutil.copy(artifact, path)
|
shutil.copy(artifact, path)
|
||||||
built.append(path / artifact.name)
|
built.append(path / artifact.name)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
# pylint: disable=too-many-lines
|
# pylint: disable=too-many-lines
|
||||||
|
import contextlib
|
||||||
import datetime
|
import datetime
|
||||||
import io
|
import io
|
||||||
import itertools
|
import itertools
|
||||||
@@ -47,6 +48,7 @@ __all__ = [
|
|||||||
"dataclass_view",
|
"dataclass_view",
|
||||||
"enum_values",
|
"enum_values",
|
||||||
"extract_user",
|
"extract_user",
|
||||||
|
"filelock",
|
||||||
"filter_json",
|
"filter_json",
|
||||||
"full_version",
|
"full_version",
|
||||||
"list_flatmap",
|
"list_flatmap",
|
||||||
@@ -87,7 +89,7 @@ def atomic_move(src: Path, dst: Path) -> None:
|
|||||||
|
|
||||||
>>> atomic_move(src, dst)
|
>>> atomic_move(src, dst)
|
||||||
"""
|
"""
|
||||||
with FileLock(dst.with_name(f".{dst.name}.lock")):
|
with filelock(dst):
|
||||||
shutil.move(src, dst)
|
shutil.move(src, dst)
|
||||||
|
|
||||||
|
|
||||||
@@ -262,6 +264,25 @@ def extract_user() -> str | None:
|
|||||||
return os.getenv("SUDO_USER") or os.getenv("DOAS_USER") or os.getenv("USER")
|
return os.getenv("SUDO_USER") or os.getenv("DOAS_USER") or os.getenv("USER")
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def filelock(path: Path) -> Iterator[FileLock]:
|
||||||
|
"""
|
||||||
|
wrapper around :class:`filelock.FileLock`, which also removes locks afterward
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path(Path): path to lock on. The lock file will be created as ``.{path.name}.lock``
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
FileLock: acquired file lock instance
|
||||||
|
"""
|
||||||
|
lock_path = path.with_name(f".{path.name}.lock")
|
||||||
|
try:
|
||||||
|
with FileLock(lock_path) as lock:
|
||||||
|
yield lock
|
||||||
|
finally:
|
||||||
|
lock_path.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
def filter_json(source: dict[str, Any], known_fields: Iterable[str]) -> dict[str, Any]:
|
def filter_json(source: dict[str, Any], known_fields: Iterable[str]) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
filter json object by fields used for json-to-object conversion
|
filter json object by fields used for json-to-object conversion
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ def test_atomic_move(mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
must move file with locking
|
must move file with locking
|
||||||
"""
|
"""
|
||||||
filelock_mock = mocker.patch("ahriman.core.utils.FileLock")
|
filelock_mock = mocker.patch("ahriman.core.utils.filelock")
|
||||||
move_mock = mocker.patch("shutil.move")
|
move_mock = mocker.patch("shutil.move")
|
||||||
|
|
||||||
atomic_move(Path("source"), Path("destination"))
|
atomic_move(Path("source"), Path("destination"))
|
||||||
filelock_mock.assert_called_once_with(Path(".destination.lock"))
|
filelock_mock.assert_called_once_with(Path("destination"))
|
||||||
move_mock.assert_called_once_with(Path("source"), Path("destination"))
|
move_mock.assert_called_once_with(Path("source"), Path("destination"))
|
||||||
|
|
||||||
|
|
||||||
@@ -247,6 +247,30 @@ def test_extract_user() -> None:
|
|||||||
assert extract_user() == "doas"
|
assert extract_user() == "doas"
|
||||||
|
|
||||||
|
|
||||||
|
def test_filelock(tmp_path: Path) -> None:
|
||||||
|
"""
|
||||||
|
must acquire lock and remove lock file after
|
||||||
|
"""
|
||||||
|
local = tmp_path / "local"
|
||||||
|
lock = local.with_name(f".{local.name}.lock")
|
||||||
|
|
||||||
|
with filelock(local):
|
||||||
|
assert lock.exists()
|
||||||
|
assert not lock.exists()
|
||||||
|
|
||||||
|
|
||||||
|
def test_filelock_cleanup_on_missing(tmp_path: Path) -> None:
|
||||||
|
"""
|
||||||
|
must not fail if lock file is already removed
|
||||||
|
"""
|
||||||
|
local = tmp_path / "local"
|
||||||
|
lock = local.with_name(f".{local.name}.lock")
|
||||||
|
|
||||||
|
with filelock(local):
|
||||||
|
lock.unlink(missing_ok=True)
|
||||||
|
assert not lock.exists()
|
||||||
|
|
||||||
|
|
||||||
def test_filter_json(package_ahriman: Package) -> None:
|
def test_filter_json(package_ahriman: Package) -> None:
|
||||||
"""
|
"""
|
||||||
must filter fields by known list
|
must filter fields by known list
|
||||||
|
|||||||
Reference in New Issue
Block a user