def _parse_commands(self): """Read :attr:`self.cmds` and parse them out to make sure that the requested base command and argument makes any sense at all. This function will also set :attr:`self.base.basecmd` and :attr:`self.extcmds`. """ self.logger.debug('dnf version: %s', dnf.const.VERSION) self.logger.log(dnf.logging.SUBDEBUG, 'Command: %s', self.cmdstring) self.logger.log(dnf.logging.SUBDEBUG, 'Installroot: %s', self.base.conf.installroot) if len(self.base.conf.commands) == 0 and len(self.base.cmds) < 1: self.base.cmds = self.base.conf.commands else: self.base.conf.commands = self.base.cmds if len(self.base.cmds) < 1: self.logger.critical(_('You need to give some command')) self.print_usage() raise CliError basecmd = self.base.cmds[0] # our base command command_cls = self.cli_commands.get(basecmd) if command_cls is None: self.logger.critical(_('No such command: %s. Please use %s --help'), basecmd, sys.argv[0]) raise CliError self.command = command_cls(self) (base, ext) = self.command.canonical(self.base.cmds) self.base.basecmd, self.base.extcmds = (base, ext) self.logger.log(dnf.logging.SUBDEBUG, 'Base command: %s', base) self.logger.log(dnf.logging.SUBDEBUG, 'Extra commands: %s', ext)
def _config(self, args=None): def print_or_set(key, val, conf): if val: setattr(conf, key, val) else: try: print('{}: {}'.format(key, getattr(conf, str(key)))) except: logger.warning(_('Unsupported key value.')) if not args or len(args) > 2: logger.warning(_('Missing config or key value.')) key = args[0] val = args[1] if len(args) == 2 else None period = key.find('.') if period != -1: repo_name = key[:period] key = key[period+1:] repos = self.base.repos.get_matching(repo_name) for repo in repos: print_or_set(key, val, repo) if not repos: logger.warning(_('Could not find repository: %s'), repo_name) else: print_or_set(key, val, self.base.conf)
def __init__(self, no_match_group_specs=(), error_group_specs=(), no_match_pkg_specs=(), error_pkg_specs=(), module_depsolv_errors=()): """Initialize the marking error instance.""" msg = _("Problems in request:") if (no_match_pkg_specs): msg += "\n" + _("missing packages: ") + ", ".join(no_match_pkg_specs) if (error_pkg_specs): msg += "\n" + _("broken packages: ") + ", ".join(error_pkg_specs) if (no_match_group_specs): msg += "\n" + _("missing groups or modules: ") + ", ".join(no_match_group_specs) if (error_group_specs): msg += "\n" + _("broken groups or modules: ") + ", ".join(error_group_specs) if (module_depsolv_errors): msg_mod = dnf.util._format_resolve_problems(module_depsolv_errors[0]) if module_depsolv_errors[1] == \ libdnf.module.ModulePackageContainer.ModuleErrorType_ERROR_IN_DEFAULTS: msg += "\n" + "\n".join([P_('Modular dependency problem with Defaults:', 'Modular dependency problems with Defaults:', len(module_depsolv_errors)), msg_mod]) else: msg += "\n" + "\n".join([P_('Modular dependency problem:', 'Modular dependency problems:', len(module_depsolv_errors)), msg_mod]) super(MarkingErrors, self).__init__(msg) self.no_match_group_specs = no_match_group_specs self.error_group_specs = error_group_specs self.no_match_pkg_specs = no_match_pkg_specs self.error_pkg_specs = error_pkg_specs self.module_depsolv_errors = module_depsolv_errors
def run(self, extcmds): pkg_specs, filenames = self.parse_extcmds(extcmds) # Reinstall files. local_pkgs = map(self.base.add_remote_rpm, filenames) results = map(self.base.package_install, local_pkgs) done = functools.reduce(operator.or_, results, False) # Reinstall packages. for pkg_spec in pkg_specs: try: self.base.reinstall(pkg_spec) except dnf.exceptions.PackagesNotInstalledError: logger.info(_('No match for argument: %s'), pkg_spec) except dnf.exceptions.PackagesNotAvailableError as err: for pkg in err.packages: xmsg = '' yumdb_info = self.base.yumdb.get_package(pkg) if 'from_repo' in yumdb_info: xmsg = _(' (from %s)') % yumdb_info.from_repo msg = _('Installed package %s%s%s%s not available.') logger.info(msg, self.base.output.term.MODE['bold'], pkg, self.base.output.term.MODE['normal'], xmsg) except dnf.exceptions.MarkingError: assert False, 'Only the above marking errors are expected.' else: done = True if not done: raise dnf.exceptions.Error(_('Nothing to do.'))
def cli_run(cli, base): # Try to open the current directory to see if we have # read and execute access. If not, chdir to / try: f = open(".") except IOError as e: if e.errno == errno.EACCES: logger.critical(_('No read/execute access in current directory, moving to /')) os.chdir("/") else: f.close() try: cli.run() except dnf.exceptions.LockError: raise except (IOError, OSError) as e: return ex_IOError(e) if cli.demands.resolving: try: ret = resolving(cli, base) except dnf.exceptions.DepsolveError as e: ex_Error(e) if not cli.demands.allow_erasing: logger.info(_("(try to add '%s' to command line to" " replace conflicting packages)"), "--allowerasing") raise if ret: return ret cli.command.run_transaction() return cli.demands.success_exit_status
def history_undo_transaction(self, extcmd): """Undo given transaction.""" old = self.history_get_transaction((extcmd,)) if old is None: return 1, ['Failed history undo'] tm = time.ctime(old.beg_timestamp) print("Undoing transaction %u, from %s" % (old.tid, tm)) self.output.historyInfoCmdPkgsAltered(old) # :todo history = dnf.history.open_history(self.history) # :todo hibeg = self.output.term.MODE['bold'] hiend = self.output.term.MODE['normal'] try: self.history_undo_operations(history.transaction_nevra_ops(old.tid)) except dnf.exceptions.PackagesNotInstalledError as err: logger.info(_('No package %s%s%s installed.'), hibeg, ucd(err.pkg_spec), hiend) return 1, ['An operation cannot be undone'] except dnf.exceptions.PackagesNotAvailableError as err: logger.info(_('No package %s%s%s available.'), hibeg, ucd(err.pkg_spec), hiend) return 1, ['An operation cannot be undone'] except dnf.exceptions.MarkingError: assert False else: return 2, ["Undoing transaction %u" % (old.tid,)]
def run(self): # Reinstall files. done = False for pkg in self.base.add_remote_rpms(self.opts.filenames, strict=False): try: self.base.package_reinstall(pkg) except dnf.exceptions.MarkingError as e: logger.info(e) else: done = True # Reinstall packages. for pkg_spec in self.opts.pkg_specs + ['@' + x for x in self.opts.grp_specs]: try: self.base.reinstall(pkg_spec) except dnf.exceptions.PackagesNotInstalledError: logger.info(_('No match for argument: %s'), pkg_spec) except dnf.exceptions.PackagesNotAvailableError as err: for pkg in err.packages: xmsg = '' yumdb_info = self.base._yumdb.get_package(pkg) if 'from_repo' in yumdb_info: xmsg = _(' (from %s)') % yumdb_info.from_repo msg = _('Installed package %s%s%s%s not available.') logger.info(msg, self.base.output.term.MODE['bold'], pkg, self.base.output.term.MODE['normal'], xmsg) except dnf.exceptions.MarkingError: assert False, 'Only the above marking errors are expected.' else: done = True if not done: raise dnf.exceptions.Error(_('Nothing to do.'))
def errorSummary(self, errstring): """Parse the error string for 'interesting' errors which can be grouped, such as disk space issues. :param errstring: the error string :return: a string containing a summary of the errors """ summary = '' # do disk space report first p = re.compile('needs (\d+)MB on the (\S+) filesystem') disk = {} for m in p.finditer(errstring): if m.group(2) not in disk: disk[m.group(2)] = int(m.group(1)) if disk[m.group(2)] < int(m.group(1)): disk[m.group(2)] = int(m.group(1)) if disk: summary += _('Disk Requirements:\n') for k in disk: summary += P_(' At least %dMB more space needed on the %s filesystem.\n', ' At least %dMB more space needed on the %s filesystem.\n', disk[k]) % (disk[k], k) # TODO: simplify the dependency errors? # Fixup the summary summary = _('Error Summary\n-------------\n') + summary return summary
def _history_get_transactions(self, extcmds): if not extcmds: logger.critical(_('No transaction ID given')) return None tids = [] last = None for extcmd in extcmds: try: id_or_offset = self.transaction_id_or_offset(extcmd) except ValueError: logger.critical(_('Bad transaction ID given')) return None if id_or_offset < 0: if last is None: cto = False last = self.history.last(complete_transactions_only=cto) if last is None: logger.critical(_('Bad transaction ID given')) return None tids.append(str(last.tid + id_or_offset + 1)) else: tids.append(str(id_or_offset)) old = self.history.old(tids) if not old: logger.critical(_('Not found given transaction ID')) return None return old
def _parse_commands(self): """Check that the requested CLI command exists.""" if len(self.base.cmds) < 1: logger.critical(_('You need to give some command')) self.print_usage() raise CliError basecmd = self.base.cmds[0] # our base command command_cls = self.cli_commands.get(basecmd) if command_cls is None: logger.critical(_('No such command: %s. Please use %s --help'), basecmd, sys.argv[0]) if self.base.conf.plugins: logger.info(_("It could be a DNF plugin command, " "try: \"dnf install 'dnf-command(%s)'\""), basecmd) else: logger.info(_("It could be a DNF plugin command, " "but loading of plugins is currently disabled.")) raise CliError self.command = command_cls(self) (base, ext) = self.command.canonical(self.base.cmds) self.base.basecmd, self.base.extcmds = (base, ext) logger.log(dnf.logging.DDEBUG, 'Base command: %s', base) logger.log(dnf.logging.DDEBUG, 'Extra commands: %s', ext)
def run(self): if any([self.opts.grp_specs, self.opts.pkg_specs, self.opts.filenames]): self.opts.pkg_specs += self.opts.filenames done = False # Remove groups. if self.opts.grp_specs and self.forms: for grp_spec in self.opts.grp_specs: msg = _('Not a valid form: %s') logger.warning(msg, self.base.output.term.bold(grp_spec)) elif self.opts.grp_specs: self.base.read_comps(arch_filter=True) if self.base.env_group_remove(self.opts.grp_specs): done = True for pkg_spec in self.opts.pkg_specs: try: self.base.remove(pkg_spec, forms=self.forms) except dnf.exceptions.MarkingError: logger.info(_('No match for argument: %s'), pkg_spec) else: done = True if not done: raise dnf.exceptions.Error(_('No packages marked for removal.')) else: base = self.base pkgs = base.sack.query()._unneeded(base.sack, base._yumdb, debug_solver=base.conf.debug_solver) for pkg in pkgs: base.package_remove(pkg)
def run_on_repo(self, reponame, cli_args): """Execute the command with respect to given arguments *cli_args*.""" self.check(cli_args) pkg_specs = self.parse_arguments(cli_args) done = False if not pkg_specs: # Remove all packages. try: self.base.remove("*", reponame) except dnf.exceptions.MarkingError: msg = _("No package installed from the repository.") logger.info(msg) else: done = True else: # Remove packages. for pkg_spec in pkg_specs: try: self.base.remove(pkg_spec, reponame) except dnf.exceptions.MarkingError: logger.info(_("No match for argument: %s"), pkg_spec) else: done = True if not done: raise dnf.exceptions.Error(_("No packages marked for removal."))
def _process_demands(self): demands = self.demands repos = self.base.repos if not demands.cacheonly: if demands.freshest_metadata: for repo in repos.iter_enabled(): repo.md_expire_cache() elif not demands.fresh_metadata: for repo in repos.values(): repo.md_lazy = True if demands.sack_activation: lar = self.demands.available_repos self.base.fill_sack(load_system_repo='auto', load_available_repos=lar) if lar: repos = list(self.base.repos.iter_enabled()) if repos: mts = max(repo.metadata.timestamp for repo in repos) # do not bother users with fractions of seconds age = int(min(repo.metadata.age for repo in repos)) for repo in repos: logger.debug(_("%s: using metadata from %s."), repo.id, time.ctime(repo.metadata.md_timestamp)) if age != 0: logger.info(_("Last metadata expiration check: " "%s ago on %s."), datetime.timedelta(seconds=age), time.ctime(mts)) self.base.plugins.run_sack()
def run_on_repo(self, reponame, cli_args): """Execute the command with respect to given arguments *cli_args*.""" self.check(cli_args) pkg_specs = self.parse_arguments(cli_args) done = False if not pkg_specs: # Sync all packages. try: self._replace("*", reponame) except dnf.exceptions.PackagesNotInstalledError: msg = _("No package installed from the repository.") logger.info(msg) else: done = True else: # Reinstall packages. for pkg_spec in pkg_specs: try: self._replace(pkg_spec, reponame) except dnf.exceptions.PackagesNotInstalledError: msg = _("No match for argument: %s") logger.info(msg, pkg_spec) else: done = True if not done: raise dnf.exceptions.Error(_("Nothing to do."))
def run_on_repo(self, reponame, cli_args): """Execute the command with respect to given arguments *cli_args*.""" self.check(cli_args) pkg_specs = self.parse_arguments(cli_args) done = False if not pkg_specs: # Reinstall all packages. try: self.base.reinstall("*", old_reponame=reponame, new_reponame_neq=reponame, remove_na=True) except dnf.exceptions.PackagesNotInstalledError: msg = _("No package installed from the repository.") logger.info(msg) except dnf.exceptions.MarkingError: assert False, "Only the above marking error is expected." else: done = True else: # Reinstall packages. for pkg_spec in pkg_specs: try: self.base.reinstall(pkg_spec, old_reponame=reponame, new_reponame_neq=reponame, remove_na=True) except dnf.exceptions.PackagesNotInstalledError: msg = _("No match for argument: %s") logger.info(msg, pkg_spec) except dnf.exceptions.MarkingError: assert False, "Only the above marking error is expected." else: done = True if not done: raise dnf.exceptions.Error(_("Nothing to do."))
def run_on_repo(self, reponame, cli_args): """Execute the command with respect to given arguments *cli_args*.""" self.check(cli_args) pkg_specs = self.parse_arguments(cli_args) done = False if not pkg_specs: # Install all packages. try: self.base.install("*", reponame) except dnf.exceptions.MarkingError: logger.info(_("No package available.")) else: done = True else: # Install packages. for pkg_spec in pkg_specs: try: self.base.install(pkg_spec, reponame) except dnf.exceptions.MarkingError: msg = _("No package %s%s%s available.") logger.info(msg, self.output.term.MODE["bold"], pkg_spec, self.output.term.MODE["normal"]) else: done = True if not done: raise dnf.exceptions.Error(_("Nothing to do."))
def checkGPGKey(base, cli): """Verify that there are gpg keys for the enabled repositories in the rpm database. :param base: a :class:`dnf.Base` object. :raises: :class:`cli.CliError` """ if cli.nogpgcheck: return if not base.gpgKeyCheck(): for repo in base.repos.iter_enabled(): if (repo.gpgcheck or repo.repo_gpgcheck) and not repo.gpgkey: msg = _( """ You have enabled checking of packages via GPG keys. This is a good thing. However, you do not have any GPG public keys installed. You need to download the keys for packages you wish to install and install them. You can do that by running the command: rpm --import public.gpg.key Alternatively you can specify the url to the key you would like to use for a repository in the 'gpgkey' option in a repository section and DNF will install it for you. For more information contact your distribution or package provider. """ ) logger.critical(msg) logger.critical(_("Problem repository: %s"), repo) raise dnf.cli.CliError
def _makeOutput(command): canonical_name = command.aliases[0] usage = command.usage summary = command.summary # XXX need detailed help here, too help_output = "" if usage is not None: help_output += "%s %s" % (canonical_name, usage) if summary is not None: help_output += "\n\n%s" % summary if usage is None and summary is None: help_output = _("No help available for %s") % canonical_name command_names = command.aliases if len(command_names) > 1: if len(command_names) > 2: help_output += _("\n\naliases: ") else: help_output += _("\n\nalias: ") help_output += ", ".join(command.aliases[1:]) return help_output
def _hcmd_redo(self, extcmds): try: extcmd, = extcmds except ValueError: if not extcmds: logger.critical(_("No transaction ID given")) elif len(extcmds) > 1: logger.critical(_("Found more than one transaction ID!")) return 1, ["Failed history redo"] old = self.base.history_get_transaction((extcmd,)) if old is None: return 1, ["Failed history redo"] tm = time.ctime(old.beg_timestamp) print("Repeating transaction %u, from %s" % (old.tid, tm)) self.output.historyInfoCmdPkgsAltered(old) converter = dnf.history.TransactionConverter(self.base.sack) history = dnf.history.open_history(self.base.history) operations = history.transaction_nevra_ops(old.tid) hibeg = self.output.term.MODE["bold"] hiend = self.output.term.MODE["normal"] try: self.base.transaction = converter.convert(operations, "history") except dnf.exceptions.PackagesNotInstalledError as err: logger.info(_("No package %s%s%s installed."), hibeg, ucd(err.pkg_spec), hiend) return 1, ["An operation cannot be redone"] except dnf.exceptions.PackagesNotAvailableError as err: logger.info(_("No package %s%s%s available."), hibeg, ucd(err.pkg_spec), hiend) return 1, ["An operation cannot be redone"] else: return 2, ["Repeating transaction %u" % (old.tid,)]
def print_versions(pkgs, base, output): def sm_ui_time(x): return time.strftime("%Y-%m-%d %H:%M", time.gmtime(x)) def sm_ui_date(x): # For changelogs, there is no time return time.strftime("%Y-%m-%d", time.gmtime(x)) rpmdb_sack = dnf.sack.rpmdb_sack(base) done = False for pkg in rpmdb_sack.query().installed().filter(name=pkgs): if done: print("") done = True if pkg.epoch == '0': ver = '%s-%s.%s' % (pkg.version, pkg.release, pkg.arch) else: ver = '%s:%s-%s.%s' % (pkg.epoch, pkg.version, pkg.release, pkg.arch) name = "%s%s%s" % (output.term.MODE['bold'], pkg.name, output.term.MODE['normal']) print(_(" Installed: %s-%s at %s") % (name, ver, sm_ui_time(pkg.installtime))) print( _(" Built : %s at %s") % (pkg.packager if pkg.packager else "", sm_ui_time(pkg.buildtime)))
def _try_revive_by_metalink(self): """Use metalink to check whether our metadata are still current.""" repomd_fn = self.metadata._repo_dct['repomd'] with dnf.util.tmpdir() as tmpdir, open(repomd_fn) as repomd: handle = self._handle_new_remote(tmpdir) handle.fetchmirrors = True handle._perform() if handle.metalink is None: logger.debug(_("reviving: repo '%s' skipped, no metalink."), self.id) return False hashes = handle.metalink['hashes'] hashes = [hsh_val for hsh_val in hashes if hsh_val[0] in _RECOGNIZED_CHKSUMS] if len(hashes) < 1: logger.debug(_("reviving: repo '%s' skipped, no usable hash."), self.id) return False algos = list(map(operator.itemgetter(0), hashes)) chksums = dnf.yum.misc.Checksums(algos, ignore_missing=True, ignore_none=True) chksums.read(repomd, -1) digests = chksums.hexdigests() for (algo, digest) in hashes: if digests[algo] != digest: logger.debug(_("reviving: failed for '%s', mismatched %s sum."), self.id, algo) return False logger.debug(_("reviving: '%s' can be revived - metalink checksums match."), self.id) return True
def _parse(self, s): if len(s) < 1: raise ValueError(_("no value specified")) if s == "-1" or s == "never": # Special cache timeout, meaning never return -1 if s[-1].isalpha(): n = s[:-1] unit = s[-1].lower() mult = self.MULTS.get(unit, None) if not mult: raise ValueError(_("unknown unit '%s'") % unit) else: n = s mult = 1 try: n = float(n) except (ValueError, TypeError): raise ValueError(_("invalid value '%s'") % s) if n < 0: raise ValueError(_("seconds value '%s' must not be negative") % s) return int(n * mult)
def resolving(cli, base): """Perform the depsolve, download and RPM transaction stage.""" if base.transaction is None: base.resolve(cli.demands.allow_erasing) logger.info(_('Dependencies resolved.')) # Run the transaction displays = [] if cli.demands.transaction_display is not None: displays.append(cli.demands.transaction_display) try: base.do_transaction(display=displays) except dnf.cli.CliError as exc: logger.error(ucd(exc)) return 1 except dnf.exceptions.TransactionCheckError as err: for msg in cli.command.get_error_output(err): logger.critical(msg) return 1 except IOError as e: return ex_IOError(e) else: logger.info(_('Complete!')) return 0
def _mark_install(self, patterns): prst = self.base._group_persistor q = CompsQuery(self.base.comps, prst, CompsQuery.GROUPS | CompsQuery.ENVIRONMENTS, CompsQuery.AVAILABLE | CompsQuery.INSTALLED) solver = self.base._build_comps_solver() res = q.get(*patterns) types = dnf.comps.DEFAULT | dnf.comps.MANDATORY | dnf.comps.OPTIONAL for env_id in res.environments: if not dnf.comps.install_or_skip(solver._environment_install, env_id, types): res.environments.remove(env_id) for group_id in res.groups: if not dnf.comps.install_or_skip(solver._group_install, group_id, types): res.groups.remove(group_id) if res.environments: logger.info(_('Environments marked installed: %s'), ','.join([prst.environment(g).ui_name for g in res.environments])) if res.groups: logger.info(_('Groups marked installed: %s'), ','.join([prst.group(g).ui_name for g in res.groups])) prst.commit()
def run(self): strict = self.base.conf.strict # Install files. err_pkgs = [] for pkg in self.base.add_remote_rpms(self.opts.filenames, strict=strict): try: self.base.package_install(pkg, strict=strict) except dnf.exceptions.MarkingError: msg = _("No match for argument: %s") logger.info(msg, self.base.output.term.bold(pkg.location)) err_pkgs.append(pkg) # Install groups. if self.opts.grp_specs: self.base.read_comps() try: self.base.env_group_install(self.opts.grp_specs, dnf.const.GROUP_PACKAGE_TYPES, strict=strict) except dnf.exceptions.Error: if self.base.conf.strict: raise # Install packages. errs = [] for pkg_spec in self.opts.pkg_specs: try: self.base.install(pkg_spec, strict=strict) except dnf.exceptions.MarkingError: msg = _("No package %s available.") logger.info(msg, self.base.output.term.bold(pkg_spec)) errs.append(pkg_spec) if (len(errs) != 0 or len(err_pkgs) != 0) and self.base.conf.strict: raise dnf.exceptions.PackagesNotAvailableError( _("Unable to find a match"), pkg_spec=" ".join(errs), packages=err_pkgs )
def run(self, reponame, cli_args): """Execute the command with respect to given arguments *cli_args*.""" super(RepoPkgsCommand.UpgradeSubCommand, self).run(cli_args) self.check(cli_args) pkg_specs = self.parse_arguments(cli_args) done = False if not pkg_specs: # Update all packages. self.base.upgrade_all(reponame) done = True else: # Update packages. for pkg_spec in pkg_specs: try: self.base.upgrade(pkg_spec, reponame) except dnf.exceptions.MarkingError: logger.info(_('No match for argument: %s'), pkg_spec) else: done = True if not done: raise dnf.exceptions.Error(_('No packages marked for upgrade.'))
def downgradePkgs(self, specs=[], file_pkgs=[], strict=False): """Attempt to take the user specified list of packages or wildcards and downgrade them. If a complete version number is specified, attempt to downgrade them to the specified version :param specs: a list of names or wildcards specifying packages to downgrade :param file_pkgs: a list of pkg objects from local files """ oldcount = self._goal.req_length() for pkg in file_pkgs: try: self.package_downgrade(pkg, strict=strict) continue # it was something on disk and it ended in rpm # no matter what we don't go looking at repos except dnf.exceptions.MarkingError as e: logger.info(_('No match for argument: %s'), self.output.term.bold(pkg.location)) # it was something on disk and it ended in rpm # no matter what we don't go looking at repos for arg in specs: try: self.downgrade_to(arg, strict=strict) except dnf.exceptions.PackageNotFoundError as err: msg = _('No package %s available.') logger.info(msg, self.output.term.bold(arg)) except dnf.exceptions.PackagesNotInstalledError as err: logger.info(_('Packages for argument %s available, but not installed.'), self.output.term.bold(err.pkg_spec)) except dnf.exceptions.MarkingError: assert False cnt = self._goal.req_length() - oldcount if cnt <= 0: raise dnf.exceptions.Error(_('Nothing to do.'))
def show_lock_owner(pid, logger): """Output information about another process that is holding the yum lock. :param pid: the process id number of the process holding the yum lock :param logger: the logger to output the information to :return: a dictionary containing information about the process. This is the same as the dictionary returned by :func:`get_process_info`. """ ps = get_process_info(pid) if not ps: return None # This yumBackend isn't very friendly, so... msg = _(' The application with PID %d is: %s') if ps['name'] == 'yumBackend.py': nmsg = msg % (pid, 'PackageKit') else: nmsg = msg % (pid, ps['name']) logger.critical("%s", nmsg) logger.critical(_(" Memory : %5s RSS (%5sB VSZ)") % (format_number(int(ps['vmrss']) * 1024), format_number(int(ps['vmsize']) * 1024))) ago = seconds_to_ui_time(int(time.time()) - ps['start_time']) logger.critical(_(" Started: %s - %s ago") % (time.ctime(ps['start_time']), ago)) logger.critical(_(" State : %s") % ps['state']) return ps
def run(self, reponame, cli_args): """Execute the command with respect to given arguments *cli_args*.""" super(RepoPkgsCommand.InstallSubCommand, self).run(cli_args) self.check(cli_args) pkg_specs = self.parse_arguments(cli_args) done = False if not pkg_specs: # Install all packages. try: self.base.install('*', reponame) except dnf.exceptions.MarkingError: logger.info(_('No package available.')) else: done = True else: # Install packages. for pkg_spec in pkg_specs: try: self.base.install(pkg_spec, reponame) except dnf.exceptions.MarkingError: msg = _('No package %s%s%s available.') logger.info( msg, self.output.term.MODE['bold'], pkg_spec, self.output.term.MODE['normal']) else: done = True if not done: raise dnf.exceptions.Error(_('Nothing to do.'))
def _parse(self, s): """Parse a friendly bandwidth option to bytes. The input should be a string containing a (possibly floating point) number followed by an optional single character unit. Valid units are 'k', 'M', 'G'. Case is ignored. The convention that 1k = 1024 bytes is used. Valid inputs: 100, 123M, 45.6k, 12.4G, 100K, 786.3, 0. Invalid inputs: -10, -0.1, 45.6L, 123Mb. """ if len(s) < 1: raise ValueError(_("no value specified")) if s[-1].isalpha(): n = s[:-1] unit = s[-1].lower() mult = self.MULTS.get(unit, None) if not mult: raise ValueError(_("unknown unit '%s'") % unit) else: n = s mult = 1 try: n = float(n) except ValueError: raise ValueError(_("couldn't convert '%s' to number") % s) if n < 0: raise ValueError(_("bytes value '%s' must not be negative") % s) return int(n * mult)
class InstallCommand(commands.Command): """A class containing methods needed by the cli to execute the install command. """ nevra_forms = { 'install-n': hawkey.FORM_NAME, 'install-na': hawkey.FORM_NA, 'install-nevra': hawkey.FORM_NEVRA } alternatives_provide = 'alternative-for({})' aliases = ('install', 'localinstall') + tuple(nevra_forms.keys()) summary = _('install a package or packages on your system') @staticmethod def set_argparser(parser): parser.add_argument('package', nargs='+', metavar=_('PACKAGE'), action=OptionParser.ParseSpecGroupFileCallback, help=_('Package to install')) def configure(self): """Verify that conditions are met so that this command can run. That there are enabled repositories with gpg keys, and that this command is called with appropriate arguments. """ demands = self.cli.demands demands.sack_activation = True demands.available_repos = True demands.resolving = True demands.root_user = True commands._checkGPGKey(self.base, self.cli) if not self.opts.filenames: commands._checkEnabledRepo(self.base) def run(self): err_pkgs = [] errs = [] error_module_specs = [] nevra_forms = self._get_nevra_forms_from_command() self.cli._populate_update_security_filter(self.opts, self.base.sack.query()) if self.opts.command == ['localinstall'] and (self.opts.grp_specs or self.opts.pkg_specs): self._log_not_valid_rpm_file_paths(self.opts.grp_specs) if self.base.conf.strict: raise dnf.exceptions.Error(_('Nothing to do.')) skipped_grp_specs = [] if self.opts.grp_specs and self.opts.command != ['localinstall']: if dnf.base.WITH_MODULES: try: module_base = dnf.module.module_base.ModuleBase(self.base) module_base.install(self.opts.grp_specs, strict=self.base.conf.strict) except dnf.exceptions.MarkingErrors as e: if e.no_match_group_specs: for e_spec in e.no_match_group_specs: skipped_grp_specs.append(e_spec) if e.error_group_specs: for e_spec in e.error_group_specs: error_module_specs.append("@" + e_spec) module_debsolv_errors = e.module_debsolv_errors if module_debsolv_errors: logger.error( dnf.module.module_base. format_modular_solver_errors( module_debsolv_errors)) else: skipped_grp_specs = self.opts.grp_specs if self.opts.filenames and nevra_forms: self._inform_not_a_valid_combination(self.opts.filenames) if self.base.conf.strict: raise dnf.exceptions.Error(_('Nothing to do.')) else: err_pkgs = self._install_files() if skipped_grp_specs and nevra_forms: self._inform_not_a_valid_combination(skipped_grp_specs) if self.base.conf.strict: raise dnf.exceptions.Error(_('Nothing to do.')) elif skipped_grp_specs and self.opts.command != ['localinstall']: self._install_groups(skipped_grp_specs) if self.opts.command != ['localinstall']: errs = self._install_packages(nevra_forms) if (len(errs) != 0 or len(err_pkgs) != 0 or error_module_specs) and self.base.conf.strict: raise dnf.exceptions.PackagesNotAvailableError( _("Unable to find a match"), pkg_spec=' '.join(errs), packages=err_pkgs) def _get_nevra_forms_from_command(self): return [ self.nevra_forms[command] for command in self.opts.command if command in list(self.nevra_forms.keys()) ] def _log_not_valid_rpm_file_paths(self, grp_specs): group_names = map(lambda g: '@' + g, grp_specs) for pkg in chain(self.opts.pkg_specs, group_names): msg = _('Not a valid rpm file path: %s') logger.info(msg, self.base.output.term.bold(pkg)) def _inform_not_a_valid_combination(self, forms): for form in forms: msg = _('Not a valid form: %s') logger.warning(msg, self.base.output.term.bold(form)) def _install_files(self): err_pkgs = [] strict = self.base.conf.strict for pkg in self.base.add_remote_rpms( self.opts.filenames, strict=strict, progress=self.base.output.progress): try: self.base.package_install(pkg, strict=strict) except dnf.exceptions.MarkingError: msg = _('No match for argument: %s') logger.info(msg, self.base.output.term.bold(pkg.location)) err_pkgs.append(pkg) return err_pkgs def _install_groups(self, grp_specs): self.base.read_comps(arch_filter=True) try: self.base.env_group_install( grp_specs, tuple(self.base.conf.group_package_types), strict=self.base.conf.strict) except dnf.exceptions.Error: if self.base.conf.strict: raise def _report_alternatives(self, pkg_spec): query = self.base.sack.query().filterm( provides=self.alternatives_provide.format(pkg_spec)) if query: msg = _('There are following alternatives for "{0}": {1}') logger.info( msg.format(pkg_spec, ', '.join(sorted(set([alt.name for alt in query]))))) def _install_packages(self, nevra_forms): errs = [] strict = self.base.conf.strict for pkg_spec in self.opts.pkg_specs: try: self.base.install(pkg_spec, strict=strict, forms=nevra_forms) except dnf.exceptions.MarkingError: msg = _('No match for argument: %s') logger.info(msg, self.base.output.term.bold(pkg_spec)) self.base._report_icase_hint(pkg_spec) self._report_alternatives(pkg_spec) errs.append(pkg_spec) return errs
def set_argparser(parser): parser.add_argument('dependency', nargs='+', metavar=_('SOME_STRING'))
class InfoCommand(Command): """A class containing methods needed by the cli to execute the info command. """ aliases = ('info', ) summary = _('display details about a package or group of packages') DEFAULT_PKGNARROW = 'all' pkgnarrows = { 'available', 'installed', 'extras', 'updates', 'upgrades', 'autoremove', 'recent', 'obsoletes', DEFAULT_PKGNARROW } @classmethod def set_argparser(cls, parser): narrows = parser.add_mutually_exclusive_group() narrows.add_argument('--all', dest='_packages_action', action='store_const', const='all', default=None, help=_("show all packages (default)")) narrows.add_argument('--available', dest='_packages_action', action='store_const', const='available', help=_("show only available packages")) narrows.add_argument('--installed', dest='_packages_action', action='store_const', const='installed', help=_("show only installed packages")) narrows.add_argument('--extras', dest='_packages_action', action='store_const', const='extras', help=_("show only extras packages")) narrows.add_argument('--updates', dest='_packages_action', action='store_const', const='upgrades', help=_("show only upgrades packages")) narrows.add_argument('--upgrades', dest='_packages_action', action='store_const', const='upgrades', help=_("show only upgrades packages")) narrows.add_argument('--autoremove', dest='_packages_action', action='store_const', const='autoremove', help=_("show only autoremove packages")) narrows.add_argument('--recent', dest='_packages_action', action='store_const', const='recent', help=_("show only recently changed packages")) narrows.add_argument('--obsoletes', dest='_packages_action', action='store_const', const='obsoletes', help=_("show only obsoletes packages")) parser.add_argument('packages', nargs='*', metavar=_('PACKAGE'), choices=cls.pkgnarrows, default=cls.DEFAULT_PKGNARROW, action=OptionParser.PkgNarrowCallback) def configure(self): demands = self.cli.demands demands.available_repos = True demands.fresh_metadata = False demands.sack_activation = True if self.opts._packages_action: self.opts.packages_action = self.opts._packages_action if self.opts.packages_action == 'updates': self.opts.packages_action = 'upgrades' def run(self): return self.base.output_packages('info', self.opts.packages_action, self.opts.packages)
import argparse import dnf.cli import dnf.cli.demand import dnf.const import dnf.exceptions import dnf.i18n import dnf.pycomp import dnf.util import functools import logging import operator import os logger = logging.getLogger('dnf') _RPM_VERIFY = _("To diagnose the problem, try running: '%s'.") % \ 'rpm -Va --nofiles --nodigest' _RPM_REBUILDDB = _("You probably have corrupted RPMDB, running '%s'" " might fix the issue.") % 'rpm --rebuilddb' gpg_msg = \ _("""You have enabled checking of packages via GPG keys. This is a good thing. However, you do not have any GPG public keys installed. You need to download the keys for packages you wish to install and install them. You can do that by running the command: rpm --import public.gpg.key Alternatively you can specify the url to the key you would like to use for a repository in the 'gpgkey' option in a repository section and DNF will install it for you.
def run(self): strict = self.base.conf.strict forms = [self.nevra_forms[command] for command in self.opts.command if command in list(self.nevra_forms.keys())] self.cli._populate_update_security_filter(self.opts, self.base.sack.query()) # localinstall valid arguments check nonfilenames = self.opts.grp_specs or self.opts.pkg_specs if self.opts.command == ['localinstall'] and nonfilenames: group_names = map(lambda g: '@' + g, self.opts.grp_specs) for pkg in chain(self.opts.pkg_specs, group_names): msg = _('Not a valid rpm file path: %s') logger.info(msg, self.base.output.term.bold(pkg)) if strict: raise dnf.exceptions.Error(_('No packages marked for install.')) # Install files. err_pkgs = [] if self.opts.filenames and forms: for filename in self.opts.filenames: msg = _('Not a valid form: %s') logger.warning(msg, self.base.output.term.bold(filename)) if strict: raise dnf.exceptions.Error(_('No packages marked for install.')) else: for pkg in self.base.add_remote_rpms(self.opts.filenames, strict=strict): try: self.base.package_install(pkg, strict=strict) except dnf.exceptions.MarkingError: msg = _('No match for argument: %s') logger.info(msg, self.base.output.term.bold(pkg.location)) err_pkgs.append(pkg) # Install groups. if self.opts.grp_specs and forms: for grp_spec in self.opts.grp_specs: msg = _('Not a valid form: %s') logger.warning(msg, self.base.output.term.bold(grp_spec)) if strict: raise dnf.exceptions.Error(_('No packages marked for install.')) elif self.opts.grp_specs and self.opts.command != ['localinstall']: self.base.read_comps(arch_filter=True) try: self.base.env_group_install(self.opts.grp_specs, tuple(self.base.conf.group_package_types), strict=strict) except dnf.exceptions.Error: if self.base.conf.strict: raise # Install packages. errs = [] if self.opts.command != ['localinstall']: for pkg_spec in self.opts.pkg_specs: try: self.base.install(pkg_spec, strict=strict, forms=forms) except dnf.exceptions.MarkingError: msg = _('No match for argument: %s') logger.info(msg, self.base.output.term.bold(pkg_spec)) errs.append(pkg_spec) if (len(errs) != 0 or len(err_pkgs) != 0) and self.base.conf.strict: raise dnf.exceptions.PackagesNotAvailableError( _("Unable to find a match"), pkg_spec=' '.join(errs), packages=err_pkgs)
def set_argparser(parser): parser.add_argument('package', nargs='+', metavar=_('PACKAGE'), action=OptionParser.ParseSpecGroupFileCallback, help=_('Package to install'))
class InstallCommand(commands.Command): """A class containing methods needed by the cli to execute the install command. """ nevra_forms = {'install-n': hawkey.FORM_NAME, 'install-na': hawkey.FORM_NA, 'install-nevra': hawkey.FORM_NEVRA} aliases = ('install', 'localinstall') + tuple(nevra_forms.keys()) summary = _('install a package or packages on your system') @staticmethod def set_argparser(parser): parser.add_argument('package', nargs='+', metavar=_('PACKAGE'), action=OptionParser.ParseSpecGroupFileCallback, help=_('Package to install')) def configure(self): """Verify that conditions are met so that this command can run. That there are enabled repositories with gpg keys, and that this command is called with appropriate arguments. """ demands = self.cli.demands demands.sack_activation = True demands.available_repos = True demands.resolving = True demands.root_user = True commands._checkGPGKey(self.base, self.cli) if not self.opts.filenames: commands._checkEnabledRepo(self.base) def run(self): strict = self.base.conf.strict forms = [self.nevra_forms[command] for command in self.opts.command if command in list(self.nevra_forms.keys())] self.cli._populate_update_security_filter(self.opts, self.base.sack.query()) # localinstall valid arguments check nonfilenames = self.opts.grp_specs or self.opts.pkg_specs if self.opts.command == ['localinstall'] and nonfilenames: group_names = map(lambda g: '@' + g, self.opts.grp_specs) for pkg in chain(self.opts.pkg_specs, group_names): msg = _('Not a valid rpm file path: %s') logger.info(msg, self.base.output.term.bold(pkg)) if strict: raise dnf.exceptions.Error(_('No packages marked for install.')) # Install files. err_pkgs = [] if self.opts.filenames and forms: for filename in self.opts.filenames: msg = _('Not a valid form: %s') logger.warning(msg, self.base.output.term.bold(filename)) if strict: raise dnf.exceptions.Error(_('No packages marked for install.')) else: for pkg in self.base.add_remote_rpms(self.opts.filenames, strict=strict): try: self.base.package_install(pkg, strict=strict) except dnf.exceptions.MarkingError: msg = _('No match for argument: %s') logger.info(msg, self.base.output.term.bold(pkg.location)) err_pkgs.append(pkg) # Install groups. if self.opts.grp_specs and forms: for grp_spec in self.opts.grp_specs: msg = _('Not a valid form: %s') logger.warning(msg, self.base.output.term.bold(grp_spec)) if strict: raise dnf.exceptions.Error(_('No packages marked for install.')) elif self.opts.grp_specs and self.opts.command != ['localinstall']: self.base.read_comps(arch_filter=True) try: self.base.env_group_install(self.opts.grp_specs, tuple(self.base.conf.group_package_types), strict=strict) except dnf.exceptions.Error: if self.base.conf.strict: raise # Install packages. errs = [] if self.opts.command != ['localinstall']: for pkg_spec in self.opts.pkg_specs: try: self.base.install(pkg_spec, strict=strict, forms=forms) except dnf.exceptions.MarkingError: msg = _('No match for argument: %s') logger.info(msg, self.base.output.term.bold(pkg_spec)) errs.append(pkg_spec) if (len(errs) != 0 or len(err_pkgs) != 0) and self.base.conf.strict: raise dnf.exceptions.PackagesNotAvailableError( _("Unable to find a match"), pkg_spec=' '.join(errs), packages=err_pkgs)
def _log_not_valid_rpm_file_paths(self, grp_specs): group_names = map(lambda g: '@' + g, grp_specs) for pkg in chain(self.opts.pkg_specs, group_names): msg = _('Not a valid rpm file path: %s') logger.info(msg, self.base.output.term.bold(pkg))
def _get_key_for_package(self, po, askcb=None, fullaskcb=None): """Retrieve a key for a package. If needed, use the given callback to prompt whether the key should be imported. :param po: the package object to retrieve the key of :param askcb: Callback function to use to ask permission to import a key. The arguments *askck* should take are the package object, the userid of the key, and the keyid :param fullaskcb: Callback function to use to ask permission to import a key. This differs from *askcb* in that it gets passed a dictionary so that we can expand the values passed. :raises: :class:`dnf.exceptions.Error` if there are errors retrieving the keys """ repo = self.repos[po.repoid] keyurls = repo.gpgkey key_installed = False def _prov_key_data(msg): msg += _('Failing package is: %s') % (po) + '\n ' msg += _('GPG Keys are configured as: %s') % \ (', '.join(repo.gpgkey) + '\n') return '\n\n\n' + msg user_cb_fail = False for keyurl in keyurls: keys = dnf.crypto.retrieve(keyurl, repo) for info in keys: ts = self._rpmconn.readonly_ts # Check if key is already installed if misc.keyInstalled(ts, info.rpm_id, info.timestamp) >= 0: msg = _('GPG key at %s (0x%s) is already installed') logger.info(msg, keyurl, info.short_id) continue # Try installing/updating GPG key info.url = keyurl dnf.crypto.log_key_import(info) rc = False if self.conf.assumeno: rc = False elif self.conf.assumeyes: rc = True # grab the .sig/.asc for the keyurl, if it exists if it # does check the signature on the key if it is signed by # one of our ca-keys for this repo or the global one then # rc = True else ask as normal. elif fullaskcb: rc = fullaskcb({ "po": po, "userid": info.userid, "hexkeyid": info.short_id, "keyurl": keyurl, "fingerprint": info.fingerprint, "timestamp": info.timestamp }) elif askcb: rc = askcb(po, info.userid, info.short_id) if not rc: user_cb_fail = True continue # Import the key result = ts.pgpImportPubkey(misc.procgpgkey(info.raw_key)) if result != 0: msg = _('Key import failed (code %d)') % result raise dnf.exceptions.Error(_prov_key_data(msg)) logger.info(_('Key imported successfully')) key_installed = True if not key_installed and user_cb_fail: raise dnf.exceptions.Error(_("Didn't install any keys")) if not key_installed: msg = _('The GPG keys listed for the "%s" repository are ' 'already installed but they are not correct for this ' 'package.\n' 'Check that the correct key URLs are configured for ' 'this repository.') % repo.name raise dnf.exceptions.Error(_prov_key_data(msg)) # Check if the newly installed keys helped result, errmsg = self._sig_check_pkg(po) if result != 0: msg = _("Import of key(s) didn't help, wrong key(s)?") logger.info(msg) errmsg = ucd(errmsg) raise dnf.exceptions.Error(_prov_key_data(errmsg))
def _inform_not_a_valid_combination(self, forms): for form in forms: msg = _('Not a valid form: %s') logger.warning(msg, self.base.output.term.bold(form))
def output_packages(self, basecmd, pkgnarrow='all', patterns=(), reponame=None): """Output selection *pkgnarrow* of packages matching *patterns* and *repoid*.""" try: highlight = self.output.term.MODE['bold'] ypl = self.returnPkgLists( pkgnarrow, patterns, installed_available=highlight, reponame=reponame) except dnf.exceptions.Error as e: return 1, [str(e)] else: update_pkgs = {} inst_pkgs = {} local_pkgs = {} columns = None if basecmd == 'list': # Dynamically size the columns columns = _list_cmd_calc_columns(self.output, ypl) if highlight and ypl.installed: # If we have installed and available lists, then do the # highlighting for the installed packages so you can see what's # available to update, an extra, or newer than what we have. for pkg in (ypl.hidden_available + ypl.reinstall_available + ypl.old_available): key = (pkg.name, pkg.arch) if key not in update_pkgs or pkg > update_pkgs[key]: update_pkgs[key] = pkg if highlight and ypl.available: # If we have installed and available lists, then do the # highlighting for the available packages so you can see what's # available to install vs. update vs. old. for pkg in ypl.hidden_installed: key = (pkg.name, pkg.arch) if key not in inst_pkgs or pkg > inst_pkgs[key]: inst_pkgs[key] = pkg if highlight and ypl.updates: # Do the local/remote split we get in "yum updates" for po in sorted(ypl.updates): if po.reponame != hawkey.SYSTEM_REPO_NAME: local_pkgs[(po.name, po.arch)] = po # Output the packages: clio = self.conf.color_list_installed_older clin = self.conf.color_list_installed_newer clir = self.conf.color_list_installed_reinstall clie = self.conf.color_list_installed_extra rip = self.output.listPkgs(ypl.installed, _('Installed Packages'), basecmd, highlight_na=update_pkgs, columns=columns, highlight_modes={'>' : clio, '<' : clin, '=' : clir, 'not in' : clie}) clau = self.conf.color_list_available_upgrade clad = self.conf.color_list_available_downgrade clar = self.conf.color_list_available_reinstall clai = self.conf.color_list_available_install rap = self.output.listPkgs(ypl.available, _('Available Packages'), basecmd, highlight_na=inst_pkgs, columns=columns, highlight_modes={'<' : clau, '>' : clad, '=' : clar, 'not in' : clai}) raep = self.output.listPkgs(ypl.autoremove, _('Autoremove Packages'), basecmd, columns=columns) rep = self.output.listPkgs(ypl.extras, _('Extra Packages'), basecmd, columns=columns) cul = self.conf.color_update_local cur = self.conf.color_update_remote rup = self.output.listPkgs(ypl.updates, _('Upgraded Packages'), basecmd, highlight_na=local_pkgs, columns=columns, highlight_modes={'=' : cul, 'not in' : cur}) # XXX put this into the ListCommand at some point if len(ypl.obsoletes) > 0 and basecmd == 'list': # if we've looked up obsolete lists and it's a list request rop = [0, ''] print(_('Obsoleting Packages')) for obtup in sorted(ypl.obsoletesTuples, key=operator.itemgetter(0)): self.output.updatesObsoletesList(obtup, 'obsoletes', columns=columns) else: rop = self.output.listPkgs(ypl.obsoletes, _('Obsoleting Packages'), basecmd, columns=columns) rrap = self.output.listPkgs(ypl.recent, _('Recently Added Packages'), basecmd, columns=columns) if len(patterns) and \ rrap[0] and rop[0] and rup[0] and rep[0] and rap[0] and \ raep[0] and rip[0]: raise dnf.exceptions.Error(_('No matching Packages to list'))
def _prov_key_data(msg): msg += _('Failing package is: %s') % (po) + '\n ' msg += _('GPG Keys are configured as: %s') % \ (', '.join(repo.gpgkey) + '\n') return '\n\n\n' + msg
def register_command(self, command_cls): """Register a Command. :api""" for name in command_cls.aliases: if name in self.cli_commands: raise dnf.exceptions.ConfigError(_('Command "%s" already defined') % name) self.cli_commands[name] = command_cls
def configure(self, args): """Parse command line arguments, and set up :attr:`self.base.conf` and :attr:`self.cmds`, as well as logger objects in base instance. :param args: a list of command line arguments """ self.optparser = dnf.cli.option_parser.OptionParser() opts, cmds = self.optparser.parse_known_args(args) # Just print out the version if that's what the user wanted if opts.version: print(dnf.const.VERSION) opts.quiet = True opts.verbose = False # go through all the setopts and set the global ones bad_setopt_tm, bad_setopt_ne = self._parse_setopts(opts.setopts) if self.main_setopts: for opt in self.main_setopts.items: setattr(opts, opt, getattr(self.main_setopts, opt)) # get the install root to use self.optparser._checkAbsInstallRoot(opts.installroot) (root, opts.conffile) = self._root_and_conffile(opts.installroot, opts.conffile) # the conffile is solid now assert(opts.conffile is not None) if opts.quiet: opts.debuglevel = 0 if opts.verbose: opts.debuglevel = opts.errorlevel = dnf.const.VERBOSE_LEVEL # Read up configuration options and initialize plugins overrides = self.optparser._non_nones2dict(self._get_first_config(opts)) releasever = opts.releasever try: self.read_conf_file(opts.conffile, root, releasever, overrides) # now set all the non-first-start opts from main from our setopts if self.main_setopts: for opt in self.main_setopts.items: if not hasattr(self.base.conf, opt): msg ="Main config did not have a %s attr. before setopt" logger.warning(msg % opt) setattr(self.base.conf, opt, getattr(self.main_setopts, opt)) except (dnf.exceptions.ConfigError, ValueError) as e: logger.critical(_('Config error: %s'), e) sys.exit(1) except IOError as e: e = '%s: %s' % (ucd(e.args[1]), repr(e.filename)) logger.critical(_('Config error: %s'), e) sys.exit(1) for item in bad_setopt_tm: msg = "Setopt argument has multiple values: %s" logger.warning(msg % item) for item in bad_setopt_ne: msg = "Setopt argument has no value: %s" logger.warning(msg % item) self.optparser.configure_from_options(opts, self.base.conf, self.demands, self.base.output) self.base.cmds = cmds if opts.version: opts.quiet = True opts.verbose = False if opts.quiet: opts.debuglevel = 0 if opts.verbose: opts.debuglevel = opts.errorlevel = dnf.const.VERBOSE_LEVEL self.nogpgcheck = opts.nogpgcheck # the configuration reading phase is now concluded, finish the init self._configure_cachedir() # with cachedir in place we can configure stuff depending on it: self.base.activate_persistor() self._configure_repos(opts) if opts.version: print_versions(self.base.conf.history_record_packages, self.base, self.base.output) sys.exit(0) # store the main commands & summaries, before plugins are loaded self.optparser.add_commands(self.cli_commands, 'main') if self.base.conf.plugins: self.base.plugins.load(self.base.conf.pluginpath, opts.disableplugins) self.base.plugins.run_init(self.base, self) # store the plugin commands & summaries self.optparser.add_commands(self.cli_commands,'plugin') # build the usage info and put it into the optparser. self.optparser.usage = self.optparser.get_usage() # show help if the user requests it # this is done here, because we first have the full # usage info after the plugins are loaded. if opts.help: self.optparser.print_help() sys.exit(0) # save our original args out self.base.args = args # save out as a nice command string self.cmdstring = dnf.const.PROGRAM_NAME + ' ' for arg in self.base.args: self.cmdstring += '%s ' % arg self._log_essentials() try: self._parse_commands() # before we return check over the base command # + args make sure they match/make sense except CliError: sys.exit(1) self.command.configure(self.base.extcmds) if opts.debugsolver: self.base.conf.debug_solver = True self.base.plugins.run_config()
class ModuleCommand(commands.Command): class SubCommand(commands.Command): def __init__(self, cli): super(ModuleCommand.SubCommand, self).__init__(cli) class ListSubCommand(SubCommand): aliases = ('list',) def configure(self): demands = self.cli.demands demands.available_repos = True demands.sack_activation = True def run_on_module(self): mods = self.base.repo_module_dict if self.opts.enabled: print(mods.get_brief_description_enabled(self.opts.module_nsvp)) elif self.opts.disabled: print(mods.get_brief_description_disabled(self.opts.module_nsvp)) elif self.opts.installed: print(mods.get_brief_description_installed(self.opts.module_nsvp)) else: print(mods.get_brief_description_latest(self.opts.module_nsvp)) return 0 class InfoSubCommand(SubCommand): aliases = ('info',) def configure(self): demands = self.cli.demands demands.available_repos = True demands.sack_activation = True def run_on_module(self): for spec in self.opts.module_nsvp: try: print() if self.opts.verbose: print(self.base.repo_module_dict.get_full_info(spec)) elif self.opts.profile: print(self.base.repo_module_dict.get_info_profiles(spec)) else: print(self.base.repo_module_dict.get_info(spec)) except NoModuleException as e: logger.info(e) class EnableSubCommand(SubCommand): aliases = ('enable',) def configure(self): demands = self.cli.demands demands.available_repos = True demands.sack_activation = True demands.root_user = True def run_on_module(self): module_versions = dict() for module_ns in self.opts.module_nsvp: subj = ModuleSubject(module_ns) module_version, module_form = subj.find_module_version(self.base.repo_module_dict) if module_version.name in module_versions: raise EnableMultipleStreamsException(module_version.name) module_versions[module_version.name] = (module_version, module_form) for module_version, module_form in module_versions.values(): if module_form.profile: logger.info("Ignoring unnecessary profile: '{}/{}'".format(module_form.name, module_form.profile)) self.base.repo_module_dict.enable_by_version(module_version, True) logger.info("Module stream has been enabled: {}:{}".format(module_version.name, module_version.stream)) logger.info(_("\nTo switch to the new streams' RPMs, run '{} distro-sync'. \n" "Then migrate configuration files and data as necessary." .format(os.path.basename(sys.argv[0])))) class DisableSubCommand(SubCommand): aliases = ('disable',) def configure(self): demands = self.cli.demands demands.available_repos = True demands.sack_activation = True demands.root_user = True def run_on_module(self): for module_n in self.opts.module_nsvp: subj = ModuleSubject(module_n) module_version, module_form = subj.find_module_version(self.base.repo_module_dict) if module_form.profile: logger.info("Ignoring unnecessary profile: '{}/{}'".format(module_form.name, module_form.profile)) self.base.repo_module_dict.disable_by_version(module_version, True) logger.info("Module stream has been disabled: {}:{}".format(module_version.name, module_version.stream)) class InstallSubCommand(SubCommand): aliases = ('install',) def configure(self): demands = self.cli.demands demands.available_repos = True demands.sack_activation = True demands.resolving = True demands.root_user = True def run_on_module(self): module_specs = self.base.repo_module_dict.install(self.opts.module_nsvp, self.base.conf.strict) if module_specs: raise NoModuleException(", ".join(module_specs)) class UpdateSubCommand(SubCommand): aliases = ('update',) def configure(self): demands = self.cli.demands demands.available_repos = True demands.sack_activation = True demands.resolving = True demands.root_user = True def run_on_module(self): module_specs = self.base.repo_module_dict.upgrade(self.opts.module_nsvp, True) if module_specs: raise NoModuleException(", ".join(module_specs)) class RemoveSubCommand(SubCommand): aliases = ('remove', 'erase',) def configure(self): demands = self.cli.demands demands.allow_erasing = True demands.available_repos = True demands.resolving = True demands.root_user = True demands.sack_activation = True def run_on_module(self): self.base.repo_module_dict.remove(self.opts.module_nsvp) class ProfileInfoSubCommand(SubCommand): aliases = ("profile", "profile-info") def configure(self): demands = self.cli.demands demands.available_repos = True demands.sack_activation = True def run_on_module(self): for spec in self.opts.module_nsvp: print() logger.info(self.base.repo_module_dict.get_info_profiles(spec)) class StreamsSubCommand(SubCommand): aliases = ("streams", "enabled", "enabled-streams") def configure(self): demands = self.cli.demands demands.available_repos = True demands.sack_activation = True def run_on_module(self): logger.info(self.base.repo_module_dict .get_brief_description_enabled(self.opts.module_nsvp)) class ProvidesSubCommand(SubCommand): aliases = ("provides", ) def configure(self): demands = self.cli.demands demands.available_repos = True demands.sack_activation = True def run_on_module(self): self.base.repo_module_dict.print_what_provides(self.opts.module_nsvp) SUBCMDS = {ListSubCommand, InfoSubCommand, EnableSubCommand, DisableSubCommand, InstallSubCommand, UpdateSubCommand, RemoveSubCommand, ProfileInfoSubCommand, StreamsSubCommand, ProvidesSubCommand} SUBCMDS_NOT_REQUIRED_ARG = {ListSubCommand, StreamsSubCommand} aliases = ("module",) summary = _("Interact with Modules.") def __init__(self, cli): super(ModuleCommand, self).__init__(cli) subcmd_objs = (subcmd(cli) for subcmd in self.SUBCMDS) self.subcmd = None self._subcmd_name2obj = { alias: subcmd for subcmd in subcmd_objs for alias in subcmd.aliases} def set_argparser(self, parser): subcommand_help = [subcmd.aliases[0] for subcmd in self.SUBCMDS] parser.add_argument('subcmd', nargs=1, choices=subcommand_help) parser.add_argument('module_nsvp', nargs='*') narrows = parser.add_mutually_exclusive_group() narrows.add_argument('--enabled', dest='enabled', action='store_true', help=_("show only enabled modules")) narrows.add_argument('--disabled', dest='disabled', action='store_true', help=_("show only disabled modules")) narrows.add_argument('--installed', dest='installed', action='store_true', help=_("show only installed modules")) narrows.add_argument('--profile', dest='profile', action='store_true', help=_("show profile content")) narrows.add_argument('--autoenable', dest='autoenable', action='store_true', help=_("auto enable stream")) def configure(self): try: self.subcmd = self._subcmd_name2obj[self.opts.subcmd[0]] except (CliError, KeyError): self.cli.optparser.print_usage() raise CliError self.subcmd.opts = self.opts self.subcmd.configure() def run(self): self.check_required_argument() self.subcmd.run_on_module() def check_required_argument(self): not_required_argument = [alias for subcmd in self.SUBCMDS_NOT_REQUIRED_ARG for alias in subcmd.aliases] if self.opts.subcmd[0] not in not_required_argument: if not self.opts.module_nsvp: raise CliError( "dnf {} {}: too few arguments".format(self.opts.command[0], self.opts.subcmd[0]))
def do_transaction(self, display=()): """Take care of package downloading, checking, user confirmation and actually running the transaction. :param display: `TransactionDisplay` object(s) :return: a numeric return code, and optionally a list of errors. A negative return code indicates that errors occurred in the pre-transaction checks """ grp_diff = self._groups_diff() grp_str = self.output.list_group_transaction(self.comps, grp_diff) if grp_str: logger.info(grp_str) trans = self.transaction pkg_str = self.output.list_transaction(trans) if pkg_str: logger.info(pkg_str) if trans: # Check which packages have to be downloaded downloadpkgs = [] rmpkgs = [] stuff_to_download = False install_only = True for tsi in trans: installed = tsi.installed if installed is not None: stuff_to_download = True downloadpkgs.append(installed) erased = tsi.erased if erased is not None: install_only = False rmpkgs.append(erased) # Close the connection to the rpmdb so that rpm doesn't hold the # SIGINT handler during the downloads. del self.ts # report the total download size to the user if not stuff_to_download: self.output.reportRemoveSize(rmpkgs) else: self.output.reportDownloadSize(downloadpkgs, install_only) if trans or (grp_diff and not grp_diff.empty()): # confirm with user if self._promptWanted(): if self.conf.assumeno or not self.output.userconfirm(): raise CliError(_("Operation aborted.")) else: logger.info(_('Nothing to do.')) return if trans: if downloadpkgs: logger.info(_('Downloading Packages:')) try: total_cb = self.output.download_callback_total_cb self.download_packages(downloadpkgs, self.output.progress, total_cb) except dnf.exceptions.DownloadError as e: specific = dnf.cli.format.indent_block(ucd(e)) errstring = _('Error downloading packages:\n%s') % specific raise dnf.exceptions.Error(errstring) # Check GPG signatures self.gpgsigcheck(downloadpkgs) if not isinstance(display, collections.Sequence): display = [display] display = [output.CliTransactionDisplay()] + list(display) super(BaseCli, self).do_transaction(display) if trans: msg = self.output.post_transaction_output(trans) logger.info(msg)
def display_info(self, apkg_adv_insts, mixed, description): """Display the details about available advisories.""" info = self._info(apkg_adv_insts).items() # Convert objects to string lines and mark verbose fields. verbse = lambda value: value if self.base.conf.verbose else None info = ( (tit, ([id_], [self.TYPE2LABEL[typ]], [unicode(upd)], (id_title[0] + ' - ' + id_title[1] for id_title in bzs), (id_title[0] for id_title in cvs), desc.splitlines(), verbse(rigs.splitlines() if rigs else None), verbse(fils), None if not mixed else [_('true') if ins else _('false')])) for tit, (id_, typ, upd, bzs, cvs, desc, rigs, fils, ins) in info) labels = (_('Update ID'), _('Type'), _('Updated'), _('Bugs'), _('CVEs'), _('Description'), _('Rights'), _('Files'), _('Installed')) width = _maxlen(labels) for title, vallines in info: print('=' * 79) print(' ' + title) print('=' * 79) for label, lines in zip(labels, vallines): if lines is None: continue # Use the label only for the first item. For the remaining # items, use an empty label. labels_ = chain([label], itertools.repeat('')) for label_, line in zip(labels_, lines): print('%*s : %s' % (width, label_, line)) print()
def _ensure_sanity(self): """Make sure the input db is valid.""" if 'GROUPS' in self.db and 'ENVIRONMENTS' in self.db: return logger.warning(_('Invalid groups database, clearing.')) self.db = self._empty_db()
def _addYumBasicOptions(self): # All defaults need to be a None, so we can always tell whether the user # has set something or whether we are getting a default. self.conflict_handler = "resolve" self.conflict_handler = "error" self.add_argument('--allowerasing', action='store_true', default=None, help=_('allow erasing of installed packages to ' 'resolve dependencies')) self.add_argument("-b", "--best", action="store_true", default=None, help=_("try the best available package versions in " "transactions.")) self.add_argument("-C", "--cacheonly", dest="cacheonly", action="store_true", default=None, help=_("run entirely from system cache, " "don't update cache")) self.add_argument("-c", "--config", dest="conffile", default=None, metavar='[config file]', help=_("config file location")) self.add_argument("-d", "--debuglevel", dest="debuglevel", metavar='[debug level]', default=None, help=_("debugging output level"), type=int) self.add_argument("--debugsolver", action="store_true", default=None, help=_("dumps detailed solving results into files")) self.add_argument("--showduplicates", dest="showdupesfromrepos", action="store_true", default=None, help=_("show duplicates, in repos, " "in list/search commands")) self.add_argument("-e", "--errorlevel", default=None, type=int, help=_("error output level")) self.add_argument("--rpmverbosity", default=None, help=_("debugging output level for rpm"), metavar='[debug level name]') self.add_argument("-q", "--quiet", dest="quiet", action="store_true", default=None, help=_("quiet operation")) self.add_argument("-v", "--verbose", action="store_true", default=None, help=_("verbose operation")) self.add_argument("-y", "--assumeyes", action="store_true", default=None, help=_("answer yes for all questions")) self.add_argument("--assumeno", action="store_true", default=None, help=_("answer no for all questions")) self.add_argument("--version", action="store_true", default=None, help=_("show DNF version and exit")) self.add_argument("--installroot", help=_("set install root"), metavar='[path]') self.add_argument("--enablerepo", action=self._RepoCallback, dest='repos_ed', default=[], metavar='[repo]') self.add_argument("--disablerepo", action=self._RepoCallback, dest='repos_ed', default=[], metavar='[repo]') self.add_argument("-x", "--exclude", default=[], dest='excludepkgs', action=self._SplitCallback, help=_("exclude packages by name or glob"), metavar='[package]') self.add_argument("--disableexcludes", default=[], dest="disable_excludes", action=self._SplitCallback, help=_("disable excludes"), metavar='[repo]') self.add_argument( "--obsoletes", action="store_true", default=None, help=_("enable obsoletes processing during upgrades")) self.add_argument("--noplugins", action="store_false", default=None, dest='plugins', help=_("disable all plugins")) self.add_argument("--nogpgcheck", action="store_true", default=None, help=_("disable gpg signature checking")) self.add_argument("--disableplugin", dest="disableplugins", default=[], action=self._SplitCallback, help=_("disable plugins by name"), metavar='[plugin]') self.add_argument("--color", dest="color", default=None, help=_("control whether color is used")) self.add_argument("--releasever", default=None, help=_("override the value of $releasever in config" " and repo files")) self.add_argument("--setopt", dest="setopts", default=[], action="append", help=_("set arbitrary config and repo options")) self.add_argument("--refresh", dest="freshest_metadata", action="store_true") self.add_argument("-4", dest="ip_resolve", default=None, help=_("resolve to IPv4 addresses only"), action="store_const", const='ipv4') self.add_argument("-6", dest="ip_resolve", default=None, help=_("resolve to IPv6 addresses only"), action="store_const", const='ipv6') # we add our own help option, so we can control that help is not shown # automatic when we do the .parse_known_args(args) # but first after plugins are loaded. self.add_argument('-h', '--help', action="store_true", help="show help")
class UpdateInfoCommand(commands.Command): """Implementation of the UpdateInfo command.""" TYPE2LABEL = {hawkey.ADVISORY_BUGFIX: _('bugfix'), hawkey.ADVISORY_ENHANCEMENT: _('enhancement'), hawkey.ADVISORY_SECURITY: _('security'), hawkey.ADVISORY_UNKNOWN: _('unknown'), hawkey.ADVISORY_NEWPACKAGE: _('newpackage')} aliases = ['updateinfo'] summary = _('display advisories about packages') def __init__(self, cli): """Initialize the command.""" super(UpdateInfoCommand, self).__init__(cli) self._ina2evr_cache = None self.clear_installed_cache() def refresh_installed_cache(self): """Fill the cache of installed packages.""" self._ina2evr_cache = {(pkg.name, pkg.arch): pkg.evr for pkg in self.base.sack.query().installed()} def clear_installed_cache(self): """Clear the cache of installed packages.""" self._ina2evr_cache = None def _older_installed(self, apackage): """Test whether an older version of a package is installed.""" # Non-cached lookup not implemented. Fill the cache or implement the # functionality via the slow sack query. assert self._ina2evr_cache is not None try: ievr = self._ina2evr_cache[(apackage.name, apackage.arch)] except KeyError: return False q = self.base.sack.query().filter(name=apackage.name, evr=apackage.evr) if len(self.base._merge_update_filters(q, warning=False)) == 0: return False return self.base.sack.evr_cmp(ievr, apackage.evr) < 0 def _newer_equal_installed(self, apkg): """Test whether a newer or equal version of a package is installed.""" # Non-cached lookup not implemented. Fill the cache or implement the # functionality via the slow sack query. assert self._ina2evr_cache is not None try: ievr = self._ina2evr_cache[(apkg.name, apkg.arch)] except KeyError: return False q = self.base.sack.query().filter(name=apkg.name, evr=apkg.evr) if len(self.base._merge_update_filters(q, warning=False)) == 0: return False return self.base.sack.evr_cmp(ievr, apkg.evr) >= 0 def _any_installed(self, apkg): """Test whether any version of a package is installed.""" # Non-cached lookup not implemented. Fill the cache or implement the # functionality via the slow sack query. assert self._ina2evr_cache is not None q = self.base.sack.query().filter(name=apkg.name, evr=apkg.evr) if len(self.base._merge_update_filters(q, warning=False)) == 0: return False return (apkg.name, apkg.arch) in self._ina2evr_cache @staticmethod def set_argparser(parser): cmds = ['summary', 'list', 'info'] parser.add_argument('spec', nargs='*', metavar='SPEC', choices=cmds, default=cmds[0], action=OptionParser.PkgNarrowCallback) def configure(self): """Do any command-specific configuration based on command arguments.""" self.cli.demands.available_repos = True self.cli.demands.sack_activation = True @staticmethod def _apackage_advisory_match(apackage, advisory, specs=()): """Test whether an (adv. pkg., adv.) pair matches specifications.""" if not specs: return True specs = set(specs) types = set() if 'bugfix' in specs: types.add(hawkey.ADVISORY_BUGFIX) if 'enhancement' in specs: types.add(hawkey.ADVISORY_ENHANCEMENT) if {'security', 'sec'} & specs: types.add(hawkey.ADVISORY_SECURITY) if 'newpackage' in specs: types.add(hawkey.ADVISORY_NEWPACKAGE) return (any(fnmatch.fnmatchcase(advisory.id, pat) for pat in specs) or advisory.type in types or any(fnmatch.fnmatchcase(apackage.name, pat) for pat in specs)) def _apackage_advisory_installeds(self, pkgs, cmptype, req_apkg, specs=()): """Return (adv. package, advisory, installed) triplets and a flag.""" for package in pkgs: for advisory in package.get_advisories(cmptype): for apackage in advisory.packages: passed = (req_apkg(apackage) and self._apackage_advisory_match( apackage, advisory, specs)) if passed: installed = self._newer_equal_installed(apackage) yield apackage, advisory, installed def available_apkg_adv_insts(self, specs=()): """Return available (adv. package, adv., inst.) triplets and a flag.""" return False, self._apackage_advisory_installeds( self.base.sack.query().installed(), hawkey.GT, self._older_installed, specs) def installed_apkg_adv_insts(self, specs=()): """Return installed (adv. package, adv., inst.) triplets and a flag.""" return False, self._apackage_advisory_installeds( self.base.sack.query().installed(), hawkey.LT | hawkey.EQ, self._newer_equal_installed, specs) def updating_apkg_adv_insts(self, specs=()): """Return updating (adv. package, adv., inst.) triplets and a flag.""" return False, self._apackage_advisory_installeds( self.base.sack.query().filter(upgradable=True), hawkey.GT, self._older_installed, specs) def all_apkg_adv_insts(self, specs=()): """Return installed (adv. package, adv., inst.) triplets and a flag.""" ipackages = self.base.sack.query().installed() gttriplets = self._apackage_advisory_installeds( ipackages, hawkey.GT, self._any_installed, specs) lteqtriplets = self._apackage_advisory_installeds( ipackages, hawkey.LT | hawkey.EQ, self._any_installed, specs) return True, chain(gttriplets, lteqtriplets) @staticmethod def _summary(apkg_adv_insts): """Make the summary of advisories.""" # Remove duplicate advisory IDs. We assume that the ID is unique within # a repository and two advisories with the same IDs in different # repositories must have the same type. id2type = {pkadin[1].id: pkadin[1].type for pkadin in apkg_adv_insts} return collections.Counter(id2type.values()) @classmethod def display_summary(cls, apkg_adv_insts, mixed, description): """Display the summary of advisories.""" typ2cnt = cls._summary(apkg_adv_insts) if not typ2cnt: return print(_('Updates Information Summary: ') + description) # Convert types to strings and order the entries. label_counts = [ (_('New Package notice(s)'), typ2cnt[hawkey.ADVISORY_NEWPACKAGE]), (_('Security notice(s)'), typ2cnt[hawkey.ADVISORY_SECURITY]), (_('Bugfix notice(s)'), typ2cnt[hawkey.ADVISORY_BUGFIX]), (_('Enhancement notice(s)'), typ2cnt[hawkey.ADVISORY_ENHANCEMENT]), (_('other notice(s)'), typ2cnt[hawkey.ADVISORY_UNKNOWN])] # Convert counts to strings and skip missing types. label2value = OrderedDict( (label, unicode(count)) for label, count in label_counts if count) width = _maxlen(label2value.values()) for label, value in label2value.items(): print(' %*s %s' % (width, value, label)) @staticmethod def _list(apkg_adv_insts): """Make the list of advisories.""" # Get ((NEVRA, installed), advisory ID, advisory type) apkg2nevra = lambda apkg: apkg.name + '-' + apkg.evr + '.' + apkg.arch nevrains_id_types = ( ((apkg2nevra(apkg), inst), adv.id, adv.type) for apkg, adv, inst in apkg_adv_insts) # Sort and group by (NEVRA, installed). nevrains_nits = itertools.groupby( sorted(nevrains_id_types, key=itemgetter(0)), key=itemgetter(0)) for nevra_ins, nits in nevrains_nits: # Remove duplicate IDs. We assume that two advisories with the same # IDs (e.g. from different repositories) must have the same type. yield nevra_ins, {nit[1]: nit[2] for nit in nits} @classmethod def display_list(cls, apkg_adv_insts, mixed, description): """Display the list of advisories.""" # Sort IDs and convert types to labels. inst2mark = lambda inst: '' if not mixed else 'i ' if inst else ' ' nevramark2id2tlbl = OrderedDict( ((nevra, inst2mark(inst)), OrderedDict(sorted(((id_, cls.TYPE2LABEL[typ]) for id_, typ in id2type.items()), key=itemgetter(0)))) for (nevra, inst), id2type in cls._list(apkg_adv_insts)) if not nevramark2id2tlbl: return # Get all advisory IDs and types as two iterables. ids, tlbls = zip(*chain.from_iterable( id2tlbl.items() for id2tlbl in nevramark2id2tlbl.values())) idw, tlw = _maxlen(ids), _maxlen(tlbls) for (nevra, mark), id2tlbl in nevramark2id2tlbl.items(): for id_, tlbl in id2tlbl.items(): print('%s%-*s %-*s %s' % (mark, idw, id_, tlw, tlbl, nevra)) def _info(self, apkg_adv_insts): """Make detailed information about advisories.""" # Get mapping from identity to (title, ID, type, time, BZs, CVEs, # description, rights, files, installed). This way we get rid of # unneeded advisory packages given with the advisories and we remove # duplicate advisories (that SPEEDS UP the information extraction # because the advisory attribute getters are expensive, so we won't get # the attributes multiple times). We cannot use a set because # advisories are not hashable. getrefs = lambda apkg, typ: ( (ref.id, ref.title) for ref in apkg.references if ref.type == typ) id2tuple = OrderedDict() for apkg_adv_inst in apkg_adv_insts: identity, inst = id(apkg_adv_inst[1]), apkg_adv_inst[2] try: tuple_ = id2tuple[identity] except KeyError: id2tuple[identity] = ( apkg_adv_inst[1].title, apkg_adv_inst[1].id, apkg_adv_inst[1].type, apkg_adv_inst[1].updated, getrefs(apkg_adv_inst[1], hawkey.REFERENCE_BUGZILLA), getrefs(apkg_adv_inst[1], hawkey.REFERENCE_CVE), apkg_adv_inst[1].description, apkg_adv_inst[1].rights, (pkg.filename for pkg in apkg_adv_inst[1].packages if pkg.arch in self.base.sack.list_arches()), inst) else: # If the stored advisory is marked as not installed and the # current is marked as installed, mark the stored as installed. if not tuple_[9] and inst: id2tuple[identity] = tuple_[:9] + (inst,) # Get mapping from title to (ID, type, time, BZs, CVEs, description, # rights, files, installed) => group by titles and merge values. We # assume that two advisories with the same title (e.g. from different # repositories) must have the same ID, type, time, description and # rights. References, files and installs are merged. merge = lambda old, new: set(chain(old, new)) title2info = OrderedDict() for tuple_ in id2tuple.values(): title, new = tuple_[0], tuple_[1:] old = title2info.get( title, (None, None, None, [], [], None, None, [], False)) title2info[title] = ( new[:3] + (merge(old[3], new[3]), merge(old[4], new[4])) + new[5:7] + (merge(old[7], new[7]), old[8] or new[8])) return title2info def display_info(self, apkg_adv_insts, mixed, description): """Display the details about available advisories.""" info = self._info(apkg_adv_insts).items() # Convert objects to string lines and mark verbose fields. verbse = lambda value: value if self.base.conf.verbose else None info = ( (tit, ([id_], [self.TYPE2LABEL[typ]], [unicode(upd)], (id_title[0] + ' - ' + id_title[1] for id_title in bzs), (id_title[0] for id_title in cvs), desc.splitlines(), verbse(rigs.splitlines() if rigs else None), verbse(fils), None if not mixed else [_('true') if ins else _('false')])) for tit, (id_, typ, upd, bzs, cvs, desc, rigs, fils, ins) in info) labels = (_('Update ID'), _('Type'), _('Updated'), _('Bugs'), _('CVEs'), _('Description'), _('Rights'), _('Files'), _('Installed')) width = _maxlen(labels) for title, vallines in info: print('=' * 79) print(' ' + title) print('=' * 79) for label, lines in zip(labels, vallines): if lines is None: continue # Use the label only for the first item. For the remaining # items, use an empty label. labels_ = chain([label], itertools.repeat('')) for label_, line in zip(labels_, lines): print('%*s : %s' % (width, label_, line)) print() def run(self): """Execute the command with arguments.""" self.cli._populate_update_security_filter(self.opts, minimal=True) args = self.opts.spec display = self.display_summary if self.opts.spec_action == 'list': display = self.display_list elif self.opts.spec_action == 'info': display = self.display_info self.refresh_installed_cache() if args[:1] == ['installed']: mixed, apkg_adv_insts = self.installed_apkg_adv_insts(args[1:]) description = _('installed') elif args[:1] == ['updates']: mixed, apkg_adv_insts = self.updating_apkg_adv_insts(args[1:]) description = _('updates') elif args[:1] == ['all']: mixed, apkg_adv_insts = self.all_apkg_adv_insts(args[1:]) description = _('all') else: if args[:1] == ['available']: args = args[1:] mixed, apkg_adv_insts = self.available_apkg_adv_insts(args) description = _('available') display(apkg_adv_insts, mixed, description) self.clear_installed_cache()
def configure(self, args, option_parser=None): """Parse command line arguments, and set up :attr:`self.base.conf` and :attr:`self.cmds`, as well as logger objects in base instance. :param args: a list of command line arguments :param option_parser: a class for parsing cli options """ aliases = dnf.cli.aliases.Aliases() args = aliases.resolve(args) self.optparser = dnf.cli.option_parser.OptionParser() \ if option_parser is None else option_parser opts = self.optparser.parse_main_args(args) # Just print out the version if that's what the user wanted if opts.version: print(dnf.const.VERSION) print_versions(self.base.conf.history_record_packages, self.base, self.base.output) sys.exit(0) if opts.quiet: opts.debuglevel = 0 opts.errorlevel = 2 if opts.verbose: opts.debuglevel = opts.errorlevel = dnf.const.VERBOSE_LEVEL # Read up configuration options and initialize plugins try: if opts.cacheonly: self.base.conf._set_value("cachedir", self.base.conf.system_cachedir, dnf.conf.PRIO_DEFAULT) self.demands.cacheonly = True self.base.conf._configure_from_options(opts) self._read_conf_file(opts.releasever) if 'arch' in opts: self.base.conf.arch = opts.arch self.base.conf._adjust_conf_options() except (dnf.exceptions.ConfigError, ValueError) as e: logger.critical(_('Config error: %s'), e) sys.exit(1) except IOError as e: e = '%s: %s' % (ucd(str(e)), repr(e.filename)) logger.critical(_('Config error: %s'), e) sys.exit(1) if opts.destdir is not None: self.base.conf.destdir = opts.destdir if not self.base.conf.downloadonly and opts.command not in ( 'download', 'system-upgrade', 'reposync'): logger.critical( _('--destdir or --downloaddir must be used with --downloadonly ' 'or download or system-upgrade command.')) sys.exit(1) if (opts.set_enabled or opts.set_disabled) and opts.command != 'config-manager': logger.critical( _('--enable, --set-enabled and --disable, --set-disabled ' 'must be used with config-manager command.')) sys.exit(1) if opts.sleeptime is not None: time.sleep(random.randrange(opts.sleeptime * 60)) # store the main commands & summaries, before plugins are loaded self.optparser.add_commands(self.cli_commands, 'main') # store the plugin commands & summaries self.base.init_plugins(opts.disableplugin, opts.enableplugin, self) self.optparser.add_commands(self.cli_commands, 'plugin') # show help if no command specified # this is done here, because we first have the full # usage info after the plugins are loaded. if not opts.command: self.optparser.print_help() sys.exit(0) # save our original args out self.base.args = args # save out as a nice command string self.cmdstring = self.optparser.prog + ' ' for arg in self.base.args: self.cmdstring += '%s ' % arg self._log_essentials() try: self._parse_commands(opts, args) except CliError: sys.exit(1) # show help for dnf <command> --help / --help-cmd if opts.help: self.optparser.print_help(self.command) sys.exit(0) opts = self.optparser.parse_command_args(self.command, args) if opts.allowerasing: self.demands.allow_erasing = opts.allowerasing self.base._allow_erasing = True if opts.freshest_metadata: self.demands.freshest_metadata = opts.freshest_metadata if opts.debugsolver: self.base.conf.debug_solver = True if opts.obsoletes: self.base.conf.obsoletes = True self.command.pre_configure() self.base.pre_configure_plugins() # with cachedir in place we can configure stuff depending on it: self.base._activate_persistor() self._configure_repos(opts) self.base.configure_plugins() self.base.conf._configure_from_options(opts) self.command.configure() if self.base.conf.destdir: dnf.util.ensure_dir(self.base.conf.destdir) self.base.repos.all().pkgdir = self.base.conf.destdir if self.base.conf.color != 'auto': self.base.output.term.reinit(color=self.base.conf.color) if rpm.expandMacro('%_pkgverify_level') in ('signature', 'all'): forcing = False for repo in self.base.repos.iter_enabled(): if repo.gpgcheck: continue repo.gpgcheck = True forcing = True if not self.base.conf.localpkg_gpgcheck: self.base.conf.localpkg_gpgcheck = True forcing = True if forcing: logger.warning( _("Warning: Enforcing GPG signature check globally " "as per active RPM security policy (see 'gpgcheck' in " "dnf.conf(5) for how to squelch this message)"))
class ReinstallCommand(commands.Command): """A class containing methods needed by the cli to execute the reinstall command. """ aliases = ('reinstall', 'rei', 'ri') summary = _('reinstall a package') @staticmethod def set_argparser(parser): parser.add_argument('packages', nargs='+', help=_('Package to reinstall'), action=OptionParser.ParseSpecGroupFileCallback, metavar=_('PACKAGE')) def configure(self): """Verify that conditions are met so that this command can run. These include that the program is being run by the root user, that there are enabled repositories with gpg keys, and that this command is called with appropriate arguments. """ demands = self.cli.demands demands.sack_activation = True demands.available_repos = True demands.resolving = True demands.root_user = True commands._checkGPGKey(self.base, self.cli) if not self.opts.filenames: commands._checkEnabledRepo(self.base) def run(self): # Reinstall files. done = False for pkg in self.base.add_remote_rpms(self.opts.filenames, strict=False): try: self.base.package_reinstall(pkg) except dnf.exceptions.MarkingError: logger.info(_('No match for argument: %s'), self.base.output.term.bold(pkg.location)) else: done = True # Reinstall packages. for pkg_spec in self.opts.pkg_specs + [ '@' + x for x in self.opts.grp_specs ]: try: self.base.reinstall(pkg_spec) except dnf.exceptions.PackagesNotInstalledError as err: for pkg in err.packages: logger.info(_('Package %s available, but not installed.'), self.output.term.bold(pkg.name)) break logger.info(_('No match for argument: %s'), self.base.output.term.bold(pkg_spec)) except dnf.exceptions.PackagesNotAvailableError as err: for pkg in err.packages: xmsg = '' yumdb_info = self.base._yumdb.get_package(pkg) if 'from_repo' in yumdb_info: xmsg = _(' (from %s)') % yumdb_info.from_repo msg = _('Installed package %s%s not available.') logger.info(msg, self.base.output.term.bold(pkg), xmsg) except dnf.exceptions.MarkingError: assert False, 'Only the above marking errors are expected.' else: done = True if not done: raise dnf.exceptions.Error(_('Nothing to do.'))
def report_module_switch(switchedModules): msg1 = _( "The operation would result in switching of module '{0}' stream '{1}' to " "stream '{2}'") for moduleName, streams in switchedModules.items(): logger.warning(msg1.format(moduleName, streams[0], streams[1]))
def _name_unset_wrapper(input_name): # returns <name-unset> for everything that evaluates to False (None, empty..) return input_name if input_name else _("<name-unset>")
def ex_Error(e): logger.log(dnf.logging.SUBDEBUG, '', exc_info=True) if e.value is not None: logger.critical(_('Error: %s'), ucd(e)) return 1
def do_transaction(self, display=()): """Take care of package downloading, checking, user confirmation and actually running the transaction. :param display: `rpm.callback.TransactionProgress` object(s) :return: history database transaction ID or None """ if dnf.base.WITH_MODULES: if not self.conf.module_stream_switch: switchedModules = dict( self._moduleContainer.getSwitchedStreams()) if switchedModules: report_module_switch(switchedModules) msg = _( "It is not possible to switch enabled streams of a module unless explicitly " "enabled via configuration option module_stream_switch.\n" "It is recommended to rather remove all installed content from the module, and " "reset the module using '{prog} module reset <module_name>' command. After " "you reset the module, you can install the other stream." ).format(prog=dnf.util.MAIN_PROG) raise dnf.exceptions.Error(msg) trans = self.transaction pkg_str = self.output.list_transaction(trans) if pkg_str: logger.info(pkg_str) if trans: # Check which packages have to be downloaded install_pkgs = [] rmpkgs = [] install_only = True for tsi in trans: if tsi.action in dnf.transaction.FORWARD_ACTIONS: install_pkgs.append(tsi.pkg) elif tsi.action in dnf.transaction.BACKWARD_ACTIONS: install_only = False rmpkgs.append(tsi.pkg) # Close the connection to the rpmdb so that rpm doesn't hold the # SIGINT handler during the downloads. del self._ts # report the total download size to the user if not install_pkgs: self.output.reportRemoveSize(rmpkgs) else: self.output.reportDownloadSize(install_pkgs, install_only) if trans or self._moduleContainer.isChanged() or \ (self._history and (self._history.group or self._history.env)): # confirm with user if self.conf.downloadonly: logger.info( _("{prog} will only download packages for the transaction." ).format(prog=dnf.util.MAIN_PROG_UPPER)) elif 'test' in self.conf.tsflags: logger.info( _("{prog} will only download packages, install gpg keys, and check the " "transaction.").format(prog=dnf.util.MAIN_PROG_UPPER)) if self._promptWanted(): if self.conf.assumeno or not self.output.userconfirm(): raise CliError(_("Operation aborted.")) else: logger.info(_('Nothing to do.')) return if trans: if install_pkgs: logger.info(_('Downloading Packages:')) try: total_cb = self.output.download_callback_total_cb self.download_packages(install_pkgs, self.output.progress, total_cb) except dnf.exceptions.DownloadError as e: specific = dnf.cli.format.indent_block(ucd(e)) errstr = _( 'Error downloading packages:') + '\n%s' % specific # setting the new line to prevent next chars being eaten up # by carriage returns print() raise dnf.exceptions.Error(errstr) # Check GPG signatures self.gpgsigcheck(install_pkgs) if self.conf.downloadonly: return if not isinstance(display, Sequence): display = [display] display = [output.CliTransactionDisplay()] + list(display) tid = super(BaseCli, self).do_transaction(display) # display last transaction (which was closed during do_transaction()) if tid is not None: trans = self.history.old([tid])[0] trans = dnf.db.group.RPMTransaction(self.history, trans._trans) else: trans = None if trans: # the post transaction summary is already written to log during # Base.do_transaction() so here only print the messages to the # user arranged in columns print() print('\n'.join(self.output.post_transaction_output(trans))) print() for tsi in trans: if tsi.state == libdnf.transaction.TransactionItemState_ERROR: raise dnf.exceptions.Error(_('Transaction failed')) return tid
class ShellCommand(commands.Command, cmd.Cmd): aliases = ('shell', 'sh') summary = _('run an interactive DNF shell') MAPPING = { 'repo': 'repo', 'repository': 'repo', 'exit': 'quit', 'quit': 'quit', 'run': 'ts_run', 'ts': 'transaction', 'transaction': 'transaction', 'config': 'config', 'resolvedep': 'resolve', 'help': 'help' } def __init__(self, cli): commands.Command.__init__(self, cli) cmd.Cmd.__init__(self) self.prompt = '> ' @staticmethod def set_argparser(parser): parser.add_argument('script', nargs='?', metavar=_('SCRIPT'), help=_('Script to run in DNF shell')) def configure(self): self.cli.demands = ShellDemandSheet() def run(self): if self.opts.script: self._run_script(self.opts.script) else: self.cmdloop() def _clean(self): self.base._finalize_base() self.base._transaction = None self.base.fill_sack() def onecmd(self, line): if not line or line == '\n': return if line == 'EOF': line = 'quit' try: s_line = shlex.split(line) except: self._help() return opts = self.cli.optparser.parse_main_args(s_line) # Disable shell recursion. if opts.command == 'shell': return if opts.command in self.MAPPING: getattr(self, '_' + self.MAPPING[opts.command])(s_line[1::]) else: cmd_cls = self.cli.cli_commands.get(opts.command) if cmd_cls is not None: cmd = cmd_cls(self.cli) try: opts = self.cli.optparser.parse_command_args(cmd, s_line) cmd.cli.demands = copy.deepcopy(self.cli.demands) cmd.configure() cmd.run() except dnf.exceptions.Error as e: logger.error(_("Error:") + " " + e.value) except: return else: self._help() def _config(self, args=None): def print_or_set(key, val, conf): if val: setattr(conf, key, val) else: try: print('{}: {}'.format(key, getattr(conf, str(key)))) except: logger.warning(_('Unsupported key value.')) if not args or len(args) > 2: self._help('config') return key = args[0] val = args[1] if len(args) == 2 else None period = key.find('.') if period != -1: repo_name = key[:period] key = key[period + 1:] repos = self.base.repos.get_matching(repo_name) for repo in repos: print_or_set(key, val, repo) if not repos: logger.warning(_('Could not find repository: %s'), repo_name) else: print_or_set(key, val, self.base.conf) def _help(self, args=None): """Output help information. :param args: the command to output help information about. If *args* is an empty, general help will be output. """ arg = args[0] if isinstance(args, list) and len(args) > 0 else args msg = None if arg: if arg == 'config': msg = _("""{} arg [value] arg: debuglevel, errorlevel, obsoletes, gpgcheck, assumeyes, exclude, repo_id.gpgcheck, repo_id.exclude If no value is given it prints the current value. If value is given it sets that value.""").format(arg) elif arg == 'help': msg = _("""{} [command] print help""").format(arg) elif arg in ['repo', 'repository']: msg = _("""{} arg [option] list: lists repositories and their status. option = [all | id | glob] enable: enable repositories. option = repository id disable: disable repositories. option = repository id""").format(arg) elif arg == 'resolvedep': msg = _("""{} resolve the transaction set""").format(arg) elif arg in ['transaction', 'ts']: msg = _("""{} arg list: lists the contents of the transaction reset: reset (zero-out) the transaction run: run the transaction""").format(arg) elif arg == 'run': msg = _("""{} run the transaction""").format(arg) elif arg in ['exit', 'quit']: msg = _("""{} exit the shell""").format(arg) if not msg: self.cli.optparser.print_help() msg = _("""Shell specific arguments: config set config options help print help repository (or repo) enable, disable or list repositories resolvedep resolve the transaction set transaction (or ts) list, reset or run the transaction set run resolve and run the transaction set exit (or quit) exit the shell""") print('\n' + msg) def _repo(self, args=None): cmd = args[0] if args else None if cmd in ['list', None]: self.onecmd('repolist ' + ' '.join(args[1:])) elif cmd in ['enable', 'disable']: repos = self.cli.base.repos fill_sack = False for repo in args[1::]: r = repos.get_matching(repo) if r: getattr(r, cmd)() fill_sack = True else: logger.critical( _("Error:") + " " + _("Unknown repo: '%s'"), self.base.output.term.bold(repo)) if fill_sack: self.base.fill_sack() else: self._help('repo') def _resolve(self, args=None): if self.cli.base.transaction is None: try: self.cli.base.resolve(self.cli.demands.allow_erasing) except dnf.exceptions.DepsolveError as e: print(e) def _run_script(self, file): try: with open(file, 'r') as fd: lines = fd.readlines() for line in lines: if not line.startswith('#'): self.onecmd(line) except IOError: logger.info(_('Error: Cannot open %s for reading'), self.base.output.term.bold(file)) sys.exit(1) def _transaction(self, args=None): cmd = args[0] if args else None if cmd == 'reset': self._clean() return self._resolve() if cmd in ['list', None]: if self.base._transaction: out = self.base.output.list_transaction(self.base._transaction) logger.info(out) elif cmd == 'run': try: self.base.do_transaction() except: pass self._clean() else: self._help('transaction') def _ts_run(self, args=None): self._transaction(['run']) def _quit(self, args=None): logger.info(_('Leaving Shell')) sys.exit(0)
def _option_conflict(self, option_string_1, option_string_2): print(self.optparser.print_usage()) raise dnf.exceptions.Error( _("argument {}: not allowed with argument {}".format( option_string_1, option_string_2)))
def _quit(self, args=None): logger.info(_('Leaving Shell')) sys.exit(0)
def set_argparser(parser): parser.add_argument('script', nargs='?', metavar=_('SCRIPT'), help=_('Script to run in DNF shell'))