def test_history_undo_operations_erase_twoavailable(self): """Test history_undo_operations with an erase available in two repos.""" base = Base() base._sack = mock_sack('main', 'search') operations = NEVRAOperations() operations.add('Erase', 'lotus-3-16.x86_64') with base: base.history_undo_operations(operations) transaction_it = iter(base.transaction) self.assertEqual(next(transaction_it), self._create_item_matcher( INSTALL, installed='lotus-3-16.x86_64', reason='history')) self.assertRaises(StopIteration, next, transaction_it)
def repo_baseurl_make_native(base: dnf.Base) -> dnf.Base: """Ensure that baseurl in each repository is a list of Python strings. Workaround: rhbz#1649284 -- Package.remote_location fails with AttributeError """ class BaseurlRepoProxy: def __init__(self, repo): self.__repo = repo def __getattr__(self, name): return getattr(self.__repo, name) @property def baseurl(self): return list(map(str, self.__repo.baseurl)) for name, repo in base.repos.items(): base.repos[name] = BaseurlRepoProxy(repo) return base
def setUp(self): """Prepare the test fixture.""" self._base = Base() self._base._sack = mock_sack('main', 'updates')
class BaseTest(TestCase): """Unit tests of dnf.Base.""" def _create_item_matcher(self, op_type, installed=None, erased=None, obsoleted=[], reason='unknown'): """Create a new instance of dnf.transaction.TransactionItem matcher.""" attrs = {'op_type': op_type, 'installed': self._create_package_matcher(installed) if installed else installed, 'erased': self._create_package_matcher(erased) if erased else erased, 'obsoleted': [self._create_package_matcher(nevra) for nevra in obsoleted], 'reason': reason} return ObjectMatcher(TransactionItem, attrs) def _create_package_matcher(self, nevra_str): """Create a new instance of dnf.package.Package matcher.""" nevra = split_nevra(nevra_str) attrs = {'name': nevra.name, 'epoch': nevra.epoch, 'version': nevra.version, 'release': nevra.release, 'arch': nevra.arch} return ObjectMatcher(Package, attrs) def setUp(self): """Prepare the test fixture.""" self._base = Base() self._base._sack = mock_sack('main', 'updates') def test_history_undo_operations_downgrade(self): """Test history_undo_operations with a downgrade.""" operations = NEVRAOperations() operations.add('Downgrade', 'pepper-20-0.x86_64', 'pepper-20-1.x86_64', ('lotus-3-16.x86_64',)) with self._base: self._base.history_undo_operations(operations) transaction_it = iter(self._base.transaction) self.assertEqual(next(transaction_it), self._create_item_matcher( UPGRADE, installed='pepper-20-1.x86_64', erased='pepper-20-0.x86_64')) self.assertEqual(next(transaction_it), self._create_item_matcher( INSTALL, installed='lotus-3-16.x86_64', reason='history')) self.assertRaises(StopIteration, next, transaction_it) def test_history_undo_operations_downgrade_notavailable(self): """Test history_undo_operations with an unavailable downgrade.""" operations = NEVRAOperations() operations.add('Downgrade', 'pepper-20-0.x86_64', 'pepper-20-2.x86_64') with self._base, self.assertRaises(PackagesNotAvailableError) as context: self._base.history_undo_operations(operations) self.assertEqual(context.exception.pkg_spec, 'pepper-20-2.x86_64') def test_history_undo_operations_downgrade_notinstalled(self): """Test history_undo_operations with a not installed downgrade.""" operations = NEVRAOperations() operations.add('Downgrade', 'lotus-3-0.x86_64', 'lotus-3-16.x86_64') with self._base, self.assertRaises(PackagesNotInstalledError) as context: self._base.history_undo_operations(operations) self.assertEqual(context.exception.pkg_spec, 'lotus-3-0.x86_64') def test_history_undo_operations_erase(self): """Test history_undo_operations with an erase.""" operations = NEVRAOperations() operations.add('Erase', 'lotus-3-16.x86_64') with self._base: self._base.history_undo_operations(operations) transaction_it = iter(self._base.transaction) self.assertEqual(next(transaction_it), self._create_item_matcher( INSTALL, installed='lotus-3-16.x86_64', reason='history')) self.assertRaises(StopIteration, next, transaction_it) def test_history_undo_operations_erase_twoavailable(self): """Test history_undo_operations with an erase available in two repos.""" base = Base() base._sack = mock_sack('main', 'search') operations = NEVRAOperations() operations.add('Erase', 'lotus-3-16.x86_64') with base: base.history_undo_operations(operations) transaction_it = iter(base.transaction) self.assertEqual(next(transaction_it), self._create_item_matcher( INSTALL, installed='lotus-3-16.x86_64', reason='history')) self.assertRaises(StopIteration, next, transaction_it) def test_history_undo_operations_erase_notavailable(self): """Test history_undo_operations with an unavailable erase.""" operations = NEVRAOperations() operations.add('Erase', 'hole-1-1.x86_64') with self._base, self.assertRaises(PackagesNotAvailableError) as context: self._base.history_undo_operations(operations) self.assertEqual(context.exception.pkg_spec, 'hole-1-1.x86_64') def test_history_undo_operations_install(self): """Test history_undo_operations with an install.""" operations = NEVRAOperations() operations.add('Install', 'pepper-20-0.x86_64', obsoleted_nevras=('lotus-3-16.x86_64',)) with self._base: self._base.history_undo_operations(operations) transaction_it = iter(self._base.transaction) self.assertEqual(next(transaction_it), self._create_item_matcher( ERASE, erased='pepper-20-0.x86_64')) self.assertEqual(next(transaction_it), self._create_item_matcher( INSTALL, installed='lotus-3-16.x86_64', reason='history')) self.assertRaises(StopIteration, next, transaction_it) def test_history_undo_operations_install_notinstalled(self): """Test history_undo_operations with a not installed install.""" operations = NEVRAOperations() operations.add('Install', 'mrkite-2-0.x86_64') with self._base, self.assertRaises(PackagesNotInstalledError) as context: self._base.history_undo_operations(operations) self.assertEqual(context.exception.pkg_spec, 'mrkite-2-0.x86_64') def test_history_undo_operations_reinstall(self): """Test history_undo_operations with a reinstall.""" operations = NEVRAOperations() operations.add('Reinstall', 'pepper-20-0.x86_64', 'pepper-20-0.x86_64', ('hole-1-1.x86_64',)) with self._base: self._base.history_undo_operations(operations) transaction_it = iter(self._base.transaction) self.assertEqual(next(transaction_it), self._create_item_matcher( REINSTALL, installed='pepper-20-0.x86_64', erased='pepper-20-0.x86_64', obsoleted=('hole-1-1.x86_64',))) self.assertRaises(StopIteration, next, transaction_it) def test_history_undo_operations_reinstall_notavailable(self): """Test history_undo_operations with an unvailable reinstall.""" operations = NEVRAOperations() operations.add('Reinstall', 'mrkite-2-0.x86_64', 'mrkite-2-0.x86_64') with self._base, self.assertRaises(PackagesNotInstalledError) as context: self._base.history_undo_operations(operations) self.assertEqual(context.exception.pkg_spec, 'mrkite-2-0.x86_64') def test_history_undo_operations_reinstall_notinstalled(self): """Test history_undo_operations with a not installed reinstall.""" operations = NEVRAOperations() operations.add('Reinstall', 'hole-1-1.x86_64', 'hole-1-1.x86_64') with self._base, self.assertRaises(PackagesNotAvailableError) as context: self._base.history_undo_operations(operations) self.assertEqual(context.exception.pkg_spec, 'hole-1-1.x86_64') def test_history_undo_operations_reinstall_notinstalled_obsoleted(self): """Test history_undo_operations with a not installed obsoleted of a reinstall.""" operations = NEVRAOperations() operations.add('Reinstall', 'pepper-20-0.x86_64', 'pepper-20-0.x86_64', ('lotus-3-16.x86_64',)) with self._base: self._base.history_undo_operations(operations) transaction_it = iter(self._base.transaction) self.assertEqual(next(transaction_it), self._create_item_matcher( REINSTALL, installed='pepper-20-0.x86_64', erased='pepper-20-0.x86_64', obsoleted=())) self.assertRaises(StopIteration, next, transaction_it) def test_history_undo_operations_update(self): """Test history_undo_operations with an update.""" operations = NEVRAOperations() operations.add('Update', 'tour-5-0.noarch', 'tour-4.6-1.noarch', ('lotus-3-16.x86_64',)) with self._base: self._base.history_undo_operations(operations) transaction_it = iter(self._base.transaction) self.assertEqual(next(transaction_it), self._create_item_matcher( DOWNGRADE, installed='tour-4.6-1.noarch', erased='tour-5-0.noarch')) self.assertEqual(next(transaction_it), self._create_item_matcher( INSTALL, installed='lotus-3-16.x86_64', reason='history')) self.assertRaises(StopIteration, next, transaction_it) def test_history_undo_operations_update_notavailable(self): """Test history_undo_operations with an unavailable update.""" operations = NEVRAOperations() operations.add('Update', 'tour-5-0.noarch', 'tour-4.6-2.noarch') with self._base, self.assertRaises(PackagesNotAvailableError) as context: self._base.history_undo_operations(operations) self.assertEqual(context.exception.pkg_spec, 'tour-4.6-2.noarch') def test_history_undo_operations_update_notinstalled(self): """Test history_undo_operations with a not installed update.""" operations = NEVRAOperations() operations.add('Update', 'lotus-4-0.x86_64', 'lotus-3-16.x86_64') with self._base, self.assertRaises(PackagesNotInstalledError) as context: self._base.history_undo_operations(operations) self.assertEqual(context.exception.pkg_spec, 'lotus-4-0.x86_64')
def dnf_base(): base = Base() base.read_all_repos() base.fill_sack() base.sack.query() return base.sack.query()
def setup(self): """ Setup DNF builder. """ dnf_conf = Conf() dnf_conf.debuglevel = 10 dnf_conf.logdir = self.log_path dnf_conf.assumeyes = True dnf_conf.installroot = self.image_path pdir = os.path.join(self.image_path, "var", "lib", "dnf") dnf_conf.persistdir = pdir dnf_conf.cachedir = os.path.join(pdir, "cache") dnf_conf.keepcache = not self.cleanall dnf_conf.releasever = str(self.config["releasever"]) for arch in ("arch", "basearch"): dnf_conf.substitutions[arch] = self.config["architecture"] for conf in ("proxy", "proxy_username", "proxy_password"): if conf in self.runtime: setattr(dnf_conf, conf, self.runtime[conf]) self.dnf_builder = Base(dnf_conf) self.dnf_builder.read_all_repos() all_repos = self.config["repo"].get("*", False) runtime_all_repos = self.runtime["repo"].get("*", False) for repo_name, repo in self.dnf_builder.repos.items(): repo_conf = None if all_repos or runtime_all_repos: repo_conf = configfile.merge(self.config["repo"].get("*", {}), self.runtime["repo"].get("*", {})) if repo_conf.get("baseurl"): del repo_conf["baseurl"] if (repo_name in self.config["repo"] or repo_name in self.runtime["repo"]): merge_conf = configfile.merge( self.config["repo"].get(repo_name, {}), self.runtime["repo"].get(repo_name, {})) if not merge_conf: continue if repo_conf: repo_conf = configfile.merge(merge_conf, repo_conf) else: repo_conf = merge_conf if repo_conf: if "baseurl" in repo_conf: repo.baseurl = repo_conf["baseurl"] # Explicitly remove these as # they can override the baseurl settings repo.mirrorlist = None repo.metalink = None if "enabled" in repo_conf: if not repo_conf["enabled"]: repo.disable() else: repo.enable() else: repo.enable() # If the RPM DBs aren't initialised, # hawkey doesn't fill the sack correctly and fails. # But we don't want to overwrite any already setup RPM DBs. rpm_path = os.path.join(self.image_path, "var", "lib", "rpm") if not os.path.exists(rpm_path): self.dnf_builder.ts.ts.initDB() self.dnf_builder.fill_sack()
class DNFBuilder(object): """ DNF wrapper. """ def __init__(self, image_path, log_path, architecture, config, runtime): """ Create DNF builder. :param image_path: image base path :type image_path: str :param log_path: logging path :type log_path: str :param architecture: architecture to run on :type architecture: str :param config: configuration options :type config: dict :param runtime: runtime configuration options :type runtime: dict or None """ self.dnf_builder = None self.image_path = image_path self.log_path = log_path self.cleanall = config.pop("cleanall", True) arch = "i686" if architecture == "x86" else "x86_64" self.config = { "releasever": detect_releasever("/"), "architecture": arch, "repo": {} } self.config.update(config) self.runtime = {"repo": {}} if runtime: self.runtime.update(runtime) def setup(self): """ Setup DNF builder. """ dnf_conf = Conf() dnf_conf.debuglevel = 10 dnf_conf.logdir = self.log_path dnf_conf.assumeyes = True dnf_conf.installroot = self.image_path pdir = os.path.join(self.image_path, "var", "lib", "dnf") dnf_conf.persistdir = pdir dnf_conf.cachedir = os.path.join(pdir, "cache") dnf_conf.keepcache = not self.cleanall dnf_conf.releasever = str(self.config["releasever"]) for arch in ("arch", "basearch"): dnf_conf.substitutions[arch] = self.config["architecture"] for conf in ("proxy", "proxy_username", "proxy_password"): if conf in self.runtime: setattr(dnf_conf, conf, self.runtime[conf]) self.dnf_builder = Base(dnf_conf) self.dnf_builder.read_all_repos() all_repos = self.config["repo"].get("*", False) runtime_all_repos = self.runtime["repo"].get("*", False) for repo_name, repo in self.dnf_builder.repos.items(): repo_conf = None if all_repos or runtime_all_repos: repo_conf = configfile.merge(self.config["repo"].get("*", {}), self.runtime["repo"].get("*", {})) if repo_conf.get("baseurl"): del repo_conf["baseurl"] if (repo_name in self.config["repo"] or repo_name in self.runtime["repo"]): merge_conf = configfile.merge( self.config["repo"].get(repo_name, {}), self.runtime["repo"].get(repo_name, {})) if not merge_conf: continue if repo_conf: repo_conf = configfile.merge(merge_conf, repo_conf) else: repo_conf = merge_conf if repo_conf: if "baseurl" in repo_conf: repo.baseurl = repo_conf["baseurl"] # Explicitly remove these as # they can override the baseurl settings repo.mirrorlist = None repo.metalink = None if "enabled" in repo_conf: if not repo_conf["enabled"]: repo.disable() else: repo.enable() else: repo.enable() # If the RPM DBs aren't initialised, # hawkey doesn't fill the sack correctly and fails. # But we don't want to overwrite any already setup RPM DBs. rpm_path = os.path.join(self.image_path, "var", "lib", "rpm") if not os.path.exists(rpm_path): self.dnf_builder.ts.ts.initDB() self.dnf_builder.fill_sack() def install(self, pkgs): """ Install the list of provided packages. :param pkgs: list of packages to install :type pkgs: list """ if not self.dnf_builder: self.setup() for pkg in pkgs: try: self.dnf_builder.install(pkg) except dnf.exceptions.MarkingError: raise DNFError("Cannot install package '{}'".format(pkg)) try: self.dnf_builder.resolve() except dnf.exceptions.DepsolveError: raise DNFError("Cannot resolve package dependencies") try: self.dnf_builder.download_packages( self.dnf_builder.transaction.install_set) except dnf.exceptions.DownloadError: raise DNFError("Cannot download packages for installation") self.dnf_builder.do_transaction() def finish(self): """ Run any cleanup steps. """ if self.dnf_builder: self.dnf_builder.close() if self.cleanall: shutil.rmtree(self.dnf_builder.conf.cachedir, True)