Esempio n. 1
0
    def _handle_conflict_to_update_and_to_install(
            self, pkg1: str, pkg2: str, pkg1_to_install: bool,
            context: UpdateRequirementsContext):
        to_install, to_update = (pkg1, pkg2) if pkg1_to_install else (pkg2,
                                                                      pkg1)
        to_install_srcs = {
            p
            for p, data in context.pkgs_data.items()
            if data['d'] and to_install in data['d']
        }

        if to_update not in context.cannot_upgrade:
            srcs_str = ', '.join(("'{}'".format(p) for p in to_install_srcs))
            reason = self.i18n[
                'arch.update_summary.to_update.conflicts_dep'].format(
                    "'{}'".format(to_install), srcs_str)
            context.cannot_upgrade[to_install] = UpgradeRequirement(
                context.to_update[to_update], reason)

        if to_update in context.to_update:
            del context.to_update[to_update]

        for src_pkg in to_install_srcs:
            src_to_install = src_pkg in context.to_install
            pkg = context.to_install[
                src_pkg] if src_to_install else context.to_update[src_pkg]
            if src_pkg not in context.cannot_upgrade:
                reason = self.i18n[
                    'arch.update_summary.to_update.dep_conflicts'].format(
                        "'{}'".format(to_install), "'{}'".format(to_update))
                context.cannot_upgrade[src_pkg] = UpgradeRequirement(
                    pkg, reason)

            if src_to_install:
                del context.to_install[src_pkg]

                if src_pkg in context.repo_to_install:
                    del context.repo_to_install[src_pkg]
                else:
                    del context.aur_to_install[src_pkg]
            else:
                del context.to_update[src_pkg]

                if src_pkg in context.repo_to_update:
                    del context.repo_to_update[src_pkg]
                else:
                    del context.aur_to_update[src_pkg]

            del context.pkgs_data[src_pkg]

        if to_install in context.to_install:
            del context.to_install[to_install]
Esempio n. 2
0
    def _fill_conflicts(self,
                        context: UpdateRequirementsContext,
                        blacklist: Iterable[str] = None):
        self.logger.info("Checking conflicts")

        root_conflict = self._filter_and_map_conflicts(context)

        sub_conflict = pacman.get_dependencies_to_remove(
            root_conflict.keys(),
            context.root_password) if root_conflict else None

        to_remove_map = {}
        if sub_conflict:
            for dep, source in sub_conflict.items():
                if dep not in to_remove_map and (not blacklist
                                                 or dep not in blacklist):
                    req = ArchPackage(name=dep, installed=True, i18n=self.i18n)
                    to_remove_map[dep] = req
                    reason = "{} '{}'".format(
                        self.i18n['arch.info.depends on'].capitalize(), source)
                    context.to_remove[dep] = UpgradeRequirement(req, reason)

        if root_conflict:
            for dep, source in root_conflict.items():
                if dep not in to_remove_map and (not blacklist
                                                 or dep not in blacklist):
                    req = ArchPackage(name=dep, installed=True, i18n=self.i18n)
                    to_remove_map[dep] = req
                    reason = "{} '{}'".format(
                        self.i18n['arch.info.conflicts with'].capitalize(),
                        source)
                    context.to_remove[dep] = UpgradeRequirement(req, reason)

        if to_remove_map:
            for name in to_remove_map.keys():  # upgrading lists
                if name in context.pkgs_data:
                    del context.pkgs_data[name]

                if name in context.aur_to_update:
                    del context.aur_to_update[name]

                if name in context.repo_to_update:
                    del context.repo_to_update[name]

            removed_size = pacman.get_installed_size([*to_remove_map.keys()])

            if removed_size:
                for name, size in removed_size.items():
                    if size is not None:
                        req = context.to_remove.get(name)
                        if req:
                            req.extra_size = size
