import dnf-4.2.23-4.el8
This commit is contained in:
		
							parent
							
								
									553f17f763
								
							
						
					
					
						commit
						ebe355c9b4
					
				| @ -1 +1 @@ | ||||
| 535f46b9a5242a315e1269a59372362013a5a6f0 SOURCES/dnf-4.2.17.tar.gz | ||||
| 0da07a3e6ff19430ffe39699e474439eab63ee7d SOURCES/dnf-4.2.23.tar.gz | ||||
|  | ||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | ||||
| SOURCES/dnf-4.2.17.tar.gz | ||||
| SOURCES/dnf-4.2.23.tar.gz | ||||
|  | ||||
| @ -1,101 +0,0 @@ | ||||
| From 8bcd196fd95e70fd1f0be16d2c274e39a1cabe2e Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Rohel <jrohel@redhat.com> | ||||
| Date: Thu, 21 Nov 2019 11:45:03 +0100 | ||||
| Subject: [PATCH] Do a substitution of variables in repo_id (RhBug:1748841) | ||||
| 
 | ||||
| Example of repo file: | ||||
| [test-$basearch-$releasever] | ||||
| Name=Test-$basearch-$releasever | ||||
| baseurl=file:///mnt/ | ||||
| gpgcheck=0 | ||||
| enabled=1 | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1748841 | ||||
| ---
 | ||||
|  dnf/conf/read.py | 40 +++++++++++++++++++++++++++------------- | ||||
|  1 file changed, 27 insertions(+), 13 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/conf/read.py b/dnf/conf/read.py
 | ||||
| index a526a71..1efac22 100644
 | ||||
| --- a/dnf/conf/read.py
 | ||||
| +++ b/dnf/conf/read.py
 | ||||
| @@ -43,7 +43,7 @@ class RepoReader(object):
 | ||||
|   | ||||
|          # read .repo files from directories specified by conf.reposdir | ||||
|          for repofn in (repofn for reposdir in self.conf.reposdir | ||||
| -                       for repofn in sorted(glob.glob('%s/*.repo' % reposdir))):
 | ||||
| +                       for repofn in sorted(glob.glob('{}/*.repo'.format(reposdir)))):
 | ||||
|              try: | ||||
|                  for r in self._get_repos(repofn): | ||||
|                      yield r | ||||
| @@ -54,17 +54,38 @@ class RepoReader(object):
 | ||||
|      def _build_repo(self, parser, id_, repofn): | ||||
|          """Build a repository using the parsed data.""" | ||||
|   | ||||
| -        repo = dnf.repo.Repo(id_, self.conf)
 | ||||
| +        substituted_id = libdnf.conf.ConfigParser.substitute(id_, self.conf.substitutions)
 | ||||
| +
 | ||||
| +        # Check the repo.id against the valid chars
 | ||||
| +        invalid = dnf.repo.repo_id_invalid(substituted_id)
 | ||||
| +        if invalid is not None:
 | ||||
| +            if substituted_id != id_:
 | ||||
| +                msg = _("Bad id for repo: {} ({}), byte = {} {}").format(substituted_id, id_,
 | ||||
| +                                                                         substituted_id[invalid],
 | ||||
| +                                                                         invalid)
 | ||||
| +            else:
 | ||||
| +                msg = _("Bad id for repo: {}, byte = {} {}").format(id_, id_[invalid], invalid)
 | ||||
| +            raise dnf.exceptions.ConfigError(msg)
 | ||||
| +
 | ||||
| +        repo = dnf.repo.Repo(substituted_id, self.conf)
 | ||||
|          try: | ||||
|              repo._populate(parser, id_, repofn, dnf.conf.PRIO_REPOCONFIG) | ||||
|          except ValueError as e: | ||||
| -            msg = _("Repository '%s': Error parsing config: %s") % (id_, e)
 | ||||
| +            if substituted_id != id_:
 | ||||
| +                msg = _("Repository '{}' ({}): Error parsing config: {}").format(substituted_id,
 | ||||
| +                                                                                 id_, e)
 | ||||
| +            else:
 | ||||
| +                msg = _("Repository '{}': Error parsing config: {}").format(id_, e)
 | ||||
|              raise dnf.exceptions.ConfigError(msg) | ||||
|   | ||||
|          # Ensure that the repo name is set | ||||
|          if repo._get_priority('name') == dnf.conf.PRIO_DEFAULT: | ||||
| -            msg = _("Repository '%s' is missing name in configuration, using id.")
 | ||||
| -            logger.warning(msg, id_)
 | ||||
| +            if substituted_id != id_:
 | ||||
| +                msg = _("Repository '{}' ({}) is missing name in configuration, using id.").format(
 | ||||
| +                    substituted_id, id_)
 | ||||
| +            else:
 | ||||
| +                msg = _("Repository '{}' is missing name in configuration, using id.").format(id_)
 | ||||
| +            logger.warning(msg)
 | ||||
|          repo.name = ucd(repo.name) | ||||
|          repo._substitutions.update(self.conf.substitutions) | ||||
|          repo.cfg = parser | ||||
| @@ -80,23 +101,16 @@ class RepoReader(object):
 | ||||
|          try: | ||||
|              parser.read(repofn) | ||||
|          except RuntimeError as e: | ||||
| -            raise dnf.exceptions.ConfigError(_('Parsing file "%s" failed: %s') % (repofn, e))
 | ||||
| +            raise dnf.exceptions.ConfigError(_('Parsing file "{}" failed: {}').format(repofn, e))
 | ||||
|          except IOError as e: | ||||
|              logger.warning(e) | ||||
|   | ||||
|          # Check sections in the .repo file that was just slurped up | ||||
|          for section in parser.getData(): | ||||
|   | ||||
|              if section == 'main': | ||||
|                  continue | ||||
|   | ||||
| -            # Check the repo.id against the valid chars
 | ||||
| -            invalid = dnf.repo.repo_id_invalid(section)
 | ||||
| -            if invalid is not None:
 | ||||
| -                logger.warning(_("Bad id for repo: %s, byte = %s %d"), section,
 | ||||
| -                               section[invalid], invalid)
 | ||||
| -                continue
 | ||||
| -
 | ||||
|              try: | ||||
|                  thisrepo = self._build_repo(parser, ucd(section), repofn) | ||||
|              except (dnf.exceptions.RepoError, dnf.exceptions.ConfigError) as e: | ||||
| --
 | ||||
| libgit2 0.28.2 | ||||
| 
 | ||||
							
								
								
									
										238
									
								
								SOURCES/0001-Handle-empty-comps-group-name-RhBug1826198.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								SOURCES/0001-Handle-empty-comps-group-name-RhBug1826198.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,238 @@ | ||||
| From 3c758a4ea670fab1f4b55fa878ebf2b2ff4b678b Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com> | ||||
| Date: Tue, 28 Apr 2020 09:08:05 +0200 | ||||
| Subject: [PATCH] Handle empty comps group name (RhBug:1826198) | ||||
| 
 | ||||
| Don't crash on empty comps group/environment name. In outputs, use the | ||||
| "<name-unset>" placeholder instead of the name. | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1826198 | ||||
| ---
 | ||||
|  dnf/cli/commands/group.py  |  4 ++-- | ||||
|  dnf/cli/output.py          | 16 ++++++++++------ | ||||
|  dnf/comps.py               | 11 ++++++++++- | ||||
|  dnf/db/group.py            | 12 ++++++++---- | ||||
|  tests/repos/main_comps.xml |  7 +++++++ | ||||
|  tests/support.py           |  2 +- | ||||
|  tests/test_comps.py        |  6 +++--- | ||||
|  tests/test_groups.py       |  9 +++++++++ | ||||
|  8 files changed, 50 insertions(+), 17 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/commands/group.py b/dnf/cli/commands/group.py
 | ||||
| index f535a50980..4ffd3b89c8 100644
 | ||||
| --- a/dnf/cli/commands/group.py
 | ||||
| +++ b/dnf/cli/commands/group.py
 | ||||
| @@ -177,7 +177,7 @@ def _list(self, userlist):
 | ||||
|          def _out_grp(sect, group): | ||||
|              if not done: | ||||
|                  print(sect) | ||||
| -            msg = '   %s' % group.ui_name
 | ||||
| +            msg = '   %s' % (group.ui_name if group.ui_name is not None else _("<name-unset>"))
 | ||||
|              if print_ids: | ||||
|                  msg += ' (%s)' % group.id | ||||
|              if group.lang_only: | ||||
| @@ -188,7 +188,7 @@ def _out_env(sect, envs):
 | ||||
|              if envs: | ||||
|                  print(sect) | ||||
|              for e in envs: | ||||
| -                msg = '   %s' % e.ui_name
 | ||||
| +                msg = '   %s' % (e.ui_name if e.ui_name is not None else _("<name-unset>"))
 | ||||
|                  if print_ids: | ||||
|                      msg += ' (%s)' % e.id | ||||
|                  print(msg) | ||||
| diff --git a/dnf/cli/output.py b/dnf/cli/output.py
 | ||||
| index 67eab80b19..2585a5c773 100644
 | ||||
| --- a/dnf/cli/output.py
 | ||||
| +++ b/dnf/cli/output.py
 | ||||
| @@ -1221,47 +1221,51 @@ def _add_line(lines, data, a_wid, po, obsoletes=[]):
 | ||||
|                  lines.append((name, "", "", "", "", "", "")) | ||||
|              pkglist_lines.append((action, lines)) | ||||
|          if self.base._history: | ||||
| +            def format_line(group):
 | ||||
| +                name = group.getName()
 | ||||
| +                return (name if name else _("<name-unset>"), "", "", "", "", "", "")
 | ||||
| +
 | ||||
|              install_env_group = self.base._history.env._installed | ||||
|              if install_env_group: | ||||
|                  action = _("Installing Environment Groups") | ||||
|                  lines = [] | ||||
|                  for group in install_env_group.values(): | ||||
| -                    lines.append((group.getName(), "", "", "", "", "", ""))
 | ||||
| +                    lines.append(format_line(group))
 | ||||
|                  pkglist_lines.append((action, lines)) | ||||
|              upgrade_env_group = self.base._history.env._upgraded | ||||
|              if upgrade_env_group: | ||||
|                  action = _("Upgrading Environment Groups") | ||||
|                  lines = [] | ||||
|                  for group in upgrade_env_group.values(): | ||||
| -                    lines.append((group.getName(), "", "", "", "", "", ""))
 | ||||
| +                    lines.append(format_line(group))
 | ||||
|                  pkglist_lines.append((action, lines)) | ||||
|              remove_env_group = self.base._history.env._removed | ||||
|              if remove_env_group: | ||||
|                  action = _("Removing Environment Groups") | ||||
|                  lines = [] | ||||
|                  for group in remove_env_group.values(): | ||||
| -                    lines.append((group.getName(), "", "", "", "", "", ""))
 | ||||
| +                    lines.append(format_line(group))
 | ||||
|                  pkglist_lines.append((action, lines)) | ||||
|              install_group = self.base._history.group._installed | ||||
|              if install_group: | ||||
|                  action = _("Installing Groups") | ||||
|                  lines = [] | ||||
|                  for group in install_group.values(): | ||||
| -                    lines.append((group.getName(), "", "", "", "", "", ""))
 | ||||
| +                    lines.append(format_line(group))
 | ||||
|                  pkglist_lines.append((action, lines)) | ||||
|              upgrade_group = self.base._history.group._upgraded | ||||
|              if upgrade_group: | ||||
|                  action = _("Upgrading Groups") | ||||
|                  lines = [] | ||||
|                  for group in upgrade_group.values(): | ||||
| -                    lines.append((group.getName(), "", "", "", "", "", ""))
 | ||||
| +                    lines.append(format_line(group))
 | ||||
|                  pkglist_lines.append((action, lines)) | ||||
|              remove_group = self.base._history.group._removed | ||||
|              if remove_group: | ||||
|                  action = _("Removing Groups") | ||||
|                  lines = [] | ||||
|                  for group in remove_group.values(): | ||||
| -                    lines.append((group.getName(), "", "", "", "", "", ""))
 | ||||
| +                    lines.append(format_line(group))
 | ||||
|                  pkglist_lines.append((action, lines)) | ||||
|          # show skipped conflicting packages | ||||
|          if not self.conf.best and self.base._goal.actions & forward_actions: | ||||
| diff --git a/dnf/comps.py b/dnf/comps.py
 | ||||
| index 316d647087..4ca15b1e07 100644
 | ||||
| --- a/dnf/comps.py
 | ||||
| +++ b/dnf/comps.py
 | ||||
| @@ -75,7 +75,16 @@ def _by_pattern(pattern, case_sensitive, sqn):
 | ||||
|      else: | ||||
|          match = re.compile(fnmatch.translate(pattern), flags=re.I).match | ||||
|   | ||||
| -    return {g for g in sqn if match(g.name) or match(g.id) or match(g.ui_name)}
 | ||||
| +    ret = set()
 | ||||
| +    for g in sqn:
 | ||||
| +        if match(g.id):
 | ||||
| +            ret.add(g)
 | ||||
| +        elif g.name is not None and match(g.name):
 | ||||
| +            ret.add(g)
 | ||||
| +        elif g.ui_name is not None and match(g.ui_name):
 | ||||
| +            ret.add(g)
 | ||||
| +
 | ||||
| +    return ret
 | ||||
|   | ||||
|   | ||||
|  def _fn_display_order(group): | ||||
| diff --git a/dnf/db/group.py b/dnf/db/group.py
 | ||||
| index e3a087760b..5d7e18d1a8 100644
 | ||||
| --- a/dnf/db/group.py
 | ||||
| +++ b/dnf/db/group.py
 | ||||
| @@ -78,8 +78,10 @@ def _get_obj_id(self, obj):
 | ||||
|      def new(self, obj_id, name, translated_name, pkg_types): | ||||
|          swdb_group = self.history.swdb.createCompsGroupItem() | ||||
|          swdb_group.setGroupId(obj_id) | ||||
| -        swdb_group.setName(name)
 | ||||
| -        swdb_group.setTranslatedName(translated_name)
 | ||||
| +        if name is not None:
 | ||||
| +            swdb_group.setName(name)
 | ||||
| +        if translated_name is not None:
 | ||||
| +            swdb_group.setTranslatedName(translated_name)
 | ||||
|          swdb_group.setPackageTypes(pkg_types) | ||||
|          return swdb_group | ||||
|   | ||||
| @@ -136,8 +138,10 @@ def _get_obj_id(self, obj):
 | ||||
|      def new(self, obj_id, name, translated_name, pkg_types): | ||||
|          swdb_env = self.history.swdb.createCompsEnvironmentItem() | ||||
|          swdb_env.setEnvironmentId(obj_id) | ||||
| -        swdb_env.setName(name)
 | ||||
| -        swdb_env.setTranslatedName(translated_name)
 | ||||
| +        if name is not None:
 | ||||
| +            swdb_env.setName(name)
 | ||||
| +        if translated_name is not None:
 | ||||
| +            swdb_env.setTranslatedName(translated_name)
 | ||||
|          swdb_env.setPackageTypes(pkg_types) | ||||
|          return swdb_env | ||||
|   | ||||
| diff --git a/tests/repos/main_comps.xml b/tests/repos/main_comps.xml
 | ||||
| index 9e694d13a5..584bb25b3a 100644
 | ||||
| --- a/tests/repos/main_comps.xml
 | ||||
| +++ b/tests/repos/main_comps.xml
 | ||||
| @@ -49,6 +49,13 @@
 | ||||
|        <packagereq type="optional">brokendeps</packagereq> | ||||
|      </packagelist> | ||||
|    </group> | ||||
| +  <group>
 | ||||
| +    <id>missing-name-group</id>
 | ||||
| +    <name></name>
 | ||||
| +    <packagelist>
 | ||||
| +      <packagereq type="mandatory">meaning-of-life</packagereq>
 | ||||
| +    </packagelist>
 | ||||
| +  </group>
 | ||||
|    <category> | ||||
|     <id>base-system</id> | ||||
|     <display_order>99</display_order> | ||||
| diff --git a/tests/support.py b/tests/support.py
 | ||||
| index e549ba5b95..a7d6a8542c 100644
 | ||||
| --- a/tests/support.py
 | ||||
| +++ b/tests/support.py
 | ||||
| @@ -94,7 +94,7 @@ def mock_open(mock=None, data=None):
 | ||||
|  MAIN_NSOLVABLES = 9 | ||||
|  UPDATES_NSOLVABLES = 4 | ||||
|  AVAILABLE_NSOLVABLES = MAIN_NSOLVABLES + UPDATES_NSOLVABLES | ||||
| -TOTAL_GROUPS = 4
 | ||||
| +TOTAL_GROUPS = 5
 | ||||
|  TOTAL_NSOLVABLES = SYSTEM_NSOLVABLES + AVAILABLE_NSOLVABLES | ||||
|   | ||||
|   | ||||
| diff --git a/tests/test_comps.py b/tests/test_comps.py
 | ||||
| index 30d468e3af..763218587f 100644
 | ||||
| --- a/tests/test_comps.py
 | ||||
| +++ b/tests/test_comps.py
 | ||||
| @@ -107,7 +107,7 @@ def test_group_packages(self):
 | ||||
|      def test_iteration(self): | ||||
|          comps = self.comps | ||||
|          self.assertEqual([g.name for g in comps.groups_iter()], | ||||
| -                         ['Base', 'Solid Ground', "Pepper's", "Broken Group"])
 | ||||
| +                         ['Base', 'Solid Ground', "Pepper's", "Broken Group", None])
 | ||||
|          self.assertEqual([c.name for c in comps.categories_iter()], | ||||
|                           ['Base System']) | ||||
|          g = dnf.util.first(comps.groups_iter()) | ||||
| @@ -115,7 +115,7 @@ def test_iteration(self):
 | ||||
|   | ||||
|      def test_group_display_order(self): | ||||
|          self.assertEqual([g.name for g in self.comps.groups], | ||||
| -                         ["Pepper's", 'Base', 'Solid Ground', 'Broken Group'])
 | ||||
| +                         ["Pepper's", 'Base', 'Solid Ground', 'Broken Group', None])
 | ||||
|   | ||||
|      def test_packages(self): | ||||
|          comps = self.comps | ||||
| @@ -127,7 +127,7 @@ def test_packages(self):
 | ||||
