From 69f7b049a8db75cb98bc4488454b2d80cb46bf90 Mon Sep 17 00:00:00 2001 From: Evgenii Alekseev Date: Wed, 16 Jul 2025 01:42:24 +0300 Subject: [PATCH] tree demo --- src/ahriman/core/alpm/repo.py | 42 +++++++++++++++++++++---- src/ahriman/core/repository/executor.py | 11 ++++--- src/ahriman/models/repository_paths.py | 28 +++++++++++++++++ 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/src/ahriman/core/alpm/repo.py b/src/ahriman/core/alpm/repo.py index e7810b33..982c4f01 100644 --- a/src/ahriman/core/alpm/repo.py +++ b/src/ahriman/core/alpm/repo.py @@ -48,6 +48,16 @@ class Repo(LazyLogging): self.uid, _ = paths.root_owner self.sign_args = sign_args + @property + def repo_archive_path(self) -> Path: + """ + get full path to the repository archive + + Returns: + Path: path to repository archive + """ + return self.paths.archive / f"{self.name}.db.tar.gz" + @property def repo_path(self) -> Path: """ @@ -65,19 +75,38 @@ class Repo(LazyLogging): Args: path(Path): path to archive to add """ + # add to archive first check_output( - "repo-add", *self.sign_args, "-R", str(self.repo_path), str(path), + "repo-add", *self.sign_args, str(self.repo_archive_path), str(path), + exception=BuildError.from_process(path.name), + cwd=self.paths.archive, + logger=self.logger, + user=self.uid, + ) + + # create symlinks to the main repository + for full_path in path.parent.glob(f"{path.name}*"): # grab both packages and signatures + symlink = self.paths.repository / full_path.name + if symlink.exists(): + continue # skip already created symlinks (or files) + symlink.symlink_to(full_path.relative_to(symlink.parent, walk_up=True)) + + # add to repository + check_output( + "repo-add", *self.sign_args, "--remove", str(self.repo_path), str(path), exception=BuildError.from_process(path.name), cwd=self.paths.repository, logger=self.logger, - user=self.uid) + user=self.uid, + ) def init(self) -> None: """ create empty repository database. It just calls add with empty arguments """ - check_output("repo-add", *self.sign_args, str(self.repo_path), - cwd=self.paths.repository, logger=self.logger, user=self.uid) + for root in (self.repo_path, self.repo_archive_path): + check_output("repo-add", *self.sign_args, str(root), + cwd=root, logger=self.logger, user=self.uid) def remove(self, package: str, filename: Path) -> None: """ @@ -88,7 +117,7 @@ class Repo(LazyLogging): filename(Path): package filename to remove """ # remove package and signature (if any) from filesystem - for full_path in self.paths.repository.glob(f"{filename}*"): + for full_path in self.paths.repository.glob(f"**/{filename}*"): full_path.unlink() # remove package from registry @@ -97,4 +126,5 @@ class Repo(LazyLogging): exception=BuildError.from_process(package), cwd=self.paths.repository, logger=self.logger, - user=self.uid) + user=self.uid, + ) diff --git a/src/ahriman/core/repository/executor.py b/src/ahriman/core/repository/executor.py index 41755e79..8a71d8c4 100644 --- a/src/ahriman/core/repository/executor.py +++ b/src/ahriman/core/repository/executor.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -import shutil +import shutil # shutil.move is used here to ensure cross fs file movement from collections.abc import Iterable from pathlib import Path @@ -187,10 +187,13 @@ class Executor(PackageInfo, Cleaner): # in theory, it might be NOT packages directory, but we suppose it is full_path = self.paths.packages / name files = self.sign.process_sign_package(full_path, packager_key) + for src in files: - dst = self.paths.repository / safe_filename(src.name) - shutil.move(src, dst) - package_path = self.paths.repository / safe_filename(name) + archive = self.paths.archive_for(package_base) / safe_filename(src.name) + shutil.move(src, archive) + if not (symlink := self.paths.repository / archive.name).exists(): + symlink.symlink_to(archive.relative_to(symlink.parent, walk_up=True)) + package_path = self.paths.archive / safe_filename(name) self.repo.add(package_path) current_packages = {package.base: package for package in self.packages()} diff --git a/src/ahriman/models/repository_paths.py b/src/ahriman/models/repository_paths.py index 7e8ae558..033f0074 100644 --- a/src/ahriman/models/repository_paths.py +++ b/src/ahriman/models/repository_paths.py @@ -85,6 +85,16 @@ class RepositoryPaths(LazyLogging): return Path(self.repository_id.architecture) # legacy tree suffix return Path(self.repository_id.name) / self.repository_id.architecture + @property + def archive(self) -> Path: + """ + archive directory root + + Returns: + Path: archive directory root + """ + return self.root / "archive" / self._suffix + @property def build_root(self) -> Path: """ @@ -249,6 +259,23 @@ class RepositoryPaths(LazyLogging): set_owner(path) path = path.parent + def archive_for(self, package_base: str) -> Path: + """ + get path to archive specified search criteria + + Args: + package_base(str): package base name + + Returns: + Path: path to archive directory for package base + """ + directory = self.archive / package_base[0] / package_base + if not directory.is_dir(): # create if not exists + with self.preserve_owner(self.archive): + directory.mkdir(mode=0o755, parents=True) + + return directory + def cache_for(self, package_base: str) -> Path: """ get path to cached PKGBUILD and package sources for the package base @@ -320,6 +347,7 @@ class RepositoryPaths(LazyLogging): with self.preserve_owner(): for directory in ( + self.archive, self.cache, self.chroot, self.packages,