[arch] refactoring: conflict resolution checking (+ test cases)

This commit is contained in:
Vinicius Moreira
2022-11-20 11:13:54 -03:00
parent 53e3caba58
commit 69cf81dbe9
7 changed files with 1556 additions and 204 deletions

View File

@@ -8,7 +8,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixes
- Arch
- not properly mapping all provided packages by the system when checking for upgrade requirements
- not properly checking all provided packages by the system when checking for conflicts (upgrade requirements)
### Improvements
- Arch
- added several test cases to ensure conflicting scenarios are properly covered when checking for upgrade requirements
## [0.10.4] 2022-11-05

View File

@@ -58,7 +58,7 @@ class SearchResult:
class UpgradeRequirement:
def __init__(self, pkg: SoftwarePackage, reason: str = None, required_size: float = None, extra_size: float = None, sorting_priority: int = 0):
def __init__(self, pkg: SoftwarePackage, reason: Optional[str] = None, required_size: Optional[float] = None, extra_size: Optional[float] = None, sorting_priority: int = 0):
"""
:param pkg:
@@ -77,6 +77,15 @@ class UpgradeRequirement:
def sort_by_priority(req: "UpgradeRequirement") -> Tuple[int, str]:
return -req.sorting_priority, req.pkg.name
def __eq__(self, other) -> bool:
if isinstance(other, UpgradeRequirement):
return self.__dict__ == other.__dict__
return False
def __hash__(self) -> int:
return sum((hash(k) + hash(v) for k, v in self.__dict__.items()))
class UpgradeRequirements:

View File

@@ -464,9 +464,9 @@ class DependenciesAnalyser:
if missing_deps:
self._fill_single_providers_data(missing_deps, repo_missing, aur_missing, deps_data)
missing_subdeps = self.map_missing_deps(pkgs_data={**deps_data}, provided_map=provided_map, aur_index=aur_index,
deps_checked=deps_checked, sort=False, deps_data=deps_data,
watcher=watcher,
missing_subdeps = self.map_missing_deps(pkgs_data={**deps_data}, provided_map=provided_map,
aur_index=aur_index, deps_checked=deps_checked, sort=False,
deps_data=deps_data, watcher=watcher,
remote_provided_map=remote_provided_map,
remote_repo_map=remote_repo_map,
automatch_providers=automatch_providers,
@@ -650,7 +650,7 @@ class DependenciesAnalyser:
if pkgnames:
to_ignore.update(pkgnames)
all_requirements = {req for reqs in pacman.map_required_by(pkgnames).values() for req in reqs if req not in to_ignore}
all_requirements = {r for reqs in pacman.map_required_by(pkgnames).values() for r in reqs if r not in to_ignore}
if all_requirements:
sub_requirements = self.map_all_required_by(all_requirements, to_ignore)

View File

@@ -396,7 +396,7 @@ def get_version_for_not_installed(pkgname: str) -> str:
def map_repositories(pkgnames: Iterable[str] = None) -> Dict[str, str]:
info = run_cmd('pacman -Si {}'.format(' '.join(pkgnames) if pkgnames else ''), print_error=False, ignore_return_code=True)
info = run_cmd(f"pacman -Si {' '.join(pkgnames) if pkgnames else ''}", print_error=False, ignore_return_code=True)
if info:
repos = re.findall(r'(Name|Repository)\s*:\s*(.+)', info)
@@ -529,7 +529,7 @@ def upgrade_system(root_password: Optional[str]) -> SimpleProcess:
return SimpleProcess(cmd=['pacman', '-Syyu', '--noconfirm'], root_password=root_password)
def fill_provided_map(key: str, val: str, output: dict):
def _fill_provided_map(key: str, val: str, output: Dict[str, Set[str]]):
current_val = output.get(key)
if current_val is None:
@@ -558,19 +558,19 @@ def map_provided(remote: bool = False, pkgs: Iterable[str] = None) -> Optional[D
elif field == 'Version':
latest_version = val.split('=')[0]
elif field == 'Provides':
fill_provided_map(latest_name, latest_name, provided_map)
fill_provided_map(f'{latest_name}={latest_version}', latest_name, provided_map)
_fill_provided_map(latest_name, latest_name, provided_map)
_fill_provided_map(f'{latest_name}={latest_version}', latest_name, provided_map)
if val != 'None':
for w in val.split(' '):
if w:
word = w.strip()
fill_provided_map(word, latest_name, provided_map)
_fill_provided_map(word, latest_name, provided_map)
word_split = word.split('=')
if word_split[0] != word:
fill_provided_map(word_split[0], latest_name, provided_map)
_fill_provided_map(word_split[0], latest_name, provided_map)
else:
provided = True
@@ -583,12 +583,12 @@ def map_provided(remote: bool = False, pkgs: Iterable[str] = None) -> Optional[D
for w in l.split(' '):
if w:
word = w.strip()
fill_provided_map(word, latest_name, provided_map)
_fill_provided_map(word, latest_name, provided_map)
word_split = word.split('=')
if word_split[0] != word:
fill_provided_map(word_split[0], latest_name, provided_map)
_fill_provided_map(word_split[0], latest_name, provided_map)
return provided_map
@@ -857,7 +857,8 @@ def get_cache_dir() -> str:
def map_required_by(names: Iterable[str] = None, remote: bool = False) -> Dict[str, Set[str]]:
output = run_cmd('pacman -{} {}'.format('Sii' if remote else 'Qi', ' '.join(names) if names else ''), print_error=False)
output = run_cmd(f"pacman -{'Sii' if remote else 'Qi'} {' '.join(names) if names else ''}".strip(),
print_error=False)
if output:
latest_name, required = None, None

View File

@@ -2,7 +2,7 @@ import logging
import time
import traceback
from threading import Thread
from typing import Dict, Set, List, Tuple, Iterable, Optional
from typing import Dict, Set, List, Tuple, Iterable, Optional, Any
from bauh.api.abstract.controller import UpgradeRequirements, UpgradeRequirement
from bauh.api.abstract.handler import ProcessWatcher
@@ -47,12 +47,26 @@ class UpdateRequirementsContext:
if self.provided_map is None:
self.provided_map = {**update}
else:
for key, val in update.items():
if key not in self.provided_map:
self.provided_map[key] = val
elif val:
current_val = self.provided_map[key]
current_val.update(val)
for provider, provided in update.items():
provided_set = self.provided_map.get(provider)
if provided_set is None:
provided_set = set()
self.provided_map[provider] = provided_set
provided_set.update(provided)
def add_to_provided_map(self, provider: str, provided: str):
if self.provided_map is None:
self.provided_map = dict()
provided_set = self.provided_map.get(provider)
if provided_set is None:
provided_set = set()
self.provided_map[provider] = provided_set
provided_set.add(provided)
class UpdatesSummarizer:
@@ -72,8 +86,7 @@ class UpdatesSummarizer:
for src_pkg in {p for p, data in context.pkgs_data.items() if
data['d'] and pkg1 in data['d'] or pkg2 in data['d']}:
if src_pkg not in context.cannot_upgrade:
reason = self.i18n['arch.update_summary.to_install.dep_conflict'].format("'{}'".format(pkg1),
"'{}'".format(pkg2))
reason = self.i18n['arch.update_summary.to_install.dep_conflict'].format(f"'{pkg1}'", f"'{pkg2}'")
context.cannot_upgrade[src_pkg] = UpgradeRequirement(context.to_update[src_pkg], reason)
del context.to_update[src_pkg]
@@ -137,11 +150,11 @@ class UpdatesSummarizer:
def _handle_conflict_both_to_update(self, pkg1: str, pkg2: str, context: UpdateRequirementsContext):
if pkg1 not in context.cannot_upgrade:
reason = "{} '{}'".format(self.i18n['arch.info.conflicts with'].capitalize(), pkg2)
reason = f"{self.i18n['arch.info.conflicts with'].capitalize()} '{pkg2}'"
context.cannot_upgrade[pkg1] = UpgradeRequirement(pkg=context.to_update[pkg1], reason=reason)
if pkg2 not in context.cannot_upgrade:
reason = "{} '{}'".format(self.i18n['arch.info.conflicts with'].capitalize(), pkg1)
reason = f"{self.i18n['arch.info.conflicts with'].capitalize()} '{pkg1}'"
context.cannot_upgrade[pkg2] = UpgradeRequirement(pkg=context.to_update[pkg2], reason=reason)
for p in (pkg1, pkg2):
@@ -153,65 +166,101 @@ class UpdatesSummarizer:
else:
del context.aur_to_update[p]
def _filter_and_map_conflicts(self, context: UpdateRequirementsContext) -> Dict[str, str]:
def _map_conflicts(self, data: Dict[str, Dict[str, Any]], providers: Dict[str, Set[str]],
versions: Dict[str, str]) -> Tuple[Dict[str, str], Dict[str, str]]:
"""
Parameters
pkgs_data: a dict mapping the packages whose conflicts need to be analyzed to their data
providers: a dict mapping the available providers on the context (installed and to be installed) to their
respective package
versions: a dict mapping the package name to it's version (the updated or to be installed version)
Return
a tuple with two dictionaries:
- first: containing all conflicts
- second: containing mutual conflicts
"""
root_conflict = {}
mutual_conflicts = {}
for p, data in context.pkgs_data.items():
for pkg_name, data in data.items():
if data['c']:
for c in data['c']:
if c:
name_op_exp = DependenciesAnalyser.re_dep_operator().split(c)
conflict_name = name_op_exp[0]
if conflict_name != p:
conflict_version = context.installed.get(conflict_name)
if conflict_name != pkg_name:
conflict_providers = providers.get(conflict_name)
if conflict_version:
if len(name_op_exp) == 1 or match_required_version(conflict_version,
if conflict_providers:
checked_conflicts = []
for provider in conflict_providers:
if provider != pkg_name:
if len(name_op_exp) == 1:
checked_conflicts.append(provider)
else:
provider_version = versions.get(provider)
if match_required_version(provider_version,
name_op_exp[1],
name_op_exp[2]):
root_conflict[conflict_name] = p
checked_conflicts.append(provider)
if (p, conflict_name) in root_conflict.items():
mutual_conflicts[conflict_name] = p
for provider in checked_conflicts:
root_conflict[provider] = pkg_name
if mutual_conflicts:
if (pkg_name, provider) in root_conflict.items():
mutual_conflicts[provider] = pkg_name
return root_conflict, mutual_conflicts
def _handle_mutual_conflicts(self, mutual_conflicts: Dict[str, str], all_conflicts: Dict[str, str],
context: UpdateRequirementsContext):
for pkg1, pkg2 in mutual_conflicts.items():
pkg1_to_install = pkg1 in context.to_install
pkg2_to_install = pkg2 in context.to_install
if pkg1_to_install and pkg2_to_install: # remove both from to install and mark their source packages as 'cannot_update'
if pkg1_to_install and pkg2_to_install:
# remove both from to install and mark their source packages as 'cannot_update'
self._handle_conflict_both_to_install(pkg1, pkg2, context)
elif (pkg1_to_install and not pkg2_to_install) or (not pkg1_to_install and pkg2_to_install):
self._handle_conflict_to_update_and_to_install(pkg1, pkg2, pkg1_to_install, context)
else:
self._handle_conflict_both_to_update(pkg1, pkg2, context) # adding both to the 'cannot update' list
# adding both to the 'cannot update' list
self._handle_conflict_both_to_update(pkg1, pkg2, context)
for pkg1, pkg2 in mutual_conflicts.items(): # removing conflicting packages from the packages selected to upgrade
for p in (pkg1, pkg2):
if p in context.pkgs_data:
if context.pkgs_data[p].get('c'):
for c in context.pkgs_data[p]['c']:
# removing conflicting packages from the packages selected to upgrade
for pkg1, pkg2 in mutual_conflicts.items():
for pkg_name in (pkg1, pkg2):
if pkg_name in context.pkgs_data:
if context.pkgs_data[pkg_name].get('c'):
for c in context.pkgs_data[pkg_name]['c']:
# source = provided_map[c]
if c in root_conflict:
del root_conflict[c]
if c in all_conflicts:
del all_conflicts[c]
del context.pkgs_data[p]
del context.pkgs_data[pkg_name]
return root_conflict
def _fill_conflicts(self, context: UpdateRequirementsContext, blacklist: Iterable[str] = None):
def _fill_conflicts(self, context: UpdateRequirementsContext, blacklist: Optional[Iterable[str]] = None):
self.logger.info("Checking conflicts")
root_conflict = self._filter_and_map_conflicts(context)
conflicts, mutual_conflicts = self._map_conflicts(data=context.pkgs_data,
providers=context.provided_map,
versions=context.installed)
if root_conflict:
for dep, source in root_conflict.items():
if dep not in context.to_remove and (not blacklist or dep not in blacklist):
req = ArchPackage(name=dep, installed=True, i18n=self.i18n)
reason = "{} '{}'".format(self.i18n['arch.info.conflicts with'].capitalize(), source)
context.to_remove[dep] = UpgradeRequirement(req, reason)
if mutual_conflicts:
self._handle_mutual_conflicts(mutual_conflicts, conflicts, context)
if conflicts:
for conflict_name, source_name in conflicts.items():
if conflict_name not in context.to_remove and (not blacklist or conflict_name not in blacklist):
if conflict_name in context.to_update:
conflict = context.to_update[conflict_name]
else:
conflict = ArchPackage(name=conflict_name, installed=True, i18n=self.i18n)
reason = f"{self.i18n['arch.info.conflicts with'].capitalize()} '{source_name}'"
context.to_remove[conflict_name] = UpgradeRequirement(conflict, reason)
def _map_and_add_package(self, pkg_data: Tuple[str, str], idx: int, output: dict):
version = None
@@ -234,6 +283,31 @@ class UpdatesSummarizer:
output[idx] = ArchPackage(name=pkg_data[0], version=version, latest_version=version, repository=pkg_data[1], i18n=self.i18n)
def _fill_conflicts_to_install(self, context: UpdateRequirementsContext, install_data: Dict[str, Dict[str, Any]]):
"""
Parameters
context: update context
install_data: a dict mapping the packages to be installed names by their data
"""
# to properly fill conflicts considering new packages to be installed:
# - the 'context.provided_map' should contain the providers of these new packages
# - the 'context.installed' should contain the versions of these new packages
provided_map_bkp = {**context.provided_map}
self.__fill_provided_map(context=context, pkgs=context.to_install, fill_installed=False)
# adding the new packages to install as 'installed'
for pkg, data in install_data.items():
context.installed[pkg] = data["v"]
self._fill_conflicts(context, context.to_remove.keys())
# restoring the original data structures
context.provided_map = provided_map_bkp
for pkg in install_data:
if pkg in context.installed:
del context.installed[pkg]
def _fill_to_install(self, context: UpdateRequirementsContext) -> bool:
ti = time.time()
self.logger.info("Discovering updates missing packages")
@@ -266,7 +340,8 @@ class UpdatesSummarizer:
for idx, dep in enumerate(deps):
data = deps_data[dep[0]]
pkg = ArchPackage(name=dep[0], version=data['v'], latest_version=data['v'], repository=dep[1], i18n=self.i18n, package_base=data.get('b', dep[0]))
pkg = ArchPackage(name=dep[0], version=data['v'], latest_version=data['v'], repository=dep[1],
i18n=self.i18n, package_base=data.get('b', dep[0]))
sorted_pkgs[idx] = pkg
context.to_install[dep[0]] = pkg
@@ -284,16 +359,17 @@ class UpdatesSummarizer:
if all_to_install_data:
context.pkgs_data.update(all_to_install_data)
self._fill_conflicts(context, context.to_remove.keys())
self._fill_conflicts_to_install(context, all_to_install_data)
if context.to_install:
self.__fill_provided_map(context=context, pkgs=context.to_install, fill_installed=False)
tf = time.time()
self.logger.info("It took {0:.2f} seconds to retrieve required upgrade packages".format(tf - ti))
self.logger.info(f"It took {tf - ti:.2f} seconds to retrieve required upgrade packages")
return True
def __fill_provided_map(self, context: UpdateRequirementsContext, pkgs: Dict[str, ArchPackage], fill_installed: bool = True):
def __fill_provided_map(self, context: UpdateRequirementsContext, pkgs: Dict[str, ArchPackage],
fill_installed: bool = True):
if pkgs:
ti = time.time()
self.logger.info("Filling provided names")
@@ -304,26 +380,26 @@ class UpdatesSummarizer:
installed_to_ignore = set()
for pkgname in pkgs:
pacman.fill_provided_map(pkgname, pkgname, context.provided_map)
context.add_to_provided_map(pkgname, pkgname)
if fill_installed:
installed_to_ignore.add(pkgname)
pdata = context.pkgs_data.get(pkgname)
if pdata and pdata['p']:
pacman.fill_provided_map('{}={}'.format(pkgname, pdata['v']), pkgname, context.provided_map)
context.add_to_provided_map(f"{pkgname}={pdata['v']}", pkgname)
ver_split = pdata['v'].split('-')
if len(ver_split) > 1:
pacman.fill_provided_map('{}={}'.format(pkgname, '-'.join(ver_split[0:-1])), pkgname, context.provided_map)
context.add_to_provided_map(f"{pkgname}={'-'.join(ver_split[0:-1])}", pkgname)
for p in pdata['p']:
pacman.fill_provided_map(p, pkgname, context.provided_map)
context.add_to_provided_map(p, pkgname)
split_provided = p.split('=')
if len(split_provided) > 1 and split_provided[0] != p:
pacman.fill_provided_map(split_provided[0], pkgname, context.provided_map)
context.add_to_provided_map(split_provided[0], pkgname)
if context.installed and installed_to_ignore: # filling the provided names of the installed
installed_to_query = {*context.installed}.difference(installed_to_ignore)
@@ -343,7 +419,10 @@ class UpdatesSummarizer:
context.aur_index.update(names)
self.logger.info("AUR index loaded on the context")
def _map_requirement(self, pkg: ArchPackage, context: UpdateRequirementsContext, installed_sizes: Dict[str, int] = None, to_install: bool = False, to_sync: Set[str] = None) -> UpgradeRequirement:
def _map_requirement(self, pkg: ArchPackage, context: UpdateRequirementsContext,
installed_sizes: Optional[Dict[str, float]] = None, to_install: bool = False,
to_sync: Set[str] = None) -> UpgradeRequirement:
requirement = UpgradeRequirement(pkg)
if pkg.repository != 'aur':
@@ -383,13 +462,15 @@ class UpdatesSummarizer:
required_by.add(p)
break
requirement.reason = '{}: {}'.format(self.i18n['arch.info.required by'].capitalize(), ','.join(required_by) if required_by else '?')
requirement.reason = f"{self.i18n['arch.info.required by'].capitalize()}: " \
f"{','.join(required_by) if required_by else '?'}"
return requirement
def summarize(self, pkgs: List[ArchPackage], root_password: Optional[str], arch_config: dict) -> Optional[UpgradeRequirements]:
res = UpgradeRequirements([], [], [], [])
def summarize(self, pkgs: List[ArchPackage], root_password: Optional[str], arch_config: dict) \
-> Optional[UpgradeRequirements]:
res = UpgradeRequirements([], [], [], [])
remote_provided_map = pacman.map_provided(remote=True)
remote_repo_map = pacman.map_repositories()
context = UpdateRequirementsContext(to_update={}, repo_to_update={}, aur_to_update={}, repo_to_install={},
@@ -434,12 +515,13 @@ class UpdatesSummarizer:
self.logger.info("The operation was cancelled by the user")
return
except PackageNotFoundException as e:
self.logger.error("Package '{}' not found".format(e.name))
self.logger.error(f"Package '{e.name}' not found")
return
if context.pkgs_data:
self._fill_dependency_breakage(context)
if context.to_remove:
self.__update_context_based_on_to_remove(context)
if context.to_update:
@@ -447,7 +529,8 @@ class UpdatesSummarizer:
sorted_pkgs = []
if context.repo_to_update: # only sorting by name ( pacman already knows the best order to perform the upgrade )
if context.repo_to_update:
# only sorting by name (pacman already knows the best order to perform the upgrade)
sorted_pkgs.extend(context.repo_to_update.values())
sorted_pkgs.sort(key=lambda pkg: pkg.name)
@@ -468,16 +551,23 @@ class UpdatesSummarizer:
if context.to_install:
to_sync = {r.pkg.name for r in res.to_upgrade} if res.to_upgrade else {}
to_sync.update(context.to_install.keys())
res.to_install = [self._map_requirement(p, context, to_install=True, to_sync=to_sync) for p in context.to_install.values()]
res.to_install = [self._map_requirement(p, context, to_install=True, to_sync=to_sync)
for p in context.to_install.values()]
res.context['data'] = context.pkgs_data
return res
def __update_context_based_on_to_remove(self, context: UpdateRequirementsContext):
if context.to_remove:
to_remove_provided = {}
# filtering all package to synchronization from the transaction context
to_sync = {*(context.to_update.keys() if context.to_update else set()), *(context.to_install.keys() if context.to_install else set())}
to_sync = set()
if context.to_update:
to_sync.update(context.to_update.keys())
if context.to_install:
to_sync.update(context.to_install.keys())
to_remove_provided = {}
if to_sync: # checking if any packages to sync on the context rely on the 'to remove' ones
to_remove_provided.update(pacman.map_provided(remote=False, pkgs=context.to_remove.keys()))
to_remove_from_sync = {} # will store all packages that should be removed
@@ -498,16 +588,18 @@ class UpdatesSummarizer:
if required:
to_remove_from_sync[pname] = required
else:
self.logger.warning("Conflict resolution: package '{}' marked to synchronization has no data loaded")
self.logger.warning(f"Conflict resolution: package '{pname}' marked to synchronization "
f"has no data loaded")
if to_remove_from_sync: # removing all these packages and their dependents from the context
self._add_to_remove(to_sync, to_remove_from_sync, context)
# checking if the installed packages that are not in the transaction context rely on the current packages to be removed:
# checking if the installed packages that are not in the transaction context rely on the current
# packages to be removed:
current_to_remove = {*context.to_remove.keys()}
required_by_installed = self.deps_analyser.map_all_required_by(current_to_remove, {*to_sync})
required_by_to_remove = self.deps_analyser.map_all_required_by(current_to_remove, {*to_sync})
if required_by_installed:
if required_by_to_remove:
# updating provided context:
provided_not_mapped = set()
for pkg in current_to_remove.difference({*to_remove_provided.keys()}):
@@ -523,12 +615,12 @@ class UpdatesSummarizer:
if provided_not_mapped:
to_remove_provided.update(pacman.map_provided(remote=False, pkgs=provided_not_mapped))
deps_no_data = {dep for dep in required_by_installed if dep in context.pkgs_data}
deps_no_data = {dep for dep in required_by_to_remove if dep not in context.pkgs_data}
deps_nodata_deps = pacman.map_required_dependencies(*deps_no_data) if deps_no_data else {}
reverse_to_remove_provided = {p: name for name, provided in to_remove_provided.items() for p in provided}
for pkg in required_by_installed:
for pkg in required_by_to_remove:
if pkg not in context.to_remove:
if pkg in context.pkgs_data:
dep_deps = context.pkgs_data[pkg].get('d')
@@ -536,11 +628,20 @@ class UpdatesSummarizer:
dep_deps = deps_nodata_deps.get(pkg)
if dep_deps:
source = ', '.join((reverse_to_remove_provided[d] for d in dep_deps if d in reverse_to_remove_provided))
reason = "{} '{}'".format(self.i18n['arch.info.depends on'].capitalize(), source if source else '?')
source = ', '.join(
(reverse_to_remove_provided[d] for d in dep_deps if d in reverse_to_remove_provided))
reason = f"{self.i18n['arch.info.depends on'].capitalize()} '{source if source else '?'}'"
else:
reason = '?'
pkg_repo = context.remote_repo_map.get(pkg)
pkg_version = context.installed.get(pkg)
context.to_remove[pkg] = UpgradeRequirement(pkg=ArchPackage(name=pkg,
installed=True,
i18n=self.i18n),
i18n=self.i18n,
version=pkg_version,
latest_version=pkg_version,
repository=pkg_repo),
reason=reason)
for name in context.to_remove: # upgrading lists
@@ -562,7 +663,9 @@ class UpdatesSummarizer:
if req:
req.extra_size = size
def _add_to_remove(self, pkgs_to_sync: Set[str], names: Dict[str, Set[str]], context: UpdateRequirementsContext, to_ignore: Set[str] = None):
def _add_to_remove(self, pkgs_to_sync: Set[str], names: Dict[str, Set[str]], context: UpdateRequirementsContext,
to_ignore: Set[str] = None):
blacklist = to_ignore if to_ignore else set()
blacklist.update(names)
@@ -582,20 +685,19 @@ class UpdatesSummarizer:
dependents[n] = all_deps
else:
self.logger.warning("Package '{}' to sync could not be removed from the transaction context because its data was not loaded")
self.logger.warning(f"Package '{pname}' to sync could not be removed from the transaction context "
f"because its data was not loaded")
for n in names:
if n in context.pkgs_data:
if n not in context.to_remove:
depends_on = names.get(n)
if depends_on:
reason = "{} '{}'".format(self.i18n['arch.info.depends on'].capitalize(), ', '.join(depends_on))
reason = f"{self.i18n['arch.info.depends on'].capitalize()} '{', '.join(depends_on)}'"
else:
reason = '?'
context.to_remove[n] = UpgradeRequirement(pkg=ArchPackage(name=n,
installed=True,
i18n=self.i18n),
context.to_remove[n] = UpgradeRequirement(pkg=ArchPackage(name=n, installed=True, i18n=self.i18n),
reason=reason)
all_deps = dependents.get(n)
@@ -603,7 +705,8 @@ class UpdatesSummarizer:
if all_deps:
self._add_to_remove(pkgs_to_sync, {dep: {n} for dep in all_deps}, context, blacklist)
else:
self.logger.warning("Package '{}' could not be removed from the transaction context because its data was not loaded")
self.logger.warning(f"Package '{n}' could not be removed from the transaction context because its "
f"data was not loaded")
def _fill_dependency_breakage(self, context: UpdateRequirementsContext):
if bool(context.arch_config['check_dependency_breakage']) and (context.to_update or context.to_install):
@@ -667,9 +770,10 @@ class UpdatesSummarizer:
context=context)
if cannot_upgrade:
pkgs_available = {*context.to_update.values(), *context.to_install.values()}
cannot_upgrade.update(self._add_dependents_as_cannot_upgrade(context=context,
names=cannot_upgrade,
pkgs_available={*context.to_update.values(), *context.to_install.values()}))
pkgs_available=pkgs_available))
for p in cannot_upgrade:
if p in context.to_update:
@@ -696,7 +800,9 @@ class UpdatesSummarizer:
tf = time.time()
self.logger.info("End: checking dependency breakage. Time: {0:.2f} seconds".format(tf - ti))
def _add_dependents_as_cannot_upgrade(self, context: UpdateRequirementsContext, names: Iterable[str], pkgs_available: Set[ArchPackage], already_removed: Optional[Set[str]] = None, iteration_level: int = 0) -> Set[str]:
def _add_dependents_as_cannot_upgrade(self, context: UpdateRequirementsContext, names: Iterable[str],
pkgs_available: Set[ArchPackage], already_removed: Optional[Set[str]] = None,
iteration_level: int = 0) -> Set[str]:
removed = set() if already_removed is None else already_removed
removed.update(names)
@@ -718,11 +824,10 @@ class UpdatesSummarizer:
to_remove.add(pkg.name)
if pkg.name not in context.cannot_upgrade:
reason = "{} {}".format(self.i18n['arch.info.depends on'].capitalize(), p)
context.cannot_upgrade[pkg.name] = UpgradeRequirement(pkg=pkg,
reason=reason,
reason = f"{self.i18n['arch.info.depends on'].capitalize()} {p}"
req = UpgradeRequirement(pkg=pkg, reason=reason,
sorting_priority=iteration_level - 1)
context.cannot_upgrade[pkg.name] = req
break
if to_remove:
@@ -732,7 +837,9 @@ class UpdatesSummarizer:
return to_remove
def _add_dependency_breakage(self, pkgname: str, pkgdeps: Optional[Set[str]], provided_versions: Dict[str, Set[str]], cannot_upgrade: Set[str], context: UpdateRequirementsContext):
def _add_dependency_breakage(self, pkgname: str, pkgdeps: Optional[Set[str]],
provided_versions: Dict[str, Set[str]], cannot_upgrade: Set[str],
context: UpdateRequirementsContext):
if pkgdeps:
for dep in pkgdeps:
dep_split = RE_DEP_OPERATORS.split(dep)
@@ -750,11 +857,14 @@ class UpdatesSummarizer:
for v in versions:
try:
if match_required_version(current_version=v, operator=op, required_version=dep_split[1]):
if match_required_version(current_version=v,
operator=op,
required_version=dep_split[1]):
version_match = True
break
except:
self.logger.error("Error when comparing versions {} (provided) and {} (required)".format(v, dep_split[1]))
self.logger.error(f"Error when comparing versions {v} (provided) and "
f"{dep_split[1]} (required)")
traceback.print_exc()
if not version_match:

View File

@@ -1,52 +1,52 @@
Australia=Australia
Austria=Austria
Bangladesh=Bangladesh
Belarus=Belarus
Belgium=Belgium
Brazil=Brazil
Belarus=Biellorussia
Belgium=Belgio
Brazil=Brasile
Bulgaria=Bulgaria
Canada=Canada
Chile=Chile
China=China
Chile=Cile
China=Cina
Costa Rica=Costa Rica
Czech=Czech
Denmark=Denmark
Czech=Cecoslovacchia
Denmark=Danimarca
Ecuador=Ecuador
France=France
France=Francia
Georgia=Georgia
Germany=Germany
Greece=Greece
Germany=Germania
Greece=Grecia
Hong Kong=Hong Kong
Hungary=Hungary
Iceland=Iceland
Hungary=Ungheria
Iceland=Islanda
India=India
Indonesia=Indonesia
Iran=Iran
Italy=Italy
Japan=Japan
Italy=Italia
Japan=Giappone
Kenya=Kenya
Netherlands=Netherlands
New Zealand=New Zealand
Norway=Norway
Philippines=Philippines
Poland=Poland
Portugal=Portugal
Netherlands=Olanda
New Zealand=Nuova Zelanda
Norway=Norvegia
Philippines=Filippine
Poland=Polonia
Portugal=Portogallo
Russia=Russia
Singapore=Singapore
South Africa=South Africa
South Korea=South Korea
Spain=Spain
Sweden=Sweden
Switzerland=Switzerland
South Korea=Korea del Sud
Spain=Spagna
Sweden=Svezia
Switzerland=Svizzera
Taiwan=Taiwan
Thailand=Thailand
Turkey=Turkey
Ukraine=Ukraine
United Kingdom=United Kingdom
United States=United States
action.backup.error.create=It was not possible to generate a new system copy
action.backup.error.delete=It was not possible to delete all the old system copies
action.backup.error.proceed=Proceed anyway ?
Thailand=Tailandia
Turkey=Turchia
Ukraine=Ucraina
United Kingdom=Regno Unito
United States=Stati Uniti
action.backup.error.create=Non è stato possibile generare una nuova copia di sistema
action.backup.error.delete=Non è stato possibile eliminare tutte le vecchie copie di sistema
action.backup.error.proceed=Procedere comunque ?
action.backup.invalid_mode=Invalid backup mode
action.backup.msg=Do you want to generate a system copy before proceeding ?
action.backup.substatus.create=Generating a new system backup

File diff suppressed because it is too large Load Diff