Esempio n. 3
0
    def _map_requirement(self, pkg: ArchPackage, context: UpdateRequirementsContext, installed_sizes: Dict[str, int] = None) -> UpgradeRequirement:
        requirement = UpgradeRequirement(pkg)

        if pkg.repository != 'aur':
            data = context.pkgs_data[pkg.name]
            requirement.required_size = data['ds']
            requirement.extra_size = data['s']
    
            current_size = installed_sizes.get(pkg.name) if installed_sizes else None

            if current_size is not None and data['s']:
                requirement.extra_size = data['s'] - current_size

        return requirement
Esempio n. 4
0
    def get_upgrade_requirements(self, pkgs: List[AppImage], root_password: Optional[str], watcher: ProcessWatcher) -> UpgradeRequirements:
        to_update = []

        for pkg in pkgs:
            requirement = UpgradeRequirement(pkg)
            installed_size = self.http_client.get_content_length_in_bytes(pkg.url_download)
            upgrade_size = self.http_client.get_content_length_in_bytes(pkg.url_download_latest_version)
            requirement.required_size = upgrade_size

            if upgrade_size and installed_size:
                requirement.extra_size = upgrade_size - installed_size

            to_update.append(requirement)

        return UpgradeRequirements([], [], to_update, [])
Esempio n. 5
0
    def _handle_conflict_both_to_install(self, pkg1: str, pkg2: str, context: UpdateRequirementsContext):
        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))
                context.cannot_upgrade[src_pkg] = UpgradeRequirement(context.to_update[src_pkg], reason)

            del context.to_update[src_pkg]

            if src_pkg in context.repo_to_update:
                del context.repo_to_update[src_pkg]
            else:
                del context.aur_to_update[src_pkg]

            del context.pkgs_data[src_pkg]

        for p in (pkg1, pkg2):
            if p in context.to_install:
                del context.to_install[p]

                if p in context.repo_to_install:
                    del context.repo_to_install[p]
                else:
                    del context.aur_to_install[p]
Esempio n. 6
0
    def get_upgrade_requirements(
            self, pkgs: List[FlatpakApplication], root_password: str,
            watcher: ProcessWatcher) -> UpgradeRequirements:
        flatpak_version = flatpak.get_version()

        user_pkgs, system_pkgs = [], []

        for pkg in pkgs:
            if pkg.installation == 'user':
                user_pkgs.append(pkg)
            else:
                system_pkgs.append(pkg)

        for apps_by_install in ((user_pkgs, 'user'), (system_pkgs, 'system')):
            if apps_by_install[0]:
                sizes = flatpak.map_update_download_size(
                    [str(p.id) for p in apps_by_install[0]],
                    apps_by_install[1], flatpak_version)

                if sizes:
                    for p in apps_by_install[0]:
                        p.size = sizes.get(str(p.id))

        to_update = [
            UpgradeRequirement(pkg=p, extra_size=p.size, required_size=p.size)
            for p in self.sort_update_order(pkgs)
        ]
        return UpgradeRequirements(None, None, to_update, [])
Esempio n. 7
0
    def update_file(self, pkg: AppImage, root_password: Optional[str], watcher: ProcessWatcher):
        max_width = 350
        file_chooser = FileChooserComponent(label=self.i18n['file'].capitalize(),
                                            allowed_extensions={'AppImage', '*'},
                                            search_path=get_default_manual_installation_file_dir(),
                                            max_width=max_width)
        input_version = TextInputComponent(label=self.i18n['version'].capitalize(), max_width=max_width)
        file_chooser.observers.append(ManualInstallationFileObserver(None, input_version))

        while True:
            if watcher.request_confirmation(title=self.i18n['appimage.custom_action.manual_update.details'], body=None,
                                            components=[FormComponent(label='', components=[file_chooser, input_version], spaces=False)],
                                            confirmation_label=self.i18n['proceed'].capitalize(),
                                            deny_label=self.i18n['cancel'].capitalize(),
                                            min_height=100, max_width=max_width + 150):

                if not file_chooser.file_path or not os.path.isfile(file_chooser.file_path) or not file_chooser.file_path.lower().strip().endswith('.appimage'):
                    watcher.request_confirmation(title=self.i18n['error'].capitalize(),
                                                 body=self.i18n['appimage.custom_action.install_file.invalid_file'],
                                                 deny_button=False)
                else:
                    break
            else:
                return False

        pkg.local_file_path = file_chooser.file_path
        pkg.version = input_version.get_value()

        reqs = UpgradeRequirements(to_install=None, to_remove=None, to_upgrade=[UpgradeRequirement(pkg=pkg)], cannot_upgrade=None)
        return self.upgrade(reqs, root_password=root_password, watcher=watcher)