|   | ||||
|      def test_size(self): | ||||
|          comps = self.comps | ||||
| -        self.assertLength(comps, 6)
 | ||||
| +        self.assertLength(comps, 7)
 | ||||
|          self.assertLength(comps.groups, tests.support.TOTAL_GROUPS) | ||||
|          self.assertLength(comps.categories, 1) | ||||
|          self.assertLength(comps.environments, 1) | ||||
| diff --git a/tests/test_groups.py b/tests/test_groups.py
 | ||||
| index fe388f96c0..8972da687e 100644
 | ||||
| --- a/tests/test_groups.py
 | ||||
| +++ b/tests/test_groups.py
 | ||||
| @@ -295,6 +295,15 @@ def test_group_install_broken_optional_nonstrict(self):
 | ||||
|          self.assertLength(inst, 1) | ||||
|          self.assertEmpty(removed) | ||||
|   | ||||
| +    def test_group_install_missing_name(self):
 | ||||
| +        comps_group = self.base.comps.group_by_pattern('missing-name-group')
 | ||||
| +
 | ||||
| +        cnt = self.base.group_install(comps_group.id, ('mandatory', 'default', 'optional'),
 | ||||
| +                                      strict=False)
 | ||||
| +        self._swdb_commit()
 | ||||
| +        self.base.resolve()
 | ||||
| +        self.assertEqual(cnt, 1)
 | ||||
| +
 | ||||
|   | ||||
|  class EnvironmentInstallTest(tests.support.ResultTestCase): | ||||
|      """Set up a test where sugar is considered not installed.""" | ||||
							
								
								
									
										302
									
								
								SOURCES/0002-Add-logfilelevel-configuration-RhBug-1802074.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								SOURCES/0002-Add-logfilelevel-configuration-RhBug-1802074.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,302 @@ | ||||
| From 9f9bfdfcb576846436f97275d6ee82004ceb4cb9 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com> | ||||
| Date: Thu, 4 Jun 2020 16:02:58 +0200 | ||||
| Subject: [PATCH 1/3] Add logfilelevel configuration (RhBug:1802074) | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1802074 | ||||
| ---
 | ||||
|  dnf.spec         |  2 +- | ||||
|  dnf/logging.py   | 17 +++++++++++------ | ||||
|  doc/conf_ref.rst |  6 ++++++ | ||||
|  3 files changed, 18 insertions(+), 7 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf.spec b/dnf.spec
 | ||||
| index 1423c6d5b5..27bae7aaa7 100644
 | ||||
| --- a/dnf.spec
 | ||||
| +++ b/dnf.spec
 | ||||
| @@ -1,5 +1,5 @@
 | ||||
|  # default dependencies | ||||
| -%global hawkey_version 0.48.0
 | ||||
| +%global hawkey_version 0.50.0
 | ||||
|  %global libcomps_version 0.1.8 | ||||
|  %global libmodulemd_version 1.4.0 | ||||
|  %global rpm_version 4.14.0 | ||||
| diff --git a/dnf/logging.py b/dnf/logging.py
 | ||||
| index bd660470a3..c578575e1c 100644
 | ||||
| --- a/dnf/logging.py
 | ||||
| +++ b/dnf/logging.py
 | ||||
| @@ -70,11 +70,14 @@ def filter(self, record):
 | ||||
|      4 : logging.DEBUG, | ||||
|      5 : logging.DEBUG, | ||||
|      6 : logging.DEBUG, # verbose value | ||||
| +    7 : DDEBUG,
 | ||||
| +    8 : SUBDEBUG,
 | ||||
| +    9 : TRACE,
 | ||||
|      } | ||||
|   | ||||
|  def _cfg_verbose_val2level(cfg_errval): | ||||
|      assert 0 <= cfg_errval <= 10 | ||||
| -    return _VERBOSE_VAL_MAPPING.get(cfg_errval, DDEBUG)
 | ||||
| +    return _VERBOSE_VAL_MAPPING.get(cfg_errval, TRACE)
 | ||||
|   | ||||
|   | ||||
|  # Both the DNF default and the verbose default are WARNING. Note that ERROR has | ||||
| @@ -157,13 +160,14 @@ def _presetup(self):
 | ||||
|          self.stderr_handler = stderr | ||||
|   | ||||
|      @only_once | ||||
| -    def _setup_file_loggers(self, verbose_level, logdir, log_size, log_rotate):
 | ||||
| +    def _setup_file_loggers(self, logfile_level, verbose_level, logdir, log_size, log_rotate):
 | ||||
|          logger_dnf = logging.getLogger("dnf") | ||||
|          logger_dnf.setLevel(TRACE) | ||||
|   | ||||
|          # setup file logger | ||||
|          logfile = os.path.join(logdir, dnf.const.LOG) | ||||
|          handler = _create_filehandler(logfile, log_size, log_rotate) | ||||
| +        handler.setLevel(logfile_level)
 | ||||
|          logger_dnf.addHandler(handler) | ||||
|          # put the marker in the file now: | ||||
|          _paint_mark(logger_dnf) | ||||
| @@ -185,14 +189,14 @@ def _setup_file_loggers(self, verbose_level, logdir, log_size, log_rotate):
 | ||||
|          _paint_mark(logger_rpm) | ||||
|   | ||||
|      @only_once | ||||
| -    def _setup(self, verbose_level, error_level, logdir, log_size, log_rotate):
 | ||||
| +    def _setup(self, verbose_level, error_level, logfile_level, logdir, log_size, log_rotate):
 | ||||
|          self._presetup() | ||||
|   | ||||
|          # temporarily turn off stdout/stderr handlers: | ||||
|          self.stdout_handler.setLevel(SUPERCRITICAL) | ||||
|          self.stderr_handler.setLevel(SUPERCRITICAL) | ||||
|   | ||||
| -        self._setup_file_loggers(verbose_level, logdir, log_size, log_rotate)
 | ||||
| +        self._setup_file_loggers(logfile_level, verbose_level, logdir, log_size, log_rotate)
 | ||||
|   | ||||
|          logger_warnings = logging.getLogger("py.warnings") | ||||
|          logger_warnings.addHandler(self.stderr_handler) | ||||
| @@ -209,13 +213,14 @@ def _setup(self, verbose_level, error_level, logdir, log_size, log_rotate):
 | ||||
|      def _setup_from_dnf_conf(self, conf, file_loggers_only=False): | ||||
|          verbose_level_r = _cfg_verbose_val2level(conf.debuglevel) | ||||
|          error_level_r = _cfg_err_val2level(conf.errorlevel) | ||||
| +        logfile_level_r = _cfg_verbose_val2level(conf.logfilelevel)
 | ||||
|          logdir = conf.logdir | ||||
|          log_size = conf.log_size | ||||
|          log_rotate = conf.log_rotate | ||||
|          if file_loggers_only: | ||||
| -            return self._setup_file_loggers(verbose_level_r, logdir, log_size, log_rotate)
 | ||||
| +            return self._setup_file_loggers(logfile_level_r, verbose_level_r, logdir, log_size, log_rotate)
 | ||||
|          else: | ||||
| -            return self._setup(verbose_level_r, error_level_r, logdir, log_size, log_rotate)
 | ||||
| +            return self._setup(verbose_level_r, error_level_r, logfile_level_r, logdir, log_size, log_rotate)
 | ||||
|   | ||||
|   | ||||
|  class Timer(object): | ||||
| diff --git a/doc/conf_ref.rst b/doc/conf_ref.rst
 | ||||
| index cf442770c9..fed6efcec7 100644
 | ||||
| --- a/doc/conf_ref.rst
 | ||||
| +++ b/doc/conf_ref.rst
 | ||||
| @@ -268,6 +268,12 @@ configuration file by your distribution to override the DNF defaults.
 | ||||
|   | ||||
|      Directory where the log files will be stored. Default is ``/var/log``. | ||||
|   | ||||
| +``logfilelevel``
 | ||||
| +    :ref:`integer <integer-label>`
 | ||||
| +
 | ||||
| +    Log file messages output level, in the range 0 to 10. The higher the number the
 | ||||
| +    more debug output is put to logs. Default is 9.
 | ||||
| +
 | ||||
|  .. _log_rotate-label: | ||||
|   | ||||
|  ``log_rotate`` | ||||
| 
 | ||||
| From 1233d7da657ffbd03f9ffc274b648da0bb2898bf Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com> | ||||
| Date: Fri, 5 Jun 2020 09:21:15 +0200 | ||||
| Subject: [PATCH 2/3] Update unit logging test to reflect logfilelevel addition | ||||
| 
 | ||||
| ---
 | ||||
|  tests/test_logging.py | 16 +++++++++------- | ||||
|  1 file changed, 9 insertions(+), 7 deletions(-) | ||||
| 
 | ||||
| diff --git a/tests/test_logging.py b/tests/test_logging.py
 | ||||
| index a7fee3e67c..80e219d882 100644
 | ||||
| --- a/tests/test_logging.py
 | ||||
| +++ b/tests/test_logging.py
 | ||||
| @@ -88,7 +88,7 @@ def test_setup(self):
 | ||||
|          logger = logging.getLogger("dnf") | ||||
|          with tests.support.patch_std_streams() as (stdout, stderr): | ||||
|              self.logging._setup( | ||||
| -                logging.INFO, logging.ERROR, self.logdir, self.log_size, self.log_rotate)
 | ||||
| +                logging.INFO, logging.ERROR, dnf.logging.TRACE, self.logdir, self.log_size, self.log_rotate)
 | ||||
|              self._bench(logger) | ||||
|          self.assertEqual("i\n", stdout.getvalue()) | ||||
|          self.assertEqual("e\n", stderr.getvalue()) | ||||
| @@ -97,7 +97,7 @@ def test_setup_verbose(self):
 | ||||
|          logger = logging.getLogger("dnf") | ||||
|          with tests.support.patch_std_streams() as (stdout, stderr): | ||||
|              self.logging._setup( | ||||
| -                logging.DEBUG, logging.WARNING, self.logdir, self.log_size, self.log_rotate)
 | ||||
| +                logging.DEBUG, logging.WARNING, dnf.logging.TRACE, self.logdir, self.log_size, self.log_rotate)
 | ||||
|              self._bench(logger) | ||||
|          self.assertEqual("d\ni\n", stdout.getvalue()) | ||||
|          self.assertEqual("w\ne\n", stderr.getvalue()) | ||||
| @@ -105,20 +105,22 @@ def test_setup_verbose(self):
 | ||||
|      @mock.patch('dnf.logging.Logging._setup') | ||||
|      def test_setup_from_dnf_conf(self, setup_m): | ||||
|          conf = mock.Mock( | ||||
| -            debuglevel=2, errorlevel=3, logdir=self.logdir,
 | ||||
| +            debuglevel=2, errorlevel=3, logfilelevel=2, logdir=self.logdir,
 | ||||
|              log_size=self.log_size, log_rotate=self.log_rotate) | ||||
|          self.logging._setup_from_dnf_conf(conf) | ||||
|          self.assertEqual(setup_m.call_args, mock.call(dnf.logging.INFO, | ||||
|                                                        dnf.logging.WARNING, | ||||
| +                                                      dnf.logging.INFO,
 | ||||
|                                                        self.logdir, | ||||
|                                                        self.log_size, | ||||
|                                                        self.log_rotate)) | ||||
|          conf = mock.Mock( | ||||
| -            debuglevel=6, errorlevel=6, logdir=self.logdir,
 | ||||
| +            debuglevel=6, errorlevel=6, logfilelevel=6, logdir=self.logdir,
 | ||||
|              log_size=self.log_size, log_rotate=self.log_rotate) | ||||
|          self.logging._setup_from_dnf_conf(conf) | ||||
|          self.assertEqual(setup_m.call_args, mock.call(dnf.logging.DEBUG, | ||||
|                                                        dnf.logging.WARNING, | ||||
| +                                                      dnf.logging.DEBUG,
 | ||||
|                                                        self.logdir, | ||||
|                                                        self.log_size, | ||||
|                                                        self.log_rotate)) | ||||
| @@ -126,7 +128,7 @@ def test_setup_from_dnf_conf(self, setup_m):
 | ||||
|      def test_file_logging(self): | ||||
|          # log nothing to the console: | ||||
|          self.logging._setup( | ||||
| -            dnf.logging.SUPERCRITICAL, dnf.logging.SUPERCRITICAL,
 | ||||
| +            dnf.logging.SUPERCRITICAL, dnf.logging.SUPERCRITICAL, dnf.logging.TRACE,
 | ||||
|              self.logdir, self.log_size, self.log_rotate) | ||||
|          logger = logging.getLogger("dnf") | ||||
|          with tests.support.patch_std_streams() as (stdout, stderr): | ||||
| @@ -145,7 +147,7 @@ def test_file_logging(self):
 | ||||
|      def test_rpm_logging(self): | ||||
|          # log everything to the console: | ||||
|          self.logging._setup( | ||||
| -            dnf.logging.SUBDEBUG, dnf.logging.SUBDEBUG,
 | ||||
| +            dnf.logging.SUBDEBUG, dnf.logging.SUBDEBUG, dnf.logging.TRACE,
 | ||||
|              self.logdir, self.log_size, self.log_rotate) | ||||
|          logger = logging.getLogger("dnf.rpm") | ||||
|          with tests.support.patch_std_streams() as (stdout, stderr): | ||||
| @@ -167,7 +169,7 @@ def test_setup_only_once(self):
 | ||||
|          logger = logging.getLogger("dnf") | ||||
|          self.assertLength(logger.handlers, 0) | ||||
|          self.logging._setup( | ||||
| -            dnf.logging.SUBDEBUG, dnf.logging.SUBDEBUG,
 | ||||
| +            dnf.logging.SUBDEBUG, dnf.logging.SUBDEBUG, dnf.logging.TRACE,
 | ||||
|              self.logdir, self.log_size, self.log_rotate) | ||||
|          cnt = len(logger.handlers) | ||||
|          self.assertGreater(cnt, 0) | ||||
| 
 | ||||
| From 8a57da7229c67315d113b3c61cf981e1a7d81189 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com> | ||||
| Date: Thu, 25 Jun 2020 14:03:02 +0200 | ||||
| Subject: [PATCH 3/3] Control hawkey and librepo log verbosity with | ||||
|  logfilelevel | ||||
| 
 | ||||
| = changelog =
 | ||||
| msg: New config option 'logfilelevel' now controls logging to dnf.log, dnf.librepo.log and hawkey.log | ||||
| type: enhancement | ||||
| resolves: 1802074 | ||||
| ---
 | ||||
|  dnf/logging.py   | 11 +++++++---- | ||||
|  dnf/sack.py      |  2 +- | ||||
|  doc/conf_ref.rst |  3 +++ | ||||
|  3 files changed, 11 insertions(+), 5 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/logging.py b/dnf/logging.py
 | ||||
| index c578575e1c..b5196988f7 100644
 | ||||
| --- a/dnf/logging.py
 | ||||
| +++ b/dnf/logging.py
 | ||||
| @@ -43,6 +43,7 @@
 | ||||
|  DDEBUG = 8  # used by anaconda (pyanaconda/payload/dnfpayload.py) | ||||
|  SUBDEBUG = 6 | ||||
|  TRACE = 4 | ||||
| +ALL = 2
 | ||||
|   | ||||
|  def only_once(func): | ||||
|      """Method decorator turning the method into noop on second or later calls.""" | ||||
| @@ -73,6 +74,7 @@ def filter(self, record):
 | ||||
|      7 : DDEBUG, | ||||
|      8 : SUBDEBUG, | ||||
|      9 : TRACE, | ||||
| +    10: ALL,   # more verbous librepo and hawkey
 | ||||
|      } | ||||
|   | ||||
|  def _cfg_verbose_val2level(cfg_errval): | ||||
| @@ -138,6 +140,7 @@ def __init__(self):
 | ||||
|          logging.addLevelName(DDEBUG, "DDEBUG") | ||||
|          logging.addLevelName(SUBDEBUG, "SUBDEBUG") | ||||
|          logging.addLevelName(TRACE, "TRACE") | ||||
| +        logging.addLevelName(ALL, "ALL")
 | ||||
|          logging.captureWarnings(True) | ||||
|          logging.raiseExceptions = False | ||||
|   | ||||
| @@ -160,7 +163,7 @@ def _presetup(self):
 | ||||
|          self.stderr_handler = stderr | ||||
|   | ||||
|      @only_once | ||||
| -    def _setup_file_loggers(self, logfile_level, verbose_level, logdir, log_size, log_rotate):
 | ||||
| +    def _setup_file_loggers(self, logfile_level, logdir, log_size, log_rotate):
 | ||||
|          logger_dnf = logging.getLogger("dnf") | ||||
|          logger_dnf.setLevel(TRACE) | ||||
|   | ||||
| @@ -177,7 +180,7 @@ def _setup_file_loggers(self, logfile_level, verbose_level, logdir, log_size, lo
 | ||||
|          logger_warnings.addHandler(handler) | ||||
|   | ||||
|          lr_logfile = os.path.join(logdir, dnf.const.LOG_LIBREPO) | ||||
| -        libdnf.repo.LibrepoLog.addHandler(lr_logfile, verbose_level <= DEBUG)
 | ||||
| +        libdnf.repo.LibrepoLog.addHandler(lr_logfile, logfile_level <= ALL)
 | ||||
|   | ||||
|          # setup RPM callbacks logger | ||||
|          logger_rpm = logging.getLogger("dnf.rpm") | ||||
| @@ -196,7 +199,7 @@ def _setup(self, verbose_level, error_level, logfile_level, logdir, log_size, lo
 | ||||
|          self.stdout_handler.setLevel(SUPERCRITICAL) | ||||
|          self.stderr_handler.setLevel(SUPERCRITICAL) | ||||
|   | ||||
| -        self._setup_file_loggers(logfile_level, verbose_level, logdir, log_size, log_rotate)
 | ||||
| +        self._setup_file_loggers(logfile_level, logdir, log_size, log_rotate)
 | ||||
|   | ||||
|          logger_warnings = logging.getLogger("py.warnings") | ||||
|          logger_warnings.addHandler(self.stderr_handler) | ||||
| @@ -218,7 +221,7 @@ def _setup_from_dnf_conf(self, conf, file_loggers_only=False):
 | ||||
|          log_size = conf.log_size | ||||
|          log_rotate = conf.log_rotate | ||||
|          if file_loggers_only: | ||||
| -            return self._setup_file_loggers(logfile_level_r, verbose_level_r, logdir, log_size, log_rotate)
 | ||||
| +            return self._setup_file_loggers(logfile_level_r, logdir, log_size, log_rotate)
 | ||||
|          else: | ||||
|              return self._setup(verbose_level_r, error_level_r, logfile_level_r, logdir, log_size, log_rotate) | ||||
|   | ||||
| diff --git a/dnf/sack.py b/dnf/sack.py
 | ||||
| index fb8c70712f..3c6bc3bbe0 100644
 | ||||
| --- a/dnf/sack.py
 | ||||
| +++ b/dnf/sack.py
 | ||||
| @@ -53,7 +53,7 @@ def _build_sack(base):
 | ||||
|                  arch=base.conf.substitutions["arch"], | ||||
|                  cachedir=cachedir, rootdir=base.conf.installroot, | ||||
|                  logfile=os.path.join(base.conf.logdir, dnf.const.LOG_HAWKEY), | ||||
| -                logdebug=base.conf.debuglevel > 2)
 | ||||
| +                logdebug=base.conf.logfilelevel > 9)
 | ||||
