def get(self, *patterns): res = dnf.util.Bunch() res.environments = [] res.groups = [] for pat in patterns: envs = grps = [] if self.kinds & self.ENVIRONMENTS: available = self.comps.environments_by_pattern(pat) installed = self.prst.environments_by_pattern(pat) envs = self._get(available, installed) res.environments.extend(envs) if self.kinds & self.GROUPS: available = self.comps.groups_by_pattern(pat) installed = self.prst.groups_by_pattern(pat) grps = self._get(available, installed) res.groups.extend(grps) if not envs and not grps: if self.status == self.INSTALLED: msg = _("Group '%s' is not installed.") % ucd(pat) else: msg = _("Group '%s' does not exist.") % ucd(pat) raise CompsError(msg) return res
def _hcmd_redo(self, extcmds): old = self.base.history_get_transaction(extcmds) if old is None: return 1, ['Failed history redo'] tm = dnf.util.normalize_time(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) # FIXME this is wrong. Will be fixed in new swdb design. # Reason of a package installed in the original transaction is lost in the # operation above and replaced by reason USER (in the operation below). # (dependencies are promoted to user installed packages) try: self.base.transaction = converter.convert(operations, SwdbReason.USER) except dnf.exceptions.PackagesNotInstalledError as err: logger.info(_('No package %s installed.'), self.output.term.bold(ucd(err.pkg_spec))) return 1, ['An operation cannot be redone'] except dnf.exceptions.PackagesNotAvailableError as err: logger.info(_('No package %s available.'), self.output.term.bold(ucd(err.pkg_spec))) return 1, ['An operation cannot be redone'] else: return 2, ['Repeating transaction %u' % (old.tid,)]
def _hcmd_redo(self, extcmds): old = self.base.history_get_transaction(extcmds) 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 history_undo_transaction(self, extcmd): """Undo given transaction.""" old = self.history_get_transaction((extcmd,)) if old is None: return 1, ['Failed history undo'] tm = dnf.util.normalize_time(old.beg_timestamp) msg = _("Undoing transaction {}, from {}").format(old.tid, ucd(tm)) logger.info(msg) self.output.historyInfoCmdPkgsAltered(old) # :todo history = dnf.history.open_history(self.history) # :todo try: self._history_undo_operations( history.transaction_nevra_ops(old.tid), old.tid) except dnf.exceptions.PackagesNotInstalledError as err: logger.info(_('No package %s installed.'), self.output.term.bold(ucd(err.pkg_spec))) return 1, ['An operation cannot be undone'] except dnf.exceptions.PackagesNotAvailableError as err: logger.info(_('No package %s available.'), self.output.term.bold(ucd(err.pkg_spec))) return 1, ['An operation cannot be undone'] except dnf.exceptions.MarkingError: assert False else: return 2, ["Undoing transaction %u" % (old.tid,)]
def _mark_install(self, patterns): prst = self.base.history.group 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([ucd(prst.environment(g).ui_name) for g in res.environments])) if res.groups: logger.info(_('Groups marked installed: %s'), ','.join([ucd(prst.group(g).ui_name) for g in res.groups])) prst.commit()
def _resolve_specs_enable_update_sack(self, module_specs): no_match_specs = [] error_spec = [] module_dicts = {} for spec in module_specs: module_list, nsvcap = self._get_modules(spec) if not module_list: no_match_specs.append(spec) continue try: module_dict = self._create_module_dict_and_enable(module_list, True) module_dicts[spec] = (nsvcap, module_dict) except (RuntimeError, EnableMultipleStreamsException) as e: error_spec.append(spec) logger.error(ucd(e)) logger.error(_("Unable to resolve argument {}").format(spec)) hot_fix_repos = [i.id for i in self.base.repos.iter_enabled() if i.module_hotfixes] try: solver_errors = self.base.sack.filter_modules( self.base._moduleContainer, hot_fix_repos, self.base.conf.installroot, self.base.conf.module_platform_id, self.base.conf.debug_solver) except hawkey.Exception as e: raise dnf.exceptions.Error(ucd(e)) for spec, (nsvcap, moduleDict) in module_dicts.items(): for streamDict in moduleDict.values(): for modules in streamDict.values(): try: self.base._moduleContainer.enableDependencyTree( libdnf.module.VectorModulePackagePtr(modules)) except RuntimeError as e: error_spec.append(spec) logger.error(ucd(e)) logger.error(_("Unable to resolve argument {}").format(spec)) return no_match_specs, error_spec, solver_errors, module_dicts
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 _configure_from_options(self, opts): """Configure parts of CLI from the opts """ config_args = ['plugins', 'version', 'config_file_path', 'debuglevel', 'errorlevel', 'installroot', 'best', 'assumeyes', 'assumeno', 'clean_requirements_on_remove', 'gpgcheck', 'showdupesfromrepos', 'plugins', 'ip_resolve', 'rpmverbosity', 'disable_excludes', 'color', 'downloadonly', 'exclude', 'excludepkgs', 'skip_broken', 'tsflags', 'arch', 'basearch', 'ignorearch', 'cacheonly', 'comment'] for name in config_args: value = getattr(opts, name, None) if value is not None and value != []: confopt = self._get_option(name) if confopt: confopt._set(value, dnf.conf.PRIO_COMMANDLINE) elif hasattr(self, name): setattr(self, name, value) else: logger.warning(_('Unknown configuration option: %s = %s'), ucd(name), ucd(value)) if hasattr(opts, 'main_setopts'): # now set all the non-first-start opts from main from our setopts # pylint: disable=W0212 for name, val in opts.main_setopts._get_kwargs(): opt = self._get_option(name) if opt: opt._set(val, dnf.conf.PRIO_COMMANDLINE) elif hasattr(self, name): setattr(self, name, val) else: msg = "Main config did not have a %s attr. before setopt" logger.warning(msg, name)
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 dump_rpm_problems(self): self.write("%%%%RPMDB PROBLEMS\n") (missing, conflicts) = rpm_problems(self.base) self.write("".join(["Package %s requires %s\n" % (ucd(pkg), ucd(req)) for (req, pkg) in missing])) self.write("".join(["Package %s conflicts with %s\n" % (ucd(pkg), ucd(conf)) for (conf, pkg) in conflicts]))
def history_rollback_transaction(self, extcmd): """Rollback given transaction.""" old = self.history_get_transaction((extcmd, )) if old is None: return 1, ['Failed history rollback, no transaction'] last = self.history.last() if last is None: return 1, ['Failed history rollback, no last?'] if old.tid == last.tid: return 0, ['Rollback to current, nothing to do'] mobj = None for tid in self.history.old(list(range(old.tid + 1, last.tid + 1))): if tid.altered_lt_rpmdb: logger.warning( _('Transaction history is incomplete, before %u.'), tid.tid) elif tid.altered_gt_rpmdb: logger.warning( _('Transaction history is incomplete, after %u.'), tid.tid) if mobj is None: mobj = dnf.yum.history.YumMergedHistoryTransaction(tid) else: mobj.merge(tid) tm = time.ctime(old.beg_timestamp) print("Rollback to transaction %u, from %s" % (old.tid, tm)) print(self.output.fmtKeyValFill( " Undoing the following transactions: ", ", ".join( (str(x) for x in mobj.tid)))) self.output.historyInfoCmdPkgsAltered(mobj) # :todo history = dnf.history.open_history(self.history) # :todo operations = dnf.history.NEVRAOperations() for id_ in range(old.tid + 1, last.tid + 1): operations += history.transaction_nevra_ops(id_) hibeg = self.output.term.MODE['bold'] hiend = self.output.term.MODE['normal'] try: self.history_undo_operations(operations) except dnf.exceptions.PackagesNotInstalledError as err: logger.info( _('No package %s%s%s installed.'), hibeg, ucd(err.pkg_spec), hiend) return 1, ['A transaction 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, ['A transaction cannot be undone'] except dnf.exceptions.MarkingError: assert False else: return 2, ["Rollback to transaction %u" % (old.tid, )]
def exclude_pkgs(self, pkgs): # :api name = "excludepkgs" if pkgs is not None and pkgs != []: if self._has_option(name): self._set_value(name, pkgs, dnf.conf.PRIO_COMMANDLINE) else: logger.warning(_('Unknown configuration option: %s = %s'), ucd(name), ucd(pkgs))
def history_rollback_transaction(self, extcmd): """Rollback given transaction.""" old = self.history_get_transaction((extcmd,)) if old is None: return 1, ['Failed history rollback, no transaction'] last = self.history.last() if last is None: return 1, ['Failed history rollback, no last?'] if old.tid == last.tid: return 0, ['Rollback to current, nothing to do'] mobj = None for trans in self.history.old(list(range(old.tid + 1, last.tid + 1))): if trans.altered_lt_rpmdb: logger.warning(_('Transaction history is incomplete, before %u.'), trans.tid) elif trans.altered_gt_rpmdb: logger.warning(_('Transaction history is incomplete, after %u.'), trans.tid) if mobj is None: mobj = dnf.db.history.MergedTransactionWrapper(trans) else: mobj.merge(trans) tm = dnf.util.normalize_time(old.beg_timestamp) print("Rollback to transaction %u, from %s" % (old.tid, tm)) print(self.output.fmtKeyValFill(" Undoing the following transactions: ", ", ".join((str(x) for x in mobj.tids())))) self.output.historyInfoCmdPkgsAltered(mobj) # :todo # history = dnf.history.open_history(self.history) # :todo # m = libdnf.transaction.MergedTransaction() # return # operations = dnf.history.NEVRAOperations() # for id_ in range(old.tid + 1, last.tid + 1): # operations += history.transaction_nevra_ops(id_) try: self._history_undo_operations(mobj, old.tid + 1, True, strict=self.conf.strict) except dnf.exceptions.PackagesNotInstalledError as err: raise logger.info(_('No package %s installed.'), self.output.term.bold(ucd(err.pkg_spec))) return 1, ['A transaction cannot be undone'] except dnf.exceptions.PackagesNotAvailableError as err: raise logger.info(_('No package %s available.'), self.output.term.bold(ucd(err.pkg_spec))) return 1, ['A transaction cannot be undone'] except dnf.exceptions.MarkingError: raise assert False else: return 2, ["Rollback to transaction %u" % (old.tid,)]
def exclude_pkgs(self, pkgs): # :api name = "excludepkgs" if pkgs is not None and pkgs != []: confopt = self._get_option(name) if confopt: confopt._set(pkgs, dnf.conf.PRIO_COMMANDLINE) else: logger.warning(_('Unknown configuration option: %s = %s'), ucd(name), ucd(pkgs))
def _populate(self, parser, section, priority=PRIO_DEFAULT): """Set option values from an INI file section.""" if parser.has_section(section): for name in parser.options(section): value = parser.get(section, name) opt = self._get_option(name) if opt and not opt._is_runtimeonly(): opt._set(value, priority) else: logger.warning(_('Unknown configuration option: %s = %s'), ucd(name), ucd(value))
def _hcmd_redo(self, extcmds): old = self.base.history_get_transaction(extcmds) if old is None: return 1, ['Failed history redo'] tm = dnf.util.normalize_time(old.beg_timestamp) print('Repeating transaction %u, from %s' % (old.tid, tm)) self.output.historyInfoCmdPkgsAltered(old) for i in old.packages(): pkgs = list(self.base.sack.query().filter(nevra=str(i), reponame=i.from_repo)) if i.action in dnf.transaction.FORWARD_ACTIONS: if not pkgs: logger.info(_('No package %s available.'), self.output.term.bold(ucd(str(i)))) return 1, ['An operation cannot be redone'] pkg = pkgs[0] self.base.install(str(pkg)) elif i.action == libdnf.transaction.TransactionItemAction_REMOVE: if not pkgs: # package was removed already, we can skip removing it again continue pkg = pkgs[0] self.base.remove(str(pkg)) self.base.resolve() self.base.do_transaction()
def callback(self, what, amount, total, key, client_data): if isinstance(key, str): key = ucd(key) if what == rpm.RPMCALLBACK_TRANS_START: self._transStart(total) elif what == rpm.RPMCALLBACK_TRANS_STOP: self._transStop() elif what == rpm.RPMCALLBACK_ELEM_PROGRESS: # This callback type is issued every time the next transaction # element is about to be processed by RPM, before any other # callbacks are issued. "amount" carries the index of the element. self._elemProgress(amount) elif what == rpm.RPMCALLBACK_INST_OPEN_FILE: return self._instOpenFile(key) elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE: self._instCloseFile(key) elif what == rpm.RPMCALLBACK_INST_PROGRESS: self._instProgress(amount, total, key) elif what == rpm.RPMCALLBACK_UNINST_STOP: self._unInstStop(key) elif what == rpm.RPMCALLBACK_CPIO_ERROR: self._cpioError(key) elif what == rpm.RPMCALLBACK_UNPACK_ERROR: self._unpackError(key) elif what == rpm.RPMCALLBACK_SCRIPT_ERROR: self._scriptError(amount, total, key) elif what == rpm.RPMCALLBACK_SCRIPT_STOP: self._scriptStop()
def _group_install(self, group_id, pkg_types, exclude, strict=True): group = self.comps._group_by_id(group_id) if not group: raise ValueError(_("Group_id '%s' does not exist.") % ucd(group_id)) p_grp = self.persistor.group(group_id) if p_grp.installed: raise CompsError(_("Group '%s' is already installed.") % group.ui_name) exclude = set() if exclude is None else set(exclude) p_grp.name = group.name p_grp.ui_name = group.ui_name p_grp.pkg_exclude.extend(exclude) p_grp.pkg_types = pkg_types p_grp.full_list.extend(self._full_package_set(group)) trans = TransactionBunch() types = pkg_types & MANDATORY mandatory = self._pkgs_of_type(group, types, exclude) types = pkg_types & (DEFAULT | OPTIONAL) trans.install_opt = self._pkgs_of_type(group, types, exclude) if strict: trans.install = mandatory else: trans.install_opt.update(mandatory) return trans
def _group_install(self, group_id, pkg_types, exclude, strict=True): if isinstance(group_id, SwdbGroup): group_id = group_id.name_id group = self.comps._group_by_id(group_id) if not group: raise ValueError(_("Group_id '%s' does not exist.") % ucd(group_id)) # this will return DnfSwdbGroup object p_grp = self.persistor.group(group_id) if p_grp and p_grp.installed: logger.warning(_("Group '%s' is already installed.") % group.ui_name) else: p_grp = self.persistor.new_group(group_id, group.name, group.ui_name, 0, pkg_types) self.persistor.add_group(p_grp) self.persistor.install_group(p_grp) exclude = list() if exclude is None else list(exclude) p_grp.add_exclude(exclude) p_grp.add_package(list(self._full_package_set(group))) trans = TransactionBunch() trans.install.update(self._pkgs_of_type(group, pkg_types, exclude)) return trans
def sack(self): ''' Generate cache of available packages ''' # We generate this cache only if the repos were just freshed or if the # cache file doesn't exist fresh = False for repo in self.base.repos.iter_enabled(): if repo.metadata is not None and repo.metadata.fresh: # One fresh repo is enough to cause a regen of the cache fresh = True break if not os.path.exists(self.cache_file) or fresh: try: with sqlite3.connect(self.cache_file) as conn: self._out('Generating completion cache...') cur = conn.cursor() cur.execute( "create table if not exists available (pkg TEXT)") cur.execute( "create unique index if not exists " "pkg_available ON available(pkg)") cur.execute("delete from available") avail_pkgs = self.base.sack.query().available() avail_pkgs_insert = [["{}.{}".format(x.name, x.arch)] for x in avail_pkgs if x.arch != "src"] cur.executemany("insert or ignore into available values (?)", avail_pkgs_insert) conn.commit() except sqlite3.OperationalError as e: self._out("Can't write completion cache: %s" % ucd(e))
def callback( self, what, bytes, total, h, user ): if isinstance(h, str): h = ucd(h) if what == rpm.RPMCALLBACK_TRANS_START: self._transStart( bytes, total, h ) elif what == rpm.RPMCALLBACK_TRANS_PROGRESS: self._transProgress( bytes, total, h ) elif what == rpm.RPMCALLBACK_TRANS_STOP: self._transStop( bytes, total, h ) elif what == rpm.RPMCALLBACK_INST_OPEN_FILE: return self._instOpenFile( bytes, total, h ) elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE: self._instCloseFile( bytes, total, h ) elif what == rpm.RPMCALLBACK_INST_PROGRESS: self._instProgress( bytes, total, h ) elif what == rpm.RPMCALLBACK_UNINST_START: self._unInstStart( bytes, total, h ) elif what == rpm.RPMCALLBACK_UNINST_PROGRESS: self._unInstProgress( bytes, total, h ) elif what == rpm.RPMCALLBACK_UNINST_STOP: self._unInstStop( bytes, total, h ) elif what == rpm.RPMCALLBACK_CPIO_ERROR: self._cpioError(bytes, total, h) elif what == rpm.RPMCALLBACK_UNPACK_ERROR: self._unpackError(bytes, total, h) elif what == rpm.RPMCALLBACK_SCRIPT_ERROR: self._scriptError(bytes, total, h) elif what == rpm.RPMCALLBACK_SCRIPT_START: self._scriptStart(bytes, total, h) elif what == rpm.RPMCALLBACK_SCRIPT_STOP: self._scriptStop(bytes, total, h);
def _modules_reset_or_disable(self, module_specs, to_state): no_match_specs = [] for spec in module_specs: module_list, nsvcap = self._get_modules(spec) if not module_list: logger.error(_("Unable to resolve argument {}").format(spec)) no_match_specs.append(spec) continue if nsvcap.stream or nsvcap.version or nsvcap.context or nsvcap.arch or nsvcap.profile: logger.info(_("Only module name is required. " "Ignoring unneeded information in argument: '{}'").format(spec)) module_names = set() for module in module_list: module_names.add(module.getName()) for name in module_names: if to_state == STATE_UNKNOWN: self.base._moduleContainer.reset(name) if to_state == STATE_DISABLED: self.base._moduleContainer.disable(name) hot_fix_repos = [i.id for i in self.base.repos.iter_enabled() if i.module_hotfixes] try: solver_errors = self.base.sack.filter_modules( self.base._moduleContainer, hot_fix_repos, self.base.conf.installroot, self.base.conf.module_platform_id, update_only=True, debugsolver=self.base.conf.debug_solver) except hawkey.Exception as e: raise dnf.exceptions.Error(ucd(e)) return no_match_specs, solver_errors
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 read_dump_file(filename): if filename.endswith(".gz"): fobj = gzip.GzipFile(filename) else: fobj = open(filename) if ucd(fobj.readline()) != DEBUG_VERSION: dnfpluginsextras.logger.error(_("Bad dnf debug file: %s"), filename) raise dnf.exceptions.Error skip = True pkgs = {} for line in fobj: line = ucd(line) if skip: if line == "%%%%RPMDB\n": skip = False continue if not line or line[0] != " ": break pkg_spec = line.strip() nevra = hawkey.split_nevra(pkg_spec) pkgs[(nevra.name, nevra.arch)] = ["install", ucd(nevra.name), ucd(nevra.arch), ucd(nevra.epoch), ucd(nevra.version), ucd(nevra.release)] return pkgs
def test_dump(self): dump = self.repo.dump() f = io.StringIO(ucd(dump)) parser = iniparse.compat.ConfigParser() parser.readfp(f) self.assertIn('r', parser.sections()) opts = parser.options('r') self.assertIn('bandwidth', opts) self.assertIn('gpgkey', opts)
def transaction(self): ''' Generate cache of installed packages ''' try: with open(self.installed_cache_file, 'w') as cache_file: installed_packages = self.base.sack.query().installed() self._out('Generating completion cache...') for package in installed_packages: cache_file.write(package.name + '\n') except Exception as e: self._out("Can't write completion cache: %s" % ucd(e))
def install_or_skip(install_fnc, grp_or_env, types, exclude=None): """Either mark in persistor as installed given `grp_or_env` (group or environment) or skip it (if it's already installed). `install_fnc` has to be Solver.group_install or Solver.environment_install. """ try: return install_fnc(grp_or_env, types, exclude) except dnf.comps.CompsError as e: logger.warning("%s, %s", ucd(e)[:-1], _("skipping."))
def _mark_remove(self, patterns): prst = self.base.history.group q = CompsQuery(self.base.comps, prst, CompsQuery.GROUPS | CompsQuery.ENVIRONMENTS, CompsQuery.INSTALLED) solver = self.base._build_comps_solver() res = q.get(*patterns) for env_id in res.environments: solver._environment_remove(env_id) for grp_id in res.groups: solver._group_remove(grp_id) if res.environments: logger.info(_('Environments marked removed: %s'), ','.join([ucd(prst.environment(e_id).ui_name) for e_id in res.environments])) if res.groups: logger.info(_('Groups marked removed: %s'), ','.join([ucd(prst.group(g_id).ui_name) for g_id in res.groups])) prst.commit()
def __getattr__(self, name): if "_config" not in self.__dict__: raise AttributeError("'{}' object has no attribute '{}'".format(self.__class__, name)) option = getattr(self._config, name) if option is None: return None try: value = option().getValue() except Exception as ex: return None if isinstance(value, str): return ucd(value) return value
def transaction(self): main, crepo = self.main, self.crepo if not main["enabled"]: return repodir = main["repodir"] if not os.path.exists(repodir): try: os.makedirs(repodir, mode=0o755) except OSError as e: self.logger.error("local: " + _( "Unable to create a directory '{}' due to '{}'").format(repodir, ucd(e))) return elif not os.path.isdir(repodir): self.logger.error( "local: " + _("'{}' is not a directory").format(repodir)) return needs_rebuild = False for pkg in self.base.transaction.install_set: path = pkg.localPkg() if os.path.dirname(path) == repodir: continue self.logger.debug( "local: " + _("Copying '{}' to local repo").format(path)) try: shutil.copy2(path, repodir) needs_rebuild = True except IOError: self.logger.error( "local: " + _("Can't write file '{}'").format(os.path.join( repodir, os.path.basename(path)))) if not crepo["enabled"] or not needs_rebuild: return args = ["createrepo_c", "--update", "--unique-md-filenames"] if crepo["verbose"]: args.append("--verbose") elif crepo["quiet"]: args.append("--quiet") if crepo["cachedir"] is not None: args.append("--cachedir") args.append(crepo["cachedir"]) args.append(repodir) self.logger.debug("local: " + _("Rebuilding local repo")) p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in p.stdout: print(line.decode().rstrip("\n"))
def _log_errors(self, errors): for error in errors: error = ucd(error) self.swdb.log_error(self._tid, error)
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 """ 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 = 0 if opts.verbose: opts.debuglevel = opts.errorlevel = dnf.const.VERBOSE_LEVEL # Read up configuration options and initialize plugins try: self.base.conf._configure_from_options(opts) self._read_conf_file(opts.releasever) 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) # 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.disableplugins, 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 = dnf.const.PROGRAM_NAME + ' ' 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 if opts.freshest_metadata: self.demands.freshest_metadata = opts.freshest_metadata if opts.debugsolver: self.base.conf.debug_solver = True if opts.cacheonly: self.demands.cacheonly = True # 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.color != 'auto': self.base.output.term.reinit(color=self.base.conf.color)
def __init__(self, section='main', parser=None): # pylint: disable=R0915 super(MainConf, self).__init__(section, parser) self.substitutions = dnf.conf.substitutions.Substitutions() # setup different cache and log for non-priviledged users if dnf.util.am_i_root(): cachedir = dnf.const.SYSTEM_CACHEDIR logdir = '/var/log' else: try: cachedir = logdir = misc.getCacheDir() except (IOError, OSError) as e: logger.critical(_('Could not set cachedir: %s'), ucd(e)) self._add_option('debuglevel', IntOption(2, range_min=0, range_max=10)) # :api self._add_option('errorlevel', IntOption(2, range_min=0, range_max=10)) self._add_option('installroot', PathOption('/', abspath=True)) # :api self._add_option('config_file_path', PathOption(dnf.const.CONF_FILENAME)) # :api self._add_option('plugins', BoolOption(True)) self._add_option('pluginpath', ListOption([dnf.const.PLUGINPATH])) # :api self._add_option('pluginconfpath', ListOption([dnf.const.PLUGINCONFPATH])) # :api self._add_option('persistdir', PathOption(dnf.const.PERSISTDIR)) # :api self._add_option('recent', IntOption(7, range_min=0)) self._add_option('retries', PositiveIntOption(10, names_of_0=["0"])) self._add_option('reset_nice', BoolOption(True)) self._add_option('cachedir', PathOption(cachedir)) # :api self._add_option('system_cachedir', PathOption(dnf.const.SYSTEM_CACHEDIR)) # :api self._add_option('keepcache', BoolOption(False)) self._add_option('logdir', Option(logdir)) # :api self._add_option('reposdir', ListOption(['/etc/yum.repos.d', '/etc/yum/repos.d', '/etc/distro.repos.d'])) # :api self._add_option('debug_solver', BoolOption(False)) self._add_option('excludepkgs', ListAppendOption()) self._add_option('includepkgs', ListAppendOption()) self._add_option('exclude', self._get_option('excludepkgs')) # ^ compatibility with yum self._add_option('fastestmirror', BoolOption(False)) self._add_option('proxy', UrlOption(schemes=('http', 'ftp', 'https', 'socks5', 'socks5h', 'socks4', 'socks4a'), allow_none=True)) # :api self._add_option('proxy_username', Option()) # :api self._add_option('proxy_password', Option()) # :api self._add_option('protected_packages', ListOption("dnf glob:/etc/yum/protected.d/*.conf " \ "glob:/etc/dnf/protected.d/*.conf")) #:api self._add_option('username', Option()) # :api self._add_option('password', Option()) # :api self._add_option('installonlypkgs', ListAppendOption(dnf.const.INSTALLONLYPKGS)) self._add_option('group_package_types', ListOption(dnf.const.GROUP_PACKAGE_TYPES)) # NOTE: If you set this to 2, then because it keeps the current # kernel it means if you ever install an "old" kernel it'll get rid # of the newest one so you probably want to use 3 as a minimum # ... if you turn it on. self._add_option('installonly_limit', PositiveIntOption(0, range_min=2, names_of_0=["0", "<off>"])) # :api self._add_option('tsflags', ListAppendOption()) # :api self._add_option('assumeyes', BoolOption(False)) # :api self._add_option('assumeno', BoolOption(False)) self._add_option('check_config_file_age', BoolOption(True)) self._add_option('defaultyes', BoolOption(False)) self._add_option('alwaysprompt', BoolOption(True)) self._add_option('diskspacecheck', BoolOption(True)) self._add_option('gpgcheck', BoolOption(False)) self._add_option('repo_gpgcheck', BoolOption(False)) self._add_option('localpkg_gpgcheck', BoolOption(False)) self._add_option('obsoletes', BoolOption(True)) self._add_option('showdupesfromrepos', BoolOption(False)) self._add_option('enabled', BoolOption(True)) self._add_option('enablegroups', BoolOption(True)) self._add_option('exit_on_lock', BoolOption(False)) self._add_option('bandwidth', BytesOption(0)) self._add_option('minrate', BytesOption(1000)) self._add_option('ip_resolve', CaselessSelectionOption(choices=('ipv4', 'ipv6', 'whatever'), mapper={'4': 'ipv4', '6': 'ipv6'})) self._add_option('throttle', ThrottleOption(0)) self._add_option('timeout', SecondsOption(120)) self._add_option('max_parallel_downloads', IntOption(None, range_min=1)) self._add_option('metadata_expire', SecondsOption(60 * 60 * 48)) # 48 hours self._add_option('metadata_timer_sync', SecondsOption(60 * 60 * 3)) # 3 hours self._add_option('disable_excludes', ListOption()) self._add_option('multilib_policy', SelectionOption('best', choices=('best', 'all'))) # :api self._add_option('best', BoolOption(False)) # :api self._add_option('install_weak_deps', BoolOption(True)) self._add_option('bugtracker_url', Option(dnf.const.BUGTRACKER)) self._add_option('color', SelectionOption('auto', choices=('auto', 'never', 'always'), mapper={'on': 'always', 'yes' : 'always', '1' : 'always', 'true': 'always', 'off': 'never', 'no': 'never', '0': 'never', 'false': 'never', 'tty': 'auto', 'if-tty': 'auto'}) ) self._add_option('color_list_installed_older', Option('bold')) self._add_option('color_list_installed_newer', Option('bold,yellow')) self._add_option('color_list_installed_reinstall', Option('normal')) self._add_option('color_list_installed_extra', Option('bold,red')) self._add_option('color_list_available_upgrade', Option('bold,blue')) self._add_option('color_list_available_downgrade', Option('dim,cyan')) self._add_option('color_list_available_reinstall', Option('bold,underline,green')) self._add_option('color_list_available_install', Option('normal')) self._add_option('color_update_installed', Option('normal')) self._add_option('color_update_local', Option('bold')) self._add_option('color_update_remote', Option('normal')) self._add_option('color_search_match', Option('bold')) self._add_option('sslcacert', PathOption()) # :api self._add_option('sslverify', BoolOption(True)) # :api self._add_option('sslclientcert', Option()) # :api self._add_option('sslclientkey', Option()) # :api self._add_option('deltarpm', BoolOption(True)) self._add_option('deltarpm_percentage', PositiveIntOption(75, names_of_0=["0", "<off>"])) self._add_option('history_record', BoolOption(True)) self._add_option('history_record_packages', ListOption(['dnf', 'rpm'])) self._add_option('rpmverbosity', Option('info')) self._add_option('strict', BoolOption(True)) # :api self._add_option('skip_broken', BoolOption(False)) # :yum-compatibility self._add_option('clean_requirements_on_remove', BoolOption(True)) self._add_option('history_list_view', SelectionOption('commands', choices=('single-user-commands', 'users', 'commands'), mapper={'cmds': 'commands', 'default': 'commands'})) self._add_option('upgrade_group_objects_upgrade', BoolOption(True)) # :api # runtime only options self._add_option('downloadonly', BoolOption(False, runtimeonly=True))
def log_scriptlet_output(self, msg): if msg is None or not hasattr(self, '_tid'): return # Not configured to run for error in msg.splitlines(): error = ucd(error) self.swdb.log_output(self._tid, error)
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 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: opt = self.base.conf._get_option("cachedir") opt._set(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 = dnf.const.PROGRAM_NAME + ' ' 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)
def history_rollback_transaction(self, extcmd): """Rollback given transaction.""" old = self.history_get_transaction((extcmd, )) if old is None: return 1, ['Failed history rollback, no transaction'] last = self.history.last() if last is None: return 1, ['Failed history rollback, no last?'] if old.tid == last.tid: return 0, ['Rollback to current, nothing to do'] mobj = None for trans in self.history.old(list(range(old.tid + 1, last.tid + 1))): if trans.altered_lt_rpmdb: logger.warning( _('Transaction history is incomplete, before %u.'), trans.tid) elif trans.altered_gt_rpmdb: logger.warning( _('Transaction history is incomplete, after %u.'), trans.tid) if mobj is None: mobj = dnf.db.history.MergedTransactionWrapper(trans) else: mobj.merge(trans) tm = dnf.util.normalize_time(old.beg_timestamp) print("Rollback to transaction %u, from %s" % (old.tid, tm)) print( self.output.fmtKeyValFill(" Undoing the following transactions: ", ", ".join( (str(x) for x in mobj.tids())))) self.output.historyInfoCmdPkgsAltered(mobj) # :todo # history = dnf.history.open_history(self.history) # :todo # m = libdnf.transaction.MergedTransaction() # return # operations = dnf.history.NEVRAOperations() # for id_ in range(old.tid + 1, last.tid + 1): # operations += history.transaction_nevra_ops(id_) try: self._history_undo_operations(mobj, old.tid + 1, True, strict=self.conf.strict) except dnf.exceptions.PackagesNotInstalledError as err: raise logger.info(_('No package %s installed.'), self.output.term.bold(ucd(err.pkg_spec))) return 1, ['A transaction cannot be undone'] except dnf.exceptions.PackagesNotAvailableError as err: raise logger.info(_('No package %s available.'), self.output.term.bold(ucd(err.pkg_spec))) return 1, ['A transaction cannot be undone'] except dnf.exceptions.MarkingError: raise assert False else: return 2, ["Rollback to transaction %u" % (old.tid, )]
def _configure_from_options(self, opts): """Configure parts of CLI from the opts """ config_args = [ 'plugins', 'version', 'config_file_path', 'debuglevel', 'errorlevel', 'installroot', 'best', 'assumeyes', 'assumeno', 'clean_requirements_on_remove', 'gpgcheck', 'showdupesfromrepos', 'plugins', 'ip_resolve', 'rpmverbosity', 'disable_excludes', 'color', 'downloadonly', 'exclude', 'excludepkgs', 'skip_broken', 'tsflags', 'arch', 'basearch', 'ignorearch', 'cacheonly', 'comment' ] for name in config_args: value = getattr(opts, name, None) if value is not None and value != []: opt = self._get_option(name) if opt is not None: appendValue = False if self._config: try: appendValue = self._config.optBinds().at( name).getAddValue() except RuntimeError: # fails if option with "name" does not exist in _config (libdnf) pass if appendValue: add_priority = dnf.conf.PRIO_COMMANDLINE if add_priority < opt._get_priority(): add_priority = opt._get_priority() for item in value: if item: opt._set(opt._get() + [item], add_priority) else: opt._set([], dnf.conf.PRIO_COMMANDLINE) else: opt._set(value, dnf.conf.PRIO_COMMANDLINE) elif hasattr(self, name): setattr(self, name, value) else: logger.warning(_('Unknown configuration option: %s = %s'), ucd(name), ucd(value)) if getattr(opts, 'gpgcheck', None) is False: opt = self._get_option("localpkg_gpgcheck") opt._set(False, dnf.conf.PRIO_COMMANDLINE) if hasattr(opts, 'main_setopts'): # now set all the non-first-start opts from main from our setopts # pylint: disable=W0212 for name, values in opts.main_setopts.items(): for val in values: if hasattr(self._config, name): try: # values in main_setopts are strings, try to parse it using newString() self._config.optBinds().at(name).newString( PRIO_COMMANDLINE, val) except RuntimeError as e: raise dnf.exceptions.ConfigError(_( "Error parsing --setopt with key '%s', value '%s': %s" ) % (name, val, str(e)), raw_error=str(e)) else: # if config option with "name" doesn't exist in _config, it could be defined # only in Python layer if hasattr(self, name): setattr(self, name, val) else: msg = _( "Main config did not have a %s attr. before setopt" ) logger.warning(msg, name)
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()
def _per_nevra_dict(pkg_list): return {ucd(pkg): pkg for pkg in pkg_list}
def __unicode__(self): return ucd(self.__str__())
def __init__(self, value=None, raw_error=None): super(ConfigError, self).__init__(value) self.raw_error = ucd(raw_error) if raw_error is not None else None
def __init__(self, value=None): super(Error, self).__init__() self.value = None if value is None else ucd(value)
def six_digits(num): return ucd(dnf.pycomp.format("%6d", num, True))
def messages(self): messages = self._scriptOutput() if messages: for line in messages.splitlines(): yield ucd(line)
def __init__(self, value=None, pkg_spec=None): """Initialize the marking error instance.""" super(MarkingError, self).__init__(value) self.pkg_spec = None if pkg_spec is None else ucd(pkg_spec)
def _num2ui_num(num): return ucd(dnf.pycomp.format("%d", num, True))
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
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 _print_match_section(text, keys): # Print them in the order they were passed used_keys = [arg for arg in args if arg in keys] formatted = self.base.output.fmtSection(text % ", ".join(used_keys)) print(ucd(formatted))
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 """ 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( _("DNF will only download packages for the transaction.")) elif 'test' in self.conf.tsflags: logger.info( _("DNF will only download packages, install gpg keys, and check the " "transaction.")) 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: msg = self.output.post_transaction_output(trans) logger.info(msg) for tsi in trans: if tsi.state == libdnf.transaction.TransactionItemState_ERROR: raise dnf.exceptions.Error(_('Transaction failed')) return tid
def run(self): arg = self.opts.repos_action extcmds = [x.lower() for x in self.opts.repos] verbose = self.base.conf.verbose repos = list(self.base.repos.values()) repos.sort(key=operator.attrgetter('id')) term = self.output.term on_ehibeg = term.FG_COLOR['green'] + term.MODE['bold'] on_dhibeg = term.FG_COLOR['red'] on_hiend = term.MODE['normal'] tot_num = 0 cols = [] if not repos: logger.warning(_('No repositories available')) return include_status = arg == 'all' or (arg == 'enabled-default' and extcmds) repoinfo_output = [] for repo in repos: if len(extcmds) and not _repo_match(repo, extcmds): continue (ehibeg, dhibeg, hiend) = '', '', '' ui_enabled = '' ui_endis_wid = 0 ui_excludes_num = '' if include_status: (ehibeg, dhibeg, hiend) = (on_ehibeg, on_dhibeg, on_hiend) if repo.enabled: enabled = True if arg == 'disabled': continue if include_status or verbose or self.opts.command == 'repoinfo': ui_enabled = ehibeg + _('enabled') + hiend ui_endis_wid = exact_width(_('enabled')) if verbose or self.opts.command == 'repoinfo': ui_size = _repo_size(self.base.sack, repo) else: enabled = False if arg == 'enabled' or (arg == 'enabled-default' and not extcmds): continue ui_enabled = dhibeg + _('disabled') + hiend ui_endis_wid = exact_width(_('disabled')) if not (verbose or self.opts.command == 'repoinfo'): rid = ucd(repo.id) cols.append((rid, repo.name, (ui_enabled, ui_endis_wid))) else: if enabled: md = repo.metadata else: md = None out = [ self.output.fmtKeyValFill(_("Repo-id : "), repo.id), self.output.fmtKeyValFill(_("Repo-name : "), repo.name) ] if include_status: out += [ self.output.fmtKeyValFill(_("Repo-status : "), ui_enabled) ] if md and repo._repo.getRevision(): out += [ self.output.fmtKeyValFill(_("Repo-revision : "), repo._repo.getRevision()) ] if md and repo._repo.getContentTags(): tags = repo._repo.getContentTags() out += [ self.output.fmtKeyValFill(_("Repo-tags : "), ", ".join(sorted(tags))) ] if md and repo._repo.getDistroTags(): distroTagsDict = { k: v for (k, v) in repo._repo.getDistroTags() } for (distro, tags) in distroTagsDict.items(): out += [ self.output.fmtKeyValFill( _("Repo-distro-tags : "), "[%s]: %s" % (distro, ", ".join(sorted(tags)))) ] if md: num = len( self.base.sack.query( flags=hawkey.IGNORE_EXCLUDES).filterm( reponame__eq=repo.id)) num_available = len( self.base.sack.query().filterm(reponame__eq=repo.id)) ui_num = _num2ui_num(num) ui_num_available = _num2ui_num(num_available) tot_num += num out += [ self.output.fmtKeyValFill( _("Repo-updated : "), dnf.util.normalize_time( repo._repo.getMaxTimestamp())), self.output.fmtKeyValFill(_("Repo-pkgs : "), ui_num), self.output.fmtKeyValFill(_("Repo-available-pkgs: "), ui_num_available), self.output.fmtKeyValFill(_("Repo-size : "), ui_size) ] if repo.metalink: out += [ self.output.fmtKeyValFill(_("Repo-metalink : "), repo.metalink) ] if enabled: ts = repo._repo.getTimestamp() out += [ self.output.fmtKeyValFill( _(" Updated : "), dnf.util.normalize_time(ts)) ] elif repo.mirrorlist: out += [ self.output.fmtKeyValFill(_("Repo-mirrors : "), repo.mirrorlist) ] baseurls = repo.baseurl if baseurls: out += [ self.output.fmtKeyValFill(_("Repo-baseurl : "), ", ".join(baseurls)) ] elif enabled: mirrors = repo._repo.getMirrors() if mirrors: url = "%s (%d more)" % (mirrors[0], len(mirrors) - 1) out += [ self.output.fmtKeyValFill( _("Repo-baseurl : "), url) ] expire = _expire_str(repo, md) out += [ self.output.fmtKeyValFill(_("Repo-expire : "), expire) ] if repo.excludepkgs: # TRANSLATORS: Packages that are excluded - their names like (dnf systemd) out += [ self.output.fmtKeyValFill(_("Repo-exclude : "), ", ".join(repo.excludepkgs)) ] if repo.includepkgs: out += [ self.output.fmtKeyValFill(_("Repo-include : "), ", ".join(repo.includepkgs)) ] if ui_excludes_num: # TRANSLATORS: Number of packages that where excluded (5) out += [ self.output.fmtKeyValFill(_("Repo-excluded : "), ui_excludes_num) ] if repo.repofile: out += [ self.output.fmtKeyValFill(_("Repo-filename : "), repo.repofile) ] repoinfo_output.append("\n".join(map(ucd, out))) if repoinfo_output: print("\n\n".join(repoinfo_output)) if not verbose and cols: # Work out the first (id) and last (enabled/disabled/count), # then chop the middle (name)... id_len = exact_width(_('repo id')) nm_len = 0 st_len = 0 for (rid, rname, (ui_enabled, ui_endis_wid)) in cols: if id_len < exact_width(rid): id_len = exact_width(rid) if nm_len < exact_width(rname): nm_len = exact_width(rname) if st_len < ui_endis_wid: st_len = ui_endis_wid # Need this as well as above for: fill_exact_width() if include_status: if exact_width(_('status')) > st_len: left = term.columns - (id_len + len(_('status')) + 2) else: left = term.columns - (id_len + st_len + 2) else: # Don't output a status column. left = term.columns - (id_len + 1) if left < nm_len: # Name gets chopped nm_len = left else: # Share the extra... left -= nm_len id_len += left // 2 nm_len += left - (left // 2) txt_rid = fill_exact_width(_('repo id'), id_len) if include_status: txt_rnam = fill_exact_width(_('repo name'), nm_len, nm_len) else: txt_rnam = _('repo name') if not include_status: # Don't output a status column. print("%s %s" % (txt_rid, txt_rnam)) else: print("%s %s %s" % (txt_rid, txt_rnam, _('status'))) for (rid, rname, (ui_enabled, ui_endis_wid)) in cols: if not include_status: # Don't output a status column. print("%s %s" % (fill_exact_width(rid, id_len), rname)) continue print("%s %s %s" % (fill_exact_width(rid, id_len), fill_exact_width(rname, nm_len, nm_len), ui_enabled)) if verbose or self.opts.command == 'repoinfo': msg = _('Total packages: {}') print(msg.format(_num2ui_num(tot_num)))
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: a numeric return code, and optionally a list of errors. A negative return code indicates that errors occurred in the pre-transaction checks """ # Reports about excludes and includes (but not from plugins) if self.conf.excludepkgs: logger.debug('Excludes in dnf.conf: ' + ", ".join(sorted(set(self.conf.excludepkgs)))) if self.conf.includepkgs: logger.debug('Includes in dnf.conf: ' + ", ".join(sorted(set(self.conf.includepkgs)))) for repo in self.repos.iter_enabled(): if repo.excludepkgs: logger.debug('Excludes in repo ' + repo.id + ": " + ", ".join(sorted(set(repo.excludepkgs)))) if repo.includepkgs: logger.debug('Includes in repo ' + repo.id + ": " + ", ".join(sorted(set(repo.includepkgs)))) 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: installed = tsi.installed if installed is not None: install_pkgs.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 install_pkgs: self.output.reportRemoveSize(rmpkgs) else: self.output.reportDownloadSize(install_pkgs, install_only) if trans: # confirm with user if self.conf.downloadonly: logger.info( _("DNF will only download packages for the transaction.")) elif 'test' in self.conf.tsflags: logger.info( _("DNF will only download packages, install gpg keys, and check the " "transaction.")) 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, 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) for tsi in trans: if tsi.op_type == dnf.transaction.FAIL: raise dnf.exceptions.Error(_('Transaction failed'))
def run(self, extcmds): try: subcommand = extcmds[0] except (ValueError, IndexError): dnf.cli.commands.err_mini_usage(self.cli, self.cli.base.basecmd) return 0 if subcommand == "help": dnf.cli.commands.err_mini_usage(self.cli, self.cli.base.basecmd) return 0 try: project_name = extcmds[1] except (ValueError, IndexError): logger.critical( _('Error: ') + _('exactly two additional parameters to ' 'copr command are required')) dnf.cli.commands.err_mini_usage(self.cli, self.cli.base.basecmd) raise dnf.cli.CliError( _('exactly two additional parameters to ' 'copr command are required')) try: chroot = extcmds[2] except IndexError: chroot = self._guess_chroot() repo_filename = "/etc/yum.repos.d/_copr_{}.repo" \ .format(project_name.replace("/", "-")) if subcommand == "enable": self._need_root() self._ask_user(""" You are about to enable a Copr repository. Please note that this repository is not part of the main Fedora distribution, and quality may vary. The Fedora Project does not exercise any power over the contents of this repository beyond the rules outlined in the Copr FAQ at <https://fedorahosted.org/copr/wiki/UserDocs#WhatIcanbuildinCopr>, and packages are not held to any quality or security level. Please do not file bug reports about these packages in Fedora Bugzilla. In case of problems, contact the owner of this repository. Do you want to continue? [y/N]: """) self._download_repo(project_name, repo_filename, chroot) logger.info(_("Repository successfully enabled.")) elif subcommand == "disable": self._need_root() self._remove_repo(repo_filename) logger.info(_("Repository successfully disabled.")) elif subcommand == "list": #http://copr.fedoraproject.org/api/coprs/ignatenkobrain/ api_path = "/api/coprs/{}/".format(project_name) res = dnfpluginscore.lib.urlopen(self, None, self.copr_url + api_path, 'w+') try: json_parse = json.loads(res.read()) except ValueError: raise dnf.exceptions.Error( _("Can't parse repositories for username '{}'.").format( project_name)) self._check_json_output(json_parse) section_text = _("List of {} coprs").format(project_name) self._print_match_section(section_text) i = 0 while i < len(json_parse["repos"]): msg = "{0}/{1} : ".format(project_name, json_parse["repos"][i]["name"]) desc = json_parse["repos"][i]["description"] if not desc: desc = _("No description given") msg = self.base.output.fmtKeyValFill(ucd(msg), desc) print(msg) i += 1 elif subcommand == "search": #http://copr.fedoraproject.org/api/coprs/search/tests/ api_path = "/api/coprs/search/{}/".format(project_name) res = dnfpluginscore.lib.urlopen(self, None, self.copr_url + api_path, 'w+') try: json_parse = json.loads(res.read()) except ValueError: raise dnf.exceptions.Error( _("Can't parse search for '{}'.").format(project_name)) self._check_json_output(json_parse) section_text = _("Matched: {}").format(project_name) self._print_match_section(section_text) i = 0 while i < len(json_parse["repos"]): msg = "{0}/{1} : ".format(json_parse["repos"][i]["username"], json_parse["repos"][i]["coprname"]) desc = json_parse["repos"][i]["description"] if not desc: desc = _("No description given.") msg = self.base.output.fmtKeyValFill(ucd(msg), desc) print(msg) i += 1 else: raise dnf.exceptions.Error( _('Unknown subcommand {}.').format(subcommand))
def ex_IOError(e): logger.log(dnf.logging.SUBDEBUG, '', exc_info=True) logger.critical(ucd(e)) return 1
def _file_timestamp(self, what): try: return dnf.util.file_timestamp(self._repo_dct[what]) except OSError as e: raise dnf.exceptions.MetadataError(ucd(e))
def scriptout(self, msgs): if msgs: self.rpm_logger.info(ucd(msgs))