# vim:set fileencoding=utf-8 et ts=4 sts=4 sw=4: # # apt-listchanges - Show changelog entries between the installed versions # of a set of packages and the versions contained in # corresponding .deb files # # Copyright (C) 2000-2006 Matt Zimmerman # Copyright (C) 2006 Pierre Habouzit # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. # import configparser import getopt import sys, os import ALCLog from ALChacks import _ class ALCConfig: def __init__(self): ### Command line only options self.apt_mode = False # "--apt" option self.dump_seen = False self.profile = None ### Options that can be set in the config file self.frontend = 'pager' self.email_address = None self.email_format = 'text' self.verbose = False self.show_all = False self.confirm = False self.headers = False self.debug = False self.save_seen = None self.which = 'both' self.since = None self.latest = None self.reverse = False self.no_network = False self.select_frontend = False self.ignore_apt_assume = False self.ignore_debian_frontend = False self.titled = True self.log = '/var/log/apt/listchanges.log' self.filter = None ### Internal options for managing the config file options # - options that can be also used for command line parameters # (after replacing '_' with '-', and adding trailing '=' if needed) self._bool_opts = [ 'confirm', 'debug', 'show_all', 'headers', 'verbose', 'reverse', 'dump_seen', 'select_frontend', 'no_network', 'ignore_apt_assume', 'ignore_debian_frontend', 'titled', ] self._value_opts = [ 'frontend', 'email_address', 'email_format', 'latest', 'log', 'filter', 'save_seen', 'since', 'which', ] # - options that can be given only in the config file self._cfgfile_only_opts = [ 'browser', 'pager', 'xterm', ] ### Other options self.quiet = 0 self.frontend_from_env = False self._allowed_email_formats = ('text', 'html') self._allowed_which = ('both', 'news', 'changelogs') def read(self, file): self.parser = configparser.ConfigParser() self.parser.read(file) def expose(self): if self.parser.has_section(self.profile): for option in self.parser.options(self.profile): value = None if self.parser.has_option(self.profile, option): if option in self._bool_opts: value = self.parser.getboolean(self.profile, option) elif option in self._value_opts or option in self._cfgfile_only_opts: value = self.parser.get(self.profile, option) else: ALCLog.warning(_("Unknown configuration file option: %s") % option) continue setattr(self, option, value) def get(self, option, defvalue=None): return getattr(self, option, defvalue) def usage(self, exitcode): if exitcode == 0: fh = sys.stdout else: fh = sys.stderr fh.write(_("Usage: apt-listchanges [options] {--apt | filename.deb ...}\n")) sys.exit(exitcode) def _check_allowed(self, arg, opt, allowed): if arg in allowed: return arg ALCLog.error((_('Unknown argument %(arg)s for option %(opt)s. Allowed are: %(allowed)s.') % {'arg': arg, 'opt': opt, 'allowed': ', '.join(allowed)})) sys.exit(1) def _check_debs(self, debs): if self.apt_mode or self.dump_seen: return if not debs: self.usage(1) for deb in debs: ext = os.path.splitext(deb)[1] if ext != ".deb": ALCLog.error(_("%(deb)s does not have '.deb' extension") % {'deb': deb}) sys.exit(1) if not os.path.isfile(deb): ALCLog.error(_('%(deb)s does not exist or is not a file') % {'deb': deb}) sys.exit(1) if not os.access(deb, os.R_OK): ALCLog.error(_('%(deb)s is not readable') % {'deb' : deb}) sys.exit(1) def getopt(self, argv): try: (optlist, args) = getopt.getopt(argv[1:], 'vf:s:cah', [ # command line only "apt", "profile=", "help", # deprecated options for backward compatibility "all", "save_seen=" ] # boolean options + [ x.replace('_', '-') for x in self._bool_opts ] # with value options + [ x.replace('_', '-')+'=' for x in self._value_opts ] ) except getopt.GetoptError as err: ALCLog.error(str(err)) sys.exit(1) # Determine mode and profile before processing other options for opt, arg in optlist: if opt == '--profile': self.profile = arg elif opt == '--apt': self.apt_mode = True # Provide a default profile if none has been specified if self.profile is None: if self.apt_mode: self.profile = 'apt' else: self.profile = 'cmdline' # Expose defaults from config file self.expose() # Environment variables override config file if 'APT_LISTCHANGES_FRONTEND' in os.environ: self.frontend = os.getenv('APT_LISTCHANGES_FRONTEND') self.frontend_from_env = True # Prefer APT_LISTCHANGES_FRONTEND over DEBIAN_FRONTEND self.ignore_debian_frontend = True (since, latest, show_all) = (None, None, False) # Command-line options override environment and config file for opt, arg in optlist: if opt == '--help': self.usage(0) elif opt in ('-v', '--verbose'): self.verbose = True elif opt in ('-f', '--frontend'): self.frontend = arg elif opt == '--email-address': self.email_address = arg elif opt == '--email-format': self.email_format = self._check_allowed(arg, opt, self._allowed_email_formats) elif opt in ('-c', '--confirm'): self.confirm = True elif opt in ('--since'): since = arg elif opt in ('--latest'): latest = arg elif opt in ('-a', '--show-all', '--all'): show_all = True elif opt in ('-h', '--headers'): self.headers = True elif opt in ('--save-seen', '--save_seen'): self.save_seen = arg elif opt == '--dump-seen': self.dump_seen = True elif opt == '--which': self.which = self._check_allowed(arg, opt, self._allowed_which) elif opt == '--debug': self.debug = True elif opt == '--reverse': self.reverse = True elif opt in ('-n', '--no-network'): self.no_network = True elif opt == '--select-frontend': self.select_frontend = True elif opt == '--ignore-apt-assume': self.ignore_apt_assume = True elif opt == '--ignore-debian-frontend': self.ignore_debian_frontend = True elif opt == '--titled': self.titled = True elif opt == '--untitled': self.titled = False elif opt in ('--log'): self.log = arg elif opt in ('--filter'): self.filter = arg if self.email_address == 'none': self.email_address = None if self.save_seen == 'none': self.save_seen = None if ((self.since is not None and self.show_all) or (since is not None and show_all)): ALCLog.error(_('--since= and --show-all are mutually exclusive')) sys.exit(1) elif since is not None or show_all: self.since = since self.show_all = show_all if self.since is not None: if len(args) != 1: ALCLog.error(_('--since= expects a path to exactly one .deb archive')) sys.exit(1) self.save_seen = None if ((self.latest is not None and self.show_all) or (latest is not None and show_all)): ALCLog.error(_('--latest= and --show-all are mutually exclusive')) sys.exit(1) elif latest is not None or show_all: self.latest = latest self.show_all = show_all if (self.apt_mode and not self.ignore_debian_frontend and os.getenv('DEBIAN_FRONTEND', '') == 'noninteractive'): # Force non-interactive usage self.quiet = 1 self.confirm = False self._check_debs(args) return args __all__ = [ 'ALCConfig' ]