|   | ||||
|   | ||||
|  def _rpmdb_sack(base): | ||||
| diff --git a/doc/conf_ref.rst b/doc/conf_ref.rst
 | ||||
| index fed6efcec7..fdb44a657d 100644
 | ||||
| --- a/doc/conf_ref.rst
 | ||||
| +++ b/doc/conf_ref.rst
 | ||||
| @@ -274,6 +274,9 @@ configuration file by your distribution to override the DNF defaults.
 | ||||
|      Log file messages output level, in the range 0 to 10. The higher the number the | ||||
|      more debug output is put to logs. Default is 9. | ||||
|   | ||||
| +    This option controls dnf.log, dnf.librepo.log and hawkey.log. Although dnf.librepo.log
 | ||||
| +    and hawkey.log are affected only by setting the logfilelevel to 10.
 | ||||
| +
 | ||||
|  .. _log_rotate-label: | ||||
|   | ||||
|  ``log_rotate`` | ||||
| @ -1,67 +0,0 @@ | ||||
| From ba3615c600532a0ce8693a626a9cbe71a458399a Mon Sep 17 00:00:00 2001 | ||||
| From: Pavla Kratochvilova <pkratoch@redhat.com> | ||||
| Date: Thu, 23 May 2019 14:48:29 +0200 | ||||
| Subject: [PATCH 1/2] Respect order of config files in aliases.d | ||||
|  (RhBug:1680489) | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1680489 | ||||
| The aliases config files were read in arbitrary order (os.listdir does not | ||||
| give sorted output). It is better to define clear order (i.e. all config files | ||||
| except USER.conf are ordered alphabetically, USER.conf is the last). | ||||
| 
 | ||||
| Closes: #1542 | ||||
| Approved by: kontura | ||||
| ---
 | ||||
|  dnf/cli/aliases.py | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/aliases.py b/dnf/cli/aliases.py
 | ||||
| index 0b3ba8f6b..b5283d0f3 100644
 | ||||
| --- a/dnf/cli/aliases.py
 | ||||
| +++ b/dnf/cli/aliases.py
 | ||||
| @@ -143,7 +143,7 @@ class Aliases(object):
 | ||||
|          try: | ||||
|              if not os.path.exists(ALIASES_DROPIN_DIR): | ||||
|                  os.mkdir(ALIASES_DROPIN_DIR) | ||||
| -            for fn in os.listdir(ALIASES_DROPIN_DIR):
 | ||||
| +            for fn in sorted(os.listdir(ALIASES_DROPIN_DIR)):
 | ||||
|                  if _ignore_filename(fn): | ||||
|                      continue | ||||
|                  filenames.append(os.path.join(ALIASES_DROPIN_DIR, fn)) | ||||
| -- 
 | ||||
| 2.21.0 | ||||
| 
 | ||||
| 
 | ||||
| From e292de84fcdec844530099a6c37ef29e1a330003 Mon Sep 17 00:00:00 2001 | ||||
| From: Pavla Kratochvilova <pkratoch@redhat.com> | ||||
| Date: Thu, 23 May 2019 15:04:34 +0200 | ||||
| Subject: [PATCH 2/2] [doc] Describe priorities of config files in aliases.d | ||||
|  (RhBug:1680489) | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1680489 | ||||
| 
 | ||||
| Closes: #1542 | ||||
| Approved by: kontura | ||||
| ---
 | ||||
|  doc/command_ref.rst | 5 ++++- | ||||
|  1 file changed, 4 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/doc/command_ref.rst b/doc/command_ref.rst
 | ||||
| index 7141fc2aa..637ccf96b 100644
 | ||||
| --- a/doc/command_ref.rst
 | ||||
| +++ b/doc/command_ref.rst
 | ||||
| @@ -424,7 +424,10 @@ for aliases. The alias processing stops when the first found command is not a na
 | ||||
|  Also, like in shell aliases, if the result starts with a ``\``, the alias processing will stop. | ||||
|   | ||||
|  All aliases are defined in configuration files in the ``/etc/dnf/aliases.d/`` directory in the [aliases] section, | ||||
| -and aliases created by the alias command are written to the ``USER.conf`` file.
 | ||||
| +and aliases created by the alias command are written to the ``USER.conf`` file. In case of conflicts,
 | ||||
| +the ``USER.conf`` has the highest priority, and alphabetical ordering is used for the rest of the
 | ||||
| +configuration files.
 | ||||
| +
 | ||||
|  Optionally, there is the ``enabled`` option in the ``[main]`` section defaulting to True. This can be set for each | ||||
|  file separately in the respective file, or globally for all aliases in the ``ALIASES.conf`` file. | ||||
|   | ||||
| -- 
 | ||||
| 2.21.0 | ||||
| 
 | ||||
| @ -0,0 +1,41 @@ | ||||
| From 03eac4f0b87bb9393e1662af76c433c996c702ab Mon Sep 17 00:00:00 2001 | ||||
| From: Marek Blaha <mblaha@redhat.com> | ||||
| Date: Tue, 14 Jul 2020 08:37:28 +0200 | ||||
| Subject: [PATCH] [doc] Enhance repo variables documentation | ||||
|  (RhBug:1848161,1848615) | ||||
| 
 | ||||
| - clarify DNF_VAR_XXX variables usage
 | ||||
| - mention numeric variables
 | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1848615 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1848161 | ||||
| ---
 | ||||
|  doc/conf_ref.rst | 15 +++++++++++++++ | ||||
|  1 file changed, 15 insertions(+) | ||||
| 
 | ||||
| diff --git a/doc/conf_ref.rst b/doc/conf_ref.rst
 | ||||
| index fdb44a657d..a0362d0779 100644
 | ||||
| --- a/doc/conf_ref.rst
 | ||||
| +++ b/doc/conf_ref.rst
 | ||||
| @@ -629,6 +629,21 @@ In addition to these hard coded variables, user-defined ones can also be used. T
 | ||||
|   | ||||
|      $ DNF_VAR_MY_VARIABLE=value | ||||
|   | ||||
| +To use such variable in your repository configuration remove the prefix. E.g.::
 | ||||
| +
 | ||||
| +    [myrepo]
 | ||||
| +    baseurl=https://example.site/pub/fedora/$MY_VARIABLE/releases/$releasever
 | ||||
| +
 | ||||
| +Note that it is not possible to override the ``arch`` and ``basearch`` variables using either variable files or environmental variables.
 | ||||
| +
 | ||||
| +Although users are encouraged to use named variables, the numbered environmental variables ``DNF0`` - ``DNF9`` are still supported::
 | ||||
| +
 | ||||
| +    $ DNF1=value
 | ||||
| +
 | ||||
| +    [myrepo]
 | ||||
| +    baseurl=https://example.site/pub/fedora/$DNF1/releases/$releasever
 | ||||
| +
 | ||||
| +
 | ||||
|  .. _conf_main_and_repo_options-label: | ||||
|   | ||||
|  ================================== | ||||
| @ -1,32 +0,0 @@ | ||||
| From 3c473306e5e1b630a3030791fb1ef7ea0c0cd823 Mon Sep 17 00:00:00 2001 | ||||
| From: Michal Domonkos <mdomonko@redhat.com> | ||||
| Date: Tue, 26 Nov 2019 13:22:15 +0100 | ||||
| Subject: [PATCH] [doc] Remove note about whitelist | ||||
| 
 | ||||
| The whitelist mechanism has been recently removed from libdnf. | ||||
| 
 | ||||
| Closes: #1543 | ||||
| Approved by: Conan-Kudo | ||||
| ---
 | ||||
|  doc/conf_ref.rst | 5 ----- | ||||
|  1 file changed, 5 deletions(-) | ||||
| 
 | ||||
| diff --git a/doc/conf_ref.rst b/doc/conf_ref.rst
 | ||||
| index d3ea11d..cb95e47 100644
 | ||||
| --- a/doc/conf_ref.rst
 | ||||
| +++ b/doc/conf_ref.rst
 | ||||
| @@ -806,11 +806,6 @@ configuration.
 | ||||
|   | ||||
|          libdnf (Fedora 31; server; Linux.x86_64) | ||||
|   | ||||
| -    To avoid leaking identifiable data, the variant in the above string will be
 | ||||
| -    replaced by "generic" if the value is not an official Fedora variant.
 | ||||
| -    Likewise, the whole OS part (enclosed in parenthesis) will be omitted if
 | ||||
| -    this is a non-Fedora system.
 | ||||
| -
 | ||||
|  ================= | ||||
|  Types of Options | ||||
|  ================= | ||||
| --
 | ||||
| libgit2 0.28.2 | ||||
| 
 | ||||
| @ -1,157 +0,0 @@ | ||||
| From c8d79c0b9956aeeb8cd3a0422656b030d4656578 Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Mracek <jmracek@redhat.com> | ||||
| Date: Mon, 9 Dec 2019 12:32:18 +0100 | ||||
| Subject: [PATCH 1/2] Fix detection of the latest module (RhBug:1781769) | ||||
| 
 | ||||
| The code originally compared module version as a string, but it should | ||||
| be compared as a int. | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1781769 | ||||
| 
 | ||||
| Closes: #1548 | ||||
| Approved by: m-blaha | ||||
| ---
 | ||||
|  dnf/module/module_base.py | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/dnf/module/module_base.py b/dnf/module/module_base.py
 | ||||
| index 8093ab443..64bad84b6 100644
 | ||||
| --- a/dnf/module/module_base.py
 | ||||
| +++ b/dnf/module/module_base.py
 | ||||
| @@ -285,7 +285,7 @@ class ModuleBase(object):
 | ||||
|          if module_list: | ||||
|              latest = module_list[0] | ||||
|              for module in module_list[1:]: | ||||
| -                if module.getVersion() > latest.getVersion():
 | ||||
| +                if module.getVersionNum() > latest.getVersionNum():
 | ||||
|                      latest = module | ||||
|          return latest | ||||
|   | ||||
| -- 
 | ||||
| 2.21.0 | ||||
| 
 | ||||
| 
 | ||||
| From 44e9095404569dbf8a19726eb79be8e580bed60c Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Mracek <jmracek@redhat.com> | ||||
| Date: Wed, 11 Dec 2019 09:52:16 +0100 | ||||
| Subject: [PATCH 2/2] Improve transaction table formatting | ||||
| 
 | ||||
| It improves formatting of transaction table in case when terminal has | ||||
| unknown width. | ||||
| 
 | ||||
| Closes: #1548 | ||||
| Approved by: m-blaha | ||||
| ---
 | ||||
|  dnf/cli/output.py | 45 ++++++++++++++++++++++++--------------------- | ||||
|  1 file changed, 24 insertions(+), 21 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/output.py b/dnf/cli/output.py
 | ||||
| index a03df610c..2ff41b625 100644
 | ||||
| --- a/dnf/cli/output.py
 | ||||
| +++ b/dnf/cli/output.py
 | ||||
| @@ -224,16 +224,32 @@ class Output(object):
 | ||||
|          if total_width is None: | ||||
|              total_width = self.term.real_columns | ||||
|   | ||||
| +        #  We start allocating 1 char to everything but the last column, and a
 | ||||
| +        # space between each (again, except for the last column). Because
 | ||||
| +        # at worst we are better with:
 | ||||
| +        # |one two three|
 | ||||
| +        # | four        |
 | ||||
| +        # ...than:
 | ||||
| +        # |one two three|
 | ||||
| +        # |            f|
 | ||||
| +        # |our          |
 | ||||
| +        # ...the later being what we get if we pre-allocate the last column, and
 | ||||
| +        # thus. the space, due to "three" overflowing it's column by 2 chars.
 | ||||
| +        if columns is None:
 | ||||
| +            columns = [1] * (cols - 1)
 | ||||
| +            columns.append(0)
 | ||||
| +
 | ||||
|          # i'm not able to get real terminal width so i'm probably | ||||
|          # running in non interactive terminal (pipe to grep, redirect to file...) | ||||
|          # avoid splitting lines to enable filtering output | ||||
|          if not total_width: | ||||
|              full_columns = [] | ||||
| -            for col in data:
 | ||||
| +            for d in xrange(0, cols):
 | ||||
| +                col = data[d]
 | ||||
|                  if col: | ||||
|                      full_columns.append(col[-1][0]) | ||||
|                  else: | ||||
| -                    full_columns.append(0)
 | ||||
| +                    full_columns.append(columns[d] + 1)
 | ||||
|              full_columns[0] += len(indent) | ||||
|              # if possible, try to keep default width (usually 80 columns) | ||||
|              default_width = self.term.columns | ||||
| @@ -241,20 +257,6 @@ class Output(object):
 | ||||
|                  return full_columns | ||||
|              total_width = default_width | ||||
|   | ||||
| -        #  We start allocating 1 char to everything but the last column, and a
 | ||||
| -        # space between each (again, except for the last column). Because
 | ||||
| -        # at worst we are better with:
 | ||||
| -        # |one two three|
 | ||||
| -        # | four        |
 | ||||
| -        # ...than:
 | ||||
| -        # |one two three|
 | ||||
| -        # |            f|
 | ||||
| -        # |our          |
 | ||||
| -        # ...the later being what we get if we pre-allocate the last column, and
 | ||||
| -        # thus. the space, due to "three" overflowing it's column by 2 chars.
 | ||||
| -        if columns is None:
 | ||||
| -            columns = [1] * (cols - 1)
 | ||||
| -            columns.append(0)
 | ||||
|   | ||||
|          total_width -= (sum(columns) + (cols - 1) + exact_width(indent)) | ||||
|          if not columns[-1]: | ||||
| @@ -1273,7 +1275,7 @@ class Output(object):
 | ||||
|                  skip_str = skip_str % _(" or part of a group") | ||||
|   | ||||
|              pkglist_lines.append((skip_str, lines)) | ||||
| -
 | ||||
| +        output_width = self.term.columns
 | ||||
|          if not data['n'] and not self.base._moduleContainer.isChanged() and not \ | ||||
|                  (self.base._history and (self.base._history.group or self.base._history.env)): | ||||
|              return u'' | ||||
| @@ -1283,6 +1285,8 @@ class Output(object):
 | ||||
|              columns = self.calcColumns(data, indent="  ", columns=columns, | ||||
|                                         remainder_column=2, total_width=total_width) | ||||
|              (n_wid, a_wid, v_wid, r_wid, s_wid) = columns | ||||
| +            real_width = sum(columns) + 5
 | ||||
| +            output_width = output_width if output_width >= real_width else real_width
 | ||||
|   | ||||
|              # Do not use 'Package' without context. Using context resolves | ||||
|              # RhBug 1302935 as a side effect. | ||||
| @@ -1325,13 +1329,13 @@ class Output(object):
 | ||||
|              # Translators: This is the full (unabbreviated) term 'Size'. | ||||
|                                           C_('long', 'Size')) | ||||
|   | ||||
| -            out = [u"%s\n%s\n%s\n" % ('=' * self.term.columns,
 | ||||
| +            out = [u"%s\n%s\n%s\n" % ('=' * output_width,
 | ||||
|                                        self.fmtColumns(((msg_package, -n_wid), | ||||
|                                                         (msg_arch, -a_wid), | ||||
|                                                         (msg_version, -v_wid), | ||||
|                                                         (msg_repository, -r_wid), | ||||
|                                                         (msg_size, s_wid)), u" "), | ||||
| -                                      '=' * self.term.columns)]
 | ||||
| +                                      '=' * output_width)]
 | ||||
|   | ||||
|          for (action, lines) in pkglist_lines: | ||||
|              if lines: | ||||
| @@ -1349,11 +1353,10 @@ class Output(object):
 | ||||
|   | ||||
|              if lines: | ||||
|                  out.append(totalmsg) | ||||
| -
 | ||||
|          out.append(_(""" | ||||
|  Transaction Summary | ||||
|  %s | ||||
| -""") % ('=' * self.term.columns))
 | ||||
