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
__accessibility_packages__ = ["brltty", "espeakup", "alsa-utils"]
from .pacman import run_pacman
class InstallationFile:
def __init__(self, installation :'Installer', filename :str, owner :str, mode :str = "w"):
@ -292,7 +294,7 @@ class Installer:
def enable_multilib_repository(self):
# Set up a regular expression pattern of a commented line containing 'multilib' within []
pattern = re.compile("^#\\[.*multilib.*\\]$")
# This is used to track if the previous line is a match, so we end up uncommenting the line after the block.
matched = False
@ -318,7 +320,7 @@ class Installer:
def enable_testing_repositories(self, enable_multilib_testing=False):
# Set up a regular expression pattern of a commented line containing 'testing' within []
pattern = re.compile("^#\\[.*testing.*\\]$")
# This is used to track if the previous line is a match, so we end up uncommenting the line after the block.
matched = False
@ -352,7 +354,7 @@ class Installer:
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:
return True
else:

View File

@ -7,6 +7,7 @@ from typing import Union, Dict, Any, List
from .exceptions import HardwareIncompatibilityError
from .general import SysCommand
from .output import log
from .pacman import run_pacman
from .storage import storage
@ -32,7 +33,7 @@ def list_interfaces(skip_loopback :bool = True) -> Dict[str, str]:
def check_mirror_reachable() -> bool:
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
elif os.geteuid() != 0:
@ -42,9 +43,9 @@ def check_mirror_reachable() -> bool:
def update_keyring() -> bool:
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
elif os.geteuid() != 0:
log("update_keyring() uses 'pacman -Sy archlinux-keyring' which requires root.", level=logging.ERROR, fg="red")

View File

@ -4,8 +4,8 @@ import urllib.request
from typing import Dict, Any, Tuple, List
from ..exceptions import PackageError, SysCallError
from ..general import SysCommand
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_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:
package_info = {}
try:
for line in SysCommand(f"pacman -Q --info {package}"):
for line in run_pacman(f"-Q --info {package}"):
if b':' in line:
key, value = line.decode().split(':', 1)
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}')