From 920d0833018b1f4414e1fab5fea11360bff3403d Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Mon, 11 Feb 2019 14:02:06 -0800 Subject: [PATCH] setup: Add option to handle configuration prompts during install This is optional and does not affect normal installations. However, when performing configuration migration in FreedomBox (due to unattended-upgrades refusing it), it is useful as a part of strategy to read configuration, force install new configuration files and apply configuration again. This option can be used on such cases. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/packages | 19 +++++++++++++++---- plinth/package.py | 33 ++++++++++++++++++++++++++------- plinth/setup.py | 5 +++-- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/actions/packages b/actions/packages index 9167fdd1f..f28805937 100755 --- a/actions/packages +++ b/actions/packages @@ -41,6 +41,9 @@ def parse_arguments(): subparser.add_argument( '--skip-recommends', action='store_true', help='whether to skip installing recommended packages') + subparser.add_argument( + '--force-configuration', choices=['new', 'old'], + help='force old/new configuration files during install') subparser.add_argument( 'module', help='name of module for which package is being installed') subparser.add_argument('packages', nargs='+', @@ -85,11 +88,19 @@ def subcommand_install(arguments): print('Access check failed:', exception, file=sys.stderr) sys.exit(99) + extra_arguments = [] if arguments.skip_recommends: - _run_apt_command( - ['install', '--no-install-recommends'] + arguments.packages) - else: - _run_apt_command(['install'] + arguments.packages) + extra_arguments.append('--no-install-recommends') + + if arguments.force_configuration == 'old': + extra_arguments += [ + '-o', 'Dpkg::Options::=--force-confdef', '-o', + 'Dpkg::Options::=--force-confold' + ] + elif arguments.force_configuration == 'new': + extra_arguments += ['-o', 'Dpkg::Options::=--force-confnew'] + + _run_apt_command(['install'] + extra_arguments + arguments.packages) def _assert_managed_packages(module, packages): diff --git a/plinth/package.py b/plinth/package.py index 0731346b8..2e7b1c13b 100644 --- a/plinth/package.py +++ b/plinth/package.py @@ -68,23 +68,42 @@ class Transaction(object): self.percentage = 0 self.stderr = None - def install(self, skip_recommends=False): + def install(self, skip_recommends=False, force_configuration=None): """Run an apt-get transaction to install given packages. FreedomBox Service (Plinth) needs to be running as root when calling this. Currently, this is meant to be only during first time setup when --setup is argument is passed. + If force_configuration is set to 'new', dpkg options will be enabled to + make it force overwrite (without prompts) new configuration in place of + old configuration (with a backup). This is useful when writing + migration scripts in FreedomBox to handle the upgrades when + unattended-upgrades refuse to upgrade a package due to configuration + prompts. + + If force_configuration is set to 'old', dpkg options will be enabled to + make it keep the old configuration (without prompts). This is useful + when the Debian packages introduce new configuration with just + cosmetics (such as updates to comments) and keeping the old + configuration has same semantics. + + If force_configuration is None, no special options are passed to + apt/dpkg for configuration file behavior. + """ try: self._run_apt_command(['update']) + extra_arguments = [] if skip_recommends: - self._run_apt_command( - ['install', '--skip-recommends', self.module_name] + - self.package_names) - else: - self._run_apt_command(['install', self.module_name] + - self.package_names) + extra_arguments.append('--skip-recommends') + + if force_configuration is not None: + extra_arguments.append( + '--force-configuration={}'.format(force_configuration)) + + self._run_apt_command(['install'] + extra_arguments + + [self.module_name] + self.package_names) except subprocess.CalledProcessError as exception: logger.exception('Error installing package: %s', exception) raise diff --git a/plinth/setup.py b/plinth/setup.py index ba8d0c513..05f3c9c3c 100644 --- a/plinth/setup.py +++ b/plinth/setup.py @@ -101,7 +101,8 @@ class Helper(object): self.is_finished = True self.current_operation = None - def install(self, package_names, skip_recommends=False): + def install(self, package_names, skip_recommends=False, + force_configuration=None): """Install a set of packages marking progress.""" if self.allow_install is False: # Raise error if packages are not already installed. @@ -120,7 +121,7 @@ class Helper(object): 'step': 'install', 'transaction': transaction, } - transaction.install(skip_recommends) + transaction.install(skip_recommends, force_configuration) def call(self, step, method, *args, **kwargs): """Call an arbitrary method during setup and note down its stage."""