| +""") % ('=' * output_width))
 | ||||
|          summary_data = ( | ||||
|              (_('Install'), len(list_bunch.installed) + | ||||
|               len(list_bunch.installed_group) + | ||||
| -- 
 | ||||
| 2.21.0 | ||||
| 
 | ||||
							
								
								
									
										9957
									
								
								SOURCES/0004-Update-translations-RhBug-1820544.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9957
									
								
								SOURCES/0004-Update-translations-RhBug-1820544.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,106 +0,0 @@ | ||||
| From 4c2f0dbd2ffecec35c9df09190a5eeb8c4abce73 Mon Sep 17 00:00:00 2001 | ||||
| From: Marek Blaha <mblaha@redhat.com> | ||||
| Date: Fri, 22 Nov 2019 08:02:45 +0100 | ||||
| Subject: [PATCH 1/2] Remove misleading comments | ||||
| 
 | ||||
| ---
 | ||||
|  dnf/cli/cli.py | 4 ---- | ||||
|  1 file changed, 4 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/cli.py b/dnf/cli/cli.py
 | ||||
| index 80df950c8d..9fbe7d3ada 100644
 | ||||
| --- a/dnf/cli/cli.py
 | ||||
| +++ b/dnf/cli/cli.py
 | ||||
| @@ -405,13 +405,9 @@ def downgradePkgs(self, specs=[], file_pkgs=[], strict=False):
 | ||||
|          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: | ||||
| 
 | ||||
| From 09b035f5d71c86b88da2d6ea117282fab5e87caa Mon Sep 17 00:00:00 2001 | ||||
| From: Marek Blaha <mblaha@redhat.com> | ||||
| Date: Tue, 19 Nov 2019 07:08:21 +0100 | ||||
| Subject: [PATCH 2/2] Unify downgrade exit codes with upgrade (RhBug:1759847) | ||||
| 
 | ||||
| Now the dnf downgrade/upgrade commands behave consistently | ||||
| in case the lowest/highest available version was already | ||||
| installed. On top of that the behaviour is now compatible with | ||||
| yum-3. | ||||
| 
 | ||||
| Behaviour of upgrade command in case that the latest version of | ||||
| acpi is already installed: | ||||
| $ dnf upgrade acpi | ||||
| Dependencies resolved. | ||||
| Nothing to do. | ||||
| Complete! | ||||
| 
 | ||||
| The exit code of dnf upgrade is 0 | ||||
| 
 | ||||
| In case that the lowest version of acpi is installed: | ||||
| 
 | ||||
| Previous behaviour: | ||||
| $ dnf downgrade acpi | ||||
| Package acpi of lowest version already installed, cannot downgrade it. | ||||
| Error: No packages marked for downgrade. | ||||
| 
 | ||||
| The exit code of dnf downgrade was 1 | ||||
| 
 | ||||
| New behaviour: | ||||
| $ dnf downgrade acpi | ||||
| Package acpi of lowest version already installed, cannot downgrade it. | ||||
| Dependencies resolved. | ||||
| Nothing to do. | ||||
| Complete! | ||||
| 
 | ||||
| The exit code of dnf downgrade is 0 | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1759847 | ||||
| ---
 | ||||
|  dnf/cli/cli.py | 8 +++++--- | ||||
|  1 file changed, 5 insertions(+), 3 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/cli.py b/dnf/cli/cli.py
 | ||||
| index 9fbe7d3ada..7a8d9e3b27 100644
 | ||||
| --- a/dnf/cli/cli.py
 | ||||
| +++ b/dnf/cli/cli.py
 | ||||
| @@ -401,10 +401,11 @@ def downgradePkgs(self, specs=[], file_pkgs=[], strict=False):
 | ||||
|          :param file_pkgs: a list of pkg objects from local files | ||||
|          """ | ||||
|   | ||||
| -        oldcount = self._goal.req_length()
 | ||||
| +        result = False
 | ||||
|          for pkg in file_pkgs: | ||||
|              try: | ||||
|                  self.package_downgrade(pkg, strict=strict) | ||||
| +                result = True
 | ||||
|              except dnf.exceptions.MarkingError as e: | ||||
|                  logger.info(_('No match for argument: %s'), | ||||
|                              self.output.term.bold(pkg.location)) | ||||
| @@ -412,6 +413,7 @@ def downgradePkgs(self, specs=[], file_pkgs=[], strict=False):
 | ||||
|          for arg in specs: | ||||
|              try: | ||||
|                  self.downgrade_to(arg, strict=strict) | ||||
| +                result = True
 | ||||
|              except dnf.exceptions.PackageNotFoundError as err: | ||||
|                  msg = _('No package %s available.') | ||||
|                  logger.info(msg, self.output.term.bold(arg)) | ||||
| @@ -420,8 +422,8 @@ def downgradePkgs(self, specs=[], file_pkgs=[], strict=False):
 | ||||
|                              self.output.term.bold(err.pkg_spec)) | ||||
|              except dnf.exceptions.MarkingError: | ||||
|                  assert False | ||||
| -        cnt = self._goal.req_length() - oldcount
 | ||||
| -        if cnt <= 0:
 | ||||
| +
 | ||||
| +        if not result:
 | ||||
|              raise dnf.exceptions.Error(_('No packages marked for downgrade.')) | ||||
|   | ||||
|      def output_packages(self, basecmd, pkgnarrow='all', patterns=(), reponame=None): | ||||
| @ -1,125 +0,0 @@ | ||||
| From ee670a94b7f53716ac8db4a7ee1723d886378d6f Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Mracek <jmracek@redhat.com> | ||||
| Date: Fri, 22 Nov 2019 18:24:37 +0100 | ||||
| Subject: [PATCH 1/3] Restore functionality of remove --oldinstallonly | ||||
| 
 | ||||
| Additionally it also starts to protect running kernel. | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1774666 | ||||
| ---
 | ||||
|  dnf/cli/commands/remove.py | 10 ++++++++-- | ||||
|  1 file changed, 8 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/commands/remove.py b/dnf/cli/commands/remove.py
 | ||||
| index f8059e4634..7b53dafcc4 100644
 | ||||
| --- a/dnf/cli/commands/remove.py
 | ||||
| +++ b/dnf/cli/commands/remove.py
 | ||||
| @@ -110,8 +110,14 @@ def run(self):
 | ||||
|   | ||||
|          if self.opts.oldinstallonly: | ||||
|              q = self.base.sack.query() | ||||
| -            instonly = self.base._get_installonly_query(q.installed()).latest(
 | ||||
| -                - self.base.conf.installonly_limit)
 | ||||
| +            instonly = self.base._get_installonly_query(q.installed()).latest(-1)
 | ||||
| +            # also remove running kernel from the set
 | ||||
| +            kernel = self.base.sack.get_running_kernel()
 | ||||
| +            if kernel is not None:
 | ||||
| +                running_installonly = instonly.filter(
 | ||||
| +                    epoch=kernel.epoch, version=kernel.version, release=kernel.release)
 | ||||
| +                if running_installonly:
 | ||||
| +                    instonly = instonly.difference(running_installonly)
 | ||||
|              if instonly: | ||||
|                  for pkg in instonly: | ||||
|                      self.base.package_remove(pkg) | ||||
| 
 | ||||
| From 031b424e3cf944f7585308ddda024ca6d2031c08 Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Mracek <jmracek@redhat.com> | ||||
| Date: Fri, 6 Dec 2019 13:50:37 +0100 | ||||
| Subject: [PATCH 2/3] Keep installed packages in upgrade transaction | ||||
| 
 | ||||
| In some cases missing installed packages could lead in an alternative | ||||
| decision. | ||||
| ---
 | ||||
|  dnf/base.py | 8 +++++--- | ||||
|  1 file changed, 5 insertions(+), 3 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/base.py b/dnf/base.py
 | ||||
| index 8091ca0366..f9d31b3f34 100644
 | ||||
| --- a/dnf/base.py
 | ||||
| +++ b/dnf/base.py
 | ||||
| @@ -1975,17 +1975,19 @@ def package_upgrade(self, pkg):
 | ||||
|              return 0 | ||||
|   | ||||
|      def _upgrade_internal(self, query, obsoletes, reponame, pkg_spec=None): | ||||
| -        installed = self.sack.query().installed()
 | ||||
| -        q = query.intersection(self.sack.query().filterm(name=[pkg.name for pkg in installed]))
 | ||||
| +        installed_all = self.sack.query().installed()
 | ||||
| +        q = query.intersection(self.sack.query().filterm(name=[pkg.name for pkg in installed_all]))
 | ||||
| +        installed_query = q.installed()
 | ||||
|          if obsoletes: | ||||
|              obsoletes = self.sack.query().available().filterm( | ||||
| -                obsoletes=q.installed().union(q.upgrades()))
 | ||||
| +                obsoletes=installed_query.union(q.upgrades()))
 | ||||
|              # add obsoletes into transaction | ||||
|              q = q.union(obsoletes) | ||||
|          if reponame is not None: | ||||
|              q.filterm(reponame=reponame) | ||||
|          q = self._merge_update_filters(q, pkg_spec=pkg_spec) | ||||
|          if q: | ||||
| +            q = q.available().union(installed_query.latest())
 | ||||
|              sltr = dnf.selector.Selector(self.sack) | ||||
|              sltr.set(pkg=q) | ||||
|              self._goal.upgrade(select=sltr) | ||||
| 
 | ||||
| From 7cba81e129944b8b610895d24df1c4dbaa23b6a1 Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Mracek <jmracek@redhat.com> | ||||
| Date: Fri, 6 Dec 2019 13:51:11 +0100 | ||||
| Subject: [PATCH 3/3] [doc] Update documentation of remove --oldinstallonly | ||||
| 
 | ||||
| ---
 | ||||
|  doc/cli_vs_yum.rst  | 18 +++++++++--------- | ||||
|  doc/command_ref.rst |  2 +- | ||||
|  2 files changed, 10 insertions(+), 10 deletions(-) | ||||
| 
 | ||||
| diff --git a/doc/cli_vs_yum.rst b/doc/cli_vs_yum.rst
 | ||||
| index 56945869c9..bb379ab03e 100644
 | ||||
| --- a/doc/cli_vs_yum.rst
 | ||||
| +++ b/doc/cli_vs_yum.rst
 | ||||
| @@ -387,15 +387,15 @@ Original YUM tool          New DNF command                                  Pack
 | ||||
|   | ||||
|  Detailed table for ``package-cleanup`` replacement: | ||||
|   | ||||
| -==================================       =====================================
 | ||||
| -``package-cleanup --dupes``              ``dnf repoquery --duplicates``
 | ||||
| -``package-cleanup --leaves``             ``dnf repoquery --unneeded``
 | ||||
| -``package-cleanup --orphans``            ``dnf repoquery --extras``
 | ||||
| -``package-cleanup --oldkernels``         ``dnf repoquery --installonly``
 | ||||
| -``package-cleanup --problems``           ``dnf repoquery --unsatisfied``
 | ||||
| -``package-cleanup --cleandupes``         ``dnf remove --duplicates``
 | ||||
| -``package-cleanup --oldkernels``         ``dnf remove --oldinstallonly``
 | ||||
| -==================================       =====================================
 | ||||
| +==========================================       ===============================================================
 | ||||
| +``package-cleanup --dupes``                      ``dnf repoquery --duplicates``
 | ||||
| +``package-cleanup --leaves``                     ``dnf repoquery --unneeded``
 | ||||
| +``package-cleanup --orphans``                    ``dnf repoquery --extras``
 | ||||
| +``package-cleanup --problems``                   ``dnf repoquery --unsatisfied``
 | ||||
| +``package-cleanup --cleandupes``                 ``dnf remove --duplicates``
 | ||||
| +``package-cleanup --oldkernels``                 ``dnf remove --oldinstallonly``
 | ||||
| +``package-cleanup --oldkernels --keep=2``        ``dnf remove $(dnf repoquery --installonly --latest-limit=-2)``
 | ||||
| +==========================================       ===============================================================
 | ||||
|   | ||||
|  ============================= | ||||
|  yum-updateonboot and yum-cron | ||||
| diff --git a/doc/command_ref.rst b/doc/command_ref.rst
 | ||||
| index 7141fc2aae..134cc3d546 100644
 | ||||
| --- a/doc/command_ref.rst
 | ||||
| +++ b/doc/command_ref.rst
 | ||||
| @@ -1061,7 +1061,7 @@ Remove Command
 | ||||
|      dnf-shell sub-commands could help. | ||||
|   | ||||
|  ``dnf [options] remove --oldinstallonly`` | ||||
| -    Removes old installonly packages, keeping only ``installonly_limit`` latest versions.
 | ||||
| +    Removes old installonly packages, keeping only latest versions and version of running kernel.
 | ||||
|   | ||||
|      There are also a few specific remove commands ``remove-n``, ``remove-na`` and ``remove-nevra`` | ||||
|      that allow the specification of an exact argument in the NEVRA format. | ||||
| @ -1,111 +0,0 @@ | ||||
| From 2e78e3006ca8b640028b98afd2ccaa5d26ead7e3 Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Mracek <jmracek@redhat.com> | ||||
| Date: Tue, 3 Dec 2019 09:09:20 +0100 | ||||
| Subject: [PATCH 1/3] [doc] Add note about limitation of the shell command | ||||
| 
 | ||||
| ---
 | ||||
|  doc/command_ref.rst | 5 +++++ | ||||
|  1 file changed, 5 insertions(+) | ||||
| 
 | ||||
| diff --git a/doc/command_ref.rst b/doc/command_ref.rst
 | ||||
| index 24e08efdb2..cc27f57bba 100644
 | ||||
| --- a/doc/command_ref.rst
 | ||||
| +++ b/doc/command_ref.rst
 | ||||
| @@ -1515,6 +1515,11 @@ Shell Command
 | ||||
|          * reset: reset the transaction | ||||
|          * run: resolve and run the transaction | ||||
|   | ||||
| +    Note that all local packages must be used in the first shell transaction subcommand (e.g.
 | ||||
| +    `install /tmp/nodejs-1-1.x86_64.rpm /tmp/acpi-1-1.noarch.rpm`) otherwise an error will occur.
 | ||||
| +    Any `disable`, `enable`, and `reset` module operations (e.g. `module enable nodejs`) must also
 | ||||
| +    be performed before any other shell transaction subcommand is used.
 | ||||
| +
 | ||||
|  .. _swap_command-label: | ||||
|   | ||||
|  ------------ | ||||
| 
 | ||||
| From 9e1958f3695b50f3c49f9aa2a8a113bbf660d62c Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Mracek <jmracek@redhat.com> | ||||
| Date: Tue, 3 Dec 2019 09:31:49 +0100 | ||||
| Subject: [PATCH 2/3] Prevent adding remote packages when goal is not empty | ||||
|  (RhBug:1773483) | ||||
| 
 | ||||
| Adding remote packages by add_remote_rpms() when goal is not empty | ||||
| results in transaction that is completely broken, because elements in | ||||
| transaction get different meaning. | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1773483 | ||||
| ---
 | ||||
|  dnf/base.py        | 3 +++ | ||||
|  tests/test_base.py | 1 + | ||||
|  2 files changed, 4 insertions(+) | ||||
| 
 | ||||
| diff --git a/dnf/base.py b/dnf/base.py
 | ||||
| index 8091ca0366..c4ea04181a 100644
 | ||||
| --- a/dnf/base.py
 | ||||
| +++ b/dnf/base.py
 | ||||
| @@ -1162,6 +1162,9 @@ def add_remote_rpms(self, path_list, strict=True, progress=None):
 | ||||
|          pkgs = [] | ||||
|          if not path_list: | ||||
|              return pkgs | ||||
| +        if self._goal.req_length():
 | ||||
| +            raise dnf.exceptions.Error(
 | ||||
| +                _("Cannot add local packages, because transaction job already exists"))
 | ||||
|          pkgs_error = [] | ||||
|          for path in path_list: | ||||
|              if not os.path.exists(path) and '://' in path: | ||||
| diff --git a/tests/test_base.py b/tests/test_base.py
 | ||||
| index 0d50516d2f..8f807b7c13 100644
 | ||||
| --- a/tests/test_base.py
 | ||||
| +++ b/tests/test_base.py
 | ||||
| @@ -168,6 +168,7 @@ class MockBaseTest(tests.support.DnfBaseTestCase):
 | ||||
|      """Test the Base methods that need a Sack.""" | ||||
|   | ||||
|      REPOS = ["main"] | ||||
| +    INIT_SACK = True
 | ||||
|   | ||||
|      def test_add_remote_rpms(self): | ||||
|          pkgs = self.base.add_remote_rpms([tests.support.TOUR_50_PKG_PATH]) | ||||
| 
 | ||||
| From 575ef19433909d3bf7d90e5e4b36f912a472b517 Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Mracek <jmracek@redhat.com> | ||||
| Date: Wed, 4 Dec 2019 13:17:26 +0100 | ||||
| Subject: [PATCH 3/3] [doc] Describe the new behavior of Base.add_remote_rpms() | ||||
| 
 | ||||
| ---
 | ||||
|  doc/api_base.rst | 15 ++++++++++----- | ||||
|  1 file changed, 10 insertions(+), 5 deletions(-) | ||||
| 
 | ||||
| diff --git a/doc/api_base.rst b/doc/api_base.rst
 | ||||
| index 5fd5b4cc99..618886d0cd 100644
 | ||||
| --- a/doc/api_base.rst
 | ||||
| +++ b/doc/api_base.rst
 | ||||
| @@ -33,6 +33,10 @@
 | ||||
|   | ||||
|      An instance of :class:`dnf.conf.Conf`, concentrates all the different configuration options. :meth:`__init__` initializes this to usable defaults. | ||||
|   | ||||
| +  .. attribute:: goal
 | ||||
| +
 | ||||
| +    An instance of :class:`dnf.goal.Goal` that this :class:`Base<dnf.Base>` object is using.
 | ||||
| +
 | ||||
|    .. attribute:: repos | ||||
|   | ||||
|      A :class:`dnf.repodict.RepoDict` instance, this member object contains all the repositories available. | ||||
| @@ -51,11 +55,12 @@
 | ||||
|   | ||||
|    .. method:: add_remote_rpms(path_list, strict=True, progress=None) | ||||
|   | ||||
| -    Add RPM files at list `path_list` to the :attr:`sack` and return the list of respective
 | ||||
| -    :class:`dnf.package.Package` instances. Does the download to a temporary files for each path if
 | ||||
| -    `path` is a remote URL. Raises :exc:`IOError` if there are problems obtaining during reading
 | ||||
| -    files and `strict=True`. `progress`, if given, should be a :class:`.DownloadProgress` and can be
 | ||||
| -    used by the caller to monitor the progress of the download.
 | ||||
| +    This function must be called before anything is added to the :attr:`goal`. Adds RPM files
 | ||||
| +    in path_list to the :attr:`sack` and return the list of respective :class:`dnf.package.Package`
 | ||||
| +    instances. Downloads the RPMs to a temporary file for each path if it is a remote URL.
 | ||||
| +    Raises :exc:`IOError` if there are `IO` problems with files and `strict=True`. Raises
 | ||||
| +    :exc:`dnf.exceptions.Error` if the :attr:`goal` is not empty. `progress`, if given, should be a
 | ||||
| +    :class:`.DownloadProgress` instance which can be used to monitor the progress of the download.
 | ||||
