#!/usr/bin/python3 # # This file is part of Plinth. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # """ Wrapper to handle package installation with apt-get. """ import argparse from importlib import import_module import os import subprocess import sys from plinth import cfg def parse_arguments(): """Return parsed command line arguments as dictionary.""" parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') subparsers.add_parser('update', help='update the package lists') subparser = subparsers.add_parser('install', help='install packages') subparser.add_argument( 'module', help='name of module for which package is being installed') subparser.add_argument( 'packages', nargs='+', help='list of packages to install') return parser.parse_args() def _run_apt_command(arguments): """Run apt-get with provided arguments.""" # Ask apt-get to output its progress to file descriptor 3. command = ['apt-get', '--assume-yes', '--quiet=2', '--option', 'APT::Status-Fd=3'] + arguments # Duplicate stdout to file descriptor 3 for this process. os.dup2(1, 3) # Pass on file descriptor 3 instead of closing it. Close stdout # so that regular output is ignored. env = os.environ.copy() env['DEBIAN_FRONTEND'] = 'noninteractive' process = subprocess.run( command, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, close_fds=False, env=env) sys.exit(process.returncode) def subcommand_update(arguments): """Update apt package lists.""" _run_apt_command(['update']) def subcommand_install(arguments): """Install packages using apt-get.""" try: _assert_managed_packages(arguments.module, arguments.packages) except Exception as exception: print('Access check failed:', exception, file=sys.stderr) sys.exit(99) _run_apt_command(['install'] + arguments.packages) def _assert_managed_packages(module, packages): """Check that list of packages are in fact managed by module.""" cfg.read() module_file = os.path.join(cfg.config_dir, 'modules-enabled', module) with open(module_file, 'r') as file_handle: module_path = file_handle.read().strip() module = import_module(module_path) for package in packages: assert package in module.managed_packages def main(): """Parse arguments and perform all duties.""" arguments = parse_arguments() subcommand = arguments.subcommand.replace('-', '_') subcommand_method = globals()['subcommand_' + subcommand] subcommand_method(arguments) if __name__ == '__main__': main()