action_utils: Use flag to indicate freedombox package has been held

In case the plinth process is interrupted, the "finally" block that is
meant to unhold the package may not be executed, and the package will
stay held. The flag is used to indicate this situation, so it can be
resolved the next time apt_hold_freedombox is used.

Tests:

- (normal) No hold on freedombox package, and flag is not set. Install
  any app. Afterwards, there is no hold, and flag is not set.

- (admin preference) Place hold on freedombox package, but flag is not
  set. Install any app. Afterwards, there is still a hold, but flag is
  not set.

- (recovery) Place hold on freedombox package, but flag is
  set. Install any app. Afterwards, there is no hold, and flag is not
  set.

Signed-off-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
James Valleroy 2021-06-23 18:12:47 -04:00
parent eccc355203
commit 9c57347931
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808

View File

@ -5,6 +5,7 @@ Python action utility functions.
import logging
import os
import pathlib
import shutil
import subprocess
import tempfile
@ -428,11 +429,23 @@ def apt_hold(packages, ignore_errors=False):
@contextmanager
def apt_hold_freedombox():
"""Prevent freedombox package from being removed during apt operations."""
# This flag is a backup indicator that we held the package, in
# case the process is interrupted and the 'finally' is not run.
apt_hold_flag = pathlib.Path('/var/lib/freedombox/package-held')
current_hold = subprocess.check_output(
['apt-mark', 'showhold', 'freedombox'])
try:
yield current_hold or subprocess.check_call(
['apt-mark', 'hold', 'freedombox'])
if current_hold:
# Package is already held, possibly by administrator.
yield current_hold
else:
# Set the flag.
apt_hold_flag.touch(mode=0o660)
yield subprocess.check_call(['apt-mark', 'hold', 'freedombox'])
finally:
if not current_hold:
# Was the package held, either in this process or a previous one?
if not current_hold or apt_hold_flag.exists():
subprocess.check_call(['apt-mark', 'unhold', 'freedombox'])
# Clear the flag.
if apt_hold_flag.exists():
apt_hold_flag.unlink()