|   | ||||
|    .. method:: close() | ||||
|   | ||||
| @ -1,115 +0,0 @@ | ||||
| From 27d2957e5051cc2edbea3a0d28a630e7eabfd673 Mon Sep 17 00:00:00 2001 | ||||
| From: Marek Blaha <mblaha@redhat.com> | ||||
| Date: Fri, 6 Dec 2019 09:19:11 +0100 | ||||
| Subject: [PATCH] Improve help for 'dnf module' command (RhBug:1758447) | ||||
| 
 | ||||
| Added short summary for each subcommand of the 'dnf module' command. | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1758447 | ||||
| ---
 | ||||
|  dnf/cli/commands/module.py | 22 ++++++++++++++++++---- | ||||
|  1 file changed, 18 insertions(+), 4 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/commands/module.py b/dnf/cli/commands/module.py
 | ||||
| index 07883af6a3..5a6c0069fb 100644
 | ||||
| --- a/dnf/cli/commands/module.py
 | ||||
| +++ b/dnf/cli/commands/module.py
 | ||||
| @@ -74,6 +74,7 @@ def _get_module_artifact_names(self, use_modules, skip_modules):
 | ||||
|      class ListSubCommand(SubCommand): | ||||
|   | ||||
|          aliases = ('list',) | ||||
| +        summary = _('list all module streams, profiles and states')
 | ||||
|   | ||||
|          def configure(self): | ||||
|              demands = self.cli.demands | ||||
| @@ -107,6 +108,7 @@ def run_on_module(self):
 | ||||
|      class InfoSubCommand(SubCommand): | ||||
|   | ||||
|          aliases = ('info',) | ||||
| +        summary = _('print detailed information about a module')
 | ||||
|   | ||||
|          def configure(self): | ||||
|              demands = self.cli.demands | ||||
| @@ -128,6 +130,7 @@ def run_on_module(self):
 | ||||
|      class EnableSubCommand(SubCommand): | ||||
|   | ||||
|          aliases = ('enable',) | ||||
| +        summary = _('enable a module stream')
 | ||||
|   | ||||
|          def configure(self): | ||||
|              demands = self.cli.demands | ||||
| @@ -151,6 +154,7 @@ def run_on_module(self):
 | ||||
|      class DisableSubCommand(SubCommand): | ||||
|   | ||||
|          aliases = ('disable',) | ||||
| +        summary = _('disable a module with all its streams')
 | ||||
|   | ||||
|          def configure(self): | ||||
|              demands = self.cli.demands | ||||
| @@ -174,6 +178,7 @@ def run_on_module(self):
 | ||||
|      class ResetSubCommand(SubCommand): | ||||
|   | ||||
|          aliases = ('reset',) | ||||
| +        summary = _('reset a module')
 | ||||
|   | ||||
|          def configure(self): | ||||
|              demands = self.cli.demands | ||||
| @@ -194,6 +199,7 @@ def run_on_module(self):
 | ||||
|      class InstallSubCommand(SubCommand): | ||||
|   | ||||
|          aliases = ('install',) | ||||
| +        summary = _('install a module profile including its packages')
 | ||||
|   | ||||
|          def configure(self): | ||||
|              demands = self.cli.demands | ||||
| @@ -214,6 +220,7 @@ def run_on_module(self):
 | ||||
|      class UpdateSubCommand(SubCommand): | ||||
|   | ||||
|          aliases = ('update',) | ||||
| +        summary = _('update packages associated with an active stream')
 | ||||
|   | ||||
|          def configure(self): | ||||
|              demands = self.cli.demands | ||||
| @@ -230,6 +237,7 @@ def run_on_module(self):
 | ||||
|      class RemoveSubCommand(SubCommand): | ||||
|   | ||||
|          aliases = ('remove', 'erase',) | ||||
| +        summary = _('remove installed module profiles and their packages')
 | ||||
|   | ||||
|          def configure(self): | ||||
|              demands = self.cli.demands | ||||
| @@ -266,6 +274,7 @@ def run_on_module(self):
 | ||||
|      class ProvidesSubCommand(SubCommand): | ||||
|   | ||||
|          aliases = ("provides", ) | ||||
| +        summary = _('list modular packages')
 | ||||
|   | ||||
|          def configure(self): | ||||
|              demands = self.cli.demands | ||||
| @@ -280,6 +289,7 @@ def run_on_module(self):
 | ||||
|      class RepoquerySubCommand(SubCommand): | ||||
|   | ||||
|          aliases = ("repoquery", ) | ||||
| +        summary = _('list packages belonging to a module')
 | ||||
|   | ||||
|          def configure(self): | ||||
|              demands = self.cli.demands | ||||
| @@ -342,10 +352,14 @@ def set_argparser(self, parser):
 | ||||
|          narrows.add_argument('--all', dest='all', | ||||
|                               action='store_true', | ||||
|                               help=_("remove all modular packages")) | ||||
| -
 | ||||
| -        subcommand_help = [subcmd.aliases[0] for subcmd in self.SUBCMDS]
 | ||||
| -        parser.add_argument('subcmd', nargs=1, choices=subcommand_help,
 | ||||
| -                            help=_("Modular command"))
 | ||||
| +        subcommand_choices = []
 | ||||
| +        subcommand_help = []
 | ||||
| +        for subcmd in sorted(self.SUBCMDS, key=lambda x: x.aliases[0]):
 | ||||
| +            subcommand_choices.append(subcmd.aliases[0])
 | ||||
| +            subcommand_help.append('{}: {}'.format(subcmd.aliases[0], subcmd.summary or ''))
 | ||||
| +        parser.add_argument('subcmd', nargs=1, choices=subcommand_choices,
 | ||||
| +                            metavar='<modular command>',
 | ||||
| +                            help='\n'.join(subcommand_help))
 | ||||
|          parser.add_argument('module_spec', metavar='module-spec', nargs='*', | ||||
|                              help=_("Module specification")) | ||||
|   | ||||
| @ -1,33 +0,0 @@ | ||||
| From 32f331724cc8b473073fa0f29ad93044b1dde824 Mon Sep 17 00:00:00 2001 | ||||
| From: Brandon Bennett <bennetb@gmail.com> | ||||
| Date: Mon, 16 Dec 2019 09:37:24 -0700 | ||||
| Subject: [PATCH] Strip '\' from aliases when processing (RhBug:1680482) | ||||
| 
 | ||||
| de40e3f7e910d5533dfbcc377807caaae115ed3e reworked the alias resolution | ||||
| to detect infinate recursion, however it broke how the '\' works during | ||||
| resolution.  Before the '\\' was stripped but now it is no longer. | ||||
| 
 | ||||
| This just adds a check to see if '\\' is in the first part of the | ||||
| arguments and strips it. | ||||
| ---
 | ||||
|  dnf/cli/aliases.py | 5 +++++ | ||||
|  1 file changed, 5 insertions(+) | ||||
| 
 | ||||
| diff --git a/dnf/cli/aliases.py b/dnf/cli/aliases.py
 | ||||
| index b5283d0f33..364aab6d21 100644
 | ||||
| --- a/dnf/cli/aliases.py
 | ||||
| +++ b/dnf/cli/aliases.py
 | ||||
| @@ -176,8 +176,13 @@ def subresolve(args):
 | ||||
|                      suffix[0].startswith('\\')):  # End resolving | ||||
|                  try: | ||||
|                      stack.pop() | ||||
| +
 | ||||
| +                    # strip the '\' if it exists
 | ||||
| +                    if suffix[0].startswith('\\'):
 | ||||
| +                        suffix[0] = suffix[0][1:]
 | ||||
|                  except IndexError: | ||||
|                      pass | ||||
| +
 | ||||
|                  return suffix | ||||
|   | ||||
|              if suffix[0] in stack:  # Infinite recursion detected | ||||
| @ -1,61 +0,0 @@ | ||||
| From 505e534817d076c5190b211983a8a2c930cbe560 Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Mracek <jmracek@redhat.com> | ||||
| Date: Mon, 16 Dec 2019 11:14:33 +0100 | ||||
| Subject: [PATCH] Honor priority with check-update (RhBug:1769466) | ||||
| 
 | ||||
| Check update is going to use the new query filter that honors repo | ||||
| priority. | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1769466 | ||||
| ---
 | ||||
|  dnf.spec                     | 2 +- | ||||
|  dnf/base.py                  | 4 ++-- | ||||
|  dnf/cli/commands/__init__.py | 2 +- | ||||
|  3 files changed, 4 insertions(+), 4 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf.spec b/dnf.spec
 | ||||
| index e20be1e241..57bfd778d4 100644
 | ||||
| --- a/dnf.spec
 | ||||
| +++ b/dnf.spec
 | ||||
| @@ -1,5 +1,5 @@
 | ||||
|  # default dependencies | ||||
| -%global hawkey_version 0.39.1
 | ||||
| +%global hawkey_version 0.41.0
 | ||||
|  %global libcomps_version 0.1.8 | ||||
|  %global libmodulemd_version 1.4.0 | ||||
|  %global rpm_version 4.14.0 | ||||
| diff --git a/dnf/base.py b/dnf/base.py
 | ||||
| index c4ea04181a..1ed01c37a9 100644
 | ||||
| --- a/dnf/base.py
 | ||||
| +++ b/dnf/base.py
 | ||||
| @@ -1365,7 +1365,7 @@ def query_for_repo(query):
 | ||||
|   | ||||
|          # produce the updates list of tuples | ||||
|          elif pkgnarrow == 'upgrades': | ||||
| -            updates = query_for_repo(q).upgrades()
 | ||||
| +            updates = query_for_repo(q).filterm(upgrades_by_priority=True)
 | ||||
|              # reduce a query to security upgrades if they are specified | ||||
|              updates = self._merge_update_filters(updates) | ||||
|              # reduce a query to latest packages | ||||
| @@ -1417,7 +1417,7 @@ def query_for_repo(query):
 | ||||
|          elif pkgnarrow == 'obsoletes': | ||||
|              inst = q.installed() | ||||
|              obsoletes = query_for_repo( | ||||
| -                self.sack.query()).filter(obsoletes=inst)
 | ||||
| +                self.sack.query()).filter(obsoletes_by_priority=inst)
 | ||||
|              # reduce a query to security upgrades if they are specified | ||||
|              obsoletes = self._merge_update_filters(obsoletes, warning=False) | ||||
|              obsoletesTuples = [] | ||||
| diff --git a/dnf/cli/commands/__init__.py b/dnf/cli/commands/__init__.py
 | ||||
| index 2a0726b654..d71a97f910 100644
 | ||||
| --- a/dnf/cli/commands/__init__.py
 | ||||
| +++ b/dnf/cli/commands/__init__.py
 | ||||
| @@ -279,7 +279,7 @@ def configure(self):
 | ||||
|          _checkEnabledRepo(self.base) | ||||
|   | ||||
|      def run(self): | ||||
| -        query = self.base.sack.query().upgrades()
 | ||||
| +        query = self.base.sack.query().filterm(upgrades_by_priority=True)
 | ||||
|          if self.base.conf.obsoletes: | ||||
|              obsoleted = query.union(self.base.sack.query().installed()) | ||||
|              obsoletes = self.base.sack.query().filter(obsoletes=obsoleted) | ||||
| @ -1,50 +0,0 @@ | ||||
| From f89ac56ef0ee7a349e0389913a510ba194022e95 Mon Sep 17 00:00:00 2001 | ||||
| From: Pavla Kratochvilova <pkratoch@redhat.com> | ||||
| Date: Thu, 23 May 2019 14:32:32 +0200 | ||||
| Subject: [PATCH 1/2] Print the whole alias definition in case of infinite | ||||
|  recursion (RhBug:1680488) | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1680488 | ||||
| ---
 | ||||
|  dnf/cli/commands/alias.py | 3 ++- | ||||
|  1 file changed, 2 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/commands/alias.py b/dnf/cli/commands/alias.py
 | ||||
| index 10f58867ca..d3e6e4326e 100644
 | ||||
| --- a/dnf/cli/commands/alias.py
 | ||||
| +++ b/dnf/cli/commands/alias.py
 | ||||
| @@ -151,7 +151,8 @@ def list_alias(self, cmd):
 | ||||
|          try: | ||||
|              args = self.aliases_base._resolve(args) | ||||
|          except dnf.exceptions.Error as e: | ||||
| -            logger.error(_('%s, alias %s'), e, cmd)
 | ||||
| +            logger.error(
 | ||||
| +                _('%s, alias %s="%s"'), e, cmd, (' ').join(self.aliases_base.aliases[cmd]))
 | ||||
|          else: | ||||
|              print(_("Alias %s='%s'") % (cmd, " ".join(args))) | ||||
|   | ||||
| 
 | ||||
| From ccd4213da366d49f6f84847fa2ccdb890d257930 Mon Sep 17 00:00:00 2001 | ||||
| From: Pavla Kratochvilova <pkratoch@redhat.com> | ||||
| Date: Thu, 23 May 2019 14:39:19 +0200 | ||||
| Subject: [PATCH 2/2] [doc] Document aliases behavior in case of infinite | ||||
|  recursion (RhBug:1680488) | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1680488 | ||||
| ---
 | ||||
|  doc/command_ref.rst | 2 ++ | ||||
|  1 file changed, 2 insertions(+) | ||||
| 
 | ||||
| diff --git a/doc/command_ref.rst b/doc/command_ref.rst
 | ||||
| index ba22453055..ab72b66f8f 100644
 | ||||
| --- a/doc/command_ref.rst
 | ||||
| +++ b/doc/command_ref.rst
 | ||||
| @@ -423,6 +423,8 @@ To use an alias (name=value), the name must be placed as the first "command" (e.
 | ||||
|  that is not an option). It is then replaced by its value and the resulting sequence is again searched | ||||
|  for aliases. The alias processing stops when the first found command is not a name of any alias. | ||||
|   | ||||
| +In case the processing would result in an infinite recursion, the original arguments are used instead.
 | ||||
| +
 | ||||
|  Also, like in shell aliases, if the result starts with a ``\``, the alias processing will stop. | ||||
|   | ||||
|  All aliases are defined in configuration files in the ``/etc/dnf/aliases.d/`` directory in the [aliases] section, | ||||
| @ -1,32 +0,0 @@ | ||||
| From 3a332e3eba6230d7da7472db654d50b8070570d8 Mon Sep 17 00:00:00 2001 | ||||
| From: Pavla Kratochvilova <pkratoch@redhat.com> | ||||
| Date: Thu, 23 May 2019 11:07:37 +0200 | ||||
| Subject: [PATCH] [doc] Explain the backslash notation also near the example | ||||
|  (RhBug:1680482) | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1680482 | ||||
| The backslash notation is mentioned before, but this adds an explanation | ||||
| directly to the example where it is used. | ||||
| ---
 | ||||
|  doc/command_ref.rst | 6 ++++-- | ||||
|  1 file changed, 4 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/doc/command_ref.rst b/doc/command_ref.rst
 | ||||
| index ba22453055..84bad4b2b3 100644
 | ||||
| --- a/doc/command_ref.rst
 | ||||
| +++ b/doc/command_ref.rst
 | ||||
| @@ -454,10 +454,12 @@ Alias Examples
 | ||||
|      Lists all defined aliases. | ||||
|   | ||||
|  ``dnf alias add rm=remove`` | ||||
| -    Adds new alias command called "rm" which does the same thing as the command "remove".
 | ||||
| +    Adds a new command alias called ``rm`` which works the same as the ``remove`` command.
 | ||||
|   | ||||
|  ``dnf alias add update="\update --skip-broken --disableexcludes=all --obsoletes"`` | ||||
| -    Adds new alias command called "update" which does the same thing as the command "update", but with options ``--skip-broken --disableexcludes=all --obsoletes``.
 | ||||
| +    Adds a new command alias called ``update`` which works the same as the ``update`` command,
 | ||||
| +    with additional options. Note that the original ``update`` command is prefixed with a ``\``
 | ||||
| +    to prevent an infinite loop in alias processing.
 | ||||
|   | ||||
|  .. _alias_processing_examples-label: | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,82 +0,0 @@ | ||||
| From fa6afad083ffc19438603f43d17785f5741505b4 Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Rohel <jrohel@redhat.com> | ||||
| Date: Mon, 16 Dec 2019 12:52:41 +0100 | ||||
| Subject: [PATCH 1/2] Sort packages in transaction output by nevra | ||||
|  (RhBug:1773436) | ||||
| 
 | ||||
| ---
 | ||||
|  dnf/cli/output.py | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/output.py b/dnf/cli/output.py
 | ||||
| index 2ff41b6255..1d3eb1e94a 100644
 | ||||
| --- a/dnf/cli/output.py
 | ||||
| +++ b/dnf/cli/output.py
 | ||||
| @@ -1147,7 +1147,7 @@ def _add_line(lines, data, a_wid, po, obsoletes=[]):
 | ||||
|                  for i in tsi._item.getReplacedBy(): | ||||
|                      replaces.setdefault(i, set()).add(tsi) | ||||
|   | ||||
| -            for tsi in pkglist:
 | ||||
| +            for tsi in sorted(pkglist, key=lambda x: x.pkg):
 | ||||
|                  if tsi.action not in dnf.transaction.FORWARD_ACTIONS + [libdnf.transaction.TransactionItemAction_REMOVE]: | ||||
|                      continue | ||||
|   | ||||
| 
 | ||||
| From 0779b458ca30e895b72bcfb2d513c13b12f605df Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Rohel <jrohel@redhat.com> | ||||
| Date: Mon, 16 Dec 2019 14:53:00 +0100 | ||||
| Subject: [PATCH 2/2] Sort packages in post transaction output by nevra | ||||
| 
 | ||||
| ---
 | ||||
|  dnf/cli/output.py | 20 ++++++++++++++++++-- | ||||
|  1 file changed, 18 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/output.py b/dnf/cli/output.py
 | ||||
| index 1d3eb1e94a..5dc0af6f4b 100644
 | ||||
| --- a/dnf/cli/output.py
 | ||||
| +++ b/dnf/cli/output.py
 | ||||
| @@ -23,6 +23,7 @@
 | ||||
|   | ||||
|  from copy import deepcopy | ||||
|  import fnmatch | ||||
| +import functools
 | ||||
|  import hawkey | ||||
|  import itertools | ||||
|  import libdnf.transaction | ||||
| @@ -1449,11 +1450,26 @@ def _fits_in_cols(msgs, num):
 | ||||
|                  col_lens[col] *= -1 | ||||
|              return col_lens | ||||
|   | ||||
| +        def _tsi_or_pkg_nevra_cmp(item1, item2):
 | ||||
