Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package dnf for openSUSE:Factory checked in at 2021-03-10 08:46:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/dnf (Old) and /work/SRC/openSUSE:Factory/.dnf.new.2378 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "dnf" Wed Mar 10 08:46:11 2021 rev:25 rq:876272 version:4.6.1 Changes: -------- --- /work/SRC/openSUSE:Factory/dnf/dnf.changes 2021-02-18 20:41:42.446742353 +0100 +++ /work/SRC/openSUSE:Factory/.dnf.new.2378/dnf.changes 2021-03-10 08:46:12.442204779 +0100 @@ -1,0 +2,19 @@ +Tue Mar 2 16:48:22 UTC 2021 - Neal Gompa <ngomp...@gmail.com> + +- Update to version 4.6.1 + + Add unit test for fill_sack_from_repos_in_cache (rh#1865803) + + Add docs and examples for fill_sack_from_repos_in_cache (rh#1865803) + + [spec] remove python2 support + + Remove problematic language + + The noroot plugin no longer exists, remove mention + + Run tests for fill_sack_from_repos_in_cache in installroot (rh#1865803) + + expand history to full term size when output is redirected (rh#1852577) (rh#1852577, rh#1906970) + + [doc] Fix: "sslcacert" contains path to the file + + [doc] Added proxy ssl configuration options, increase libdnf require + + Set persistdir and substitutions for fill_sack_from_repos_in_cache tests (rh#1865803) + + Update documentation for module_obsoletes and module_stream_switch + + print additional information when verifying GPG key using DNS + + Remove hardcoded logfile permissions (rh#1910084) + + Enhanced detection of plugins removed in transaction (rh#1929163) + +------------------------------------------------------------------- Old: ---- dnf-4.6.0.tar.gz New: ---- dnf-4.6.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dnf.spec ++++++ --- /var/tmp/diff_new_pack.DhnDo2/_old 2021-03-10 08:46:13.654206029 +0100 +++ /var/tmp/diff_new_pack.DhnDo2/_new 2021-03-10 08:46:13.658206034 +0100 @@ -17,7 +17,7 @@ # -%global hawkey_version 0.57.0 +%global hawkey_version 0.59.0 %global libcomps_version 0.1.8 %global libmodulemd_version 2.9.3 %global rpm_version 4.14.0 @@ -50,7 +50,7 @@ %bcond_with tests Name: dnf -Version: 4.6.0 +Version: 4.6.1 Release: 0 Summary: Package manager forked from Yum, using libsolv as a dependency resolver # For a breakdown of the licensing, see PACKAGE-LICENSING ++++++ dnf-4.6.0.tar.gz -> dnf-4.6.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/.github/workflows/ci.yaml new/dnf-4.6.1/.github/workflows/ci.yaml --- old/dnf-4.6.0/.github/workflows/ci.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/dnf-4.6.1/.github/workflows/ci.yaml 2021-03-02 15:05:07.000000000 +0100 @@ -0,0 +1,36 @@ +--- +name: DNF CI +on: pull_request_target + +jobs: + integration-tests: + name: Integration Tests + runs-on: ubuntu-latest + container: + image: fedora:latest + options: --privileged + steps: + - name: Check out ci-dnf-stack + uses: actions/checkout@v2 + with: + repository: rpm-software-management/ci-dnf-stack + + - name: Setup CI + id: setup-ci + uses: ./.github/actions/setup-ci + with: + copr-user: ${{secrets.COPR_USER}} + copr-api-token: ${{secrets.COPR_API_TOKEN}} + setup-integration-testing: true + + - name: Check out sources + uses: actions/checkout@v2 + with: + path: gits/${{github.event.pull_request.head.repo.name}} + ref: ${{github.event.pull_request.head.sha}} # check out the PR HEAD + fetch-depth: 0 + + - name: Run CI + uses: ./.github/actions/run-ci + with: + copr-user: ${{steps.setup-ci.outputs.copr-user}} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/VERSION.cmake new/dnf-4.6.1/VERSION.cmake --- old/dnf-4.6.0/VERSION.cmake 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/VERSION.cmake 2021-03-02 15:05:07.000000000 +0100 @@ -1,4 +1,4 @@ -set (DEFAULT_DNF_VERSION "4.6.0") +set (DEFAULT_DNF_VERSION "4.6.1") if(DEFINED DNF_VERSION) if(NOT ${DEFAULT_DNF_VERSION} STREQUAL ${DNF_VERSION}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/dnf/base.py new/dnf-4.6.1/dnf/base.py --- old/dnf-4.6.0/dnf/base.py 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/dnf/base.py 2021-03-02 15:05:07.000000000 +0100 @@ -2368,7 +2368,10 @@ # Try installing/updating GPG key info.url = keyurl - dnf.crypto.log_key_import(info) + if self.conf.gpgkey_dns_verification: + dnf.crypto.log_dns_key_import(info, dns_result) + else: + dnf.crypto.log_key_import(info) rc = False if self.conf.assumeno: rc = False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/dnf/cli/cli.py new/dnf-4.6.1/dnf/cli/cli.py --- old/dnf-4.6.0/dnf/cli/cli.py 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/dnf/cli/cli.py 2021-03-02 15:05:07.000000000 +0100 @@ -170,8 +170,9 @@ switchedModules = dict(self._moduleContainer.getSwitchedStreams()) if switchedModules: report_module_switch(switchedModules) - msg = _("It is not possible to switch enabled streams of a module.\n" - "It is recommended to remove all installed content from the module, and " + msg = _("It is not possible to switch enabled streams of a module unless explicitly " + "enabled via configuration option module_stream_switch.\n" + "It is recommended to rather remove all installed content from the module, and " "reset the module using '{prog} module reset <module_name>' command. After " "you reset the module, you can install the other stream.").format( prog=dnf.util.MAIN_PROG) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/dnf/cli/output.py new/dnf-4.6.1/dnf/cli/output.py --- old/dnf-4.6.0/dnf/cli/output.py 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/dnf/cli/output.py 2021-03-02 15:05:07.000000000 +0100 @@ -1518,12 +1518,14 @@ name = _("Command line") real_cols = self.term.real_columns if real_cols is None: - name_width = ( - 24 if not transactions - else max([len(t.cmdline) for t in transactions]) - ) - else: - name_width = real_cols - 55 if real_cols > 79 else 24 + # if output is redirected in `less` the columns + # detected are None value, to detect terminal size + # use stdin file descriptor + real_cols = dnf.cli.term._real_term_width(0) + if real_cols is None: + # if even stdin fd fails use 24 to fit to 80 cols + real_cols = 24 + name_width = real_cols - 55 if real_cols > 79 else 24 else: # TRANSLATORS: user names who executed transaction in history command output name = _("User name") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/dnf/conf/config.py new/dnf-4.6.1/dnf/conf/config.py --- old/dnf-4.6.0/dnf/conf/config.py 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/dnf/conf/config.py 2021-03-02 15:05:07.000000000 +0100 @@ -471,11 +471,11 @@ """Option definitions for repository INI file sections.""" def __init__(self, parent, section=None, parser=None): - masterConfig = parent._config if parent else libdnf.conf.ConfigMain() - super(RepoConf, self).__init__(libdnf.conf.ConfigRepo(masterConfig), section, parser) + mainConfig = parent._config if parent else libdnf.conf.ConfigMain() + super(RepoConf, self).__init__(libdnf.conf.ConfigRepo(mainConfig), section, parser) # Do not remove! Attribute is a reference holder. - # Prevents premature removal of the masterConfig. The libdnf ConfigRepo points to it. - self._masterConfigRefHolder = masterConfig + # Prevents premature removal of the mainConfig. The libdnf ConfigRepo points to it. + self._mainConfigRefHolder = mainConfig if section: self._config.name().set(PRIO_DEFAULT, section) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/dnf/crypto.py new/dnf-4.6.1/dnf/crypto.py --- old/dnf-4.6.0/dnf/crypto.py 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/dnf/crypto.py 2021-03-02 15:05:07.000000000 +0100 @@ -139,6 +139,13 @@ logger.critical("%s", msg) +def log_dns_key_import(keyinfo, dns_result): + log_key_import(keyinfo) + if dns_result == dnf.dnssec.Validity.VALID: + logger.critical(_('Verified using DNS record with DNSSEC signature.')) + else: + logger.critical(_('NOT verified using DNS record.')) + @contextlib.contextmanager def pubring_dir(pubring_dir): orig = os.environ.get(GPG_HOME_ENV, None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/dnf/logging.py new/dnf-4.6.1/dnf/logging.py --- old/dnf-4.6.0/dnf/logging.py 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/dnf/logging.py 2021-03-02 15:05:07.000000000 +0100 @@ -139,9 +139,6 @@ if not os.path.exists(logfile): dnf.util.ensure_dir(os.path.dirname(logfile)) dnf.util.touch(logfile) - # By default, make logfiles readable by the user (so the reporting ABRT - # user can attach root logfiles). - os.chmod(logfile, 0o644) handler = MultiprocessRotatingFileHandler(logfile, maxBytes=log_size, backupCount=log_rotate) formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s", "%Y-%m-%dT%H:%M:%S%z") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/dnf/plugin.py new/dnf-4.6.1/dnf/plugin.py --- old/dnf-4.6.0/dnf/plugin.py 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/dnf/plugin.py 2021-03-02 15:05:07.000000000 +0100 @@ -167,20 +167,32 @@ del sys.modules[DYNAMIC_PACKAGE] def unload_removed_plugins(self, transaction): - erased = set([package.name for package in transaction.remove_set]) - if not erased: + """ + Unload plugins that were removed in the `transaction`. + """ + if not transaction.remove_set: return - installed = set([package.name for package in transaction.install_set]) - transaction_diff = erased - installed - if not transaction_diff: - return - files_erased = set() + + # gather all installed plugins and their files + plugins = dict() + for plugin in self.plugins: + plugins[inspect.getfile(plugin.__class__)] = plugin + + # gather all removed files that are plugin files + plugin_files = set(plugins.keys()) + erased_plugin_files = set() for pkg in transaction.remove_set: - if pkg.name in transaction_diff: - files_erased.update(pkg.files) - for plugin in self.plugins[:]: - if inspect.getfile(plugin.__class__) in files_erased: - self.plugins.remove(plugin) + erased_plugin_files.update(plugin_files.intersection(pkg.files)) + if not erased_plugin_files: + return + + # check whether removed plugin file is added at the same time (upgrade of a plugin) + for pkg in transaction.install_set: + erased_plugin_files.difference_update(pkg.files) + + # unload plugins that were removed in transaction + for plugin_file in erased_plugin_files: + self.plugins.remove(plugins[plugin_file]) def _plugin_classes(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/dnf/util.py new/dnf-4.6.1/dnf/util.py --- old/dnf-4.6.0/dnf/util.py 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/dnf/util.py 2021-03-02 15:05:07.000000000 +0100 @@ -269,9 +269,14 @@ """ try: - with open("/sys/class/power_supply/AC/online") as ac_status: - data = ac_status.read() - return int(data) == 1 + ps_folder = "/sys/class/power_supply" + ac_nodes = [node for node in os.listdir(ps_folder) if node.startswith("AC")] + if len(ac_nodes) > 0: + ac_node = ac_nodes[0] + with open("{}/{}/online".format(ps_folder, ac_node)) as ac_status: + data = ac_status.read() + return int(data) == 1 + return None except (IOError, ValueError): return None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/dnf.spec new/dnf-4.6.1/dnf.spec --- old/dnf-4.6.0/dnf.spec 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/dnf.spec 2021-03-02 15:05:07.000000000 +0100 @@ -1,8 +1,8 @@ # Always build out-of-source -%undefine __cmake_in_source_build +%define __cmake_in_source_build 1 # default dependencies -%global hawkey_version 0.57.0 +%global hawkey_version 0.59.0 %global libcomps_version 0.1.8 %global libmodulemd_version 2.9.3 %global rpm_version 4.14.0 @@ -27,19 +27,6 @@ %endif -%if 0%{?rhel} && 0%{?rhel} <= 7 -%bcond_with python3 -%else -%bcond_without python3 -%endif - -%if 0%{?rhel} >= 8 || 0%{?fedora} > 29 -# Disable python2 build -%bcond_with python2 -%else -%bcond_without python2 -%endif - # YUM compat subpackage configuration # # level=full -> deploy all compat symlinks (conflicts with yum < 4) @@ -67,13 +54,7 @@ %global confdir %{_sysconfdir}/%{name} %global pluginconfpath %{confdir}/plugins -%if %{with python2} - %global py2pluginpath %{python2_sitelib}/%{name}-plugins -%endif - -%if %{with python3} - %global py3pluginpath %{python3_sitelib}/%{name}-plugins -%endif +%global py3pluginpath %{python3_sitelib}/%{name}-plugins # Use the same directory of the main package for subpackage licence and docs %global _docdir_fmt %{name} @@ -84,7 +65,7 @@ It supports RPMs, modules and comps groups & environments. Name: dnf -Version: 4.6.0 +Version: 4.6.1 Release: 1%{?dist} Summary: %{pkg_summary} # For a breakdown of the licensing, see PACKAGE-LICENSING @@ -97,22 +78,13 @@ # Documentation BuildRequires: systemd BuildRequires: bash-completion -%if %{with python3} BuildRequires: %{_bindir}/sphinx-build-3 Requires: python3-%{name} = %{version}-%{release} -%else -BuildRequires: %{_bindir}/sphinx-build -Requires: python2-%{name} = %{version}-%{release} -%endif %if 0%{?rhel} && 0%{?rhel} <= 7 Requires: python-dbus Requires: %{_bindir}/sqlite3 %else -%if %{with python3} Recommends: (python3-dbus if NetworkManager) -%else -Recommends: (python2-dbus if NetworkManager) -%endif Recommends: (%{_bindir}/sqlite3 if bash-completion) %endif Provides: dnf-command(alias) @@ -138,9 +110,7 @@ Provides: dnf-command(updateinfo) 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-common < %{conflicts_dnf_plugins_extras_version} Conflicts: python3-dnf-plugins-extras-common < %{conflicts_dnf_plugins_extras_version} %description @@ -170,55 +140,6 @@ %description -n %{yum_subpackage_name} %{pkg_description} -%if %{with python2} -%package -n python2-%{name} -Summary: Python 2 interface to DNF -%{?python_provide:%python_provide python2-%{name}} -BuildRequires: python2-devel -BuildRequires: python2-hawkey >= %{hawkey_version} -BuildRequires: python2-libdnf >= %{hawkey_version} -BuildRequires: python2-libcomps >= %{libcomps_version} -BuildRequires: python2-libdnf -BuildRequires: python2-nose -BuildRequires: libmodulemd >= %{libmodulemd_version} -Requires: libmodulemd >= %{libmodulemd_version} -%if (0%{?rhel} && 0%{?rhel} <= 7) -BuildRequires: pygpgme -Requires: pygpgme -BuildRequires: python-enum34 -Requires: python-enum34 -%else -BuildRequires: python2-gpg -Requires: python2-gpg -BuildRequires: python2-enum34 -Requires: python2-enum34 -%endif -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 -Requires: python2-hawkey >= %{hawkey_version} -Requires: python2-libdnf >= %{hawkey_version} -Requires: python2-libcomps >= %{libcomps_version} -Requires: python2-libdnf -%if 0%{?rhel} && 0%{?rhel} <= 7 -BuildRequires: rpm-python >= %{rpm_version} -Requires: rpm-python >= %{rpm_version} -%else -BuildRequires: python2-rpm >= %{rpm_version} -Requires: python2-rpm >= %{rpm_version} -Recommends: rpm-plugin-systemd-inhibit -%endif -Conflicts: dnfdaemon < %{conflicts_dnfdaemon_version} - -%description -n python2-%{name} -Python 2 interface to DNF. -%endif -# ^ %%{with python2} - -%if %{with python3} %package -n python3-%{name} Summary: Python 3 interface to DNF %{?python_provide:%python_provide python3-%{name}} @@ -252,7 +173,6 @@ %description -n python3-%{name} Python 3 interface to DNF. -%endif %package automatic Summary: %{pkg_summary} - automated upgrades @@ -267,33 +187,21 @@ %prep %autosetup +mkdir build-py3 %build -%if %{with python2} - %global _vpath_builddir build-py2 - %cmake -DPYTHON_DESIRED:FILEPATH=%{__python2} -DDNF_VERSION=%{version} - %cmake_build - %cmake_build --target doc-man -%endif - -%if %{with python3} - %global _vpath_builddir build-py3 - %cmake -DPYTHON_DESIRED:FILEPATH=%{__python3} -DDNF_VERSION=%{version} - %cmake_build - %cmake_build --target doc-man -%endif +pushd build-py3 +%cmake .. -DPYTHON_DESIRED:FILEPATH=%{__python3} -DDNF_VERSION=%{version} +%make_build +make doc-man +popd %install -%if %{with python2} - %global _vpath_builddir build-py2 - %cmake_install -%endif -%if %{with python3} - %global _vpath_builddir build-py3 - %cmake_install -%endif +pushd build-py3 +%make_install +popd %find_lang %{name} mkdir -p %{buildroot}%{confdir}/vars @@ -301,22 +209,12 @@ mkdir -p %{buildroot}%{pluginconfpath}/ mkdir -p %{buildroot}%{_sysconfdir}/%{name}/modules.d mkdir -p %{buildroot}%{_sysconfdir}/%{name}/modules.defaults.d -%if %{with python2} -mkdir -p %{buildroot}%{py2pluginpath}/ -%endif -%if %{with python3} mkdir -p %{buildroot}%{py3pluginpath}/__pycache__/ -%endif mkdir -p %{buildroot}%{_localstatedir}/log/ mkdir -p %{buildroot}%{_var}/cache/dnf/ touch %{buildroot}%{_localstatedir}/log/%{name}.log -%if %{with python3} ln -sr %{buildroot}%{_bindir}/dnf-3 %{buildroot}%{_bindir}/dnf mv %{buildroot}%{_bindir}/dnf-automatic-3 %{buildroot}%{_bindir}/dnf-automatic -%else -ln -sr %{buildroot}%{_bindir}/dnf-2 %{buildroot}%{_bindir}/dnf -mv %{buildroot}%{_bindir}/dnf-automatic-2 %{buildroot}%{_bindir}/dnf-automatic -%endif rm -vf %{buildroot}%{_bindir}/dnf-automatic-* # Strict conf distribution @@ -328,17 +226,7 @@ # YUM compat layer ln -sr %{buildroot}%{confdir}/%{name}.conf %{buildroot}%{_sysconfdir}/yum.conf -%if %{with python3} ln -sr %{buildroot}%{_bindir}/dnf-3 %{buildroot}%{_bindir}/yum -%else -%if "%{yum_compat_level}" == "preview" -ln -sr %{buildroot}%{_bindir}/dnf-2 %{buildroot}%{_bindir}/yum4 -ln -sr %{buildroot}%{_mandir}/man8/dnf.8.gz %{buildroot}%{_mandir}/man8/yum4.8.gz -rm -f %{buildroot}%{_mandir}/man8/yum.8.gz -%else -ln -sr %{buildroot}%{_bindir}/dnf-2 %{buildroot}%{_bindir}/yum -%endif -%endif %if "%{yum_compat_level}" == "full" mkdir -p %{buildroot}%{_sysconfdir}/yum ln -sr %{buildroot}%{pluginconfpath} %{buildroot}%{_sysconfdir}/yum/pluginconf.d @@ -348,15 +236,10 @@ %check -%if %{with python2} - %global _vpath_builddir build-py2 - %ctest -%endif -%if %{with python3} - %global _vpath_builddir build-py3 - %ctest -%endif +pushd build-py3 +ctest -VV +popd %post @@ -466,22 +349,12 @@ %exclude %{_mandir}/man8/yum.8* %endif -%if %{with python2} -%files -n python2-%{name} -%{_bindir}/%{name}-2 -%exclude %{python2_sitelib}/%{name}/automatic -%{python2_sitelib}/%{name}/ -%dir %{py2pluginpath} -%endif - -%if %{with python3} %files -n python3-%{name} %{_bindir}/%{name}-3 %exclude %{python3_sitelib}/%{name}/automatic %{python3_sitelib}/%{name}/ %dir %{py3pluginpath} %dir %{py3pluginpath}/__pycache__ -%endif %files automatic %{_bindir}/%{name}-automatic @@ -495,13 +368,27 @@ %{_unitdir}/%{name}-automatic-download.timer %{_unitdir}/%{name}-automatic-install.service %{_unitdir}/%{name}-automatic-install.timer -%if %{with python3} %{python3_sitelib}/%{name}/automatic/ -%else -%{python2_sitelib}/%{name}/automatic/ -%endif %changelog +* Tue Mar 02 2021 Nicola Sella <nse...@redhat.com> - 4.6.1-1 +- Fix recreate script +- Add unit test for fill_sack_from_repos_in_cache (RhBug:1865803) +- Add docs and examples for fill_sack_from_repos_in_cache (RhBug:1865803) +- [spec] remove python2 support +- Remove problematic language +- The noroot plugin no longer exists, remove mention +- Run tests for fill_sack_from_repos_in_cache in installroot (RhBug:1865803) +- expand history to full term size when output is redirected (RhBug:1852577) (RhBug:1852577,1906970) +- [doc] Fix: "sslcacert" contains path to the file +- [doc] Added proxy ssl configuration options, increase libdnf require +- Set persistdir and substitutions for fill_sack_from_repos_in_cache tests (RhBug:1865803) +- Update documentation for module_obsoletes and module_stream_switch +- print additional information when verifying GPG key using DNS +- Bugs fixed (RhBug:1897573) +- Remove hardcoded logfile permissions (RhBug:1910084) +- Enhanced detection of plugins removed in transaction (RhBug:1929163) + * Thu Jan 28 2021 Nicola Sella <nse...@redhat.com> - 4.6.0-1 - Log scriptlets output also for API users (RhBug:1847340) - Fix module remove --all when no match spec (RhBug:1904490) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/doc/api_base.rst new/dnf-4.6.1/doc/api_base.rst --- old/dnf-4.6.0/doc/api_base.rst 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/doc/api_base.rst 2021-03-02 15:05:07.000000000 +0100 @@ -111,6 +111,47 @@ print("id: {}".format(repo.id)) print("baseurl: {}".format(repo.baseurl)) + .. method:: fill_sack_from_repos_in_cache(load_system_repo=True) + + Prepare Sack and Goal objects and load all enabled repositories from cache only, it doesn't download anything and it doesn't check if metadata are expired. + To successfully load a repository cache it requires repomd.xml plus metadata (xml, yaml) or repomd.xml plus generated cache files (solv, solvx). + If there is not enough metadata given repo is either skipped or it throws a :exc:`dnf.exceptions.RepoError` exception depending on :attr:`dnf.conf.Conf.skip_if_unavailable` configuration. + + All additional metadata are loaded if present but are not generally required. Note that some metadata like updateinfo.xml get processed into a solvx cache file and its sufficient to have either xml or solvx. Module metadata represented by modules.yaml are not processed therefore they are needed when they are defined in repomd.xml. + + Example of loading all configured repositories from cache and printing available packages' names:: + + #!/usr/bin/python3 + import dnf + + with dnf.Base() as base: + base.read_all_repos() + + base.fill_sack_from_repos_in_cache(load_system_repo=False) + + query = base.sack.query().available() + for pkg in query.run(): + print(pkg.name) + + Example of loading a single repository and printing available packages' names without reading repository configuration:: + + #!/usr/bin/python3 + import dnf + + with dnf.Base() as base: + repo = dnf.repo.Repo("rawhide", base.conf) + + # Repository cache is also identified by its source therefore to find it you need to + # set metalink, mirrorlist or baseurl to the same value from which it was created. + repo.metalink = "https://mirrors.fedoraproject.org/metalink?repo=rawhide&arch=x86_64" + + base.repos.add(repo) + + base.fill_sack_from_repos_in_cache(load_system_repo=False) + + query = base.sack.query().available() + for pkg in query.run(): + print(pkg.name) .. method:: do_transaction([display]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/doc/api_module.rst new/dnf-4.6.1/doc/api_module.rst --- old/dnf-4.6.0/doc/api_module.rst 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/doc/api_module.rst 2021-03-02 15:05:07.000000000 +0100 @@ -138,7 +138,7 @@ .. class:: libdnf.module.ModulePackage -This class represents a record identified by NSVCA from the repository modular metadata. See also https://github.com/fedora-modularity/libmodulemd/blob/master/spec.v2.yaml. +This class represents a record identified by NSVCA from the repository modular metadata. See also https://github.com/fedora-modularity/libmodulemd/blob/main/spec.v2.yaml. .. method:: getName() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/doc/conf_ref.rst new/dnf-4.6.1/doc/conf_ref.rst --- old/dnf-4.6.0/doc/conf_ref.rst 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/doc/conf_ref.rst 2021-03-02 15:05:07.000000000 +0100 @@ -325,6 +325,13 @@ disable automatic metadata synchronizing. The default corresponds to three hours. The value is rounded to the next commenced hour. +.. _module_obsoletes-label: + +``module_obsoletes`` + :ref:`boolean <boolean-label>` + + This option controls whether dnf should apply modular obsoletes when possible. + .. _module_platform_id-label: ``module_platform_id`` @@ -333,6 +340,13 @@ Set this to $name:$stream to override PLATFORM_ID detected from ``/etc/os-release``. It is necessary to perform a system upgrade and switch to a new platform. +.. _module_stream_switch-label: + +``module_stream_switch`` + :ref:`boolean <boolean-label>` + + This option controls whether it's possible to switch enabled streams of a module. + ``multilib_policy`` :ref:`string <string-label>` @@ -849,6 +863,37 @@ Defaults to ``any`` +.. _proxy_sslcacert-label: + +``proxy_sslcacert`` + :ref:`string <string-label>` + + Path to the file containing the certificate authorities to verify proxy SSL certificates. + Empty by default - uses system default. + +.. _proxy_sslverify-label: + +``proxy_sslverify`` + :ref:`boolean <boolean-label>` + + When enabled, proxy SSL certificates are verified. If the client can not be authenticated, connecting fails and the repository is not used any further. If ``False``, SSL connections can be used, but certificates are not verified. Default is ``True``. + +.. _proxy_sslclientcert-label: + +``proxy_sslclientcert`` + :ref:`string <string-label>` + + Path to the SSL client certificate used to connect to proxy server. + Empty by default. + +.. _proxy_sslclientkey-label: + +``proxy_sslclientkey`` + :ref:`string <string-label>` + + Path to the SSL client key used to connect to proxy server. + Empty by default. + .. _repo_gpgcheck-label: ``repo_gpgcheck`` @@ -881,7 +926,7 @@ ``sslcacert`` :ref:`string <string-label>` - Path to the directory or file containing the certificate authorities to verify SSL certificates. + Path to the file containing the certificate authorities to verify SSL certificates. Empty by default - uses system default. .. _sslverify-label: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/doc/release_notes.rst new/dnf-4.6.1/doc/release_notes.rst --- old/dnf-4.6.0/doc/release_notes.rst 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/doc/release_notes.rst 2021-03-02 15:05:07.000000000 +0100 @@ -20,6 +20,38 @@ ################### =================== +4.6.1 Release Notes +=================== + +- Fix recreate script +- Add unit test for fill_sack_from_repos_in_cache (RhBug:1865803) +- Add docs and examples for fill_sack_from_repos_in_cache (RhBug:1865803) +- [spec] remove python2 support +- Remove problematic language +- The noroot plugin no longer exists, remove mention +- Run tests for fill_sack_from_repos_in_cache in installroot (RhBug:1865803) +- expand history to full term size when output is redirected (RhBug:1852577) (RhBug:1852577,1906970) +- [doc] Fix: "sslcacert" contains path to the file +- [doc] Added proxy ssl configuration options, increase libdnf require +- Set persistdir and substitutions for fill_sack_from_repos_in_cache tests (RhBug:1865803) +- Update documentation for module_obsoletes and module_stream_switch +- print additional information when verifying GPG key using DNS + +- Bug fixes: + - Bugs fixed (RhBug:1897573) + - Remove hardcoded logfile permissions (RhBug:1910084) + - Enhanced detection of plugins removed in transaction (RhBug:1929163) + +Bugs fixed in 4.6.1: + +* :rhbug:`1852577` +* :rhbug:`1910084` +* :rhbug:`1897573` +* :rhbug:`1929163` +* :rhbug:`1865803` +* :rhbug:`1906970` + +=================== 4.6.0 Release Notes =================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/doc/summaries_cache new/dnf-4.6.1/doc/summaries_cache --- old/dnf-4.6.0/doc/summaries_cache 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/doc/summaries_cache 2021-03-02 15:05:07.000000000 +0100 @@ -3294,5 +3294,25 @@ [ 1876606, "dnf python API does not provide an rpm header of a package (as yum API does)" + ], + [ + 1852577, + "\"dnf history list\" displays an erratic output" + ], + [ + 1910084, + "hardcoded logfile permissions" + ], + [ + 1897573, + "[spec] Make new cmake macros optional" + ], + [ + 1929163, + "problem with transaction() hook" + ], + [ + 1906970, + "dnf history wrong output if piped through more or redirected to file" ] ] \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/doc/user_faq.rst new/dnf-4.6.1/doc/user_faq.rst --- old/dnf-4.6.0/doc/user_faq.rst 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/doc/user_faq.rst 2021-03-02 15:05:07.000000000 +0100 @@ -126,8 +126,6 @@ No, there can be systems and scenarios that allow other users than root to successfully perform ``dnf install`` and similar and it would be impractical to stop these from functioning by the UID check. Alternatively, the practice of checking filesystem permissions instead of the effective UID could lead to false positives since there is plenty of time between DNF startup and the possible transaction start when permissions can be changed by a different process. -If the time loss incurred by repeated runs of DNF is unacceptable for you, consider using the `noroot plugin <https://github.com/rpm-software-management/dnf-plugins-core/blob/master/plugins/noroot.py>`_. - =================== Using DNF in Fedora =================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/po/zanata.xml new/dnf-4.6.1/po/zanata.xml --- old/dnf-4.6.0/po/zanata.xml 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/po/zanata.xml 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<config xmlns="http://zanata.org/namespace/config/"> - <url>https://fedora.zanata.org/</url> - <project>dnf</project> - <project-version>master</project-version> - <project-type>gettext</project-type> -</config> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/tests/repos/rpm/recreate new/dnf-4.6.1/tests/repos/rpm/recreate --- old/dnf-4.6.0/tests/repos/rpm/recreate 2021-01-28 17:50:32.000000000 +0100 +++ new/dnf-4.6.1/tests/repos/rpm/recreate 2021-03-02 15:05:07.000000000 +0100 @@ -1,6 +1,6 @@ #!/bin/bash -THISDIR="$( readlink -f "$( dirname "$0 )" )" +THISDIR="$( readlink -f "$( dirname "$0" )" )" cd "$THISDIR" git rm -rf repodata/ createrepo --no-database -o . .. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-4.6.0/tests/test_fill_sack_from_repos_in_cache.py new/dnf-4.6.1/tests/test_fill_sack_from_repos_in_cache.py --- old/dnf-4.6.0/tests/test_fill_sack_from_repos_in_cache.py 1970-01-01 01:00:00.000000000 +0100 +++ new/dnf-4.6.1/tests/test_fill_sack_from_repos_in_cache.py 2021-03-02 15:05:07.000000000 +0100 @@ -0,0 +1,278 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2012-2021 Red Hat, Inc. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# the GNU General Public License v.2, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY expressed or implied, including the implied warranties of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. You should have received a copy of the +# GNU General Public License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the +# source code or documentation are not subject to the GNU General Public +# License and may only be used or replicated with the express permission of +# Red Hat, Inc. +# + +from __future__ import absolute_import +from __future__ import unicode_literals + +import os +import tempfile +import glob +import shutil +import unittest + +import dnf.exceptions +import dnf.repo +import dnf.sack + +import hawkey + +import tests.support +from tests.support import mock + +TEST_REPO_NAME = "test-repo" + + +class FillSackFromReposInCacheTest(unittest.TestCase): + def _create_cache_for_repo(self, repopath, tmpdir): + conf = dnf.conf.MainConf() + conf.cachedir = os.path.join(tmpdir, "cache") + conf.installroot = tmpdir + conf.persistdir = os.path.join(conf.installroot, conf.persistdir.lstrip("/")) + conf.substitutions["arch"] = "x86_64" + conf.substitutions["basearch"] = dnf.rpm.basearch(conf.substitutions["arch"]) + + base = dnf.Base(conf=conf) + + repoconf = dnf.repo.Repo(TEST_REPO_NAME, base.conf) + repoconf.baseurl = repopath + repoconf.enable() + + base.repos.add(repoconf) + + base.fill_sack(load_system_repo=False) + base.close() + + def _setUp_from_repo_path(self, original_repo_path): + repo_copy_path = os.path.join(self.tmpdir, "repo") + shutil.copytree(original_repo_path, repo_copy_path) + + self._create_cache_for_repo(repo_copy_path, self.tmpdir) + + # Just to be sure remove repo (it shouldn't be used) + shutil.rmtree(repo_copy_path) + + # Prepare base for the actual test + conf = dnf.conf.MainConf() + conf.cachedir = os.path.join(self.tmpdir, "cache") + conf.installroot = self.tmpdir + conf.persistdir = os.path.join(conf.installroot, conf.persistdir.lstrip("/")) + conf.substitutions["arch"] = "x86_64" + conf.substitutions["basearch"] = dnf.rpm.basearch(conf.substitutions["arch"]) + self.test_base = dnf.Base(conf=conf) + repoconf = dnf.repo.Repo(TEST_REPO_NAME, conf) + repoconf.baseurl = repo_copy_path + repoconf.enable() + self.test_base.repos.add(repoconf) + + def setUp(self): + self.tmpdir = tempfile.mkdtemp(prefix="dnf_test_") + self.test_base = None + + def tearDown(self): + shutil.rmtree(self.tmpdir) + if self.test_base: + self.test_base.close() + + def test_with_solv_solvx_repomd(self): + self._setUp_from_repo_path(os.path.join(os.path.abspath(os.path.dirname(__file__)), "repos/rpm")) + + # Remove xml metadata except repomd + # repomd.xml is not compressed and doesn't end with .gz + repodata_without_repomd = glob.glob(os.path.join(self.tmpdir, "cache/test-repo-*/repodata/*.gz")) + for f in repodata_without_repomd: + os.remove(f) + + # Now we only have cache with just solv, solvx files and repomd.xml + + self.test_base.fill_sack_from_repos_in_cache(load_system_repo=False) + + q = self.test_base.sack.query() + packages = q.run() + self.assertEqual(len(packages), 9) + self.assertEqual(packages[0].evr, "4-4") + + # Use *-updateinfo.solvx + adv_pkgs = q.get_advisory_pkgs(hawkey.LT | hawkey.EQ | hawkey.GT) + adv_titles = set() + for pkg in adv_pkgs: + adv_titles.add(pkg.get_advisory(self.test_base.sack).title) + self.assertEqual(len(adv_titles), 3) + + def test_with_just_solv_repomd(self): + self._setUp_from_repo_path(os.path.join(os.path.abspath(os.path.dirname(__file__)), "repos/rpm")) + + # Remove xml metadata except repomd + # repomd.xml is not compressed and doesn't end with .gz + repodata_without_repomd = glob.glob(os.path.join(self.tmpdir, "cache/test-repo-*/repodata/*.gz")) + for f in repodata_without_repomd: + os.remove(f) + + # Remove solvx files + solvx = glob.glob(os.path.join(self.tmpdir, "cache/*.solvx")) + for f in solvx: + os.remove(f) + + # Now we only have cache with just solv files and repomd.xml + + self.test_base.fill_sack_from_repos_in_cache(load_system_repo=False) + + q = self.test_base.sack.query() + packages = q.run() + self.assertEqual(len(packages), 9) + self.assertEqual(packages[0].evr, "4-4") + + # No *-updateinfo.solvx -> we get no advisory packages + adv_pkgs = q.get_advisory_pkgs(hawkey.LT | hawkey.EQ | hawkey.GT) + self.assertEqual(len(adv_pkgs), 0) + + def test_with_xml_metadata(self): + self._setUp_from_repo_path(os.path.join(os.path.abspath(os.path.dirname(__file__)), "repos/rpm")) + + # Remove all solv and solvx files + solvx = glob.glob(os.path.join(self.tmpdir, "cache/*.solv*")) + for f in solvx: + os.remove(f) + + # Now we only have cache with just xml metadata + + self.test_base.fill_sack_from_repos_in_cache(load_system_repo=False) + + q = self.test_base.sack.query() + packages = q.run() + self.assertEqual(len(packages), 9) + self.assertEqual(packages[0].evr, "4-4") + + def test_exception_without_repomd(self): + self._setUp_from_repo_path(os.path.join(os.path.abspath(os.path.dirname(__file__)), "repos/rpm")) + + # Remove xml metadata + repodata_without_repomd = glob.glob(os.path.join(self.tmpdir, "cache/test-repo-*/repodata/*")) + for f in repodata_without_repomd: + os.remove(f) + + # Now we only have cache with just solv and solvx files + # Since we don't have repomd we cannot verify checksums -> fail (exception) + + self.assertRaises(dnf.exceptions.RepoError, + self.test_base.fill_sack_from_repos_in_cache, load_system_repo=False) + + def test_exception_with_just_repomd(self): + self._setUp_from_repo_path(os.path.join(os.path.abspath(os.path.dirname(__file__)), "repos/rpm")) + + # Remove xml metadata except repomd + # repomd.xml is not compressed and doesn't end with .gz + repodata_without_repomd = glob.glob(os.path.join(self.tmpdir, "cache/test-repo-*/repodata/*.gz")) + for f in repodata_without_repomd: + os.remove(f) + + # Remove all solv and solvx files + solvx = glob.glob(os.path.join(self.tmpdir, "cache/*.solv*")) + for f in solvx: + os.remove(f) + + # Now we only have cache with just repomd + # repomd is not enough, it doesn't contain the metadata it self -> fail (exception) + + self.assertRaises(dnf.exceptions.RepoError, + self.test_base.fill_sack_from_repos_in_cache, load_system_repo=False) + + def test_exception_with_checksum_mismatch_and_only_repomd(self): + self._setUp_from_repo_path(os.path.join(os.path.abspath(os.path.dirname(__file__)), "repos/rpm")) + + # Remove xml metadata except repomd + # repomd.xml is not compressed and doesn't end with .gz + repodata_without_repomd = glob.glob(os.path.join(self.tmpdir, "cache/test-repo-*/repodata/*.gz")) + for f in repodata_without_repomd: + os.remove(f) + + # Modify checksum of solv file so it doesn't match with repomd + solv = glob.glob(os.path.join(self.tmpdir, "cache/*.solv"))[0] + with open(solv, "a") as opensolv: + opensolv.write("appended text to change checksum") + + # Now we only have cache with solvx, modified solv file and just repomd + # Since we don't have original xml metadata we cannot regenerate solv -> fail (exception) + + self.assertRaises(dnf.exceptions.RepoError, + self.test_base.fill_sack_from_repos_in_cache, load_system_repo=False) + + def test_checksum_mistmatch_regenerates_solv(self): + self._setUp_from_repo_path(os.path.join(os.path.abspath(os.path.dirname(__file__)), "repos/rpm")) + + # Modify checksum of solv file so it doesn't match with repomd + solv = glob.glob(os.path.join(self.tmpdir, "cache/*.solv"))[0] + with open(solv, "a") as opensolv: + opensolv.write("appended text to change checksum") + + # Now we only have cache with solvx, modified solv file and xml metadata. + # Checksum mistmatch causes regeneration of solv file and repo works. + + self.test_base.fill_sack_from_repos_in_cache(load_system_repo=False) + + q = self.test_base.sack.query() + packages = q.run() + self.assertEqual(len(packages), 9) + self.assertEqual(packages[0].evr, "4-4") + + def test_with_modules_yaml(self): + self._setUp_from_repo_path(os.path.join(os.path.abspath(os.path.dirname(__file__)), + "modules/modules/_all/x86_64")) + + # Now we have full cache (also with modules.yaml) + + self.test_base.fill_sack_from_repos_in_cache(load_system_repo=False) + + q = self.test_base.sack.query() + packages = q.run() + + pkg_names = [] + for pkg in packages: + pkg_names.append(pkg.name) + + self.assertEqual(pkg_names, ['grub2', 'httpd', 'httpd', 'httpd-doc', 'httpd-doc', 'httpd-provides-name-doc', + 'httpd-provides-name-version-release-doc', 'libnghttp2']) + + self.module_base = dnf.module.module_base.ModuleBase(self.test_base) + modules, _ = self.module_base._get_modules("base-runtime*") + self.assertEqual(len(modules), 3) + self.assertEqual(modules[0].getFullIdentifier(), "base-runtime:f26:1::") + + def test_with_modular_repo_without_modules_yaml(self): + self._setUp_from_repo_path(os.path.join(os.path.abspath(os.path.dirname(__file__)), + "modules/modules/_all/x86_64")) + + # Remove xml and yaml metadata except repomd + # repomd.xml is not compressed and doesn't end with .gz + repodata_without_repomd = glob.glob(os.path.join(self.tmpdir, "cache/test-repo-*/repodata/*.gz")) + for f in repodata_without_repomd: + os.remove(f) + + # Now we have just solv, *-filenames.solvx and repomd.xml (modules.yaml are not processed into *-modules.solvx) + + self.test_base.fill_sack_from_repos_in_cache(load_system_repo=False) + + q = self.test_base.sack.query() + packages = q.run() + # We have many more packages because they are not hidden by modules + self.assertEqual(len(packages), 44) + self.assertEqual(packages[0].evr, "10.0-7") + + self.module_base = dnf.module.module_base.ModuleBase(self.test_base) + modules, _ = self.module_base._get_modules("*") + self.assertEqual(len(modules), 0)