Esempio n. 8
0
    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)
            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)
            context.cannot_upgrade[pkg2] = UpgradeRequirement(pkg=context.to_update[pkg2], reason=reason)

        for p in (pkg1, pkg2):
            if p in context.to_update:
                del context.to_update[p]

                if p in context.repo_to_update:
                    del context.repo_to_update[p]
                else:
                    del context.aur_to_update[p]
Esempio n. 9
0
    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)

        dependents = {}
        for pname in pkgs_to_sync:
            if pname not in blacklist:
                data = context.pkgs_data.get(pname)

                if data:
                    deps = data.get('d')

                    if deps:
                        for n in names:
                            if n in deps:
                                all_deps = dependents.get(n, set())
                                all_deps.update(pname)
                                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"
                    )

        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))
                    else:
                        reason = '?'

                    context.to_remove[n] = UpgradeRequirement(pkg=ArchPackage(
                        name=n, installed=True, i18n=self.i18n),
                                                              reason=reason)

                all_deps = dependents.get(n)

                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"
                )
Esempio n. 10
0
    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)

        available = {p for p in pkgs_available if p.name not in removed}
        to_remove = set()

        if available:
            for pkg in available:
                if pkg.name not in removed:
                    data = context.pkgs_data.get(pkg.name)

                    if data and data['d']:
                        for dep in data['d']:
                            dep_providers = context.provided_map.get(dep)

                            if dep_providers:
                                for p in dep_providers:
                                    if p in names:
                                        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,
                                                    sorting_priority=
                                                    iteration_level - 1)

                                        break

            if to_remove:
                removed.update(to_remove)
                self._add_dependents_as_cannot_upgrade(
                    context=context,
                    names=to_remove,
                    pkgs_available=available,
                    already_removed=to_remove,
                    iteration_level=iteration_level - 1)

        return to_remove
Esempio n. 11
0
    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)

                if len(dep_split) > 1 and dep_split[1]:
                    real_providers = context.provided_map.get(dep_split[0])

                    if real_providers:
                        versions = provided_versions.get(dep_split[0])

                        if versions:
                            op = ''.join(RE_DEP_OPERATORS.findall(dep))

                            if op == '=':
                                op = '=='

                            version_match = False

                            for v in versions:
                                try:
                                    provided_version, required_version = parse_version(
                                        v), parse_version(dep_split[1])

                                    if eval('provided_version {} required_version'
                                            .format(op)):
                                        version_match = True
                                        break
                                except:
                                    self.logger.error(
                                        "Error when comparing versions {} (provided) and {} (required)"
                                        .format(v, dep_split[1]))
                                    traceback.print_exc()

                            if not version_match:
                                for pname in real_providers:
                                    if pname not in cannot_upgrade:
                                        provider = context.to_update.get(pname)
                                        if provider:
                                            cannot_upgrade.add(pname)
                                            reason = self.i18n[
                                                'arch.sync.dep_breakage.reason'].format(
                                                    pkgname, dep)
                                            context.cannot_upgrade[
                                                pname] = UpgradeRequirement(
                                                    pkg=provider,
                                                    reason=reason)
Esempio n. 12
0
    def _fill_conflicts(self,
                        context: UpdateRequirementsContext,
                        blacklist: Iterable[str] = None):
        self.logger.info("Checking conflicts")

        root_conflict = self._filter_and_map_conflicts(context)

        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)