| +            """Compares two transaction items or packages by nevra.
 | ||||
| +               Used as a fallback when tsi does not contain package object.
 | ||||
| +            """
 | ||||
| +            ret = (item1.name > item2.name) - (item1.name < item2.name)
 | ||||
| +            if ret != 0:
 | ||||
| +                return ret
 | ||||
| +            nevra1 = hawkey.NEVRA(name=item1.name, epoch=item1.epoch, version=item1.version,
 | ||||
| +                                  release=item1.release, arch=item1.arch)
 | ||||
| +            nevra2 = hawkey.NEVRA(name=item2.name, epoch=item2.epoch, version=item2.version,
 | ||||
| +                                  release=item2.release, arch=item2.arch)
 | ||||
| +            ret = nevra1.evr_cmp(nevra2, self.sack)
 | ||||
| +            if ret != 0:
 | ||||
| +                return ret
 | ||||
| +            return (item1.arch > item2.arch) - (item1.arch < item2.arch)
 | ||||
| +
 | ||||
|          out = '' | ||||
|          list_bunch = _make_lists(transaction, self.base._goal) | ||||
|          skipped_conflicts, skipped_broken = self._skipped_packages(report_problems=False) | ||||
|          skipped = skipped_conflicts.union(skipped_broken) | ||||
| -        skipped = sorted(set([str(pkg) for pkg in skipped]))
 | ||||
|   | ||||
|          for (action, tsis) in [(_('Upgraded'), list_bunch.upgraded), | ||||
|                                 (_('Downgraded'), list_bunch.downgraded), | ||||
| @@ -1471,7 +1487,7 @@ def _fits_in_cols(msgs, num):
 | ||||
|                  continue | ||||
|              msgs = [] | ||||
|              out += '\n%s:\n' % action | ||||
| -            for tsi in tsis:
 | ||||
| +            for tsi in sorted(tsis, key=functools.cmp_to_key(_tsi_or_pkg_nevra_cmp)):
 | ||||
|                  msgs.append(str(tsi)) | ||||
|              for num in (8, 7, 6, 5, 4, 3, 2): | ||||
|                  cols = _fits_in_cols(msgs, num) | ||||
| @ -1,57 +0,0 @@ | ||||
| From bcfb9e8998a87f5737b6dbce5edd206f56d732eb Mon Sep 17 00:00:00 2001 | ||||
| From: Jaroslav Mracek <jmracek@redhat.com> | ||||
| Date: Fri, 3 Jan 2020 10:57:59 +0100 | ||||
| Subject: [PATCH] Add support of commandline packages in repoquery | ||||
|  (RhBug:1784148) | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1784148 | ||||
| ---
 | ||||
|  dnf/cli/commands/repoquery.py | 21 +++++++++++++++++++++ | ||||
|  1 file changed, 21 insertions(+) | ||||
| 
 | ||||
| diff --git a/dnf/cli/commands/repoquery.py b/dnf/cli/commands/repoquery.py
 | ||||
| index f5cb36fe57..7334ddcd90 100644
 | ||||
| --- a/dnf/cli/commands/repoquery.py
 | ||||
| +++ b/dnf/cli/commands/repoquery.py
 | ||||
| @@ -402,6 +402,20 @@ def _get_recursive_providers_query(self, query_in, providers, done=None):
 | ||||
|              done = self._get_recursive_providers_query(query_in, query_select, done=t.union(done)) | ||||
|          return t.union(done) | ||||
|   | ||||
| +    def _add_add_remote_packages(self):
 | ||||
| +        rpmnames = []
 | ||||
| +        remote_packages = []
 | ||||
| +        for key in self.opts.key:
 | ||||
| +            schemes = dnf.pycomp.urlparse.urlparse(key)[0]
 | ||||
| +            if key.endswith('.rpm'):
 | ||||
| +                rpmnames.append(key)
 | ||||
| +            elif schemes and schemes in ('http', 'ftp', 'file', 'https'):
 | ||||
| +                rpmnames.append(key)
 | ||||
| +        if rpmnames:
 | ||||
| +            remote_packages = self.base.add_remote_rpms(
 | ||||
| +                rpmnames, strict=False, progress=self.base.output.progress)
 | ||||
| +        return remote_packages
 | ||||
| +
 | ||||
|      def run(self): | ||||
|          if self.opts.querytags: | ||||
|              print(_('Available query-tags: use --queryformat ".. %{tag} .."')) | ||||
| @@ -416,6 +430,8 @@ def run(self):
 | ||||
|              else hawkey.APPLY_EXCLUDES | ||||
|          ) | ||||
|          if self.opts.key: | ||||
| +            remote_packages = self._add_add_remote_packages()
 | ||||
| +
 | ||||
|              kwark = {} | ||||
|              forms = [self.nevra_forms[command] for command in self.opts.command | ||||
|                       if command in list(self.nevra_forms.keys())] | ||||
| @@ -423,6 +439,11 @@ def run(self):
 | ||||
|                  kwark["forms"] = forms | ||||
|              pkgs = [] | ||||
|              query_results = q.filter(empty=True) | ||||
| +
 | ||||
| +            if remote_packages:
 | ||||
| +                query_results = query_results.union(
 | ||||
| +                    self.base.sack.query().filterm(pkg=remote_packages))
 | ||||
| +
 | ||||
|              for key in self.opts.key: | ||||
|                  query_results = query_results.union( | ||||
|                      dnf.subject.Subject(key, ignore_case=True).get_best_query( | ||||
| @ -1,26 +0,0 @@ | ||||
| From 8df2ca3485b0c758d2030b096ecc6acac0d2d462 Mon Sep 17 00:00:00 2001 | ||||
| From: nsella <nsella@redhat.com> | ||||
| Date: Thu, 9 Jan 2020 11:13:48 +0100 | ||||
| Subject: [PATCH] Add doc entry: include url (RhBug 1786072) | ||||
| 
 | ||||
| ---
 | ||||
|  doc/cli_vs_yum.rst | 6 ++++++ | ||||
|  1 file changed, 6 insertions(+) | ||||
| 
 | ||||
| diff --git a/doc/cli_vs_yum.rst b/doc/cli_vs_yum.rst
 | ||||
| index 5c03b598f3..199ef2fefb 100644
 | ||||
| --- a/doc/cli_vs_yum.rst
 | ||||
| +++ b/doc/cli_vs_yum.rst
 | ||||
| @@ -93,6 +93,12 @@ following will work::
 | ||||
|   | ||||
|  ``include`` directive name of [main] and Repo configuration is a more logical and better named counterpart of ``exclude`` in DNF. | ||||
|   | ||||
| +=======================================
 | ||||
| +The ``include`` option has been removed
 | ||||
| +=======================================
 | ||||
| +
 | ||||
| +Inclusion of other configuration files in the main configuration file is no longer supported.
 | ||||
| +
 | ||||
|  ==================================================== | ||||
|  ``dnf provides /bin/<file>`` is not fully supported | ||||
|  ==================================================== | ||||
| @ -1,138 +0,0 @@ | ||||
| From 9d19491f52cad798ce995f3f8d1c13e2dc54cb0c Mon Sep 17 00:00:00 2001 | ||||
| From: Marek Blaha <mblaha@redhat.com> | ||||
| Date: Sun, 12 Jan 2020 15:52:16 +0100 | ||||
| Subject: [PATCH 1/2] Split loggers setup so that file loggers could be set | ||||
|  separately | ||||
| 
 | ||||
| ---
 | ||||
|  dnf/logging.py | 46 +++++++++++++++++++++++++++++++--------------- | ||||
|  1 file changed, 31 insertions(+), 15 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/logging.py b/dnf/logging.py
 | ||||
| index df355efa57..bd660470a3 100644
 | ||||
| --- a/dnf/logging.py
 | ||||
| +++ b/dnf/logging.py
 | ||||
| @@ -132,12 +132,14 @@ def _paint_mark(logger):
 | ||||
|  class Logging(object): | ||||
|      def __init__(self): | ||||
|          self.stdout_handler = self.stderr_handler = None | ||||
| -
 | ||||
| -    @only_once
 | ||||
| -    def _presetup(self):
 | ||||
|          logging.addLevelName(DDEBUG, "DDEBUG") | ||||
|          logging.addLevelName(SUBDEBUG, "SUBDEBUG") | ||||
|          logging.addLevelName(TRACE, "TRACE") | ||||
| +        logging.captureWarnings(True)
 | ||||
| +        logging.raiseExceptions = False
 | ||||
| +
 | ||||
| +    @only_once
 | ||||
| +    def _presetup(self):
 | ||||
|          logger_dnf = logging.getLogger("dnf") | ||||
|          logger_dnf.setLevel(TRACE) | ||||
|   | ||||
| @@ -155,24 +157,19 @@ def _presetup(self):
 | ||||
|          self.stderr_handler = stderr | ||||
|   | ||||
|      @only_once | ||||
| -    def _setup(self, verbose_level, error_level, logdir, log_size, log_rotate):
 | ||||
| -        self._presetup()
 | ||||
| +    def _setup_file_loggers(self, verbose_level, logdir, log_size, log_rotate):
 | ||||
|          logger_dnf = logging.getLogger("dnf") | ||||
| +        logger_dnf.setLevel(TRACE)
 | ||||
|   | ||||
|          # setup file logger | ||||
|          logfile = os.path.join(logdir, dnf.const.LOG) | ||||
|          handler = _create_filehandler(logfile, log_size, log_rotate) | ||||
|          logger_dnf.addHandler(handler) | ||||
| -        # temporarily turn off stdout/stderr handlers:
 | ||||
| -        self.stdout_handler.setLevel(SUPERCRITICAL)
 | ||||
| -        self.stderr_handler.setLevel(SUPERCRITICAL)
 | ||||
|          # put the marker in the file now: | ||||
|          _paint_mark(logger_dnf) | ||||
|   | ||||
|          # setup Python warnings | ||||
| -        logging.captureWarnings(True)
 | ||||
|          logger_warnings = logging.getLogger("py.warnings") | ||||
| -        logger_warnings.addHandler(self.stderr_handler)
 | ||||
|          logger_warnings.addHandler(handler) | ||||
|   | ||||
|          lr_logfile = os.path.join(logdir, dnf.const.LOG_LIBREPO) | ||||
| @@ -184,22 +181,41 @@ def _setup(self, verbose_level, error_level, logdir, log_size, log_rotate):
 | ||||
|          logger_rpm.setLevel(SUBDEBUG) | ||||
|          logfile = os.path.join(logdir, dnf.const.LOG_RPM) | ||||
|          handler = _create_filehandler(logfile, log_size, log_rotate) | ||||
| -        logger_rpm.addHandler(self.stdout_handler)
 | ||||
| -        logger_rpm.addHandler(self.stderr_handler)
 | ||||
|          logger_rpm.addHandler(handler) | ||||
|          _paint_mark(logger_rpm) | ||||
| +
 | ||||
| +    @only_once
 | ||||
| +    def _setup(self, verbose_level, error_level, logdir, log_size, log_rotate):
 | ||||
| +        self._presetup()
 | ||||
| +
 | ||||
| +        # temporarily turn off stdout/stderr handlers:
 | ||||
| +        self.stdout_handler.setLevel(SUPERCRITICAL)
 | ||||
| +        self.stderr_handler.setLevel(SUPERCRITICAL)
 | ||||
| +
 | ||||
| +        self._setup_file_loggers(verbose_level, logdir, log_size, log_rotate)
 | ||||
| +
 | ||||
| +        logger_warnings = logging.getLogger("py.warnings")
 | ||||
| +        logger_warnings.addHandler(self.stderr_handler)
 | ||||
| +
 | ||||
| +        # setup RPM callbacks logger
 | ||||
| +        logger_rpm = logging.getLogger("dnf.rpm")
 | ||||
| +        logger_rpm.addHandler(self.stdout_handler)
 | ||||
| +        logger_rpm.addHandler(self.stderr_handler)
 | ||||
| +
 | ||||
|          # bring std handlers to the preferred level | ||||
|          self.stdout_handler.setLevel(verbose_level) | ||||
|          self.stderr_handler.setLevel(error_level) | ||||
| -        logging.raiseExceptions = False
 | ||||
|   | ||||
| -    def _setup_from_dnf_conf(self, conf):
 | ||||
| +    def _setup_from_dnf_conf(self, conf, file_loggers_only=False):
 | ||||
|          verbose_level_r = _cfg_verbose_val2level(conf.debuglevel) | ||||
|          error_level_r = _cfg_err_val2level(conf.errorlevel) | ||||
|          logdir = conf.logdir | ||||
|          log_size = conf.log_size | ||||
|          log_rotate = conf.log_rotate | ||||
| -        return self._setup(verbose_level_r, error_level_r, logdir, log_size, log_rotate)
 | ||||
| +        if file_loggers_only:
 | ||||
| +            return self._setup_file_loggers(verbose_level_r, logdir, log_size, log_rotate)
 | ||||
| +        else:
 | ||||
| +            return self._setup(verbose_level_r, error_level_r, logdir, log_size, log_rotate)
 | ||||
|   | ||||
|   | ||||
|  class Timer(object): | ||||
| 
 | ||||
| From e43eaba4148446523eaf3e8ff1549c7576d00f1c Mon Sep 17 00:00:00 2001 | ||||
| From: Marek Blaha <mblaha@redhat.com> | ||||
| Date: Sun, 12 Jan 2020 15:53:09 +0100 | ||||
| Subject: [PATCH 2/2] New API function base.setup_loggers() (RhBug:1788212) | ||||
| 
 | ||||
| Gives API users ability to setup DNF loggers. | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1788212 | ||||
| ---
 | ||||
|  dnf/base.py | 8 ++++++++ | ||||
|  1 file changed, 8 insertions(+) | ||||
| 
 | ||||
| diff --git a/dnf/base.py b/dnf/base.py
 | ||||
| index b2c17bba30..56a9dfb478 100644
 | ||||
| --- a/dnf/base.py
 | ||||
| +++ b/dnf/base.py
 | ||||
| @@ -2536,6 +2536,14 @@ def _raise_package_not_installed_error(self, pkg_spec, forms, reponame):
 | ||||
|              msg = _('All matches were filtered out by exclude filtering for argument') | ||||
|          raise dnf.exceptions.PackagesNotInstalledError(msg, pkg_spec) | ||||
|   | ||||
| +    def setup_loggers(self):
 | ||||
| +        # :api
 | ||||
| +        """
 | ||||
| +        Setup DNF file loggers based on given configuration file. The loggers are set the same
 | ||||
| +        way as if DNF was run from CLI.
 | ||||
| +        """
 | ||||
| +        self._logging._setup_from_dnf_conf(self.conf, file_loggers_only=True)
 | ||||
| +
 | ||||
|   | ||||
|  def _msg_installed(pkg): | ||||
|      name = ucd(pkg) | ||||
| @ -1,441 +0,0 @@ | ||||
| From bfd04883c44ad31407f0b5a48e06fa597c46d727 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com> | ||||
| Date: Fri, 12 Jul 2019 17:14:00 +0200 | ||||
| Subject: [PATCH 1/6] repoquery: move the alldeps/exactdeps check to | ||||
|  configure() | ||||
| 
 | ||||
| Moves the check for alldeps/exactdeps switches to the configure() method | ||||
| along with the other checks. | ||||
| 
 | ||||
| Raises dnf.cli.CliError instead of dnf.exceptions.Error. | ||||
| ---
 | ||||
|  dnf/cli/commands/repoquery.py | 10 ++++++---- | ||||
|  1 file changed, 6 insertions(+), 4 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/commands/repoquery.py b/dnf/cli/commands/repoquery.py
 | ||||
| index 7334ddcd90..dc09bf4403 100644
 | ||||
| --- a/dnf/cli/commands/repoquery.py
 | ||||
| +++ b/dnf/cli/commands/repoquery.py
 | ||||
| @@ -303,6 +303,12 @@ def configure(self):
 | ||||
|                        "(optionally with '--alldeps', but not with '--exactdeps'), or with " | ||||
|                        "'--requires <REQ> --resolve'")) | ||||
|   | ||||
| +        if self.opts.alldeps or self.opts.exactdeps:
 | ||||
| +            if not (self.opts.whatrequires or self.opts.whatdepends):
 | ||||
| +                raise dnf.cli.CliError(
 | ||||
| +                    _("argument {} requires --whatrequires or --whatdepends option".format(
 | ||||
| +                        '--alldeps' if self.opts.alldeps else '--exactdeps')))
 | ||||
| +
 | ||||
|          if self.opts.srpm: | ||||
|              self.base.repos.enable_source_repos() | ||||
|   | ||||
| @@ -496,10 +502,6 @@ def run(self):
 | ||||
|              else: | ||||
|                  q.filterm(file__glob=self.opts.whatprovides) | ||||
|          if self.opts.alldeps or self.opts.exactdeps: | ||||
| -            if not (self.opts.whatrequires or self.opts.whatdepends):
 | ||||
| -                raise dnf.exceptions.Error(
 | ||||
| -                    _("argument {} requires --whatrequires or --whatdepends option".format(
 | ||||
| -                        '--alldeps' if self.opts.alldeps else '--exactdeps')))
 | ||||
|              if self.opts.alldeps: | ||||
|                  q = self.by_all_deps(self.opts.whatrequires, self.opts.whatdepends, q) | ||||
|              else: | ||||
| 
 | ||||
| From d9492fef24989085011047dd561fef1dfa1e31d6 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com> | ||||
| Date: Fri, 12 Jul 2019 17:22:05 +0200 | ||||
| Subject: [PATCH 2/6] repoquery: fix calling by_all_deps() for --tree | ||||
| 
 | ||||
| Fixes a bug introduced in bd00c044, where the by_all_deps() arguments | ||||
| were changed to an array, but in tree_seed() it still passes a single | ||||
| string. | ||||
| 
 | ||||
| Untested, I have actually no idea what the code does there, it looks | ||||
| kind of suspect. | ||||
| ---
 | ||||
|  dnf/cli/commands/repoquery.py | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/commands/repoquery.py b/dnf/cli/commands/repoquery.py
 | ||||
| index dc09bf4403..db174b3bba 100644
 | ||||
| --- a/dnf/cli/commands/repoquery.py
 | ||||
