index : archinstall32 | |
Archlinux32 installer | gitolite user |
summaryrefslogtreecommitdiff |
author | Andreas Baumann <mail@andreasbaumann.cc> | 2024-05-10 15:56:28 +0200 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2024-05-10 15:56:28 +0200 |
commit | 683da22298abbd90f51d4dd38a7ec4b0dfb04555 (patch) | |
tree | ec2ac04967f9277df038edc362201937b331abe5 /archinstall/lib/pacman | |
parent | af7ab9833c9f9944874f0162ae0975175ddc628d (diff) | |
parent | 3381cd55673e5105697d354cf4a1be9a7bcef062 (diff) |
-rw-r--r-- | archinstall/lib/pacman/__init__.py | 88 | ||||
-rw-r--r-- | archinstall/lib/pacman/config.py | 44 | ||||
-rw-r--r-- | archinstall/lib/pacman/repo.py | 5 |
diff --git a/archinstall/lib/pacman/__init__.py b/archinstall/lib/pacman/__init__.py new file mode 100644 index 00000000..6478f0cc --- /dev/null +++ b/archinstall/lib/pacman/__init__.py @@ -0,0 +1,88 @@ +from pathlib import Path +import time +import re +from typing import TYPE_CHECKING, Any, List, Callable, Union +from shutil import copy2 + +from ..general import SysCommand +from ..output import warn, error, info +from .repo import Repo +from .config import Config +from ..exceptions import RequirementError +from ..plugins import plugins + +if TYPE_CHECKING: + _: Any + + +class Pacman: + + def __init__(self, target: Path, silent: bool = False): + self.synced = False + self.silent = silent + self.target = target + + @staticmethod + def run(args :str, default_cmd :str = 'pacman') -> SysCommand: + """ + A centralized function to call `pacman` from. + It also protects us from colliding with other running pacman sessions (if used locally). + The grace period is set to 10 minutes before exiting hard if another pacman instance is running. + """ + pacman_db_lock = Path('/var/lib/pacman/db.lck') + + if pacman_db_lock.exists(): + warn(_('Pacman is already running, waiting maximum 10 minutes for it to terminate.')) + + started = time.time() + while pacman_db_lock.exists(): + time.sleep(0.25) + + if time.time() - started > (60 * 10): + error(_('Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall.')) + exit(1) + + return SysCommand(f'{default_cmd} {args}') + + def ask(self, error_message: str, bail_message: str, func: Callable, *args, **kwargs): + while True: + try: + func(*args, **kwargs) + break + except Exception as err: + error(f'{error_message}: {err}') + if not self.silent and input('Would you like to re-try this download? (Y/n): ').lower().strip() in 'y': + continue + raise RequirementError(f'{bail_message}: {err}') + + def sync(self): + if self.synced: + return + self.ask( + 'Could not sync a new package database', + 'Could not sync mirrors', + self.run, + '-Syy', + default_cmd='/usr/bin/pacman' + ) + self.synced = True + + def strap(self, packages: Union[str, List[str]]): + self.sync() + if isinstance(packages, str): + packages = [packages] + + for plugin in plugins.values(): + if hasattr(plugin, 'on_pacstrap'): + if (result := plugin.on_pacstrap(packages)): + packages = result + + info(f'Installing packages: {packages}') + + self.ask( + 'Could not strap in packages', + 'Pacstrap failed. See /var/log/archinstall/install.log or above message for error details', + SysCommand, + f'/usr/bin/pacstrap -C /etc/pacman.conf -K {self.target} {" ".join(packages)} --noconfirm', + peek_output=True + ) diff --git a/archinstall/lib/pacman/config.py b/archinstall/lib/pacman/config.py new file mode 100644 index 00000000..6686f4a9 --- /dev/null +++ b/archinstall/lib/pacman/config.py @@ -0,0 +1,44 @@ +import re +from pathlib import Path +from shutil import copy2 +from typing import List + +from .repo import Repo + + +class Config: + def __init__(self, target: Path): + self.path = Path("/etc") / "pacman.conf" + self.chroot_path = target / "etc" / "pacman.conf" + self.repos: List[Repo] = [] + + def enable(self, repo: Repo): + self.repos.append(repo) + + def apply(self): + if not self.repos: + return + + if Repo.Testing in self.repos: + if Repo.Multilib in self.repos: + repos_pattern = f'({Repo.Multilib.value}|.+-{Repo.Testing.value})' + else: + repos_pattern = f'(?!{Repo.Multilib.value}).+-{Repo.Testing.value}' + else: + repos_pattern = Repo.Multilib.value + + pattern = re.compile(rf"^#\s*\[{repos_pattern}\]$") + + lines = iter(self.path.read_text().splitlines(keepends=True)) + with open(self.path, 'w') as f: + for line in lines: + if pattern.match(line): + # Uncomment this line and the next. + f.write(line.lstrip('#')) + f.write(next(lines).lstrip('#')) + else: + f.write(line) + + def persist(self): + if self.repos: + copy2(self.path, self.chroot_path) diff --git a/archinstall/lib/pacman/repo.py b/archinstall/lib/pacman/repo.py new file mode 100644 index 00000000..7a461431 --- /dev/null +++ b/archinstall/lib/pacman/repo.py @@ -0,0 +1,5 @@ +from enum import Enum + +class Repo(Enum): + Multilib = "multilib" + Testing = "testing" |