Esempio n. 13
0
    def _map_requirement(self,
                         pkg: ArchPackage,
                         context: UpdateRequirementsContext,
                         installed_sizes: Dict[str, int] = None,
                         to_install: bool = False,
                         to_sync: Set[str] = None) -> UpgradeRequirement:
        requirement = UpgradeRequirement(pkg)

        if pkg.repository != 'aur':
            pkgdata = context.pkgs_data.get(pkg.name)

            if pkgdata:
                requirement.required_size = pkgdata['ds']
                requirement.extra_size = pkgdata['s']

                current_size = installed_sizes.get(
                    pkg.name) if installed_sizes else None

                if current_size is not None and pkgdata['s'] is not None:
                    requirement.extra_size = pkgdata['s'] - current_size

            required_by = set()

            if to_install and to_sync and context.pkgs_data:
                names = pkgdata.get('p', {pkg.name}) if pkgdata else {pkg.name}
                to_sync_deps_cache = {}
                for p in to_sync:
                    if p != pkg.name and p in context.pkgs_data:
                        deps = to_sync_deps_cache.get(p)

                        if deps is None:
                            deps = context.pkgs_data[p]['d']

                            if deps is None:
                                deps = set()
                            else:
                                deps = {
                                    RE_DEP_OPERATORS.split(d)[0]
                                    for d in deps
                                }

                            to_sync_deps_cache[p] = deps

                        if deps:
                            for n in names:
                                if n in deps:
                                    required_by.add(p)
                                    break

                requirement.reason = '{}: {}'.format(
                    self.i18n['arch.info.required by'].capitalize(),
                    ','.join(required_by) if required_by else '?')

        return requirement
Esempio n. 14
0
    def update_file(self, pkg: AppImage, root_password: str,
                    watcher: ProcessWatcher):
        file_chooser = FileChooserComponent(
            label=self.i18n['file'].capitalize(),
            allowed_extensions={'AppImage'})
        input_version = TextInputComponent(
            label=self.i18n['version'].capitalize())

        while True:
            if watcher.request_confirmation(
                    title=self.
                    i18n['appimage.custom_action.manual_update.details'],
                    body=None,
                    components=[
                        FormComponent(label='',
                                      components=[file_chooser, input_version],
                                      spaces=False)
                    ],
                    confirmation_label=self.i18n['proceed'].capitalize(),
                    deny_label=self.i18n['cancel'].capitalize()):
                if not file_chooser.file_path or not os.path.isfile(
                        file_chooser.file_path):
                    watcher.request_confirmation(
                        title=self.i18n['error'].capitalize(),
                        body=self.i18n[
                            'appimage.custom_action.install_file.invalid_file'],
                        deny_button=False)
                else:
                    break
            else:
                return False

        pkg.local_file_path = file_chooser.file_path
        pkg.version = input_version.get_value()

        reqs = UpgradeRequirements(to_install=None,
                                   to_remove=None,
                                   to_upgrade=[UpgradeRequirement(pkg=pkg)],
                                   cannot_upgrade=None)
        return self.upgrade(reqs, root_password=root_password, watcher=watcher)