| +++ b/dnf/cli/commands/repoquery.py
 | ||||
| @@ -674,7 +674,7 @@ def tree_seed(self, query, aquery, opts, level=-1, usedpkgs=None):
 | ||||
|                              ar[querypkg.name + "." + querypkg.arch] = querypkg | ||||
|                      pkgquery = self.base.sack.query().filterm(pkg=list(ar.values())) | ||||
|                  else: | ||||
| -                    pkgquery = self.by_all_deps(pkg.name, None, aquery) if opts.alldeps \
 | ||||
| +                    pkgquery = self.by_all_deps((pkg.name, ), None, aquery) if opts.alldeps \
 | ||||
|                          else aquery.filter(requires__glob=pkg.name) | ||||
|                  self.tree_seed(pkgquery, aquery, opts, level + 1, usedpkgs) | ||||
|   | ||||
| 
 | ||||
| From f2f31452876b37b54150cba1bf08fc46ecaf72f2 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com> | ||||
| Date: Fri, 12 Jul 2019 17:44:38 +0200 | ||||
| Subject: [PATCH 3/6] repoquery: simplify handling of whatrequires and | ||||
|  whatdepends | ||||
| 
 | ||||
| Separates whatrequires and whatdepends handling into two separate code | ||||
| branches, the original was overly complex, confusing and presented | ||||
| multiple unnecessary corner cases. | ||||
| 
 | ||||
| The by_all_deps() arguments now also have a much better defined role. | ||||
| ---
 | ||||
|  dnf/cli/commands/repoquery.py | 59 +++++++++++++++++------------------ | ||||
|  1 file changed, 29 insertions(+), 30 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/commands/repoquery.py b/dnf/cli/commands/repoquery.py
 | ||||
| index db174b3bba..f5e951c9c8 100644
 | ||||
| --- a/dnf/cli/commands/repoquery.py
 | ||||
| +++ b/dnf/cli/commands/repoquery.py
 | ||||
| @@ -350,7 +350,7 @@ def build_format_fn(self, opts, pkg):
 | ||||
|              raise dnf.exceptions.Error(str(e)) | ||||
|   | ||||
|      def _get_recursive_deps_query(self, query_in, query_select, done=None, recursive=False, | ||||
| -                                  all_deps=False):
 | ||||
| +                                  all_dep_types=False):
 | ||||
|          done = done if done else self.base.sack.query().filterm(empty=True) | ||||
|          t = self.base.sack.query().filterm(empty=True) | ||||
|          set_requires = set() | ||||
| @@ -360,7 +360,7 @@ def _get_recursive_deps_query(self, query_in, query_select, done=None, recursive
 | ||||
|              pkg_provides = pkg.provides | ||||
|              set_requires.update(pkg_provides) | ||||
|              set_requires.update(pkg.files) | ||||
| -            if all_deps:
 | ||||
| +            if all_dep_types:
 | ||||
|                  set_all_deps.update(pkg_provides) | ||||
|   | ||||
|          t = t.union(query_in.filter(requires=set_requires)) | ||||
| @@ -373,29 +373,29 @@ def _get_recursive_deps_query(self, query_in, query_select, done=None, recursive
 | ||||
|              query_select = t.difference(done) | ||||
|              if query_select: | ||||
|                  done = self._get_recursive_deps_query(query_in, query_select, done=t.union(done), | ||||
| -                                                      recursive=recursive, all_deps=all_deps)
 | ||||
| +                                                      recursive=recursive,
 | ||||
| +                                                      all_dep_types=all_dep_types)
 | ||||
|          return t.union(done) | ||||
|   | ||||
| -    def by_all_deps(self, requires_name, depends_name, query):
 | ||||
| -        names = requires_name or depends_name
 | ||||
| +    def by_all_deps(self, names, query, all_dep_types=False):
 | ||||
|          defaultquery = self.base.sack.query().filterm(empty=True) | ||||
|          for name in names: | ||||
|              defaultquery = defaultquery.union(query.intersection( | ||||
|                  dnf.subject.Subject(name).get_best_query(self.base.sack, with_provides=False, | ||||
|                                                           with_filenames=False))) | ||||
|          requiresquery = query.filter(requires__glob=names) | ||||
| -        if depends_name:
 | ||||
| -            requiresquery = requiresquery.union(query.filter(recommends__glob=depends_name))
 | ||||
| -            requiresquery = requiresquery.union(query.filter(enhances__glob=depends_name))
 | ||||
| -            requiresquery = requiresquery.union(query.filter(supplements__glob=depends_name))
 | ||||
| -            requiresquery = requiresquery.union(query.filter(suggests__glob=depends_name))
 | ||||
| +        if all_dep_types:
 | ||||
| +            requiresquery = requiresquery.union(query.filter(recommends__glob=names))
 | ||||
| +            requiresquery = requiresquery.union(query.filter(enhances__glob=names))
 | ||||
| +            requiresquery = requiresquery.union(query.filter(supplements__glob=names))
 | ||||
| +            requiresquery = requiresquery.union(query.filter(suggests__glob=names))
 | ||||
|   | ||||
|          done = requiresquery.union(self._get_recursive_deps_query(query, defaultquery, | ||||
| -                                                                  all_deps=depends_name))
 | ||||
| +                                                                  all_dep_types=all_dep_types))
 | ||||
|          if self.opts.recursive: | ||||
|              done = done.union(self._get_recursive_deps_query(query, done, | ||||
|                                                               recursive=self.opts.recursive, | ||||
| -                                                             all_deps=depends_name))
 | ||||
| +                                                             all_dep_types=all_dep_types))
 | ||||
|          return done | ||||
|   | ||||
|      def _get_recursive_providers_query(self, query_in, providers, done=None): | ||||
| @@ -501,24 +501,23 @@ def run(self):
 | ||||
|                  q = query_for_provide | ||||
|              else: | ||||
|                  q.filterm(file__glob=self.opts.whatprovides) | ||||
| -        if self.opts.alldeps or self.opts.exactdeps:
 | ||||
| -            if self.opts.alldeps:
 | ||||
| -                q = self.by_all_deps(self.opts.whatrequires, self.opts.whatdepends, q)
 | ||||
| +
 | ||||
| +        if self.opts.whatrequires:
 | ||||
| +            if (self.opts.exactdeps):
 | ||||
| +                q.filterm(requires__glob=self.opts.whatrequires)
 | ||||
|              else: | ||||
| -                if self.opts.whatrequires:
 | ||||
| -                    q.filterm(requires__glob=self.opts.whatrequires)
 | ||||
| -                else:
 | ||||
| -                    dependsquery = q.filter(requires__glob=self.opts.whatdepends)
 | ||||
| -                    dependsquery = dependsquery.union(
 | ||||
| -                        q.filter(recommends__glob=self.opts.whatdepends))
 | ||||
| -                    dependsquery = dependsquery.union(
 | ||||
| -                        q.filter(enhances__glob=self.opts.whatdepends))
 | ||||
| -                    dependsquery = dependsquery.union(
 | ||||
| -                        q.filter(supplements__glob=self.opts.whatdepends))
 | ||||
| -                    q = dependsquery.union(q.filter(suggests__glob=self.opts.whatdepends))
 | ||||
| -
 | ||||
| -        elif self.opts.whatrequires or self.opts.whatdepends:
 | ||||
| -            q = self.by_all_deps(self.opts.whatrequires, self.opts.whatdepends, q)
 | ||||
| +                q = self.by_all_deps(self.opts.whatrequires, q)
 | ||||
| +
 | ||||
| +        if self.opts.whatdepends:
 | ||||
| +            if (self.opts.exactdeps):
 | ||||
| +                dependsquery = q.filter(requires__glob=self.opts.whatdepends)
 | ||||
| +                dependsquery = dependsquery.union(q.filter(recommends__glob=self.opts.whatdepends))
 | ||||
| +                dependsquery = dependsquery.union(q.filter(enhances__glob=self.opts.whatdepends))
 | ||||
| +                dependsquery = dependsquery.union(q.filter(supplements__glob=self.opts.whatdepends))
 | ||||
| +                q = dependsquery.union(q.filter(suggests__glob=self.opts.whatdepends))
 | ||||
| +            else:
 | ||||
| +                q = self.by_all_deps(self.opts.whatdepends, q, True)
 | ||||
| +
 | ||||
|          if self.opts.whatrecommends: | ||||
|              q.filterm(recommends__glob=self.opts.whatrecommends) | ||||
|          if self.opts.whatenhances: | ||||
| @@ -674,7 +673,7 @@ def tree_seed(self, query, aquery, opts, level=-1, usedpkgs=None):
 | ||||
|                              ar[querypkg.name + "." + querypkg.arch] = querypkg | ||||
|                      pkgquery = self.base.sack.query().filterm(pkg=list(ar.values())) | ||||
|                  else: | ||||
| -                    pkgquery = self.by_all_deps((pkg.name, ), None, aquery) if opts.alldeps \
 | ||||
| +                    pkgquery = self.by_all_deps((pkg.name, ), aquery) if opts.alldeps \
 | ||||
|                          else aquery.filter(requires__glob=pkg.name) | ||||
|                  self.tree_seed(pkgquery, aquery, opts, level + 1, usedpkgs) | ||||
|   | ||||
| 
 | ||||
| From a1bdbfa498438c2710aecd607a82face05a1bdfd Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com> | ||||
| Date: Tue, 9 Jul 2019 17:30:58 +0200 | ||||
| Subject: [PATCH 4/6] repoquery: rework "alldeps" dependency search | ||||
|  (RhBug:1534123,1698034) | ||||
| 
 | ||||
| Uses the new feature of filtering by solvables to properly resolve rich | ||||
| dependencies for packages. The new code now, along with serching for the | ||||
| arguments as reldeps, also searches for them as NEVRAs and then looks up | ||||
| the dependencies for the packages it found. | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1534123 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1698034 | ||||
| ---
 | ||||
|  dnf.spec                      |  2 +- | ||||
|  dnf/cli/commands/repoquery.py | 93 +++++++++++++++++++---------------- | ||||
|  2 files changed, 51 insertions(+), 44 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf.spec b/dnf.spec
 | ||||
| index 79e4d27dab..578baccac4 100644
 | ||||
| --- a/dnf.spec
 | ||||
| +++ b/dnf.spec
 | ||||
| @@ -1,5 +1,5 @@
 | ||||
|  # default dependencies | ||||
| -%global hawkey_version 0.41.0
 | ||||
| +%global hawkey_version 0.44.0
 | ||||
|  %global libcomps_version 0.1.8 | ||||
|  %global libmodulemd_version 1.4.0 | ||||
|  %global rpm_version 4.14.0 | ||||
| diff --git a/dnf/cli/commands/repoquery.py b/dnf/cli/commands/repoquery.py
 | ||||
| index f5e951c9c8..d86d32ffcd 100644
 | ||||
| --- a/dnf/cli/commands/repoquery.py
 | ||||
| +++ b/dnf/cli/commands/repoquery.py
 | ||||
| @@ -349,54 +349,61 @@ def build_format_fn(self, opts, pkg):
 | ||||
|              # there don't exist on the dnf Package object. | ||||
|              raise dnf.exceptions.Error(str(e)) | ||||
|   | ||||
| -    def _get_recursive_deps_query(self, query_in, query_select, done=None, recursive=False,
 | ||||
| -                                  all_dep_types=False):
 | ||||
| -        done = done if done else self.base.sack.query().filterm(empty=True)
 | ||||
| -        t = self.base.sack.query().filterm(empty=True)
 | ||||
| -        set_requires = set()
 | ||||
| -        set_all_deps = set()
 | ||||
| -
 | ||||
| -        for pkg in query_select.run():
 | ||||
| -            pkg_provides = pkg.provides
 | ||||
| -            set_requires.update(pkg_provides)
 | ||||
| -            set_requires.update(pkg.files)
 | ||||
| -            if all_dep_types:
 | ||||
| -                set_all_deps.update(pkg_provides)
 | ||||
| -
 | ||||
| -        t = t.union(query_in.filter(requires=set_requires))
 | ||||
| -        if set_all_deps:
 | ||||
| -            t = t.union(query_in.filter(recommends=set_all_deps))
 | ||||
| -            t = t.union(query_in.filter(enhances=set_all_deps))
 | ||||
| -            t = t.union(query_in.filter(supplements=set_all_deps))
 | ||||
| -            t = t.union(query_in.filter(suggests=set_all_deps))
 | ||||
| -        if recursive:
 | ||||
| -            query_select = t.difference(done)
 | ||||
| -            if query_select:
 | ||||
| -                done = self._get_recursive_deps_query(query_in, query_select, done=t.union(done),
 | ||||
| -                                                      recursive=recursive,
 | ||||
| -                                                      all_dep_types=all_dep_types)
 | ||||
| -        return t.union(done)
 | ||||
| +    def _resolve_nevras(self, nevras, base_query):
 | ||||
| +        resolved_nevras_query = self.base.sack.query().filterm(empty=True)
 | ||||
| +        for nevra in nevras:
 | ||||
| +            resolved_nevras_query = resolved_nevras_query.union(base_query.intersection(
 | ||||
| +                dnf.subject.Subject(nevra).get_best_query(
 | ||||
| +                    self.base.sack,
 | ||||
| +                    with_provides=False,
 | ||||
| +                    with_filenames=False
 | ||||
| +                )
 | ||||
| +            ))
 | ||||
| +
 | ||||
| +        return resolved_nevras_query
 | ||||
| +
 | ||||
| +    def _do_recursive_deps(self, query_in, query_select, done=None):
 | ||||
| +        done = done if done else query_select
 | ||||
| +
 | ||||
| +        query_required = query_in.filter(requires=query_select)
 | ||||
| +
 | ||||
| +        query_select = query_required.difference(done)
 | ||||
| +        done = query_required.union(done)
 | ||||
| +
 | ||||
| +        if query_select:
 | ||||
| +            done = self._do_recursive_deps(query_in, query_select, done=done)
 | ||||
| +
 | ||||
| +        return done
 | ||||
|   | ||||
|      def by_all_deps(self, names, query, all_dep_types=False): | ||||
| -        defaultquery = self.base.sack.query().filterm(empty=True)
 | ||||
| -        for name in names:
 | ||||
| -            defaultquery = defaultquery.union(query.intersection(
 | ||||
| -                dnf.subject.Subject(name).get_best_query(self.base.sack, with_provides=False,
 | ||||
| -                                                         with_filenames=False)))
 | ||||
| -        requiresquery = query.filter(requires__glob=names)
 | ||||
| +        # in case of arguments being NEVRAs, resolve them to packages
 | ||||
| +        resolved_nevras_query = self._resolve_nevras(names, query)
 | ||||
| +
 | ||||
| +        # filter the arguments directly as reldeps
 | ||||
| +        depquery = query.filter(requires__glob=names)
 | ||||
| +
 | ||||
| +        # filter the resolved NEVRAs as packages
 | ||||
| +        depquery = depquery.union(query.filter(requires=resolved_nevras_query))
 | ||||
| +
 | ||||
|          if all_dep_types: | ||||
| -            requiresquery = requiresquery.union(query.filter(recommends__glob=names))
 | ||||
| -            requiresquery = requiresquery.union(query.filter(enhances__glob=names))
 | ||||
| -            requiresquery = requiresquery.union(query.filter(supplements__glob=names))
 | ||||
| -            requiresquery = requiresquery.union(query.filter(suggests__glob=names))
 | ||||
| +            # TODO this is very inefficient, as it resolves the `names` glob to
 | ||||
| +            # reldeps four more times, which in a reasonably wide glob like
 | ||||
| +            # `dnf repoquery --whatdepends "libdnf*"` can take roughly 50% of
 | ||||
| +            # the total execution time.
 | ||||
| +            depquery = depquery.union(query.filter(recommends__glob=names))
 | ||||
| +            depquery = depquery.union(query.filter(enhances__glob=names))
 | ||||
| +            depquery = depquery.union(query.filter(supplements__glob=names))
 | ||||
| +            depquery = depquery.union(query.filter(suggests__glob=names))
 | ||||
| +
 | ||||
| +            depquery = depquery.union(query.filter(recommends=resolved_nevras_query))
 | ||||
| +            depquery = depquery.union(query.filter(enhances=resolved_nevras_query))
 | ||||
| +            depquery = depquery.union(query.filter(supplements=resolved_nevras_query))
 | ||||
| +            depquery = depquery.union(query.filter(suggests=resolved_nevras_query))
 | ||||
|   | ||||
| -        done = requiresquery.union(self._get_recursive_deps_query(query, defaultquery,
 | ||||
| -                                                                  all_dep_types=all_dep_types))
 | ||||
|          if self.opts.recursive: | ||||
| -            done = done.union(self._get_recursive_deps_query(query, done,
 | ||||
| -                                                             recursive=self.opts.recursive,
 | ||||
| -                                                             all_dep_types=all_dep_types))
 | ||||
| -        return done
 | ||||
| +            depquery = self._do_recursive_deps(query, depquery)
 | ||||
| +
 | ||||
| +        return depquery
 | ||||
|   | ||||
|      def _get_recursive_providers_query(self, query_in, providers, done=None): | ||||
|          done = done if done else self.base.sack.query().filterm(empty=True) | ||||
| 
 | ||||
| From 60cd14aae7fe3d9ae75d5e5665fc311ef3b04402 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com> | ||||
| Date: Fri, 1 Nov 2019 18:33:13 +0100 | ||||
| Subject: [PATCH 5/6] repoquery: resolve NEVRAs to packages for most of --what* | ||||
|  arguments (RhBug:1534123,1698034) | ||||
| 
 | ||||
| To properly list the conflicts, suggests, recommends, enhances and | ||||
| supplements dependencies of packages defined through provides or even | ||||
| rich dependencies, it is required to resolve them to packages and query | ||||
| for them, because that's where the dependencies are defined. | ||||
| 
 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1534123 | ||||
| https://bugzilla.redhat.com/show_bug.cgi?id=1698034 | ||||
| ---
 | ||||
|  dnf/cli/commands/repoquery.py | 16 +++++++++++----- | ||||
|  1 file changed, 11 insertions(+), 5 deletions(-) | ||||
| 
 | ||||
| diff --git a/dnf/cli/commands/repoquery.py b/dnf/cli/commands/repoquery.py
 | ||||
| index d86d32ffcd..d0521432be 100644
 | ||||
