mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-04-07 11:03:37 +00:00
remove custom filelock
This commit is contained in:
2
.github/workflows/setup.sh
vendored
2
.github/workflows/setup.sh
vendored
@@ -10,7 +10,7 @@ echo -e '[arcanisrepo]\nServer = https://repo.arcanis.me/$arch\nSigLevel = Never
|
|||||||
# refresh the image
|
# refresh the image
|
||||||
pacman -Syyu --noconfirm
|
pacman -Syyu --noconfirm
|
||||||
# main dependencies
|
# main dependencies
|
||||||
pacman -S --noconfirm devtools git pyalpm python-bcrypt python-inflection python-pyelftools python-requests python-systemd sudo
|
pacman -S --noconfirm devtools git pyalpm python-bcrypt python-filelock python-inflection python-pyelftools python-requests python-systemd sudo
|
||||||
# make dependencies
|
# make dependencies
|
||||||
pacman -S --noconfirm --asdeps base-devel python-build python-flit python-installer python-tox python-wheel
|
pacman -S --noconfirm --asdeps base-devel python-build python-flit python-installer python-tox python-wheel
|
||||||
# optional dependencies
|
# optional dependencies
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ RUN pacman -S --noconfirm --asdeps \
|
|||||||
devtools \
|
devtools \
|
||||||
git \
|
git \
|
||||||
pyalpm \
|
pyalpm \
|
||||||
python-bcrypt \
|
python-bcrypt \
|
||||||
|
python-filelock \
|
||||||
python-inflection \
|
python-inflection \
|
||||||
python-pyelftools \
|
python-pyelftools \
|
||||||
python-requests \
|
python-requests \
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ pkgdesc="ArcH linux ReposItory MANager"
|
|||||||
arch=('any')
|
arch=('any')
|
||||||
url="https://ahriman.readthedocs.io/"
|
url="https://ahriman.readthedocs.io/"
|
||||||
license=('GPL-3.0-or-later')
|
license=('GPL-3.0-or-later')
|
||||||
depends=('devtools>=1:1.0.0' 'git' 'pyalpm' 'python-bcrypt' 'python-inflection' 'python-pyelftools' 'python-requests')
|
depends=('devtools>=1:1.0.0' 'git' 'pyalpm' 'python-bcrypt' 'python-filelock' 'python-inflection' 'python-pyelftools' 'python-requests')
|
||||||
makedepends=('python-build' 'python-flit' 'python-installer' 'python-wheel')
|
makedepends=('python-build' 'python-flit' 'python-installer' 'python-wheel')
|
||||||
source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgbase-$pkgver.tar.gz"
|
source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgbase-$pkgver.tar.gz"
|
||||||
"$pkgbase.sysusers"
|
"$pkgbase.sysusers"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ authors = [
|
|||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
|
"filelock",
|
||||||
"inflection",
|
"inflection",
|
||||||
"pyelftools",
|
"pyelftools",
|
||||||
"requests",
|
"requests",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
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
|
||||||
|
|
||||||
@@ -27,7 +28,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, filelock, list_flatmap, package_like, safe_filename, symlink_relative
|
from ahriman.core.utils import atomic_move, 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
|
||||||
@@ -111,7 +112,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 FileLock(artifact.with_name(f".{artifact.name}.lock")):
|
||||||
shutil.copy(artifact, path)
|
shutil.copy(artifact, path)
|
||||||
built.append(path / artifact.name)
|
built.append(path / artifact.name)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -18,9 +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 fcntl
|
|
||||||
import io
|
import io
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
@@ -33,6 +31,7 @@ import subprocess
|
|||||||
from collections.abc import Callable, Iterable, Iterator, Mapping
|
from collections.abc import Callable, Iterable, Iterator, Mapping
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from filelock import FileLock
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pwd import getpwuid
|
from pwd import getpwuid
|
||||||
from typing import Any, IO, TypeVar
|
from typing import Any, IO, TypeVar
|
||||||
@@ -48,7 +47,6 @@ __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",
|
||||||
@@ -89,7 +87,7 @@ def atomic_move(src: Path, dst: Path) -> None:
|
|||||||
|
|
||||||
>>> atomic_move(src, dst)
|
>>> atomic_move(src, dst)
|
||||||
"""
|
"""
|
||||||
with filelock(dst):
|
with FileLock(dst.with_name(f".{dst.name}.lock")):
|
||||||
shutil.move(src, dst)
|
shutil.move(src, dst)
|
||||||
|
|
||||||
|
|
||||||
@@ -264,29 +262,6 @@ 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[None]:
|
|
||||||
"""
|
|
||||||
lock on file passed as argument
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path(Path): path object on which lock must be performed
|
|
||||||
"""
|
|
||||||
lock_path = path.with_name(f".{path.name}")
|
|
||||||
try:
|
|
||||||
with lock_path.open("ab") as lock_file:
|
|
||||||
fd = lock_file.fileno()
|
|
||||||
try:
|
|
||||||
fcntl.flock(fd, fcntl.LOCK_EX) # lock file and wait lock is until available
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
fcntl.flock(fd, fcntl.LOCK_UN) # unlock file first
|
|
||||||
finally:
|
|
||||||
# remove lock file at the end
|
|
||||||
# there might be a race condition here, but we don't care about this case
|
|
||||||
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
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import fcntl
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
@@ -21,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"))
|
filelock_mock.assert_called_once_with(Path(".destination.lock"))
|
||||||
move_mock.assert_called_once_with(Path("source"), Path("destination"))
|
move_mock.assert_called_once_with(Path("source"), Path("destination"))
|
||||||
|
|
||||||
|
|
||||||
@@ -248,53 +247,6 @@ def test_extract_user() -> None:
|
|||||||
assert extract_user() == "doas"
|
assert extract_user() == "doas"
|
||||||
|
|
||||||
|
|
||||||
def test_filelock(mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must perform file locking
|
|
||||||
"""
|
|
||||||
lock_mock = mocker.patch("fcntl.flock")
|
|
||||||
open_mock = mocker.patch("pathlib.Path.open", autospec=True)
|
|
||||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
|
||||||
|
|
||||||
with filelock(Path("local")):
|
|
||||||
pass
|
|
||||||
open_mock.assert_called_once_with(Path(".local"), "ab")
|
|
||||||
lock_mock.assert_has_calls([
|
|
||||||
MockCall(pytest.helpers.anyvar(int), fcntl.LOCK_EX),
|
|
||||||
MockCall(pytest.helpers.anyvar(int), fcntl.LOCK_UN),
|
|
||||||
])
|
|
||||||
unlink_mock.assert_called_once_with(missing_ok=True)
|
|
||||||
|
|
||||||
|
|
||||||
def test_filelock_remove_lock(mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must remove lock file in case of exception
|
|
||||||
"""
|
|
||||||
mocker.patch("pathlib.Path.open", side_effect=Exception)
|
|
||||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
|
||||||
|
|
||||||
with pytest.raises(Exception):
|
|
||||||
with filelock(Path("local")):
|
|
||||||
pass
|
|
||||||
unlink_mock.assert_called_once_with(missing_ok=True)
|
|
||||||
|
|
||||||
|
|
||||||
def test_filelock_unlock(mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must unlock file in case of exception
|
|
||||||
"""
|
|
||||||
mocker.patch("pathlib.Path.open")
|
|
||||||
lock_mock = mocker.patch("fcntl.flock")
|
|
||||||
|
|
||||||
with pytest.raises(Exception):
|
|
||||||
with filelock(Path("local")):
|
|
||||||
raise Exception
|
|
||||||
lock_mock.assert_has_calls([
|
|
||||||
MockCall(pytest.helpers.anyvar(int), fcntl.LOCK_EX),
|
|
||||||
MockCall(pytest.helpers.anyvar(int), fcntl.LOCK_UN),
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
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