[Merge] ~enr0n/ubuntu-release-upgrader:t64-replacements into ubuntu-release-upgrader:ubuntu/main

Julian Andres Klode mp+464340 at code.launchpad.net
Mon Apr 15 17:11:44 UTC 2024


Review: Approve

This seems to work for me but could be made faster by using APT's rev_depends_list and provides_list of the apt_pkg.Package object.

Diff comments:

> diff --git a/DistUpgrade/DistUpgradeQuirks.py b/DistUpgrade/DistUpgradeQuirks.py
> index 986f88d..9d7b6d6 100644
> --- a/DistUpgrade/DistUpgradeQuirks.py
> +++ b/DistUpgrade/DistUpgradeQuirks.py
> @@ -1726,3 +1736,75 @@ class DistUpgradeQuirks(object):
>                  ) + updates_end_msg,
>              )
>              self.controller.abort()
> +
> +    def _install_t64_replacement_packages(self):
> +        """
> +        LP: #2061175
> +        """
> +        for package in self.controller.cache:
> +            if not package.is_installed:
> +                continue
> +
> +            if package.candidate and package.candidate.downloadable:
> +                continue
> +
> +            # If we get here, then it means that this package is installed
> +            # and its candidate version is obsolete (i.e. not downloadable).
> +            # Now, we need to find a replacement for it.
> +            logging.debug(f'Searching for replacement for {package.name}')
> +
> +            replacement = None
> +            for p in self.controller.cache:

This seems very slow, could you use use package._pkg.reverse_depends_list to query just the reverse depends? For example, you can do:

rdeps = [(dep.parent_ver, dep.dep_type_untranslated) for dep in package._pkg.rev_depends_list]
prvs = [providing_ver for _, _, providing_ver in package._pkg.provides_list]

To get the reverse depends as tuples (apt_pkg.Version, str) and providers of the package. as (apt_pkg.Version). Then you can check if any of the providers also Conflicts or Breaks, and Replaces it:

replacements = [prv for prv in prvs if ((prv, "Breaks") in rdeps or (prv, "Conflicts") in rdeps) and (prv, "Replaces") in rdeps]

Then you can construct the apt.Package for the replacement's parent_pkg (apt_pkg.Package):

for replacement_cand in replacements:
    replacement_package = apt.Package(cache, replacement_cand.parent_pkg)
    if replacement_package.candidate._cand == replacement_cand:
       break
else:
    print("No replacement found")
    continue

The temporary replacements array being a bit unreadable perhaps, the loop could also just iterate over the providers and add an if continue.

> +                depends_list = p.candidate._cand.depends_list_str
> +
> +                replaces = False
> +                for replace_list in depends_list.get('Replaces', []):
> +                    if package.name in [
> +                        name for (name, _, _) in replace_list
> +                    ]:
> +                        replaces = True
> +                        break
> +
> +                if not replaces:
> +                    continue
> +
> +                conflicts_or_breaks = False
> +                for conflict_list in depends_list.get('Conflicts', []):
> +                    if package.name in [
> +                        name for (name, _, _) in conflict_list
> +                    ]:
> +                        conflicts_or_breaks = True
> +                        break
> +
> +                if not conflicts_or_breaks:
> +                    for break_list in depends_list.get('Breaks', []):
> +                        if package.name in [
> +                            name for (name, _, _) in break_list
> +                        ]:
> +                            conflicts_or_breaks = True
> +                            break
> +
> +                if not conflicts_or_breaks:
> +                    continue
> +
> +                if package.name not in [
> +                    name for (name, _, _) in p.candidate._cand.provides_list
> +                ]:
> +                    continue
> +
> +                # Cool, we found a replacement.
> +                replacement = p
> +                break
> +
> +            if replacement is not None:
> +                logging.debug(
> +                    f'Found replacement {replacement.name} for {package.name}'
> +                )
> +
> +                replacement.mark_install(auto_fix=False, auto_inst=False)
> +                package.mark_delete(auto_fix=False)
> +                apt.ProblemResolver(self.controller.cache).protect(package)

I see this is needed because upgrader will call MarkInstall on each installed package even if it has no upgrade available. APT is weird.

> +            else:
> +                logging.debug(
> +                    f'Failed to find a replacement for {package.name}'
> +                )


-- 
https://code.launchpad.net/~enr0n/ubuntu-release-upgrader/+git/ubuntu-release-upgrader/+merge/464340
Your team Ubuntu Core Development Team is subscribed to branch ubuntu-release-upgrader:ubuntu/main.




More information about the Ubuntu-reviews mailing list