| --- a/dnf/cli/commands/repoquery.py
 | ||||
| +++ b/dnf/cli/commands/repoquery.py
 | ||||
| @@ -499,7 +499,8 @@ def run(self):
 | ||||
|          if self.opts.file: | ||||
|              q.filterm(file__glob=self.opts.file) | ||||
|          if self.opts.whatconflicts: | ||||
| -            q.filterm(conflicts=self.opts.whatconflicts)
 | ||||
| +            rels = q.filter(conflicts__glob=self.opts.whatconflicts)
 | ||||
| +            q = rels.union(q.filter(conflicts=self._resolve_nevras(self.opts.whatconflicts, q)))
 | ||||
|          if self.opts.whatobsoletes: | ||||
|              q.filterm(obsoletes=self.opts.whatobsoletes) | ||||
|          if self.opts.whatprovides: | ||||
| @@ -526,13 +527,18 @@ def run(self):
 | ||||
|                  q = self.by_all_deps(self.opts.whatdepends, q, True) | ||||
|   | ||||
|          if self.opts.whatrecommends: | ||||
| -            q.filterm(recommends__glob=self.opts.whatrecommends)
 | ||||
| +            rels = q.filter(recommends__glob=self.opts.whatrecommends)
 | ||||
| +            q = rels.union(q.filter(recommends=self._resolve_nevras(self.opts.whatrecommends, q)))
 | ||||
|          if self.opts.whatenhances: | ||||
| -            q.filterm(enhances__glob=self.opts.whatenhances)
 | ||||
| +            rels = q.filter(enhances__glob=self.opts.whatenhances)
 | ||||
| +            q = rels.union(q.filter(enhances=self._resolve_nevras(self.opts.whatenhances, q)))
 | ||||
|          if self.opts.whatsupplements: | ||||
| -            q.filterm(supplements__glob=self.opts.whatsupplements)
 | ||||
| +            rels = q.filter(supplements__glob=self.opts.whatsupplements)
 | ||||
| +            q = rels.union(q.filter(supplements=self._resolve_nevras(self.opts.whatsupplements, q)))
 | ||||
|          if self.opts.whatsuggests: | ||||
| -            q.filterm(suggests__glob=self.opts.whatsuggests)
 | ||||
| +            rels = q.filter(suggests__glob=self.opts.whatsuggests)
 | ||||
| +            q = rels.union(q.filter(suggests=self._resolve_nevras(self.opts.whatsuggests, q)))
 | ||||
| +
 | ||||
|          if self.opts.latest_limit: | ||||
|              q = q.latest(self.opts.latest_limit) | ||||
|          # reduce a query to security upgrades if they are specified | ||||
| 
 | ||||
| From 757f9ad4f26c5a0fee9a6a3620eea94dd6004a73 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hr=C3=A1zk=C3=BD?= <lhrazky@redhat.com> | ||||
| Date: Tue, 14 Jan 2020 16:44:07 +0100 | ||||
| Subject: [PATCH 6/6] [doc] Update documentation for the query filter API | ||||
| 
 | ||||
| Add the new types of arguments supported for dependency filtering. | ||||
| ---
 | ||||
|  doc/api_queries.rst | 11 ++++++++--- | ||||
|  1 file changed, 8 insertions(+), 3 deletions(-) | ||||
| 
 | ||||
| diff --git a/doc/api_queries.rst b/doc/api_queries.rst
 | ||||
| index 5c8804e52a..98907d95a6 100644
 | ||||
| --- a/doc/api_queries.rst
 | ||||
| +++ b/doc/api_queries.rst
 | ||||
| @@ -101,17 +101,20 @@
 | ||||
|      release           string         match against packages' releases | ||||
|      reponame          string         match against packages repositories' names | ||||
|      version           string         match against packages' versions | ||||
| -    obsoletes         Query          match packages that obsolete any package from query
 | ||||
|      pkg               Query          match against packages in query | ||||
|      pkg*              list           match against hawkey.Packages in list | ||||
|      provides          string         match against packages' provides | ||||
|      provides*         Hawkey.Reldep  match against packages' provides | ||||
| -    requires          string         match against packages' requirements
 | ||||
| -    requires*         Hawkey.Reldep  match against packages' requirements
 | ||||
| +    <DEP>             string         match against packages' <DEP>
 | ||||
| +    <DEP>*            Hawkey.Reldep  match a reldep against packages' <DEP>
 | ||||
| +    <DEP>*            Query          match the result of a query against packages' <DEP>
 | ||||
| +    <DEP>*            list(Package)  match the list of hawkey.Packages against packages' <DEP>
 | ||||
|      sourcerpm         string         match against packages' source rpm | ||||
|      upgrades          boolean        see :meth:`upgrades`. Defaults to ``False``. | ||||
|      ===============   ============== ====================================================== | ||||
|   | ||||
| +    ``<DEP>`` can be any of: requires, conflicts, obsoletes, enhances, recomments, suggests, supplements
 | ||||
| +
 | ||||
|      \* The key can also accept a list of values with specified type. | ||||
|   | ||||
|      The key name can be supplemented with a relation-specifying suffix, separated by ``__``: | ||||
| @@ -133,6 +136,8 @@
 | ||||
|   | ||||
|        q = base.sack.query().filter(name__substr="club") | ||||
|   | ||||
| +    Note that using packages or queries for dependency filtering performs a more advanced resolution than using a string or a reldep. When a package list or a query is used, rich dependencies are resolved in a more precise way than what is possible when a string or a reldep is used.
 | ||||
| +
 | ||||
|    .. method:: filterm(\*\*kwargs) | ||||
|   | ||||
|      Similar to :meth:`dnf.query.Query.filter` but it modifies the query in place. | ||||
							
								
								
									
										113
									
								
								SPECS/dnf.spec
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								SPECS/dnf.spec
									
									
									
									
									
								
							| @ -1,11 +1,11 @@ | ||||
| # default dependencies | ||||
| %global hawkey_version 0.39.1-6 | ||||
| %global hawkey_version 0.48.0-3 | ||||
| %global libcomps_version 0.1.8 | ||||
| %global libmodulemd_version 1.4.0 | ||||
| %global rpm_version 4.14.2-35 | ||||
| 
 | ||||
| # conflicts | ||||
| %global conflicts_dnf_plugins_core_version 4.0.12 | ||||
| %global conflicts_dnf_plugins_core_version 4.0.16 | ||||
| %global conflicts_dnf_plugins_extras_version 4.0.4 | ||||
| %global conflicts_dnfdaemon_version 0.3.19 | ||||
| 
 | ||||
| @ -81,31 +81,17 @@ | ||||
| It supports RPMs, modules and comps groups & environments. | ||||
| 
 | ||||
| Name:           dnf | ||||
| Version:        4.2.17 | ||||
| Release:        7%{?dist} | ||||
| Version:        4.2.23 | ||||
| Release:        4%{?dist} | ||||
| Summary:        %{pkg_summary} | ||||
| # For a breakdown of the licensing, see PACKAGE-LICENSING | ||||
| License:        GPLv2+ and GPLv2 and GPL | ||||
| URL:            https://github.com/rpm-software-management/dnf | ||||
| Source0:        %{url}/archive/%{version}/%{name}-%{version}.tar.gz | ||||
| Patch1:         0001-Do-a-substitution-of-variables-in-repo_id-RhBug1748841.patch | ||||
| Patch2:         0002-Fix-and-document-order-of-config-files-in-aliasesd-RhBug1680489.patch | ||||
| Patch3:         0003-doc-Remove-note-about-whitelist.patch | ||||
| Patch4:         0004-Fix-detection-of-the-latest-module-RhBug1781769.patch | ||||
| Patch5:         0005-Unify-downgrade-exit-codes-with-upgrade-RhBug1759847.patch | ||||
| Patch6:         0006-Restore-functionality-of-remove-oldinstallonly.patch | ||||
| Patch7:         0007-Shell-restriction-with-local-packages.patch | ||||
| Patch8:         0008-Improve-help-for-dnf-module-command-RhBug1758447.patch | ||||
| Patch9:         0009-Fix-alias-processing-with-backslash-escaping-RhBug1680482.patch | ||||
| Patch10:        0010-Honor-priority-with-check-update-RhBug1769466.patch | ||||
| Patch11:        0011-Better-descriptions-for-infinite-aliases-recursion-RhBug1680488.patch | ||||
| Patch12:        0012-doc-Explain-the-backslash-notation-also-near-the-example-RhBug1680482.patch | ||||
| Patch13:        0013-Update-translations-from-zanata-RhBug-1754959.patch | ||||
| Patch14:        0014-Sort-packages-in-transaction-output-by-nevra-RhBug-1773436.patch | ||||
| Patch15:        0015-Add-support-of-commandline-packages-by-repoquery-RhBug-1784148.patch | ||||
| Patch16:        0016-Documentation-changes-RhBug-1786072.patch | ||||
| Patch17:        0017-New-API-function-for-setting-loggers-RhBug-1788212.patch | ||||
| Patch18:        0018-repoquery-fix-rich-deps-matching-by-using-provide-expansion-from-libdn-RhBug-1819172.patch | ||||
| Patch1:         0001-Handle-empty-comps-group-name-RhBug1826198.patch | ||||
| Patch2:         0002-Add-logfilelevel-configuration-RhBug-1802074.patch | ||||
| Patch3:         0003-Enhance-repo-variables-documentation-RhBug-1848161-1848615.patch | ||||
| Patch4:         0004-Update-translations-RhBug-1820544.patch | ||||
| 
 | ||||
| BuildArch:      noarch | ||||
| BuildRequires:  cmake | ||||
| @ -156,8 +142,8 @@ Provides:       dnf-command(upgrade) | ||||
| Provides:       dnf-command(upgrade-to) | ||||
| Conflicts:      python2-dnf-plugins-core < %{conflicts_dnf_plugins_core_version} | ||||
| Conflicts:      python3-dnf-plugins-core < %{conflicts_dnf_plugins_core_version} | ||||
| Conflicts:      python2-dnf-plugins-extras < %{conflicts_dnf_plugins_extras_version} | ||||
| Conflicts:      python3-dnf-plugins-extras < %{conflicts_dnf_plugins_extras_version} | ||||
| Conflicts:      python2-dnf-plugins-extras-common < %{conflicts_dnf_plugins_extras_version} | ||||
| Conflicts:      python3-dnf-plugins-extras-common < %{conflicts_dnf_plugins_extras_version} | ||||
| 
 | ||||
| %description | ||||
| %{pkg_description} | ||||
| @ -212,11 +198,9 @@ Requires:       python2-enum34 | ||||
| Requires:       %{name}-data = %{version}-%{release} | ||||
| %if 0%{?fedora} | ||||
| Recommends:     deltarpm | ||||
| # required for DNSSEC main.gpgkey_dns_verification https://dnf.readthedocs.io/en/latest/conf_ref.html | ||||
| Recommends:     python2-unbound | ||||
| %endif | ||||
| %if 0%{?centos} | ||||
| Requires:       deltarpm | ||||
| %endif | ||||
| Requires:       python2-hawkey >= %{hawkey_version} | ||||
| Requires:       python2-libdnf >= %{hawkey_version} | ||||
| Requires:       python2-libcomps >= %{libcomps_version} | ||||
| @ -254,15 +238,13 @@ Requires:       %{name}-data = %{version}-%{release} | ||||
| %if 0%{?fedora} | ||||
| Recommends:     deltarpm | ||||
| %endif | ||||
| %if 0%{?centos} | ||||
| Requires:       deltarpm | ||||
| %endif | ||||
| Requires:       python3-hawkey >= %{hawkey_version} | ||||
| Requires:       python3-libdnf >= %{hawkey_version} | ||||
| Requires:       python3-libcomps >= %{libcomps_version} | ||||
| Requires:       python3-libdnf | ||||
| BuildRequires:  python3-rpm >= %{rpm_version} | ||||
| Requires:       python3-rpm >= %{rpm_version} | ||||
| # required for DNSSEC main.gpgkey_dns_verification https://dnf.readthedocs.io/en/latest/conf_ref.html | ||||
| Recommends:     python3-unbound | ||||
| %if 0%{?rhel} && 0%{?rhel} <= 7 | ||||
| Requires:       rpm-plugin-systemd-inhibit | ||||
| @ -293,7 +275,7 @@ mkdir build-py3 | ||||
| %build | ||||
| %if %{with python2} | ||||
|     pushd build-py2 | ||||
|     %cmake .. -DPYTHON_DESIRED:FILEPATH=%{__python2} | ||||
|     %cmake .. -DPYTHON_DESIRED:FILEPATH=%{__python2} -DDNF_VERSION=%{version} | ||||
|     %make_build | ||||
|     make doc-man | ||||
|     popd | ||||
| @ -301,7 +283,7 @@ mkdir build-py3 | ||||
| 
 | ||||
| %if %{with python3} | ||||
|     pushd build-py3 | ||||
|     %cmake .. -DPYTHON_DESIRED:FILEPATH=%{__python3} | ||||
|     %cmake .. -DPYTHON_DESIRED:FILEPATH=%{__python3} -DDNF_VERSION=%{version} | ||||
|     %make_build | ||||
|     make doc-man | ||||
|     popd | ||||
| @ -529,8 +511,71 @@ ln -sr  %{buildroot}%{confdir}/vars %{buildroot}%{_sysconfdir}/yum/vars | ||||
| %endif | ||||
| 
 | ||||
| %changelog | ||||
| * Wed May 06 2020 Nicola Sella <nsella@redhat.com> - 4.2.17-7 | ||||
| - repoquery: fix rich deps matching by using provide expansion from libdnf (RhBug:1819172) | ||||
| * Tue Jul 28 2020 Marek Blaha <mblaha@redhat.com> - 4.2.23-4 | ||||
| - Update translations | ||||
| 
 | ||||
| * Fri Jul 17 2020 Nicola Sella <nsella@redhat.com> - 4.2.23-3 | ||||
| - Add logfilelevel configuration (RhBug:1802074) | ||||
| - [doc] Enhance repo variables documentation (RhBug:1848161,1848615) | ||||
| 
 | ||||
| * Wed Jun 10 2020 Ales Matej <amatej@redhat.com> - 4.2.23-2 | ||||
| - Handle empty comps group name (RhBug:1826198)  | ||||
| 
 | ||||
| * Tue Jun 02 2020 Nicola Sella <nsella@redhat.com> - 4.2.23-1 | ||||
| - Update to 4.2.23 | ||||
| - Fix behavior of `install-n` command | ||||
| - Fix behavior of `localinstall` command | ||||
| - Fix behavior of `autoremove-n` command | ||||
| - Fix behavior of `remove-n` command | ||||
| - Fix behavior of `repoquery-n` command | ||||
| - Fix behavior of `list-updateinfo` and related aliases | ||||
| - Refactor code in `repoinfo` to use opts.command correctly. | ||||
| - Add myself to list of contributors | ||||
| - Add updated to verbose output of updateinfo list (RhBug: 1801092) | ||||
| - Fix a couple of missed grammatical errors in updateinfo docs. | ||||
| - Add comment option (RhBug:1773679) | ||||
| - Better wording of dnssec email parsing error. | ||||
| - Print nicer DnssecErrors (RhBug:1813244) | ||||
| - Add new API for handling gpg signatures (RhBug:1339617) | ||||
| - Verify GPG signatures (RhBug:1793298) | ||||
| - Fix a syntax typo | ||||
| - Fix up Conflicts: on python-dnf-plugins-extras so it actually works | ||||
| - [doc] Move yum-plugin-post-transaction-actions to dnf-plugins-core | ||||
| - Remove args "--set-enabled", "--set-disabled" from DNF (RhBug:1727882) | ||||
| -  Search command is now alphabetical (RhBug:1811802) | ||||
| - Fix downloading packages with full URL as their location | ||||
| - repo: catch libdnf.error.Error in addition to RuntimeError in load() (RhBug:1788182) | ||||
| - History tbl to max size when redirect to file (RhBug:1786335,1786316) | ||||
| 
 | ||||
| * Mon Apr 06 2020 Ales Matej <amatej@redhat.com> - 4.2.21-1 | ||||
| - Update to 4.2.21 | ||||
| - Running with tsflags=test doesn't update log files | ||||
| - Allow disabling individual aliases config files (RhBug:1680566) | ||||
| - List arguments: only first empty value is used (RhBug:1788154) | ||||
| - Report missing profiles or default as broken module (RhBug:1790967) | ||||
| - Format history table to use actual terminal width (RhBug:1786316) | ||||
| - Handle custom exceptions from libdnf | ||||
| - Fix _skipped_packages to return only skipped (RhBug:1774617) | ||||
| - Add setter for tsi.reason | ||||
| - Add new hook for commands: Run_resolved | ||||
| - Clean also .yaml repository metadata | ||||
| - Use WantedBy=timers.target for all dnf timers (RhBug:1798475) | ||||
| - Fix completion helper if solv files not in roon cache (RhBug:1714376) | ||||
| - Add bash completion for 'dnf module' (RhBug:1565614) | ||||
| - Check command no longer reports  missing %pre and %post deps (RhBug:1543449) | ||||
| - Check if arguments can be encoded in 'utf-8' | ||||
| - Fix crash with "dnf -d 6 repolist" (RhBug:1812682) | ||||
| - Do not print the first empty line for repoinfo | ||||
| - Redirect logger and repo download progress when --verbose | ||||
| - Respect repo priority when listing packages (RhBug:1800342) | ||||
| - Remove misleading green color from the "broken dependencies" lines (RhBug:1814192) | ||||
| - [repoquery] Fix rich deps matching by using provide expansion from libdnf (RhBug:1534123) | ||||
| - [repoquery] Do not protect running kernel for --unsafisfied (RhBug:1750745) | ||||
| - [doc] Document the retries config option only works for packages (RhBug:1783041) | ||||
| - [doc] repoquery --what* with  multiple arguments (RhBug:1790262) | ||||
| - [doc] Remove incorrect information about includepkgs (RhBug:1813460) | ||||
| - [doc] Document that list and info commands respect repo priority | ||||
| - [doc] Document color options | ||||
| 
 | ||||
| * Tue Feb 18 2020 Ales Matej <amatej@redhat.com> - 4.2.17-6 | ||||
| - Sort packages in transaction output by nevra (RhBug:1773436) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user