[arch] feature: allowing AUR packages to be installed when bauh is launched by the root user

This commit is contained in:
Vinicius Moreira
2021-12-07 15:41:02 -03:00
parent afcc94b934
commit 6d3917ee99
21 changed files with 330 additions and 158 deletions

View File

@@ -10,12 +10,14 @@ import traceback
from datetime import datetime
from math import floor
from pathlib import Path
from pwd import getpwnam
from threading import Thread
from typing import List, Set, Type, Tuple, Dict, Iterable, Optional, Collection
import requests
from dateutil.parser import parse as parse_date
from bauh import __app_name__
from bauh.api.abstract.controller import SearchResult, SoftwareManager, ApplicationContext, UpgradeRequirements, \
TransactionResult, SoftwareAction
from bauh.api.abstract.disk import DiskCacheLoader
@@ -25,20 +27,19 @@ from bauh.api.abstract.model import PackageUpdate, PackageHistory, SoftwarePacka
from bauh.api.abstract.view import MessageType, FormComponent, InputOption, SingleSelectComponent, SelectViewType, \
ViewComponent, PanelComponent, MultipleSelectComponent, TextInputComponent, TextInputType, \
FileChooserComponent, TextComponent
from bauh.api.paths import TEMP_DIR
from bauh.api.exception import NoInternetException
from bauh.api.paths import TEMP_DIR
from bauh.commons import system
from bauh.api import user
from bauh.commons.boot import CreateConfigFile
from bauh.commons.category import CategoriesDownloader
from bauh.commons.html import bold
from bauh.commons.system import SystemProcess, ProcessHandler, new_subprocess, run_cmd, SimpleProcess
from bauh.commons.util import datetime_as_milis
from bauh.commons.view_utils import new_select
from bauh.gems.arch import aur, pacman, makepkg, message, confirmation, disk, git, \
from bauh.gems.arch import aur, pacman, message, confirmation, disk, git, \
gpg, URL_CATEGORIES_FILE, CATEGORIES_FILE_PATH, CUSTOM_MAKEPKG_FILE, SUGGESTIONS_FILE, \
get_icon_path, database, mirrors, sorting, cpu_manager, UPDATES_IGNORED_FILE, \
ARCH_CONFIG_DIR, EDITABLE_PKGBUILDS_FILE, URL_GPG_SERVERS, BUILD_DIR, rebuild_detector
ARCH_CONFIG_DIR, EDITABLE_PKGBUILDS_FILE, URL_GPG_SERVERS, rebuild_detector, makepkg, sshell
from bauh.gems.arch.aur import AURClient
from bauh.gems.arch.config import get_build_dir, ArchConfigManager
from bauh.gems.arch.dependencies import DependenciesAnalyser
@@ -48,6 +49,7 @@ from bauh.gems.arch.mapper import AURDataMapper
from bauh.gems.arch.model import ArchPackage
from bauh.gems.arch.output import TransactionStatusHandler
from bauh.gems.arch.pacman import RE_DEP_OPERATORS
from bauh.gems.arch.proc_util import write_as_user
from bauh.gems.arch.updates import UpdatesSummarizer
from bauh.gems.arch.worker import AURIndexUpdater, ArchDiskCacheUpdater, ArchCompilationOptimizer, RefreshMirrors, \
SyncDatabases
@@ -247,6 +249,7 @@ class ArchManager(SoftwareManager):
self.index_aur = None
self.re_file_conflict = re.compile(r'[\w\d\-_.]+:')
self.disk_cache_updater = disk_cache_updater
self.pkgbuilder_user: Optional[str] = f'{__app_name__}-aur' if context.root_user else None
@staticmethod
def get_aur_semantic_search_map() -> Dict[str, str]:
@@ -673,32 +676,39 @@ class ArchManager(SoftwareManager):
return SearchResult(pkgs, None, len(pkgs))
def _downgrade_aur_pkg(self, context: TransactionContext):
def _downgrade_aur_pkg(self, context: TransactionContext) -> bool:
if not self.add_package_builder_user(context.handler):
return False
if context.commit:
self.logger.info("Package '{}' current commit {}".format(context.name, context.commit))
else:
self.logger.warning("Package '{}' has no commit associated with it. Downgrading will only compare versions.".format(context.name))
context.build_dir = '{}/build_{}'.format(get_build_dir(context.config), int(time.time()))
context.build_dir = f'{get_build_dir(context.config, self.pkgbuilder_user)}/build_{int(time.time())}'
try:
if not os.path.exists(context.build_dir):
build_dir = context.handler.handle(SystemProcess(new_subprocess(['mkdir', '-p', context.build_dir])))
build_dir, build_dir_error = sshell.mkdir(dir_path=context.build_dir, custom_user=self.pkgbuilder_user)
if build_dir:
if not build_dir:
context.watcher.print(build_dir_error)
else:
context.handler.watcher.change_progress(10)
base_name = context.get_base_name()
context.watcher.change_substatus(self.i18n['arch.clone'].format(bold(context.name)))
cloned, _ = context.handler.handle_simple(git.clone_as_process(url=URL_GIT.format(base_name), cwd=context.build_dir))
clone_dir = f'{context.build_dir}/{base_name}'
cloned, _ = context.handler.handle_simple(git.clone(url=URL_GIT.format(base_name),
target_dir=clone_dir,
custom_user=self.pkgbuilder_user))
context.watcher.change_progress(30)
if cloned:
context.watcher.change_substatus(self.i18n['arch.downgrade.reading_commits'])
clone_path = '{}/{}'.format(context.build_dir, base_name)
context.project_dir = clone_path
srcinfo_path = '{}/.SRCINFO'.format(clone_path)
context.project_dir = clone_dir
srcinfo_path = f'{clone_dir}/.SRCINFO'
logs = git.log_shas_and_timestamps(clone_path)
logs = git.log_shas_and_timestamps(clone_dir)
context.watcher.change_progress(40)
if not logs or len(logs) == 1:
@@ -719,7 +729,7 @@ class ArchManager(SoftwareManager):
self.logger.warning("Could not find '{}' target commit to revert to".format(context.name))
else:
context.watcher.change_substatus(self.i18n['arch.downgrade.version_found'])
checkout_proc = new_subprocess(['git', 'checkout', target_commit], cwd=clone_path)
checkout_proc = new_subprocess(['git', 'checkout', target_commit], cwd=clone_dir, custom_user=self.pkgbuilder_user)
if not context.handler.handle(SystemProcess(checkout_proc, check_error_output=False)):
context.watcher.print("Could not rollback to current version's commit")
return False
@@ -738,7 +748,7 @@ class ArchManager(SoftwareManager):
with open(srcinfo_path) as f:
pkgsrc = aur.map_srcinfo(string=f.read(), pkgname=context.name, fields=srcfields)
reset_proc = new_subprocess(['git', 'reset', '--hard', commit], cwd=clone_path)
reset_proc = new_subprocess(['git', 'reset', '--hard', commit], cwd=clone_dir, custom_user=self.pkgbuilder_user)
if not context.handler.handle(SystemProcess(reset_proc, check_error_output=False)):
context.handler.watcher.print('Could not downgrade anymore. Aborting...')
return False
@@ -752,18 +762,18 @@ class ArchManager(SoftwareManager):
if commit_found:
context.watcher.change_substatus(self.i18n['arch.downgrade.version_found'])
checkout_proc = new_subprocess(['git', 'checkout', commit_found], cwd=clone_path)
checkout_proc = new_subprocess(['git', 'checkout', commit_found], cwd=clone_dir, custom_user=self.pkgbuilder_user)
if not context.handler.handle(SystemProcess(checkout_proc, check_error_output=False)):
context.watcher.print("Could not rollback to current version's commit")
return False
reset_proc = new_subprocess(['git', 'reset', '--hard', commit_found], cwd=clone_path)
reset_proc = new_subprocess(['git', 'reset', '--hard', commit_found], cwd=clone_dir, custom_user=self.pkgbuilder_user)
if not context.handler.handle(SystemProcess(reset_proc, check_error_output=False)):
context.watcher.print("Could not downgrade to previous commit of '{}'. Aborting...".format(commit_found))
return False
break
elif current_version == context.get_version(): # current version found:
elif current_version == context.get_version():
commit_found, commit_date = commit, date
context.watcher.change_substatus(self.i18n['arch.downgrade.install_older'])
@@ -825,10 +835,11 @@ class ArchManager(SoftwareManager):
return self._install(context)
def downgrade(self, pkg: ArchPackage, root_password: str, watcher: ProcessWatcher) -> bool:
self.aur_client.clean_caches()
if not self._check_action_allowed(pkg, watcher):
if not self.check_action_allowed(pkg, watcher):
return False
self.aur_client.clean_caches()
handler = ProcessHandler(watcher)
if self._is_database_locked(handler, root_password):
@@ -857,14 +868,6 @@ class ArchManager(SoftwareManager):
if os.path.exists(pkg.get_disk_cache_path()):
shutil.rmtree(pkg.get_disk_cache_path())
def _check_action_allowed(self, pkg: ArchPackage, watcher: ProcessWatcher) -> bool:
if user.is_root() and pkg.repository == 'aur':
watcher.show_message(title=self.i18n['arch.install.aur.root_error.title'],
body=self.i18n['arch.install.aur.root_error.body'],
type_=MessageType.ERROR)
return False
return True
def _is_database_locked(self, handler: ProcessHandler, root_password: str) -> bool:
if os.path.exists('/var/lib/pacman/db.lck'):
handler.watcher.print('pacman database is locked')
@@ -1155,16 +1158,13 @@ class ArchManager(SoftwareManager):
pkg_sizes[req.pkg.name] = req.required_size
if aur_pkgs and not self._check_action_allowed(aur_pkgs[0], watcher):
return False
arch_config = self.configman.get_config()
aur_supported = bool(aur_pkgs) or aur.is_supported(arch_config)
self._sync_databases(arch_config=arch_config, aur_supported=aur_supported,
root_password=root_password, handler=handler)
if repo_pkgs:
if repo_pkgs and self.check_action_allowed(repo_pkgs[0], watcher):
if not self._upgrade_repo_pkgs(to_upgrade=[p.name for p in repo_pkgs],
to_remove={r.pkg.name for r in requirements.to_remove} if requirements.to_remove else None,
handler=handler,
@@ -1177,7 +1177,7 @@ class ArchManager(SoftwareManager):
elif requirements.to_remove and not self._remove_transaction_packages({r.pkg.name for r in requirements.to_remove}, handler, root_password):
return False
if aur_pkgs:
if aur_pkgs and self.check_action_allowed(aur_pkgs[0], watcher) and self.add_package_builder_user(handler):
watcher.change_status('{}...'.format(self.i18n['arch.upgrade.upgrade_aur_pkgs']))
self.logger.info("Retrieving the 'last_modified' field for each package to upgrade")
@@ -1581,21 +1581,21 @@ class ArchManager(SoftwareManager):
self.logger.warning("Package '{}' has no commit associated with it. Current history status may not be correct.".format(pkg.name))
arch_config = self.configman.get_config()
temp_dir = '{}/build_{}'.format(get_build_dir(arch_config), int(time.time()))
temp_dir = f'{get_build_dir(arch_config, self.pkgbuilder_user)}/build_{int(time.time())}'
try:
Path(temp_dir).mkdir(parents=True)
base_name = pkg.get_base_name()
run_cmd('git clone ' + URL_GIT.format(base_name), print_error=False, cwd=temp_dir)
clone_path = '{}/{}'.format(temp_dir, base_name)
clone_dir = f'{temp_dir}/{base_name}'
srcinfo_path = '{}/.SRCINFO'.format(clone_path)
srcinfo_path = f'{clone_dir}/.SRCINFO'
if not os.path.exists(srcinfo_path):
return PackageHistory.empyt(pkg)
logs = git.log_shas_and_timestamps(clone_path)
logs = git.log_shas_and_timestamps(clone_dir)
if logs:
srcfields = {'epoch', 'pkgver', 'pkgrel'}
@@ -1622,7 +1622,7 @@ class ArchManager(SoftwareManager):
'3_date': datetime.fromtimestamp(timestamp)}) # the number prefix is to ensure the rendering order
if idx + 1 < len(logs):
if not run_cmd('git reset --hard ' + logs[idx + 1][0], cwd=clone_path):
if not run_cmd('git reset --hard ' + logs[idx + 1][0], cwd=clone_dir):
break
return PackageHistory(pkg=pkg, history=history, pkg_status_idx=status_idx)
@@ -1738,7 +1738,7 @@ class ArchManager(SoftwareManager):
context.restabilish_progress()
return res
def _install_deps(self, context: TransactionContext, deps: List[Tuple[str, str]]) -> Iterable[str]:
def _install_deps(self, context: TransactionContext, deps: List[Tuple[str, str]]) -> Optional[Iterable[str]]:
progress_increment = int(100 / len(deps))
progress = 0
self._update_progress(context, 1)
@@ -1785,7 +1785,7 @@ class ArchManager(SoftwareManager):
pkg_sizes = pacman.map_download_sizes(repo_dep_names)
downloaded = self._download_packages(repo_dep_names, context.handler, context.root_password, pkg_sizes, multithreaded=True)
except ArchDownloadException:
return False
return None
status_handler = TransactionStatusHandler(watcher=context.watcher, i18n=self.i18n, names={*repo_dep_names},
logger=self.logger, percentage=len(repo_deps) > 1, downloading=downloaded)
@@ -1827,7 +1827,8 @@ class ArchManager(SoftwareManager):
return pkg_repos
def _pre_download_source(self, pkgname: str, project_dir: str, watcher: ProcessWatcher) -> bool:
if self.context.file_downloader.is_multithreaded():
# TODO: multi-threaded download client cannot be run as another user at the moment
if not self.context.root_user and self.context.file_downloader.is_multithreaded():
with open('{}/.SRCINFO'.format(project_dir)) as f:
srcinfo = aur.map_srcinfo(string=f.read(), pkgname=pkgname)
@@ -1839,7 +1840,7 @@ class ArchManager(SoftwareManager):
continue
else:
for f in srcinfo[attr]:
if RE_PRE_DOWNLOAD_WL_PROTOCOLS.match(f) and not RE_PRE_DOWNLOAD_BL_EXT.match(f):
if RE_PRE_DOWNLOAD_WL_PROTOCOLS.match(f) and not RE_PRE_DOWNLOAD_BL_EXT.match(f):
pre_download_files.append(f)
if pre_download_files:
@@ -1872,10 +1873,11 @@ class ArchManager(SoftwareManager):
deny_button=False)
if pkgbuild_input.get_value() != pkgbuild:
with open(pkgbuild_path, 'w+') as f:
f.write(pkgbuild_input.get_value())
if not write_as_user(content=pkgbuild_input.get_value(), file_path=pkgbuild_path, user=self.pkgbuilder_user):
return False
return makepkg.update_srcinfo('/'.join(pkgbuild_path.split('/')[0:-1]))
return makepkg.update_srcinfo(project_dir='/'.join(pkgbuild_path.split('/')[0:-1]),
custom_user=self.pkgbuilder_user)
return False
@@ -1897,9 +1899,10 @@ class ArchManager(SoftwareManager):
if self._ask_for_pkgbuild_edition(pkgname=context.name,
arch_config=context.config,
watcher=context.watcher,
pkgbuild_path='{}/PKGBUILD'.format(context.project_dir)):
pkgbuild_path=f'{context.project_dir}/PKGBUILD'):
context.pkgbuild_edited = True
srcinfo = aur.map_srcinfo(string=makepkg.gen_srcinfo(context.project_dir), pkgname=context.name)
srcinfo = aur.map_srcinfo(string=makepkg.gen_srcinfo(build_dir=context.project_dir, custom_user=self.pkgbuilder_user),
pkgname=context.name)
if srcinfo:
context.name = srcinfo['pkgname']
@@ -1915,12 +1918,14 @@ class ArchManager(SoftwareManager):
setattr(context.pkg, pkgattr, srcinfo.get(srcattr, getattr(context.pkg, pkgattr)))
def _read_srcinfo(self, context: TransactionContext) -> str:
src_path = '{}/.SRCINFO'.format(context.project_dir)
if not os.path.exists(src_path):
srcinfo = makepkg.gen_srcinfo(context.project_dir, context.custom_pkgbuild_path)
src_path = f'{context.project_dir}/.SRCINFO'
with open(src_path, 'w+') as f:
f.write(srcinfo)
if not os.path.exists(src_path):
srcinfo = makepkg.gen_srcinfo(build_dir=context.project_dir,
custom_pkgbuild_path=context.custom_pkgbuild_path,
custom_user=self.pkgbuilder_user)
write_as_user(content=srcinfo, file_path=src_path, user=self.pkgbuilder_user)
else:
with open(src_path) as f:
srcinfo = f.read()
@@ -1947,10 +1952,11 @@ class ArchManager(SoftwareManager):
cpus_changed, cpu_prev_governors = cpu_manager.set_all_cpus_to('performance', context.root_password, self.logger)
try:
pkgbuilt, output = makepkg.make(pkgdir=context.project_dir,
optimize=optimize,
handler=context.handler,
custom_pkgbuild=context.custom_pkgbuild_path)
pkgbuilt, output = makepkg.build(pkgdir=context.project_dir,
optimize=optimize,
handler=context.handler,
custom_pkgbuild=context.custom_pkgbuild_path,
custom_user=self.pkgbuilder_user)
finally:
if cpus_changed and cpu_prev_governors:
self.logger.info("Restoring CPU governors")
@@ -1998,7 +2004,10 @@ class ArchManager(SoftwareManager):
def __fill_aur_output_files(self, context: TransactionContext):
self.logger.info("Determining output files of '{}'".format(context.name))
context.watcher.change_substatus(self.i18n['arch.aur.build.list_output'])
output_files = {f for f in makepkg.list_output_files(context.project_dir, context.custom_pkgbuild_path) if os.path.isfile(f)}
output_files = {f for f in makepkg.list_output_files(project_dir=context.project_dir,
custom_pkgbuild_path=context.custom_pkgbuild_path,
custom_user=self.pkgbuilder_user) if os.path.isfile(f)}
if output_files:
context.install_files = output_files
@@ -2013,7 +2022,8 @@ class ArchManager(SoftwareManager):
file_to_install = gen_file[0]
if len(gen_file) > 1:
srcinfo = aur.map_srcinfo(string=makepkg.gen_srcinfo(context.project_dir), pkgname=context.name)
srcinfo = aur.map_srcinfo(string=makepkg.gen_srcinfo(build_dir=context.project_dir, custom_user=self.pkgbuilder_user),
pkgname=context.name)
pkgver = '-{}'.format(srcinfo['pkgver']) if srcinfo.get('pkgver') else ''
pkgrel = '-{}'.format(srcinfo['pkgrel']) if srcinfo.get('pkgrel') else ''
arch = '-{}'.format(srcinfo['arch']) if srcinfo.get('arch') else ''
@@ -2134,11 +2144,12 @@ class ArchManager(SoftwareManager):
if not handled_deps:
return False
check_res = makepkg.check(context.project_dir,
check_res = makepkg.check(project_dir=context.project_dir,
optimize=bool(context.config['optimize']),
missing_deps=False,
handler=context.handler,
custom_pkgbuild=context.custom_pkgbuild_path)
custom_pkgbuild=context.custom_pkgbuild_path,
custom_user=self.pkgbuilder_user)
if check_res:
if check_res.get('gpg_key'):
@@ -2502,23 +2513,30 @@ class ArchManager(SoftwareManager):
return False
def _install_from_aur(self, context: TransactionContext) -> bool:
if not context.dependency and not self.add_package_builder_user(context.handler):
return False
self._optimize_makepkg(context.config, context.watcher)
context.build_dir = '{}/build_{}'.format(get_build_dir(context.config), int(time.time()))
context.build_dir = f'{get_build_dir(context.config, self.pkgbuilder_user)}/build_{int(time.time())}'
try:
if not os.path.exists(context.build_dir):
build_dir = context.handler.handle(SystemProcess(new_subprocess(['mkdir', '-p', context.build_dir])))
build_dir, build_dir_error = sshell.mkdir(dir_path=context.build_dir, custom_user=self.pkgbuilder_user)
self._update_progress(context, 10)
if build_dir:
if not build_dir:
context.watcher.print(build_dir_error)
else:
base_name = context.get_base_name()
context.watcher.change_substatus(self.i18n['arch.clone'].format(bold(base_name)))
cloned = context.handler.handle_simple(git.clone_as_process(url=URL_GIT.format(base_name), cwd=context.build_dir, depth=1))
clone_dir = f'{context.build_dir}/{base_name}'
cloned = context.handler.handle_simple(git.clone(url=URL_GIT.format(base_name), target_dir=clone_dir,
depth=1, custom_user=self.pkgbuilder_user))
if cloned:
self._update_progress(context, 40)
context.project_dir = '{}/{}'.format(context.build_dir, base_name)
context.project_dir = clone_dir
return self._build(context)
finally:
if os.path.exists(context.build_dir) and context.config['aur_remove_build_dir']:
@@ -2544,10 +2562,10 @@ class ArchManager(SoftwareManager):
ArchCompilationOptimizer(i18n=self.i18n, logger=self.context.logger, taskman=TaskManager()).optimize()
def install(self, pkg: ArchPackage, root_password: str, disk_loader: Optional[DiskCacheLoader], watcher: ProcessWatcher, context: TransactionContext = None) -> TransactionResult:
self.aur_client.clean_caches()
if not self.check_action_allowed(pkg, watcher):
return TransactionResult.fail()
if not self._check_action_allowed(pkg, watcher):
return TransactionResult(success=False, installed=[], removed=[])
self.aur_client.clean_caches()
handler = ProcessHandler(watcher) if not context else context.handler
@@ -2936,7 +2954,7 @@ class ArchManager(SoftwareManager):
capitalize_label=False),
FileChooserComponent(id_='aur_build_dir',
label=self.i18n['arch.config.aur_build_dir'],
tooltip=self.i18n['arch.config.aur_build_dir.tip'].format(BUILD_DIR),
tooltip=self.i18n['arch.config.aur_build_dir.tip'].format(get_build_dir(arch_config, self.pkgbuilder_user)),
max_width=max_width,
file_path=arch_config['aur_build_dir'],
capitalize_label=False,
@@ -3397,7 +3415,8 @@ class ArchManager(SoftwareManager):
deny_label=self.i18n['arch.aur.sync.several_names.popup.bt_selected']):
context.pkgs_to_build = {context.name, *select.get_selected_values()}
pkgbuild_path = '{}/PKGBUILD'.format(context.project_dir)
pkgbuild_path = f'{context.project_dir}/PKGBUILD'
with open(pkgbuild_path) as f:
current_pkgbuild = f.read()
@@ -3407,16 +3426,22 @@ class ArchManager(SoftwareManager):
names = context.name
context.pkgs_to_build = {context.name}
new_pkgbuild = RE_PKGBUILD_PKGNAME.sub("pkgname={}".format(names), current_pkgbuild)
custom_pkgbuild_path = pkgbuild_path + '_CUSTOM'
new_pkgbuild = RE_PKGBUILD_PKGNAME.sub(f"pkgname={names}", current_pkgbuild)
custom_pkgbuild_path = f'{pkgbuild_path}_CUSTOM'
with open(custom_pkgbuild_path, 'w+') as f:
f.write(new_pkgbuild)
if not write_as_user(content=new_pkgbuild,
file_path=custom_pkgbuild_path,
user=self.pkgbuilder_user):
self.logger.error(f"Could not write edited PKGBUILD to '{custom_pkgbuild_path}'")
return
new_srcinfo = makepkg.gen_srcinfo(context.project_dir, custom_pkgbuild_path)
new_srcinfo = makepkg.gen_srcinfo(build_dir=context.project_dir,
custom_pkgbuild_path=custom_pkgbuild_path,
custom_user=self.pkgbuilder_user)
with open('{}/.SRCINFO'.format(context.project_dir), 'w+') as f:
f.write(new_srcinfo)
srcinfo_path = f'{context.project_dir}/.SRCINFO'
if not write_as_user(content=new_srcinfo, file_path=srcinfo_path, user=self.pkgbuilder_user):
self.logger.warning(f"Could not write the updated .SRCINFO content to '{srcinfo_path}'")
return custom_pkgbuild_path
@@ -3499,3 +3524,47 @@ class ArchManager(SoftwareManager):
pkg.update_state()
return True
def check_action_allowed(self, pkg: ArchPackage, watcher: Optional[ProcessWatcher]) -> bool:
if self.context.root_user and pkg.repository == 'aur':
if not shutil.which('useradd'):
if watcher:
watcher.show_message(title=self.i18n['error'].capitalize(),
type_=MessageType.ERROR,
body=self.i18n['arch.aur.error.missing_root_dep'].format(dep=bold('useradd'),
aur=bold('AUR'),
root=bold('root')))
return False
if not shutil.which('runuser'):
if watcher:
watcher.show_message(title=self.i18n['error'].capitalize(),
type_=MessageType.ERROR,
body=self.i18n['arch.aur.error.missing_root_dep'].format(dep=bold('runuser'),
aur=bold('AUR'),
root=bold('root')))
return False
return True
def add_package_builder_user(self, handler: ProcessHandler) -> bool:
if self.context.root_user and self.pkgbuilder_user:
try:
getpwnam(self.pkgbuilder_user)
return True
except KeyError:
self.logger.warning(f"Package builder user '{self.pkgbuilder_user}' does not exist")
self.logger.info(f"Adding the package builder user '{self.pkgbuilder_user}'")
added, output = handler.handle_simple(SimpleProcess(cmd=['useradd', self.pkgbuilder_user], shell=True))
if not added:
output_log = "Command output: {}".format(output.replace('\n', ' ') if output else '(no output)')
self.logger.error(f"Could not add the package builder user '{self.pkgbuilder_user}'. {output_log}")
handler.watcher.show_message(title=self.i18n['error'].capitalize(),
type_=MessageType.ERROR,
body=self.i18n['arch.aur.error.add_builder_user'].format(user=bold(self.pkgbuilder_user),
aur=bold('AUR')))
return added
return True