mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-28 09:17:17 +00:00
177 lines
4.8 KiB
Python
177 lines
4.8 KiB
Python
#
|
|
# Copyright (c) 2021-2022 ahriman team.
|
|
#
|
|
# This file is part of ahriman
|
|
# (see https://github.com/arcan1s/ahriman).
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import shutil
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Set, Tuple, Type
|
|
|
|
from ahriman.core.exceptions import InvalidPath
|
|
|
|
|
|
@dataclass
|
|
class RepositoryPaths:
|
|
"""
|
|
repository paths holder. For the most operations with paths you want to use this object
|
|
|
|
Attributes:
|
|
root(Path): repository root (i.e. ahriman home)
|
|
architecture(str): repository architecture
|
|
"""
|
|
|
|
root: Path
|
|
architecture: str
|
|
|
|
@property
|
|
def cache(self) -> Path:
|
|
"""
|
|
Returns:
|
|
Path: directory for packages cache (mainly used for VCS packages)
|
|
"""
|
|
return self.root / "cache"
|
|
|
|
@property
|
|
def chroot(self) -> Path:
|
|
"""
|
|
Returns:
|
|
Path: directory for devtools chroot
|
|
"""
|
|
# for the chroot directory devtools will create own tree, and we don"t have to specify architecture here
|
|
return self.root / "chroot"
|
|
|
|
@property
|
|
def packages(self) -> Path:
|
|
"""
|
|
Returns:
|
|
Path: directory for built packages
|
|
"""
|
|
return self.root / "packages" / self.architecture
|
|
|
|
@property
|
|
def repository(self) -> Path:
|
|
"""
|
|
Returns:
|
|
Path: repository directory
|
|
"""
|
|
return self.root / "repository" / self.architecture
|
|
|
|
@property
|
|
def root_owner(self) -> Tuple[int, int]:
|
|
"""
|
|
Returns:
|
|
Tuple[int, int]: owner user and group of the root directory
|
|
"""
|
|
return self.owner(self.root)
|
|
|
|
@classmethod
|
|
def known_architectures(cls: Type[RepositoryPaths], root: Path) -> Set[str]:
|
|
"""
|
|
get known architectures
|
|
|
|
Args:
|
|
root(Path): repository root
|
|
|
|
Returns:
|
|
Set[str]: list of architectures for which tree is created
|
|
"""
|
|
paths = cls(root, "")
|
|
return {
|
|
path.name
|
|
for path in paths.repository.iterdir()
|
|
if path.is_dir()
|
|
}
|
|
|
|
@staticmethod
|
|
def owner(path: Path) -> Tuple[int, int]:
|
|
"""
|
|
retrieve owner information by path
|
|
|
|
Args:
|
|
path(Path): path for which extract ids
|
|
|
|
Returns:
|
|
Tuple[int, int]: owner user and group ids of the directory
|
|
"""
|
|
stat = path.stat()
|
|
return stat.st_uid, stat.st_gid
|
|
|
|
def cache_for(self, package_base: str) -> Path:
|
|
"""
|
|
get path to cached PKGBUILD and package sources for the package base
|
|
|
|
Args:
|
|
package_base(str): package base name
|
|
|
|
Returns:
|
|
Path: full path to directory for specified package base cache
|
|
"""
|
|
return self.cache / package_base
|
|
|
|
def chown(self, path: Path) -> None:
|
|
"""
|
|
set owner of path recursively (from root) to root owner
|
|
|
|
Args:
|
|
path(Path): path to be chown
|
|
|
|
Raises:
|
|
InvalidPath: if path does not belong to root
|
|
"""
|
|
def set_owner(current: Path) -> None:
|
|
uid, gid = self.owner(current)
|
|
if uid == root_uid and gid == root_gid:
|
|
return
|
|
os.chown(current, root_uid, root_gid, follow_symlinks=False)
|
|
|
|
if self.root not in path.parents:
|
|
raise InvalidPath(path, self.root)
|
|
root_uid, root_gid = self.root_owner
|
|
while path != self.root:
|
|
set_owner(path)
|
|
path = path.parent
|
|
|
|
def tree_clear(self, package_base: str) -> None:
|
|
"""
|
|
clear package specific files
|
|
|
|
Args:
|
|
package_base(str): package base name
|
|
"""
|
|
for directory in (
|
|
self.cache_for(package_base),
|
|
):
|
|
shutil.rmtree(directory, ignore_errors=True)
|
|
|
|
def tree_create(self) -> None:
|
|
"""
|
|
create ahriman working tree
|
|
"""
|
|
for directory in (
|
|
self.cache,
|
|
self.chroot,
|
|
self.packages,
|
|
self.repository,
|
|
):
|
|
directory.mkdir(mode=0o755, parents=True, exist_ok=True)
|
|
self.chown(directory)
|