diff --git a/actions/upgrades b/actions/upgrades index 4d894782b..e9d4ca96a 100755 --- a/actions/upgrades +++ b/actions/upgrades @@ -522,10 +522,6 @@ def _perform_dist_upgrade(): print( 'Holding packages with conffile prompts: ' + ', '.join(DIST_UPGRADE_PACKAGES_WITH_PROMPTS) + '...', flush=True) - # XXX: If any of these packages have been removed from the - # next stable release, they will causes the hold command to - # fail for all packages. So it would be safer to just hold one - # package at a time. with apt_hold(DIST_UPGRADE_PACKAGES_WITH_PROMPTS): print('Running apt full-upgrade...', flush=True) run_apt_command(['full-upgrade']) diff --git a/plinth/action_utils.py b/plinth/action_utils.py index ccc71a0e6..86042f85a 100644 --- a/plinth/action_utils.py +++ b/plinth/action_utils.py @@ -424,16 +424,33 @@ def run_apt_command(arguments): @contextmanager -def apt_hold(packages, ignore_errors=False): - """Prevent packages from being removed during apt operations.""" - current_hold = subprocess.check_output(['apt-mark', 'showhold'] + packages) - try: - yield current_hold or subprocess.run(['apt-mark', 'hold'] + packages, - check=not ignore_errors) - finally: +def apt_hold(packages): + """Prevent packages from being removed during apt operations. + + `apt-mark hold PACKAGES` accepts a list of packages. But if one of + the package is missing from the apt repository, then it will fail + to hold any of the listed packages. So it is necessary to try to + hold each package by itself. + + Packages held by this context will be unheld when leaving the + context. But if a package was already held beforehand, it will be + ignored (and not unheld). + + """ + held_packages = [] + for package in packages: + current_hold = subprocess.check_output( + ['apt-mark', 'showhold', package]) if not current_hold: - subprocess.run(['apt-mark', 'unhold'] + packages, - check=not ignore_errors) + process = subprocess.run(['apt-mark', 'hold', package], + check=False) + if process.returncode == 0: # success + held_packages.append(package) + + yield held_packages + + for package in held_packages: + subprocess.check_call(['apt-mark', 'unhold', package]) @contextmanager