Check if pacman is available (#958)

* Check if pacman is available

* Update pacman call

* Added a graceful wait to `run_pacman`

* Fix flake8

Co-authored-by: Daniel Girtler <girtler.daniel@gmail.com>
Co-authored-by: Anton Hvornum <anton.feeds+github@gmail.com>
This commit is contained in:
Daniel 2022-02-18 21:33:28 +11:00 committed by GitHub
parent 62a6aec197
commit 4b3b21ed75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 8 deletions

View File

@ -30,6 +30,8 @@ __packages__ = ["base", "base-devel", "linux-firmware", "linux", "linux-lts", "l
# Additional packages that are installed if the user is running the Live ISO with accessibility tools enabled # Additional packages that are installed if the user is running the Live ISO with accessibility tools enabled
__accessibility_packages__ = ["brltty", "espeakup", "alsa-utils"] __accessibility_packages__ = ["brltty", "espeakup", "alsa-utils"]
from .pacman import run_pacman
class InstallationFile: class InstallationFile:
def __init__(self, installation :'Installer', filename :str, owner :str, mode :str = "w"): def __init__(self, installation :'Installer', filename :str, owner :str, mode :str = "w"):
@ -352,7 +354,7 @@ class Installer:
self.log(f'Installing packages: {packages}', level=logging.INFO) self.log(f'Installing packages: {packages}', level=logging.INFO)
if (sync_mirrors := SysCommand('/usr/bin/pacman -Syy')).exit_code == 0: if (sync_mirrors := run_pacman('-Syy', default_cmd='/usr/bin/pacman')).exit_code == 0:
if (pacstrap := SysCommand(f'/usr/bin/pacstrap -C /etc/pacman.conf {self.target} {" ".join(packages)} --noconfirm', peak_output=True)).exit_code == 0: if (pacstrap := SysCommand(f'/usr/bin/pacstrap -C /etc/pacman.conf {self.target} {" ".join(packages)} --noconfirm', peak_output=True)).exit_code == 0:
return True return True
else: else:

View File

@ -7,6 +7,7 @@ from typing import Union, Dict, Any, List
from .exceptions import HardwareIncompatibilityError from .exceptions import HardwareIncompatibilityError
from .general import SysCommand from .general import SysCommand
from .output import log from .output import log
from .pacman import run_pacman
from .storage import storage from .storage import storage
@ -32,7 +33,7 @@ def list_interfaces(skip_loopback :bool = True) -> Dict[str, str]:
def check_mirror_reachable() -> bool: def check_mirror_reachable() -> bool:
log("Testing connectivity to the Arch Linux mirrors ...", level=logging.INFO) log("Testing connectivity to the Arch Linux mirrors ...", level=logging.INFO)
if SysCommand("pacman -Sy").exit_code == 0: if run_pacman("-Sy").exit_code == 0:
return True return True
elif os.geteuid() != 0: elif os.geteuid() != 0:
@ -42,7 +43,7 @@ def check_mirror_reachable() -> bool:
def update_keyring() -> bool: def update_keyring() -> bool:
log("Updating archlinux-keyring ...", level=logging.INFO) log("Updating archlinux-keyring ...", level=logging.INFO)
if SysCommand("pacman -Sy --noconfirm archlinux-keyring").exit_code == 0: if run_pacman("-Sy --noconfirm archlinux-keyring").exit_code == 0:
return True return True
elif os.geteuid() != 0: elif os.geteuid() != 0:

View File

@ -4,8 +4,8 @@ import urllib.request
from typing import Dict, Any, Tuple, List from typing import Dict, Any, Tuple, List
from ..exceptions import PackageError, SysCallError from ..exceptions import PackageError, SysCallError
from ..general import SysCommand
from ..models.dataclasses import PackageSearch, PackageSearchResult, LocalPackage from ..models.dataclasses import PackageSearch, PackageSearchResult, LocalPackage
from ..pacman import run_pacman
BASE_URL_PKG_SEARCH = 'https://archlinux.org/packages/search/json/?name={package}' BASE_URL_PKG_SEARCH = 'https://archlinux.org/packages/search/json/?name={package}'
# BASE_URL_PKG_CONTENT = 'https://archlinux.org/packages/search/json/' # BASE_URL_PKG_CONTENT = 'https://archlinux.org/packages/search/json/'
@ -98,7 +98,7 @@ def validate_package_list(packages :list) -> Tuple[list, list]:
def installed_package(package :str) -> LocalPackage: def installed_package(package :str) -> LocalPackage:
package_info = {} package_info = {}
try: try:
for line in SysCommand(f"pacman -Q --info {package}"): for line in run_pacman(f"-Q --info {package}"):
if b':' in line: if b':' in line:
key, value = line.decode().split(':', 1) key, value = line.decode().split(':', 1)
package_info[key.strip().lower().replace(' ', '_')] = value.strip() package_info[key.strip().lower().replace(' ', '_')] = value.strip()

28
archinstall/lib/pacman.py Normal file
View File

@ -0,0 +1,28 @@
import logging
import pathlib
import time
from .general import SysCommand
from .output import log
def run_pacman(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 = pathlib.Path('/var/lib/pacman/db.lck')
if pacman_db_lock.exists():
log(_('Pacman is already running, waiting maximum 10 minutes for it to terminate.'), level=logging.WARNING, fg="red")
started = time.time()
while pacman_db_lock.exists():
time.sleep(0.25)
if time.time() - started > (60 * 10):
log(_('Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall.'), level=logging.WARNING, fg="red")
exit(1)
return SysCommand(f'{default_cmd} {args}')