Esempio n. 15
0
    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())
            }
            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

                for pname in to_sync:
                    if pname in context.pkgs_data:
                        deps = context.pkgs_data[pname].get('d')

                        if deps:
                            required = set()

                            for pkg in context.to_remove:
                                for provided in to_remove_provided[pkg]:
                                    if provided in deps:
                                        required.add(pkg)
                                        break

                            if required:
                                to_remove_from_sync[pname] = required
                    else:
                        self.logger.warning(
                            "Conflict resolution: package '{}' marked to synchronization 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:
            current_to_remove = {*context.to_remove.keys()}
            required_by_installed = self.deps_analyser.map_all_required_by(
                current_to_remove, {*to_sync})

            if required_by_installed:
                # updating provided context:
                provided_not_mapped = set()
                for pkg in current_to_remove.difference(
                    {*to_remove_provided.keys()}):
                    if pkg not in context.pkgs_data:
                        provided_not_mapped.add(pkg)
                    else:
                        provided = context.pkgs_data[pkg].get('p')
                        if provided:
                            to_remove_provided[pkg] = provided
                        else:
                            provided_not_mapped.add(pkg)

                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_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:
                    if pkg not in context.to_remove:
                        if pkg in context.pkgs_data:
                            dep_deps = context.pkgs_data[pkg].get('d')
                        else:
                            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 '?')
                            context.to_remove[pkg] = UpgradeRequirement(
                                pkg=ArchPackage(name=pkg,
                                                installed=True,
                                                i18n=self.i18n),
                                reason=reason)

            for name in context.to_remove:  # upgrading lists
                if name in context.pkgs_data:
                    del context.pkgs_data[name]

                if name in context.aur_to_update:
                    del context.aur_to_update[name]

                if name in context.repo_to_update:
                    del context.repo_to_update[name]

            removed_size = pacman.get_installed_size(
                [*context.to_remove.keys()])

            if removed_size:
                for name, size in removed_size.items():
                    if size is not None:
                        req = context.to_remove.get(name)
                        if req:
                            req.extra_size = size
Esempio n. 16
0
    def get_upgrade_requirements(self, pkgs: List[DebianPackage], root_password: str, watcher: ProcessWatcher) \
            -> UpgradeRequirements:

        transaction = self.aptitude.simulate_upgrade((p.name for p in pkgs))

        if transaction:
            size_to_query = (f'{p.name}={p.latest_version}' for p in (*transaction.to_upgrade,
                                                                      *transaction.to_install,
                                                                      *transaction.to_remove))

            update_extra_attrs = ('compressed size', *(('depends', 'predepends') if transaction.to_install else ()))
            update_data = self.aptitude.show(pkgs=size_to_query, attrs=update_extra_attrs)

            to_install = None
            if transaction.to_install:
                dependents = self._map_dependents(update_data)

                to_install = []
                for p in transaction.to_install:
                    p_data = update_data.get(p.name) if update_data else None
                    req_size = p_data.get('compressed size') if p_data else None

                    reason = None
                    if dependents:
                        p_dependents = dependents.get(p.name)

                        if p_dependents:
                            deps_str = ', '.join((bold(d) for d in p_dependents))
                            reason = self._i18n['debian.transaction.dependency_of'].format(pkgs=deps_str)

                    to_install.append(UpgradeRequirement(pkg=p, reason=reason, required_size=req_size,
                                                         extra_size=p.transaction_size))

                to_install.sort(key=attrgetter('pkg.name'))
                to_install = tuple(to_install)

            to_remove = None
            if transaction.to_remove:
                to_remove = []

                for p in transaction.to_remove:
                    to_remove.append(UpgradeRequirement(pkg=p, required_size=0, extra_size=p.transaction_size))

                to_remove.sort(key=attrgetter('pkg.name'))
                to_remove = tuple(to_remove)

            to_upgrade = None

            if transaction.to_upgrade:
                to_upgrade = []

                for p in transaction.to_upgrade:
                    p_data = update_data.get(p.name) if update_data else None

                    if p_data:
                        req_size = p_data.get('compressed size')
                    else:
                        req_size = None

                    to_upgrade.append(UpgradeRequirement(pkg=p, required_size=req_size, extra_size=p.transaction_size))

                to_upgrade.sort(key=attrgetter('pkg.name'))
                to_upgrade = tuple(to_upgrade)

            return UpgradeRequirements(to_install=to_install, to_upgrade=to_upgrade,
                                       to_remove=to_remove, cannot_upgrade=None)
        else:
            cannot_upgrade = [UpgradeRequirement(pkg=p, reason=self._i18n['error']) for p in pkgs]
            cannot_upgrade.sort(key=attrgetter('pkg.name'))
            return UpgradeRequirements(cannot_upgrade=cannot_upgrade, to_install=None, to_remove=None,
                                       to_upgrade=[])