diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1bcfa425..4003fad3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,6 +40,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- upgrading firstly the keyring packages declared in **SyncFirst** (**/etc/pacman.conf**) to avoid pacman downloading issues
- only removing packages after downloading the required ones
- "Multi-threaded download (repositories)" is not the default behavior anymore (current pacman download approach is faster). If your settings has this property set as 'Yes', just change it to 'No'.
+ - preventing a possible error when the optional deps of a given package cannot be found
- AUR:
- caching the PKGBUILD file used for the package installation/upgrade/downgrade (**~/.cache/bauh/arch/installed/$pkgname/PKGBUILD**)
- new settings property **aur_build_dir** -> it allows to define a custom build dir.
@@ -47,7 +48,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- new settings property **aur_remove_build_dir** -> it defines if a package's generated build directory should be removed after the operation is finished (installation, upgrading, ...). Default: true
- - preventing a possible error when the optional deps of a given package cannot be found
+ - new settings property **aur_build_only_chosen**: some AUR packages have a common file definition declaring several packages to be built. When this property is 'true' only the package the user select to install will be built (unless its name is different from those declared in the PKGBUILD base). With a 'null' value a popup asking if the user wants to build all of them will be displayed. 'false' will build and install all packages. Default: true.
+
+
+
- Flatpak
- creating the exports path **~/.local/share/flatpak/exports/share** (if it does not exist) and adding it to install/upgrade/downgrade/remove commands path to prevent warning messages. [#128](https://github.com/vinifmor/bauh/issues/128)
diff --git a/README.md b/README.md
index 7077bead..a7ac525d 100644
--- a/README.md
+++ b/README.md
@@ -196,6 +196,7 @@ automatch_providers: true # if a possible provider for a given package dependen
edit_aur_pkgbuild: false # if the AUR PKGBUILD file should be displayed for edition before the make process. true (PKGBUILD will always be displayed for edition), false (PKGBUILD never will be displayed), null (a popup will ask if the user want to edit the PKGBUILD). Default: false.
aur_build_dir: null # defines a custom build directory for AUR packages (a null value will point to /tmp/bauh/arch (non-root user) or /tmp/bauh_root/arch (root user)). Default: null.
aur_remove_build_dir: true # it defines if a package's generated build directory should be removed after the operation is finished (installation, upgrading, ...). Options: true, false (default: true).
+aur_build_only_chosen : true # some AUR packages have a common file definition declaring several packages to be built. When this property is 'true' only the package the user select to install will be built (unless its name is different from those declared in the PKGBUILD base). With a 'null' value a popup asking if the user wants to build all of them will be displayed. 'false' will build and install all packages. Default: true.
```
- Required dependencies:
- **pacman**
diff --git a/bauh/commons/system.py b/bauh/commons/system.py
index 719b6f25..08f4bc4a 100644
--- a/bauh/commons/system.py
+++ b/bauh/commons/system.py
@@ -164,8 +164,9 @@ class ProcessHandler:
return process.subproc.returncode is None or process.subproc.returncode == 0
- def handle_simple(self, proc: SimpleProcess, output_handler=None) -> Tuple[bool, str]:
- self._notify_watcher((proc.instance.args if isinstance(proc.instance.args, str) else ' '.join(proc.instance.args)) + '\n')
+ def handle_simple(self, proc: SimpleProcess, output_handler=None, notify_watcher: bool = True) -> Tuple[bool, str]:
+ if notify_watcher:
+ self._notify_watcher((proc.instance.args if isinstance(proc.instance.args, str) else ' '.join(proc.instance.args)) + '\n')
output = StringIO()
for o in proc.instance.stdout:
@@ -179,8 +180,9 @@ class ProcessHandler:
if line:
if output_handler:
output_handler(line)
-
- self._notify_watcher(line)
+
+ if notify_watcher:
+ self._notify_watcher(line)
proc.instance.wait()
output.seek(0)
diff --git a/bauh/gems/arch/aur.py b/bauh/gems/arch/aur.py
index adfb54c6..947f6f76 100644
--- a/bauh/gems/arch/aur.py
+++ b/bauh/gems/arch/aur.py
@@ -46,7 +46,7 @@ def map_pkgbuild(pkgbuild: str) -> dict:
return {attr: val.replace('"', '').replace("'", '').replace('(', '').replace(')', '') for attr, val in re.findall(r'\n(\w+)=(.+)', pkgbuild)}
-def map_srcinfo(string: str, pkgname: str, fields: Set[str] = None) -> dict:
+def map_srcinfo(string: str, pkgname: Optional[str], fields: Set[str] = None) -> dict:
subinfos, subinfo = [], {}
key_fields = {'pkgname', 'pkgbase'}
@@ -72,7 +72,7 @@ def map_srcinfo(string: str, pkgname: str, fields: Set[str] = None) -> dict:
pkgnames = {s['pkgname'] for s in subinfos if 'pkgname' in s}
return merge_subinfos(subinfos=subinfos,
- pkgname=None if (len(pkgnames) == 1 or pkgname not in pkgnames) else pkgname,
+ pkgname=None if (not pkgname or len(pkgnames) == 1 or pkgname not in pkgnames) else pkgname,
fields=fields)
diff --git a/bauh/gems/arch/config.py b/bauh/gems/arch/config.py
index d95ae12c..80f412d8 100644
--- a/bauh/gems/arch/config.py
+++ b/bauh/gems/arch/config.py
@@ -17,7 +17,8 @@ def read_config(update_file: bool = False) -> dict:
'automatch_providers': True,
'edit_aur_pkgbuild': False,
'aur_build_dir': None,
- 'aur_remove_build_dir': True}
+ 'aur_remove_build_dir': True,
+ 'aur_build_only_chosen': True}
return read(CONFIG_FILE, template, update_file=update_file)
diff --git a/bauh/gems/arch/controller.py b/bauh/gems/arch/controller.py
index 9339ebe3..83ec271f 100644
--- a/bauh/gems/arch/controller.py
+++ b/bauh/gems/arch/controller.py
@@ -43,6 +43,7 @@ from bauh.gems.arch.exceptions import PackageNotFoundException
from bauh.gems.arch.mapper import ArchDataMapper
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.updates import UpdatesSummarizer
from bauh.gems.arch.worker import AURIndexUpdater, ArchDiskCacheUpdater, ArchCompilationOptimizer, SyncDatabases, \
RefreshMirrors
@@ -56,6 +57,8 @@ RE_SPLIT_VERSION = re.compile(r'([=><]+)')
SOURCE_FIELDS = ('source', 'source_x86_64')
RE_PRE_DOWNLOAD_WL_PROTOCOLS = re.compile(r'^(.+::)?(https?|ftp)://.+')
RE_PRE_DOWNLOAD_BL_EXT = re.compile(r'.+\.(git|gpg)$')
+RE_PKGBUILD_PKGNAME = re.compile(r'pkgname\s*=.+')
+RE_CONFLICT_DETECTED = re.compile(r'\n::\s*(.+)\s+are in conflict\s*.')
class TransactionContext:
@@ -63,12 +66,13 @@ class TransactionContext:
def __init__(self, name: str = None, base: str = None, maintainer: str = None, watcher: ProcessWatcher = None,
handler: ProcessHandler = None, dependency: bool = None, skip_opt_deps: bool = False, root_password: str = None,
build_dir: str = None, project_dir: str = None, change_progress: bool = False, arch_config: dict = None,
- install_file: str = None, repository: str = None, pkg: ArchPackage = None,
+ install_files: Set[str] = None, repository: str = None, pkg: ArchPackage = None,
remote_repo_map: Dict[str, str] = None, provided_map: Dict[str, Set[str]] = None,
remote_provided_map: Dict[str, Set[str]] = None, aur_idx: Set[str] = None,
missing_deps: List[Tuple[str, str]] = None, installed: Set[str] = None, removed: Dict[str, SoftwarePackage] = None,
disk_loader: DiskCacheLoader = None, disk_cache_updater: Thread = None,
- new_pkg: bool = False):
+ new_pkg: bool = False, custom_pkgbuild_path: str = None,
+ pkgs_to_build: Set[str] = None):
self.name = name
self.base = base
self.maintainer = maintainer
@@ -82,7 +86,7 @@ class TransactionContext:
self.change_progress = change_progress
self.repository = repository
self.config = arch_config
- self.install_file = install_file
+ self.install_files = install_files
self.pkg = pkg
self.provided_map = provided_map
self.remote_repo_map = remote_repo_map
@@ -95,6 +99,8 @@ class TransactionContext:
self.disk_cache_updater = disk_cache_updater
self.pkgbuild_edited = False
self.new_pkg = new_pkg
+ self.custom_pkgbuild_path = custom_pkgbuild_path
+ self.pkgs_to_build = pkgs_to_build
@classmethod
def gen_context_from(cls, pkg: ArchPackage, arch_config: dict, root_password: str, handler: ProcessHandler) -> "TransactionContext":
@@ -123,11 +129,14 @@ class TransactionContext:
dep_context.removed = {}
return dep_context
- def has_install_file(self) -> bool:
- return self.install_file is not None
+ def has_install_files(self) -> bool:
+ return bool(self.install_files)
- def get_package_path(self) -> str:
- return self.install_file if self.install_file else self.name
+ def get_packages_paths(self) -> Set[str]:
+ return self.install_files if self.install_files else {self.name}
+
+ def get_package_names(self) -> Set[str]:
+ return self.pkgs_to_build if (self.pkgs_to_build and self.install_files) else {self.name}
def get_version(self) -> str:
return self.pkg.version if self.pkg else None
@@ -693,7 +702,7 @@ class ArchManager(SoftwareManager):
context.watcher.change_progress(50)
- context.install_file = version_files[versions[0]]
+ context.install_files = version_files[versions[0]] # TODO verify
if not self._handle_missing_deps(context=context):
return False
@@ -1654,11 +1663,26 @@ class ArchManager(SoftwareManager):
'description': 'pkgdesc'}.items():
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)
+
+ with open(src_path, 'w+') as f:
+ f.write(srcinfo)
+ else:
+ with open(src_path) as f:
+ srcinfo = f.read()
+
+ return srcinfo
+
def _build(self, context: TransactionContext) -> bool:
self._edit_pkgbuild_and_update_context(context)
self._pre_download_source(context.name, context.project_dir, context.watcher)
self._update_progress(context, 50)
+ context.custom_pkgbuild_path = self._gen_custom_pkgbuild_if_required(context)
+
if not self._handle_aur_package_deps_and_keys(context):
return False
@@ -1673,7 +1697,10 @@ class ArchManager(SoftwareManager):
cpu_optimized = True
try:
- pkgbuilt, output = makepkg.make(context.project_dir, optimize=optimize, handler=context.handler)
+ pkgbuilt, output = makepkg.make(pkgdir=context.project_dir,
+ optimize=optimize,
+ handler=context.handler,
+ custom_pkgbuild=context.custom_pkgbuild_path)
finally:
if cpu_optimized:
self.logger.info("Setting cpus to powersave mode")
@@ -1682,7 +1709,32 @@ class ArchManager(SoftwareManager):
self._update_progress(context, 65)
if pkgbuilt:
- gen_file = [fname for root, dirs, files in os.walk(context.build_dir) for fname in files if re.match(r'^{}-.+\.tar\.(xz|zst)'.format(context.name), fname)]
+ self.__fill_aur_output_files(context)
+
+ if self._install(context=context):
+ self._save_pkgbuild(context)
+
+ if context.dependency or context.skip_opt_deps:
+ return True
+
+ context.watcher.change_substatus(self.i18n['arch.optdeps.checking'].format(bold(context.name)))
+
+ self._update_progress(context, 100)
+ if self._install_optdeps(context):
+ return True
+
+ return False
+
+ 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)}
+
+ if output_files:
+ context.install_files = output_files
+ else:
+ gen_file = [fname for root, dirs, files in os.walk(context.build_dir) for fname in files if
+ re.match(r'^{}-.+\.tar\.(xz|zst)'.format(context.name), fname)]
if not gen_file:
context.watcher.print('Could not find the built package. Aborting...')
@@ -1702,21 +1754,9 @@ class ArchManager(SoftwareManager):
if perfect_match:
file_to_install = perfect_match[0]
- context.install_file = '{}/{}'.format(context.project_dir, file_to_install)
+ context.install_files = {'{}/{}'.format(context.project_dir, file_to_install)}
- if self._install(context=context):
- self._save_pkgbuild(context)
-
- if context.dependency or context.skip_opt_deps:
- return True
-
- context.watcher.change_substatus(self.i18n['arch.optdeps.checking'].format(bold(context.name)))
-
- self._update_progress(context, 100)
- if self._install_optdeps(context):
- return True
-
- return False
+ context.watcher.change_substatus('')
def _save_pkgbuild(self, context: TransactionContext):
cache_path = ArchPackage.disk_cache_path(context.name)
@@ -1761,13 +1801,27 @@ class ArchManager(SoftwareManager):
ti = time.time()
if context.repository == 'aur':
- with open('{}/.SRCINFO'.format(context.project_dir)) as f:
- srcinfo = aur.map_srcinfo(string=f.read(), pkgname=context.name)
+ srcinfo = aur.map_srcinfo(string=self._read_srcinfo(context),
+ pkgname=context.name if (not context.pkgs_to_build or len(context.pkgs_to_build) == 1) else None)
+
+ if context.pkgs_to_build and len(context.pkgs_to_build) > 1: # removing self dependencies from srcinfo
+ for attr in ('depends', 'makedepends', 'optdepends'):
+ dep_list = srcinfo.get(attr)
+
+ if dep_list and isinstance(dep_list, list):
+ to_remove = set()
+ for dep in dep_list:
+ dep_name = RE_DEP_OPERATORS.split(dep.split(':')[0])[0].strip()
+
+ if dep_name and dep_name in context.pkgs_to_build:
+ to_remove.add(dep)
+
+ for dep in to_remove:
+ dep_list.remove(dep)
pkgs_data = {context.name: self.aur_client.map_update_data(context.name, context.get_version(), srcinfo)}
else:
- file = bool(context.install_file)
- pkgs_data = pacman.map_updates_data({context.install_file if file else context.name}, files=file)
+ pkgs_data = pacman.map_updates_data(context.get_packages_paths(), files=bool(context.install_files))
deps_data, alread_checked_deps = {}, set()
@@ -1807,7 +1861,8 @@ class ArchManager(SoftwareManager):
check_res = makepkg.check(context.project_dir,
optimize=bool(context.config['optimize']),
missing_deps=False,
- handler=context.handler)
+ handler=context.handler,
+ custom_pkgbuild=context.custom_pkgbuild_path)
if check_res:
if check_res.get('gpg_key'):
@@ -1952,22 +2007,28 @@ class ArchManager(SoftwareManager):
raise ArchDownloadException()
def _install(self, context: TransactionContext) -> bool:
- check_install_output = []
- pkgpath = context.get_package_path()
+ pkgpaths = context.get_packages_paths()
context.watcher.change_substatus(self.i18n['arch.checking.conflicts'].format(bold(context.name)))
self.logger.info("Checking for possible conflicts with '{}'".format(context.name))
- for check_out in SimpleProcess(cmd=['pacman', '-U' if context.install_file else '-S', pkgpath],
- root_password=context.root_password,
- cwd=context.project_dir or '.').instance.stdout:
- check_install_output.append(check_out.decode())
+ _, output = context.handler.handle_simple(pacman.install_as_process(pkgpaths=pkgpaths,
+ root_password=context.root_password,
+ pkgdir=context.project_dir or '.',
+ file=bool(context.install_files),
+ simulate=True),
+ notify_watcher=False)
+ # for check_out in SimpleProcess(cmd=['pacman', '-U' if context.install_files else '-S', pkgpath],
+ # root_password=context.root_password,
+ # cwd=context.project_dir or '.').instance.stdout:
+ # check_install_output.append(check_out.decode())
self._update_progress(context, 70)
- if check_install_output and 'conflict' in check_install_output[-1]:
+ if 'unresolvable package conflicts detected' in output:
self.logger.info("Conflicts detected for '{}'".format(context.name))
- conflicting_apps = [w[0] for w in re.findall(r'((\w|\-|\.)+)\s(and|are)', check_install_output[-1])]
+ conflict_msgs = RE_CONFLICT_DETECTED.findall(output)
+ conflicting_apps = {n.strip() for m in conflict_msgs for n in m.split(' and ')}
conflict_msg = ' {} '.format(self.i18n['and']).join([bold(c) for c in conflicting_apps])
if not context.watcher.request_confirmation(title=self.i18n['arch.install.conflict.popup.title'],
body=self.i18n['arch.install.conflict.popup.body'].format(conflict_msg)):
@@ -1975,7 +2036,8 @@ class ArchManager(SoftwareManager):
return False
else: # uninstall conflicts
self._update_progress(context, 75)
- to_uninstall = [conflict for conflict in conflicting_apps if conflict != context.name]
+ names_to_install = context.get_package_names()
+ to_uninstall = [conflict for conflict in conflicting_apps if conflict not in names_to_install]
self.logger.info("Preparing to uninstall conflicting packages: {}".format(to_uninstall))
@@ -2006,7 +2068,7 @@ class ArchManager(SoftwareManager):
if context.missing_deps:
to_install.extend((d[0] for d in context.missing_deps))
- to_install.append(pkgpath)
+ to_install.extend(pkgpaths)
downloaded = 0
if self._multithreaded_download_enabled(context.config):
@@ -2027,7 +2089,7 @@ class ArchManager(SoftwareManager):
else:
status_handler = None
- installed_with_same_name = self.read_installed(disk_loader=context.disk_loader, internet_available=True, names={context.name}).installed
+ installed_with_same_name = self.read_installed(disk_loader=context.disk_loader, internet_available=True, names=context.get_package_names()).installed
context.watcher.change_substatus(self.i18n['arch.installing.package'].format(bold(context.name)))
installed = self._handle_install_call(context=context, to_install=to_install, status_handler=status_handler)
@@ -2038,7 +2100,7 @@ class ArchManager(SoftwareManager):
self._update_progress(context, 95)
if installed:
- context.installed.add(context.name)
+ context.installed.update(context.get_package_names())
context.installed.update((p for p in to_install if not p.startswith('/')))
if installed_with_same_name:
@@ -2091,7 +2153,7 @@ class ArchManager(SoftwareManager):
def _call_pacman_install(self, context: TransactionContext, to_install: List[str], overwrite_files: bool, status_handler: Optional[object] = None) -> Tuple[bool, str]:
return context.handler.handle_simple(pacman.install_as_process(pkgpaths=to_install,
root_password=context.root_password,
- file=context.has_install_file(),
+ file=context.has_install_files(),
pkgdir=context.project_dir,
overwrite_conflicting_files=overwrite_files),
output_handler=status_handler.handle if status_handler else None)
@@ -2520,6 +2582,17 @@ class ArchManager(SoftwareManager):
only_int=True,
max_width=max_width,
value=local_config['mirrors_sort_limit'] if isinstance(local_config['mirrors_sort_limit'], int) else ''),
+ new_select(id_='aur_build_only_chosen',
+ label=self.i18n['arch.config.aur_build_only_chosen'],
+ tip=self.i18n['arch.config.aur_build_only_chosen.tip'],
+ opts=[(self.i18n['yes'].capitalize(), True, None),
+ (self.i18n['no'].capitalize(), False, None),
+ (self.i18n['ask'].capitalize(), None, None),
+ ],
+ value=local_config['aur_build_only_chosen'],
+ max_width=max_width,
+ type_=SelectViewType.RADIO,
+ capitalize_label=False),
new_select(label=self.i18n['arch.config.edit_aur_pkgbuild'],
tip=self.i18n['arch.config.edit_aur_pkgbuild.tip'],
id_='edit_aur_pkgbuild',
@@ -2565,6 +2638,7 @@ class ArchManager(SoftwareManager):
config['edit_aur_pkgbuild'] = form_install.get_component('edit_aur_pkgbuild').get_selected()
config['aur_remove_build_dir'] = form_install.get_component('aur_remove_build_dir').get_selected()
config['aur_build_dir'] = form_install.get_component('aur_build_dir').file_path
+ config['aur_build_only_chosen'] = form_install.get_component('aur_build_only_chosen').get_selected()
if not config['aur_build_dir']:
config['aur_build_dir'] = None
@@ -2932,3 +3006,61 @@ class ArchManager(SoftwareManager):
body=self.i18n['snap.custom_action.setup_snapd.ready.body'],
type_=MessageType.INFO)
return True
+
+ def _gen_custom_pkgbuild_if_required(self, context: TransactionContext) -> Optional[str]:
+ build_only_chosen = context.config.get('aur_build_only_chosen')
+
+ pkgs_to_build = aur.map_srcinfo(string=self._read_srcinfo(context), pkgname=None, fields={'pkgname'}).get('pkgname')
+
+ if isinstance(pkgs_to_build, str):
+ pkgs_to_build = {pkgs_to_build}
+ else:
+ pkgs_to_build = {*pkgs_to_build}
+
+ if build_only_chosen is False:
+ context.pkgs_to_build = pkgs_to_build
+ return
+
+ # checking if more than one package is mapped for this pkgbuild
+
+ if not pkgs_to_build or not isinstance(pkgs_to_build, set) or len(pkgs_to_build) == 1 or context.name not in pkgs_to_build:
+ context.pkgs_to_build = pkgs_to_build
+ return
+
+ if build_only_chosen is None:
+ if not context.dependency:
+ pkgnames = [InputOption(label=n, value=n, read_only=False) for n in pkgs_to_build if n != context.name]
+ select = MultipleSelectComponent(label='',
+ options=pkgnames,
+ default_options={*pkgnames},
+ max_per_line=1)
+
+ if not context.watcher.request_confirmation(title=self.i18n['warning'].capitalize(),
+ body=self.i18n['arch.aur.sync.several_names.popup.body'].format(bold(context.name)) + ':',
+ components=[select],
+ confirmation_label=self.i18n['arch.aur.sync.several_names.popup.bt_only_chosen'].format(context.name),
+ 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)
+ with open(pkgbuild_path) as f:
+ current_pkgbuild = f.read()
+
+ if context.pkgs_to_build:
+ names = '({})'.format(' '.join(("'{}'".format(p) for p in context.pkgs_to_build)))
+ else:
+ 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'
+
+ with open(custom_pkgbuild_path, 'w+') as f:
+ f.write(new_pkgbuild)
+
+ new_srcinfo = makepkg.gen_srcinfo(context.project_dir, custom_pkgbuild_path)
+
+ with open('{}/.SRCINFO'.format(context.project_dir), 'w+') as f:
+ f.write(new_srcinfo)
+
+ return custom_pkgbuild_path
diff --git a/bauh/gems/arch/makepkg.py b/bauh/gems/arch/makepkg.py
index a89964fe..60b26640 100644
--- a/bauh/gems/arch/makepkg.py
+++ b/bauh/gems/arch/makepkg.py
@@ -1,6 +1,6 @@
import os
import re
-from typing import Tuple
+from typing import Tuple, Optional, Set
from bauh.commons.system import SimpleProcess, ProcessHandler, run_cmd
from bauh.gems.arch import CUSTOM_MAKEPKG_FILE
@@ -9,18 +9,23 @@ RE_DEPS_PATTERN = re.compile(r'\n?\s+->\s(.+)\n')
RE_UNKNOWN_GPG_KEY = re.compile(r'\(unknown public key (\w+)\)')
-def gen_srcinfo(build_dir: str) -> str:
- return run_cmd('makepkg --printsrcinfo', cwd=build_dir)
+def gen_srcinfo(build_dir: str, custom_pkgbuild_path: Optional[str] = None) -> str:
+ return run_cmd('makepkg --printsrcinfo{}'.format(' -p {}'.format(custom_pkgbuild_path) if custom_pkgbuild_path else ''),
+ cwd=build_dir)
-def check(pkgdir: str, optimize: bool, missing_deps: bool, handler: ProcessHandler) -> dict:
+def check(pkgdir: str, optimize: bool, missing_deps: bool, handler: ProcessHandler, custom_pkgbuild: Optional[str] = None) -> dict:
res = {}
- cmd = ['makepkg', '-ALcf', '--check', '--noarchive', '--nobuild', '--noprepare']
+ cmd = ['makepkg', '-ALcfm', '--check', '--noarchive', '--nobuild', '--noprepare']
if not missing_deps:
cmd.append('--nodeps')
+ if custom_pkgbuild:
+ cmd.append('-p')
+ cmd.append(custom_pkgbuild)
+
if optimize:
if os.path.exists(CUSTOM_MAKEPKG_FILE):
handler.watcher.print('Using custom makepkg.conf -> {}'.format(CUSTOM_MAKEPKG_FILE))
@@ -44,9 +49,13 @@ def check(pkgdir: str, optimize: bool, missing_deps: bool, handler: ProcessHandl
return res
-def make(pkgdir: str, optimize: bool, handler: ProcessHandler) -> Tuple[bool, str]:
+def make(pkgdir: str, optimize: bool, handler: ProcessHandler, custom_pkgbuild: Optional[str] = None) -> Tuple[bool, str]:
cmd = ['makepkg', '-ALcsmf', '--skipchecksums']
+ if custom_pkgbuild:
+ cmd.append('-p')
+ cmd.append(custom_pkgbuild)
+
if optimize:
if os.path.exists(CUSTOM_MAKEPKG_FILE):
handler.watcher.print('Using custom makepkg.conf -> {}'.format(CUSTOM_MAKEPKG_FILE))
@@ -66,3 +75,14 @@ def update_srcinfo(project_dir: str) -> bool:
return True
return False
+
+
+def list_output_files(project_dir: str, custom_pkgbuild_path: Optional[str] = None) -> Set[str]:
+ output = run_cmd(cmd='makepkg --packagelist{}'.format(' -p {}'.format(custom_pkgbuild_path) if custom_pkgbuild_path else ''),
+ print_error=False,
+ cwd=project_dir)
+
+ if output:
+ return {p.strip() for p in output.split('\n') if p}
+
+ return set()
diff --git a/bauh/gems/arch/pacman.py b/bauh/gems/arch/pacman.py
index bc247590..e2e9d0b5 100644
--- a/bauh/gems/arch/pacman.py
+++ b/bauh/gems/arch/pacman.py
@@ -141,11 +141,13 @@ def map_installed(names: Iterable[str] = None) -> dict: # returns a dict with w
return pkgs
-def install_as_process(pkgpaths: Iterable[str], root_password: str, file: bool, pkgdir: str = '.', overwrite_conflicting_files: bool = False) -> SimpleProcess:
- if file:
- cmd = ['pacman', '-U', *pkgpaths, '--noconfirm'] # pkgpath = install file path
- else:
- cmd = ['pacman', '-S', *pkgpaths, '--noconfirm'] # pkgpath = pkgname
+def install_as_process(pkgpaths: Iterable[str], root_password: str, file: bool, pkgdir: str = '.',
+ overwrite_conflicting_files: bool = False, simulate: bool = False) -> SimpleProcess:
+ cmd = ['pacman', '-U'] if file else ['pacman', '-S']
+ cmd.extend(pkgpaths)
+
+ if not simulate:
+ cmd.append('--noconfirm')
if overwrite_conflicting_files:
cmd.append('--overwrite=*')
diff --git a/bauh/gems/arch/resources/locale/ca b/bauh/gems/arch/resources/locale/ca
index 8ac03378..0fd756c4 100644
--- a/bauh/gems/arch/resources/locale/ca
+++ b/bauh/gems/arch/resources/locale/ca
@@ -21,6 +21,10 @@ arch.aur.install.validity_check.body=Alguns dels fitxers font necessaris per a l
arch.aur.install.validity_check.proceed=Voleu continuar de totes maneres? ( no es recomana )
arch.aur.install.validity_check.title=Problemes d’integritat {}
arch.aur.install.verifying_pgp=S’estan comprovant les claus PGP
+arch.aur.build.list_output=Checking built files
+arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} configures the build of other packages
+arch.aur.sync.several_names.popup.bt_only_chosen=Build only {}
+arch.aur.sync.several_names.popup.bt_selected=Build selected too
arch.building.package=S’està compilant el paquet {}
arch.checking.conflicts=S’està comprovant si hi ha conflictes amb {}
arch.checking.deps=S’estan comprovant les dependències de {}
@@ -32,6 +36,8 @@ arch.config.automatch_providers=Auto-define dependency providers
arch.config.automatch_providers.tip=It automatically chooses which provider will be used for a package dependency when both names are equal.
arch.config.aur_build_dir=Build directory (AUR)
arch.config.aur_build_dir.tip=It define a custom directory where the AUR packages will be built. Default: {}.
+arch.config.aur_build_only_chosen=Build only chosen (AUR)
+arch.config.aur_build_only_chosen.tip=Some AUR packages have a common PKGBUILD shared with other packages and that defines build instructions for each one. This property enabled will ensure that only the chosen package will be built.
arch.config.aur_remove_build_dir=Remove build directory (AUR)
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
arch.config.clean_cache=Elimina les versions antigues
diff --git a/bauh/gems/arch/resources/locale/de b/bauh/gems/arch/resources/locale/de
index f9a0a0d5..342e8775 100644
--- a/bauh/gems/arch/resources/locale/de
+++ b/bauh/gems/arch/resources/locale/de
@@ -21,6 +21,10 @@ arch.aur.install.validity_check.body=Einige der Source-Dateien für die Installa
arch.aur.install.validity_check.proceed=Wollen Sie trotzdem fortfahren? ( nicht empfohlen )
arch.aur.install.validity_check.title=Integritätsprobleme {}
arch.aur.install.verifying_pgp=PGP Schlüssel überprüfen
+arch.aur.build.list_output=Checking built files
+arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} configures the build of other packages
+arch.aur.sync.several_names.popup.bt_only_chosen=Build only {}
+arch.aur.sync.several_names.popup.bt_selected=Build selected too
arch.building.package=Paket {} erstellen
arch.checking.conflicts=Konflikte mit {} überprüfen
arch.checking.deps={} Abhängigkeiten überprüfen
@@ -32,6 +36,8 @@ arch.config.automatch_providers=Auto-define dependency providers
arch.config.automatch_providers.tip=It automatically chooses which provider will be used for a package dependency when both names are equal.
arch.config.aur_build_dir=Build directory (AUR)
arch.config.aur_build_dir.tip=It define a custom directory where the AUR packages will be built. Default: {}.
+arch.config.aur_build_only_chosen=Build only chosen (AUR)
+arch.config.aur_build_only_chosen.tip=Some AUR packages have a common PKGBUILD shared with other packages and that defines build instructions for each one. This property enabled will ensure that only the chosen package will be built.
arch.config.aur_remove_build_dir=Remove build directory (AUR)
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
arch.config.clean_cache=Remove old versions
diff --git a/bauh/gems/arch/resources/locale/en b/bauh/gems/arch/resources/locale/en
index 64d76b21..74add205 100644
--- a/bauh/gems/arch/resources/locale/en
+++ b/bauh/gems/arch/resources/locale/en
@@ -22,6 +22,10 @@ arch.aur.install.validity_check.body=Some of the source-files needed for {} inst
arch.aur.install.validity_check.proceed=Do you want to continue anyway ? ( not recommended )
arch.aur.install.validity_check.title=Integrity issues {}
arch.aur.install.verifying_pgp=Verifying PGP keys
+arch.aur.build.list_output=Checking built files
+arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} configures the build of other packages
+arch.aur.sync.several_names.popup.bt_only_chosen=Build only {}
+arch.aur.sync.several_names.popup.bt_selected=Build selected too
arch.building.package=Building package {}
arch.checking.conflicts=Checking any conflicts with {}
arch.checking.deps=Checking {} dependencies
@@ -33,6 +37,8 @@ arch.config.automatch_providers=Auto-define dependency providers
arch.config.automatch_providers.tip=It automatically chooses which provider will be used for a package dependency when both names are equal.
arch.config.aur_build_dir=Build directory (AUR)
arch.config.aur_build_dir.tip=It define a custom directory where the AUR packages will be built. Default: {}.
+arch.config.aur_build_only_chosen=Build only chosen (AUR)
+arch.config.aur_build_only_chosen.tip=Some AUR packages have a common PKGBUILD shared with other packages and that defines build instructions for each one. This property enabled will ensure that only the chosen package will be built.
arch.config.aur_remove_build_dir=Remove build directory (AUR)
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
arch.config.clean_cache=Remove old versions
diff --git a/bauh/gems/arch/resources/locale/es b/bauh/gems/arch/resources/locale/es
index 99d6f2bb..87feee95 100644
--- a/bauh/gems/arch/resources/locale/es
+++ b/bauh/gems/arch/resources/locale/es
@@ -21,6 +21,10 @@ arch.aur.install.validity_check.body=Algunos de los archivos fuente necesarios p
arch.aur.install.validity_check.proceed=¿Desea continuar de todos modos? ( no recomendado )
arch.aur.install.validity_check.title=Problemas de integridad {}
arch.aur.install.verifying_pgp=Verificando claves PGP
+arch.aur.build.list_output=Checking built files
+arch.aur.sync.several_names.popup.body=El archivo de definición (PKGBUILD) de {} configura la compilación de otros paquetes
+arch.aur.sync.several_names.popup.bt_only_chosen=Compilar sólo {}
+arch.aur.sync.several_names.popup.bt_selected=Compilar seleccionados también
arch.building.package=Construyendo el paquete {}
arch.checking.conflicts=Verificando se hay conflictos con {}
arch.checking.deps=Verificando las dependencias de {}
@@ -32,6 +36,8 @@ arch.config.automatch_providers=Autodefinir proveedores de dependencia
arch.config.automatch_providers.tip=Elige automáticamente qué proveedor se usará para una dependencia de paquete cuando ambos nombres son iguales.
arch.config.aur_build_dir=Directorio de compilación (AUR)
arch.config.aur_build_dir.tip=Define un directorio personalizado donde se construirán los paquetes AUR. Defecto: {}.
+arch.config.aur_build_only_chosen=Compilar solo elegido (AUR)
+arch.config.aur_build_only_chosen.tip=Algunos paquetes AUR tienen un PKGBUILD común compartido con otros paquetes y que define las instrucciones de construcción para cada uno. Esta propiedad habilitada garantizará que solo se compile el paquete elegido.
arch.config.aur_remove_build_dir=Eliminar directorio de compilación (AUR)
arch.config.aur_remove_build_dir.tip=Si el directorio de compilación generado para un paquete debe ser eliminado una vez finalizada la operación.
arch.config.clean_cache=Eliminar versiones antiguas
diff --git a/bauh/gems/arch/resources/locale/it b/bauh/gems/arch/resources/locale/it
index b17e9707..bfe1eff2 100644
--- a/bauh/gems/arch/resources/locale/it
+++ b/bauh/gems/arch/resources/locale/it
@@ -21,6 +21,10 @@ arch.aur.install.validity_check.body=Alcuni dei file di origine necessari per l'
arch.aur.install.validity_check.proceed=Vuoi continuare comunque? ( non consigliato )
arch.aur.install.validity_check.title=Problemi di integrità {}
arch.aur.install.verifying_pgp=Verifica chiavi PGP
+arch.aur.build.list_output=Checking built files
+arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} configures the build of other packages
+arch.aur.sync.several_names.popup.bt_only_chosen=Build only {}
+arch.aur.sync.several_names.popup.bt_selected=Build selected too
arch.building.package=Pacchetto costruito {}
arch.checking.conflicts=Verifica di eventuali conflitti con {}
arch.checking.deps=Verifica di {} dipendenze
@@ -32,6 +36,8 @@ arch.config.automatch_providers=Auto-define dependency providers
arch.config.automatch_providers.tip=It automatically chooses which provider will be used for a package dependency when both names are equal.
arch.config.aur_build_dir=Build directory (AUR)
arch.config.aur_build_dir.tip=It define a custom directory where the AUR packages will be built. Default: {}.
+arch.config.aur_build_only_chosen=Build only chosen (AUR)
+arch.config.aur_build_only_chosen.tip=Some AUR packages have a common PKGBUILD shared with other packages and that defines build instructions for each one. This property enabled will ensure that only the chosen package will be built.
arch.config.aur_remove_build_dir=Remove build directory (AUR)
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
arch.config.clean_cache=Rimuovi le vecchie versioni
diff --git a/bauh/gems/arch/resources/locale/pt b/bauh/gems/arch/resources/locale/pt
index ea9b24e2..fe526426 100644
--- a/bauh/gems/arch/resources/locale/pt
+++ b/bauh/gems/arch/resources/locale/pt
@@ -22,6 +22,10 @@ arch.aur.install.validity_check.body=Alguns dos arquivos-fonte necessários para
arch.aur.install.validity_check.proceed=Você deseja continuar mesmo assim ? ( não recomendado )
arch.aur.install.validity_check.title=Problemas de integridade {}
arch.aur.install.verifying_pgp=Verificando chaves PGP
+arch.aur.build.list_output=Verificando arquivos construídos
+arch.aur.sync.several_names.popup.body=O arquivo de definição (PKGBUILD) de {} configura a construção de outros pacotes
+arch.aur.sync.several_names.popup.bt_only_chosen=Construir somente {}
+arch.aur.sync.several_names.popup.bt_selected=Construir selecionados também
arch.building.package=Construindo o pacote {}
arch.checking.conflicts=Verificando se há conflitos com {}
arch.checking.deps=Verificando as dependências de {}
@@ -33,6 +37,8 @@ arch.config.automatch_providers=Auto-definir provedores de dependências
arch.config.automatch_providers.tip=Escolhe automaticamente qual provedor será utilizado para determinada dependência de um pacote caso os nomes de ambos sejam iguais.
arch.config.aur_build_dir=Diretório de construção (AUR)
arch.config.aur_build_dir.tip=Define um diretório personalizado onde pacotes do AUR serão construídos. Padrão: {}.
+arch.config.aur_build_only_chosen=Construir somente escolhido (AUR)
+arch.config.aur_build_only_chosen.tip=Alguns pacotes do AUR têm um PKGBUILD comum a outros pacotes e que define a construção para todos. Essa propriedade ativada garantirá que somente o pacote escolhido será construído.
arch.config.aur_remove_build_dir=Remover diretório de construção (AUR)
arch.config.aur_remove_build_dir.tip=Se o diretório gerado para a construção de um pacote do AUR deve ser removido após a operação ser finalizada.
arch.config.clean_cache=Remover versões antigas
diff --git a/bauh/gems/arch/resources/locale/ru b/bauh/gems/arch/resources/locale/ru
index 05d256e1..02329c12 100644
--- a/bauh/gems/arch/resources/locale/ru
+++ b/bauh/gems/arch/resources/locale/ru
@@ -21,6 +21,10 @@ arch.aur.install.validity_check.body=Некоторые исходные фай
arch.aur.install.validity_check.proceed=Вы всё равно хотите продолжить ? ( не рекомендуется )
arch.aur.install.validity_check.title=Проблемы целостности
arch.aur.install.verifying_pgp=Проверка ключей PGP
+arch.aur.build.list_output=Checking built files
+arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} configures the build of other packages
+arch.aur.sync.several_names.popup.bt_only_chosen=Build only {}
+arch.aur.sync.several_names.popup.bt_selected=Build selected too
arch.building.package=Сборка пакета {}
arch.checking.conflicts=Проверка конфликтов с {}
arch.checking.deps=Проверка зависимостей {}
@@ -32,6 +36,8 @@ arch.config.automatch_providers=Auto-define dependency providers
arch.config.automatch_providers.tip=It automatically chooses which provider will be used for a package dependency when both names are equal.
arch.config.aur_build_dir=Build directory (AUR)
arch.config.aur_build_dir.tip=It define a custom directory where the AUR packages will be built. Default: {}.
+arch.config.aur_build_only_chosen=Build only chosen (AUR)
+arch.config.aur_build_only_chosen.tip=Some AUR packages have a common PKGBUILD shared with other packages and that defines build instructions for each one. This property enabled will ensure that only the chosen package will be built.
arch.config.aur_remove_build_dir=Remove build directory (AUR)
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
arch.config.clean_cache=Remove old versions
diff --git a/bauh/gems/arch/resources/locale/tr b/bauh/gems/arch/resources/locale/tr
index 5b52a195..74efb19d 100644
--- a/bauh/gems/arch/resources/locale/tr
+++ b/bauh/gems/arch/resources/locale/tr
@@ -21,6 +21,10 @@ arch.aur.install.validity_check.body={} kurulumu için gereken kaynak dosyalarda
arch.aur.install.validity_check.proceed=Yine de devam etmek istiyor musunuz? ( önerilmez )
arch.aur.install.validity_check.title=Bütünlük sorunları {}
arch.aur.install.verifying_pgp=PGP anahtarları doğrulanıyor
+arch.aur.build.list_output=Checking built files
+arch.aur.sync.several_names.popup.body=The definition file (PKGBUILD) of {} configures the build of other packages
+arch.aur.sync.several_names.popup.bt_only_chosen=Build only {}
+arch.aur.sync.several_names.popup.bt_selected=Build selected too
arch.building.package=Paket inşa ediliyor {}
arch.checking.conflicts={} ile çakışmalar kontrol ediliyor
arch.checking.deps={} bağımlılıkları kontrol ediliyor
@@ -32,6 +36,8 @@ arch.config.automatch_providers=Auto-define dependency providers
arch.config.automatch_providers.tip=It automatically chooses which provider will be used for a package dependency when both names are equal.
arch.config.aur_build_dir=Build directory (AUR)
arch.config.aur_build_dir.tip=It define a custom directory where the AUR packages will be built. Default: {}.
+arch.config.aur_build_only_chosen=Build only chosen (AUR)
+arch.config.aur_build_only_chosen.tip=Some AUR packages have a common PKGBUILD shared with other packages and that defines build instructions for each one. This property enabled will ensure that only the chosen package will be built.
arch.config.aur_remove_build_dir=Remove build directory (AUR)
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
arch.config.clean_cache=Önbelleği temizle