From 6b340378e521454c5e9295e6fc9498de65a6ae7d Mon Sep 17 00:00:00 2001 From: MSVSphere Packaging Team Date: Fri, 29 Mar 2024 15:28:57 +0300 Subject: [PATCH] import dnf-plugins-core-4.0.21-25.el8 --- .dnf-plugins-core.metadata | 1 + .gitignore | 1 + ...clude-locked-obsoleters-RhBug1957280.patch | 38 + ...age-Allow-running-only-with-metadata.patch | 49 + ...epomanage-documentation-RhBug1898293.patch | 42 + ...back-on-empty-lines-in-etcos-release.patch | 33 + ...en-downloading-packages-RhBug2009894.patch | 40 + ...0006-copr-migrate-all-calls-to-APIv3.patch | 101 + ...t-resolving-of-packages-RhBug2013633.patch | 31 + ...lock-fix-multi-pkg-lock-RhBug2013324.patch | 95 + ...adding-specific-version-RhBug2013332.patch | 31 + ...ing-Fix-wrong-boot-time-RhBug1960437.patch | 25 + ...-new-command-modulesync-RhBug1868047.patch | 439 ++ ...12-Update-translations-RhBug-2017271.patch | 7024 +++++++++++++++++ ...odules-only-from-repo-they-are-handl.patch | 48 + ...at-repomanage-Add-new-option-oldonly.patch | 117 + ...-tsi-for-transaction_action-plugins-.patch | 28 + ...016-Fix-dnf-copr-enable-on-Fedora-35.patch | 28 + .../0017-Disable-dnf-playground-command.patch | 37 + ...Fix-baseurl-for-centos-stream-chroot.patch | 29 + ...precation-warning-in-plugins-copr.py.patch | 42 + ...verification-that-the-project-exists.patch | 49 + ...er-error-message-for-dnf-copr-enable.patch | 114 + ...w-specifying-protocol-as-part-of-hub.patch | 33 + ...chroots-for-CentOS-Stream-RhBug-2058.patch | 37 + ...-when-using-macros-with-source-rpms-.patch | 45 + ...upgrade-plugin-to-core-RhBug-2054235.patch | 1711 ++++ ...ng-when-using-system-upgrade-on-RHEL.patch | 78 + ...offline-upgrade-Add-security-filters.patch | 61 + ...Show-warning-always-for-a-downstream.patch | 62 + SOURCES/0029-Update-translations.patch | 3803 +++++++++ ...only-most-specif-NEVRA-RhBug-1961217.patch | 88 + ...e-derivation-for-systems-with-no-rtc.patch | 55 + ...e-for-reposync-RhBug-2132383-2182004.patch | 34 + ...-assertion-for-no-systemd-unit-exist.patch | 88 + ...lib-reboot-requirement-RhBug-2092033.patch | 51 + ...e-with-binary-garbage-in-smaps-files.patch | 75 + ...g-Add-microcode_ctl-to-a-reboot-list.patch | 40 + SPECS/dnf-plugins-core.spec | 1723 ++++ 39 files changed, 16426 insertions(+) create mode 100644 .dnf-plugins-core.metadata create mode 100644 .gitignore create mode 100644 SOURCES/0001-versionlock-Do-not-exclude-locked-obsoleters-RhBug1957280.patch create mode 100644 SOURCES/0002-repomanage-Allow-running-only-with-metadata.patch create mode 100644 SOURCES/0003-repomanage-Enhance-repomanage-documentation-RhBug1898293.patch create mode 100644 SOURCES/0004-copr-dont-traceback-on-empty-lines-in-etcos-release.patch create mode 100644 SOURCES/0005-reposync-Use-fail_fastFalse-when-downloading-packages-RhBug2009894.patch create mode 100644 SOURCES/0006-copr-migrate-all-calls-to-APIv3.patch create mode 100644 SOURCES/0007-groups-manager-More-benevolent-resolving-of-packages-RhBug2013633.patch create mode 100644 SOURCES/0008-versionlock-fix-multi-pkg-lock-RhBug2013324.patch create mode 100644 SOURCES/0009-Update-documentation-for-adding-specific-version-RhBug2013332.patch create mode 100644 SOURCES/0010-needs-restarting-Fix-wrong-boot-time-RhBug1960437.patch create mode 100644 SOURCES/0011-Add-new-command-modulesync-RhBug1868047.patch create mode 100644 SOURCES/0012-Update-translations-RhBug-2017271.patch create mode 100644 SOURCES/0013-repomanage-Use-modules-only-from-repo-they-are-handl.patch create mode 100644 SOURCES/0014-feat-repomanage-Add-new-option-oldonly.patch create mode 100644 SOURCES/0015-Skip-all-non-rpm-tsi-for-transaction_action-plugins-.patch create mode 100644 SOURCES/0016-Fix-dnf-copr-enable-on-Fedora-35.patch create mode 100644 SOURCES/0017-Disable-dnf-playground-command.patch create mode 100644 SOURCES/0018-Fix-baseurl-for-centos-stream-chroot.patch create mode 100644 SOURCES/0019-Silence-a-deprecation-warning-in-plugins-copr.py.patch create mode 100644 SOURCES/0020-Shorter-verification-that-the-project-exists.patch create mode 100644 SOURCES/0021-Better-error-message-for-dnf-copr-enable.patch create mode 100644 SOURCES/0022-copr-allow-specifying-protocol-as-part-of-hub.patch create mode 100644 SOURCES/0023-copr-Guess-EPEL-chroots-for-CentOS-Stream-RhBug-2058.patch create mode 100644 SOURCES/0024-builddep-Warning-when-using-macros-with-source-rpms-.patch create mode 100644 SOURCES/0025-Move-system-upgrade-plugin-to-core-RhBug-2054235.patch create mode 100644 SOURCES/0026-Add-a-warning-when-using-system-upgrade-on-RHEL.patch create mode 100644 SOURCES/0027-offline-upgrade-Add-security-filters.patch create mode 100644 SOURCES/0028-system-upgrade-Show-warning-always-for-a-downstream.patch create mode 100644 SOURCES/0029-Update-translations.patch create mode 100644 SOURCES/0030-versionlock-Use-only-most-specif-NEVRA-RhBug-1961217.patch create mode 100644 SOURCES/0031-Fix-boot-time-derivation-for-systems-with-no-rtc.patch create mode 100644 SOURCES/0032-Doc-update-for-reposync-RhBug-2132383-2182004.patch create mode 100644 SOURCES/0033-Add-fix-and-test-assertion-for-no-systemd-unit-exist.patch create mode 100644 SOURCES/0034-Fix-zlib-reboot-requirement-RhBug-2092033.patch create mode 100644 SOURCES/0035-Fix-for-issue-with-binary-garbage-in-smaps-files.patch create mode 100644 SOURCES/0036-needs-restarting-Add-microcode_ctl-to-a-reboot-list.patch create mode 100644 SPECS/dnf-plugins-core.spec diff --git a/.dnf-plugins-core.metadata b/.dnf-plugins-core.metadata new file mode 100644 index 0000000..40ecba9 --- /dev/null +++ b/.dnf-plugins-core.metadata @@ -0,0 +1 @@ +40f26a50a6605eacb1e9c4a443f01655fa461767 SOURCES/dnf-plugins-core-4.0.21.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae4a8af --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/dnf-plugins-core-4.0.21.tar.gz diff --git a/SOURCES/0001-versionlock-Do-not-exclude-locked-obsoleters-RhBug1957280.patch b/SOURCES/0001-versionlock-Do-not-exclude-locked-obsoleters-RhBug1957280.patch new file mode 100644 index 0000000..133ea78 --- /dev/null +++ b/SOURCES/0001-versionlock-Do-not-exclude-locked-obsoleters-RhBug1957280.patch @@ -0,0 +1,38 @@ +From a3b9e17628994b43080b8c03b9f665a0e6514cd6 Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Tue, 11 May 2021 08:29:31 +0200 +Subject: [PATCH] versionlock: Do not exclude locked obsoleters (RhBug:1957280) + +The versionlock plugin excludes all obsoleters of locked packages. If +both versions (obsoleted package and its obsoleter) are locked, this +leads to the inability to install the obsoleter package. The patch +protects all locked packages from being excluded as obsoleters. + += changelog = +msg: versionlock: Locking obsoleted package does not make the obsoleter unavailable +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1957280 +--- + plugins/versionlock.py | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/plugins/versionlock.py b/plugins/versionlock.py +index d997130..c89a75d 100644 +--- a/plugins/versionlock.py ++++ b/plugins/versionlock.py +@@ -113,8 +113,10 @@ class VersionLock(dnf.Plugin): + other_versions = all_versions.difference(locked_query) + excludes_query = excludes_query.union(other_versions) + # exclude also anything that obsoletes the locked versions of packages +- excludes_query = excludes_query.union( +- self.base.sack.query().filterm(obsoletes=locked_query)) ++ obsoletes_query = self.base.sack.query().filterm(obsoletes=locked_query) ++ # leave out obsoleters that are also part of locked versions (otherwise the obsoleter package ++ # would not be installable at all) ++ excludes_query = excludes_query.union(obsoletes_query.difference(locked_query)) + + excludes_query.filterm(reponame__neq=hawkey.SYSTEM_REPO_NAME) + if excludes_query: +-- +libgit2 1.0.1 + diff --git a/SOURCES/0002-repomanage-Allow-running-only-with-metadata.patch b/SOURCES/0002-repomanage-Allow-running-only-with-metadata.patch new file mode 100644 index 0000000..2067f00 --- /dev/null +++ b/SOURCES/0002-repomanage-Allow-running-only-with-metadata.patch @@ -0,0 +1,49 @@ +From 716c5978a8036df22d6f5b430ba38c35d034f3ea Mon Sep 17 00:00:00 2001 +From: Aleš Matěj +Date: Tue, 8 Jun 2021 10:25:55 +0200 +Subject: [PATCH] [repomanage] Allow running only with metadata + +Requiring some packages to be present even if there are repodata was +arbitrary because they are never used. +--- + plugins/repomanage.py | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/plugins/repomanage.py b/plugins/repomanage.py +index 445006d..989bd78 100644 +--- a/plugins/repomanage.py ++++ b/plugins/repomanage.py +@@ -58,18 +58,13 @@ class RepoManageCommand(dnf.cli.Command): + if self.opts.new and self.opts.old: + raise dnf.exceptions.Error(_("Pass either --old or --new, not both!")) + +- rpm_list = [] +- rpm_list = self._get_file_list(self.opts.path, ".rpm") + verfile = {} + pkgdict = {} + module_dict = {} # {NameStream: {Version: [modules]}} + all_modular_artifacts = set() + + keepnum = int(self.opts.keep) # the number of items to keep + +- if len(rpm_list) == 0: +- raise dnf.exceptions.Error(_("No files to process")) +- + try: + repo_conf = self.base.repos.add_new_repo("repomanage_repo", self.base.conf, baseurl=[self.opts.path]) + # Always expire the repo, otherwise repomanage could use cached metadata and give identical results +@@ -88,6 +83,11 @@ class RepoManageCommand(dnf.cli.Command): + module_package.getVersionNum(), []).append(module_package) + + except dnf.exceptions.RepoError: ++ rpm_list = [] ++ rpm_list = self._get_file_list(self.opts.path, ".rpm") ++ if len(rpm_list) == 0: ++ raise dnf.exceptions.Error(_("No files to process")) ++ + self.base.reset(sack=True, repos=True) + self.base.fill_sack(load_system_repo=False, load_available_repos=False) + try: +-- +libgit2 1.0.1 + diff --git a/SOURCES/0003-repomanage-Enhance-repomanage-documentation-RhBug1898293.patch b/SOURCES/0003-repomanage-Enhance-repomanage-documentation-RhBug1898293.patch new file mode 100644 index 0000000..7563d02 --- /dev/null +++ b/SOURCES/0003-repomanage-Enhance-repomanage-documentation-RhBug1898293.patch @@ -0,0 +1,42 @@ +From 1b432bada5a3627f729cb42b99b7a93f808e3a80 Mon Sep 17 00:00:00 2001 +From: Aleš Matěj +Date: Tue, 8 Jun 2021 11:48:07 +0200 +Subject: [PATCH] [repomanage] Enhance repomanage documentation (RhBug:1898293) + += changelog = +msg: Enhance repomanage documentation +type: enhancement +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1898293 +--- + doc/repomanage.rst | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/doc/repomanage.rst b/doc/repomanage.rst +index e4da441..e3171ef 100644 +--- a/doc/repomanage.rst ++++ b/doc/repomanage.rst +@@ -31,9 +31,10 @@ Synopsis + Description + ----------- + +-`repomanage` prints newest or oldest packages in a repository specified by for easy piping to xargs or similar programs. In case doesn't contain a valid repository it is searched for rpm packages which are then used instead. ++`repomanage` prints newest or older packages in a repository specified by for easy piping to xargs or similar programs. In case doesn't contain a valid repodata, it is searched for rpm packages which are then used instead. ++If the repodata are present, `repomanage` uses them as the source of truth, it doesn't verify that they match the present rpm packages. In fact, `repomanage` can run with just the repodata, no rpm packages are needed. + +-In order to work correctly with modular packages has to contain repodata with modular metadata. If modular content is present `repomanage` prints packages from newest or oldest versions of each stream in addition to newest or oldest non-modular packages. ++In order to work correctly with modular packages, has to contain repodata with modular metadata. If modular content is present, `repomanage` prints packages from newest or older stream versions in addition to newest or older non-modular packages. + + + Options +@@ -44,7 +45,7 @@ All general DNF options are accepted, see `Options` in :manpage:`dnf(8)` for det + The following options set what packages are displayed. These options are mutually exclusive, i.e. only one can be specified. If no option is specified, the newest packages are shown. + + ``--old`` +- Show older packages. ++ Show older packages (for a package or a stream show all versions except the newest one). + + ``--new`` + Show newest packages. +-- +libgit2 1.0.1 + diff --git a/SOURCES/0004-copr-dont-traceback-on-empty-lines-in-etcos-release.patch b/SOURCES/0004-copr-dont-traceback-on-empty-lines-in-etcos-release.patch new file mode 100644 index 0000000..60a4db5 --- /dev/null +++ b/SOURCES/0004-copr-dont-traceback-on-empty-lines-in-etcos-release.patch @@ -0,0 +1,33 @@ +From ebacba86979d16cdb92ace9d7dc601a85c97b5db Mon Sep 17 00:00:00 2001 +From: Jakub Kadlcik +Date: Tue, 12 Oct 2021 18:30:47 +0200 +Subject: [PATCH] copr: don't traceback on empty lines in /etc/os-release + +Fix RHBZ 1994944 +--- + plugins/copr.py | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/plugins/copr.py b/plugins/copr.py +index 4644495..8841f03 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -50,8 +50,13 @@ except ImportError: + with open('/etc/os-release') as os_release_file: + os_release_data = {} + for line in os_release_file: +- os_release_key, os_release_value = line.rstrip().split('=') +- os_release_data[os_release_key] = os_release_value.strip('"') ++ try: ++ os_release_key, os_release_value = line.rstrip().split('=') ++ os_release_data[os_release_key] = os_release_value.strip('"') ++ except ValueError: ++ # Skip empty lines and everything that is not a simple ++ # variable assignment ++ pass + return (os_release_data['NAME'], os_release_data['VERSION_ID'], None) + + PLUGIN_CONF = 'copr' +-- +libgit2 1.0.1 + diff --git a/SOURCES/0005-reposync-Use-fail_fastFalse-when-downloading-packages-RhBug2009894.patch b/SOURCES/0005-reposync-Use-fail_fastFalse-when-downloading-packages-RhBug2009894.patch new file mode 100644 index 0000000..1e5a989 --- /dev/null +++ b/SOURCES/0005-reposync-Use-fail_fastFalse-when-downloading-packages-RhBug2009894.patch @@ -0,0 +1,40 @@ +From b60f27006cdbdd14fb480aa22610fcd32bfe41e5 Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Wed, 6 Oct 2021 13:40:55 +0200 +Subject: [PATCH] reposync: Use fail_fast=False when downloading packages (RhBug:2009894) + += changelog = +msg: Reposync does not stop downloading packages on the first error +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2009894 +--- + dnf-plugins-core.spec | 2 +- + plugins/reposync.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec +index 83ae6ae..cef836f 100644 +--- a/dnf-plugins-core.spec ++++ b/dnf-plugins-core.spec +@@ -1,4 +1,4 @@ +-%{?!dnf_lowest_compatible: %global dnf_lowest_compatible 4.2.22} ++%{?!dnf_lowest_compatible: %global dnf_lowest_compatible 4.9.2} + %global dnf_plugins_extra 2.0.0 + %global hawkey_version 0.46.1 + %global yum_utils_subpackage_name dnf-utils +diff --git a/plugins/reposync.py b/plugins/reposync.py +index 66c76a7..0ff936f 100644 +--- a/plugins/reposync.py ++++ b/plugins/reposync.py +@@ -303,7 +303,7 @@ class RepoSyncCommand(dnf.cli.Command): + progress, 0) + payloads = [RPMPayloadLocation(pkg, progress, self.pkg_download_path(pkg)) + for pkg in pkglist] +- base._download_remote_payloads(payloads, drpm, progress, None) ++ base._download_remote_payloads(payloads, drpm, progress, None, False) + + def print_urls(self, pkglist): + for pkg in pkglist: +-- +libgit2 1.0.1 + diff --git a/SOURCES/0006-copr-migrate-all-calls-to-APIv3.patch b/SOURCES/0006-copr-migrate-all-calls-to-APIv3.patch new file mode 100644 index 0000000..b23ce54 --- /dev/null +++ b/SOURCES/0006-copr-migrate-all-calls-to-APIv3.patch @@ -0,0 +1,101 @@ +From 54b7c5f91b4ad1db1f716f25cc7973ec7542f0d4 Mon Sep 17 00:00:00 2001 +From: Jakub Kadlcik +Date: Tue, 12 Oct 2021 12:54:05 +0200 +Subject: [PATCH] copr: migrate all calls to APIv3 + +In the latest Copr release we dropped all APIv1 code from frontend. +https://docs.pagure.org/copr.copr/release-notes/2021-10-01.html + +Unfortunatelly we frogot to migrate DNF copr plugin to APIv3 and +therefore the following commands started failing with 404. + + dnf copr search tests + dnf copr list --available-by-user frostyx +--- + plugins/copr.py | 40 +++++++++++++++++----------------------- + 1 file changed, 17 insertions(+), 23 deletions(-) + +diff --git a/plugins/copr.py b/plugins/copr.py +index 8841f03..7fc6c6f 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -355,51 +355,45 @@ Bugzilla. In case of problems, contact the owner of this repository. + "Re-enable the project to fix this.")) + + def _list_user_projects(self, user_name): +- # http://copr.fedorainfracloud.org/api/coprs/ignatenkobrain/ +- api_path = "/api/coprs/{}/".format(user_name) +- res = self.base.urlopen(self.copr_url + api_path, mode='w+') ++ # https://copr.fedorainfracloud.org/api_3/project/list?ownername=ignatenkobrain ++ api_path = "/api_3/project/list?ownername={0}".format(user_name) ++ url = self.copr_url + api_path ++ res = self.base.urlopen(url, mode='w+') + try: + json_parse = json.loads(res.read()) + except ValueError: + raise dnf.exceptions.Error( + _("Can't parse repositories for username '{}'.") + .format(user_name)) + self._check_json_output(json_parse) + section_text = _("List of {} coprs").format(user_name) + self._print_match_section(section_text) +- i = 0 +- while i < len(json_parse["repos"]): +- msg = "{0}/{1} : ".format(user_name, +- json_parse["repos"][i]["name"]) +- desc = json_parse["repos"][i]["description"] +- if not desc: +- desc = _("No description given") ++ ++ for item in json_parse["items"]: ++ msg = "{0}/{1} : ".format(user_name, item["name"]) ++ desc = item["description"] or _("No description given") + msg = self.base.output.fmtKeyValFill(ucd(msg), desc) + print(msg) +- i += 1 + + def _search(self, query): +- # http://copr.fedorainfracloud.org/api/coprs/search/tests/ +- api_path = "/api/coprs/search/{}/".format(query) +- res = self.base.urlopen(self.copr_url + api_path, mode='w+') ++ # https://copr.fedorainfracloud.org/api_3/project/search?query=tests ++ api_path = "/api_3/project/search?query={}".format(query) ++ url = self.copr_url + api_path ++ res = self.base.urlopen(url, mode='w+') + try: + json_parse = json.loads(res.read()) + except ValueError: + raise dnf.exceptions.Error(_("Can't parse search for '{}'." + ).format(query)) + self._check_json_output(json_parse) + section_text = _("Matched: {}").format(query) + self._print_match_section(section_text) +- i = 0 +- while i < len(json_parse["repos"]): +- msg = "{0}/{1} : ".format(json_parse["repos"][i]["username"], +- json_parse["repos"][i]["coprname"]) +- desc = json_parse["repos"][i]["description"] +- if not desc: +- desc = _("No description given.") ++ ++ for item in json_parse["items"]: ++ msg = "{0} : ".format(item["full_name"]) ++ desc = item["description"] or _("No description given.") + msg = self.base.output.fmtKeyValFill(ucd(msg), desc) + print(msg) +- i += 1 + + def _print_match_section(self, text): + formatted = self.base.output.fmtSection(text) +@@ -624,7 +618,7 @@ Bugzilla. In case of problems, contact the owner of this repository. + + @classmethod + def _check_json_output(cls, json_obj): +- if json_obj["output"] != "ok": ++ if "error" in json_obj: + raise dnf.exceptions.Error("{}".format(json_obj["error"])) + + @classmethod +-- +libgit2 1.0.1 + diff --git a/SOURCES/0007-groups-manager-More-benevolent-resolving-of-packages-RhBug2013633.patch b/SOURCES/0007-groups-manager-More-benevolent-resolving-of-packages-RhBug2013633.patch new file mode 100644 index 0000000..274f1c5 --- /dev/null +++ b/SOURCES/0007-groups-manager-More-benevolent-resolving-of-packages-RhBug2013633.patch @@ -0,0 +1,31 @@ +From 5c8f753503be87e5d6237be12eec2330236d78ed Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Mon, 8 Nov 2021 16:51:56 +0100 +Subject: [PATCH] groups-manager: More benevolent resolving of packages (RhBug:2013633) + += changelog = +msg: groups-manager uses for matching packages full NEVRA and not only name. +type: enhancement +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2013633 +--- + plugins/groups_manager.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/plugins/groups_manager.py b/plugins/groups_manager.py +index 382df37..12da183 100644 +--- a/plugins/groups_manager.py ++++ b/plugins/groups_manager.py +@@ -254,7 +254,9 @@ class GroupsManagerCommand(dnf.cli.Command): + # find packages according to specifications from command line + packages = set() + for pkg_spec in self.opts.packages: +- q = self.base.sack.query().filterm(name__glob=pkg_spec).latest() ++ subj = dnf.subject.Subject(pkg_spec) ++ q = subj.get_best_query(self.base.sack, with_nevra=True, ++ with_provides=False, with_filenames=False).latest() + if not q: + logger.warning(_("No match for argument: {}").format(pkg_spec)) + continue +-- +libgit2 1.1.0 + diff --git a/SOURCES/0008-versionlock-fix-multi-pkg-lock-RhBug2013324.patch b/SOURCES/0008-versionlock-fix-multi-pkg-lock-RhBug2013324.patch new file mode 100644 index 0000000..d517175 --- /dev/null +++ b/SOURCES/0008-versionlock-fix-multi-pkg-lock-RhBug2013324.patch @@ -0,0 +1,95 @@ +From 0030ea94dd261b66cac6f08c9dfa99e3d8ee3648 Mon Sep 17 00:00:00 2001 +From: Nicola Sella +Date: Mon, 1 Nov 2021 18:29:40 +0100 +Subject: [PATCH] [versionlock] fix multi pkg lock (RhBug:2013324) + += changelog = +msg: [versionlock] Fix: Multiple package-name-spec arguments don't lock +correctly (RhBug:2001039) +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2013324 +--- + plugins/versionlock.py | 57 +++++++++++++++++++++++++++++++++------------------------ + 1 file changed, 33 insertions(+), 24 deletions(-) + +diff --git a/plugins/versionlock.py b/plugins/versionlock.py +index c89a75d..77b7f91 100644 +--- a/plugins/versionlock.py ++++ b/plugins/versionlock.py +@@ -167,25 +167,27 @@ class VersionLockCommand(dnf.cli.Command): + cmd = self.opts.subcommand + + if cmd == 'add': +- (entry, entry_cmd) = _search_locklist(self.opts.package) +- if entry == '': +- _write_locklist(self.base, self.opts.package, self.opts.raw, True, +- "\n# Added lock on %s\n" % time.ctime(), +- ADDING_SPEC, '') +- elif cmd != entry_cmd: +- raise dnf.exceptions.Error(ALREADY_EXCLUDED.format(entry)) +- else: +- logger.info("%s %s", EXISTING_SPEC, entry) ++ results = _search_locklist(self.opts.package) ++ for entry, entry_cmd in results: ++ if entry_cmd == '': ++ _write_locklist(self.base, [entry], self.opts.raw, True, ++ "\n# Added lock on %s\n" % time.ctime(), ++ ADDING_SPEC, '') ++ elif cmd != entry_cmd: ++ raise dnf.exceptions.Error(ALREADY_EXCLUDED.format(entry)) ++ else: ++ logger.info("%s %s", EXISTING_SPEC, entry) + elif cmd == 'exclude': +- (entry, entry_cmd) = _search_locklist(self.opts.package) +- if entry == '': +- _write_locklist(self.base, self.opts.package, self.opts.raw, False, +- "\n# Added exclude on %s\n" % time.ctime(), +- EXCLUDING_SPEC, '!') +- elif cmd != entry_cmd: +- raise dnf.exceptions.Error(ALREADY_LOCKED.format(entry)) +- else: +- logger.info("%s %s", EXISTING_SPEC, entry) ++ results = _search_locklist(self.opts.package) ++ for entry, entry_cmd in results: ++ if entry_cmd == '': ++ _write_locklist(self.base, [entry], self.opts.raw, False, ++ "\n# Added exclude on %s\n" % time.ctime(), ++ EXCLUDING_SPEC, '!') ++ elif cmd != entry_cmd: ++ raise dnf.exceptions.Error(ALREADY_LOCKED.format(entry)) ++ else: ++ logger.info("%s %s", EXISTING_SPEC, entry) + elif cmd == 'list': + for pat in _read_locklist(): + print(pat) +@@ -233,14 +235,21 @@ def _read_locklist(): + + + def _search_locklist(package): ++ results = [] + found = action = '' + locked_specs = _read_locklist() +- for ent in locked_specs: +- if _match(ent, package): +- found = ent +- action = 'exclude' if ent.startswith('!') else 'add' +- break +- return (found, action) ++ for pkg in package: ++ match = False ++ for ent in locked_specs: ++ found = action = '' ++ if _match(ent, [pkg]): ++ found = ent ++ action = 'exclude' if ent.startswith('!') else 'add' ++ results.append((found, action)) ++ match = True ++ if not match: ++ results.append((pkg, action)) ++ return results + + + def _write_locklist(base, args, raw, try_installed, comment, info, prefix): +-- +libgit2 1.1.0 + diff --git a/SOURCES/0009-Update-documentation-for-adding-specific-version-RhBug2013332.patch b/SOURCES/0009-Update-documentation-for-adding-specific-version-RhBug2013332.patch new file mode 100644 index 0000000..445c330 --- /dev/null +++ b/SOURCES/0009-Update-documentation-for-adding-specific-version-RhBug2013332.patch @@ -0,0 +1,31 @@ +From ed05ce74cfb9151ea5218da0f8b9eccb70c00f70 Mon Sep 17 00:00:00 2001 +From: Nicola Sella +Date: Thu, 11 Nov 2021 13:48:39 +0100 +Subject: [PATCH] Update documentation for adding specific version (RhBug:2013332) + +=changelog= +msg: [versionlock] update documentation for adding specifi version +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2013332 +--- + doc/versionlock.rst | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/doc/versionlock.rst b/doc/versionlock.rst +index 061ce80..1ac7196 100644 +--- a/doc/versionlock.rst ++++ b/doc/versionlock.rst +@@ -97,6 +97,10 @@ Subcommands + Adding versionlock on: mutt-5:1.11.4-1.fc30.* + Adding versionlock on: mutt-5:1.12.1-3.fc30.* + ++ .. note:: Be careful when adding specific versions ++ ++ If you add a package specifying a version with ``dnf versionlock mutt-5:1.11.4-1.fc30.x86_64`` then, if you run ``dnf versionlock add mutt`` ++ versionlock will not add ``mutt-5:1.12.1-3.fc30.x86_64``. + + ``dnf versionlock exclude `` + Add an exclude (within versionlock) for the available packages matching the spec. It means that +-- +libgit2 1.1.0 + diff --git a/SOURCES/0010-needs-restarting-Fix-wrong-boot-time-RhBug1960437.patch b/SOURCES/0010-needs-restarting-Fix-wrong-boot-time-RhBug1960437.patch new file mode 100644 index 0000000..3090d60 --- /dev/null +++ b/SOURCES/0010-needs-restarting-Fix-wrong-boot-time-RhBug1960437.patch @@ -0,0 +1,25 @@ +From dc13ed6bab62a38ef74b00376e2ba05c82115e47 Mon Sep 17 00:00:00 2001 +From: Nicola Sella +Date: Thu, 8 Jul 2021 15:54:21 +0200 +Subject: [PATCH] [needs-restarting] Fix wrong boot time (RhBug:1960437) + +--- + plugins/needs_restarting.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py +index 1fedb73..91dbe66 100644 +--- a/plugins/needs_restarting.py ++++ b/plugins/needs_restarting.py +@@ -199,7 +199,7 @@ class ProcessStart(object): + + @staticmethod + def get_boot_time(): +- return int(os.stat('/proc/1/cmdline').st_mtime) ++ return int(os.stat('/proc/1').st_mtime) + + @staticmethod + def get_sc_clk_tck(): +-- +libgit2 1.1.0 + diff --git a/SOURCES/0011-Add-new-command-modulesync-RhBug1868047.patch b/SOURCES/0011-Add-new-command-modulesync-RhBug1868047.patch new file mode 100644 index 0000000..9dfc812 --- /dev/null +++ b/SOURCES/0011-Add-new-command-modulesync-RhBug1868047.patch @@ -0,0 +1,439 @@ +From 6ea94d9c768eb45975f314e11ab9dd88284fa380 Mon Sep 17 00:00:00 2001 +From: Jaroslav Mracek +Date: Mon, 27 Sep 2021 11:29:01 +0200 +Subject: [PATCH] Add new command modulesync (RhBug:1868047) + +It will download module metadata from all enabled repositories, +module artifacts and profiles of matching modules. Then it creates +a repository. + += changelog = +msg: Add a new subpackage with modulesync command. The command +downloads packages from modules and/or creates a repository with modular +data. +type: enhancement +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1868047 +--- + dnf-plugins-core.spec | 20 ++++++++++++++++++++ + doc/CMakeLists.txt | 1 + + doc/conf.py | 1 + + doc/index.rst | 1 + + doc/modulesync.rst | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + plugins/CMakeLists.txt | 1 + + plugins/modulesync.py | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 335 insertions(+) + create mode 100644 doc/modulesync.rst + create mode 100644 plugins/modulesync.py + +diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec +index cef836f..afdbcbb 100644 +--- a/dnf-plugins-core.spec ++++ b/dnf-plugins-core.spec +@@ -402,6 +402,19 @@ versions of those packages. This allows you to e.g. protect packages from being + updated by newer versions. + %endif + ++%if %{with python3} ++%package -n python3-dnf-plugin-modulesync ++Summary: Download module metadata and packages and create repository ++Requires: python3-%{name} = %{version}-%{release} ++Requires: createrepo_c >= 0.17.4 ++Provides: dnf-plugin-modulesync = %{version}-%{release} ++Provides: dnf-command(modulesync) ++ ++%description -n python3-dnf-plugin-modulesync ++Download module metadata from all enabled repositories, module artifacts and profiles of matching modules and create ++repository. ++%endif ++ + %prep + %autosetup + %if %{with python2} +@@ -762,6 +775,13 @@ ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/ + %endif + %endif + ++%if %{with python3} ++%files -n python3-dnf-plugin-modulesync ++%{python3_sitelib}/dnf-plugins/modulesync.* ++%{python3_sitelib}/dnf-plugins/__pycache__/modulesync.* ++%{_mandir}/man8/dnf-modulesync.* ++%endif ++ + %changelog + * Mon Apr 12 2021 Nicola Sella - 4.0.21-1 + - Add missing command line option to documentation +diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt +index 3fb665d..ff84cf8 100644 +--- a/doc/CMakeLists.txt ++++ b/doc/CMakeLists.txt +@@ -28,6 +28,7 @@ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/dnf-builddep.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-generate_completion_cache.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-groups-manager.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-leaves.8 ++ ${CMAKE_CURRENT_BINARY_DIR}/dnf-modulesync.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-needs-restarting.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-repoclosure.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-repodiff.8 +diff --git a/doc/conf.py b/doc/conf.py +index 645185a..41d6936 100644 +--- a/doc/conf.py ++++ b/doc/conf.py +@@ -254,6 +254,7 @@ man_pages = [ + ('groups-manager', 'dnf-groups-manager', u'DNF groups-manager Plugin', AUTHORS, 8), + ('leaves', 'dnf-leaves', u'DNF leaves Plugin', AUTHORS, 8), + ('local', 'dnf-local', u'DNF local Plugin', AUTHORS, 8), ++ ('modulesync', 'dnf-modulesync', u'DNF modulesync Plugin', AUTHORS, 8), + ('needs_restarting', 'dnf-needs-restarting', u'DNF needs_restarting Plugin', AUTHORS, 8), + ('repoclosure', 'dnf-repoclosure', u'DNF repoclosure Plugin', AUTHORS, 8), + ('repodiff', 'dnf-repodiff', u'DNF repodiff Plugin', AUTHORS, 8), +diff --git a/doc/index.rst b/doc/index.rst +index 7213253..07f6052 100644 +--- a/doc/index.rst ++++ b/doc/index.rst +@@ -37,6 +37,7 @@ This documents core plugins of DNF: + leaves + local + migrate ++ modulesync + needs_restarting + post-transaction-actions + repoclosure +diff --git a/doc/modulesync.rst b/doc/modulesync.rst +new file mode 100644 +index 0000000..2837287 +--- /dev/null ++++ b/doc/modulesync.rst +@@ -0,0 +1,103 @@ ++.. ++ Copyright (C) 2015 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. ++ ++==================== ++DNF modulesync Plugin ++==================== ++ ++Download packages from modules and/or create a repository with modular data. ++ ++-------- ++Synopsis ++-------- ++ ++``dnf modulesync [options] [...]`` ++ ++----------- ++Description ++----------- ++ ++`modulesync` downloads packages from modules according to provided arguments and creates a repository with modular data ++in working directory. In environment with modules it is recommend to use the command for redistribution of packages, ++because DNF does not allow installation of modular packages without modular metadata on the system (Fail-safe ++mechanism). The command without an argument creates a repository like `createrepo_c` but with modular metadata collected ++from all available repositories. ++ ++See examples. ++ ++--------- ++Arguments ++--------- ++ ++```` ++ Module specification for the package to download. The argument is an optional. ++ ++------- ++Options ++------- ++ ++All general DNF options are accepted. Namely, the ``--destdir`` option can be used to specify directory where packages ++will be downloaded and the new repository created. See `Options` in :manpage:`dnf(8)` for details. ++ ++ ++``-n, --newest-only`` ++ Download only packages from the newest modules. ++ ++``--enable_source_repos`` ++ Enable repositories with source packages ++ ++``--enable_debug_repos`` ++ Enable repositories with debug-info and debug-source packages ++ ++``--resolve`` ++ Resolve and download needed dependencies ++ ++-------- ++Examples ++-------- ++ ++``dnf modulesync nodejs`` ++ Download packages from `nodejs` module and crete a repository with modular metadata in working directory ++ ++``dnf download nodejs`` ++ ++``dnf modulesync`` ++ The first `download` command downloads nodejs package into working directory. In environment with modules `nodejs` ++ package can be a modular package therefore when I create a repository I have to insert also modular metadata ++ from available repositories to ensure 100% functionality. Instead of `createrepo_c` use `dnf modulesync` ++ to create a repository in working directory with nodejs package and modular metadata. ++ ++``dnf --destdir=/tmp/my-temp modulesync nodejs:14/minimal --resolve`` ++ Download package required for installation of `minimal` profile from module `nodejs` and stream `14` into directory ++ `/tmp/my-temp` and all required dependencies. Then it will create a repository in `/tmp/my-temp` directory with ++ previously downloaded packages and modular metadata from all available repositories. ++ ++``dnf module install nodejs:14/minimal --downloadonly --destdir=/tmp/my-temp`` ++ ++``dnf modulesync --destdir=/tmp/my-temp`` ++ The first `dnf module install` command downloads package from required for installation of `minimal` profile from module ++ `nodejs` and stream `14` into directory `/tmp/my-temp`. The second command `dnf modulesync` will create ++ a repository in `/tmp/my-temp` directory with previously downloaded packages and modular metadata from all ++ available repositories. In comparison to `dnf --destdir=/tmp/my-temp modulesync nodejs:14/minimal --resolve` it will ++ only download packages required for installation on current system. ++ ++ ++-------- ++See Also ++-------- ++ ++* :manpage:`dnf(8)`, DNF Command Reference +diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt +index f66d3df..59f148f 100644 +--- a/plugins/CMakeLists.txt ++++ b/plugins/CMakeLists.txt +@@ -22,6 +22,7 @@ INSTALL (FILES repograph.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES repomanage.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES reposync.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES show_leaves.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) ++INSTALL (FILES modulesync.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES versionlock.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + + ADD_SUBDIRECTORY (dnfpluginscore) +diff --git a/plugins/modulesync.py b/plugins/modulesync.py +new file mode 100644 +index 0000000..c1c33e4 +--- /dev/null ++++ b/plugins/modulesync.py +@@ -0,0 +1,208 @@ ++# Copyright (C) 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 ++from dnfpluginscore import _, P_, logger ++from dnf.cli.option_parser import OptionParser ++ ++import os ++import shutil ++import subprocess ++ ++import dnf ++import dnf.cli ++import dnf.i18n ++import hawkey ++ ++ ++@dnf.plugin.register_command ++class SyncToolCommand(dnf.cli.Command): ++ ++ aliases = ['modulesync'] ++ summary = _('Download packages from modules and/or create a repository with modular data') ++ ++ def __init__(self, cli): ++ super(SyncToolCommand, self).__init__(cli) ++ ++ @staticmethod ++ def set_argparser(parser): ++ parser.add_argument('module', nargs='*', metavar=_('MODULE'), ++ help=_('modules to download')) ++ parser.add_argument("--enable_source_repos", action='store_true', ++ help=_('enable repositories with source packages')) ++ parser.add_argument("--enable_debug_repos", action='store_true', ++ help=_('enable repositories with debug-info and debug-source packages')) ++ parser.add_argument('--resolve', action='store_true', ++ help=_('resolve and download needed dependencies')) ++ parser.add_argument('-n', '--newest-only', default=False, action='store_true', ++ help=_('download only packages from newest modules')) ++ ++ def configure(self): ++ # setup sack and populate it with enabled repos ++ demands = self.cli.demands ++ demands.sack_activation = True ++ demands.available_repos = True ++ ++ demands.load_system_repo = False ++ ++ if self.opts.enable_source_repos: ++ self.base.repos.enable_source_repos() ++ ++ if self.opts.enable_debug_repos: ++ self.base.repos.enable_debug_repos() ++ ++ if self.opts.destdir: ++ self.base.conf.destdir = self.opts.destdir ++ else: ++ self.base.conf.destdir = dnf.i18n.ucd(os.getcwd()) ++ ++ def run(self): ++ """Execute the util action here.""" ++ ++ pkgs = self.base.sack.query().filterm(empty=True) ++ no_matched_spec = [] ++ for module_spec in self.opts.module: ++ try: ++ pkgs = pkgs.union(self._get_packages_from_modules(module_spec)) ++ except dnf.exceptions.Error: ++ no_matched_spec.append(module_spec) ++ if no_matched_spec: ++ msg = P_("Unable to find a match for argument: '{}'", "Unable to find a match for arguments: '{}'", ++ len(no_matched_spec)).format("' '".join(no_matched_spec)) ++ raise dnf.exceptions.Error(msg) ++ ++ if self.opts.resolve: ++ pkgs = pkgs.union(self._get_providers_of_requires(pkgs)) ++ ++ # download rpms ++ self._do_downloads(pkgs) ++ ++ # Create a repository at destdir with modular data ++ remove_tmp_moduleyamls_files = [] ++ for repo in self.base.repos.iter_enabled(): ++ module_md_path = repo.get_metadata_path('modules') ++ if module_md_path: ++ filename = "".join([repo.id, "-", os.path.basename(module_md_path)]) ++ dest_path = os.path.join(self.base.conf.destdir, filename) ++ shutil.copy(module_md_path, dest_path) ++ remove_tmp_moduleyamls_files.append(dest_path) ++ args = ["createrepo_c", "--update", "--unique-md-filenames", self.base.conf.destdir] ++ p = subprocess.run(args) ++ if p.returncode: ++ msg = _("Creation of repository failed with return code {}. All downloaded content was kept on the system") ++ msg = msg.format(p.returncode) ++ raise dnf.exceptions.Error(msg) ++ for file_path in remove_tmp_moduleyamls_files: ++ os.remove(file_path) ++ ++ def _do_downloads(self, pkgs): ++ """ ++ Perform the download for a list of packages ++ """ ++ pkg_dict = {} ++ for pkg in pkgs: ++ pkg_dict.setdefault(str(pkg), []).append(pkg) ++ ++ to_download = [] ++ ++ for pkg_list in pkg_dict.values(): ++ pkg_list.sort(key=lambda x: (x.repo.priority, x.repo.cost)) ++ to_download.append(pkg_list[0]) ++ if to_download: ++ self.base.download_packages(to_download, self.base.output.progress) ++ ++ def _get_packages_from_modules(self, module_spec): ++ """Gets packages from modules matching module spec ++ 1. From module artifacts ++ 2. From module profiles""" ++ result_query = self.base.sack.query().filterm(empty=True) ++ module_base = dnf.module.module_base.ModuleBase(self.base) ++ module_list, nsvcap = module_base.get_modules(module_spec) ++ if self.opts.newest_only: ++ module_list = self.base._moduleContainer.getLatestModules(module_list, False) ++ for module in module_list: ++ for artifact in module.getArtifacts(): ++ query = self.base.sack.query(flags=hawkey.IGNORE_EXCLUDES).filterm(nevra_strict=artifact) ++ if query: ++ result_query = result_query.union(query) ++ else: ++ msg = _("No match for artifact '{0}' from module '{1}'").format( ++ artifact, module.getFullIdentifier()) ++ logger.warning(msg) ++ if nsvcap.profile: ++ profiles_set = module.getProfiles(nsvcap.profile) ++ else: ++ profiles_set = module.getProfiles() ++ if profiles_set: ++ for profile in profiles_set: ++ for pkg_name in profile.getContent(): ++ query = self.base.sack.query(flags=hawkey.IGNORE_EXCLUDES).filterm(name=pkg_name) ++ # Prefer to add modular providers selected by argument ++ if result_query.intersection(query): ++ continue ++ # Add all packages with the same name as profile described ++ elif query: ++ result_query = result_query.union(query) ++ else: ++ msg = _("No match for package name '{0}' in profile {1} from module {2}")\ ++ .format(pkg_name, profile.getName(), module.getFullIdentifier()) ++ logger.warning(msg) ++ if not module_list: ++ msg = _("No mach for argument '{}'").format(module_spec) ++ raise dnf.exceptions.Error(msg) ++ ++ return result_query ++ ++ def _get_providers_of_requires(self, to_test, done=None, req_dict=None): ++ done = done if done else to_test ++ # req_dict = {} {req : set(pkgs)} ++ if req_dict is None: ++ req_dict = {} ++ test_requires = [] ++ for pkg in to_test: ++ for require in pkg.requires: ++ if require not in req_dict: ++ test_requires.append(require) ++ req_dict.setdefault(require, set()).add(pkg) ++ ++ if self.opts.newest_only: ++ # Prepare cache with all packages related affected by modular filtering ++ names = set() ++ for module in self.base._moduleContainer.getModulePackages(): ++ for artifact in module.getArtifacts(): ++ name, __, __ = artifact.rsplit("-", 2) ++ names.add(name) ++ modular_related = self.base.sack.query(flags=hawkey.IGNORE_EXCLUDES).filterm(provides=names) ++ ++ requires = self.base.sack.query().filterm(empty=True) ++ for require in test_requires: ++ q = self.base.sack.query(flags=hawkey.IGNORE_EXCLUDES).filterm(provides=require) ++ ++ if not q: ++ # TODO(jmracek) Shell we end with an error or with RC 1? ++ logger.warning((_("Unable to satisfy require {}").format(require))) ++ else: ++ if self.opts.newest_only: ++ if not modular_related.intersection(q): ++ q.filterm(latest_per_arch_by_priority=1) ++ requires = requires.union(q.difference(done)) ++ done = done.union(requires) ++ if requires: ++ done = self._get_providers_of_requires(requires, done=done, req_dict=req_dict) ++ ++ return done +-- +libgit2 1.1.0 + diff --git a/SOURCES/0012-Update-translations-RhBug-2017271.patch b/SOURCES/0012-Update-translations-RhBug-2017271.patch new file mode 100644 index 0000000..eff2480 --- /dev/null +++ b/SOURCES/0012-Update-translations-RhBug-2017271.patch @@ -0,0 +1,7024 @@ +From 7844c40c75b3b753284982398962d399f63ef6f0 Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Fri, 18 Mar 2022 15:29:49 +0100 +Subject: [PATCH] Update translations (RhBug:2017271) + +--- + po/dnf-plugins-core.pot | 434 +++++++++++++++------ + po/fr.po | 518 ++++++++++++++++++------- + po/ja.po | 706 ++++++++++++++++++++++++---------- + po/ko.po | 832 +++++++++++++++++++++++++++------------- + po/zh_CN.po | 681 +++++++++++++++++++++----------- + po/zh_TW.po | 512 ++++++++++++++++++------- + 6 files changed, 2580 insertions(+), 1103 deletions(-) + +diff --git a/po/dnf-plugins-core.pot b/po/dnf-plugins-core.pot +index 7cd717e..3ec9a50 100644 +--- a/po/dnf-plugins-core.pot ++++ b/po/dnf-plugins-core.pot +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2020-10-05 09:18-0400\n" ++"POT-Creation-Date: 2022-02-28 11:53+0100\n" + "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" + "Last-Translator: FULL NAME \n" + "Language-Team: LANGUAGE \n" +@@ -137,91 +137,91 @@ msgstr "" + msgid "Changelogs for {}" + msgstr "" + +-#: plugins/config_manager.py:37 ++#: plugins/config_manager.py:38 + #, python-brace-format + msgid "manage {prog} configuration options and repositories" + msgstr "" + +-#: plugins/config_manager.py:44 ++#: plugins/config_manager.py:45 + msgid "repo to modify" + msgstr "" + +-#: plugins/config_manager.py:47 ++#: plugins/config_manager.py:48 + msgid "save the current options (useful with --setopt)" + msgstr "" + +-#: plugins/config_manager.py:50 ++#: plugins/config_manager.py:51 + msgid "add (and enable) the repo from the specified file or url" + msgstr "" + +-#: plugins/config_manager.py:53 ++#: plugins/config_manager.py:54 + msgid "print current configuration values to stdout" + msgstr "" + +-#: plugins/config_manager.py:56 ++#: plugins/config_manager.py:57 + msgid "print variable values to stdout" + msgstr "" + +-#: plugins/config_manager.py:60 ++#: plugins/config_manager.py:61 + msgid "enable repos (automatically saves)" + msgstr "" + +-#: plugins/config_manager.py:63 ++#: plugins/config_manager.py:64 + msgid "disable repos (automatically saves)" + msgstr "" + +-#: plugins/config_manager.py:77 ++#: plugins/config_manager.py:78 + msgid "one of the following arguments is required: {}" + msgstr "" + +-#: plugins/config_manager.py:86 ++#: plugins/config_manager.py:87 + msgid "" + "Warning: --enablerepo/--disablerepo arguments have no meaningwith config " + "manager. Use --set-enabled/--set-disabled instead." + msgstr "" + +-#: plugins/config_manager.py:131 ++#: plugins/config_manager.py:132 + #, python-format + msgid "No matching repo to modify: %s." + msgstr "" + +-#: plugins/config_manager.py:182 ++#: plugins/config_manager.py:183 + #, python-format + msgid "Adding repo from: %s" + msgstr "" + +-#: plugins/config_manager.py:206 ++#: plugins/config_manager.py:207 + msgid "Configuration of repo failed" + msgid_plural "Configuration of repos failed" + msgstr[0] "" + msgstr[1] "" + +-#: plugins/config_manager.py:216 ++#: plugins/config_manager.py:217 + #, python-format + msgid "Could not save repo to repofile %s: %s" + msgstr "" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "y" + msgstr "" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "yes" + msgstr "" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "n" + msgstr "" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "no" + msgstr "" + +-#: plugins/copr.py:79 ++#: plugins/copr.py:84 + msgid "Interact with Copr repositories." + msgstr "" + +-#: plugins/copr.py:81 ++#: plugins/copr.py:86 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -242,53 +242,63 @@ msgid "" + " " + msgstr "" + +-#: plugins/copr.py:107 ++#: plugins/copr.py:112 + msgid "List all installed Copr repositories (default)" + msgstr "" + +-#: plugins/copr.py:109 ++#: plugins/copr.py:114 + msgid "List enabled Copr repositories" + msgstr "" + +-#: plugins/copr.py:111 ++#: plugins/copr.py:116 + msgid "List disabled Copr repositories" + msgstr "" + +-#: plugins/copr.py:113 ++#: plugins/copr.py:118 + msgid "List available Copr repositories by user NAME" + msgstr "" + +-#: plugins/copr.py:115 ++#: plugins/copr.py:120 + msgid "Specify an instance of Copr to work with" + msgstr "" + +-#: plugins/copr.py:149 plugins/copr.py:217 plugins/copr.py:237 ++#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 + msgid "Error: " + msgstr "" + +-#: plugins/copr.py:150 ++#: plugins/copr.py:155 + msgid "" + "specify Copr hub either with `--hub` or using `copr_hub/copr_username/" + "copr_projectname` format" + msgstr "" + +-#: plugins/copr.py:153 ++#: plugins/copr.py:158 + msgid "multiple hubs specified" + msgstr "" + +-#: plugins/copr.py:218 plugins/copr.py:222 ++#: plugins/copr.py:223 plugins/copr.py:227 + msgid "exactly two additional parameters to copr command are required" + msgstr "" + +-#: plugins/copr.py:238 ++#: plugins/copr.py:232 ++msgid "Too many arguments." ++msgstr "" ++ ++#: plugins/copr.py:235 ++msgid "" ++"Bad format of optional chroot. The format is distribution-version-" ++"architecture." ++msgstr "" ++ ++#: plugins/copr.py:250 + msgid "use format `copr_username/copr_projectname` to reference copr project" + msgstr "" + +-#: plugins/copr.py:240 ++#: plugins/copr.py:252 + msgid "bad copr project format" + msgstr "" + +-#: plugins/copr.py:254 ++#: plugins/copr.py:266 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -304,71 +314,71 @@ msgid "" + "Bugzilla. In case of problems, contact the owner of this repository.\n" + msgstr "" + +-#: plugins/copr.py:271 ++#: plugins/copr.py:283 + msgid "Repository successfully enabled." + msgstr "" + +-#: plugins/copr.py:276 ++#: plugins/copr.py:288 + msgid "Repository successfully disabled." + msgstr "" + +-#: plugins/copr.py:280 ++#: plugins/copr.py:292 + msgid "Repository successfully removed." + msgstr "" + +-#: plugins/copr.py:284 plugins/copr.py:693 ++#: plugins/copr.py:296 plugins/copr.py:697 + msgid "Unknown subcommand {}." + msgstr "" + +-#: plugins/copr.py:341 ++#: plugins/copr.py:353 + msgid "" + "* These coprs have repo file with an old format that contains no information " + "about Copr hub - the default one was assumed. Re-enable the project to fix " + "this." + msgstr "" + +-#: plugins/copr.py:353 ++#: plugins/copr.py:366 + msgid "Can't parse repositories for username '{}'." + msgstr "" + +-#: plugins/copr.py:356 ++#: plugins/copr.py:369 + msgid "List of {} coprs" + msgstr "" + +-#: plugins/copr.py:364 ++#: plugins/copr.py:374 + msgid "No description given" + msgstr "" + +-#: plugins/copr.py:376 ++#: plugins/copr.py:386 + msgid "Can't parse search for '{}'." + msgstr "" + +-#: plugins/copr.py:379 ++#: plugins/copr.py:389 + msgid "Matched: {}" + msgstr "" + +-#: plugins/copr.py:387 ++#: plugins/copr.py:394 + msgid "No description given." + msgstr "" + +-#: plugins/copr.py:410 ++#: plugins/copr.py:416 + msgid "Safe and good answer. Exiting." + msgstr "" + +-#: plugins/copr.py:417 ++#: plugins/copr.py:423 + msgid "This command has to be run under the root user." + msgstr "" + +-#: plugins/copr.py:481 ++#: plugins/copr.py:485 + msgid "" + "This repository does not have any builds yet so you cannot enable it now." + msgstr "" + +-#: plugins/copr.py:484 ++#: plugins/copr.py:488 + msgid "Such repository does not exist." + msgstr "" + +-#: plugins/copr.py:528 ++#: plugins/copr.py:532 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -385,44 +395,44 @@ msgid "" + "These repositories have been enabled automatically." + msgstr "" + +-#: plugins/copr.py:549 ++#: plugins/copr.py:553 + msgid "Do you want to keep them enabled?" + msgstr "" + +-#: plugins/copr.py:582 ++#: plugins/copr.py:586 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" + msgstr "" + +-#: plugins/copr.py:593 ++#: plugins/copr.py:597 + msgid "Failed to disable copr repo {}/{}" + msgstr "" + +-#: plugins/copr.py:611 plugins/copr.py:648 ++#: plugins/copr.py:615 plugins/copr.py:652 + msgid "Unknown response from server." + msgstr "" + +-#: plugins/copr.py:633 ++#: plugins/copr.py:637 + msgid "Interact with Playground repository." + msgstr "" + +-#: plugins/copr.py:639 ++#: plugins/copr.py:643 + msgid "Enabling a Playground repository." + msgstr "" + +-#: plugins/copr.py:640 ++#: plugins/copr.py:644 + msgid "Do you want to continue?" + msgstr "" + +-#: plugins/copr.py:683 ++#: plugins/copr.py:687 + msgid "Playground repositories successfully enabled." + msgstr "" + +-#: plugins/copr.py:686 ++#: plugins/copr.py:690 + msgid "Playground repositories successfully disabled." + msgstr "" + +-#: plugins/copr.py:690 ++#: plugins/copr.py:694 + msgid "Playground repositories successfully updated." + msgstr "" + +@@ -541,7 +551,7 @@ msgstr "" + msgid "limit the query to packages of given architectures." + msgstr "" + +-#: plugins/download.py:62 ++#: plugins/download.py:62 plugins/modulesync.py:51 + msgid "resolve and download needed dependencies" + msgstr "" + +@@ -560,7 +570,7 @@ msgstr "" + msgid "when running with --url, limit to specific protocols" + msgstr "" + +-#: plugins/download.py:121 plugins/reposync.py:293 ++#: plugins/download.py:121 plugins/reposync.py:314 + #, python-format + msgid "Failed to get mirror for package: %s" + msgstr "" +@@ -583,6 +593,120 @@ msgstr "" + msgid "No package %s available." + msgstr "" + ++#: plugins/groups_manager.py:49 ++msgid "Invalid group id" ++msgstr "" ++ ++#: plugins/groups_manager.py:58 ++msgid "Invalid translated data, should be in form 'lang:text'" ++msgstr "" ++ ++#: plugins/groups_manager.py:61 ++msgid "Invalid/empty language for translated data" ++msgstr "" ++ ++#: plugins/groups_manager.py:71 ++msgid "Can't generate group id from '{}'. Please specify group id using --id." ++msgstr "" ++ ++#: plugins/groups_manager.py:79 ++msgid "create and edit groups metadata file" ++msgstr "" ++ ++#: plugins/groups_manager.py:90 ++msgid "load groups metadata from file" ++msgstr "" ++ ++#: plugins/groups_manager.py:93 ++msgid "save groups metadata to file" ++msgstr "" ++ ++#: plugins/groups_manager.py:95 ++msgid "load and save groups metadata to file" ++msgstr "" ++ ++#: plugins/groups_manager.py:97 ++msgid "print the result metadata to stdout" ++msgstr "" ++ ++#: plugins/groups_manager.py:100 ++msgid "group id" ++msgstr "" ++ ++#: plugins/groups_manager.py:101 ++msgid "group name" ++msgstr "" ++ ++#: plugins/groups_manager.py:103 ++msgid "group description" ++msgstr "" ++ ++#: plugins/groups_manager.py:105 ++msgid "group display order" ++msgstr "" ++ ++#: plugins/groups_manager.py:108 ++msgid "translated name for the group" ++msgstr "" ++ ++#: plugins/groups_manager.py:111 ++msgid "translated description for the group" ++msgstr "" ++ ++#: plugins/groups_manager.py:115 ++msgid "make the group user visible (default)" ++msgstr "" ++ ++#: plugins/groups_manager.py:118 ++msgid "make the group user invisible" ++msgstr "" ++ ++#: plugins/groups_manager.py:123 ++msgid "add packages to the mandatory section" ++msgstr "" ++ ++#: plugins/groups_manager.py:125 ++msgid "add packages to the optional section" ++msgstr "" ++ ++#: plugins/groups_manager.py:127 ++msgid "remove packages from the group instead of adding them" ++msgstr "" ++ ++#: plugins/groups_manager.py:129 ++msgid "include also direct dependencies for packages" ++msgstr "" ++ ++#: plugins/groups_manager.py:132 ++msgid "package specification" ++msgstr "" ++ ++#: plugins/groups_manager.py:156 ++msgid "Can't edit group without specifying it (use --id or --name)" ++msgstr "" ++ ++#: plugins/groups_manager.py:190 ++msgid "Can't load file \"{}\": {}" ++msgstr "" ++ ++#: plugins/groups_manager.py:206 ++msgid "Can't save file \"{}\": {}" ++msgstr "" ++ ++#: plugins/groups_manager.py:261 ++msgid "No match for argument: {}" ++msgstr "" ++ ++#: plugins/groups_manager.py:298 ++msgid "Can't remove packages from non-existent group" ++msgstr "" ++ ++#: plugins/groups_manager.py:307 ++msgid "" ++"Group id '{}' generated from '{}' is duplicit. Please specify group id using " ++"--id." ++msgstr "" ++ + #: plugins/leaves.py:32 + msgid "List installed packages not required by any other package" + msgstr "" +@@ -615,43 +739,103 @@ msgstr "" + msgid "Migrating history data..." + msgstr "" + +-#: plugins/needs_restarting.py:65 ++#: plugins/modulesync.py:37 ++msgid "" ++"Download packages from modules and/or create a repository with modular data" ++msgstr "" ++ ++#: plugins/modulesync.py:44 ++msgid "MODULE" ++msgstr "" ++ ++#: plugins/modulesync.py:45 ++msgid "modules to download" ++msgstr "" ++ ++#: plugins/modulesync.py:47 ++msgid "enable repositories with source packages" ++msgstr "" ++ ++#: plugins/modulesync.py:49 ++msgid "enable repositories with debug-info and debug-source packages" ++msgstr "" ++ ++#: plugins/modulesync.py:53 ++msgid "download only packages from newest modules" ++msgstr "" ++ ++#: plugins/modulesync.py:85 ++msgid "Unable to find a match for argument: '{}'" ++msgid_plural "Unable to find a match for arguments: '{}'" ++msgstr[0] "" ++msgstr[1] "" ++ ++#: plugins/modulesync.py:107 ++msgid "" ++"Creation of repository failed with return code {}. All downloaded content " ++"was kept on the system" ++msgstr "" ++ ++#: plugins/modulesync.py:144 ++#, python-brace-format ++msgid "No match for artifact '{0}' from module '{1}'" ++msgstr "" ++ ++#: plugins/modulesync.py:162 ++#, python-brace-format ++msgid "No match for package name '{0}' in profile {1} from module {2}" ++msgstr "" ++ ++#: plugins/modulesync.py:166 ++msgid "No mach for argument '{}'" ++msgstr "" ++ ++#. TODO(jmracek) Shell we end with an error or with RC 1? ++#: plugins/modulesync.py:198 ++msgid "Unable to satisfy require {}" ++msgstr "" ++ ++#: plugins/needs_restarting.py:66 + #, python-brace-format + msgid "" + "No installed package found for package name \"{pkg}\" specified in needs-" + "restarting file \"{file}\"." + msgstr "" + +-#: plugins/needs_restarting.py:199 ++#: plugins/needs_restarting.py:220 + msgid "determine updated binaries that need restarting" + msgstr "" + +-#: plugins/needs_restarting.py:204 ++#: plugins/needs_restarting.py:225 + msgid "only consider this user's processes" + msgstr "" + +-#: plugins/needs_restarting.py:206 ++#: plugins/needs_restarting.py:227 + msgid "" + "only report whether a reboot is required (exit code 1) or not (exit code 0)" + msgstr "" + + #: plugins/needs_restarting.py:230 ++msgid "only report affected systemd services" ++msgstr "" ++ ++#: plugins/needs_restarting.py:253 + msgid "Core libraries or services have been updated since boot-up:" + msgstr "" + +-#: plugins/needs_restarting.py:235 ++#: plugins/needs_restarting.py:258 + msgid "Reboot is required to fully utilize these updates." + msgstr "" + +-#: plugins/needs_restarting.py:236 ++#: plugins/needs_restarting.py:259 + msgid "More information:" + msgstr "" + +-#: plugins/needs_restarting.py:240 ++#: plugins/needs_restarting.py:263 + msgid "No core libraries or services have been updated since boot-up." + msgstr "" + +-#: plugins/needs_restarting.py:242 ++#: plugins/needs_restarting.py:265 + msgid "Reboot should not be necessary." + msgstr "" + +@@ -666,13 +850,13 @@ msgstr "" + msgid "Bad Transaction State: %s" + msgstr "" + +-#: plugins/post-transaction-actions.py:153 +-#: plugins/post-transaction-actions.py:155 ++#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:159 + #, python-format + msgid "post-transaction-actions: %s" + msgstr "" + +-#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:161 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" + msgstr "" +@@ -843,112 +1027,124 @@ msgstr "" + msgid "Pass either --old or --new, not both!" + msgstr "" + +-#: plugins/repomanage.py:71 ++#: plugins/repomanage.py:89 + msgid "No files to process" + msgstr "" + +-#: plugins/repomanage.py:93 ++#: plugins/repomanage.py:96 + msgid "Could not open {}" + msgstr "" + +-#: plugins/repomanage.py:177 ++#: plugins/repomanage.py:180 + msgid "Print the older packages" + msgstr "" + +-#: plugins/repomanage.py:179 ++#: plugins/repomanage.py:182 + msgid "Print the newest packages" + msgstr "" + +-#: plugins/repomanage.py:181 ++#: plugins/repomanage.py:184 + msgid "Space separated output, not newline" + msgstr "" + +-#: plugins/repomanage.py:183 ++#: plugins/repomanage.py:186 + msgid "Newest N packages to keep - defaults to 1" + msgstr "" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:189 + msgid "Path to directory" + msgstr "" + +-#: plugins/reposync.py:54 ++#: plugins/reposync.py:55 + msgid "download all packages from remote repo" + msgstr "" + +-#: plugins/reposync.py:63 ++#: plugins/reposync.py:64 + msgid "download only packages for this ARCH" + msgstr "" + +-#: plugins/reposync.py:65 ++#: plugins/reposync.py:66 + msgid "delete local packages no longer present in repository" + msgstr "" + +-#: plugins/reposync.py:67 +-msgid "also download and uncompress comps.xml" +-msgstr "" +- +-#: plugins/reposync.py:69 ++#: plugins/reposync.py:68 + msgid "download all the metadata." + msgstr "" + +-#: plugins/reposync.py:71 +-msgid "download only newest packages per-repo" ++#: plugins/reposync.py:70 ++msgid "Remove packages that fail GPG signature checking after downloading" + msgstr "" + + #: plugins/reposync.py:73 +-msgid "where to store downloaded repositories" ++msgid "also download and uncompress comps.xml" + msgstr "" + + #: plugins/reposync.py:75 +-msgid "Don't add the reponame to the download path." +-msgstr "" +- +-#: plugins/reposync.py:77 + msgid "" + "where to store downloaded repository metadata. Defaults to the value of --" + "download-path." + msgstr "" + ++#: plugins/reposync.py:78 ++msgid "download only newest packages per-repo" ++msgstr "" ++ + #: plugins/reposync.py:80 +-msgid "operate on source packages" ++msgid "Don't add the reponame to the download path." + msgstr "" + + #: plugins/reposync.py:82 ++msgid "where to store downloaded repositories" ++msgstr "" ++ ++#: plugins/reposync.py:84 + msgid "try to set local timestamps of local files by the one on the server" + msgstr "" + +-#: plugins/reposync.py:85 ++#: plugins/reposync.py:87 ++msgid "download only source packages" ++msgstr "" ++ ++#: plugins/reposync.py:89 + msgid "Just list urls of what would be downloaded, don't download" + msgstr "" + +-#: plugins/reposync.py:109 ++#: plugins/reposync.py:113 + msgid "Can't use --norepopath with multiple repositories" + msgstr "" + +-#: plugins/reposync.py:127 ++#: plugins/reposync.py:132 + #, python-format + msgid "Failed to get mirror for metadata: %s" + msgstr "" + +-#: plugins/reposync.py:144 ++#: plugins/reposync.py:149 + msgid "Failed to get mirror for the group file." + msgstr "" + ++#: plugins/reposync.py:168 ++msgid "Removing {}: {}" ++msgstr "" ++ + #: plugins/reposync.py:175 ++msgid "GPG signature check failed." ++msgstr "" ++ ++#: plugins/reposync.py:196 + msgid "Download target '{}' is outside of download path '{}'." + msgstr "" + +-#: plugins/reposync.py:190 ++#: plugins/reposync.py:211 + #, python-format + msgid "[DELETED] %s" + msgstr "" + +-#: plugins/reposync.py:192 ++#: plugins/reposync.py:213 + #, python-format + msgid "failed to delete file %s" + msgstr "" + +-#: plugins/reposync.py:201 ++#: plugins/reposync.py:222 + #, python-format + msgid "comps.xml for repository %s saved" + msgstr "" +@@ -957,64 +1153,68 @@ msgstr "" + msgid "New leaves:" + msgstr "" + +-#: plugins/versionlock.py:32 ++#: plugins/versionlock.py:33 + #, python-format + msgid "Unable to read version lock configuration: %s" + msgstr "" + +-#: plugins/versionlock.py:33 ++#: plugins/versionlock.py:34 + msgid "Locklist not set" + msgstr "" + +-#: plugins/versionlock.py:34 ++#: plugins/versionlock.py:35 + msgid "Adding versionlock on:" + msgstr "" + +-#: plugins/versionlock.py:35 ++#: plugins/versionlock.py:36 + msgid "Adding exclude on:" + msgstr "" + +-#: plugins/versionlock.py:36 ++#: plugins/versionlock.py:37 + msgid "Package already locked in equivalent form:" + msgstr "" + +-#: plugins/versionlock.py:37 ++#: plugins/versionlock.py:38 + msgid "Package {} is already locked" + msgstr "" + +-#: plugins/versionlock.py:38 ++#: plugins/versionlock.py:39 + msgid "Package {} is already excluded" + msgstr "" + +-#: plugins/versionlock.py:39 ++#: plugins/versionlock.py:40 + msgid "Deleting versionlock for:" + msgstr "" + +-#: plugins/versionlock.py:40 ++#: plugins/versionlock.py:41 + msgid "No package found for:" + msgstr "" + +-#: plugins/versionlock.py:41 ++#: plugins/versionlock.py:42 + msgid "Excludes from versionlock plugin were not applied" + msgstr "" + +-#: plugins/versionlock.py:42 ++#: plugins/versionlock.py:43 + msgid "Versionlock plugin: number of lock rules from file \"{}\" applied: {}" + msgstr "" + +-#: plugins/versionlock.py:43 ++#: plugins/versionlock.py:44 + msgid "" + "Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" + msgstr "" + +-#: plugins/versionlock.py:44 ++#: plugins/versionlock.py:45 + msgid "Versionlock plugin: could not parse pattern:" + msgstr "" + +-#: plugins/versionlock.py:130 ++#: plugins/versionlock.py:134 + msgid "control package version locks" + msgstr "" + +-#: plugins/versionlock.py:136 ++#: plugins/versionlock.py:140 + msgid "Use package specifications as they are, do not try to parse them" + msgstr "" ++ ++#: plugins/versionlock.py:160 ++msgid "Subcommand '{}' is deprecated. Use 'exclude' subcommand instead." ++msgstr "" +diff --git a/po/fr.po b/po/fr.po +index dfa06ad..f70bfb2 100644 +--- a/po/fr.po ++++ b/po/fr.po +@@ -3,23 +3,26 @@ + # José Fournier , 2017. #zanata + # Jérôme Fenal , 2017. #zanata + # Jean-Baptiste Holcroft , 2018. #zanata, 2020. +-# Ludek Janda , 2018. #zanata ++# Ludek Janda , 2018. #zanata, 2021, 2022. + # Jean-Baptiste Holcroft , 2019. #zanata, 2020. + # Julien Humbert , 2020. ++# Sundeep Anand , 2021. ++# Transtats , 2022. + msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2020-10-05 09:18-0400\n" +-"PO-Revision-Date: 2020-07-09 13:27+0000\n" +-"Last-Translator: Julien Humbert \n" +-"Language-Team: French \n" ++"POT-Creation-Date: 2022-02-28 11:53+0100\n" ++"PO-Revision-Date: 2022-03-09 12:39+0000\n" ++"Last-Translator: Ludek Janda \n" ++"Language-Team: French \n" + "Language: fr\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=2; plural=n > 1;\n" +-"X-Generator: Weblate 4.1.1\n" ++"X-Generator: Weblate 4.11.2\n" + + #: plugins/builddep.py:45 + msgid "[PACKAGE|PACKAGE.spec]" +@@ -40,8 +43,7 @@ msgstr "définit une macro pour l’interprétation du fichier spec" + + #: plugins/builddep.py:95 + msgid "skip build dependencies not available in repositories" +-msgstr "" +-"ignorer les dépendances de compilation non disponibles dans les dépôts" ++msgstr "ignorer les dépendances de compilation non disponibles dans les dépôts" + + #: plugins/builddep.py:98 + msgid "treat commandline arguments as spec files" +@@ -60,8 +62,7 @@ msgid "Some packages could not be found." + msgstr "Certains paquets n’ont pu être trouvés." + + #. No provides, no files +-#. Richdeps can have no matches but it could be correct (solver must decide +-#. later) ++#. Richdeps can have no matches but it could be correct (solver must decide later) + #: plugins/builddep.py:173 + #, python-format + msgid "No matching package to install: '%s'" +@@ -150,45 +151,45 @@ msgstr "Liste tous les changements" + msgid "Changelogs for {}" + msgstr "Changements pour {}" + +-#: plugins/config_manager.py:37 ++#: plugins/config_manager.py:38 + #, python-brace-format + msgid "manage {prog} configuration options and repositories" + msgstr "gestion de la configuration et des dépôts {prog}" + +-#: plugins/config_manager.py:44 ++#: plugins/config_manager.py:45 + msgid "repo to modify" + msgstr "dépôt à modifier" + +-#: plugins/config_manager.py:47 ++#: plugins/config_manager.py:48 + msgid "save the current options (useful with --setopt)" + msgstr "enregistrer les options actuelles (utile avec --setopt)" + +-#: plugins/config_manager.py:50 ++#: plugins/config_manager.py:51 + msgid "add (and enable) the repo from the specified file or url" + msgstr "ajoute (et active) le dépôt à partir du fichier ou de l’url indiqué" + +-#: plugins/config_manager.py:53 ++#: plugins/config_manager.py:54 + msgid "print current configuration values to stdout" + msgstr "" + "affiche les valeurs de la configuration actuelle sur la sortie standard" + +-#: plugins/config_manager.py:56 ++#: plugins/config_manager.py:57 + msgid "print variable values to stdout" + msgstr "affiche les valeurs des variables sur la sortie standard" + +-#: plugins/config_manager.py:60 ++#: plugins/config_manager.py:61 + msgid "enable repos (automatically saves)" + msgstr "activer les dépôts (enregistre automatiquement)" + +-#: plugins/config_manager.py:63 ++#: plugins/config_manager.py:64 + msgid "disable repos (automatically saves)" + msgstr "désactiver les dépôts (enregistre automatiquement)" + +-#: plugins/config_manager.py:77 ++#: plugins/config_manager.py:78 + msgid "one of the following arguments is required: {}" + msgstr "un des paramètres suivants est nécessaire : {}" + +-#: plugins/config_manager.py:86 ++#: plugins/config_manager.py:87 + msgid "" + "Warning: --enablerepo/--disablerepo arguments have no meaningwith config " + "manager. Use --set-enabled/--set-disabled instead." +@@ -197,48 +198,48 @@ msgstr "" + "signification avec le gestionnaire de configuration. Utilisez plutôt --set-" + "enabled/--set-disabled." + +-#: plugins/config_manager.py:131 ++#: plugins/config_manager.py:132 + #, python-format + msgid "No matching repo to modify: %s." + msgstr "Aucun dépôt correspondant à modifier : %s." + +-#: plugins/config_manager.py:182 ++#: plugins/config_manager.py:183 + #, python-format + msgid "Adding repo from: %s" + msgstr "Ajout du dépôt depuis : %s" + +-#: plugins/config_manager.py:206 ++#: plugins/config_manager.py:207 + msgid "Configuration of repo failed" + msgid_plural "Configuration of repos failed" + msgstr[0] "La configuration du dépôt a échoué" + msgstr[1] "La configuration des dépôts a échoué" + +-#: plugins/config_manager.py:216 ++#: plugins/config_manager.py:217 + #, python-format + msgid "Could not save repo to repofile %s: %s" + msgstr "Sauvegarde impossible du dépôt dans le fichier du dépôt %s : %s" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "y" + msgstr "o" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "yes" + msgstr "oui" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "n" + msgstr "n" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "no" + msgstr "non" + +-#: plugins/copr.py:79 ++#: plugins/copr.py:84 + msgid "Interact with Copr repositories." + msgstr "Interagit avec les dépôts Copr." + +-#: plugins/copr.py:81 ++#: plugins/copr.py:86 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -276,57 +277,69 @@ msgstr "" + " copr search tests\n" + " " + +-#: plugins/copr.py:107 ++#: plugins/copr.py:112 + msgid "List all installed Copr repositories (default)" + msgstr "Lister tous les dépôts Copr installés (par défaut)" + +-#: plugins/copr.py:109 ++#: plugins/copr.py:114 + msgid "List enabled Copr repositories" + msgstr "Lister les dépôts Copr activés" + +-#: plugins/copr.py:111 ++#: plugins/copr.py:116 + msgid "List disabled Copr repositories" + msgstr "Lister les dépôts Copr désactivés" + +-#: plugins/copr.py:113 ++#: plugins/copr.py:118 + msgid "List available Copr repositories by user NAME" + msgstr "Lister les dépôts Copr disponibles par NOM d’utilisateur" + +-#: plugins/copr.py:115 ++#: plugins/copr.py:120 + msgid "Specify an instance of Copr to work with" + msgstr "Précisez une instance Copr avec laquelle travailler" + +-#: plugins/copr.py:149 plugins/copr.py:217 plugins/copr.py:237 ++#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 + msgid "Error: " + msgstr "Erreur : " + +-#: plugins/copr.py:150 ++#: plugins/copr.py:155 + msgid "" +-"specify Copr hub either with `--hub` or using " +-"`copr_hub/copr_username/copr_projectname` format" ++"specify Copr hub either with `--hub` or using `copr_hub/copr_username/" ++"copr_projectname` format" + msgstr "" +-"précisez un hub Copr soit via `--hub` ou en utilisant le format " +-"`hub_copr/utilisateur_copr/projet_copr`" ++"précisez un hub Copr soit via `--hub` ou en utilisant le format `hub_copr/" ++"utilisateur_copr/projet_copr`" + +-#: plugins/copr.py:153 ++#: plugins/copr.py:158 + msgid "multiple hubs specified" + msgstr "de multiples hubs ont été renseignés" + +-#: plugins/copr.py:218 plugins/copr.py:222 ++#: plugins/copr.py:223 plugins/copr.py:227 + msgid "exactly two additional parameters to copr command are required" + msgstr "la commande copr requiert exactement deux paramètres additionnels" + +-#: plugins/copr.py:238 ++#: plugins/copr.py:232 ++msgid "Too many arguments." ++msgstr "Trop d'arguments." ++ ++#: plugins/copr.py:235 ++msgid "" ++"Bad format of optional chroot. The format is distribution-version-" ++"architecture." ++msgstr "" ++"Mauvais format du chroot optionnel. Le format est distribution-version-" ++"architecture." ++ ++#: plugins/copr.py:250 + msgid "use format `copr_username/copr_projectname` to reference copr project" + msgstr "" + "utilisez le format `copr_username/copr_projectname` pour faire référence au " + "projet copr" + +-#: plugins/copr.py:240 ++#: plugins/copr.py:252 + msgid "bad copr project format" + msgstr "mauvais format de projet copr" + +-#: plugins/copr.py:254 ++#: plugins/copr.py:266 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -334,7 +347,8 @@ msgid "" + "\n" + "The Fedora Project does not exercise any power over the contents of\n" + "this repository beyond the rules outlined in the Copr FAQ at\n" +-",\n" ++",\n" + "and packages are not held to any quality or security level.\n" + "\n" + "Please do not file bug reports about these packages in Fedora\n" +@@ -346,83 +360,85 @@ msgstr "" + "\n" + "Le projet Fedora n’exerce aucun pouvoir sur le contenu de ce dépôt au delà\n" + "des règles précisées dans la FAQ Copr \n" +-",\n" ++",\n" + "et les paquets ne sont tenus à aucun niveau de qualité ou de sécurité.\n" + "\n" +-"Veuillez ne pas signaler de bogues à propos de ces paquets dans le Bugzilla de Fedora.\n" ++"Veuillez ne pas signaler de bogues à propos de ces paquets dans le Bugzilla " ++"de Fedora.\n" + "En cas de problèmes, contactez le propriétaire de ce dépôt.\n" + +-#: plugins/copr.py:271 ++#: plugins/copr.py:283 + msgid "Repository successfully enabled." + msgstr "Activation du dépôt réussie." + +-#: plugins/copr.py:276 ++#: plugins/copr.py:288 + msgid "Repository successfully disabled." + msgstr "Désactivation du dépôt réussie." + +-#: plugins/copr.py:280 ++#: plugins/copr.py:292 + msgid "Repository successfully removed." + msgstr "Suppression du dépôt réussie." + +-#: plugins/copr.py:284 plugins/copr.py:693 ++#: plugins/copr.py:296 plugins/copr.py:697 + msgid "Unknown subcommand {}." + msgstr "Sous-commande inconnue {}." + +-#: plugins/copr.py:341 ++#: plugins/copr.py:353 + msgid "" +-"* These coprs have repo file with an old format that contains no information" +-" about Copr hub - the default one was assumed. Re-enable the project to fix " ++"* These coprs have repo file with an old format that contains no information " ++"about Copr hub - the default one was assumed. Re-enable the project to fix " + "this." + msgstr "" + "* Ces Copr ont des fichiers de dépôts avec un ancien format qui ne contient " + "aucune information à propos de Copr hub - celui par défaut a été utilisé. " + "Réactivez le projet pour résoudre le problème." + +-#: plugins/copr.py:353 ++#: plugins/copr.py:366 + msgid "Can't parse repositories for username '{}'." + msgstr "" + "Ne peut analyser les dépôts pour y chercher le nom d’utilisateur « {} »." + +-#: plugins/copr.py:356 ++#: plugins/copr.py:369 + msgid "List of {} coprs" + msgstr "Liste de {} coprs" + +-#: plugins/copr.py:364 ++#: plugins/copr.py:374 + msgid "No description given" + msgstr "Aucune description fournie" + +-#: plugins/copr.py:376 ++#: plugins/copr.py:386 + msgid "Can't parse search for '{}'." + msgstr "Impossible d’analyser la recherche pour « {} »." + +-#: plugins/copr.py:379 ++#: plugins/copr.py:389 + msgid "Matched: {}" + msgstr "Correspondance : {}" + +-#: plugins/copr.py:387 ++#: plugins/copr.py:394 + msgid "No description given." + msgstr "Pas de description fournie." + +-#: plugins/copr.py:410 ++#: plugins/copr.py:416 + msgid "Safe and good answer. Exiting." + msgstr "Réponse sûre et exacte. Fin." + +-#: plugins/copr.py:417 ++#: plugins/copr.py:423 + msgid "This command has to be run under the root user." + msgstr "Cette commande requiert les privilèges du super utilisateur." + +-#: plugins/copr.py:481 ++#: plugins/copr.py:485 + msgid "" + "This repository does not have any builds yet so you cannot enable it now." + msgstr "" + "Ce dépôt ne contient pas encore d’exécutables vous ne pouvez donc pas " + "l’activer." + +-#: plugins/copr.py:484 ++#: plugins/copr.py:488 + msgid "Such repository does not exist." + msgstr "Ce dépôt n’existe pas." + +-#: plugins/copr.py:528 ++#: plugins/copr.py:532 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -451,44 +467,44 @@ msgstr "" + "\n" + "Ces dépôts ont été activés automatiquement." + +-#: plugins/copr.py:549 ++#: plugins/copr.py:553 + msgid "Do you want to keep them enabled?" + msgstr "Souhaitez-vous les maintenir activés ?" + +-#: plugins/copr.py:582 ++#: plugins/copr.py:586 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" + msgstr "Échec de la suppression du dépôt Copr {0}/{1}/{2}" + +-#: plugins/copr.py:593 ++#: plugins/copr.py:597 + msgid "Failed to disable copr repo {}/{}" + msgstr "Échec de la désactivation du dépôt copr {}/{}" + +-#: plugins/copr.py:611 plugins/copr.py:648 ++#: plugins/copr.py:615 plugins/copr.py:652 + msgid "Unknown response from server." + msgstr "Réponse inconnue du serveur." + +-#: plugins/copr.py:633 ++#: plugins/copr.py:637 + msgid "Interact with Playground repository." + msgstr "Interagit avec le dépôt Playground." + +-#: plugins/copr.py:639 ++#: plugins/copr.py:643 + msgid "Enabling a Playground repository." + msgstr "Activation d’un dépôt Playground." + +-#: plugins/copr.py:640 ++#: plugins/copr.py:644 + msgid "Do you want to continue?" + msgstr "Souhaitez-vous continuer ?" + +-#: plugins/copr.py:683 ++#: plugins/copr.py:687 + msgid "Playground repositories successfully enabled." + msgstr "Activation des dépôts Playground réussie." + +-#: plugins/copr.py:686 ++#: plugins/copr.py:690 + msgid "Playground repositories successfully disabled." + msgstr "Désactivation des dépôts Playground réussie." + +-#: plugins/copr.py:690 ++#: plugins/copr.py:694 + msgid "Playground repositories successfully updated." + msgstr "Mise à jour des dépôts Playground réussie." + +@@ -574,8 +590,7 @@ msgstr "" + msgid "" + "Could not find debugsource package for the following available packages: %s" + msgstr "" +-"Impossible de trouver le paquet debugsource pour ces paquets disponibles : " +-"%s" ++"Impossible de trouver le paquet debugsource pour ces paquets disponibles : %s" + + #: plugins/debuginfo-install.py:190 + #, python-format +@@ -619,7 +634,7 @@ msgstr "télécharge plutôt le paquet -debugsource" + msgid "limit the query to packages of given architectures." + msgstr "limite les requêtes de paquets aux architectures spécifiées." + +-#: plugins/download.py:62 ++#: plugins/download.py:62 plugins/modulesync.py:51 + msgid "resolve and download needed dependencies" + msgstr "résout et télécharge les dépendances nécessaires" + +@@ -642,7 +657,7 @@ msgstr "" + msgid "when running with --url, limit to specific protocols" + msgstr "si --url est renseigné, limite aux protocoles spécifiés" + +-#: plugins/download.py:121 plugins/reposync.py:293 ++#: plugins/download.py:121 plugins/reposync.py:314 + #, python-format + msgid "Failed to get mirror for package: %s" + msgstr "Échec de l’obtention du miroir pour le paquet : %s" +@@ -665,6 +680,125 @@ msgstr "Aucune source définie pour %s" + msgid "No package %s available." + msgstr "Aucun paquet %s n’est disponible." + ++#: plugins/groups_manager.py:49 ++msgid "Invalid group id" ++msgstr "id de groupe invalide" ++ ++#: plugins/groups_manager.py:58 ++msgid "Invalid translated data, should be in form 'lang:text'" ++msgstr "Données traduites invalides, doivent être au format « lang : text »" ++ ++#: plugins/groups_manager.py:61 ++msgid "Invalid/empty language for translated data" ++msgstr "Langue non valide / vide pour les données traduites" ++ ++#: plugins/groups_manager.py:71 ++msgid "Can't generate group id from '{}'. Please specify group id using --id." ++msgstr "" ++"Impossible de générer l'id du groupe à partir de «{}». Veuillez spécifier " ++"l'id du groupe en utilisant --id." ++ ++#: plugins/groups_manager.py:79 ++msgid "create and edit groups metadata file" ++msgstr "créer et modifier le fichier de métadonnées des groupes" ++ ++#: plugins/groups_manager.py:90 ++msgid "load groups metadata from file" ++msgstr "charger des métadonnées de groupes à partir d'un fichier" ++ ++#: plugins/groups_manager.py:93 ++msgid "save groups metadata to file" ++msgstr "enregistrer les métadonnées des groupes dans un fichier" ++ ++#: plugins/groups_manager.py:95 ++msgid "load and save groups metadata to file" ++msgstr "charge et enregistre les métadonnées des groupes dans un fichier" ++ ++#: plugins/groups_manager.py:97 ++msgid "print the result metadata to stdout" ++msgstr "affiche les métadonnées du résultat sur la sortie standard" ++ ++#: plugins/groups_manager.py:100 ++msgid "group id" ++msgstr "id du groupe" ++ ++#: plugins/groups_manager.py:101 ++msgid "group name" ++msgstr "Nom du groupe" ++ ++#: plugins/groups_manager.py:103 ++msgid "group description" ++msgstr "description du groupe" ++ ++#: plugins/groups_manager.py:105 ++msgid "group display order" ++msgstr "ordre d'affichage du groupe" ++ ++#: plugins/groups_manager.py:108 ++msgid "translated name for the group" ++msgstr "nom traduit pour le groupe" ++ ++#: plugins/groups_manager.py:111 ++msgid "translated description for the group" ++msgstr "description traduite pour le groupe" ++ ++#: plugins/groups_manager.py:115 ++msgid "make the group user visible (default)" ++msgstr "rendre l'utilisateur du groupe visible (par défaut)" ++ ++#: plugins/groups_manager.py:118 ++msgid "make the group user invisible" ++msgstr "rendre l'utilisateur du groupe invisible" ++ ++#: plugins/groups_manager.py:123 ++msgid "add packages to the mandatory section" ++msgstr "ajoute les paquets à la section obligatoire" ++ ++#: plugins/groups_manager.py:125 ++msgid "add packages to the optional section" ++msgstr "ajoute les paquets à la section optionnelle" ++ ++#: plugins/groups_manager.py:127 ++msgid "remove packages from the group instead of adding them" ++msgstr "supprime les paquets du groupe au lieu de les ajouter" ++ ++#: plugins/groups_manager.py:129 ++msgid "include also direct dependencies for packages" ++msgstr "inclus également les dépendances directes pour les paquets" ++ ++#: plugins/groups_manager.py:132 ++msgid "package specification" ++msgstr "spécification du paquet" ++ ++#: plugins/groups_manager.py:156 ++msgid "Can't edit group without specifying it (use --id or --name)" ++msgstr "" ++"Un groupe ne peut pas être édité sans le spécifier (utilisez --id ou --name)" ++ ++#: plugins/groups_manager.py:190 ++msgid "Can't load file \"{}\": {}" ++msgstr "Impossible de charger le fichier « {} » : {}" ++ ++#: plugins/groups_manager.py:206 ++msgid "Can't save file \"{}\": {}" ++msgstr "Impossible d’enregistrer le fichier « {} » : {}" ++ ++#: plugins/groups_manager.py:261 ++msgid "No match for argument: {}" ++msgstr "Aucune correspondance pour l’argument : {}" ++ ++#: plugins/groups_manager.py:298 ++msgid "Can't remove packages from non-existent group" ++msgstr "Les paquets ne peuvent pas être retirés d'un groupe qui n'existe pas" ++ ++#: plugins/groups_manager.py:307 ++msgid "" ++"Group id '{}' generated from '{}' is duplicit. Please specify group id using " ++"--id." ++msgstr "" ++"L'id du groupe « {} » qui a été généré pour « {} » est en double. Veuillez " ++"le spécifier en utilisant --id." ++ + #: plugins/leaves.py:32 + msgid "List installed packages not required by any other package" + msgstr "" +@@ -698,7 +832,69 @@ msgstr "migrer les données d’historique, de groupe et de yumdb, vers dnf" + msgid "Migrating history data..." + msgstr "Migration des données d’historique …" + +-#: plugins/needs_restarting.py:65 ++#: plugins/modulesync.py:37 ++msgid "" ++"Download packages from modules and/or create a repository with modular data" ++msgstr "" ++"Télécharger les paquets des modules et/ou créer un référentiel avec les " ++"données des modules" ++ ++#: plugins/modulesync.py:44 ++msgid "MODULE" ++msgstr "MODULE" ++ ++#: plugins/modulesync.py:45 ++msgid "modules to download" ++msgstr "modules à télécharger" ++ ++#: plugins/modulesync.py:47 ++msgid "enable repositories with source packages" ++msgstr "activer les dépôts avec les paquets sources" ++ ++#: plugins/modulesync.py:49 ++msgid "enable repositories with debug-info and debug-source packages" ++msgstr "activer les dépôts avec les paquets debug-info et debug-source" ++ ++#: plugins/modulesync.py:53 ++msgid "download only packages from newest modules" ++msgstr "télécharger uniquement les paquets des modules les plus récents" ++ ++#: plugins/modulesync.py:85 ++msgid "Unable to find a match for argument: '{}'" ++msgid_plural "Unable to find a match for arguments: '{}'" ++msgstr[0] "Impossible de trouver une correspondance pour l'argument : '{}'" ++msgstr[1] "Impossible de trouver une correspondance pour les arguments : '{}'" ++ ++#: plugins/modulesync.py:107 ++msgid "" ++"Creation of repository failed with return code {}. All downloaded content " ++"was kept on the system" ++msgstr "" ++"La création du référentiel a échoué avec le code de retour {}. Tout le " ++"contenu téléchargé a été conservé sur le système" ++ ++#: plugins/modulesync.py:144 ++#, python-brace-format ++msgid "No match for artifact '{0}' from module '{1}'" ++msgstr "Aucune correspondance pour l'artefact '{0}' du module '{1}'" ++ ++#: plugins/modulesync.py:162 ++#, python-brace-format ++msgid "No match for package name '{0}' in profile {1} from module {2}" ++msgstr "" ++"Aucune correspondance pour le nom de paquet '{0}' dans le profil {1} du " ++"module {2}" ++ ++#: plugins/modulesync.py:166 ++msgid "No mach for argument '{}'" ++msgstr "Pas de correspondance pour l'argument '{}'" ++ ++#. TODO(jmracek) Shell we end with an error or with RC 1? ++#: plugins/modulesync.py:198 ++msgid "Unable to satisfy require {}" ++msgstr "Impossible de satisfaire le besoin {}" ++ ++#: plugins/needs_restarting.py:66 + #, python-brace-format + msgid "" + "No installed package found for package name \"{pkg}\" specified in needs-" +@@ -707,15 +903,15 @@ msgstr "" + "Aucun paquet installé trouvé pour le nom de paquet « {pkg} » spécifié dans " + "needs-restarting du fichier « {file} »." + +-#: plugins/needs_restarting.py:199 ++#: plugins/needs_restarting.py:220 + msgid "determine updated binaries that need restarting" + msgstr "détermine les binaires mis à jour qui nécessitent un redémarrage" + +-#: plugins/needs_restarting.py:204 ++#: plugins/needs_restarting.py:225 + msgid "only consider this user's processes" + msgstr "considère uniquement les processus de cet utilisateur" + +-#: plugins/needs_restarting.py:206 ++#: plugins/needs_restarting.py:227 + msgid "" + "only report whether a reboot is required (exit code 1) or not (exit code 0)" + msgstr "" +@@ -723,28 +919,32 @@ msgstr "" + "(exit code 0)" + + #: plugins/needs_restarting.py:230 ++msgid "only report affected systemd services" ++msgstr "signaler uniquement les services systemd affectés" ++ ++#: plugins/needs_restarting.py:253 + msgid "Core libraries or services have been updated since boot-up:" + msgstr "" + "les bibliothèques et les services de base ont été mis à jour depuis le " + "démarrage (boot-up) :" + +-#: plugins/needs_restarting.py:235 ++#: plugins/needs_restarting.py:258 + msgid "Reboot is required to fully utilize these updates." + msgstr "" + "Un nouveau démarrage est requis pour pouvoir bénéficier totalement de ces " + "mises à jour." + +-#: plugins/needs_restarting.py:236 ++#: plugins/needs_restarting.py:259 + msgid "More information:" + msgstr "Plus d’information :" + +-#: plugins/needs_restarting.py:240 ++#: plugins/needs_restarting.py:263 + msgid "No core libraries or services have been updated since boot-up." + msgstr "" + "Aucune bibliothèque ou service de base n’a été mis à jour depuis le " + "démarrage." + +-#: plugins/needs_restarting.py:242 ++#: plugins/needs_restarting.py:265 + msgid "Reboot should not be necessary." + msgstr "Un nouveau démarrage ne devrait pas être utile." + +@@ -759,13 +959,13 @@ msgstr "Mauvaise ligne d’action « %s » : %s" + msgid "Bad Transaction State: %s" + msgstr "Mauvais état de transaction : %s" + +-#: plugins/post-transaction-actions.py:153 +-#: plugins/post-transaction-actions.py:155 ++#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:159 + #, python-format + msgid "post-transaction-actions: %s" + msgstr "post-transaction-actions : %s" + +-#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:161 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" + msgstr "post-transaction-actions : mauvaise commande « %s » : %s" +@@ -822,11 +1022,10 @@ msgstr "Affichez des données supplémentaires sur la taille des changements." + + #: plugins/repodiff.py:69 + msgid "" +-"Compare packages also by arch. By default packages are compared just by " +-"name." ++"Compare packages also by arch. By default packages are compared just by name." + msgstr "" +-"Compare également les paquets par architecture. Par défaut, les paquets sont" +-" uniquement comparés par nom." ++"Compare également les paquets par architecture. Par défaut, les paquets sont " ++"uniquement comparés par nom." + + #: plugins/repodiff.py:72 + msgid "Output a simple one line message for modified packages." +@@ -953,119 +1152,133 @@ msgstr "Gère un dossier de paquets rpm" + msgid "Pass either --old or --new, not both!" + msgstr "Passez soit --old, soit --new, mais pas les deux !" + +-#: plugins/repomanage.py:71 ++#: plugins/repomanage.py:89 + msgid "No files to process" + msgstr "Aucun fichier à traiter" + +-#: plugins/repomanage.py:93 ++#: plugins/repomanage.py:96 + msgid "Could not open {}" + msgstr "Ouverture de {} impossible" + +-#: plugins/repomanage.py:177 ++#: plugins/repomanage.py:180 + msgid "Print the older packages" + msgstr "Afficher les paquets plus anciens" + +-#: plugins/repomanage.py:179 ++#: plugins/repomanage.py:182 + msgid "Print the newest packages" + msgstr "Afficher les paquets les plus récents" + +-#: plugins/repomanage.py:181 ++#: plugins/repomanage.py:184 + msgid "Space separated output, not newline" + msgstr "Sorties séparées par des espaces plutôt que des retours à la ligne" + +-#: plugins/repomanage.py:183 ++#: plugins/repomanage.py:186 + msgid "Newest N packages to keep - defaults to 1" + msgstr "N paquets les plus récents à conserver — par défaut 1" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:189 + msgid "Path to directory" + msgstr "Chemin vers le répertoire" + +-#: plugins/reposync.py:54 ++#: plugins/reposync.py:55 + msgid "download all packages from remote repo" + msgstr "télécharger tous les paquets depuis le dépôt distant" + +-#: plugins/reposync.py:63 ++#: plugins/reposync.py:64 + msgid "download only packages for this ARCH" + msgstr "télécharger seulement les paquets s’appliquant à cette ARCH" + +-#: plugins/reposync.py:65 ++#: plugins/reposync.py:66 + msgid "delete local packages no longer present in repository" + msgstr "supprimer les paquets locaux qui ne sont plus présents dans le dépôt" + +-#: plugins/reposync.py:67 +-msgid "also download and uncompress comps.xml" +-msgstr "également télécharger et décompresser comps.xml" +- +-#: plugins/reposync.py:69 ++#: plugins/reposync.py:68 + msgid "download all the metadata." + msgstr "télécharger toutes les métadonnées." + +-#: plugins/reposync.py:71 +-msgid "download only newest packages per-repo" +-msgstr "ne télécharger que les nouveaux paquets per-rep" ++#: plugins/reposync.py:70 ++msgid "Remove packages that fail GPG signature checking after downloading" ++msgstr "" ++"Retire les paquets qui ont échoué la vérification de la signature GPG après " ++"téléchargement" + + #: plugins/reposync.py:73 +-msgid "where to store downloaded repositories" +-msgstr "lieu où stocker les dépôts téléchargés" ++msgid "also download and uncompress comps.xml" ++msgstr "également télécharger et décompresser comps.xml" + + #: plugins/reposync.py:75 +-msgid "Don't add the reponame to the download path." +-msgstr "N’ajoutez pas le nom du dépôt dans le chemin de téléchargement." +- +-#: plugins/reposync.py:77 + msgid "" +-"where to store downloaded repository metadata. Defaults to the value of " +-"--download-path." ++"where to store downloaded repository metadata. Defaults to the value of --" ++"download-path." + msgstr "" +-"là où stocker les métadonnées du dépôt. Prend par défaut la valeur de " +-"--download-path." ++"là où stocker les métadonnées du dépôt. Prend par défaut la valeur de --" ++"download-path." ++ ++#: plugins/reposync.py:78 ++msgid "download only newest packages per-repo" ++msgstr "ne télécharger que les nouveaux paquets per-rep" + + #: plugins/reposync.py:80 +-msgid "operate on source packages" +-msgstr "opère sur les paquets source" ++msgid "Don't add the reponame to the download path." ++msgstr "N’ajoutez pas le nom du dépôt dans le chemin de téléchargement." + + #: plugins/reposync.py:82 ++msgid "where to store downloaded repositories" ++msgstr "lieu où stocker les dépôts téléchargés" ++ ++#: plugins/reposync.py:84 + msgid "try to set local timestamps of local files by the one on the server" + msgstr "" + "essayez de définir les horodatages locaux des fichiers locaux par celui du " + "serveur" + +-#: plugins/reposync.py:85 ++#: plugins/reposync.py:87 ++msgid "download only source packages" ++msgstr "télécharger uniquement les packages sources" ++ ++#: plugins/reposync.py:89 + msgid "Just list urls of what would be downloaded, don't download" + msgstr "" + "Uniquement lister les URL qui seraient téléchargées, ne pas télécharger" + +-#: plugins/reposync.py:109 ++#: plugins/reposync.py:113 + msgid "Can't use --norepopath with multiple repositories" + msgstr "Impossible d’utiliser --norepopath avec de multiples dépôts" + +-#: plugins/reposync.py:127 ++#: plugins/reposync.py:132 + #, python-format + msgid "Failed to get mirror for metadata: %s" + msgstr "Échec de l’obtention du miroir pour les métadonnées : %s" + +-#: plugins/reposync.py:144 ++#: plugins/reposync.py:149 + msgid "Failed to get mirror for the group file." + msgstr "Échec de l’obtention du miroir pour le fichier de groupe." + ++#: plugins/reposync.py:168 ++msgid "Removing {}: {}" ++msgstr "Suppression de « {} » : {}" ++ + #: plugins/reposync.py:175 ++msgid "GPG signature check failed." ++msgstr "La vérification de la signature GPG a échoué." ++ ++#: plugins/reposync.py:196 + msgid "Download target '{}' is outside of download path '{}'." + msgstr "" + "La cible de téléchargement « {} » est en dehors du chemin de téléchargement " + "« {} »." + +-#: plugins/reposync.py:190 ++#: plugins/reposync.py:211 + #, python-format + msgid "[DELETED] %s" + msgstr "[DELETED] %s" + +-#: plugins/reposync.py:192 ++#: plugins/reposync.py:213 + #, python-format + msgid "failed to delete file %s" + msgstr "n’a pas pu supprimer le fichier %s" + +-#: plugins/reposync.py:201 ++#: plugins/reposync.py:222 + #, python-format + msgid "comps.xml for repository %s saved" + msgstr "comps.xml pour le dépôt %s sauvegardé" +@@ -1074,73 +1287,80 @@ msgstr "comps.xml pour le dépôt %s sauvegardé" + msgid "New leaves:" + msgstr "Nouvelles feuilles :" + +-#: plugins/versionlock.py:32 ++#: plugins/versionlock.py:33 + #, python-format + msgid "Unable to read version lock configuration: %s" + msgstr "Ne peut lire la configuration du verrouillage de version : %s" + +-#: plugins/versionlock.py:33 ++#: plugins/versionlock.py:34 + msgid "Locklist not set" + msgstr "Liste des verrouillages non établie" + +-#: plugins/versionlock.py:34 ++#: plugins/versionlock.py:35 + msgid "Adding versionlock on:" + msgstr "Verrouille la version de :" + +-#: plugins/versionlock.py:35 ++#: plugins/versionlock.py:36 + msgid "Adding exclude on:" + msgstr "Exclusion de :" + +-#: plugins/versionlock.py:36 ++#: plugins/versionlock.py:37 + msgid "Package already locked in equivalent form:" + msgstr "Paquet déjà verrouillé sous une forme équivalente :" + +-#: plugins/versionlock.py:37 ++#: plugins/versionlock.py:38 + msgid "Package {} is already locked" + msgstr "Le paquet {} est déjà verrouillé" + +-#: plugins/versionlock.py:38 ++#: plugins/versionlock.py:39 + msgid "Package {} is already excluded" + msgstr "Le paquet {} est déjà exclu" + +-#: plugins/versionlock.py:39 ++#: plugins/versionlock.py:40 + msgid "Deleting versionlock for:" + msgstr "Déverrouille la version de :" + +-#: plugins/versionlock.py:40 ++#: plugins/versionlock.py:41 + msgid "No package found for:" + msgstr "Aucun paquet trouvé pour :" + +-#: plugins/versionlock.py:41 ++#: plugins/versionlock.py:42 + msgid "Excludes from versionlock plugin were not applied" + msgstr "Les exclusions du plugin versionlock n’ont pas été appliquées" + +-#: plugins/versionlock.py:42 ++#: plugins/versionlock.py:43 + msgid "Versionlock plugin: number of lock rules from file \"{}\" applied: {}" + msgstr "" + "Plugin versionlock : nombre de règles de verrouillage du fichier \"{}\" " + "appliquées : {}" + +-#: plugins/versionlock.py:43 +-msgid "Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" ++#: plugins/versionlock.py:44 ++msgid "" ++"Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" + msgstr "" + "Plugin versionlock : nombre de règles d’exclusion du fichier \"{}\" " + "appliquées : {}" + +-#: plugins/versionlock.py:44 ++#: plugins/versionlock.py:45 + msgid "Versionlock plugin: could not parse pattern:" + msgstr "Plugin versionlock : n’a pas pu analyser le modèle :" + +-#: plugins/versionlock.py:130 ++#: plugins/versionlock.py:134 + msgid "control package version locks" + msgstr "contrôle le verrouillage de version des paquets" + +-#: plugins/versionlock.py:136 ++#: plugins/versionlock.py:140 + msgid "Use package specifications as they are, do not try to parse them" + msgstr "" + "Utiliser les spécifications de paquet telles quelles, ne pas essayer de les " + "analyser" + ++#: plugins/versionlock.py:160 ++msgid "Subcommand '{}' is deprecated. Use 'exclude' subcommand instead." ++msgstr "" ++"La sous-commande '{}' est obsolète. Utilisez plutôt la sous-commande " ++"'exclude'." ++ + #~ msgid "" + #~ "\n" + #~ "These repositories have been enabled automatically.\n" +diff --git a/po/ja.po b/po/ja.po +index 5e443ec..c5c4691 100644 +--- a/po/ja.po ++++ b/po/ja.po +@@ -1,20 +1,23 @@ + # Ooyama Yosiyuki , 2015. #zanata +-# Ludek Janda , 2018. #zanata ++# Ludek Janda , 2018. #zanata, 2021. + # Casey Jones , 2020. ++# Sundeep Anand , 2021. ++# Transtats , 2022. + msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2020-10-05 09:18-0400\n" +-"PO-Revision-Date: 2020-05-04 06:40+0000\n" +-"Last-Translator: Casey Jones \n" +-"Language-Team: Japanese \n" ++"POT-Creation-Date: 2022-02-28 11:53+0100\n" ++"PO-Revision-Date: 2022-03-09 12:39+0000\n" ++"Last-Translator: Transtats \n" ++"Language-Team: Japanese \n" + "Language: ja\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=1; plural=0;\n" +-"X-Generator: Weblate 4.0.3\n" ++"X-Generator: Weblate 4.11.2\n" + + #: plugins/builddep.py:45 + msgid "[PACKAGE|PACKAGE.spec]" +@@ -35,7 +38,7 @@ msgstr "スペックファイルの解析にマクロを定義" + + #: plugins/builddep.py:95 + msgid "skip build dependencies not available in repositories" +-msgstr "" ++msgstr "リポジトリーで利用できないビルドの依存関係をスキップします" + + #: plugins/builddep.py:98 + msgid "treat commandline arguments as spec files" +@@ -54,8 +57,7 @@ msgid "Some packages could not be found." + msgstr "一部のパッケージは見つかりませんでした。" + + #. No provides, no files +-#. Richdeps can have no matches but it could be correct (solver must decide +-#. later) ++#. Richdeps can have no matches but it could be correct (solver must decide later) + #: plugins/builddep.py:173 + #, python-format + msgid "No matching package to install: '%s'" +@@ -64,7 +66,8 @@ msgstr "インストール用の一致するパッケージがありません: ' + #: plugins/builddep.py:191 + #, python-format + msgid "Failed to open: '%s', not a valid source rpm file." +-msgstr "開くことに失敗しました: '%s'、有効なソース rpm ファイルではありません。" ++msgstr "" ++"開くことに失敗しました: '%s'、有効なソース rpm ファイルではありません。" + + #: plugins/builddep.py:204 plugins/builddep.py:220 plugins/builddep.py:237 + msgid "Not all dependencies satisfied" +@@ -83,31 +86,35 @@ msgstr "一致するパッケージはありません: %s" + #: plugins/changelog.py:37 + #, python-brace-format + msgid "Not a valid date: \"{0}\"." +-msgstr "" ++msgstr "有効な日付ではありません: \"{0}\"。" + + #: plugins/changelog.py:43 + msgid "Show changelog data of packages" +-msgstr "" ++msgstr "パッケージの changelog データを表示します" + + #: plugins/changelog.py:51 + msgid "" + "show changelog entries since DATE. To avoid ambiguosity, YYYY-MM-DD format " + "is recommended." + msgstr "" ++"DATE 以降の changelog エントリーを表示します。不明瞭さを避けるため、YYYY-MM-" ++"DD のフォーマットが推奨されます。" + + #: plugins/changelog.py:55 + msgid "show given number of changelog entries per package" +-msgstr "" ++msgstr "パッケージごとの changelog エントリーの与えられた数を表示します" + + #: plugins/changelog.py:58 + msgid "" + "show only new changelog entries for packages, that provide an upgrade for " + "some of already installed packages." + msgstr "" ++"パッケージ向けの新しい changelog エントリーのみを表示します。これは、インス" ++"トール済みのパッケージの一部にアップグレードを提供します。" + + #: plugins/changelog.py:60 + msgid "PACKAGE" +-msgstr "" ++msgstr "パッケージ" + + #: plugins/changelog.py:81 plugins/debuginfo-install.py:90 + #, python-format +@@ -116,109 +123,113 @@ msgstr "一致した引数がありません: %s" + + #: plugins/changelog.py:109 + msgid "Listing changelogs since {}" +-msgstr "" ++msgstr "{} 以降の changelogs を一覧表示します" + + #: plugins/changelog.py:111 + msgid "Listing only latest changelog" + msgid_plural "Listing {} latest changelogs" +-msgstr[0] "" ++msgstr[0] "最新の changelog のみを一覧表示します" + + #: plugins/changelog.py:116 + msgid "Listing only new changelogs since installed version of the package" + msgstr "" ++"パッケージのインストールされたバージョン以降の新しい changelogs のみを一覧表" ++"示します" + + #: plugins/changelog.py:118 + msgid "Listing all changelogs" +-msgstr "" ++msgstr "すべての changelogs を一覧表示します" + + #: plugins/changelog.py:122 + msgid "Changelogs for {}" + msgstr "{} の Changelogs" + +-#: plugins/config_manager.py:37 ++#: plugins/config_manager.py:38 + #, python-brace-format + msgid "manage {prog} configuration options and repositories" +-msgstr "" ++msgstr "{prog} 設定オプションおよびリポジトリーを管理します" + +-#: plugins/config_manager.py:44 ++#: plugins/config_manager.py:45 + msgid "repo to modify" + msgstr "修正する repo" + +-#: plugins/config_manager.py:47 ++#: plugins/config_manager.py:48 + msgid "save the current options (useful with --setopt)" + msgstr "現在のオプションを保存 (--setopt で有用)" + +-#: plugins/config_manager.py:50 ++#: plugins/config_manager.py:51 + msgid "add (and enable) the repo from the specified file or url" + msgstr "指定されたファイルまたは url から repo を追加 (および有効化)" + +-#: plugins/config_manager.py:53 ++#: plugins/config_manager.py:54 + msgid "print current configuration values to stdout" + msgstr "stdout に現在の設定値を印刷" + +-#: plugins/config_manager.py:56 ++#: plugins/config_manager.py:57 + msgid "print variable values to stdout" + msgstr "stdout に変数値を印刷" + +-#: plugins/config_manager.py:60 ++#: plugins/config_manager.py:61 + msgid "enable repos (automatically saves)" +-msgstr "" ++msgstr "レポを有効にする (自動保存)" + +-#: plugins/config_manager.py:63 ++#: plugins/config_manager.py:64 + msgid "disable repos (automatically saves)" +-msgstr "" ++msgstr "レポを無効にする (自動保存)" + +-#: plugins/config_manager.py:77 ++#: plugins/config_manager.py:78 + msgid "one of the following arguments is required: {}" +-msgstr "" ++msgstr "以下のいずれかの引数が必要です。{}" + +-#: plugins/config_manager.py:86 ++#: plugins/config_manager.py:87 + msgid "" + "Warning: --enablerepo/--disablerepo arguments have no meaningwith config " + "manager. Use --set-enabled/--set-disabled instead." + msgstr "" ++"警告: --enablerepo/--disablerepo の引数は config manager では意味がありませ" ++"ん。代わりに -set-enabled/--set-disabled を使用してください。" + +-#: plugins/config_manager.py:131 ++#: plugins/config_manager.py:132 + #, python-format + msgid "No matching repo to modify: %s." + msgstr "修正用の一致する repo はありません: %s." + +-#: plugins/config_manager.py:182 ++#: plugins/config_manager.py:183 + #, python-format + msgid "Adding repo from: %s" + msgstr "repo の追加: %s" + +-#: plugins/config_manager.py:206 ++#: plugins/config_manager.py:207 + msgid "Configuration of repo failed" + msgid_plural "Configuration of repos failed" + msgstr[0] "repo の設定に失敗しました" + +-#: plugins/config_manager.py:216 ++#: plugins/config_manager.py:217 + #, python-format + msgid "Could not save repo to repofile %s: %s" + msgstr "repofile %s に repo を保存できませんでした: %s" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "y" + msgstr "y" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "yes" + msgstr "はい" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "n" + msgstr "n" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "no" + msgstr "いいえ" + +-#: plugins/copr.py:79 ++#: plugins/copr.py:84 + msgid "Interact with Copr repositories." + msgstr "Copr リポジトリーとの対話。" + +-#: plugins/copr.py:81 ++#: plugins/copr.py:86 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -246,7 +257,7 @@ msgstr "" + " list --available-by-user=NAME\n" + " search project\n" + "\n" +-" Examples:\n" ++" 例:\n" + " copr enable rhscl/perl516 epel-6-x86_64\n" + " copr enable ignatenkobrain/ocltoys\n" + " copr disable rhscl/perl516\n" +@@ -256,53 +267,69 @@ msgstr "" + " copr search tests\n" + " " + +-#: plugins/copr.py:107 ++#: plugins/copr.py:112 + msgid "List all installed Copr repositories (default)" +-msgstr "インストール済みのすべての Copr リポジトリーを一覧表示します (デフォルト)" ++msgstr "" ++"インストール済みのすべての Copr リポジトリーを一覧表示します (デフォルト)" + +-#: plugins/copr.py:109 ++#: plugins/copr.py:114 + msgid "List enabled Copr repositories" + msgstr "有効化された Copr リポジトリーを一覧表示します" + +-#: plugins/copr.py:111 ++#: plugins/copr.py:116 + msgid "List disabled Copr repositories" + msgstr "無効化された Copr リポジトリーを一覧表示します" + +-#: plugins/copr.py:113 ++#: plugins/copr.py:118 + msgid "List available Copr repositories by user NAME" + msgstr "利用可能な Copr リポジトリーをユーザー NAME ごとに一覧表示します" + +-#: plugins/copr.py:115 ++#: plugins/copr.py:120 + msgid "Specify an instance of Copr to work with" +-msgstr "" ++msgstr "作業する Copr のインスタンスを指定します" + +-#: plugins/copr.py:149 plugins/copr.py:217 plugins/copr.py:237 ++#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 + msgid "Error: " + msgstr "エラー: " + +-#: plugins/copr.py:150 ++#: plugins/copr.py:155 + msgid "" +-"specify Copr hub either with `--hub` or using " +-"`copr_hub/copr_username/copr_projectname` format" ++"specify Copr hub either with `--hub` or using `copr_hub/copr_username/" ++"copr_projectname` format" + msgstr "" ++"`--hub` または `copr_hub/copr_username/copr_projectname` フォーマットを使っ" ++"て、Copr ハブを指定します" + +-#: plugins/copr.py:153 ++#: plugins/copr.py:158 + msgid "multiple hubs specified" +-msgstr "" ++msgstr "複数のハブが指定されています" + +-#: plugins/copr.py:218 plugins/copr.py:222 ++#: plugins/copr.py:223 plugins/copr.py:227 + msgid "exactly two additional parameters to copr command are required" + msgstr "copr コマンドに厳密に 2 つの追加パラメーターが必要です" + +-#: plugins/copr.py:238 ++#: plugins/copr.py:232 ++msgid "Too many arguments." ++msgstr "引数が多すぎます。" ++ ++#: plugins/copr.py:235 ++msgid "" ++"Bad format of optional chroot. The format is distribution-version-" ++"architecture." ++msgstr "オプションの chroot の形式が無効です。正しい形式は distribution-version-" ++"architecture です。" ++ ++#: plugins/copr.py:250 + msgid "use format `copr_username/copr_projectname` to reference copr project" +-msgstr "copr プロジェクトを参照するには `copr_username/copr_projectname` 形式を使用します" ++msgstr "" ++"copr プロジェクトを参照するには `copr_username/copr_projectname` 形式を使用し" ++"ます" + +-#: plugins/copr.py:240 ++#: plugins/copr.py:252 + msgid "bad copr project format" + msgstr "不正な copr プロジェクト形式" + +-#: plugins/copr.py:254 ++#: plugins/copr.py:266 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -310,78 +337,96 @@ msgid "" + "\n" + "The Fedora Project does not exercise any power over the contents of\n" + "this repository beyond the rules outlined in the Copr FAQ at\n" +-",\n" ++",\n" + "and packages are not held to any quality or security level.\n" + "\n" + "Please do not file bug reports about these packages in Fedora\n" + "Bugzilla. In case of problems, contact the owner of this repository.\n" + msgstr "" ++"\n" ++"Copr リポジトリーを有効化しています。このリポジトリーは\n" ++"主要ディストリビューションの一部ではないため、品質が一定していない点に注意し" ++"てください。\n" ++"\n" ++"Fedora Project は、このリポジトリーのコンテンツに関して、 の \n" ++"Copr FAQ で示されたルールを超えて権利を行使することは\n" ++"ありません。また、パッケージは、任意の品質またはセキュリ\n" ++"ティーレベルを固守していません。\n" ++"\n" ++"Fedora Bugzilla でこれらのパッケージに関するバグ報告をしないでください。\n" ++"問題が発生した場合は、このリポジトリーのオーナーに連絡してください。\n" + +-#: plugins/copr.py:271 ++#: plugins/copr.py:283 + msgid "Repository successfully enabled." + msgstr "リポジトリが正常に有効化されました。" + +-#: plugins/copr.py:276 ++#: plugins/copr.py:288 + msgid "Repository successfully disabled." + msgstr "リポジトリが正常に無効化されました。" + +-#: plugins/copr.py:280 ++#: plugins/copr.py:292 + msgid "Repository successfully removed." + msgstr "リポジトリーが正常に削除されました。" + +-#: plugins/copr.py:284 plugins/copr.py:693 ++#: plugins/copr.py:296 plugins/copr.py:697 + msgid "Unknown subcommand {}." + msgstr "不明なサブコマンド {}。" + +-#: plugins/copr.py:341 ++#: plugins/copr.py:353 + msgid "" +-"* These coprs have repo file with an old format that contains no information" +-" about Copr hub - the default one was assumed. Re-enable the project to fix " ++"* These coprs have repo file with an old format that contains no information " ++"about Copr hub - the default one was assumed. Re-enable the project to fix " + "this." + msgstr "" ++"* これらの coprs には、Copr ハブに関する情報がない古いフォーマットの repo " ++"ファイルがあります。デフォルトは仮定です。これを修正するには、プロジェクトを" ++"再度有効化してください。" + +-#: plugins/copr.py:353 ++#: plugins/copr.py:366 + msgid "Can't parse repositories for username '{}'." + msgstr "ユーザー名 '{}' のリポジトリーを解析できません。" + +-#: plugins/copr.py:356 ++#: plugins/copr.py:369 + msgid "List of {} coprs" + msgstr "{} coprs の一覧" + +-#: plugins/copr.py:364 ++#: plugins/copr.py:374 + msgid "No description given" + msgstr "説明がありません" + +-#: plugins/copr.py:376 ++#: plugins/copr.py:386 + msgid "Can't parse search for '{}'." + msgstr "'{}' の検索を解析できません。" + +-#: plugins/copr.py:379 ++#: plugins/copr.py:389 + msgid "Matched: {}" + msgstr "一致: {}" + +-#: plugins/copr.py:387 ++#: plugins/copr.py:394 + msgid "No description given." + msgstr "説明が与えられていません。" + +-#: plugins/copr.py:410 ++#: plugins/copr.py:416 + msgid "Safe and good answer. Exiting." + msgstr "安全で優れた回答。終了中。" + +-#: plugins/copr.py:417 ++#: plugins/copr.py:423 + msgid "This command has to be run under the root user." + msgstr "このコマンドは root ユーザーの下で実行する必要があります。" + +-#: plugins/copr.py:481 ++#: plugins/copr.py:485 + msgid "" + "This repository does not have any builds yet so you cannot enable it now." +-msgstr "このリポジトリーにはまだビルドがありませんので、今すぐ有効化できません。" ++msgstr "" ++"このリポジトリーにはまだビルドがありませんので、今すぐ有効化できません。" + +-#: plugins/copr.py:484 ++#: plugins/copr.py:488 + msgid "Such repository does not exist." + msgstr "そのようなリポジトリーは存在しません。" + +-#: plugins/copr.py:528 ++#: plugins/copr.py:532 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -397,47 +442,58 @@ msgid "" + "\n" + "These repositories have been enabled automatically." + msgstr "" ++"有効化した Copr リポジトリーの管理者は\n" ++"他のリポジトリーに依存するように決めました。\n" ++"そのようなリポジトリーは通常、主な Corp " ++"レジストリー(ランタイム依存関係を提供) から RPM を\n" ++"正常にインストールするために必要です。\n" ++"\n" ++"上記の品質とバグ報告についての注意点がここでも適用\n" ++"されますが、Fedora Project は内容を管理していないことに\n" ++"注意してください。以下のリストを確認してください。\n" ++"\n" ++"{0}\n" ++"\n" ++"これらのリポジトリーは自動的に有効になっています。" + +-#: plugins/copr.py:549 ++#: plugins/copr.py:553 + msgid "Do you want to keep them enabled?" +-msgstr "" ++msgstr "有効にしておきますか?" + +-#: plugins/copr.py:582 ++#: plugins/copr.py:586 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" +-msgstr "" ++msgstr "copr repo {0}/{1}/{2} の削除に失敗しました" + +-#: plugins/copr.py:593 ++#: plugins/copr.py:597 + msgid "Failed to disable copr repo {}/{}" +-msgstr "copr repo {}/{} の無効化に失敗しました。" ++msgstr "copr repo {}/{} の無効化に失敗しました" + +-#: plugins/copr.py:611 plugins/copr.py:648 ++#: plugins/copr.py:615 plugins/copr.py:652 + msgid "Unknown response from server." + msgstr "サーバーからの不明な応答です。" + +-#: plugins/copr.py:633 ++#: plugins/copr.py:637 + msgid "Interact with Playground repository." + msgstr "Playground リポジトリーとの対話。" + +-#: plugins/copr.py:639 +-#, fuzzy +-#| msgid "Interact with Playground repository." ++#: plugins/copr.py:643 + msgid "Enabling a Playground repository." +-msgstr "Playground リポジトリーとの対話。" ++msgstr "Playgroundのリポジトリーの有効化。" + +-#: plugins/copr.py:640 ++#: plugins/copr.py:644 + msgid "Do you want to continue?" +-msgstr "" ++msgstr "続行しますか?" + +-#: plugins/copr.py:683 ++#: plugins/copr.py:687 + msgid "Playground repositories successfully enabled." + msgstr "Playground リポジトリーが正常に有効化されました。" + +-#: plugins/copr.py:686 ++#: plugins/copr.py:690 + msgid "Playground repositories successfully disabled." + msgstr "Playground リポジトリーが正常に無効化されました。" + +-#: plugins/copr.py:690 ++#: plugins/copr.py:694 + msgid "Playground repositories successfully updated." + msgstr "Playground リポジトリーが正常に更新されました。" + +@@ -474,7 +530,9 @@ msgstr "記録されたパッケージの最新バージョンをインストー + msgid "" + "Ignore architecture and install missing packages matching the name, epoch, " + "version and release." +-msgstr "アーキテクチャーを無視し、名前、エポック、バージョン、およびリリースと一致する不足のパッケージをインストールします。" ++msgstr "" ++"アーキテクチャーを無視し、名前、エポック、バージョン、およびリリースと一致す" ++"る不足のパッケージをインストールします。" + + #: plugins/debug.py:196 + msgid "limit to specified type" +@@ -485,6 +543,8 @@ msgid "" + "Allow removing of install-only packages. Using this option may result in an " + "attempt to remove the running kernel." + msgstr "" ++"インストールのみのパッケージの削除を許可します。このオプションを使用すると、" ++"実行しているカーネルの削除を試みる可能性があります。" + + #: plugins/debug.py:202 + msgid "name of dump file" +@@ -509,24 +569,30 @@ msgstr "debuginfo パッケージのインストール" + msgid "" + "Could not find debuginfo package for the following available packages: %s" + msgstr "" ++"次の利用可能なパッケージの debuginfo パッケージが見つかりませんでした: %s" + + #: plugins/debuginfo-install.py:185 + #, python-format + msgid "" + "Could not find debugsource package for the following available packages: %s" + msgstr "" ++"次の利用可能なパッケージの debugsource パッケージが見つかりませんでした: %s" + + #: plugins/debuginfo-install.py:190 + #, python-format + msgid "" + "Could not find debuginfo package for the following installed packages: %s" + msgstr "" ++"次のインストールされたパッケージの debuginfo パッケージが見つかりませんでし" ++"た: %s" + + #: plugins/debuginfo-install.py:195 + #, python-format + msgid "" + "Could not find debugsource package for the following installed packages: %s" + msgstr "" ++"次のインストールされたパッケージの debugsource パッケージが見つかりませんでし" ++"た: %s" + + #: plugins/debuginfo-install.py:199 + msgid "Unable to find a match" +@@ -550,13 +616,13 @@ msgstr "代わりに -debuginfo パッケージをダウンロードします" + + #: plugins/download.py:57 + msgid "download the -debugsource package instead" +-msgstr "" ++msgstr "代わりに、-debugsource パッケージをダウンロードします" + + #: plugins/download.py:60 + msgid "limit the query to packages of given architectures." + msgstr "特定のアーキテクチャーのパッケージへのクエリーを制限します。" + +-#: plugins/download.py:62 ++#: plugins/download.py:62 plugins/modulesync.py:51 + msgid "resolve and download needed dependencies" + msgstr "必要な依存関係を解決し、ダウンロードします" + +@@ -565,17 +631,20 @@ msgid "" + "when running with --resolve, download all dependencies (do not exclude " + "already installed ones)" + msgstr "" ++"--resolve で実行する場合、すべての依存関係をダウンロードします (インストール" ++"済みのものを除外しないでください)" + + #: plugins/download.py:67 + msgid "" + "print list of urls where the rpms can be downloaded instead of downloading" +-msgstr "ダウンロードする代わりに、rpm をダウンロードできる url の一覧を印刷します" ++msgstr "" ++"ダウンロードする代わりに、rpm をダウンロードできる url の一覧を印刷します" + + #: plugins/download.py:72 + msgid "when running with --url, limit to specific protocols" + msgstr "--url で実行中の際は、特定のプロトコルに限定します" + +-#: plugins/download.py:121 plugins/reposync.py:293 ++#: plugins/download.py:121 plugins/reposync.py:314 + #, python-format + msgid "Failed to get mirror for package: %s" + msgstr "パッケージのミラー取得に失敗しました: %s" +@@ -598,9 +667,129 @@ msgstr "%s に対して定義されているソース rpm はありません" + msgid "No package %s available." + msgstr "利用可能なパッケージ %s はありません。" + ++#: plugins/groups_manager.py:49 ++msgid "Invalid group id" ++msgstr "'無効なグループ ID" ++ ++#: plugins/groups_manager.py:58 ++msgid "Invalid translated data, should be in form 'lang:text'" ++msgstr "無効な翻訳データです。'lang:text' の形式で指定する必要があります" ++ ++#: plugins/groups_manager.py:61 ++msgid "Invalid/empty language for translated data" ++msgstr "翻訳されたデータの無効または空な言語" ++ ++#: plugins/groups_manager.py:71 ++msgid "Can't generate group id from '{}'. Please specify group id using --id." ++msgstr "" ++"'{}' からグループ ID を生成できません。--id を使用してグループ ID を指定して" ++"ください。" ++ ++#: plugins/groups_manager.py:79 ++msgid "create and edit groups metadata file" ++msgstr "グループメタデータファイルの作成および編集" ++ ++#: plugins/groups_manager.py:90 ++msgid "load groups metadata from file" ++msgstr "ファイルからグループメタデータを読み込みます" ++ ++#: plugins/groups_manager.py:93 ++msgid "save groups metadata to file" ++msgstr "グループメタデータをファイルに保存します" ++ ++#: plugins/groups_manager.py:95 ++msgid "load and save groups metadata to file" ++msgstr "グループメタデータをファイルにロードして保存します" ++ ++#: plugins/groups_manager.py:97 ++msgid "print the result metadata to stdout" ++msgstr "生成されたメタデータを stdout に出力します" ++ ++#: plugins/groups_manager.py:100 ++msgid "group id" ++msgstr "グループ id" ++ ++#: plugins/groups_manager.py:101 ++msgid "group name" ++msgstr "グループ名" ++ ++#: plugins/groups_manager.py:103 ++msgid "group description" ++msgstr "グループ説明" ++ ++#: plugins/groups_manager.py:105 ++msgid "group display order" ++msgstr "グループ表示順序" ++ ++#: plugins/groups_manager.py:108 ++msgid "translated name for the group" ++msgstr "グループの翻訳名" ++ ++#: plugins/groups_manager.py:111 ++msgid "translated description for the group" ++msgstr "グループの翻訳説明" ++ ++#: plugins/groups_manager.py:115 ++msgid "make the group user visible (default)" ++msgstr "グループユーザーを表示させる (デフォルト)" ++ ++#: plugins/groups_manager.py:118 ++msgid "make the group user invisible" ++msgstr "グループユーザーを非表示の状態にする" ++ ++#: plugins/groups_manager.py:123 ++msgid "add packages to the mandatory section" ++msgstr "必須セクションへのパッケージの追加" ++ ++#: plugins/groups_manager.py:125 ++msgid "add packages to the optional section" ++msgstr "オプションセクションへのパッケージの追加" ++ ++#: plugins/groups_manager.py:127 ++msgid "remove packages from the group instead of adding them" ++msgstr "パッケージを追加する代わりに、グループからパッケージを削除します" ++ ++#: plugins/groups_manager.py:129 ++msgid "include also direct dependencies for packages" ++msgstr "リポジトリーの直接の依存関係を含みます" ++ ++#: plugins/groups_manager.py:132 ++msgid "package specification" ++msgstr "パッケージ仕様" ++ ++#: plugins/groups_manager.py:156 ++msgid "Can't edit group without specifying it (use --id or --name)" ++msgstr "" ++"指定せずにはグループを編集できません (--id または --name を使用してください)" ++ ++#: plugins/groups_manager.py:190 ++msgid "Can't load file \"{}\": {}" ++msgstr "ファイル '{}' を書き込みできません: {}" ++ ++#: plugins/groups_manager.py:206 ++msgid "Can't save file \"{}\": {}" ++msgstr "ファイル '{}' を保存できません: {}" ++ ++#: plugins/groups_manager.py:261 ++msgid "No match for argument: {}" ++msgstr "一致した引数がありません: {}" ++ ++#: plugins/groups_manager.py:298 ++msgid "Can't remove packages from non-existent group" ++msgstr "存在しないグループからパッケージを削除できません" ++ ++#: plugins/groups_manager.py:307 ++msgid "" ++"Group id '{}' generated from '{}' is duplicit. Please specify group id using " ++"--id." ++msgstr "" ++"'{}' から生成されたグループ ID '{}' は重複しています。--id を使用してグルー" ++"プ ID を指定してください。" ++ + #: plugins/leaves.py:32 + msgid "List installed packages not required by any other package" +-msgstr "他のパッケージから必要とされないインスール済みパッケージを一覧表示します" ++msgstr "" ++"他のパッケージから必要とされないインスール済みパッケージを一覧表示します" + + #: plugins/local.py:122 + msgid "Unable to create a directory '{}' due to '{}'" +@@ -630,67 +819,134 @@ msgstr "yum の履歴、グループ、および yumdb データを dnf へ移 + msgid "Migrating history data..." + msgstr "履歴データを移行中..." + +-#: plugins/needs_restarting.py:65 ++#: plugins/modulesync.py:37 ++msgid "" ++"Download packages from modules and/or create a repository with modular data" ++msgstr "モジュールからパッケージをダウンロードしたり、モジュラーデータでリポジトリー" ++"を作成したりします" ++ ++#: plugins/modulesync.py:44 ++msgid "MODULE" ++msgstr "MODULE" ++ ++#: plugins/modulesync.py:45 ++msgid "modules to download" ++msgstr "ダウンロードするモジュール" ++ ++#: plugins/modulesync.py:47 ++msgid "enable repositories with source packages" ++msgstr "ソースパッケージを含むリポジトリーを有効にします" ++ ++#: plugins/modulesync.py:49 ++msgid "enable repositories with debug-info and debug-source packages" ++msgstr "debug-info パッケージおよび debug-source " ++"パッケージでリポジトリーを有効にします" ++ ++#: plugins/modulesync.py:53 ++msgid "download only packages from newest modules" ++msgstr "最新のモジュールからパッケージのみをダウンロードします" ++ ++#: plugins/modulesync.py:85 ++msgid "Unable to find a match for argument: '{}'" ++msgid_plural "Unable to find a match for arguments: '{}'" ++msgstr[0] "引数に一致するものが見つかりませんでした: '{}'" ++ ++#: plugins/modulesync.py:107 ++msgid "" ++"Creation of repository failed with return code {}. All downloaded content " ++"was kept on the system" ++msgstr "リポジトリーの作成は戻りコード {} " ++"で失敗しました。ダウンロードされたコンテンツはすべてシステムに保持されました" ++ ++#: plugins/modulesync.py:144 ++#, python-brace-format ++msgid "No match for artifact '{0}' from module '{1}'" ++msgstr "モジュール '{1}' のアーティファクト '{0}' に一致するものはありません" ++ ++#: plugins/modulesync.py:162 ++#, python-brace-format ++msgid "No match for package name '{0}' in profile {1} from module {2}" ++msgstr "モジュール {2} からのプロファイル {1} のパッケージ名 '{0}' " ++"に一致するものはありません" ++ ++#: plugins/modulesync.py:166 ++msgid "No mach for argument '{}'" ++msgstr "引数 '{}' に一致するものはありません" ++ ++#. TODO(jmracek) Shell we end with an error or with RC 1? ++#: plugins/modulesync.py:198 ++msgid "Unable to satisfy require {}" ++msgstr "要求 {} を満たすことができません" ++ ++#: plugins/needs_restarting.py:66 + #, python-brace-format + msgid "" + "No installed package found for package name \"{pkg}\" specified in needs-" + "restarting file \"{file}\"." + msgstr "" ++"needs-restarting ファイル \"{file}\" に指定されている \"{pkg}\" " ++"というパッケージのインストール済みパッケージが見つかりません。" + +-#: plugins/needs_restarting.py:199 ++#: plugins/needs_restarting.py:220 + msgid "determine updated binaries that need restarting" + msgstr "再起動が必要な更新済みバイナリーを決定します" + +-#: plugins/needs_restarting.py:204 ++#: plugins/needs_restarting.py:225 + msgid "only consider this user's processes" + msgstr "このユーザーのプロセスのみを検討します" + +-#: plugins/needs_restarting.py:206 ++#: plugins/needs_restarting.py:227 + msgid "" + "only report whether a reboot is required (exit code 1) or not (exit code 0)" + msgstr "" ++"再起動が必要か (終了コード 1) 必要でないか (終了コード 0) のみを報告します" + + #: plugins/needs_restarting.py:230 ++msgid "only report affected systemd services" ++msgstr "影響を受ける systemd サービスのみを報告" ++ ++#: plugins/needs_restarting.py:253 + msgid "Core libraries or services have been updated since boot-up:" +-msgstr "" ++msgstr "起動以降にコアライブラリーまたはサービスがアップデートされました:" + +-#: plugins/needs_restarting.py:235 ++#: plugins/needs_restarting.py:258 + msgid "Reboot is required to fully utilize these updates." +-msgstr "" ++msgstr "これらのアップデートを完全に活用するには、再起動が必要です。" + +-#: plugins/needs_restarting.py:236 ++#: plugins/needs_restarting.py:259 + msgid "More information:" +-msgstr "" ++msgstr "詳細情報:" + +-#: plugins/needs_restarting.py:240 ++#: plugins/needs_restarting.py:263 + msgid "No core libraries or services have been updated since boot-up." + msgstr "" ++"起動以降にアップデートされたコアライブラリーまたはサービスはありません。" + +-#: plugins/needs_restarting.py:242 ++#: plugins/needs_restarting.py:265 + msgid "Reboot should not be necessary." +-msgstr "" ++msgstr "再起動な必要ありません。" + + #: plugins/post-transaction-actions.py:71 + #, python-format + msgid "Bad Action Line \"%s\": %s" +-msgstr "" ++msgstr "不正なアクション行 \"%s\": %s" + + #. unsupported state, skip it + #: plugins/post-transaction-actions.py:130 + #, python-format + msgid "Bad Transaction State: %s" +-msgstr "" ++msgstr "不正なトランザクション状態: %s" + +-#: plugins/post-transaction-actions.py:153 +-#: plugins/post-transaction-actions.py:155 ++#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:159 + #, python-format + msgid "post-transaction-actions: %s" +-msgstr "" ++msgstr "post-transaction-actions: %s" + +-#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:161 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" +-msgstr "" ++msgstr "post-transaction-actions: 不正なコマンド \"%s\": %s" + + #: plugins/repoclosure.py:42 + msgid "Display a list of unresolved dependencies for repositories" +@@ -718,129 +974,142 @@ msgstr "このパッケージのみのクロージャーを確認します" + + #: plugins/repodiff.py:45 + msgid "List differences between two sets of repositories" +-msgstr "" ++msgstr "2 セットのリポジトリー間の違いを一覧表示します" + + #: plugins/repodiff.py:58 + msgid "Specify old repository, can be used multiple times" +-msgstr "" ++msgstr "古いリポジトリーを指定します、これは複数回使用できます" + + #: plugins/repodiff.py:60 + msgid "Specify new repository, can be used multiple times" +-msgstr "" ++msgstr "新しいリポジトリーを指定します、これは複数回使用できます" + + #: plugins/repodiff.py:63 + msgid "" + "Specify architectures to compare, can be used multiple times. By default, " + "only source rpms are compared." + msgstr "" ++"比較するアーキテクチャーを指定します、これは複数回使用できます。デフォルト" ++"で、ソース rpms のみが比較されます。" + + #: plugins/repodiff.py:67 + msgid "Output additional data about the size of the changes." +-msgstr "" ++msgstr "変更サイズに関する追加データを出力します。" + + #: plugins/repodiff.py:69 + msgid "" +-"Compare packages also by arch. By default packages are compared just by " +-"name." ++"Compare packages also by arch. By default packages are compared just by name." + msgstr "" ++"パッケージを Arch でも比較します。デフォルトで、パッケージは名前のみで比較さ" ++"れます。" + + #: plugins/repodiff.py:72 + msgid "Output a simple one line message for modified packages." +-msgstr "" ++msgstr "変更されたパッケージに簡単な 1 行メッセージを出力します。" + + #: plugins/repodiff.py:74 + msgid "" + "Split the data for modified packages between upgraded and downgraded " + "packages." + msgstr "" ++"アップグレードされたパッケージとダウングレードされたパッケージとの間で、変更" ++"されたパッケージのデータを分割します。" + + #: plugins/repodiff.py:86 + msgid "Both old and new repositories must be set." +-msgstr "" ++msgstr "新旧両方のリポジトリーを設定する必要があります。" + + #: plugins/repodiff.py:178 + msgid "Size change: {} bytes" +-msgstr "" ++msgstr "サイズの変更: {} バイト" + + #: plugins/repodiff.py:184 + msgid "Added package : {}" +-msgstr "" ++msgstr "追加されたパッケージ : {}" + + #: plugins/repodiff.py:187 + msgid "Removed package: {}" +-msgstr "" ++msgstr "削除されたパッケージ: {}" + + #: plugins/repodiff.py:190 + msgid "Obsoleted by : {}" +-msgstr "" ++msgstr "により廃止されました: {}" + + #: plugins/repodiff.py:195 + msgid "" + "\n" + "Upgraded packages" + msgstr "" ++"\n" ++"アップグレードされたパッケージ" + + #: plugins/repodiff.py:200 + msgid "" + "\n" + "Downgraded packages" + msgstr "" ++"\n" ++"ダウングレードされたパッケージ" + + #: plugins/repodiff.py:207 + msgid "" + "\n" + "Modified packages" + msgstr "" ++"\n" ++"変更されたパッケージ" + + #: plugins/repodiff.py:212 + msgid "" + "\n" + "Summary" + msgstr "" ++"\n" ++"サマリー" + + #: plugins/repodiff.py:213 + msgid "Added packages: {}" +-msgstr "" ++msgstr "追加されたパッケージ: {}" + + #: plugins/repodiff.py:214 + msgid "Removed packages: {}" +-msgstr "" ++msgstr "削除されたパッケージ: {}" + + #: plugins/repodiff.py:216 + msgid "Upgraded packages: {}" +-msgstr "" ++msgstr "アップグレードされたパッケージ: {}" + + #: plugins/repodiff.py:217 + msgid "Downgraded packages: {}" +-msgstr "" ++msgstr "ダウングレードされたパッケージ: {}" + + #: plugins/repodiff.py:219 + msgid "Modified packages: {}" +-msgstr "" ++msgstr "変更されたパッケージ: {}" + + #: plugins/repodiff.py:222 + msgid "Size of added packages: {}" +-msgstr "" ++msgstr "追加されたパッケージのサイズ: {}" + + #: plugins/repodiff.py:223 + msgid "Size of removed packages: {}" +-msgstr "" ++msgstr "削除されたパッケージのサイズ: {}" + + #: plugins/repodiff.py:225 + msgid "Size of modified packages: {}" +-msgstr "" ++msgstr "変更されたパッケージのサイズ: {}" + + #: plugins/repodiff.py:228 + msgid "Size of upgraded packages: {}" +-msgstr "" ++msgstr "アップグレードされたパッケージのサイズ: {}" + + #: plugins/repodiff.py:230 + msgid "Size of downgraded packages: {}" +-msgstr "" ++msgstr "ダウングレードされたパッケージのサイズ: {}" + + #: plugins/repodiff.py:232 + msgid "Size change: {}" +-msgstr "" ++msgstr "サイズの変更: {}" + + #: plugins/repograph.py:50 + msgid "Output a full package dependency graph in dot format" +@@ -859,180 +1128,203 @@ msgstr "rpm パッケージのディレクトリーを管理します" + msgid "Pass either --old or --new, not both!" + msgstr "--old または --new のいずれかを渡します。両方ではありません。" + +-#: plugins/repomanage.py:71 ++#: plugins/repomanage.py:89 + msgid "No files to process" + msgstr "処理するファイルはありません" + +-#: plugins/repomanage.py:93 ++#: plugins/repomanage.py:96 + msgid "Could not open {}" + msgstr "{} を開くことができません" + +-#: plugins/repomanage.py:177 ++#: plugins/repomanage.py:180 + msgid "Print the older packages" + msgstr "古いパッケージを印刷します" + +-#: plugins/repomanage.py:179 ++#: plugins/repomanage.py:182 + msgid "Print the newest packages" + msgstr "最新のパッケージを印刷します" + +-#: plugins/repomanage.py:181 ++#: plugins/repomanage.py:184 + msgid "Space separated output, not newline" + msgstr "スペースで区切られた出力で、改行ではありません" + +-#: plugins/repomanage.py:183 ++#: plugins/repomanage.py:186 + msgid "Newest N packages to keep - defaults to 1" + msgstr "維持する最新の N パッケージ - デフォルトは 1 に設定されます" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:189 + msgid "Path to directory" + msgstr "ディレクトリーへのパス" + +-#: plugins/reposync.py:54 ++#: plugins/reposync.py:55 + msgid "download all packages from remote repo" + msgstr "リモート repo からすべてのパッケージをダウンロードします" + +-#: plugins/reposync.py:63 ++#: plugins/reposync.py:64 + msgid "download only packages for this ARCH" + msgstr "この ARCH 向けのパッケージのみをダウンロード" + +-#: plugins/reposync.py:65 ++#: plugins/reposync.py:66 + msgid "delete local packages no longer present in repository" + msgstr "リポジトリーにもはや存在しないローカルパッケージを削除" + +-#: plugins/reposync.py:67 +-msgid "also download and uncompress comps.xml" +-msgstr "" +- +-#: plugins/reposync.py:69 ++#: plugins/reposync.py:68 + msgid "download all the metadata." +-msgstr "" ++msgstr "すべてのメタデータをダウンロードします。" + +-#: plugins/reposync.py:71 +-msgid "download only newest packages per-repo" +-msgstr "最新のパッケージ per-repo のみをダウンロード" ++#: plugins/reposync.py:70 ++msgid "Remove packages that fail GPG signature checking after downloading" ++msgstr "ダウンロード後に GPG 署名の確認に失敗するパッケージを削除します" + + #: plugins/reposync.py:73 +-msgid "where to store downloaded repositories" +-msgstr "" ++msgid "also download and uncompress comps.xml" ++msgstr "comps.xml もダウンロードして展開します" + + #: plugins/reposync.py:75 +-msgid "Don't add the reponame to the download path." +-msgstr "" +- +-#: plugins/reposync.py:77 + msgid "" +-"where to store downloaded repository metadata. Defaults to the value of " +-"--download-path." ++"where to store downloaded repository metadata. Defaults to the value of --" ++"download-path." + msgstr "" ++"ダウンロード済みリポジトリーメタデータの保管場所。初期値は --download-path で" ++"す。" ++ ++#: plugins/reposync.py:78 ++msgid "download only newest packages per-repo" ++msgstr "最新のパッケージ per-repo のみをダウンロード" + + #: plugins/reposync.py:80 +-msgid "operate on source packages" +-msgstr "ソースパッケージでの操作" ++msgid "Don't add the reponame to the download path." ++msgstr "ダウンロードパスにはリポネームを追加しないでください。" + + #: plugins/reposync.py:82 ++msgid "where to store downloaded repositories" ++msgstr "ダウンロード済みリポジトリーの保管場所" ++ ++#: plugins/reposync.py:84 + msgid "try to set local timestamps of local files by the one on the server" +-msgstr "" ++msgstr "サーバー上から、ローカルファイルのローカル timestamps の設定を試みます" ++ ++#: plugins/reposync.py:87 ++msgid "download only source packages" ++msgstr "ソースパッケージのみをダウンロード" + +-#: plugins/reposync.py:85 ++#: plugins/reposync.py:89 + msgid "Just list urls of what would be downloaded, don't download" + msgstr "" ++"ダウンロードする予定のものの URL をリストするだけで、ダウンロードしないでくだ" ++"さい" + +-#: plugins/reposync.py:109 ++#: plugins/reposync.py:113 + msgid "Can't use --norepopath with multiple repositories" +-msgstr "" ++msgstr "複数のリポジトリーでは -norepopath は使えません" + +-#: plugins/reposync.py:127 ++#: plugins/reposync.py:132 + #, python-format + msgid "Failed to get mirror for metadata: %s" +-msgstr "" ++msgstr "メタデータのミラー取得に失敗しました: %s" + +-#: plugins/reposync.py:144 ++#: plugins/reposync.py:149 + msgid "Failed to get mirror for the group file." +-msgstr "" ++msgstr "グループファイルのミラー取得に失敗しました。" ++ ++#: plugins/reposync.py:168 ++msgid "Removing {}: {}" ++msgstr "{} の削除中: {}" + + #: plugins/reposync.py:175 ++msgid "GPG signature check failed." ++msgstr "GPG 署名の確認に失敗しました。" ++ ++#: plugins/reposync.py:196 + msgid "Download target '{}' is outside of download path '{}'." +-msgstr "" ++msgstr "ダウンロードターゲット '{}' は、ダウンロードパス '{}' の外にあります。" + +-#: plugins/reposync.py:190 ++#: plugins/reposync.py:211 + #, python-format + msgid "[DELETED] %s" + msgstr "[DELETED] %s" + +-#: plugins/reposync.py:192 ++#: plugins/reposync.py:213 + #, python-format + msgid "failed to delete file %s" + msgstr "ファイル %s の削除に失敗しました" + +-#: plugins/reposync.py:201 ++#: plugins/reposync.py:222 + #, python-format + msgid "comps.xml for repository %s saved" + msgstr "リポジトリー %s の comps.xml が保存されました" + + #: plugins/show_leaves.py:54 + msgid "New leaves:" +-msgstr "新規のリーフパッケージ (他のパッケージから依存されていないパッケージ) :" ++msgstr "" ++"新規のリーフパッケージ (他のパッケージから依存されていないパッケージ) :" + +-#: plugins/versionlock.py:32 ++#: plugins/versionlock.py:33 + #, python-format + msgid "Unable to read version lock configuration: %s" + msgstr "バージョンロック設定の読み込みができません: %s" + +-#: plugins/versionlock.py:33 ++#: plugins/versionlock.py:34 + msgid "Locklist not set" + msgstr "ロックリストが設定されていません" + +-#: plugins/versionlock.py:34 ++#: plugins/versionlock.py:35 + msgid "Adding versionlock on:" + msgstr "versionlock を追加:" + +-#: plugins/versionlock.py:35 ++#: plugins/versionlock.py:36 + msgid "Adding exclude on:" + msgstr "除外を追加:" + +-#: plugins/versionlock.py:36 ++#: plugins/versionlock.py:37 + msgid "Package already locked in equivalent form:" +-msgstr "" ++msgstr "同等の形で既にロックされているパッケージ:" + +-#: plugins/versionlock.py:37 ++#: plugins/versionlock.py:38 + msgid "Package {} is already locked" +-msgstr "" ++msgstr "パッケージ {} は既にロックされています" + +-#: plugins/versionlock.py:38 ++#: plugins/versionlock.py:39 + msgid "Package {} is already excluded" +-msgstr "" ++msgstr "パッケージ{}はすでに除外されています" + +-#: plugins/versionlock.py:39 ++#: plugins/versionlock.py:40 + msgid "Deleting versionlock for:" + msgstr "versionlock を削除:" + +-#: plugins/versionlock.py:40 ++#: plugins/versionlock.py:41 + msgid "No package found for:" + msgstr "パッケージが見つかりませんでした:" + +-#: plugins/versionlock.py:41 ++#: plugins/versionlock.py:42 + msgid "Excludes from versionlock plugin were not applied" + msgstr "versionlock プラグインからの除外は適用されませんでした" + +-#: plugins/versionlock.py:42 ++#: plugins/versionlock.py:43 + msgid "Versionlock plugin: number of lock rules from file \"{}\" applied: {}" + msgstr "versionlock プラグイン: ファイル \"{}\" のロックルールの数を適用: {}" + +-#: plugins/versionlock.py:43 +-msgid "Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" ++#: plugins/versionlock.py:44 ++msgid "" ++"Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" + msgstr "versionlock プラグイン: ファイル \"{}\" の除外ルールの数を適用: {}" + +-#: plugins/versionlock.py:44 ++#: plugins/versionlock.py:45 + msgid "Versionlock plugin: could not parse pattern:" + msgstr "versionlock プラグイン: パターンを解析できませんでした:" + +-#: plugins/versionlock.py:130 ++#: plugins/versionlock.py:134 + msgid "control package version locks" + msgstr "パッケージバージョンロックの制御" + +-#: plugins/versionlock.py:136 ++#: plugins/versionlock.py:140 + msgid "Use package specifications as they are, do not try to parse them" +-msgstr "" ++msgstr "パッケージ仕様をそのまま使用し、解析を試みないでください" ++ ++#: plugins/versionlock.py:160 ++msgid "Subcommand '{}' is deprecated. Use 'exclude' subcommand instead." ++msgstr "サブコマンド '{}' は非推奨になりました。代わりに 'exclude' " ++"サブコマンドを使用してください。" + + #~ msgid "" + #~ "\n" +diff --git a/po/ko.po b/po/ko.po +index 3f4eb89..307ccc7 100644 +--- a/po/ko.po ++++ b/po/ko.po +@@ -1,222 +1,230 @@ + # Ludek Janda , 2018. #zanata, 2020. ++# simmon , 2021. ++# Kim InSoo , 2022. + msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2020-10-05 09:18-0400\n" +-"PO-Revision-Date: 2020-09-12 11:29+0000\n" +-"Last-Translator: Ludek Janda \n" +-"Language-Team: Korean \n" ++"POT-Creation-Date: 2022-02-28 11:53+0100\n" ++"PO-Revision-Date: 2022-03-02 04:16+0000\n" ++"Last-Translator: Kim InSoo \n" ++"Language-Team: Korean \n" + "Language: ko\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=1; plural=0;\n" +-"X-Generator: Weblate 4.2.2\n" ++"X-Generator: Weblate 4.11\n" + + #: plugins/builddep.py:45 + msgid "[PACKAGE|PACKAGE.spec]" +-msgstr "" ++msgstr "[PACKAGE|PACKAGE.spec]" + + #: plugins/builddep.py:85 + #, python-format + msgid "'%s' is not of the format 'MACRO EXPR'" +-msgstr "" ++msgstr "'%s'는 'MACRO EXPR' 형식이 아닙니다" + + #: plugins/builddep.py:90 + msgid "packages with builddeps to install" +-msgstr "" ++msgstr "설치 할 builddeps가 있는 꾸러미(package)" + + #: plugins/builddep.py:93 + msgid "define a macro for spec file parsing" +-msgstr "" ++msgstr "특정한 파일 구문분석을 위해 매크로를 정의한다" + + #: plugins/builddep.py:95 + msgid "skip build dependencies not available in repositories" +-msgstr "" ++msgstr "저장소에서 사용 할 수 없는 구성 의존성을 건너띄기 한다" + + #: plugins/builddep.py:98 + msgid "treat commandline arguments as spec files" +-msgstr "" ++msgstr "명령줄 인수를 지정한 파일로 다룬다" + + #: plugins/builddep.py:100 + msgid "treat commandline arguments as source rpm" +-msgstr "" ++msgstr "명령줄 인수를 rpm 소스로 다룬다" + + #: plugins/builddep.py:144 + msgid "RPM: {}" +-msgstr "" ++msgstr "RPM: {}" + + #: plugins/builddep.py:153 + msgid "Some packages could not be found." +-msgstr "" ++msgstr "몇몇 꾸러미(packages)를 찾을 수 없습니다." + + #. No provides, no files +-#. Richdeps can have no matches but it could be correct (solver must decide +-#. later) ++#. Richdeps can have no matches but it could be correct (solver must decide later) + #: plugins/builddep.py:173 + #, python-format + msgid "No matching package to install: '%s'" +-msgstr "" ++msgstr "설치: '%s' 꾸러미(package)가 일치하지 않습니다" + + #: plugins/builddep.py:191 + #, python-format + msgid "Failed to open: '%s', not a valid source rpm file." +-msgstr "" ++msgstr "여는데 실패하였습니다: '%s', 유효한 rpm 파일 출처가 아닙니다." + + #: plugins/builddep.py:204 plugins/builddep.py:220 plugins/builddep.py:237 + msgid "Not all dependencies satisfied" +-msgstr "" ++msgstr "모든 의존성을 만족하지 않습니다" + + #: plugins/builddep.py:211 + #, python-format + msgid "Failed to open: '%s', not a valid spec file: %s" +-msgstr "" ++msgstr "여는데 실패하였습니다 '%s', 지정한 파일: %s가 유효하지 않습니다" + + #: plugins/builddep.py:230 plugins/repoclosure.py:118 + #, python-format + msgid "no package matched: %s" +-msgstr "일치하는 패키지 없음 : %s" ++msgstr "일치하는 꾸러미(package) 없음: %s" + + #: plugins/changelog.py:37 + #, python-brace-format + msgid "Not a valid date: \"{0}\"." +-msgstr "" ++msgstr "유효한 날자가 아닙니다: \"{0}\"." + + #: plugins/changelog.py:43 + msgid "Show changelog data of packages" +-msgstr "" ++msgstr "꾸러미(packages)의 변화 기록자료를 보여줍니다" + + #: plugins/changelog.py:51 + msgid "" + "show changelog entries since DATE. To avoid ambiguosity, YYYY-MM-DD format " + "is recommended." + msgstr "" ++"DATE 이후에 변화기록를 보여줍니다. 모호함을 피하기 위하여, YYYY-MM-DD 형식을 " ++"추천합니다." + + #: plugins/changelog.py:55 + msgid "show given number of changelog entries per package" +-msgstr "" ++msgstr "주어진 수의 꾸러미(package) 마다 변화기록 항목을 보여줍니다" + + #: plugins/changelog.py:58 + msgid "" + "show only new changelog entries for packages, that provide an upgrade for " + "some of already installed packages." + msgstr "" ++"몇몇 이미 설치된 꾸러미(package)들의 최신화를 제공하는 꾸러미를 위하여 새로" ++"운 변화기록만을 보여줍니다." + + #: plugins/changelog.py:60 + msgid "PACKAGE" +-msgstr "" ++msgstr "꾸러미(package)" + + #: plugins/changelog.py:81 plugins/debuginfo-install.py:90 + #, python-format + msgid "No match for argument: %s" +-msgstr "인수와 일치하는 항목 없음 : %s" ++msgstr "인수가 일치하지 않습니다: %s" + + #: plugins/changelog.py:109 + msgid "Listing changelogs since {}" +-msgstr "" ++msgstr "{} 이 후의 변화기록 목록" + + #: plugins/changelog.py:111 + msgid "Listing only latest changelog" + msgid_plural "Listing {} latest changelogs" +-msgstr[0] "" ++msgstr[0] "최신화된 변화기록 목록 {}" + + #: plugins/changelog.py:116 + msgid "Listing only new changelogs since installed version of the package" +-msgstr "" ++msgstr "꾸러미 설치 버전 이후의 새로운 변화 기록만 목록화함" + + #: plugins/changelog.py:118 + msgid "Listing all changelogs" +-msgstr "" ++msgstr "모든 변화기록 목록" + + #: plugins/changelog.py:122 + msgid "Changelogs for {}" +-msgstr "" ++msgstr "{}의 변경 사항" + +-#: plugins/config_manager.py:37 ++#: plugins/config_manager.py:38 + #, python-brace-format + msgid "manage {prog} configuration options and repositories" +-msgstr "" ++msgstr "{prog} 환경 선택과 저장소 관리" + +-#: plugins/config_manager.py:44 ++#: plugins/config_manager.py:45 + msgid "repo to modify" + msgstr "수정할 repo" + +-#: plugins/config_manager.py:47 ++#: plugins/config_manager.py:48 + msgid "save the current options (useful with --setopt)" + msgstr "현재 옵션 저장 (--setopt와 함께 유용함)" + +-#: plugins/config_manager.py:50 ++#: plugins/config_manager.py:51 + msgid "add (and enable) the repo from the specified file or url" + msgstr "지정된 파일 또는 URL에서 repo를 추가 (및 활성화)" + +-#: plugins/config_manager.py:53 ++#: plugins/config_manager.py:54 + msgid "print current configuration values to stdout" + msgstr "현재 구성 값을 표준 출력으로 인쇄" + +-#: plugins/config_manager.py:56 ++#: plugins/config_manager.py:57 + msgid "print variable values to stdout" + msgstr "변수 값을 표준 출력으로 출력" + +-#: plugins/config_manager.py:60 ++#: plugins/config_manager.py:61 + msgid "enable repos (automatically saves)" +-msgstr "" ++msgstr "저장소 활성화 (자동으로 저장합니다)" + +-#: plugins/config_manager.py:63 ++#: plugins/config_manager.py:64 + msgid "disable repos (automatically saves)" +-msgstr "" ++msgstr "저장소 비활성화 (자동으로 저장합니다)" + +-#: plugins/config_manager.py:77 ++#: plugins/config_manager.py:78 + msgid "one of the following arguments is required: {}" +-msgstr "" ++msgstr "다음 인수 중 하나가 필요합니다: {}" + +-#: plugins/config_manager.py:86 ++#: plugins/config_manager.py:87 + msgid "" + "Warning: --enablerepo/--disablerepo arguments have no meaningwith config " + "manager. Use --set-enabled/--set-disabled instead." + msgstr "" ++"경고: -- --enablerepo/--disablerepo 인수는 설정 관리자와 함께 의미를 갖고 있" ++"지 않습니다. 대신에 --set-enabled/--set-disabled를 사용하세요." + +-#: plugins/config_manager.py:131 ++#: plugins/config_manager.py:132 + #, python-format + msgid "No matching repo to modify: %s." + msgstr "수정할 일치하는 Repo가 없습니다. %s." + +-#: plugins/config_manager.py:182 ++#: plugins/config_manager.py:183 + #, python-format + msgid "Adding repo from: %s" + msgstr "다음 위치에서 레포 추가 : %s" + +-#: plugins/config_manager.py:206 ++#: plugins/config_manager.py:207 + msgid "Configuration of repo failed" + msgid_plural "Configuration of repos failed" +-msgstr[0] "저장소 구성에 실패했습니다." ++msgstr[0] "저장소 구성에 실패했습니다" + +-#: plugins/config_manager.py:216 ++#: plugins/config_manager.py:217 + #, python-format + msgid "Could not save repo to repofile %s: %s" + msgstr "repofile에 repo를 저장할 수 없습니다. %s: %s" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "y" + msgstr "y" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "yes" + msgstr "예" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "n" + msgstr "n" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "no" + msgstr "아니" + +-#: plugins/copr.py:79 ++#: plugins/copr.py:84 + msgid "Interact with Copr repositories." + msgstr "Copr 저장소와 상호 작용하십시오." + +-#: plugins/copr.py:81 ++#: plugins/copr.py:86 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -237,56 +245,84 @@ msgid "" + " " + msgstr "" + "\n" +-" 프로젝트 이름 / 프로젝트 제거 - 설치 / 사용 / 사용 안 함 목록 - 사용 가능 사용자 = NAME 검색 프로젝트 예 : copr enable rhscl / perl516 epel-6-x86_64 copr enable ignatenkobrain / ocltoys copr 비활성화 rhscl / perl516 copr 제거 rhscl / perl516 copr 목록 - 사용 가능 목록 - 사용 가능 사용자 = ignatenkobrain copr 검색 테스트\n" ++" enable name/project [chroot]\n" ++" disable name/project\n" ++" remove name/project\n" ++" list --installed/enabled/disabled\n" ++" list --available-by-user=NAME\n" ++" search project\n" ++"\n" ++" Examples:\n" ++" copr enable rhscl/perl516 epel-6-x86_64\n" ++" copr enable ignatenkobrain/ocltoys\n" ++" copr disable rhscl/perl516\n" ++" copr remove rhscl/perl516\n" ++" copr list --enabled\n" ++" copr list --available-by-user=ignatenkobrain\n" ++" copr search tests\n" + " " + +-#: plugins/copr.py:107 ++#: plugins/copr.py:112 + msgid "List all installed Copr repositories (default)" + msgstr "설치된 모든 Copr 저장소 나열 (기본값)" + +-#: plugins/copr.py:109 ++#: plugins/copr.py:114 + msgid "List enabled Copr repositories" + msgstr "사용 가능한 Copr 저장소 목록" + +-#: plugins/copr.py:111 ++#: plugins/copr.py:116 + msgid "List disabled Copr repositories" + msgstr "비활성화 된 Copr 저장소 목록" + +-#: plugins/copr.py:113 ++#: plugins/copr.py:118 + msgid "List available Copr repositories by user NAME" + msgstr "사용자가 사용할 수있는 Copr 저장소를 나열합니다. NAME" + +-#: plugins/copr.py:115 ++#: plugins/copr.py:120 + msgid "Specify an instance of Copr to work with" +-msgstr "" ++msgstr "일하는 Copr의 예를 지정합니다" + +-#: plugins/copr.py:149 plugins/copr.py:217 plugins/copr.py:237 ++#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 + msgid "Error: " + msgstr "오류: " + +-#: plugins/copr.py:150 ++#: plugins/copr.py:155 + msgid "" +-"specify Copr hub either with `--hub` or using " +-"`copr_hub/copr_username/copr_projectname` format" ++"specify Copr hub either with `--hub` or using `copr_hub/copr_username/" ++"copr_projectname` format" + msgstr "" ++"Corp hub를 `--hub` 또는 사용하기 `copr_hub/copr_username/copr_projectname`형" ++"식으로 지정합니다" + +-#: plugins/copr.py:153 ++#: plugins/copr.py:158 + msgid "multiple hubs specified" +-msgstr "" ++msgstr "지정된 여러 허브" + +-#: plugins/copr.py:218 plugins/copr.py:222 ++#: plugins/copr.py:223 plugins/copr.py:227 + msgid "exactly two additional parameters to copr command are required" +-msgstr "copr 명령에 정확히 두 개의 추가 매개 변수가 필요합니다." ++msgstr "copr 명령에 정확히 두 개의 추가 매개 변수가 필요합니다" ++ ++#: plugins/copr.py:232 ++msgid "Too many arguments." ++msgstr "너무 많은 인수." + +-#: plugins/copr.py:238 ++#: plugins/copr.py:235 ++msgid "" ++"Bad format of optional chroot. The format is distribution-version-" ++"architecture." ++msgstr "선택적인 chroot의 나쁜 형식. 형식은 배포-버전-구조입니다." ++ ++#: plugins/copr.py:250 + msgid "use format `copr_username/copr_projectname` to reference copr project" +-msgstr "copr 프로젝트를 참조하기 위해`copr_username / copr_projectname` 형식을 사용하십시오" ++msgstr "" ++"copr 프로젝트를 참조하기 위해`copr_username / copr_projectname` 형식을 사용하" ++"십시오" + +-#: plugins/copr.py:240 ++#: plugins/copr.py:252 + msgid "bad copr project format" + msgstr "나쁜 copr 프로젝트 형식" + +-#: plugins/copr.py:254 ++#: plugins/copr.py:266 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -294,78 +330,95 @@ msgid "" + "\n" + "The Fedora Project does not exercise any power over the contents of\n" + "this repository beyond the rules outlined in the Copr FAQ at\n" +-",\n" ++",\n" + "and packages are not held to any quality or security level.\n" + "\n" + "Please do not file bug reports about these packages in Fedora\n" + "Bugzilla. In case of problems, contact the owner of this repository.\n" + msgstr "" ++"\n" ++"Core 저정소를 활성화합니다. 이 저장소는 주요 배포판 부분이 아님을 알고 있기 " ++"바라고,\n" ++"품질이 다를 수 있습니다.\n" ++"\n" ++"페도라 프로젝트는\n" ++"에\n" ++"Core FAQ에 있는 설명된 규칙을 넘는 저장소 내용 이상의 권한을 시험하지 않으" ++"며,\n" ++"그리고 꾸러미(package)는 어떤 품질이나 보안 수준을 유지하지 않습니다.\n" ++"\n" ++"페도라 버그질라에 이들 꾸러미에 대한 파일 결점 보고를 제출하지 마세요.\n" ++"이들 문제는, 이들 저장소 소유자와 접촉하세요.\n" + +-#: plugins/copr.py:271 ++#: plugins/copr.py:283 + msgid "Repository successfully enabled." + msgstr "저장소가 사용 설정되었습니다." + +-#: plugins/copr.py:276 ++#: plugins/copr.py:288 + msgid "Repository successfully disabled." + msgstr "저장소가 사용 중지되었습니다." + +-#: plugins/copr.py:280 ++#: plugins/copr.py:292 + msgid "Repository successfully removed." + msgstr "저장소가 제거되었습니다." + +-#: plugins/copr.py:284 plugins/copr.py:693 ++#: plugins/copr.py:296 plugins/copr.py:697 + msgid "Unknown subcommand {}." + msgstr "알 수없는 부속 명령 {}." + +-#: plugins/copr.py:341 ++#: plugins/copr.py:353 + msgid "" +-"* These coprs have repo file with an old format that contains no information" +-" about Copr hub - the default one was assumed. Re-enable the project to fix " ++"* These coprs have repo file with an old format that contains no information " ++"about Copr hub - the default one was assumed. Re-enable the project to fix " + "this." + msgstr "" ++"* 이들 coprs은 Copr hub에 대하여 어떤 정보도 포함하지 않는 오래된 형태의 저장" ++"소 파일을 갖고 있습니다. 이 문제를 수정하기 위하여 프로젝트를 재활성화하세요." + +-#: plugins/copr.py:353 ++#: plugins/copr.py:366 + msgid "Can't parse repositories for username '{}'." + msgstr "사용자 이름 '{}'에 대한 리포지토리를 구문 분석 할 수 없습니다." + +-#: plugins/copr.py:356 ++#: plugins/copr.py:369 + msgid "List of {} coprs" + msgstr "{} 명의 경찰 목록" + +-#: plugins/copr.py:364 ++#: plugins/copr.py:374 + msgid "No description given" +-msgstr "설명이 없습니다." ++msgstr "설명이 없습니다" + +-#: plugins/copr.py:376 ++#: plugins/copr.py:386 + msgid "Can't parse search for '{}'." + msgstr "'{}'에 대한 검색을 구문 분석 할 수 없습니다." + +-#: plugins/copr.py:379 ++#: plugins/copr.py:389 + msgid "Matched: {}" + msgstr "일치하는 항목 : {}" + +-#: plugins/copr.py:387 ++#: plugins/copr.py:394 + msgid "No description given." + msgstr "설명이 없습니다." + +-#: plugins/copr.py:410 ++#: plugins/copr.py:416 + msgid "Safe and good answer. Exiting." + msgstr "안전하고 좋은 대답. 나가기." + +-#: plugins/copr.py:417 ++#: plugins/copr.py:423 + msgid "This command has to be run under the root user." + msgstr "이 명령은 루트 사용자로 실행해야합니다." + +-#: plugins/copr.py:481 ++#: plugins/copr.py:485 + msgid "" + "This repository does not have any builds yet so you cannot enable it now." + msgstr "이 저장소에는 빌드가 아직 없으므로 지금 사용할 수 없습니다." + +-#: plugins/copr.py:484 ++#: plugins/copr.py:488 + msgid "Such repository does not exist." + msgstr "이러한 저장소는 존재하지 않습니다." + +-#: plugins/copr.py:528 ++#: plugins/copr.py:532 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -381,53 +434,63 @@ msgid "" + "\n" + "These repositories have been enabled automatically." + msgstr "" ++"활성화된 Core 저장소의 유지는 다른 저장소에 이를 독립적으로\n" ++"만드는 것으로 결정하였습니다.\n" ++"그런 저장소는 주요 Corp 저장소에서 성공적인 RPM 설치를\n" ++"위하여 일반적으로 필요합니다(이들은 실행 의존성을 제공합니다).\n" ++"\n" ++"위도 여기에 적용되며 품질과 결점-보고에 대한 참고 사항을 알아야 하고,\n" ++"페도라 프로젝트는 그 내용을 통제하지 않습니다.\n" ++"목록을 다시 검토합니다:\n" ++"\n" ++"{0}\n" ++"\n" ++"이들 저장소는 자동으로 활성화 됩니다." + +-#: plugins/copr.py:549 ++#: plugins/copr.py:553 + msgid "Do you want to keep them enabled?" +-msgstr "" ++msgstr "계속 사용하길 원하시나요?" + +-#: plugins/copr.py:582 ++#: plugins/copr.py:586 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" +-msgstr "" ++msgstr "copr repo {0}/{1}/{2} 제거를 실패하였습니다" + +-#: plugins/copr.py:593 ++#: plugins/copr.py:597 + msgid "Failed to disable copr repo {}/{}" +-msgstr "copr repo {} / {}를 사용 중지하지 못했습니다." ++msgstr "copr repo {} / {}를 사용 중지를 실패하였습니다" + +-#: plugins/copr.py:611 plugins/copr.py:648 ++#: plugins/copr.py:615 plugins/copr.py:652 + msgid "Unknown response from server." + msgstr "서버에서 알 수없는 응답." + +-#: plugins/copr.py:633 ++#: plugins/copr.py:637 + msgid "Interact with Playground repository." + msgstr "놀이터 저장소와 상호 작용하십시오." + +-#: plugins/copr.py:639 +-#, fuzzy +-#| msgid "Interact with Playground repository." ++#: plugins/copr.py:643 + msgid "Enabling a Playground repository." +-msgstr "놀이터 저장소와 상호 작용하십시오." ++msgstr "동작 저장소와 활용하기." + +-#: plugins/copr.py:640 ++#: plugins/copr.py:644 + msgid "Do you want to continue?" +-msgstr "" ++msgstr "계속하기를 원하십니까?" + +-#: plugins/copr.py:683 ++#: plugins/copr.py:687 + msgid "Playground repositories successfully enabled." + msgstr "놀이터 저장소를 사용하도록 설정했습니다." + +-#: plugins/copr.py:686 ++#: plugins/copr.py:690 + msgid "Playground repositories successfully disabled." + msgstr "놀이터 저장소가 사용 중지되었습니다." + +-#: plugins/copr.py:690 ++#: plugins/copr.py:694 + msgid "Playground repositories successfully updated." + msgstr "놀이터 저장소가 성공적으로 업데이트되었습니다." + + #: plugins/debug.py:53 + msgid "dump information about installed rpm packages to file" +-msgstr "설치된 rpm 패키지에 대한 정보를 파일에 덤프하십시오." ++msgstr "설치된 rpm 꾸러미(package)에 대한 정보를 파일에 덤프하십시오" + + #: plugins/debug.py:67 + msgid "do not attempt to dump the repository contents." +@@ -444,7 +507,7 @@ msgstr "작성된 출력 : %s" + + #: plugins/debug.py:172 + msgid "restore packages recorded in debug-dump file" +-msgstr "디버그 덤프 파일에 기록 된 패키지 복원" ++msgstr "디버그 덤프 파일에 기록 된 꾸러미(package) 복원" + + #: plugins/debug.py:185 + msgid "output commands that would be run to stdout." +@@ -452,13 +515,15 @@ msgstr "stdout으로 실행될 출력 명령." + + #: plugins/debug.py:188 + msgid "Install the latest version of recorded packages." +-msgstr "기록 된 패키지의 최신 버전을 설치하십시오." ++msgstr "기록 된 꾸러미의 최신 버전을 설치하십시오." + + #: plugins/debug.py:191 + msgid "" + "Ignore architecture and install missing packages matching the name, epoch, " + "version and release." +-msgstr "아키텍처를 무시하고 이름, 기원, 버전 및 릴리스와 일치하는 누락 된 패키지를 설치하십시오." ++msgstr "" ++"구조를 무시하고 이름, 기원, 버전및 출시와 일치하는 누락 된 꾸러미를 설치하십" ++"시오." + + #: plugins/debug.py:196 + msgid "limit to specified type" +@@ -469,6 +534,8 @@ msgid "" + "Allow removing of install-only packages. Using this option may result in an " + "attempt to remove the running kernel." + msgstr "" ++"설치전용 꾸리미 제거를 허용합니다. 이 선택의 사용은 동작하고 있는 커널을 제거" ++"하는 결과가 나타날 수 있습니다." + + #: plugins/debug.py:202 + msgid "name of dump file" +@@ -477,7 +544,7 @@ msgstr "덤프 파일의 이름" + #: plugins/debug.py:273 + #, python-format + msgid "Package %s is not available" +-msgstr "꾸러미 %s 사용할 수 없습니다" ++msgstr "꾸러미(package) %s 사용 할 수 없습니다" + + #: plugins/debug.py:283 + #, python-format +@@ -486,31 +553,39 @@ msgstr "잘못된 dnf 디버그 파일 : %s" + + #: plugins/debuginfo-install.py:56 + msgid "install debuginfo packages" +-msgstr "debuginfo 패키지 설치" ++msgstr "디버그정보 꾸러미(package) 설치" + + #: plugins/debuginfo-install.py:180 + #, python-format + msgid "" + "Could not find debuginfo package for the following available packages: %s" + msgstr "" ++"다음 사용가능한 꾸러미(package): %s 를 위하여 디버그정보 꾸러미를 찾을 수 없" ++"습니다" + + #: plugins/debuginfo-install.py:185 + #, python-format + msgid "" + "Could not find debugsource package for the following available packages: %s" + msgstr "" ++"다음 가용한 꾸러미(package): %s 를 위하여 디버그자원 꾸러미(package)를 찾을 " ++"수 없습니다" + + #: plugins/debuginfo-install.py:190 + #, python-format + msgid "" + "Could not find debuginfo package for the following installed packages: %s" + msgstr "" ++"다음 설치된 꾸러미(package): %s 를 위한 디버그정보 꾸러미(package)를 찾을 수 " ++"없습니다" + + #: plugins/debuginfo-install.py:195 + #, python-format + msgid "" + "Could not find debugsource package for the following installed packages: %s" + msgstr "" ++"다음 설치된 꾸러미(package): %s 를 위하여 디버그자원 꾸러미(package)를 찾을 " ++"수 없습니다" + + #: plugins/debuginfo-install.py:199 + msgid "Unable to find a match" +@@ -518,51 +593,53 @@ msgstr "일치하는 항목을 찾을 수 없습니다" + + #: plugins/download.py:41 + msgid "Download package to current directory" +-msgstr "현재 디렉토리에 패키지 다운로드" ++msgstr "현재 디렉토리에 꾸러미 내려받기" + + #: plugins/download.py:51 + msgid "packages to download" +-msgstr "다운로드 할 패키지" ++msgstr "내려받기 할 꾸러미" + + #: plugins/download.py:53 + msgid "download the src.rpm instead" +-msgstr "대신 src.rpm을 다운로드하십시오." ++msgstr "대신 src.rpm을 내려받으세요" + + #: plugins/download.py:55 + msgid "download the -debuginfo package instead" +-msgstr "대신 -debuginfo 패키지를 다운로드하십시오." ++msgstr "대신 -debuginfo 꾸러미(package)를 내려받아요" + + #: plugins/download.py:57 + msgid "download the -debugsource package instead" +-msgstr "" ++msgstr "대신 -debuginfo 꾸러미(package)를 내려받으세요" + + #: plugins/download.py:60 + msgid "limit the query to packages of given architectures." +-msgstr "쿼리를 주어진 아키텍처의 패키지로 제한하십시오." ++msgstr "요청를 주어진 구조 꾸러미(package)로 제한하십시오." + +-#: plugins/download.py:62 ++#: plugins/download.py:62 plugins/modulesync.py:51 + msgid "resolve and download needed dependencies" +-msgstr "필요한 종속성을 해결하고 다운로드하십시오." ++msgstr "필요한 종속성을 해결하고 내려받아요" + + #: plugins/download.py:64 + msgid "" + "when running with --resolve, download all dependencies (do not exclude " + "already installed ones)" + msgstr "" ++"--resolve 와 함께 실행 할 때에, 모든 의존성을 내려받습니다 (이미 설치된 것들" ++"은 포함하지 않습니다)" + + #: plugins/download.py:67 + msgid "" + "print list of urls where the rpms can be downloaded instead of downloading" +-msgstr "다운로드 대신 rpms를 다운로드 할 수있는 URL 목록 인쇄" ++msgstr "내려받기 대신 rpms를 내려받기 할 수 있는 URL 목록 인쇄" + + #: plugins/download.py:72 + msgid "when running with --url, limit to specific protocols" +-msgstr "--url을 사용하여 실행하면 특정 프로토콜로 제한됩니다." ++msgstr "--url을 사용하여 실행하면 특정 통신규약이 제한됩니다" + +-#: plugins/download.py:121 plugins/reposync.py:293 ++#: plugins/download.py:121 plugins/reposync.py:314 + #, python-format + msgid "Failed to get mirror for package: %s" +-msgstr "패키지 미러링에 실패했습니다. %s" ++msgstr "꾸러미 연결주소 얻기에 실패했습니다: %s" + + #: plugins/download.py:243 + msgid "Exiting due to strict setting." +@@ -570,7 +647,7 @@ msgstr "엄격한 설정으로 인해 종료됩니다." + + #: plugins/download.py:261 + msgid "Error in resolve of packages:" +-msgstr "패키지 해결 오류 :" ++msgstr "꾸러미(package) 해결 오류 :" + + #: plugins/download.py:279 + #, python-format +@@ -580,27 +657,145 @@ msgstr "소스 rpm이 정의되지 않았습니다. %s" + #: plugins/download.py:296 plugins/download.py:309 + #, python-format + msgid "No package %s available." +-msgstr "패키지 없음 %s 유효한." ++msgstr "가용한 꾸러미(package) %s가 없습니다." ++ ++#: plugins/groups_manager.py:49 ++msgid "Invalid group id" ++msgstr "유효하지 않는 그룹 id" ++ ++#: plugins/groups_manager.py:58 ++msgid "Invalid translated data, should be in form 'lang:text'" ++msgstr "잘못 번역된 자료, 형식 'lang:text' 에 있어야 합니다" ++ ++#: plugins/groups_manager.py:61 ++msgid "Invalid/empty language for translated data" ++msgstr "번역된 자료가 유효하지 않음/비워짐" ++ ++#: plugins/groups_manager.py:71 ++msgid "Can't generate group id from '{}'. Please specify group id using --id." ++msgstr "" ++"'{}' 에서 그룹 id를 발생 할 수 없습니다. --id를 사용하여 그룹 id를 지정해 주" ++"세요." ++ ++#: plugins/groups_manager.py:79 ++msgid "create and edit groups metadata file" ++msgstr "그룹 메타데이타 파일 생성하고 수정합니다" ++ ++#: plugins/groups_manager.py:90 ++msgid "load groups metadata from file" ++msgstr "파일에서 그룹 메타파일을 적재합니다" ++ ++#: plugins/groups_manager.py:93 ++msgid "save groups metadata to file" ++msgstr "그룹 메타자료를 파일에 저장합니다" ++ ++#: plugins/groups_manager.py:95 ++msgid "load and save groups metadata to file" ++msgstr "그룹 메타파일을 파일에 적재하고 저장합니다" ++ ++#: plugins/groups_manager.py:97 ++msgid "print the result metadata to stdout" ++msgstr "결과 메타데이타를 표준출력으로 출력한다" ++ ++#: plugins/groups_manager.py:100 ++msgid "group id" ++msgstr "그룹 id" ++ ++#: plugins/groups_manager.py:101 ++msgid "group name" ++msgstr "그룹 이름" ++ ++#: plugins/groups_manager.py:103 ++msgid "group description" ++msgstr "그룹 설명" ++ ++#: plugins/groups_manager.py:105 ++msgid "group display order" ++msgstr "그룸 표시 순서" ++ ++#: plugins/groups_manager.py:108 ++msgid "translated name for the group" ++msgstr "그룹을 위한 번역된 이름" ++ ++#: plugins/groups_manager.py:111 ++msgid "translated description for the group" ++msgstr "그룹을 위한 번역 설명" ++ ++#: plugins/groups_manager.py:115 ++msgid "make the group user visible (default)" ++msgstr "그룹 사용자를 표시 (기본값)" ++ ++#: plugins/groups_manager.py:118 ++msgid "make the group user invisible" ++msgstr "그룹 사용자를 보이지 않게 표시" ++ ++#: plugins/groups_manager.py:123 ++msgid "add packages to the mandatory section" ++msgstr "꾸러미(package)를 필 수 부분에 추가합니다" ++ ++#: plugins/groups_manager.py:125 ++msgid "add packages to the optional section" ++msgstr "꾸러미(package)를 선택 부분에 추가합니다" ++ ++#: plugins/groups_manager.py:127 ++msgid "remove packages from the group instead of adding them" ++msgstr "추가하기 대신에 그룹에서 꾸러미(package)를 제거합니다" ++ ++#: plugins/groups_manager.py:129 ++msgid "include also direct dependencies for packages" ++msgstr "꾸러미(package)를 위해 직접적인 의존성을 포함한다" ++ ++#: plugins/groups_manager.py:132 ++msgid "package specification" ++msgstr "꾸러미(package) 사양" ++ ++#: plugins/groups_manager.py:156 ++msgid "Can't edit group without specifying it (use --id or --name)" ++msgstr "이것(user --id 또느 --name)을 특정하지 않고 그룹을 수정 할 수 없습니다" ++ ++#: plugins/groups_manager.py:190 ++msgid "Can't load file \"{}\": {}" ++msgstr "파일 \"{}\": {} 를 적재 할 수 없습니다" ++ ++#: plugins/groups_manager.py:206 ++msgid "Can't save file \"{}\": {}" ++msgstr "파일 \"{}\": {}을 저장 할 수 없습니다" ++ ++#: plugins/groups_manager.py:261 ++msgid "No match for argument: {}" ++msgstr "일치하는 인수가 없습니다 :{}" ++ ++#: plugins/groups_manager.py:298 ++msgid "Can't remove packages from non-existent group" ++msgstr "존재하지 않는 그룹에서 꾸러미(package)를 제거 할 수 없습니다" ++ ++#: plugins/groups_manager.py:307 ++msgid "" ++"Group id '{}' generated from '{}' is duplicit. Please specify group id using " ++"--id." ++msgstr "" ++"'{}'에서 발생한 그룹 id '{}'는 중복되었습니다. --id를 사용하여 그룹 id를 지정" ++"하기 바랍니다." + + #: plugins/leaves.py:32 + msgid "List installed packages not required by any other package" +-msgstr "다른 패키지에서 필요하지 않은 설치된 패키지 나열" ++msgstr "다른 꾸러미(package)에서 필요하지 않은 설치된 꾸러미(packages) 나열" + + #: plugins/local.py:122 + msgid "Unable to create a directory '{}' due to '{}'" +-msgstr "'{}'(으)로 인해 '{}'디렉토리를 만들 수 없습니다." ++msgstr "'{}'(으)로 인해 '{}'디렉토리를 만들 수 없습니다" + + #: plugins/local.py:126 + msgid "'{}' is not a directory" +-msgstr "'{}'은 (는) 디렉토리가 아닙니다." ++msgstr "'{}'는 디렉토리가 아닙니다" + + #: plugins/local.py:135 + msgid "Copying '{}' to local repo" +-msgstr "'{}'을 (를) 로컬 저장소로 복사 중입니다." ++msgstr "'{}'을 로컬 저장소로 복사 중입니다" + + #: plugins/local.py:141 + msgid "Can't write file '{}'" +-msgstr "'{}'파일을 쓸 수 없습니다." ++msgstr "'{}'파일을 쓸 수 없습니다" + + #: plugins/local.py:156 + msgid "Rebuilding local repo" +@@ -608,73 +803,135 @@ msgstr "지역 레포 복구" + + #: plugins/migrate.py:45 + msgid "migrate yum's history, group and yumdb data to dnf" +-msgstr "yum의 히스토리, 그룹 및 yumdb 데이터를 dnf로 마이그레이션합니다." ++msgstr "yum 사용기록, 그룹 및 yumdb 데이터를 dnf로 마이그레이션합니다" + + #: plugins/migrate.py:54 + msgid "Migrating history data..." + msgstr "기록 데이터 마이그레이션 중 ..." + +-#: plugins/needs_restarting.py:65 ++#: plugins/modulesync.py:37 ++msgid "" ++"Download packages from modules and/or create a repository with modular data" ++msgstr "모듈에서 꾸러미를 내려 받기와/또는 모듈식 자료를 갖고 있는 저장소를 생성" ++ ++#: plugins/modulesync.py:44 ++msgid "MODULE" ++msgstr "모듈" ++ ++#: plugins/modulesync.py:45 ++msgid "modules to download" ++msgstr "내려받아야 할 모듈" ++ ++#: plugins/modulesync.py:47 ++msgid "enable repositories with source packages" ++msgstr "원천 꾸러미와 함께 저장소를 활성화" ++ ++#: plugins/modulesync.py:49 ++msgid "enable repositories with debug-info and debug-source packages" ++msgstr "디버그-정보와 디버그-원천 꾸러미와 함께 저장소 활성화" ++ ++#: plugins/modulesync.py:53 ++msgid "download only packages from newest modules" ++msgstr "최신 모듈에서 꾸러미만 내려받기" ++ ++#: plugins/modulesync.py:85 ++msgid "Unable to find a match for argument: '{}'" ++msgid_plural "Unable to find a match for arguments: '{}'" ++msgstr[0] "인수와 일치하는 항목을 찾을 수 없습니다: '{}'" ++ ++#: plugins/modulesync.py:107 ++msgid "" ++"Creation of repository failed with return code {}. All downloaded content " ++"was kept on the system" ++msgstr "반환 코드 {}로 인하여 저장소 생성에 실패함. 모두 내려받기된 내용은 " ++"시스템에서 보관됩니다" ++ ++#: plugins/modulesync.py:144 ++#, python-brace-format ++msgid "No match for artifact '{0}' from module '{1}'" ++msgstr "모듈 '{1}'에서 인위 결과물 '{0}'과 일치하는 부분이 없습니다" ++ ++#: plugins/modulesync.py:162 ++#, python-brace-format ++msgid "No match for package name '{0}' in profile {1} from module {2}" ++msgstr "모듈 {2}에서 프로파일 {1}인 꾸러미 이름 '{0}'과 일치하는 부분이 없습니다" ++ ++#: plugins/modulesync.py:166 ++msgid "No mach for argument '{}'" ++msgstr "인수와 일치하는 항목이 없습니다 '{}'" ++ ++#. TODO(jmracek) Shell we end with an error or with RC 1? ++#: plugins/modulesync.py:198 ++msgid "Unable to satisfy require {}" ++msgstr "필요사항 {}를 만족 할 수 없음" ++ ++#: plugins/needs_restarting.py:66 + #, python-brace-format + msgid "" + "No installed package found for package name \"{pkg}\" specified in needs-" + "restarting file \"{file}\"." +-msgstr "" ++msgstr "재시작이 필요한 파일 \"{file}\" 에 지정한 꾸러미 이름 \"{pkg}\"을 위하여 " ++"설치된 꾸러미를 찾을 수 없습니다." + +-#: plugins/needs_restarting.py:199 ++#: plugins/needs_restarting.py:220 + msgid "determine updated binaries that need restarting" + msgstr "다시 시작해야하는 업데이트 된 바이너리 결정" + +-#: plugins/needs_restarting.py:204 ++#: plugins/needs_restarting.py:225 + msgid "only consider this user's processes" +-msgstr "이 사용자의 프로세스 만 고려하십시오." ++msgstr "이 사용자의 프로세스만 고려하세요" + +-#: plugins/needs_restarting.py:206 ++#: plugins/needs_restarting.py:227 + msgid "" + "only report whether a reboot is required (exit code 1) or not (exit code 0)" + msgstr "" ++"재시작이 요구되는 (exit code 1) 또는 아닌(exit code0) 경우에만 보고합니다" + + #: plugins/needs_restarting.py:230 ++msgid "only report affected systemd services" ++msgstr "systemd 서비스에 영향을 미치는 것만 보고합니다" ++ ++#: plugins/needs_restarting.py:253 + msgid "Core libraries or services have been updated since boot-up:" +-msgstr "" ++msgstr "Core 라이브러리와 서비스는 재시작 이 후에 최신화 됩니다:" + +-#: plugins/needs_restarting.py:235 ++#: plugins/needs_restarting.py:258 + msgid "Reboot is required to fully utilize these updates." +-msgstr "" ++msgstr "재시작은 이들 최신화를 완전히 사용하려면 필요합니다." + +-#: plugins/needs_restarting.py:236 ++#: plugins/needs_restarting.py:259 + msgid "More information:" +-msgstr "" ++msgstr "자세한 정보:" + +-#: plugins/needs_restarting.py:240 ++#: plugins/needs_restarting.py:263 + msgid "No core libraries or services have been updated since boot-up." +-msgstr "" ++msgstr "핵심 라이브러리와 서비스는 재시작 이 후에 최신화 되지 않습니다." + +-#: plugins/needs_restarting.py:242 ++#: plugins/needs_restarting.py:265 + msgid "Reboot should not be necessary." +-msgstr "" ++msgstr "재시작은 필요하지 않을 수 있습니다." + + #: plugins/post-transaction-actions.py:71 + #, python-format + msgid "Bad Action Line \"%s\": %s" +-msgstr "" ++msgstr "잘못된 동작 선 \"%s\": %s" + + #. unsupported state, skip it + #: plugins/post-transaction-actions.py:130 + #, python-format + msgid "Bad Transaction State: %s" +-msgstr "" ++msgstr "잘못된 연결 상태: %s" + +-#: plugins/post-transaction-actions.py:153 +-#: plugins/post-transaction-actions.py:155 ++#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:159 + #, python-format + msgid "post-transaction-actions: %s" +-msgstr "" ++msgstr "연결 후 동작: %s" + +-#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:161 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" +-msgstr "" ++msgstr "연결 후 동작: 잘못된 명령 \"%s\": %s" + + #: plugins/repoclosure.py:42 + msgid "Display a list of unresolved dependencies for repositories" +@@ -686,149 +943,160 @@ msgstr "재구 축은 해결되지 않은 종속성으로 종료되었습니다. + + #: plugins/repoclosure.py:153 + msgid "check packages of the given archs, can be specified multiple times" +-msgstr "지정된 아치의 패키지를 검사하고 여러 번 지정할 수 있습니다." ++msgstr "지정된 아치의 꾸러미(package)를 검사하고 여러 번 지정할 수 있습니다" + + #: plugins/repoclosure.py:156 + msgid "Specify repositories to check" +-msgstr "확인할 저장소를 지정하십시오." ++msgstr "점검 할 저장소를 지정하세요" + + #: plugins/repoclosure.py:158 + msgid "Check only the newest packages in the repos" +-msgstr "리포지토리의 최신 패키지 만 확인하십시오." ++msgstr "저장소 최신 꾸러미(package)만 확인하세요" + + #: plugins/repoclosure.py:161 + msgid "Check closure for this package only" +-msgstr "이 패키지의 폐쇄 만 확인하십시오." ++msgstr "이 꾸러미(package)의 폐쇄만 확인하세요" + + #: plugins/repodiff.py:45 + msgid "List differences between two sets of repositories" +-msgstr "" ++msgstr "두 개의 저장소 구성 사이의 목록 차이점" + + #: plugins/repodiff.py:58 + msgid "Specify old repository, can be used multiple times" +-msgstr "" ++msgstr "여러번 사용될 수 있는, 오래된 저장소를 지정합니다" + + #: plugins/repodiff.py:60 + msgid "Specify new repository, can be used multiple times" +-msgstr "" ++msgstr "여러 번 사용 될 수 있는, 새로운 저장소를 지정합니다" + + #: plugins/repodiff.py:63 + msgid "" + "Specify architectures to compare, can be used multiple times. By default, " + "only source rpms are compared." + msgstr "" ++"비교 할 구조를 지정하고, 여러 번 사용 될 수 있습니다. 기본적으로, 자원 rpms" ++"만 비교됩니다." + + #: plugins/repodiff.py:67 + msgid "Output additional data about the size of the changes." +-msgstr "" ++msgstr "크기 변화에 대한 추가 자료를 출력합니다." + + #: plugins/repodiff.py:69 + msgid "" +-"Compare packages also by arch. By default packages are compared just by " +-"name." ++"Compare packages also by arch. By default packages are compared just by name." + msgstr "" ++"구조에 의해 꾸러미(package) 또한 비교합니다. 기본적으로 꾸러미(package)는 이" ++"름으로만 비교됩니다." + + #: plugins/repodiff.py:72 + msgid "Output a simple one line message for modified packages." +-msgstr "" ++msgstr "수정된 꾸러미(pacakage)지를 위해 단순히 한 줄 메시지를 출력합니다." + + #: plugins/repodiff.py:74 + msgid "" + "Split the data for modified packages between upgraded and downgraded " + "packages." +-msgstr "" ++msgstr "향상 또는 향상 꾸러미 사이에서 변형된 꾸러미를 위해 자료를 분할합니다." + + #: plugins/repodiff.py:86 + msgid "Both old and new repositories must be set." +-msgstr "" ++msgstr "오래된 것과 새로운 저장소 모두 구성되어야 합니다." + + #: plugins/repodiff.py:178 + msgid "Size change: {} bytes" +-msgstr "" ++msgstr "크기 변화: {} bytes" + + #: plugins/repodiff.py:184 + msgid "Added package : {}" +-msgstr "" ++msgstr "추가된 꾸러미(package) : {}" + + #: plugins/repodiff.py:187 + msgid "Removed package: {}" +-msgstr "" ++msgstr "제거된 꾸러미(package): {}" + + #: plugins/repodiff.py:190 + msgid "Obsoleted by : {}" +-msgstr "" ++msgstr "사용되지 않음 : {}" + + #: plugins/repodiff.py:195 + msgid "" + "\n" + "Upgraded packages" + msgstr "" ++"\n" ++"향상된 꾸러미(package)" + + #: plugins/repodiff.py:200 + msgid "" + "\n" + "Downgraded packages" + msgstr "" ++"\n" ++"꾸러미 하향설치" + + #: plugins/repodiff.py:207 + msgid "" + "\n" + "Modified packages" + msgstr "" ++"\n" ++"변형된 꾸러미(package)" + + #: plugins/repodiff.py:212 + msgid "" + "\n" + "Summary" + msgstr "" ++"\n" ++"요약" + + #: plugins/repodiff.py:213 + msgid "Added packages: {}" +-msgstr "" ++msgstr "추가된 꾸러미(package): {}" + + #: plugins/repodiff.py:214 + msgid "Removed packages: {}" +-msgstr "" ++msgstr "제거된 꾸러미(package): {}" + + #: plugins/repodiff.py:216 + msgid "Upgraded packages: {}" +-msgstr "" ++msgstr "향상된 꾸러미(package): {}" + + #: plugins/repodiff.py:217 + msgid "Downgraded packages: {}" +-msgstr "" ++msgstr "하향설치된 꾸러미: {}" + + #: plugins/repodiff.py:219 + msgid "Modified packages: {}" +-msgstr "" ++msgstr "변형된 꾸러미(package): {}" + + #: plugins/repodiff.py:222 + msgid "Size of added packages: {}" +-msgstr "" ++msgstr "크기가 증가된 꾸러미(package): {}" + + #: plugins/repodiff.py:223 + msgid "Size of removed packages: {}" +-msgstr "" ++msgstr "크기가 제거된 꾸러미(package): {}" + + #: plugins/repodiff.py:225 + msgid "Size of modified packages: {}" +-msgstr "" ++msgstr "크기가 변형된 꾸러미(package): {}" + + #: plugins/repodiff.py:228 + msgid "Size of upgraded packages: {}" +-msgstr "" ++msgstr "크기가 향상된 꾸러미: {}" + + #: plugins/repodiff.py:230 + msgid "Size of downgraded packages: {}" +-msgstr "" ++msgstr "크기가 하향설치된 꾸러미: {}" + + #: plugins/repodiff.py:232 + msgid "Size change: {}" +-msgstr "" ++msgstr "크기 변경: {}" + + #: plugins/repograph.py:50 + msgid "Output a full package dependency graph in dot format" +-msgstr "도트 형식의 전체 패키지 종속성 그래프 출력" ++msgstr "도트 형식의 전체 꾸러미(package) 종속성 그래프 출력" + + #: plugins/repograph.py:110 + #, python-format +@@ -837,186 +1105,206 @@ msgstr "아무것도 제공하지 않습니다 : '%s'" + + #: plugins/repomanage.py:45 + msgid "Manage a directory of rpm packages" +-msgstr "rpm 패키지 디렉토리 관리" ++msgstr "rpm 꾸러미(package) 디렉토리 관리" + + #: plugins/repomanage.py:59 + msgid "Pass either --old or --new, not both!" +-msgstr "--old 또는 --new 중 하나를 전달하십시오." ++msgstr "--old 또는 --new 중 하나를 전달하세요!" + +-#: plugins/repomanage.py:71 ++#: plugins/repomanage.py:89 + msgid "No files to process" +-msgstr "처리 할 파일이 없습니다." ++msgstr "처리 할 파일 없음" + +-#: plugins/repomanage.py:93 ++#: plugins/repomanage.py:96 + msgid "Could not open {}" +-msgstr "{}을 (를) 열 수 없습니다." ++msgstr "{}을 열 수 없습니다" + +-#: plugins/repomanage.py:177 ++#: plugins/repomanage.py:180 + msgid "Print the older packages" +-msgstr "이전 패키지 인쇄" ++msgstr "이전 꾸러미(package) 인쇄" + +-#: plugins/repomanage.py:179 ++#: plugins/repomanage.py:182 + msgid "Print the newest packages" +-msgstr "최신 패키지 인쇄" ++msgstr "최신 꾸러미(package) 인쇄" + +-#: plugins/repomanage.py:181 ++#: plugins/repomanage.py:184 + msgid "Space separated output, not newline" + msgstr "공백으로 구분 된 출력이 아닌 개행 문자" + +-#: plugins/repomanage.py:183 ++#: plugins/repomanage.py:186 + msgid "Newest N packages to keep - defaults to 1" +-msgstr "보관할 최신 N 패키지 - 기본값은 1입니다." ++msgstr "보관할 최신 N 꾸러미(package) - 기본값은 1입니다" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:189 + msgid "Path to directory" + msgstr "디렉토리 경로" + +-#: plugins/reposync.py:54 ++#: plugins/reposync.py:55 + msgid "download all packages from remote repo" +-msgstr "원격 저장소에서 모든 패키지를 다운로드하십시오." ++msgstr "원격 저장소에서 모든 꾸러미(package)를 내려받아요" + +-#: plugins/reposync.py:63 ++#: plugins/reposync.py:64 + msgid "download only packages for this ARCH" +-msgstr "이 ARCH 용 패키지 만 다운로드하십시오." ++msgstr "이 ARCH용 꾸러미(package)만 내려받아요" + +-#: plugins/reposync.py:65 ++#: plugins/reposync.py:66 + msgid "delete local packages no longer present in repository" +-msgstr "저장소에 더 이상 존재하지 않는 로컬 패키지 삭제" ++msgstr "저장소에 더 이상 존재하지 않는 로컬 꾸러미(package) 삭제" + +-#: plugins/reposync.py:67 +-msgid "also download and uncompress comps.xml" +-msgstr "" +- +-#: plugins/reposync.py:69 ++#: plugins/reposync.py:68 + msgid "download all the metadata." +-msgstr "" ++msgstr "모든 메타데이타 내려받기." + +-#: plugins/reposync.py:71 +-msgid "download only newest packages per-repo" +-msgstr "repo 당 최신 패키지 만 다운로드하십시오." ++#: plugins/reposync.py:70 ++msgid "Remove packages that fail GPG signature checking after downloading" ++msgstr "내려받기 후에 점검한 GPG 서명이 실패한 꾸러미를 제거합니다" + + #: plugins/reposync.py:73 +-msgid "where to store downloaded repositories" +-msgstr "" ++msgid "also download and uncompress comps.xml" ++msgstr "또한 comps.xml 내려받기와 압축 풀기" + + #: plugins/reposync.py:75 +-msgid "Don't add the reponame to the download path." +-msgstr "" +- +-#: plugins/reposync.py:77 + msgid "" +-"where to store downloaded repository metadata. Defaults to the value of " +-"--download-path." ++"where to store downloaded repository metadata. Defaults to the value of --" ++"download-path." + msgstr "" ++"내려받은 저장소 메타데이타를 저장하기 위한 장소. --download-path의 값으로 기" ++"본 지정합니다." ++ ++#: plugins/reposync.py:78 ++msgid "download only newest packages per-repo" ++msgstr "저장소 최신 꾸러미(package)만 내려받아요" + + #: plugins/reposync.py:80 +-msgid "operate on source packages" +-msgstr "소스 패키지를 조작한다." ++msgid "Don't add the reponame to the download path." ++msgstr "내려받기 경로에 저장소이름을 추가하지 않습니다." + + #: plugins/reposync.py:82 ++msgid "where to store downloaded repositories" ++msgstr "내려받기 한 저장소를 저장할 위치" ++ ++#: plugins/reposync.py:84 + msgid "try to set local timestamps of local files by the one on the server" +-msgstr "" ++msgstr "서버에 있는 하나에서 로컬파일의 로컬 타임스템프 설정을 시도하세요" ++ ++#: plugins/reposync.py:87 ++msgid "download only source packages" ++msgstr "원천 꾸러미만 내려받기" + +-#: plugins/reposync.py:85 ++#: plugins/reposync.py:89 + msgid "Just list urls of what would be downloaded, don't download" +-msgstr "" ++msgstr "내려 받을 수 있는 url만 목록화하며, 내려 받지 않습니다" + +-#: plugins/reposync.py:109 ++#: plugins/reposync.py:113 + msgid "Can't use --norepopath with multiple repositories" +-msgstr "" ++msgstr "다중 저장소와 함께 --norepath를 사용 할 수 없습니다" + +-#: plugins/reposync.py:127 ++#: plugins/reposync.py:132 + #, python-format + msgid "Failed to get mirror for metadata: %s" +-msgstr "" ++msgstr "메타데이타에 대한 연결주소 얻기를 실패하였습니다:%s" + +-#: plugins/reposync.py:144 ++#: plugins/reposync.py:149 + msgid "Failed to get mirror for the group file." +-msgstr "" ++msgstr "그룹 파일을 위하여 연결주소 얻기에 실패하였습니다." ++ ++#: plugins/reposync.py:168 ++msgid "Removing {}: {}" ++msgstr "제거하기{}: {}" + + #: plugins/reposync.py:175 ++msgid "GPG signature check failed." ++msgstr "GPG 서명 점검이 실패하였습니다." ++ ++#: plugins/reposync.py:196 + msgid "Download target '{}' is outside of download path '{}'." +-msgstr "" ++msgstr "내려받기 대상 '{}'는 내려받기 경로'{}'의 밖에 있습니다." + +-#: plugins/reposync.py:190 ++#: plugins/reposync.py:211 + #, python-format + msgid "[DELETED] %s" + msgstr "[DELETED] %s" + +-#: plugins/reposync.py:192 ++#: plugins/reposync.py:213 + #, python-format + msgid "failed to delete file %s" + msgstr "파일을 삭제하지 못했습니다. %s" + +-#: plugins/reposync.py:201 ++#: plugins/reposync.py:222 + #, python-format + msgid "comps.xml for repository %s saved" + msgstr "저장소에 대한 comps.xml %s 저장된" + + #: plugins/show_leaves.py:54 + msgid "New leaves:" +-msgstr "새 잎 :" ++msgstr "독립 꾸러미(package):" + +-#: plugins/versionlock.py:32 ++#: plugins/versionlock.py:33 + #, python-format + msgid "Unable to read version lock configuration: %s" + msgstr "버전 잠금 설정을 읽을 수 없습니다 : %s" + +-#: plugins/versionlock.py:33 +-msgid "Locklist not set" +-msgstr "잠금 목록이 설정되지 않았습니다." +- + #: plugins/versionlock.py:34 +-msgid "Adding versionlock on:" +-msgstr "" ++msgid "Locklist not set" ++msgstr "잠금 목록 설정되지 않음" + + #: plugins/versionlock.py:35 +-msgid "Adding exclude on:" +-msgstr "" ++msgid "Adding versionlock on:" ++msgstr "버전잠금 설정 추가하기:" + + #: plugins/versionlock.py:36 +-msgid "Package already locked in equivalent form:" +-msgstr "" ++msgid "Adding exclude on:" ++msgstr "제외 하기 추가하기:" + + #: plugins/versionlock.py:37 +-msgid "Package {} is already locked" +-msgstr "" ++msgid "Package already locked in equivalent form:" ++msgstr "꾸러미(package)는 이미 동일한 형태로 잠겨졌습니다:" + + #: plugins/versionlock.py:38 +-msgid "Package {} is already excluded" +-msgstr "" ++msgid "Package {} is already locked" ++msgstr "꾸러미(package) {} 는 이미 잠겨졌습니다" + + #: plugins/versionlock.py:39 +-msgid "Deleting versionlock for:" +-msgstr "" ++msgid "Package {} is already excluded" ++msgstr "꾸러미(package) {} 는 이미 제외되었습니다" + + #: plugins/versionlock.py:40 +-msgid "No package found for:" +-msgstr "" ++msgid "Deleting versionlock for:" ++msgstr "버전 잠금을 제거하기:" + + #: plugins/versionlock.py:41 +-msgid "Excludes from versionlock plugin were not applied" +-msgstr "" ++msgid "No package found for:" ++msgstr "찾고자 하는 꾸러미(package)가 없습니다:" + + #: plugins/versionlock.py:42 +-msgid "Versionlock plugin: number of lock rules from file \"{}\" applied: {}" +-msgstr "" ++msgid "Excludes from versionlock plugin were not applied" ++msgstr "버전 잠금 플러그인에서 제외는 적용되지 않습니다" + + #: plugins/versionlock.py:43 +-msgid "Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" +-msgstr "" ++msgid "Versionlock plugin: number of lock rules from file \"{}\" applied: {}" ++msgstr "버전 잠금 플러그인: 적용된 파일 \"{} \"에서 잠금 규칙의 수: {}" + + #: plugins/versionlock.py:44 ++msgid "" ++"Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" ++msgstr "버전 잠금 플러그인: 적용된 파일 \"{} \"에서 제외 규칙의 수: {}" ++ ++#: plugins/versionlock.py:45 + msgid "Versionlock plugin: could not parse pattern:" +-msgstr "" ++msgstr "버전 잠금 플러그인: 유형을 구문 분석 할 수 없습니다:" + +-#: plugins/versionlock.py:130 ++#: plugins/versionlock.py:134 + msgid "control package version locks" +-msgstr "" ++msgstr "꾸러미 버전 잠금을 제어합니다" + +-#: plugins/versionlock.py:136 ++#: plugins/versionlock.py:140 + msgid "Use package specifications as they are, do not try to parse them" +-msgstr "" ++msgstr "꾸러미(package) 사양을 그대로 사용하며, 구문 분석을 시도하지 않습니다" ++ ++#: plugins/versionlock.py:160 ++msgid "Subcommand '{}' is deprecated. Use 'exclude' subcommand instead." ++msgstr "하위명령 '{}'는 더 이상 사용하지 않습니다. 대신에 하위명령 'exclude'를 " ++"사용합니다." + + #~ msgid "" + #~ "\n" +diff --git a/po/zh_CN.po b/po/zh_CN.po +index 151441d..5e5627e 100644 +--- a/po/zh_CN.po ++++ b/po/zh_CN.po +@@ -1,24 +1,28 @@ + # Tommy He , 2015. #zanata + # Tommy He , 2016. #zanata + # mosquito , 2016. #zanata +-# Charles Lee , 2017. #zanata, 2020. ++# Charles Lee , 2017. #zanata, 2020, 2021. + # cheng ye <18969068329@163.com>, 2017. #zanata +-# Ludek Janda , 2018. #zanata ++# Ludek Janda , 2018. #zanata, 2021. + # Hongqiao Chen , 2020. ++# Sundeep Anand , 2021. ++# Qiyu Yan , 2021. ++# Transtats , 2022. + msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2020-10-05 09:18-0400\n" +-"PO-Revision-Date: 2020-07-09 13:27+0000\n" +-"Last-Translator: Charles Lee \n" +-"Language-Team: Chinese (Simplified) \n" ++"POT-Creation-Date: 2022-02-28 11:53+0100\n" ++"PO-Revision-Date: 2022-03-09 12:39+0000\n" ++"Last-Translator: Transtats \n" ++"Language-Team: Chinese (Simplified) \n" + "Language: zh_CN\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=1; plural=0;\n" +-"X-Generator: Weblate 4.1.1\n" ++"X-Generator: Weblate 4.11.2\n" + + #: plugins/builddep.py:45 + msgid "[PACKAGE|PACKAGE.spec]" +@@ -39,7 +43,7 @@ msgstr "定义一个用于处理 Spec 文件的宏" + + #: plugins/builddep.py:95 + msgid "skip build dependencies not available in repositories" +-msgstr "" ++msgstr "跳过存储库中不可用的构建依赖项" + + #: plugins/builddep.py:98 + msgid "treat commandline arguments as spec files" +@@ -51,15 +55,14 @@ msgstr "将命令行参数作为源码 RPM 处理" + + #: plugins/builddep.py:144 + msgid "RPM: {}" +-msgstr "" ++msgstr "RPM软件包: {}" + + #: plugins/builddep.py:153 + msgid "Some packages could not be found." + msgstr "某些软件包无法找到。" + + #. No provides, no files +-#. Richdeps can have no matches but it could be correct (solver must decide +-#. later) ++#. Richdeps can have no matches but it could be correct (solver must decide later) + #: plugins/builddep.py:173 + #, python-format + msgid "No matching package to install: '%s'" +@@ -87,27 +90,28 @@ msgstr "无匹配软件包: %s" + #: plugins/changelog.py:37 + #, python-brace-format + msgid "Not a valid date: \"{0}\"." +-msgstr "" ++msgstr "无效的日期 : \"{0}\"。" + + #: plugins/changelog.py:43 + msgid "Show changelog data of packages" +-msgstr "" ++msgstr "查看软件包的改变日志数据" + + #: plugins/changelog.py:51 + msgid "" + "show changelog entries since DATE. To avoid ambiguosity, YYYY-MM-DD format " + "is recommended." + msgstr "" ++"显示自 DATE 开始的改变日志信息。为了避免混淆,推荐使用 YYYY-MM-DD 格式。" + + #: plugins/changelog.py:55 + msgid "show given number of changelog entries per package" +-msgstr "" ++msgstr "每个软件包显示指定数量的改变日志信息" + + #: plugins/changelog.py:58 + msgid "" + "show only new changelog entries for packages, that provide an upgrade for " + "some of already installed packages." +-msgstr "" ++msgstr "只显示软件包新的改变日志信息,为已安装的软件包提供升级。" + + #: plugins/changelog.py:60 + msgid "PACKAGE" +@@ -120,109 +124,111 @@ msgstr "未找到匹配的参数: %s" + + #: plugins/changelog.py:109 + msgid "Listing changelogs since {}" +-msgstr "" ++msgstr "列出自 {} 后的改变日志信息" + + #: plugins/changelog.py:111 + msgid "Listing only latest changelog" + msgid_plural "Listing {} latest changelogs" +-msgstr[0] "" ++msgstr[0] "只列出最新 {} 项更改日志" + + #: plugins/changelog.py:116 + msgid "Listing only new changelogs since installed version of the package" +-msgstr "" ++msgstr "在列出安装的软件包版本后的新改变日志" + + #: plugins/changelog.py:118 + msgid "Listing all changelogs" +-msgstr "" ++msgstr "列出所有改变日志" + + #: plugins/changelog.py:122 + msgid "Changelogs for {}" + msgstr "{}的变更记录" + +-#: plugins/config_manager.py:37 ++#: plugins/config_manager.py:38 + #, python-brace-format + msgid "manage {prog} configuration options and repositories" +-msgstr "" ++msgstr "管理 {prog} 配置选项和软件仓库" + +-#: plugins/config_manager.py:44 ++#: plugins/config_manager.py:45 + msgid "repo to modify" + msgstr "要修改的仓库" + +-#: plugins/config_manager.py:47 ++#: plugins/config_manager.py:48 + msgid "save the current options (useful with --setopt)" + msgstr "保存当前选项(与 --setopt 和用)" + +-#: plugins/config_manager.py:50 ++#: plugins/config_manager.py:51 + msgid "add (and enable) the repo from the specified file or url" + msgstr "从指定文件或 URL 添加(并启用)仓库" + +-#: plugins/config_manager.py:53 ++#: plugins/config_manager.py:54 + msgid "print current configuration values to stdout" + msgstr "打印当前配置值到标准输出" + +-#: plugins/config_manager.py:56 ++#: plugins/config_manager.py:57 + msgid "print variable values to stdout" + msgstr "打印变量值到标准输出" + +-#: plugins/config_manager.py:60 ++#: plugins/config_manager.py:61 + msgid "enable repos (automatically saves)" +-msgstr "" ++msgstr "启用仓库(自动保存)" + +-#: plugins/config_manager.py:63 ++#: plugins/config_manager.py:64 + msgid "disable repos (automatically saves)" +-msgstr "" ++msgstr "禁用仓库(自动保存)" + +-#: plugins/config_manager.py:77 ++#: plugins/config_manager.py:78 + msgid "one of the following arguments is required: {}" +-msgstr "" ++msgstr "需要以下参数之一:{}" + +-#: plugins/config_manager.py:86 ++#: plugins/config_manager.py:87 + msgid "" + "Warning: --enablerepo/--disablerepo arguments have no meaningwith config " + "manager. Use --set-enabled/--set-disabled instead." + msgstr "" ++"警告:--enablerepo/--disablerepo 参数对于 config manager 没有作用。请使用 --" ++"set-enabled/--set-disabled。" + +-#: plugins/config_manager.py:131 ++#: plugins/config_manager.py:132 + #, python-format + msgid "No matching repo to modify: %s." + msgstr "没有匹配的仓库可以修改:%s 。" + +-#: plugins/config_manager.py:182 ++#: plugins/config_manager.py:183 + #, python-format + msgid "Adding repo from: %s" + msgstr "添加仓库自:%s" + +-#: plugins/config_manager.py:206 ++#: plugins/config_manager.py:207 + msgid "Configuration of repo failed" + msgid_plural "Configuration of repos failed" + msgstr[0] "配置仓库失败" + +-#: plugins/config_manager.py:216 ++#: plugins/config_manager.py:217 + #, python-format + msgid "Could not save repo to repofile %s: %s" + msgstr "无法保存仓库至仓库文件 %s:%s" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "y" + msgstr "y" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "yes" + msgstr "是" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "n" + msgstr "n" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "no" + msgstr "否" + +-#: plugins/copr.py:79 ++#: plugins/copr.py:84 + msgid "Interact with Copr repositories." +-msgstr "与 Copr 仓库交互" ++msgstr "与 Copr 仓库交互。" + +-#: plugins/copr.py:81 ++#: plugins/copr.py:86 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -250,7 +256,7 @@ msgstr "" + " list --available-by-user=NAME\n" + " search project\n" + "\n" +-" Examples:\n" ++" 例如:\n" + " copr enable rhscl/perl516 epel-6-x86_64\n" + " copr enable ignatenkobrain/ocltoys\n" + " copr disable rhscl/perl516\n" +@@ -260,53 +266,65 @@ msgstr "" + " copr search tests\n" + " " + +-#: plugins/copr.py:107 ++#: plugins/copr.py:112 + msgid "List all installed Copr repositories (default)" + msgstr "列出所有安装的 Copr 仓库(默认)" + +-#: plugins/copr.py:109 ++#: plugins/copr.py:114 + msgid "List enabled Copr repositories" + msgstr "列出启动的 Copr 仓库" + +-#: plugins/copr.py:111 ++#: plugins/copr.py:116 + msgid "List disabled Copr repositories" + msgstr "列出禁用的 Copr 仓库" + +-#: plugins/copr.py:113 ++#: plugins/copr.py:118 + msgid "List available Copr repositories by user NAME" + msgstr "按照用户 NAME 列出可用的 Copr 仓库" + +-#: plugins/copr.py:115 ++#: plugins/copr.py:120 + msgid "Specify an instance of Copr to work with" +-msgstr "" ++msgstr "指定需要使用的 Copr 实例" + +-#: plugins/copr.py:149 plugins/copr.py:217 plugins/copr.py:237 ++#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 + msgid "Error: " + msgstr "错误: " + +-#: plugins/copr.py:150 ++#: plugins/copr.py:155 + msgid "" +-"specify Copr hub either with `--hub` or using " +-"`copr_hub/copr_username/copr_projectname` format" ++"specify Copr hub either with `--hub` or using `copr_hub/copr_username/" ++"copr_projectname` format" + msgstr "" ++"使用 `--hub` 或使用 `copr_hub/copr_username/copr_projectname` 格式指定 Copr " ++"hub" + +-#: plugins/copr.py:153 ++#: plugins/copr.py:158 + msgid "multiple hubs specified" +-msgstr "" ++msgstr "指定多个 hub" + +-#: plugins/copr.py:218 plugins/copr.py:222 ++#: plugins/copr.py:223 plugins/copr.py:227 + msgid "exactly two additional parameters to copr command are required" + msgstr "Copr 命令要求有且仅有两个额外参数" + +-#: plugins/copr.py:238 ++#: plugins/copr.py:232 ++msgid "Too many arguments." ++msgstr "参数过多。" ++ ++#: plugins/copr.py:235 ++msgid "" ++"Bad format of optional chroot. The format is distribution-version-" ++"architecture." ++msgstr "可选 chroot 的错误格式。格式为 distribution-version-architecture。" ++ ++#: plugins/copr.py:250 + msgid "use format `copr_username/copr_projectname` to reference copr project" + msgstr "使用格式 `copr_username/copr_projectname` 来引用 Copr 项目" + +-#: plugins/copr.py:240 ++#: plugins/copr.py:252 + msgid "bad copr project format" + msgstr "错误的 Copr 项目格式" + +-#: plugins/copr.py:254 ++#: plugins/copr.py:266 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -314,78 +332,93 @@ msgid "" + "\n" + "The Fedora Project does not exercise any power over the contents of\n" + "this repository beyond the rules outlined in the Copr FAQ at\n" +-",\n" ++",\n" + "and packages are not held to any quality or security level.\n" + "\n" + "Please do not file bug reports about these packages in Fedora\n" + "Bugzilla. In case of problems, contact the owner of this repository.\n" + msgstr "" ++"\n" ++"启用一个 Copr 仓库。请注意这个仓库\n" ++"不是主发行版本的一部分,质量可能会有所不同。\n" ++"\n" ++"Fedora 项目对其不行使除了于 Copr 常见问题\n" ++"\n" ++"中所提出的规则外的任何权力,并且其软件包不保证达到特定质量\n" ++"和安全水准。\n" ++"\n" ++"请不要在 Fedora Bugzilla 中报告这些软件包中出现的\n" ++"问题。当出现问题时,请联系仓库的所有者。\n" + +-#: plugins/copr.py:271 ++#: plugins/copr.py:283 + msgid "Repository successfully enabled." + msgstr "启用软件仓库成功。" + +-#: plugins/copr.py:276 ++#: plugins/copr.py:288 + msgid "Repository successfully disabled." + msgstr "禁用软件仓库成功。" + +-#: plugins/copr.py:280 ++#: plugins/copr.py:292 + msgid "Repository successfully removed." + msgstr "软件仓库已成功删除。" + +-#: plugins/copr.py:284 plugins/copr.py:693 ++#: plugins/copr.py:296 plugins/copr.py:697 + msgid "Unknown subcommand {}." + msgstr "未知的子命令 {}。" + +-#: plugins/copr.py:341 ++#: plugins/copr.py:353 + msgid "" +-"* These coprs have repo file with an old format that contains no information" +-" about Copr hub - the default one was assumed. Re-enable the project to fix " ++"* These coprs have repo file with an old format that contains no information " ++"about Copr hub - the default one was assumed. Re-enable the project to fix " + "this." + msgstr "" ++"* 这些 coprs 有使用旧格式的 repo 文件,它们没有包括 Copr hub 的信息 - 假设使" ++"用默认值。重新启用项目来解决这个问题。" + +-#: plugins/copr.py:353 ++#: plugins/copr.py:366 + msgid "Can't parse repositories for username '{}'." + msgstr "无法为用户名 username '{}' 解析仓库。" + +-#: plugins/copr.py:356 ++#: plugins/copr.py:369 + msgid "List of {} coprs" + msgstr "{} Coprs 列表" + +-#: plugins/copr.py:364 ++#: plugins/copr.py:374 + msgid "No description given" + msgstr "没有给出描述" + +-#: plugins/copr.py:376 ++#: plugins/copr.py:386 + msgid "Can't parse search for '{}'." + msgstr "无法解析针对 '{}' 的搜索。" + +-#: plugins/copr.py:379 ++#: plugins/copr.py:389 + msgid "Matched: {}" + msgstr "匹配:{}" + +-#: plugins/copr.py:387 ++#: plugins/copr.py:394 + msgid "No description given." + msgstr "没有给出描述。" + +-#: plugins/copr.py:410 ++#: plugins/copr.py:416 + msgid "Safe and good answer. Exiting." + msgstr "安全及明智的答案。退出。" + +-#: plugins/copr.py:417 ++#: plugins/copr.py:423 + msgid "This command has to be run under the root user." +-msgstr "该命令必须以 root 用户运行" ++msgstr "该命令必须以 root 用户运行。" + +-#: plugins/copr.py:481 ++#: plugins/copr.py:485 + msgid "" + "This repository does not have any builds yet so you cannot enable it now." + msgstr "该仓库尚未包含任何构建所以您现在无法启用它。" + +-#: plugins/copr.py:484 ++#: plugins/copr.py:488 + msgid "Such repository does not exist." + msgstr "该软件仓库不存在。" + +-#: plugins/copr.py:528 ++#: plugins/copr.py:532 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -401,47 +434,57 @@ msgid "" + "\n" + "These repositories have been enabled automatically." + msgstr "" ++"启用的 Copr 仓库的维护人员决定\n" ++"它需要依赖于其他仓库。这些仓库\n" ++"通常是必需的,如果需要从主 Copr 仓库\n" ++"(它们会提供运行时依赖软件包)安装 RPM。\n" ++"\n" ++"请注意上面关于质量和程序错误报告的备注\n" ++"也适用于这里,Fedora Project 不控制内容。\n" ++"请检查列表:\n" ++"\n" ++"{0}\n" ++"\n" ++"这些仓库已被自动启用。" + +-#: plugins/copr.py:549 ++#: plugins/copr.py:553 + msgid "Do you want to keep them enabled?" +-msgstr "" ++msgstr "您需要保持它们被启用吗?" + +-#: plugins/copr.py:582 ++#: plugins/copr.py:586 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" +-msgstr "" ++msgstr "删除 copr 仓库 {0}/{1}/{2} 失败" + +-#: plugins/copr.py:593 ++#: plugins/copr.py:597 + msgid "Failed to disable copr repo {}/{}" + msgstr "无法禁用 Copr 软件仓库 {}/{}" + +-#: plugins/copr.py:611 plugins/copr.py:648 ++#: plugins/copr.py:615 plugins/copr.py:652 + msgid "Unknown response from server." + msgstr "来自服务器的未知响应。" + +-#: plugins/copr.py:633 ++#: plugins/copr.py:637 + msgid "Interact with Playground repository." + msgstr "与 Playground 仓库交互。" + +-#: plugins/copr.py:639 +-#, fuzzy +-#| msgid "Interact with Playground repository." ++#: plugins/copr.py:643 + msgid "Enabling a Playground repository." +-msgstr "与 Playground 仓库交互。" ++msgstr "启用 Playground 仓库。" + +-#: plugins/copr.py:640 ++#: plugins/copr.py:644 + msgid "Do you want to continue?" +-msgstr "" ++msgstr "您希望继续吗?" + +-#: plugins/copr.py:683 ++#: plugins/copr.py:687 + msgid "Playground repositories successfully enabled." + msgstr "启用 Playground 仓库成功。" + +-#: plugins/copr.py:686 ++#: plugins/copr.py:690 + msgid "Playground repositories successfully disabled." + msgstr "禁用 Playground 仓库成功。" + +-#: plugins/copr.py:690 ++#: plugins/copr.py:694 + msgid "Playground repositories successfully updated." + msgstr "更新 Playground 仓库成功。" + +@@ -489,6 +532,8 @@ msgid "" + "Allow removing of install-only packages. Using this option may result in an " + "attempt to remove the running kernel." + msgstr "" ++"允许删除仅安装(install-only)的软件包。使用这个选项可能会导致尝试删除正在运行" ++"的内核。" + + #: plugins/debug.py:202 + msgid "name of dump file" +@@ -497,7 +542,7 @@ msgstr "转储文件名称" + #: plugins/debug.py:273 + #, python-format + msgid "Package %s is not available" +-msgstr "软件包 %s 不可用。" ++msgstr "软件包 %s 不可用" + + #: plugins/debug.py:283 + #, python-format +@@ -512,25 +557,25 @@ msgstr "安装调试信息软件包" + #, python-format + msgid "" + "Could not find debuginfo package for the following available packages: %s" +-msgstr "" ++msgstr "无法为以下可用的软件包找到 debuginfo 软件包: %s" + + #: plugins/debuginfo-install.py:185 + #, python-format + msgid "" + "Could not find debugsource package for the following available packages: %s" +-msgstr "" ++msgstr "无法为以下可用的软件包找到 debugsource 软件包: %s" + + #: plugins/debuginfo-install.py:190 + #, python-format + msgid "" + "Could not find debuginfo package for the following installed packages: %s" +-msgstr "" ++msgstr "无法为以下安装的软件包找到 debuginfo 软件包: %s" + + #: plugins/debuginfo-install.py:195 + #, python-format + msgid "" + "Could not find debugsource package for the following installed packages: %s" +-msgstr "" ++msgstr "无法为以下安装的软件包找到 debugsource 软件包: %s" + + #: plugins/debuginfo-install.py:199 + msgid "Unable to find a match" +@@ -554,13 +599,13 @@ msgstr "取而代之下载 -debuginfo 软件包" + + #: plugins/download.py:57 + msgid "download the -debugsource package instead" +-msgstr "" ++msgstr "取而代之下载 -debugsource 软件包" + + #: plugins/download.py:60 + msgid "limit the query to packages of given architectures." +-msgstr "限定查询指定架构的软件包" ++msgstr "限定查询指定架构的软件包。" + +-#: plugins/download.py:62 ++#: plugins/download.py:62 plugins/modulesync.py:51 + msgid "resolve and download needed dependencies" + msgstr "解析并下载所需的依赖关系" + +@@ -568,7 +613,7 @@ msgstr "解析并下载所需的依赖关系" + msgid "" + "when running with --resolve, download all dependencies (do not exclude " + "already installed ones)" +-msgstr "" ++msgstr "当运行时使用 --resolve,下载所有依赖软件包 (不排除已安装的软件包)" + + #: plugins/download.py:67 + msgid "" +@@ -579,7 +624,7 @@ msgstr "打印 rpm 可被下载的 url 列表而不是直接下载" + msgid "when running with --url, limit to specific protocols" + msgstr "当执行时带有 --url 参数,则限制使用指定协议" + +-#: plugins/download.py:121 plugins/reposync.py:293 ++#: plugins/download.py:121 plugins/reposync.py:314 + #, python-format + msgid "Failed to get mirror for package: %s" + msgstr "获取针对以下软件包的镜像失败:%s" +@@ -602,13 +647,127 @@ msgstr "未找到所定义 %s 的源代码软件包 SRPM" + msgid "No package %s available." + msgstr "没有可用的软件包 %s。" + ++#: plugins/groups_manager.py:49 ++msgid "Invalid group id" ++msgstr "无效的组 ID" ++ ++#: plugins/groups_manager.py:58 ++msgid "Invalid translated data, should be in form 'lang:text'" ++msgstr "无效的翻译数据,格式应该是 'lang:text'" ++ ++#: plugins/groups_manager.py:61 ++msgid "Invalid/empty language for translated data" ++msgstr "翻译数据的无效/空语言" ++ ++#: plugins/groups_manager.py:71 ++msgid "Can't generate group id from '{}'. Please specify group id using --id." ++msgstr "无法从 '{}' 生成组 ID。请使用 --id 指定组 ID。" ++ ++#: plugins/groups_manager.py:79 ++msgid "create and edit groups metadata file" ++msgstr "创建并编辑组元数据文件" ++ ++#: plugins/groups_manager.py:90 ++msgid "load groups metadata from file" ++msgstr "从文件加载组元数据" ++ ++#: plugins/groups_manager.py:93 ++msgid "save groups metadata to file" ++msgstr "将组元数据保存到文件中" ++ ++#: plugins/groups_manager.py:95 ++msgid "load and save groups metadata to file" ++msgstr "将组元数据加载并保存到文件中" ++ ++#: plugins/groups_manager.py:97 ++msgid "print the result metadata to stdout" ++msgstr "将结果元数据输出到标准输出" ++ ++#: plugins/groups_manager.py:100 ++msgid "group id" ++msgstr "组 id" ++ ++#: plugins/groups_manager.py:101 ++msgid "group name" ++msgstr "组名称" ++ ++#: plugins/groups_manager.py:103 ++msgid "group description" ++msgstr "组描述" ++ ++#: plugins/groups_manager.py:105 ++msgid "group display order" ++msgstr "组显示顺序" ++ ++#: plugins/groups_manager.py:108 ++msgid "translated name for the group" ++msgstr "组的翻译名称" ++ ++#: plugins/groups_manager.py:111 ++msgid "translated description for the group" ++msgstr "组的翻译描述" ++ ++#: plugins/groups_manager.py:115 ++msgid "make the group user visible (default)" ++msgstr "使组用户可见(默认)" ++ ++#: plugins/groups_manager.py:118 ++msgid "make the group user invisible" ++msgstr "使组用户不可见" ++ ++#: plugins/groups_manager.py:123 ++msgid "add packages to the mandatory section" ++msgstr "在必填部分添加软件包" ++ ++#: plugins/groups_manager.py:125 ++msgid "add packages to the optional section" ++msgstr "在可选部分添加软件包" ++ ++#: plugins/groups_manager.py:127 ++msgid "remove packages from the group instead of adding them" ++msgstr "从组群中删除软件包而不是添加它们" ++ ++#: plugins/groups_manager.py:129 ++msgid "include also direct dependencies for packages" ++msgstr "同时包括软件包的直接依赖软件包" ++ ++#: plugins/groups_manager.py:132 ++msgid "package specification" ++msgstr "软件包规格" ++ ++#: plugins/groups_manager.py:156 ++msgid "Can't edit group without specifying it (use --id or --name)" ++msgstr "没有指定组(使用 --id 或 --name)就无法编辑组" ++ ++#: plugins/groups_manager.py:190 ++msgid "Can't load file \"{}\": {}" ++msgstr "无法加载文件 \"{}\": {}" ++ ++#: plugins/groups_manager.py:206 ++msgid "Can't save file \"{}\": {}" ++msgstr "无法保存文件 \"{}\": {}" ++ ++#: plugins/groups_manager.py:261 ++msgid "No match for argument: {}" ++msgstr "未找到匹配的参数: {}" ++ ++#: plugins/groups_manager.py:298 ++msgid "Can't remove packages from non-existent group" ++msgstr "无法从不存在的组中删除软件包" ++ ++#: plugins/groups_manager.py:307 ++msgid "" ++"Group id '{}' generated from '{}' is duplicit. Please specify group id using " ++"--id." ++msgstr "从 '{}' 生成的组 id '{}' 是显式的。请使用 --id 指定组 ID。" ++ + #: plugins/leaves.py:32 + msgid "List installed packages not required by any other package" + msgstr "列出已安装但不被任何其他软件包所需要的软件包" + + #: plugins/local.py:122 + msgid "Unable to create a directory '{}' due to '{}'" +-msgstr "无法创建目录 '{}' 由于 '{}'" ++msgstr "无法创建目录 '{}' 由于 '{}'" + + #: plugins/local.py:126 + msgid "'{}' is not a directory" +@@ -634,67 +793,127 @@ msgstr "迁移 yum 的历史、分组以及 yumdb 数据至 dnf" + msgid "Migrating history data..." + msgstr "正在迁移历史数据…" + +-#: plugins/needs_restarting.py:65 ++#: plugins/modulesync.py:37 ++msgid "" ++"Download packages from modules and/or create a repository with modular data" ++msgstr "从模块下载软件包和/或创建带有模块化数据的存储库" ++ ++#: plugins/modulesync.py:44 ++msgid "MODULE" ++msgstr "模块" ++ ++#: plugins/modulesync.py:45 ++msgid "modules to download" ++msgstr "要下载的模块" ++ ++#: plugins/modulesync.py:47 ++msgid "enable repositories with source packages" ++msgstr "启用带有源软件包的软件仓库" ++ ++#: plugins/modulesync.py:49 ++msgid "enable repositories with debug-info and debug-source packages" ++msgstr "启用带有 debug-info 和 debug-source 软件包的软件仓库" ++ ++#: plugins/modulesync.py:53 ++msgid "download only packages from newest modules" ++msgstr "只从最新的模块中下载软件包" ++ ++#: plugins/modulesync.py:85 ++msgid "Unable to find a match for argument: '{}'" ++msgid_plural "Unable to find a match for arguments: '{}'" ++msgstr[0] "找不到与参数:'{}'相匹配的项" ++ ++#: plugins/modulesync.py:107 ++msgid "" ++"Creation of repository failed with return code {}. All downloaded content " ++"was kept on the system" ++msgstr "创建存储库会失败,并显示返回码 {}。所有下载的内容都保存在系统上" ++ ++#: plugins/modulesync.py:144 ++#, python-brace-format ++msgid "No match for artifact '{0}' from module '{1}'" ++msgstr "没有与模块 '{1}' 的工件 '{0}' 相匹配的项" ++ ++#: plugins/modulesync.py:162 ++#, python-brace-format ++msgid "No match for package name '{0}' in profile {1} from module {2}" ++msgstr "没有与模块 {2} 中配置文件 {1} 的软件包名称 '{0}' 相匹配的项" ++ ++#: plugins/modulesync.py:166 ++msgid "No mach for argument '{}'" ++msgstr "没有与参数 '{}' 相匹配的项" ++ ++#. TODO(jmracek) Shell we end with an error or with RC 1? ++#: plugins/modulesync.py:198 ++msgid "Unable to satisfy require {}" ++msgstr "无法满足要求 {}" ++ ++#: plugins/needs_restarting.py:66 + #, python-brace-format + msgid "" + "No installed package found for package name \"{pkg}\" specified in needs-" + "restarting file \"{file}\"." +-msgstr "" ++msgstr "未找到在需要重新启动文件 \"{file}\" 中指定的软件包名为 \"{pkg}\" " ++"的已安装的软件包。" + +-#: plugins/needs_restarting.py:199 ++#: plugins/needs_restarting.py:220 + msgid "determine updated binaries that need restarting" + msgstr "判断所升级的二进制文件是否需要重启" + +-#: plugins/needs_restarting.py:204 ++#: plugins/needs_restarting.py:225 + msgid "only consider this user's processes" + msgstr "仅考虑当前用户的进程" + +-#: plugins/needs_restarting.py:206 ++#: plugins/needs_restarting.py:227 + msgid "" + "only report whether a reboot is required (exit code 1) or not (exit code 0)" +-msgstr "" ++msgstr "只报告需要重新引导 (退出代码为 1) 或不需要重新引导 (退出代码为 0)" + + #: plugins/needs_restarting.py:230 ++msgid "only report affected systemd services" ++msgstr "只报告受影响的 systemd 服务" ++ ++#: plugins/needs_restarting.py:253 + msgid "Core libraries or services have been updated since boot-up:" +-msgstr "" ++msgstr "在引导后 Core 库或服务已被更新 :" + +-#: plugins/needs_restarting.py:235 ++#: plugins/needs_restarting.py:258 + msgid "Reboot is required to fully utilize these updates." +-msgstr "" ++msgstr "需要重新启动后才可以使这些更新完全生效。" + +-#: plugins/needs_restarting.py:236 ++#: plugins/needs_restarting.py:259 + msgid "More information:" +-msgstr "" ++msgstr "更多信息 :" + +-#: plugins/needs_restarting.py:240 ++#: plugins/needs_restarting.py:263 + msgid "No core libraries or services have been updated since boot-up." +-msgstr "" ++msgstr "在引导后没有 core 库或服务被更新。" + +-#: plugins/needs_restarting.py:242 ++#: plugins/needs_restarting.py:265 + msgid "Reboot should not be necessary." +-msgstr "" ++msgstr "不需要重新启动。" + + #: plugins/post-transaction-actions.py:71 + #, python-format + msgid "Bad Action Line \"%s\": %s" +-msgstr "" ++msgstr "错误的操作行“ %s”: %s" + + #. unsupported state, skip it + #: plugins/post-transaction-actions.py:130 + #, python-format + msgid "Bad Transaction State: %s" +-msgstr "" ++msgstr "错误的事务状态: %s" + +-#: plugins/post-transaction-actions.py:153 +-#: plugins/post-transaction-actions.py:155 ++#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:159 + #, python-format + msgid "post-transaction-actions: %s" +-msgstr "" ++msgstr "事物后的操作: %s" + +-#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:161 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" +-msgstr "" ++msgstr "事物后的操作 : 无效的命令 \"%s\": %s" + + #: plugins/repoclosure.py:42 + msgid "Display a list of unresolved dependencies for repositories" +@@ -722,129 +941,136 @@ msgstr "仅为该软件包检查依赖闭合性" + + #: plugins/repodiff.py:45 + msgid "List differences between two sets of repositories" +-msgstr "" ++msgstr "列出两组仓库中的不同" + + #: plugins/repodiff.py:58 + msgid "Specify old repository, can be used multiple times" +-msgstr "" ++msgstr "指定旧的仓库,可以使用多次" + + #: plugins/repodiff.py:60 + msgid "Specify new repository, can be used multiple times" +-msgstr "" ++msgstr "指定新的仓库,可以使用多次" + + #: plugins/repodiff.py:63 + msgid "" + "Specify architectures to compare, can be used multiple times. By default, " + "only source rpms are compared." +-msgstr "" ++msgstr "指定要比较的架构,可以使用多次。默认情况下,只比较源 rpms。" + + #: plugins/repodiff.py:67 + msgid "Output additional data about the size of the changes." +-msgstr "" ++msgstr "输出关于改变大小的额外数据。" + + #: plugins/repodiff.py:69 + msgid "" +-"Compare packages also by arch. By default packages are compared just by " +-"name." +-msgstr "" ++"Compare packages also by arch. By default packages are compared just by name." ++msgstr "同时按架构比较软件包。在默认情况下只按名称比较软件包。" + + #: plugins/repodiff.py:72 + msgid "Output a simple one line message for modified packages." +-msgstr "" ++msgstr "为修改的软件包输出一个简单的单行信息。" + + #: plugins/repodiff.py:74 + msgid "" + "Split the data for modified packages between upgraded and downgraded " + "packages." +-msgstr "" ++msgstr "在升级和降级的软件包间为修改的软件包分隔数据。" + + #: plugins/repodiff.py:86 + msgid "Both old and new repositories must be set." +-msgstr "" ++msgstr "新仓库和旧仓库都需要被设置。" + + #: plugins/repodiff.py:178 + msgid "Size change: {} bytes" +-msgstr "" ++msgstr "大小的变化 : {} 字节" + + #: plugins/repodiff.py:184 + msgid "Added package : {}" +-msgstr "" ++msgstr "添加的软件包 : {}" + + #: plugins/repodiff.py:187 + msgid "Removed package: {}" +-msgstr "" ++msgstr "删除的软件包 : {}" + + #: plugins/repodiff.py:190 + msgid "Obsoleted by : {}" +-msgstr "" ++msgstr "被下述软件包弃用:{}" + + #: plugins/repodiff.py:195 + msgid "" + "\n" + "Upgraded packages" + msgstr "" ++"\n" ++"升级的软件包" + + #: plugins/repodiff.py:200 + msgid "" + "\n" + "Downgraded packages" + msgstr "" ++"\n" ++"降级的软件包" + + #: plugins/repodiff.py:207 + msgid "" + "\n" + "Modified packages" + msgstr "" ++"\n" ++"修改的软件包" + + #: plugins/repodiff.py:212 + msgid "" + "\n" + "Summary" + msgstr "" ++"\n" ++"概述" + + #: plugins/repodiff.py:213 + msgid "Added packages: {}" +-msgstr "" ++msgstr "添加的软件包 : {}" + + #: plugins/repodiff.py:214 + msgid "Removed packages: {}" +-msgstr "" ++msgstr "删除的软件包 : {}" + + #: plugins/repodiff.py:216 + msgid "Upgraded packages: {}" +-msgstr "" ++msgstr "升级的软件包 : {}" + + #: plugins/repodiff.py:217 + msgid "Downgraded packages: {}" +-msgstr "" ++msgstr "降级的软件包 : {}" + + #: plugins/repodiff.py:219 + msgid "Modified packages: {}" +-msgstr "" ++msgstr "修改的软件包 : {}" + + #: plugins/repodiff.py:222 + msgid "Size of added packages: {}" +-msgstr "" ++msgstr "添加的软件包的大小 : {}" + + #: plugins/repodiff.py:223 + msgid "Size of removed packages: {}" +-msgstr "" ++msgstr "删除的软件包的大小 : {}" + + #: plugins/repodiff.py:225 + msgid "Size of modified packages: {}" +-msgstr "" ++msgstr "修改的软件包的大小 : {}" + + #: plugins/repodiff.py:228 + msgid "Size of upgraded packages: {}" +-msgstr "" ++msgstr "升级的软件包的大小 : {}" + + #: plugins/repodiff.py:230 + msgid "Size of downgraded packages: {}" +-msgstr "" ++msgstr "降级的软件包的大小 : {}" + + #: plugins/repodiff.py:232 + msgid "Size change: {}" +-msgstr "" ++msgstr "大小改变 : {}" + + #: plugins/repograph.py:50 + msgid "Output a full package dependency graph in dot format" +@@ -863,112 +1089,124 @@ msgstr "管理 RPM 软件包目录" + msgid "Pass either --old or --new, not both!" + msgstr "传入 --old 或者 --new,不可同时传入!" + +-#: plugins/repomanage.py:71 ++#: plugins/repomanage.py:89 + msgid "No files to process" + msgstr "没有可处理的文件" + +-#: plugins/repomanage.py:93 ++#: plugins/repomanage.py:96 + msgid "Could not open {}" + msgstr "无法打开 {}" + +-#: plugins/repomanage.py:177 ++#: plugins/repomanage.py:180 + msgid "Print the older packages" + msgstr "打印较旧的软件包" + +-#: plugins/repomanage.py:179 ++#: plugins/repomanage.py:182 + msgid "Print the newest packages" + msgstr "打印最新的软件包" + +-#: plugins/repomanage.py:181 ++#: plugins/repomanage.py:184 + msgid "Space separated output, not newline" + msgstr "用空格分割输出,而不是新行" + +-#: plugins/repomanage.py:183 ++#: plugins/repomanage.py:186 + msgid "Newest N packages to keep - defaults to 1" + msgstr "要保留的最新的 N 个软件包 - 默认值为 1" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:189 + msgid "Path to directory" + msgstr "指向目录的路径" + +-#: plugins/reposync.py:54 ++#: plugins/reposync.py:55 + msgid "download all packages from remote repo" + msgstr "下载远程仓库中的全部软件包" + +-#: plugins/reposync.py:63 ++#: plugins/reposync.py:64 + msgid "download only packages for this ARCH" + msgstr "只下载这个 ARCH 的软件包" + +-#: plugins/reposync.py:65 ++#: plugins/reposync.py:66 + msgid "delete local packages no longer present in repository" + msgstr "删除已不在仓库中的本地软件包" + +-#: plugins/reposync.py:67 +-msgid "also download and uncompress comps.xml" +-msgstr "" +- +-#: plugins/reposync.py:69 ++#: plugins/reposync.py:68 + msgid "download all the metadata." +-msgstr "" ++msgstr "下载所有元数据。" + +-#: plugins/reposync.py:71 +-msgid "download only newest packages per-repo" +-msgstr "只下载最新的软件包 per-repo" ++#: plugins/reposync.py:70 ++msgid "Remove packages that fail GPG signature checking after downloading" ++msgstr "下载后删除无法通过 GPG 签名检查的软件包" + + #: plugins/reposync.py:73 +-msgid "where to store downloaded repositories" +-msgstr "" ++msgid "also download and uncompress comps.xml" ++msgstr "同时下载并解压 comps.xml" + + #: plugins/reposync.py:75 +-msgid "Don't add the reponame to the download path." +-msgstr "" +- +-#: plugins/reposync.py:77 + msgid "" +-"where to store downloaded repository metadata. Defaults to the value of " +-"--download-path." +-msgstr "" ++"where to store downloaded repository metadata. Defaults to the value of --" ++"download-path." ++msgstr "存储下载的仓库元数据的位置。默认为 --download-path 的值。" ++ ++#: plugins/reposync.py:78 ++msgid "download only newest packages per-repo" ++msgstr "只下载最新的软件包 per-repo" + + #: plugins/reposync.py:80 +-msgid "operate on source packages" +-msgstr "在源软件包中操作" ++msgid "Don't add the reponame to the download path." ++msgstr "不要在下载路径中添加仓库名(reponame)。" + + #: plugins/reposync.py:82 ++msgid "where to store downloaded repositories" ++msgstr "在何处存储已下载的仓库" ++ ++#: plugins/reposync.py:84 + msgid "try to set local timestamps of local files by the one on the server" +-msgstr "" ++msgstr "根据服务器上的文件设置本地文件的本地时间戳" ++ ++#: plugins/reposync.py:87 ++msgid "download only source packages" ++msgstr "只下载源软件包" + +-#: plugins/reposync.py:85 ++#: plugins/reposync.py:89 + msgid "Just list urls of what would be downloaded, don't download" +-msgstr "" ++msgstr "只列出要下载内容的 url,不实际下载" + +-#: plugins/reposync.py:109 ++#: plugins/reposync.py:113 + msgid "Can't use --norepopath with multiple repositories" +-msgstr "" ++msgstr "不能将 --norepopath 与多个仓库一起使用" + +-#: plugins/reposync.py:127 ++#: plugins/reposync.py:132 + #, python-format + msgid "Failed to get mirror for metadata: %s" +-msgstr "" ++msgstr "获取元数据镜像失败:%s" + +-#: plugins/reposync.py:144 ++#: plugins/reposync.py:149 + msgid "Failed to get mirror for the group file." +-msgstr "" ++msgstr "获取组文件镜像失败。" ++ ++#: plugins/reposync.py:168 ++msgid "Removing {}: {}" ++msgstr "正在删除 {}: {}" + + #: plugins/reposync.py:175 ++msgid "GPG signature check failed." ++msgstr "GPG 签名检查失败。" ++ ++#: plugins/reposync.py:196 + msgid "Download target '{}' is outside of download path '{}'." +-msgstr "" ++msgstr "下载的目标 '{}' 在下载路径 '{}' 以外。" + +-#: plugins/reposync.py:190 ++#: plugins/reposync.py:211 + #, python-format + msgid "[DELETED] %s" + msgstr "[DELETED] %s" + +-#: plugins/reposync.py:192 ++#: plugins/reposync.py:213 + #, python-format + msgid "failed to delete file %s" + msgstr "无法删除文件 %s" + +-#: plugins/reposync.py:201 ++#: plugins/reposync.py:222 + #, python-format + msgid "comps.xml for repository %s saved" + msgstr "仓库 %s 的 comps.xml 已保存" +@@ -977,66 +1215,71 @@ msgstr "仓库 %s 的 comps.xml 已保存" + msgid "New leaves:" + msgstr "新增保留项:" + +-#: plugins/versionlock.py:32 ++#: plugins/versionlock.py:33 + #, python-format + msgid "Unable to read version lock configuration: %s" + msgstr "无法读取版本锁配置: %s" + +-#: plugins/versionlock.py:33 ++#: plugins/versionlock.py:34 + msgid "Locklist not set" + msgstr "锁列表未设置" + +-#: plugins/versionlock.py:34 ++#: plugins/versionlock.py:35 + msgid "Adding versionlock on:" + msgstr "正在添加版本锁:" + +-#: plugins/versionlock.py:35 ++#: plugins/versionlock.py:36 + msgid "Adding exclude on:" + msgstr "正在添加排除:" + +-#: plugins/versionlock.py:36 ++#: plugins/versionlock.py:37 + msgid "Package already locked in equivalent form:" +-msgstr "" ++msgstr "软件包已使用等同的格式锁定:" + +-#: plugins/versionlock.py:37 ++#: plugins/versionlock.py:38 + msgid "Package {} is already locked" +-msgstr "" ++msgstr "软件包 {} 已被锁定" + +-#: plugins/versionlock.py:38 ++#: plugins/versionlock.py:39 + msgid "Package {} is already excluded" +-msgstr "" ++msgstr "软件包 {} 已被排除" + +-#: plugins/versionlock.py:39 ++#: plugins/versionlock.py:40 + msgid "Deleting versionlock for:" + msgstr "正在删除版本锁:" + +-#: plugins/versionlock.py:40 ++#: plugins/versionlock.py:41 + msgid "No package found for:" + msgstr "未找到软件包:" + +-#: plugins/versionlock.py:41 ++#: plugins/versionlock.py:42 + msgid "Excludes from versionlock plugin were not applied" + msgstr "从 versionlock 插件中排除的没有被应用" + +-#: plugins/versionlock.py:42 ++#: plugins/versionlock.py:43 + msgid "Versionlock plugin: number of lock rules from file \"{}\" applied: {}" + msgstr "Versionlock 插件: 文件 \"{}\" 中的锁定数量规则被应用:{}" + +-#: plugins/versionlock.py:43 +-msgid "Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" ++#: plugins/versionlock.py:44 ++msgid "" ++"Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" + msgstr "Versionlock 插件: 文件 \"{}\" 中的排除规则数量被应用:{}" + +-#: plugins/versionlock.py:44 ++#: plugins/versionlock.py:45 + msgid "Versionlock plugin: could not parse pattern:" + msgstr "Versionlock 插件:不能解析特征:" + +-#: plugins/versionlock.py:130 ++#: plugins/versionlock.py:134 + msgid "control package version locks" + msgstr "控制软件包版本锁" + +-#: plugins/versionlock.py:136 ++#: plugins/versionlock.py:140 + msgid "Use package specifications as they are, do not try to parse them" +-msgstr "" ++msgstr "按原样使用程序包规格,请勿尝试解析它们" ++ ++#: plugins/versionlock.py:160 ++msgid "Subcommand '{}' is deprecated. Use 'exclude' subcommand instead." ++msgstr "子命令 '{}' 已被弃用。改为使用 'exclude' 子命令。" + + #~ msgid "" + #~ "\n" +diff --git a/po/zh_TW.po b/po/zh_TW.po +index 755d9e6..f7ea95b 100644 +--- a/po/zh_TW.po ++++ b/po/zh_TW.po +@@ -10,10 +10,11 @@ msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2020-10-05 09:18-0400\n" ++"POT-Creation-Date: 2022-02-28 11:53+0100\n" + "PO-Revision-Date: 2020-08-28 21:29+0000\n" + "Last-Translator: Yi-Jyun Pan \n" +-"Language-Team: Chinese (Traditional) \n" ++"Language-Team: Chinese (Traditional) \n" + "Language: zh_TW\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" +@@ -59,8 +60,7 @@ msgid "Some packages could not be found." + msgstr "有些軟體包遍尋不著。" + + #. No provides, no files +-#. Richdeps can have no matches but it could be correct (solver must decide +-#. later) ++#. Richdeps can have no matches but it could be correct (solver must decide later) + #: plugins/builddep.py:173 + #, python-format + msgid "No matching package to install: '%s'" +@@ -141,92 +141,92 @@ msgstr "列出所有變更記錄" + msgid "Changelogs for {}" + msgstr "{} 的變更記錄" + +-#: plugins/config_manager.py:37 ++#: plugins/config_manager.py:38 + #, python-brace-format + msgid "manage {prog} configuration options and repositories" + msgstr "管理 {prog} 的設定選項及軟體庫" + +-#: plugins/config_manager.py:44 ++#: plugins/config_manager.py:45 + msgid "repo to modify" + msgstr "要修改的軟體庫" + +-#: plugins/config_manager.py:47 ++#: plugins/config_manager.py:48 + msgid "save the current options (useful with --setopt)" + msgstr "儲存目前的選項(用於 --setopt)" + +-#: plugins/config_manager.py:50 ++#: plugins/config_manager.py:51 + msgid "add (and enable) the repo from the specified file or url" + msgstr "從指定的檔案或 URL 新增(並啟用)此軟體庫" + +-#: plugins/config_manager.py:53 ++#: plugins/config_manager.py:54 + msgid "print current configuration values to stdout" + msgstr "輸出目前的設定檔值至標準輸出" + +-#: plugins/config_manager.py:56 ++#: plugins/config_manager.py:57 + msgid "print variable values to stdout" + msgstr "輸出變數值至標準輸出" + +-#: plugins/config_manager.py:60 ++#: plugins/config_manager.py:61 + msgid "enable repos (automatically saves)" + msgstr "啟用軟體庫(自動儲存)" + +-#: plugins/config_manager.py:63 ++#: plugins/config_manager.py:64 + msgid "disable repos (automatically saves)" + msgstr "停用軟體庫(自動儲存)" + +-#: plugins/config_manager.py:77 ++#: plugins/config_manager.py:78 + msgid "one of the following arguments is required: {}" + msgstr "需要以下任一引數:{}" + +-#: plugins/config_manager.py:86 ++#: plugins/config_manager.py:87 + msgid "" + "Warning: --enablerepo/--disablerepo arguments have no meaningwith config " + "manager. Use --set-enabled/--set-disabled instead." + msgstr "" +-"警告:--enablerepo/--disablerepo 引數在組態管理員下沒有意義。請改用 --set-enabled/--set-" +-"disabled。" ++"警告:--enablerepo/--disablerepo 引數在組態管理員下沒有意義。請改用 --set-" ++"enabled/--set-disabled。" + +-#: plugins/config_manager.py:131 ++#: plugins/config_manager.py:132 + #, python-format + msgid "No matching repo to modify: %s." + msgstr "沒有符合要修改的軟體庫:%s。" + +-#: plugins/config_manager.py:182 ++#: plugins/config_manager.py:183 + #, python-format + msgid "Adding repo from: %s" + msgstr "從下述加入軟體庫:%s" + +-#: plugins/config_manager.py:206 ++#: plugins/config_manager.py:207 + msgid "Configuration of repo failed" + msgid_plural "Configuration of repos failed" + msgstr[0] "設定軟體庫失敗" + +-#: plugins/config_manager.py:216 ++#: plugins/config_manager.py:217 + #, python-format + msgid "Could not save repo to repofile %s: %s" + msgstr "無法儲存軟體庫至 repofile %s:%s" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "y" + msgstr "y" + +-#: plugins/copr.py:59 ++#: plugins/copr.py:64 + msgid "yes" + msgstr "yes" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "n" + msgstr "n" + +-#: plugins/copr.py:60 ++#: plugins/copr.py:65 + msgid "no" + msgstr "no" + +-#: plugins/copr.py:79 ++#: plugins/copr.py:84 + msgid "Interact with Copr repositories." + msgstr "與 Copr 軟體庫互動。" + +-#: plugins/copr.py:81 ++#: plugins/copr.py:86 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -264,54 +264,67 @@ msgstr "" + " copr search tests\n" + " " + +-#: plugins/copr.py:107 ++#: plugins/copr.py:112 + msgid "List all installed Copr repositories (default)" + msgstr "列出所有安裝的 Copr 軟體庫(預設值)" + +-#: plugins/copr.py:109 ++#: plugins/copr.py:114 + msgid "List enabled Copr repositories" + msgstr "列出啟用的 Copr 軟體庫" + +-#: plugins/copr.py:111 ++#: plugins/copr.py:116 + msgid "List disabled Copr repositories" + msgstr "列出停用的 Copr 軟體庫" + +-#: plugins/copr.py:113 ++#: plugins/copr.py:118 + msgid "List available Copr repositories by user NAME" + msgstr "列出使用者 NAME 可用的 Copr 軟體庫" + +-#: plugins/copr.py:115 ++#: plugins/copr.py:120 + msgid "Specify an instance of Copr to work with" + msgstr "指定要使用 Copr 的實體:" + +-#: plugins/copr.py:149 plugins/copr.py:217 plugins/copr.py:237 ++#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 + msgid "Error: " + msgstr "錯誤: " + +-#: plugins/copr.py:150 ++#: plugins/copr.py:155 + msgid "" +-"specify Copr hub either with `--hub` or using " +-"`copr_hub/copr_username/copr_projectname` format" ++"specify Copr hub either with `--hub` or using `copr_hub/copr_username/" ++"copr_projectname` format" + msgstr "" +-"使用 `--hub` 或者用 `copr_hub/copr_username/copr_projectname` 格式指定 Copr hub" ++"使用 `--hub` 或者用 `copr_hub/copr_username/copr_projectname` 格式指定 Copr " ++"hub" + +-#: plugins/copr.py:153 ++#: plugins/copr.py:158 + msgid "multiple hubs specified" + msgstr "指定了多個 hub" + +-#: plugins/copr.py:218 plugins/copr.py:222 ++#: plugins/copr.py:223 plugins/copr.py:227 + msgid "exactly two additional parameters to copr command are required" + msgstr "傳入 copr 命令的選用參數必須剛好兩個" + +-#: plugins/copr.py:238 ++#: plugins/copr.py:232 ++#, fuzzy ++#| msgid "No match for argument: %s" ++msgid "Too many arguments." ++msgstr "引數不符:%s" ++ ++#: plugins/copr.py:235 ++msgid "" ++"Bad format of optional chroot. The format is distribution-version-" ++"architecture." ++msgstr "" ++ ++#: plugins/copr.py:250 + msgid "use format `copr_username/copr_projectname` to reference copr project" + msgstr "使用 `copr_username/copr_projectname` 格式來參照 Copr 專案" + +-#: plugins/copr.py:240 ++#: plugins/copr.py:252 + msgid "bad copr project format" + msgstr "Copr 專案格式無效" + +-#: plugins/copr.py:254 ++#: plugins/copr.py:266 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -319,7 +332,8 @@ msgid "" + "\n" + "The Fedora Project does not exercise any power over the contents of\n" + "this repository beyond the rules outlined in the Copr FAQ at\n" +-",\n" ++",\n" + "and packages are not held to any quality or security level.\n" + "\n" + "Please do not file bug reports about these packages in Fedora\n" +@@ -330,77 +344,80 @@ msgstr "" + "不是主散布版的一部分,並且品質不定。\n" + "\n" + "Fedora Project 不會對這個軟體庫的內容行使任何超出 Copr 常見問題\n" +-"()\n" ++"()\n" + "列出規則之外的權力,且軟體包並不保有任何的品質與安全性保證。\n" + "\n" + "請不要將這些軟體包的漏洞回報至 Fedora Bugzilla。\n" + "假如碰到問題,請聯絡此軟體庫的擁有者。\n" + +-#: plugins/copr.py:271 ++#: plugins/copr.py:283 + msgid "Repository successfully enabled." + msgstr "軟體庫成功啟用。" + +-#: plugins/copr.py:276 ++#: plugins/copr.py:288 + msgid "Repository successfully disabled." + msgstr "軟體庫成功停用。" + +-#: plugins/copr.py:280 ++#: plugins/copr.py:292 + msgid "Repository successfully removed." + msgstr "軟體庫成功移除。" + +-#: plugins/copr.py:284 plugins/copr.py:693 ++#: plugins/copr.py:296 plugins/copr.py:697 + msgid "Unknown subcommand {}." + msgstr "{} 子命令未知。" + +-#: plugins/copr.py:341 ++#: plugins/copr.py:353 + msgid "" +-"* These coprs have repo file with an old format that contains no information" +-" about Copr hub - the default one was assumed. Re-enable the project to fix " ++"* These coprs have repo file with an old format that contains no information " ++"about Copr hub - the default one was assumed. Re-enable the project to fix " + "this." +-msgstr "* 這些 Copr 包含可能沒有 Copr hub 資訊的舊格式 repo 檔案 — 已假設為預設 hub。請重新啟用專案以修正。" ++msgstr "" ++"* 這些 Copr 包含可能沒有 Copr hub 資訊的舊格式 repo 檔案 — 已假設為預設 hub。" ++"請重新啟用專案以修正。" + +-#: plugins/copr.py:353 ++#: plugins/copr.py:366 + msgid "Can't parse repositories for username '{}'." + msgstr "無法解析「{}」使用者名稱的軟體庫。" + +-#: plugins/copr.py:356 ++#: plugins/copr.py:369 + msgid "List of {} coprs" + msgstr "{} Copr 清單" + +-#: plugins/copr.py:364 ++#: plugins/copr.py:374 + msgid "No description given" + msgstr "沒有提供描述" + +-#: plugins/copr.py:376 ++#: plugins/copr.py:386 + msgid "Can't parse search for '{}'." + msgstr "無法解析「{}」搜尋。" + +-#: plugins/copr.py:379 ++#: plugins/copr.py:389 + msgid "Matched: {}" + msgstr "符合項目:{}" + +-#: plugins/copr.py:387 ++#: plugins/copr.py:394 + msgid "No description given." + msgstr "沒有提供描述。" + +-#: plugins/copr.py:410 ++#: plugins/copr.py:416 + msgid "Safe and good answer. Exiting." + msgstr "安全且更棒的回應。結束。" + +-#: plugins/copr.py:417 ++#: plugins/copr.py:423 + msgid "This command has to be run under the root user." + msgstr "此命令必須在 root 使用者下執行" + +-#: plugins/copr.py:481 ++#: plugins/copr.py:485 + msgid "" + "This repository does not have any builds yet so you cannot enable it now." + msgstr "這個軟體庫尚無任何組建,所以您尚無法啟用。" + +-#: plugins/copr.py:484 ++#: plugins/copr.py:488 + msgid "Such repository does not exist." + msgstr "不存在此軟體庫。" + +-#: plugins/copr.py:528 ++#: plugins/copr.py:532 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -417,44 +434,44 @@ msgid "" + "These repositories have been enabled automatically." + msgstr "" + +-#: plugins/copr.py:549 ++#: plugins/copr.py:553 + msgid "Do you want to keep them enabled?" + msgstr "是否保持啟用?" + +-#: plugins/copr.py:582 ++#: plugins/copr.py:586 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" + msgstr "無法移除 Copr 軟體庫 {0}/{1}/{2}" + +-#: plugins/copr.py:593 ++#: plugins/copr.py:597 + msgid "Failed to disable copr repo {}/{}" + msgstr "無法停用 Copr 軟體庫 {}/{}" + +-#: plugins/copr.py:611 plugins/copr.py:648 ++#: plugins/copr.py:615 plugins/copr.py:652 + msgid "Unknown response from server." + msgstr "未知的伺服器回應。" + +-#: plugins/copr.py:633 ++#: plugins/copr.py:637 + msgid "Interact with Playground repository." + msgstr "與 Playground 軟體庫互動。" + +-#: plugins/copr.py:639 ++#: plugins/copr.py:643 + msgid "Enabling a Playground repository." + msgstr "啟用 Playground 軟體庫。" + +-#: plugins/copr.py:640 ++#: plugins/copr.py:644 + msgid "Do you want to continue?" + msgstr "是否繼續?" + +-#: plugins/copr.py:683 ++#: plugins/copr.py:687 + msgid "Playground repositories successfully enabled." + msgstr "Playground 軟體庫成功啟用。" + +-#: plugins/copr.py:686 ++#: plugins/copr.py:690 + msgid "Playground repositories successfully disabled." + msgstr "Playground 軟體庫成功停用。" + +-#: plugins/copr.py:690 ++#: plugins/copr.py:694 + msgid "Playground repositories successfully updated." + msgstr "Playground 軟體庫成功更新。" + +@@ -501,7 +518,9 @@ msgstr "限縮至指定類型" + msgid "" + "Allow removing of install-only packages. Using this option may result in an " + "attempt to remove the running kernel." +-msgstr "允許移除僅安裝 (install-only) 軟體包。啟用這個選項可能會導致執行中內核被移除。" ++msgstr "" ++"允許移除僅安裝 (install-only) 軟體包。啟用這個選項可能會導致執行中內核被移" ++"除。" + + #: plugins/debug.py:202 + msgid "name of dump file" +@@ -573,7 +592,7 @@ msgstr "改下載 -debugsource 軟體包" + msgid "limit the query to packages of given architectures." + msgstr "將查詢限縮至指定架構的軟體包。" + +-#: plugins/download.py:62 ++#: plugins/download.py:62 plugins/modulesync.py:51 + msgid "resolve and download needed dependencies" + msgstr "解析並下載需要的依賴關係" + +@@ -592,7 +611,7 @@ msgstr "輸出可以下載 RPM 的 URL 清單而不下載" + msgid "when running with --url, limit to specific protocols" + msgstr "使用 --url 執行時,限縮至指定的通訊協定" + +-#: plugins/download.py:121 plugins/reposync.py:293 ++#: plugins/download.py:121 plugins/reposync.py:314 + #, python-format + msgid "Failed to get mirror for package: %s" + msgstr "無法取得軟體庫的鏡像站:%s" +@@ -615,6 +634,134 @@ msgstr "未指定 %s 的來源 RPM" + msgid "No package %s available." + msgstr "沒有 %s 軟體包可用。" + ++#: plugins/groups_manager.py:49 ++msgid "Invalid group id" ++msgstr "" ++ ++#: plugins/groups_manager.py:58 ++msgid "Invalid translated data, should be in form 'lang:text'" ++msgstr "" ++ ++#: plugins/groups_manager.py:61 ++msgid "Invalid/empty language for translated data" ++msgstr "" ++ ++#: plugins/groups_manager.py:71 ++msgid "Can't generate group id from '{}'. Please specify group id using --id." ++msgstr "" ++ ++#: plugins/groups_manager.py:79 ++msgid "create and edit groups metadata file" ++msgstr "" ++ ++#: plugins/groups_manager.py:90 ++msgid "load groups metadata from file" ++msgstr "" ++ ++#: plugins/groups_manager.py:93 ++msgid "save groups metadata to file" ++msgstr "" ++ ++#: plugins/groups_manager.py:95 ++msgid "load and save groups metadata to file" ++msgstr "" ++ ++#: plugins/groups_manager.py:97 ++#, fuzzy ++#| msgid "print variable values to stdout" ++msgid "print the result metadata to stdout" ++msgstr "輸出變數值至標準輸出" ++ ++#: plugins/groups_manager.py:100 ++msgid "group id" ++msgstr "" ++ ++#: plugins/groups_manager.py:101 ++msgid "group name" ++msgstr "" ++ ++#: plugins/groups_manager.py:103 ++#, fuzzy ++#| msgid "No description given" ++msgid "group description" ++msgstr "沒有提供描述" ++ ++#: plugins/groups_manager.py:105 ++msgid "group display order" ++msgstr "" ++ ++#: plugins/groups_manager.py:108 ++msgid "translated name for the group" ++msgstr "" ++ ++#: plugins/groups_manager.py:111 ++#, fuzzy ++#| msgid "Failed to get mirror for the group file." ++msgid "translated description for the group" ++msgstr "無法取得群組檔案的鏡像站。" ++ ++#: plugins/groups_manager.py:115 ++msgid "make the group user visible (default)" ++msgstr "" ++ ++#: plugins/groups_manager.py:118 ++msgid "make the group user invisible" ++msgstr "" ++ ++#: plugins/groups_manager.py:123 ++msgid "add packages to the mandatory section" ++msgstr "" ++ ++#: plugins/groups_manager.py:125 ++msgid "add packages to the optional section" ++msgstr "" ++ ++#: plugins/groups_manager.py:127 ++msgid "remove packages from the group instead of adding them" ++msgstr "" ++ ++#: plugins/groups_manager.py:129 ++#, fuzzy ++#| msgid "Display a list of unresolved dependencies for repositories" ++msgid "include also direct dependencies for packages" ++msgstr "顯示軟體庫中未回應的依賴關係列表" ++ ++#: plugins/groups_manager.py:132 ++msgid "package specification" ++msgstr "" ++ ++#: plugins/groups_manager.py:156 ++msgid "Can't edit group without specifying it (use --id or --name)" ++msgstr "" ++ ++#: plugins/groups_manager.py:190 ++#, fuzzy ++#| msgid "Can't write file '{}'" ++msgid "Can't load file \"{}\": {}" ++msgstr "無法寫入「{}」檔案" ++ ++#: plugins/groups_manager.py:206 ++#, fuzzy ++#| msgid "Can't write file '{}'" ++msgid "Can't save file \"{}\": {}" ++msgstr "無法寫入「{}」檔案" ++ ++#: plugins/groups_manager.py:261 ++#, fuzzy ++#| msgid "No match for argument: %s" ++msgid "No match for argument: {}" ++msgstr "引數不符:%s" ++ ++#: plugins/groups_manager.py:298 ++msgid "Can't remove packages from non-existent group" ++msgstr "" ++ ++#: plugins/groups_manager.py:307 ++msgid "" ++"Group id '{}' generated from '{}' is duplicit. Please specify group id using " ++"--id." ++msgstr "" ++ + #: plugins/leaves.py:32 + msgid "List installed packages not required by any other package" + msgstr "列出其他軟體包已經不需要的安裝軟體包" +@@ -647,43 +794,112 @@ msgstr "遷移 yum 的歷史記錄、群組與 yumdb 資料至 dnf" + msgid "Migrating history data..." + msgstr "正在遷移歷史資料…" + +-#: plugins/needs_restarting.py:65 ++#: plugins/modulesync.py:37 ++msgid "" ++"Download packages from modules and/or create a repository with modular data" ++msgstr "" ++ ++#: plugins/modulesync.py:44 ++msgid "MODULE" ++msgstr "" ++ ++#: plugins/modulesync.py:45 ++#, fuzzy ++#| msgid "packages to download" ++msgid "modules to download" ++msgstr "要下載的軟體包" ++ ++#: plugins/modulesync.py:47 ++#, fuzzy ++#| msgid "operate on source packages" ++msgid "enable repositories with source packages" ++msgstr "在來源軟體包上操作" ++ ++#: plugins/modulesync.py:49 ++msgid "enable repositories with debug-info and debug-source packages" ++msgstr "" ++ ++#: plugins/modulesync.py:53 ++#, fuzzy ++#| msgid "download all packages from remote repo" ++msgid "download only packages from newest modules" ++msgstr "從遠端軟體庫下載所有軟體包" ++ ++#: plugins/modulesync.py:85 ++#, fuzzy ++#| msgid "No match for argument: %s" ++msgid "Unable to find a match for argument: '{}'" ++msgid_plural "Unable to find a match for arguments: '{}'" ++msgstr[0] "引數不符:%s" ++ ++#: plugins/modulesync.py:107 ++msgid "" ++"Creation of repository failed with return code {}. All downloaded content " ++"was kept on the system" ++msgstr "" ++ ++#: plugins/modulesync.py:144 ++#, python-brace-format ++msgid "No match for artifact '{0}' from module '{1}'" ++msgstr "" ++ ++#: plugins/modulesync.py:162 ++#, python-brace-format ++msgid "No match for package name '{0}' in profile {1} from module {2}" ++msgstr "" ++ ++#: plugins/modulesync.py:166 ++#, fuzzy ++#| msgid "No match for argument: %s" ++msgid "No mach for argument '{}'" ++msgstr "引數不符:%s" ++ ++#. TODO(jmracek) Shell we end with an error or with RC 1? ++#: plugins/modulesync.py:198 ++msgid "Unable to satisfy require {}" ++msgstr "" ++ ++#: plugins/needs_restarting.py:66 + #, fuzzy, python-brace-format + msgid "" + "No installed package found for package name \"{pkg}\" specified in needs-" + "restarting file \"{file}\"." + msgstr "未安裝 \"{file}\" 需要重新啟動檔案中指定的 \"{pkg}\" 軟體包。" + +-#: plugins/needs_restarting.py:199 ++#: plugins/needs_restarting.py:220 + msgid "determine updated binaries that need restarting" + msgstr "決定需要重新啟動的已更新二進位檔" + +-#: plugins/needs_restarting.py:204 ++#: plugins/needs_restarting.py:225 + msgid "only consider this user's processes" + msgstr "只考慮此位使用者的處理程序" + +-#: plugins/needs_restarting.py:206 ++#: plugins/needs_restarting.py:227 + msgid "" + "only report whether a reboot is required (exit code 1) or not (exit code 0)" + msgstr "只回報是(錯誤碼 1)否(錯誤碼 0)需要重新啟動" + + #: plugins/needs_restarting.py:230 ++msgid "only report affected systemd services" ++msgstr "" ++ ++#: plugins/needs_restarting.py:253 + msgid "Core libraries or services have been updated since boot-up:" + msgstr "開機後更新過的核心函式庫或服務:" + +-#: plugins/needs_restarting.py:235 ++#: plugins/needs_restarting.py:258 + msgid "Reboot is required to fully utilize these updates." + msgstr "需要重新啟動,才可以完全套用這些更新。" + +-#: plugins/needs_restarting.py:236 ++#: plugins/needs_restarting.py:259 + msgid "More information:" + msgstr "更多資訊:" + +-#: plugins/needs_restarting.py:240 ++#: plugins/needs_restarting.py:263 + msgid "No core libraries or services have been updated since boot-up." + msgstr "開機後沒有更新過的核心函式庫或服務。" + +-#: plugins/needs_restarting.py:242 ++#: plugins/needs_restarting.py:265 + msgid "Reboot should not be necessary." + msgstr "應不需要重新啟動。" + +@@ -698,13 +914,13 @@ msgstr "動作列「%s」格式錯誤:%s" + msgid "Bad Transaction State: %s" + msgstr "無效的處理事項狀態:%s" + +-#: plugins/post-transaction-actions.py:153 +-#: plugins/post-transaction-actions.py:155 ++#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:159 + #, python-format + msgid "post-transaction-actions: %s" + msgstr "post-transaction-actions:%s" + +-#: plugins/post-transaction-actions.py:157 ++#: plugins/post-transaction-actions.py:161 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" + msgstr "post-transaction-actions:「%s」命令無效:%s" +@@ -757,8 +973,7 @@ msgstr "輸出跟變更大小有關的額外資料。" + + #: plugins/repodiff.py:69 + msgid "" +-"Compare packages also by arch. By default packages are compared just by " +-"name." ++"Compare packages also by arch. By default packages are compared just by name." + msgstr "也依架構比較軟體包。預設情況下,軟體包只會依名稱比較。" + + #: plugins/repodiff.py:72 +@@ -885,112 +1100,126 @@ msgstr "管理 rpm 軟體包目錄" + msgid "Pass either --old or --new, not both!" + msgstr "只能傳入 --old 或 --new 任一,而非兩者!" + +-#: plugins/repomanage.py:71 ++#: plugins/repomanage.py:89 + msgid "No files to process" + msgstr "沒有要處理的檔案" + +-#: plugins/repomanage.py:93 ++#: plugins/repomanage.py:96 + msgid "Could not open {}" + msgstr "無法開啟 {}" + +-#: plugins/repomanage.py:177 ++#: plugins/repomanage.py:180 + msgid "Print the older packages" + msgstr "顯示較舊的軟體包" + +-#: plugins/repomanage.py:179 ++#: plugins/repomanage.py:182 + msgid "Print the newest packages" + msgstr "顯示較新的軟體包" + +-#: plugins/repomanage.py:181 ++#: plugins/repomanage.py:184 + msgid "Space separated output, not newline" + msgstr "以空白而非換行分割輸出" + +-#: plugins/repomanage.py:183 ++#: plugins/repomanage.py:186 + msgid "Newest N packages to keep - defaults to 1" + msgstr "保留最新 N 個軟體包 — 預設值為 1" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:189 + msgid "Path to directory" + msgstr "目錄路徑" + +-#: plugins/reposync.py:54 ++#: plugins/reposync.py:55 + msgid "download all packages from remote repo" + msgstr "從遠端軟體庫下載所有軟體包" + +-#: plugins/reposync.py:63 ++#: plugins/reposync.py:64 + msgid "download only packages for this ARCH" + msgstr "只下載此 ARCH 的軟體包" + +-#: plugins/reposync.py:65 ++#: plugins/reposync.py:66 + msgid "delete local packages no longer present in repository" + msgstr "刪除已不在軟體庫提供的本機軟體包" + +-#: plugins/reposync.py:67 +-msgid "also download and uncompress comps.xml" +-msgstr "亦下載並解壓縮 comps.xml" +- +-#: plugins/reposync.py:69 ++#: plugins/reposync.py:68 + msgid "download all the metadata." + msgstr "下載所有中介資料。" + +-#: plugins/reposync.py:71 +-msgid "download only newest packages per-repo" +-msgstr "只下載每個軟體庫最新的軟體包" ++#: plugins/reposync.py:70 ++msgid "Remove packages that fail GPG signature checking after downloading" ++msgstr "" + + #: plugins/reposync.py:73 +-msgid "where to store downloaded repositories" +-msgstr "儲存下載軟體庫的位置" ++msgid "also download and uncompress comps.xml" ++msgstr "亦下載並解壓縮 comps.xml" + + #: plugins/reposync.py:75 +-msgid "Don't add the reponame to the download path." +-msgstr "不要將軟體庫名稱加進下載路徑中。" +- +-#: plugins/reposync.py:77 + msgid "" +-"where to store downloaded repository metadata. Defaults to the value of " +-"--download-path." ++"where to store downloaded repository metadata. Defaults to the value of --" ++"download-path." + msgstr "儲存下載軟體庫之中介資料的位置。預設值為 --download-path 的值。" + ++#: plugins/reposync.py:78 ++msgid "download only newest packages per-repo" ++msgstr "只下載每個軟體庫最新的軟體包" ++ + #: plugins/reposync.py:80 +-msgid "operate on source packages" +-msgstr "在來源軟體包上操作" ++msgid "Don't add the reponame to the download path." ++msgstr "不要將軟體庫名稱加進下載路徑中。" + + #: plugins/reposync.py:82 ++msgid "where to store downloaded repositories" ++msgstr "儲存下載軟體庫的位置" ++ ++#: plugins/reposync.py:84 + msgid "try to set local timestamps of local files by the one on the server" + msgstr "嘗試將本機檔案的本地時間戳設定與伺服器一致" + +-#: plugins/reposync.py:85 ++#: plugins/reposync.py:87 ++#, fuzzy ++#| msgid "operate on source packages" ++msgid "download only source packages" ++msgstr "在來源軟體包上操作" ++ ++#: plugins/reposync.py:89 + msgid "Just list urls of what would be downloaded, don't download" + msgstr "只列出會下載的 URL 而不下載" + +-#: plugins/reposync.py:109 ++#: plugins/reposync.py:113 + msgid "Can't use --norepopath with multiple repositories" + msgstr "無法在多個軟體庫使用 --norepopath" + +-#: plugins/reposync.py:127 ++#: plugins/reposync.py:132 + #, python-format + msgid "Failed to get mirror for metadata: %s" + msgstr "無法取得中介資料的鏡像站:%s" + +-#: plugins/reposync.py:144 ++#: plugins/reposync.py:149 + msgid "Failed to get mirror for the group file." + msgstr "無法取得群組檔案的鏡像站。" + ++#: plugins/reposync.py:168 ++msgid "Removing {}: {}" ++msgstr "" ++ + #: plugins/reposync.py:175 ++msgid "GPG signature check failed." ++msgstr "" ++ ++#: plugins/reposync.py:196 + msgid "Download target '{}' is outside of download path '{}'." + msgstr "下載目標「{}」在下載位置「{}」之外。" + +-#: plugins/reposync.py:190 ++#: plugins/reposync.py:211 + #, python-format + msgid "[DELETED] %s" + msgstr "[已刪除] %s" + +-#: plugins/reposync.py:192 ++#: plugins/reposync.py:213 + #, python-format + msgid "failed to delete file %s" + msgstr "無法刪除 %s 檔案" + +-#: plugins/reposync.py:201 ++#: plugins/reposync.py:222 + #, python-format + msgid "comps.xml for repository %s saved" + msgstr "已儲存 %s 軟體庫的 comps.xml" +@@ -999,67 +1228,72 @@ msgstr "已儲存 %s 軟體庫的 comps.xml" + msgid "New leaves:" + msgstr "新保留:" + +-#: plugins/versionlock.py:32 ++#: plugins/versionlock.py:33 + #, python-format + msgid "Unable to read version lock configuration: %s" + msgstr "無法讀取版本鎖設定:%s" + +-#: plugins/versionlock.py:33 ++#: plugins/versionlock.py:34 + msgid "Locklist not set" + msgstr "未設定鎖定列表" + +-#: plugins/versionlock.py:34 ++#: plugins/versionlock.py:35 + msgid "Adding versionlock on:" + msgstr "加入版本鎖於:" + +-#: plugins/versionlock.py:35 ++#: plugins/versionlock.py:36 + msgid "Adding exclude on:" + msgstr "加入排除於:" + +-#: plugins/versionlock.py:36 ++#: plugins/versionlock.py:37 + msgid "Package already locked in equivalent form:" + msgstr "版本已鎖定在下述等同格式:" + +-#: plugins/versionlock.py:37 ++#: plugins/versionlock.py:38 + msgid "Package {} is already locked" + msgstr "已鎖定 {} 軟體包" + +-#: plugins/versionlock.py:38 ++#: plugins/versionlock.py:39 + msgid "Package {} is already excluded" + msgstr "已排除 {} 軟體包" + +-#: plugins/versionlock.py:39 ++#: plugins/versionlock.py:40 + msgid "Deleting versionlock for:" + msgstr "刪除下述的版本鎖:" + +-#: plugins/versionlock.py:40 ++#: plugins/versionlock.py:41 + msgid "No package found for:" + msgstr "找不到下述的軟體包:" + +-#: plugins/versionlock.py:41 ++#: plugins/versionlock.py:42 + msgid "Excludes from versionlock plugin were not applied" + msgstr "不會套用到自 versionlock 插件排除的軟體包" + +-#: plugins/versionlock.py:42 ++#: plugins/versionlock.py:43 + msgid "Versionlock plugin: number of lock rules from file \"{}\" applied: {}" + msgstr "Versionlock 插件:已從「{}」檔案套用大量的鎖定規則:{}" + +-#: plugins/versionlock.py:43 +-msgid "Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" ++#: plugins/versionlock.py:44 ++msgid "" ++"Versionlock plugin: number of exclude rules from file \"{}\" applied: {}" + msgstr "Versionlock 插件:已從「{}」檔案套用大量的排除規則:{}" + +-#: plugins/versionlock.py:44 ++#: plugins/versionlock.py:45 + msgid "Versionlock plugin: could not parse pattern:" + msgstr "Versionlock 插件:無法解析模式:" + +-#: plugins/versionlock.py:130 ++#: plugins/versionlock.py:134 + msgid "control package version locks" + msgstr "控制軟體包的版本鎖" + +-#: plugins/versionlock.py:136 ++#: plugins/versionlock.py:140 + msgid "Use package specifications as they are, do not try to parse them" + msgstr "使用其原本的軟體包規範,不要嘗試解析" + ++#: plugins/versionlock.py:160 ++msgid "Subcommand '{}' is deprecated. Use 'exclude' subcommand instead." ++msgstr "" ++ + #~ msgid "" + #~ "\n" + #~ "These repositories have been enabled automatically.\n" +-- +2.36.1 + diff --git a/SOURCES/0013-repomanage-Use-modules-only-from-repo-they-are-handl.patch b/SOURCES/0013-repomanage-Use-modules-only-from-repo-they-are-handl.patch new file mode 100644 index 0000000..1ddd4df --- /dev/null +++ b/SOURCES/0013-repomanage-Use-modules-only-from-repo-they-are-handl.patch @@ -0,0 +1,48 @@ +From e80f79b2f5e17a20065617c0b614b272dd53c57c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= +Date: Thu, 26 May 2022 07:21:45 +0200 +Subject: [PATCH] repomanage: Use modules only from repo they are handling + (RhBug:2072441) + += changelog = +msg: [repomanage] Modules are used only when they belong to target repo +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2072441 +--- + plugins/repomanage.py | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/plugins/repomanage.py b/plugins/repomanage.py +index 989bd78..67a6fc7 100644 +--- a/plugins/repomanage.py ++++ b/plugins/repomanage.py +@@ -66,7 +66,8 @@ class RepoManageCommand(dnf.cli.Command): + keepnum = int(self.opts.keep) # the number of items to keep + + try: +- repo_conf = self.base.repos.add_new_repo("repomanage_repo", self.base.conf, baseurl=[self.opts.path]) ++ REPOMANAGE_REPOID = "repomanage_repo" ++ repo_conf = self.base.repos.add_new_repo(REPOMANAGE_REPOID, self.base.conf, baseurl=[self.opts.path]) + # Always expire the repo, otherwise repomanage could use cached metadata and give identical results + # for multiple runs even if the actual repo changed in the meantime + repo_conf._repo.expire() +@@ -78,9 +79,13 @@ class RepoManageCommand(dnf.cli.Command): + module_packages = self.base._moduleContainer.getModulePackages() + + for module_package in module_packages: +- all_modular_artifacts.update(module_package.getArtifacts()) +- module_dict.setdefault(module_package.getNameStream(), {}).setdefault( +- module_package.getVersionNum(), []).append(module_package) ++ # Even though we load only REPOMANAGE_REPOID other modules can be loaded from system ++ # failsafe data automatically, we don't want them affecting repomanage results so ONLY ++ # use modules from REPOMANAGE_REPOID. ++ if module_package.getRepoID() == REPOMANAGE_REPOID: ++ all_modular_artifacts.update(module_package.getArtifacts()) ++ module_dict.setdefault(module_package.getNameStream(), {}).setdefault( ++ module_package.getVersionNum(), []).append(module_package) + + except dnf.exceptions.RepoError: + rpm_list = [] +-- +2.36.1 + diff --git a/SOURCES/0014-feat-repomanage-Add-new-option-oldonly.patch b/SOURCES/0014-feat-repomanage-Add-new-option-oldonly.patch new file mode 100644 index 0000000..66288c5 --- /dev/null +++ b/SOURCES/0014-feat-repomanage-Add-new-option-oldonly.patch @@ -0,0 +1,117 @@ +From eb1d6edf55c167d575ce3d16bd6349e382d05600 Mon Sep 17 00:00:00 2001 +From: Masahiro Matsuya +Date: Wed, 13 Apr 2022 18:42:03 +0900 +Subject: [PATCH] feat(repomanage): Add new option --oldonly + += changelog = +msg: repomanage: Add new option --oldonly +type: enhancement +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2034736 +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2058676 +--- + doc/repomanage.rst | 3 +++ + plugins/repomanage.py | 46 ++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 46 insertions(+), 3 deletions(-) + +diff --git a/doc/repomanage.rst b/doc/repomanage.rst +index e3171ef..3c01289 100644 +--- a/doc/repomanage.rst ++++ b/doc/repomanage.rst +@@ -47,6 +47,9 @@ The following options set what packages are displayed. These options are mutuall + ``--old`` + Show older packages (for a package or a stream show all versions except the newest one). + ++``--oldonly`` ++ Show older packages (same as --old, but exclude the newest packages even when it's included in the older stream versions). ++ + ``--new`` + Show newest packages. + +diff --git a/plugins/repomanage.py b/plugins/repomanage.py +index 67a6fc7..d23497a 100644 +--- a/plugins/repomanage.py ++++ b/plugins/repomanage.py +@@ -57,6 +57,12 @@ class RepoManageCommand(dnf.cli.Command): + def run(self): + if self.opts.new and self.opts.old: + raise dnf.exceptions.Error(_("Pass either --old or --new, not both!")) ++ if self.opts.new and self.opts.oldonly: ++ raise dnf.exceptions.Error(_("Pass either --oldonly or --new, not both!")) ++ if self.opts.old and self.opts.oldonly: ++ raise dnf.exceptions.Error(_("Pass either --old or --oldonly, not both!")) ++ if not self.opts.old and not self.opts.oldonly: ++ self.opts.new = True + + verfile = {} + pkgdict = {} +@@ -123,8 +129,7 @@ class RepoManageCommand(dnf.cli.Command): + # modular packages + keepnum_latest_stream_artifacts = set() + +- # if new +- if not self.opts.old: ++ if self.opts.new: + # regular packages + for (n, a) in pkgdict.keys(): + evrlist = pkgdict[(n, a)] +@@ -146,7 +151,6 @@ class RepoManageCommand(dnf.cli.Command): + for stream in streams_by_version[i]: + keepnum_latest_stream_artifacts.update(set(stream.getArtifacts())) + +- + if self.opts.old: + # regular packages + for (n, a) in pkgdict.keys(): +@@ -169,6 +173,40 @@ class RepoManageCommand(dnf.cli.Command): + for stream in streams_by_version[i]: + keepnum_latest_stream_artifacts.update(set(stream.getArtifacts())) + ++ if self.opts.oldonly: ++ # regular packages ++ for (n, a) in pkgdict.keys(): ++ evrlist = pkgdict[(n, a)] ++ ++ oldevrs = evrlist[:-keepnum] ++ ++ for package in oldevrs: ++ nevra = self._package_to_nevra(package) ++ for fpkg in verfile[nevra]: ++ outputpackages.append(fpkg) ++ ++ # modular packages ++ keepnum_newer_stream_artifacts = set() ++ ++ for streams_by_version in module_dict.values(): ++ sorted_stream_versions = sorted(streams_by_version.keys()) ++ ++ new_sorted_stream_versions = sorted_stream_versions[-keepnum:] ++ ++ for i in new_sorted_stream_versions: ++ for stream in streams_by_version[i]: ++ keepnum_newer_stream_artifacts.update(set(stream.getArtifacts())) ++ ++ for streams_by_version in module_dict.values(): ++ sorted_stream_versions = sorted(streams_by_version.keys()) ++ ++ old_sorted_stream_versions = sorted_stream_versions[:-keepnum] ++ ++ for i in old_sorted_stream_versions: ++ for stream in streams_by_version[i]: ++ for artifact in stream.getArtifacts(): ++ if artifact not in keepnum_newer_stream_artifacts: ++ keepnum_latest_stream_artifacts.add(artifact) + + modular_packages = [self._package_to_path(x) for x in query.filter(pkg__eq=query.filter(nevra_strict=keepnum_latest_stream_artifacts)).available()] + outputpackages = outputpackages + modular_packages +@@ -183,6 +221,8 @@ class RepoManageCommand(dnf.cli.Command): + def set_argparser(parser): + parser.add_argument("-o", "--old", action="store_true", + help=_("Print the older packages")) ++ parser.add_argument("-O", "--oldonly", action="store_true", ++ help=_("Print the older packages. Exclude the newest packages.")) + parser.add_argument("-n", "--new", action="store_true", + help=_("Print the newest packages")) + parser.add_argument("-s", "--space", action="store_true", +-- +2.36.1 + diff --git a/SOURCES/0015-Skip-all-non-rpm-tsi-for-transaction_action-plugins-.patch b/SOURCES/0015-Skip-all-non-rpm-tsi-for-transaction_action-plugins-.patch new file mode 100644 index 0000000..0ebf2f6 --- /dev/null +++ b/SOURCES/0015-Skip-all-non-rpm-tsi-for-transaction_action-plugins-.patch @@ -0,0 +1,28 @@ +From b4e0cafe70680db24ab3611e0fd4dd95c8311ccc Mon Sep 17 00:00:00 2001 +From: Jaroslav Mracek +Date: Tue, 26 Apr 2022 11:23:41 +0200 +Subject: [PATCH] Skip all non rpm tsi for transaction_action plugins + (rhbug:2023652) + +It prevent traceback in output when reason change is in transaction +--- + plugins/post-transaction-actions.py | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/plugins/post-transaction-actions.py b/plugins/post-transaction-actions.py +index 05a7841..1520c26 100644 +--- a/plugins/post-transaction-actions.py ++++ b/plugins/post-transaction-actions.py +@@ -115,6 +115,9 @@ class PostTransactionActions(dnf.Plugin): + in_ts_items.append(ts_item) + elif ts_item.action in dnf.transaction.BACKWARD_ACTIONS: + out_ts_items.append(ts_item) ++ else: ++ # The action is not rpm change. It can be a reason change, therefore we can skip that item ++ continue + all_ts_items.append(ts_item) + + commands_to_run = [] +-- +2.36.1 + diff --git a/SOURCES/0016-Fix-dnf-copr-enable-on-Fedora-35.patch b/SOURCES/0016-Fix-dnf-copr-enable-on-Fedora-35.patch new file mode 100644 index 0000000..3fad14d --- /dev/null +++ b/SOURCES/0016-Fix-dnf-copr-enable-on-Fedora-35.patch @@ -0,0 +1,28 @@ +From 76d7c9e2d2fa052cc6d9fab08af51c603d7e20e5 Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Fri, 16 Jul 2021 12:52:03 +0200 +Subject: [PATCH] Fix 'dnf copr enable' on Fedora 35 + +The output from linux_distribution() changed so it returns: +>>> distro.linux_distribution() +('Fedora Linux', '35', '') +--- + plugins/copr.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/plugins/copr.py b/plugins/copr.py +index 7fc6c6f..235989b 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -430,7 +430,7 @@ Bugzilla. In case of problems, contact the owner of this repository. + dist = linux_distribution() + # Get distribution architecture + distarch = self.base.conf.substitutions['basearch'] +- if "Fedora" in dist: ++ if any([name in dist for name in ["Fedora", "Fedora Linux"]]): + if "Rawhide" in dist: + chroot = ("fedora-rawhide-" + distarch) + # workaround for enabling repos in Rawhide when VERSION in os-release +-- +2.36.1 + diff --git a/SOURCES/0017-Disable-dnf-playground-command.patch b/SOURCES/0017-Disable-dnf-playground-command.patch new file mode 100644 index 0000000..8016028 --- /dev/null +++ b/SOURCES/0017-Disable-dnf-playground-command.patch @@ -0,0 +1,37 @@ +From 517f0093218e3c23097d7e7e3f3d65930059ef82 Mon Sep 17 00:00:00 2001 +From: Silvie Chlupova +Date: Thu, 12 Aug 2021 16:24:56 +0200 +Subject: [PATCH] Disable dnf playground command + += changelog = +msg: playground command doesn't work +type: bugfix +related: https://bugzilla.redhat.com/show_bug.cgi?id=1955907 +--- + plugins/copr.py | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/plugins/copr.py b/plugins/copr.py +index 235989b..e1e7018 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -122,6 +122,8 @@ class CoprCommand(dnf.cli.Command): + parser.add_argument('arg', nargs='*') + + def configure(self): ++ if self.cli.command.opts.command != "copr": ++ return + copr_hub = None + copr_plugin_config = ConfigParser() + config_files = [] +@@ -680,6 +682,7 @@ class PlaygroundCommand(CoprCommand): + choices=['enable', 'disable', 'upgrade']) + + def run(self): ++ raise dnf.exceptions.Error("Playground is temporarily unsupported") + subcommand = self.opts.subcommand[0] + chroot = self._guess_chroot() + if subcommand == "enable": +-- +2.36.1 + diff --git a/SOURCES/0018-Fix-baseurl-for-centos-stream-chroot.patch b/SOURCES/0018-Fix-baseurl-for-centos-stream-chroot.patch new file mode 100644 index 0000000..f9f84bc --- /dev/null +++ b/SOURCES/0018-Fix-baseurl-for-centos-stream-chroot.patch @@ -0,0 +1,29 @@ +From 7f9d6809f7cb9ac48f11ef02a4e7c0cadeef9594 Mon Sep 17 00:00:00 2001 +From: Silvie Chlupova +Date: Wed, 22 Sep 2021 22:35:21 +0200 +Subject: [PATCH] Fix baseurl for centos stream chroot + += changelog = +msg: dnf copr enable on CentOS Stream should enable centos stream chroot, not epel 8 +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1994154 +--- + plugins/copr.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/plugins/copr.py b/plugins/copr.py +index e1e7018..c216408 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -457,6 +457,8 @@ Bugzilla. In case of problems, contact the owner of this repository. + chroot = ("opensuse-tumbleweed-{}".format(distarch)) + else: + chroot = ("opensuse-leap-{0}-{1}".format(dist[1], distarch)) ++ elif "CentOS Stream" in dist: ++ chroot = ("centos-stream-{0}-{1}".format(dist[1], distarch)) + else: + chroot = ("epel-%s-x86_64" % dist[1].split(".", 1)[0]) + return chroot +-- +2.36.1 + diff --git a/SOURCES/0019-Silence-a-deprecation-warning-in-plugins-copr.py.patch b/SOURCES/0019-Silence-a-deprecation-warning-in-plugins-copr.py.patch new file mode 100644 index 0000000..09efd6c --- /dev/null +++ b/SOURCES/0019-Silence-a-deprecation-warning-in-plugins-copr.py.patch @@ -0,0 +1,42 @@ +From a07db6dcd669eecb27b7ddbf1b85cd842bdcc35b Mon Sep 17 00:00:00 2001 +From: Otto Urpelainen +Date: Wed, 6 Oct 2021 22:08:54 +0300 +Subject: [PATCH] Silence a deprecation warning in plugins/copr.py + +In version 1.6.0, the 'distro' package deprecated linux_distribution(). +This causes a deprecation warning to printed to stdout +every time the user calls the copr plugin. + +In order to avoid the printout +and to protect against possible removal in the future, +the function is reimplemented +using still supported functions from 'distro'. + += changelog = +msg: [copr] Avoid using deprecated function distro.linux_distribution() +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2011550 +--- + plugins/copr.py | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/plugins/copr.py b/plugins/copr.py +index c216408..9f597dd 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -38,7 +38,11 @@ import rpm + # If that fails, attempt to import the deprecated implementation + # from the platform module. + try: +- from distro import linux_distribution, os_release_attr ++ from distro import name, version, codename, os_release_attr ++ ++ # Re-implement distro.linux_distribution() to avoid a deprecation warning ++ def linux_distribution(): ++ return (name(), version(), codename()) + except ImportError: + def os_release_attr(_): + return "" +-- +2.36.1 + diff --git a/SOURCES/0020-Shorter-verification-that-the-project-exists.patch b/SOURCES/0020-Shorter-verification-that-the-project-exists.patch new file mode 100644 index 0000000..37ca545 --- /dev/null +++ b/SOURCES/0020-Shorter-verification-that-the-project-exists.patch @@ -0,0 +1,49 @@ +From bf230d570763acc6ccd4f4b3951f4b8325a8e4b8 Mon Sep 17 00:00:00 2001 +From: Silvie Chlupova +Date: Fri, 3 Sep 2021 15:45:43 +0200 +Subject: [PATCH] Shorter verification that the project exists + +--- + plugins/copr.py | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +diff --git a/plugins/copr.py b/plugins/copr.py +index 9f597dd..1539c0d 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -70,8 +70,10 @@ NO = set([_('no'), _('n'), '']) + + if PY3: + from configparser import ConfigParser, NoOptionError, NoSectionError ++ from urllib.request import urlopen, HTTPError + else: + from ConfigParser import ConfigParser, NoOptionError, NoSectionError ++ from urllib2 import urlopen, HTTPError + + @dnf.plugin.register_command + class CoprCommand(dnf.cli.Command): +@@ -478,17 +480,11 @@ Bugzilla. In case of problems, contact the owner of this repository. + if os.path.exists(repo_filename): + os.remove(repo_filename) + if '404' in str(e): +- if PY3: +- import urllib.request +- try: +- res = urllib.request.urlopen(self.copr_url + "/coprs/" + project_name) +- status_code = res.getcode() +- except urllib.error.HTTPError as e: +- status_code = e.getcode() +- else: +- import urllib +- res = urllib.urlopen(self.copr_url + "/coprs/" + project_name) ++ try: ++ res = urlopen(self.copr_url + "/coprs/" + project_name) + status_code = res.getcode() ++ except HTTPError as e: ++ status_code = e.getcode() + if str(status_code) != '404': + raise dnf.exceptions.Error(_("This repository does not have" + " any builds yet so you cannot enable it now.")) +-- +2.36.1 + diff --git a/SOURCES/0021-Better-error-message-for-dnf-copr-enable.patch b/SOURCES/0021-Better-error-message-for-dnf-copr-enable.patch new file mode 100644 index 0000000..43368d0 --- /dev/null +++ b/SOURCES/0021-Better-error-message-for-dnf-copr-enable.patch @@ -0,0 +1,114 @@ +From 1d097d0e4ecfef78aec5d760278b44d5f3192cdc Mon Sep 17 00:00:00 2001 +From: Silvie Chlupova +Date: Mon, 2 Aug 2021 15:04:17 +0200 +Subject: [PATCH] Better error message for dnf copr enable + += changelog = +msg: show better error message if the command dnf copr enable fails +type: enhancement +--- + plugins/copr.py | 63 +++++++++++++++++++++++++++++++------------------ + 1 file changed, 40 insertions(+), 23 deletions(-) + +diff --git a/plugins/copr.py b/plugins/copr.py +index 1539c0d..721c010 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -27,6 +27,8 @@ import re + import shutil + import stat + import sys ++import base64 ++import json + + from dnfpluginscore import _, logger + import dnf +@@ -70,10 +72,10 @@ NO = set([_('no'), _('n'), '']) + + if PY3: + from configparser import ConfigParser, NoOptionError, NoSectionError +- from urllib.request import urlopen, HTTPError ++ from urllib.request import urlopen, HTTPError, URLError + else: + from ConfigParser import ConfigParser, NoOptionError, NoSectionError +- from urllib2 import urlopen, HTTPError ++ from urllib2 import urlopen, HTTPError, URLError + + @dnf.plugin.register_command + class CoprCommand(dnf.cli.Command): +@@ -475,28 +477,40 @@ Bugzilla. In case of problems, contact the owner of this repository. + api_path = "/coprs/{0}/repo/{1}/dnf.repo?arch={2}".format(project_name, short_chroot, arch) + + try: +- f = self.base.urlopen(self.copr_url + api_path, mode='w+') +- except IOError as e: ++ response = urlopen(self.copr_url + api_path) + if os.path.exists(repo_filename): + os.remove(repo_filename) +- if '404' in str(e): +- try: +- res = urlopen(self.copr_url + "/coprs/" + project_name) +- status_code = res.getcode() +- except HTTPError as e: +- status_code = e.getcode() +- if str(status_code) != '404': +- raise dnf.exceptions.Error(_("This repository does not have" +- " any builds yet so you cannot enable it now.")) +- else: +- raise dnf.exceptions.Error(_("Such repository does not exist.")) +- raise +- +- for line in f: +- if re.match(r"\[copr:", line): +- repo_filename = os.path.join(self.base.conf.get_reposdir, +- "_" + line[1:-2] + ".repo") +- break ++ except HTTPError as e: ++ if e.code != 404: ++ error_msg = _("Request to {0} failed: {1} - {2}").format(self.copr_url + api_path, e.code, str(e)) ++ raise dnf.exceptions.Error(error_msg) ++ error_msg = _("It wasn't possible to enable this project.\n") ++ error_data = e.headers.get("Copr-Error-Data") ++ if error_data: ++ error_data_decoded = base64.b64decode(error_data).decode('utf-8') ++ error_data_decoded = json.loads(error_data_decoded) ++ error_msg += _("Repository '{0}' does not exist in project '{1}'.").format( ++ '-'.join(self.chroot_parts), project_name) ++ if error_data_decoded.get("available chroots"): ++ error_msg += _("\nAvailable repositories: ") + ', '.join( ++ "'{}'".format(x) for x in error_data_decoded["available chroots"]) ++ error_msg += _("\n\nIf you want to enable a non-default repository, use the following command:\n" ++ " 'dnf copr enable {0} '\n" ++ "But note that the installed repo file will likely need a manual " ++ "modification.").format(project_name) ++ raise dnf.exceptions.Error(error_msg) ++ else: ++ error_msg += _("Project {0} does not exist.").format(project_name) ++ raise dnf.exceptions.Error(error_msg) ++ except URLError as e: ++ error_msg = _("Failed to connect to {0}: {1}").format(self.copr_url + api_path, e.reason.strerror) ++ raise dnf.exceptions.Error(error_msg) ++ ++ # Try to read the first line, and detect the repo_filename from that (override the repo_filename value). ++ first_line = response.readline() ++ line = first_line.decode("utf-8") ++ if re.match(r"\[copr:", line): ++ repo_filename = os.path.join(self.base.conf.get_reposdir, "_" + line[1:-2] + ".repo") + + # if using default hub, remove possible old repofile + if self.copr_url == self.default_url: +@@ -507,7 +521,10 @@ Bugzilla. In case of problems, contact the owner of this repository. + if os.path.exists(old_repo_filename): + os.remove(old_repo_filename) + +- shutil.copy2(f.name, repo_filename) ++ with open(repo_filename, 'wb') as f: ++ f.write(first_line) ++ for line in response.readlines(): ++ f.write(line) + os.chmod(repo_filename, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) + + def _runtime_deps_warning(self, copr_username, copr_projectname): +-- +2.36.1 + diff --git a/SOURCES/0022-copr-allow-specifying-protocol-as-part-of-hub.patch b/SOURCES/0022-copr-allow-specifying-protocol-as-part-of-hub.patch new file mode 100644 index 0000000..802fe2d --- /dev/null +++ b/SOURCES/0022-copr-allow-specifying-protocol-as-part-of-hub.patch @@ -0,0 +1,33 @@ +From b2d019658ebb40606e1a9efcb2233a8e38834410 Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Thu, 7 Oct 2021 19:08:47 +0200 +Subject: [PATCH] copr: allow specifying protocol as part of --hub + +This way it doesn't try to connect to +https://http//url if --hub started with http://. +--- + plugins/copr.py | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/plugins/copr.py b/plugins/copr.py +index 721c010..297210b 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -198,8 +198,12 @@ class CoprCommand(dnf.cli.Command): + self.copr_hostname += ":" + port + + if not self.copr_url: +- self.copr_hostname = copr_hub +- self.copr_url = self.default_protocol + "://" + copr_hub ++ if '://' not in copr_hub: ++ self.copr_hostname = copr_hub ++ self.copr_url = self.default_protocol + "://" + copr_hub ++ else: ++ self.copr_hostname = copr_hub.split('://', 1)[1] ++ self.copr_url = copr_hub + + def _read_config_item(self, config, hub, section, default): + try: +-- +2.36.1 + diff --git a/SOURCES/0023-copr-Guess-EPEL-chroots-for-CentOS-Stream-RhBug-2058.patch b/SOURCES/0023-copr-Guess-EPEL-chroots-for-CentOS-Stream-RhBug-2058.patch new file mode 100644 index 0000000..55d370c --- /dev/null +++ b/SOURCES/0023-copr-Guess-EPEL-chroots-for-CentOS-Stream-RhBug-2058.patch @@ -0,0 +1,37 @@ +From 4b0001d0f13598369ec2e6a800af519e8c3a334c Mon Sep 17 00:00:00 2001 +From: Carl George +Date: Mon, 27 Jun 2022 23:12:05 -0500 +Subject: [PATCH] copr: Guess EPEL chroots for CentOS Stream (RhBug:2058471) + +Packages built in epel-9 chroots are almost always compatible with +CentOS Stream 9. Not having the copr plugin guess this chroot is +causing user friction. Users are creating epel-9 chroots expecting them +to work for both CentOS Stream 9 and RHEL 9. When they get reports +about `dnf copr enable` not working, they try to add a centos-stream-9 +chroot, only to discover the dependencies they need from EPEL are not +available. + +Instead of making the majority of CentOS Stream users include an +explicit chroot argument, let's reserve that workaround only for the +people that don't want their CentOS Stream systems picking the EPEL +chroot. +--- + plugins/copr.py | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/plugins/copr.py b/plugins/copr.py +index 297210b..16946b7 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -469,8 +469,6 @@ Bugzilla. In case of problems, contact the owner of this repository. + chroot = ("opensuse-tumbleweed-{}".format(distarch)) + else: + chroot = ("opensuse-leap-{0}-{1}".format(dist[1], distarch)) +- elif "CentOS Stream" in dist: +- chroot = ("centos-stream-{0}-{1}".format(dist[1], distarch)) + else: + chroot = ("epel-%s-x86_64" % dist[1].split(".", 1)[0]) + return chroot +-- +2.36.1 + diff --git a/SOURCES/0024-builddep-Warning-when-using-macros-with-source-rpms-.patch b/SOURCES/0024-builddep-Warning-when-using-macros-with-source-rpms-.patch new file mode 100644 index 0000000..49e925b --- /dev/null +++ b/SOURCES/0024-builddep-Warning-when-using-macros-with-source-rpms-.patch @@ -0,0 +1,45 @@ +From 0afd47edc60fb7fe5c72fa64bca413bdce82d900 Mon Sep 17 00:00:00 2001 +From: Jan Kolarik +Date: Thu, 11 Aug 2022 14:12:06 +0200 +Subject: [PATCH] builddep: Warning when using macros with source rpms + (RhBug:2077820) + += changelog = +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2077820 +--- + doc/builddep.rst | 2 +- + plugins/builddep.py | 4 ++++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/doc/builddep.rst b/doc/builddep.rst +index 6e9bde6..97eb823 100644 +--- a/doc/builddep.rst ++++ b/doc/builddep.rst +@@ -31,7 +31,7 @@ All general DNF options are accepted, see `Options` in :manpage:`dnf(8)` for det + Show this help. + + ``-D , --define `` +- Define the RPM macro named `macro` to the value `expr` when parsing spec files. ++ Define the RPM macro named `macro` to the value `expr` when parsing spec files. Does not apply for source rpm files. + + ``--spec`` + Treat arguments as .spec files. +diff --git a/plugins/builddep.py b/plugins/builddep.py +index e3da012..e7dac43 100644 +--- a/plugins/builddep.py ++++ b/plugins/builddep.py +@@ -204,6 +204,10 @@ class BuildDepCommand(dnf.cli.Command): + err = _("Not all dependencies satisfied") + raise dnf.exceptions.Error(err) + ++ if self.opts.define: ++ logger.warning(_("Warning: -D or --define arguments have no meaning " ++ "for source rpm packages.")) ++ + def _spec_deps(self, spec_fn): + try: + spec = rpm.spec(spec_fn) +-- +2.37.1 + diff --git a/SOURCES/0025-Move-system-upgrade-plugin-to-core-RhBug-2054235.patch b/SOURCES/0025-Move-system-upgrade-plugin-to-core-RhBug-2054235.patch new file mode 100644 index 0000000..82173ab --- /dev/null +++ b/SOURCES/0025-Move-system-upgrade-plugin-to-core-RhBug-2054235.patch @@ -0,0 +1,1711 @@ +From 54eba8059b07b31b2caa27b48269e74da959eaa6 Mon Sep 17 00:00:00 2001 +From: Jan Kolarik +Date: Thu, 22 Sep 2022 16:02:55 +0000 +Subject: [PATCH] Move system-upgrade plugin to core (RhBug:2054235) + += changelog = +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2054235 +--- + CMakeLists.txt | 15 + + dnf-plugins-core.spec | 38 +- + doc/CMakeLists.txt | 1 + + doc/conf.py | 1 + + doc/index.rst | 1 + + doc/system-upgrade.rst | 207 ++++++ + etc/CMakeLists.txt | 1 + + etc/systemd/CMakeLists.txt | 1 + + .../dnf-system-upgrade-cleanup.service | 11 + + etc/systemd/dnf-system-upgrade.service | 20 + + plugins/CMakeLists.txt | 1 + + plugins/system_upgrade.py | 699 ++++++++++++++++++ + tests/test_system_upgrade.py | 502 +++++++++++++ + 13 files changed, 1494 insertions(+), 4 deletions(-) + create mode 100644 doc/system-upgrade.rst + create mode 100644 etc/systemd/CMakeLists.txt + create mode 100644 etc/systemd/dnf-system-upgrade-cleanup.service + create mode 100644 etc/systemd/dnf-system-upgrade.service + create mode 100644 plugins/system_upgrade.py + create mode 100644 tests/test_system_upgrade.py + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f143905..bd5f35b 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -23,6 +23,21 @@ MESSAGE(STATUS "Python install dir is ${PYTHON_INSTALL_DIR}") + + SET (SYSCONFDIR /etc) + ++find_package (PkgConfig) ++ ++if (PKG_CONFIG_FOUND) ++ pkg_search_module (SYSTEMD systemd) ++ if (SYSTEMD_FOUND) ++ execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=systemdsystemunitdir systemd ++ OUTPUT_VARIABLE SYSTEMD_DIR ++ OUTPUT_STRIP_TRAILING_WHITESPACE) ++ endif () ++endif() ++ ++if (NOT SYSTEMD_DIR) ++ set (SYSTEMD_DIR /usr/lib/systemd/system) ++endif () ++ + ADD_SUBDIRECTORY (libexec) + ADD_SUBDIRECTORY (doc) + ADD_SUBDIRECTORY (etc) +diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec +index afdbcbb..0e1c9e3 100644 +--- a/dnf-plugins-core.spec ++++ b/dnf-plugins-core.spec +@@ -64,6 +64,9 @@ Provides: dnf-command(repograph) + Provides: dnf-command(repomanage) + Provides: dnf-command(reposync) + Provides: dnf-command(repodiff) ++Provides: dnf-command(system-upgrade) ++Provides: dnf-command(offline-upgrade) ++Provides: dnf-command(offline-distrosync) + Provides: dnf-plugins-extras-debug = %{version}-%{release} + Provides: dnf-plugins-extras-repoclosure = %{version}-%{release} + Provides: dnf-plugins-extras-repograph = %{version}-%{release} +@@ -80,6 +83,7 @@ Provides: dnf-plugin-repodiff = %{version}-%{release} + Provides: dnf-plugin-repograph = %{version}-%{release} + Provides: dnf-plugin-repomanage = %{version}-%{release} + Provides: dnf-plugin-reposync = %{version}-%{release} ++Provides: dnf-plugin-system-upgrade = %{version}-%{release} + %if %{with yumcompatibility} + Provides: yum-plugin-copr = %{version}-%{release} + Provides: yum-plugin-changelog = %{version}-%{release} +@@ -133,8 +137,8 @@ Conflicts: python-%{name} < %{version}-%{release} + %description -n python2-%{name} + Core Plugins for DNF, Python 2 interface. This package enhances DNF with builddep, + config-manager, copr, degug, debuginfo-install, download, needs-restarting, +-groups-manager, repoclosure, repograph, repomanage, reposync, changelog +-and repodiff commands. ++groups-manager, repoclosure, repograph, repomanage, reposync, changelog, ++repodiff, system-upgrade, offline-upgrade and offline-distrosync commands. + Additionally provides generate_completion_cache passive plugin. + %endif + +@@ -145,6 +149,10 @@ Summary: Core Plugins for DNF + BuildRequires: python3-dbus + BuildRequires: python3-devel + BuildRequires: python3-dnf >= %{dnf_lowest_compatible} ++BuildRequires: python3-systemd ++BuildRequires: pkgconfig(systemd) ++BuildRequires: systemd ++%{?systemd_ordering} + %if 0%{?fedora} + Requires: python3-distro + %endif +@@ -152,14 +160,17 @@ Requires: python3-dbus + Requires: python3-dnf >= %{dnf_lowest_compatible} + Requires: python3-hawkey >= %{hawkey_version} + Requires: python3-dateutil ++Requires: python3-systemd + Provides: python3-dnf-plugins-extras-debug = %{version}-%{release} + Provides: python3-dnf-plugins-extras-repoclosure = %{version}-%{release} + Provides: python3-dnf-plugins-extras-repograph = %{version}-%{release} + Provides: python3-dnf-plugins-extras-repomanage = %{version}-%{release} ++Provides: python3-dnf-plugin-system-upgrade = %{version}-%{release} + Obsoletes: python3-dnf-plugins-extras-debug < %{dnf_plugins_extra} + Obsoletes: python3-dnf-plugins-extras-repoclosure < %{dnf_plugins_extra} + Obsoletes: python3-dnf-plugins-extras-repograph < %{dnf_plugins_extra} + Obsoletes: python3-dnf-plugins-extras-repomanage < %{dnf_plugins_extra} ++Obsoletes: python3-dnf-plugin-system-upgrade < %{version}-%{release} + + Conflicts: %{name} <= 0.1.5 + # let the both python plugin versions be updated simultaneously +@@ -169,8 +180,8 @@ Conflicts: python-%{name} < %{version}-%{release} + %description -n python3-%{name} + Core Plugins for DNF, Python 3 interface. This package enhances DNF with builddep, + config-manager, copr, debug, debuginfo-install, download, needs-restarting, +-groups-manager, repoclosure, repograph, repomanage, reposync, changelog +-and repodiff commands. ++groups-manager, repoclosure, repograph, repomanage, reposync, changelog, ++repodiff, system-upgrade, offline-upgrade and offline-distrosync commands. + Additionally provides generate_completion_cache passive plugin. + %endif + +@@ -451,6 +462,17 @@ pushd build-py3 + %make_install + popd + %endif ++ ++%if %{with python3} ++mkdir -p %{buildroot}%{_unitdir}/system-update.target.wants/ ++pushd %{buildroot}%{_unitdir}/system-update.target.wants/ ++ ln -sr ../dnf-system-upgrade.service ++popd ++ ++ln -sf %{_mandir}/man8/dnf-system-upgrade.8.gz %{buildroot}%{_mandir}/man8/dnf-offline-upgrade.8.gz ++ln -sf %{_mandir}/man8/dnf-system-upgrade.8.gz %{buildroot}%{_mandir}/man8/dnf-offline-distrosync.8.gz ++%endif ++ + %find_lang %{name} + %if %{with yumutils} + %if %{with python3} +@@ -515,6 +537,9 @@ ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/ + %{_mandir}/man8/dnf-repograph.* + %{_mandir}/man8/dnf-repomanage.* + %{_mandir}/man8/dnf-reposync.* ++%{_mandir}/man8/dnf-system-upgrade.* ++%{_mandir}/man8/dnf-offline-upgrade.* ++%{_mandir}/man8/dnf-offline-distrosync.* + %if %{with yumcompatibility} + %{_mandir}/man1/yum-changelog.* + %{_mandir}/man8/yum-copr.* +@@ -572,6 +597,7 @@ ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/ + %{python3_sitelib}/dnf-plugins/repograph.py + %{python3_sitelib}/dnf-plugins/repomanage.py + %{python3_sitelib}/dnf-plugins/reposync.py ++%{python3_sitelib}/dnf-plugins/system_upgrade.py + %{python3_sitelib}/dnf-plugins/__pycache__/builddep.* + %{python3_sitelib}/dnf-plugins/__pycache__/changelog.* + %{python3_sitelib}/dnf-plugins/__pycache__/config_manager.* +@@ -587,7 +613,11 @@ ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/ + %{python3_sitelib}/dnf-plugins/__pycache__/repograph.* + %{python3_sitelib}/dnf-plugins/__pycache__/repomanage.* + %{python3_sitelib}/dnf-plugins/__pycache__/reposync.* ++%{python3_sitelib}/dnf-plugins/__pycache__/system_upgrade.* + %{python3_sitelib}/dnfpluginscore/ ++%{_unitdir}/dnf-system-upgrade.service ++%{_unitdir}/dnf-system-upgrade-cleanup.service ++%{_unitdir}/system-update.target.wants/dnf-system-upgrade.service + %endif + + %if %{with yumutils} +diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt +index ff84cf8..79472a5 100644 +--- a/doc/CMakeLists.txt ++++ b/doc/CMakeLists.txt +@@ -37,6 +37,7 @@ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/dnf-builddep.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-reposync.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-post-transaction-actions.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-show-leaves.8 ++ ${CMAKE_CURRENT_BINARY_DIR}/dnf-system-upgrade.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-versionlock.8 + ${CMAKE_CURRENT_BINARY_DIR}/yum-copr.8 + ${CMAKE_CURRENT_BINARY_DIR}/yum-versionlock.8 +diff --git a/doc/conf.py b/doc/conf.py +index 41d6936..327ac07 100644 +--- a/doc/conf.py ++++ b/doc/conf.py +@@ -264,6 +264,7 @@ man_pages = [ + ('post-transaction-actions', 'dnf-post-transaction-actions', + u'DNF post transaction actions Plugin', AUTHORS, 8), + ('show-leaves', 'dnf-show-leaves', u'DNF show-leaves Plugin', AUTHORS, 8), ++ ('system-upgrade', 'dnf-system-upgrade', u'DNF system-upgrade Plugin', AUTHORS, 8), + ('versionlock', 'dnf-versionlock', u'DNF versionlock Plugin', AUTHORS, 8), + + # yum3 compatible layer for manpages +diff --git a/doc/index.rst b/doc/index.rst +index 07f6052..251a24e 100644 +--- a/doc/index.rst ++++ b/doc/index.rst +@@ -46,6 +46,7 @@ This documents core plugins of DNF: + repomanage + reposync + show-leaves ++ system-upgrade + versionlock + + +diff --git a/doc/system-upgrade.rst b/doc/system-upgrade.rst +new file mode 100644 +index 0000000..3110460 +--- /dev/null ++++ b/doc/system-upgrade.rst +@@ -0,0 +1,207 @@ ++.. ++ Copyright (C) 2014-2016 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. ++ ++========================= ++DNF system-upgrade Plugin ++========================= ++ ++----------- ++Description ++----------- ++ ++DNF system-upgrades plugin provides three commands: ``system-upgrade``, ``offline-upgrade``, and ++``offline-distrosync``. Only ``system-upgrade`` command requires increase of distribution major ++version (``--releasever``) compared to installed version. ++ ++``dnf system-upgrade`` can be used to upgrade a Fedora system to a new major ++release. It replaces fedup (the old Fedora Upgrade tool). Before you proceed ensure that your system ++is fully upgraded (``dnf --refresh upgrade``). ++ ++The ``system-upgrade`` command also performes additional actions necessary for the upgrade of the ++system, for example an upgrade of groups and environments. ++ ++-------- ++Synopsis ++-------- ++ ++``dnf system-upgrade download --releasever VERSION [OPTIONS]`` ++ ++``dnf system-upgrade reboot`` ++ ++``dnf system-upgrade clean`` ++ ++``dnf system-upgrade log`` ++ ++``dnf system-upgrade log --number=`` ++ ++``dnf offline-upgrade download [OPTIONS]`` ++ ++``dnf offline-upgrade reboot`` ++ ++``dnf offline-upgrade clean`` ++ ++``dnf offline-upgrade log`` ++ ++``dnf offline-upgrade log --number=`` ++ ++``dnf offline-distrosync download [OPTIONS]`` ++ ++``dnf offline-distrosync reboot`` ++ ++``dnf offline-distrosync clean`` ++ ++``dnf offline-distrosync log`` ++ ++``dnf offline-distrosync log --number=`` ++ ++----------- ++Subcommands ++----------- ++ ++``download`` ++ Downloads everything needed to upgrade to a new major release. ++ ++``reboot`` ++ Prepares the system to perform the upgrade, and reboots to start the upgrade. ++ This can only be used after the ``download`` command completes successfully. ++ ++``clean`` ++ Remove previously-downloaded data. This happens automatically at the end of ++ a successful upgrade. ++ ++``log`` ++ Used to see a list of boots during which an upgrade was attempted, or show ++ the logs from an upgrade attempt. The logs for one of the boots can be shown ++ by specifying one of the numbers in the first column. Negative numbers can ++ be used to number the boots from last to first. For example, ``log --number=-1`` can ++ be used to see the logs for the last upgrade attempt. ++ ++------- ++Options ++------- ++ ++``--releasever=VERSION`` ++ REQUIRED. The version to upgrade to. Sets ``$releasever`` in all enabled ++ repos. Usually a number, or ``rawhide``. ++ ++``--downloaddir=`` ++ Redirect download of packages to provided ````. By default, packages ++ are downloaded into (per repository created) subdirectories of ++ /var/lib/dnf/system-upgrade. ++ ++``--distro-sync`` ++ Behave like ``dnf distro-sync``: always install packages from the new ++ release, even if they are older than the currently-installed version. This ++ is the default behavior. ++ ++``--no-downgrade`` ++ Behave like ``dnf update``: do not install packages from the new release ++ if they are older than what is currently installed. This is the opposite of ++ ``--distro-sync``. If both are specified, the last option will be used. The option cannot be ++ used with the ``offline-distrosync`` command. ++ ++``--number`` ++ Applied with ``log`` subcommand will show the log specified by the number. ++ ++----- ++Notes ++----- ++ ++``dnf system-upgrade reboot`` does not create a "System Upgrade" boot item. The ++upgrade will start regardless of which boot item is chosen. ++ ++The ``DNF_SYSTEM_UPGRADE_NO_REBOOT`` environment variable can be set to a ++non-empty value to disable the actual reboot performed by ``system-upgrade`` ++(e.g. for testing purposes). ++ ++Since this is a DNF plugin, options accepted by ``dnf`` are also valid here, ++such as ``--allowerasing``. ++See :manpage:`dnf(8)` for more information. ++ ++The ``fedup`` command is not provided, not even as an alias for ++``dnf system-upgrade``. ++ ++---- ++Bugs ++---- ++ ++Upgrading from install media (e.g. a DVD or .iso file) currently requires the ++user to manually set up a DNF repo and fstab entry for the media. ++ ++-------- ++Examples ++-------- ++ ++Typical upgrade usage ++--------------------- ++ ++``dnf --refresh upgrade`` ++ ++``dnf system-upgrade download --releasever 26`` ++ ++``dnf system-upgrade reboot`` ++ ++Show logs from last upgrade attempt ++----------------------------------- ++ ++``dnf system-upgrade log --number=-1`` ++ ++-------------- ++Reporting Bugs ++-------------- ++ ++Bugs should be filed here: ++ ++ https://bugzilla.redhat.com/ ++ ++For more info on filing bugs, see the Fedora Project wiki: ++ ++ https://fedoraproject.org/wiki/How_to_file_a_bug_report ++ ++ https://fedoraproject.org/wiki/Bugs_and_feature_requests ++ ++Please include ``/var/log/dnf.log`` and the output of ++``dnf system-upgrade log --number=-1`` (if applicable) in your bug reports. ++ ++Problems with dependency solving during download are best reported to the ++maintainers of the package(s) with the dependency problems. ++ ++Similarly, problems encountered on your system after the upgrade completes ++should be reported to the maintainers of the affected components. In other ++words: if (for example) KDE stops working, it's best if you report that to ++the KDE maintainers. ++ ++-------- ++See Also ++-------- ++ ++:manpage:`dnf(8)`, ++:manpage:`dnf.conf(5)`, ++:manpage:`journalctl(1)`. ++ ++Project homepage ++---------------- ++ ++https://github.com/rpm-software-management/dnf-plugins-core ++ ++------- ++Authors ++------- ++ ++Will Woods ++ ++Štěpán Smetana +diff --git a/etc/CMakeLists.txt b/etc/CMakeLists.txt +index 2e9cccd..a892f8a 100644 +--- a/etc/CMakeLists.txt ++++ b/etc/CMakeLists.txt +@@ -1 +1,2 @@ + ADD_SUBDIRECTORY (dnf) ++ADD_SUBDIRECTORY (systemd) +diff --git a/etc/systemd/CMakeLists.txt b/etc/systemd/CMakeLists.txt +new file mode 100644 +index 0000000..8a29403 +--- /dev/null ++++ b/etc/systemd/CMakeLists.txt +@@ -0,0 +1 @@ ++INSTALL (FILES "dnf-system-upgrade.service" "dnf-system-upgrade-cleanup.service" DESTINATION ${SYSTEMD_DIR}) +diff --git a/etc/systemd/dnf-system-upgrade-cleanup.service b/etc/systemd/dnf-system-upgrade-cleanup.service +new file mode 100644 +index 0000000..49f771c +--- /dev/null ++++ b/etc/systemd/dnf-system-upgrade-cleanup.service +@@ -0,0 +1,11 @@ ++[Unit] ++Description=System Upgrade using DNF failed ++DefaultDependencies=no ++ ++[Service] ++Type=oneshot ++# Remove the symlink if it's still there, to protect against reboot loops. ++ExecStart=/usr/bin/rm -fv /system-update ++# If anything goes wrong, reboot back to the normal system. ++ExecStart=/usr/bin/systemctl --no-block reboot ++ +diff --git a/etc/systemd/dnf-system-upgrade.service b/etc/systemd/dnf-system-upgrade.service +new file mode 100644 +index 0000000..2d23cfe +--- /dev/null ++++ b/etc/systemd/dnf-system-upgrade.service +@@ -0,0 +1,20 @@ ++[Unit] ++Description=System Upgrade using DNF ++ConditionPathExists=/system-update ++Documentation=http://www.freedesktop.org/wiki/Software/systemd/SystemUpdates ++ ++DefaultDependencies=no ++Requires=sysinit.target ++After=sysinit.target systemd-journald.socket system-update-pre.target ++Before=shutdown.target system-update.target ++OnFailure=dnf-system-upgrade-cleanup.service ++ ++[Service] ++# We are done when the script exits, not before ++Type=oneshot ++# Upgrade output goes to journal and on-screen. ++StandardOutput=journal+console ++ExecStart=/usr/bin/dnf system-upgrade upgrade ++ ++[Install] ++WantedBy=system-update.target +diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt +index 59f148f..d004e5e 100644 +--- a/plugins/CMakeLists.txt ++++ b/plugins/CMakeLists.txt +@@ -22,6 +22,7 @@ INSTALL (FILES repograph.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES repomanage.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES reposync.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES show_leaves.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) ++INSTALL (FILES system_upgrade.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES modulesync.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES versionlock.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + +diff --git a/plugins/system_upgrade.py b/plugins/system_upgrade.py +new file mode 100644 +index 0000000..fee6762 +--- /dev/null ++++ b/plugins/system_upgrade.py +@@ -0,0 +1,699 @@ ++# -*- coding: utf-8 -*- ++# ++# Copyright (c) 2015-2020 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty 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, see . ++# ++# Author(s): Will Woods ++ ++"""system_upgrade.py - DNF plugin to handle major-version system upgrades.""" ++ ++from subprocess import call, Popen, check_output, CalledProcessError ++import json ++import os ++import os.path ++import re ++import sys ++import uuid ++ ++from systemd import journal ++ ++from dnfpluginscore import _, logger ++ ++import dnf ++import dnf.cli ++from dnf.cli import CliError ++from dnf.i18n import ucd ++import dnf.transaction ++from dnf.transaction_sr import serialize_transaction, TransactionReplay ++ ++import libdnf.conf ++ ++ ++# Translators: This string is only used in unit tests. ++_("the color of the sky") ++ ++DOWNLOAD_FINISHED_ID = uuid.UUID('9348174c5cc74001a71ef26bd79d302e') ++REBOOT_REQUESTED_ID = uuid.UUID('fef1cc509d5047268b83a3a553f54b43') ++UPGRADE_STARTED_ID = uuid.UUID('3e0a5636d16b4ca4bbe5321d06c6aa62') ++UPGRADE_FINISHED_ID = uuid.UUID('8cec00a1566f4d3594f116450395f06c') ++ ++ID_TO_IDENTIFY_BOOTS = UPGRADE_STARTED_ID ++ ++PLYMOUTH = '/usr/bin/plymouth' ++ ++RELEASEVER_MSG = _( ++ "Need a --releasever greater than the current system version.") ++DOWNLOAD_FINISHED_MSG = _( # Translators: do not change "reboot" here ++ "Download complete! Use 'dnf {command} reboot' to start the upgrade.\n" ++ "To remove cached metadata and transaction use 'dnf {command} clean'") ++CANT_RESET_RELEASEVER = _( ++ "Sorry, you need to use 'download --releasever' instead of '--network'") ++ ++STATE_VERSION = 2 ++ ++# --- Miscellaneous helper functions ------------------------------------------ ++ ++ ++def reboot(): ++ if os.getenv("DNF_SYSTEM_UPGRADE_NO_REBOOT", default=False): ++ logger.info(_("Reboot turned off, not rebooting.")) ++ else: ++ Popen(["systemctl", "reboot"]) ++ ++ ++def get_url_from_os_release(): ++ key = "UPGRADE_GUIDE_URL=" ++ for path in ["/etc/os-release", "/usr/lib/os-release"]: ++ try: ++ with open(path) as release_file: ++ for line in release_file: ++ line = line.strip() ++ if line.startswith(key): ++ return line[len(key):].strip('"') ++ except IOError: ++ continue ++ return None ++ ++ ++# DNF-FIXME: dnf.util.clear_dir() doesn't delete regular files :/ ++def clear_dir(path, ignore=[]): ++ if not os.path.isdir(path): ++ return ++ ++ for entry in os.listdir(path): ++ fullpath = os.path.join(path, entry) ++ if fullpath in ignore: ++ continue ++ try: ++ if os.path.isdir(fullpath): ++ dnf.util.rm_rf(fullpath) ++ else: ++ os.unlink(fullpath) ++ except OSError: ++ pass ++ ++ ++def check_release_ver(conf, target=None): ++ if dnf.rpm.detect_releasever(conf.installroot) == conf.releasever: ++ raise CliError(RELEASEVER_MSG) ++ if target and target != conf.releasever: ++ # it's too late to set releasever here, so this can't work. ++ # (see https://bugzilla.redhat.com/show_bug.cgi?id=1212341) ++ raise CliError(CANT_RESET_RELEASEVER) ++ ++ ++def disable_blanking(): ++ try: ++ tty = open('/dev/tty0', 'wb') ++ tty.write(b'\33[9;0]') ++ except Exception as e: ++ print(_("Screen blanking can't be disabled: %s") % e) ++ ++# --- State object - for tracking upgrade state between runs ------------------ ++ ++ ++# DNF-INTEGRATION-NOTE: basically the same thing as dnf.persistor.JSONDB ++class State(object): ++ def __init__(self, statefile): ++ self.statefile = statefile ++ self._data = {} ++ self._read() ++ ++ def _read(self): ++ try: ++ with open(self.statefile) as fp: ++ self._data = json.load(fp) ++ except IOError: ++ self._data = {} ++ except ValueError: ++ self._data = {} ++ logger.warning(_("Failed loading state file: %s, continuing with " ++ "empty state."), self.statefile) ++ ++ def write(self): ++ dnf.util.ensure_dir(os.path.dirname(self.statefile)) ++ with open(self.statefile, 'w') as outf: ++ json.dump(self._data, outf, indent=4, sort_keys=True) ++ ++ def clear(self): ++ if os.path.exists(self.statefile): ++ os.unlink(self.statefile) ++ self._read() ++ ++ def __enter__(self): ++ return self ++ ++ def __exit__(self, exc_type, exc_value, traceback): ++ if exc_type is None: ++ self.write() ++ ++ # helper function for creating properties. pylint: disable=protected-access ++ def _prop(option): # pylint: disable=no-self-argument ++ def setprop(self, value): ++ self._data[option] = value ++ ++ def getprop(self): ++ return self._data.get(option) ++ return property(getprop, setprop) ++ ++ # !!! Increase STATE_VERSION for any changes in data structure like a new property or a new ++ # data structure !!! ++ state_version = _prop("state_version") ++ download_status = _prop("download_status") ++ destdir = _prop("destdir") ++ target_releasever = _prop("target_releasever") ++ system_releasever = _prop("system_releasever") ++ gpgcheck = _prop("gpgcheck") ++ # list of repos with gpgcheck=True ++ gpgcheck_repos = _prop("gpgcheck_repos") ++ # list of repos with repo_gpgcheck=True ++ repo_gpgcheck_repos = _prop("repo_gpgcheck_repos") ++ upgrade_status = _prop("upgrade_status") ++ upgrade_command = _prop("upgrade_command") ++ distro_sync = _prop("distro_sync") ++ enable_disable_repos = _prop("enable_disable_repos") ++ module_platform_id = _prop("module_platform_id") ++ ++# --- Plymouth output helpers ------------------------------------------------- ++ ++ ++class PlymouthOutput(object): ++ """A plymouth output helper class. ++ ++ Filters duplicate calls, and stops calling the plymouth binary if we ++ fail to contact it. ++ """ ++ ++ def __init__(self): ++ self.alive = True ++ self._last_args = dict() ++ self._last_msg = None ++ ++ def _plymouth(self, cmd, *args): ++ dupe_cmd = (args == self._last_args.get(cmd)) ++ if (self.alive and not dupe_cmd) or cmd == '--ping': ++ try: ++ self.alive = (call((PLYMOUTH, cmd) + args) == 0) ++ except OSError: ++ self.alive = False ++ self._last_args[cmd] = args ++ return self.alive ++ ++ def ping(self): ++ return self._plymouth("--ping") ++ ++ def message(self, msg): ++ if self._last_msg and self._last_msg != msg: ++ self._plymouth("hide-message", "--text", self._last_msg) ++ self._last_msg = msg ++ return self._plymouth("display-message", "--text", msg) ++ ++ def set_mode(self): ++ mode = 'updates' ++ try: ++ s = check_output([PLYMOUTH, '--help']) ++ if re.search('--system-upgrade', ucd(s)): ++ mode = 'system-upgrade' ++ except (CalledProcessError, OSError): ++ pass ++ return self._plymouth("change-mode", "--" + mode) ++ ++ def progress(self, percent): ++ return self._plymouth("system-update", "--progress", str(percent)) ++ ++ ++# A single PlymouthOutput instance for us to use within this module ++Plymouth = PlymouthOutput() ++ ++ ++# A TransactionProgress class that updates plymouth for us. ++class PlymouthTransactionProgress(dnf.callback.TransactionProgress): ++ ++ # pylint: disable=too-many-arguments ++ def progress(self, package, action, ti_done, ti_total, ts_done, ts_total): ++ self._update_plymouth(package, action, ts_done, ts_total) ++ ++ def _update_plymouth(self, package, action, current, total): ++ # Prevents quick jumps of progressbar when pretrans scriptlets ++ # and TRANS_PREPARATION are reported as 1/1 ++ if total == 1: ++ return ++ # Verification goes through all the packages again, ++ # which resets the "current" param value, this prevents ++ # resetting of the progress bar as well. (Rhbug:1809096) ++ if action != dnf.callback.PKG_VERIFY: ++ Plymouth.progress(int(90.0 * current / total)) ++ else: ++ Plymouth.progress(90 + int(10.0 * current / total)) ++ ++ Plymouth.message(self._fmt_event(package, action, current, total)) ++ ++ def _fmt_event(self, package, action, current, total): ++ action = dnf.transaction.ACTIONS.get(action, action) ++ return "[%d/%d] %s %s..." % (current, total, action, package) ++ ++# --- journal helpers ------------------------------------------------- ++ ++ ++def find_boots(message_id): ++ """Find all boots with this message id. ++ ++ Returns the entries of all found boots. ++ """ ++ j = journal.Reader() ++ j.add_match(MESSAGE_ID=message_id.hex, # identify the message ++ _UID=0) # prevent spoofing of logs ++ ++ oldboot = None ++ for entry in j: ++ boot = entry['_BOOT_ID'] ++ if boot == oldboot: ++ continue ++ oldboot = boot ++ yield entry ++ ++ ++def list_logs(): ++ print(_('The following boots appear to contain upgrade logs:')) ++ n = -1 ++ for n, entry in enumerate(find_boots(ID_TO_IDENTIFY_BOOTS)): ++ print('{} / {.hex}: {:%Y-%m-%d %H:%M:%S} {}→{}'.format( ++ n + 1, ++ entry['_BOOT_ID'], ++ entry['__REALTIME_TIMESTAMP'], ++ entry.get('SYSTEM_RELEASEVER', '??'), ++ entry.get('TARGET_RELEASEVER', '??'))) ++ if n == -1: ++ print(_('-- no logs were found --')) ++ ++ ++def pick_boot(message_id, n): ++ boots = list(find_boots(message_id)) ++ # Positive indices index all found boots starting with 1 and going forward, ++ # zero is the current boot, and -1, -2, -3 are previous going backwards. ++ # This is the same as journalctl. ++ try: ++ if n == 0: ++ raise IndexError ++ if n > 0: ++ n -= 1 ++ return boots[n]['_BOOT_ID'] ++ except IndexError: ++ raise CliError(_("Cannot find logs with this index.")) ++ ++ ++def show_log(n): ++ boot_id = pick_boot(ID_TO_IDENTIFY_BOOTS, n) ++ process = Popen(['journalctl', '--boot', boot_id.hex]) ++ process.wait() ++ rc = process.returncode ++ if rc == 1: ++ raise dnf.exceptions.Error(_("Unable to match systemd journal entry")) ++ ++ ++CMDS = ['download', 'clean', 'reboot', 'upgrade', 'log'] ++ ++# --- The actual Plugin and Command objects! ---------------------------------- ++ ++ ++class SystemUpgradePlugin(dnf.Plugin): ++ name = 'system-upgrade' ++ ++ def __init__(self, base, cli): ++ super(SystemUpgradePlugin, self).__init__(base, cli) ++ if cli: ++ cli.register_command(SystemUpgradeCommand) ++ cli.register_command(OfflineUpgradeCommand) ++ cli.register_command(OfflineDistrosyncCommand) ++ ++ ++class SystemUpgradeCommand(dnf.cli.Command): ++ aliases = ('system-upgrade', 'fedup',) ++ summary = _("Prepare system for upgrade to a new release") ++ ++ DATADIR = 'var/lib/dnf/system-upgrade' ++ ++ def __init__(self, cli): ++ super(SystemUpgradeCommand, self).__init__(cli) ++ self.datadir = os.path.join(cli.base.conf.installroot, self.DATADIR) ++ self.transaction_file = os.path.join(self.datadir, 'system-upgrade-transaction.json') ++ self.magic_symlink = os.path.join(cli.base.conf.installroot, 'system-update') ++ ++ self.state = State(os.path.join(self.datadir, 'system-upgrade-state.json')) ++ ++ @staticmethod ++ def set_argparser(parser): ++ parser.add_argument("--no-downgrade", dest='distro_sync', ++ action='store_false', ++ help=_("keep installed packages if the new " ++ "release's version is older")) ++ parser.add_argument('tid', nargs=1, choices=CMDS, ++ metavar="[%s]" % "|".join(CMDS)) ++ parser.add_argument('--number', type=int, help=_('which logs to show')) ++ ++ def log_status(self, message, message_id): ++ """Log directly to the journal.""" ++ journal.send(message, ++ MESSAGE_ID=message_id, ++ PRIORITY=journal.LOG_NOTICE, ++ SYSTEM_RELEASEVER=self.state.system_releasever, ++ TARGET_RELEASEVER=self.state.target_releasever, ++ DNF_VERSION=dnf.const.VERSION) ++ ++ def pre_configure(self): ++ self._call_sub("check") ++ self._call_sub("pre_configure") ++ ++ def configure(self): ++ self._call_sub("configure") ++ ++ def run(self): ++ self._call_sub("run") ++ ++ def run_transaction(self): ++ self._call_sub("transaction") ++ ++ def run_resolved(self): ++ self._call_sub("resolved") ++ ++ def _call_sub(self, name): ++ subfunc = getattr(self, name + '_' + self.opts.tid[0], None) ++ if callable(subfunc): ++ subfunc() ++ ++ def _check_state_version(self, command): ++ if self.state.state_version != STATE_VERSION: ++ msg = _("Incompatible version of data. Rerun 'dnf {command} download [OPTIONS]'" ++ "").format(command=command) ++ raise CliError(msg) ++ ++ def _set_cachedir(self): ++ # set download directories from json state file ++ self.base.conf.cachedir = self.datadir ++ self.base.conf.destdir = self.state.destdir if self.state.destdir else None ++ ++ def _get_forward_reverse_pkg_reason_pairs(self): ++ """ ++ forward = {repoid:{pkg_nevra: {tsi.action: tsi.reason}} ++ reverse = {pkg_nevra: {tsi.action: tsi.reason}} ++ :return: forward, reverse ++ """ ++ backward_action = set(dnf.transaction.BACKWARD_ACTIONS + [libdnf.transaction.TransactionItemAction_REINSTALLED]) ++ forward_actions = set(dnf.transaction.FORWARD_ACTIONS) ++ ++ forward = {} ++ reverse = {} ++ for tsi in self.cli.base.transaction: ++ if tsi.action in forward_actions: ++ pkg = tsi.pkg ++ forward.setdefault(pkg.repo.id, {}).setdefault( ++ str(pkg), {})[tsi.action] = tsi.reason ++ elif tsi.action in backward_action: ++ reverse.setdefault(str(tsi.pkg), {})[tsi.action] = tsi.reason ++ return forward, reverse ++ ++ # == pre_configure_*: set up action-specific demands ========================== ++ def pre_configure_download(self): ++ # only download subcommand accepts --destdir command line option ++ self.base.conf.cachedir = self.datadir ++ self.base.conf.destdir = self.opts.destdir if self.opts.destdir else None ++ if 'offline-distrosync' == self.opts.command and not self.opts.distro_sync: ++ raise CliError( ++ _("Command 'offline-distrosync' cannot be used with --no-downgrade option")) ++ elif 'offline-upgrade' == self.opts.command: ++ self.opts.distro_sync = False ++ ++ def pre_configure_reboot(self): ++ self._set_cachedir() ++ ++ def pre_configure_upgrade(self): ++ self._set_cachedir() ++ if self.state.enable_disable_repos: ++ self.opts.repos_ed = self.state.enable_disable_repos ++ self.base.conf.releasever = self.state.target_releasever ++ ++ def pre_configure_clean(self): ++ self._set_cachedir() ++ ++ # == configure_*: set up action-specific demands ========================== ++ ++ def configure_download(self): ++ if 'system-upgrade' == self.opts.command or 'fedup' == self.opts.command: ++ help_url = get_url_from_os_release() ++ if help_url: ++ msg = _('Additional information for System Upgrade: {}') ++ logger.info(msg.format(ucd(help_url))) ++ if self.base._promptWanted(): ++ msg = _('Before you continue ensure that your system is fully upgraded by running ' ++ '"dnf --refresh upgrade". Do you want to continue') ++ if self.base.conf.assumeno or not self.base.output.userconfirm( ++ msg='{} [y/N]: '.format(msg), defaultyes_msg='{} [Y/n]: '.format(msg)): ++ logger.error(_("Operation aborted.")) ++ sys.exit(1) ++ check_release_ver(self.base.conf, target=self.opts.releasever) ++ self.cli.demands.root_user = True ++ self.cli.demands.resolving = True ++ self.cli.demands.available_repos = True ++ self.cli.demands.sack_activation = True ++ self.cli.demands.freshest_metadata = True ++ # We want to do the depsolve / download / transaction-test, but *not* ++ # run the actual RPM transaction to install the downloaded packages. ++ # Setting the "test" flag makes the RPM transaction a test transaction, ++ # so nothing actually gets installed. ++ # (It also means that we run two test transactions in a row, which is ++ # kind of silly, but that's something for DNF to fix...) ++ self.base.conf.tsflags += ["test"] ++ ++ def configure_reboot(self): ++ # FUTURE: add a --debug-shell option to enable debug shell: ++ # systemctl add-wants system-update.target debug-shell.service ++ self.cli.demands.root_user = True ++ ++ def configure_upgrade(self): ++ # same as the download, but offline and non-interactive. so... ++ self.cli.demands.root_user = True ++ self.cli.demands.resolving = True ++ self.cli.demands.available_repos = True ++ self.cli.demands.sack_activation = True ++ # use the saved value for --allowerasing, etc. ++ self.opts.distro_sync = self.state.distro_sync ++ if self.state.gpgcheck is not None: ++ self.base.conf.gpgcheck = self.state.gpgcheck ++ if self.state.gpgcheck_repos is not None: ++ for repo in self.base.repos.values(): ++ repo.gpgcheck = repo.id in self.state.gpgcheck_repos ++ if self.state.repo_gpgcheck_repos is not None: ++ for repo in self.base.repos.values(): ++ repo.repo_gpgcheck = repo.id in self.state.repo_gpgcheck_repos ++ self.base.conf.module_platform_id = self.state.module_platform_id ++ # don't try to get new metadata, 'cuz we're offline ++ self.cli.demands.cacheonly = True ++ # and don't ask any questions (we confirmed all this beforehand) ++ self.base.conf.assumeyes = True ++ self.cli.demands.transaction_display = PlymouthTransactionProgress() ++ # upgrade operation already removes all element that must be removed. Additional removal ++ # could trigger unwanted changes in transaction. ++ self.base.conf.clean_requirements_on_remove = False ++ self.base.conf.install_weak_deps = False ++ ++ def configure_clean(self): ++ self.cli.demands.root_user = True ++ ++ def configure_log(self): ++ pass ++ ++ # == check_*: do any action-specific checks =============================== ++ ++ def check_reboot(self): ++ if not self.state.download_status == 'complete': ++ raise CliError(_("system is not ready for upgrade")) ++ self._check_state_version(self.opts.command) ++ if self.state.upgrade_command != self.opts.command: ++ msg = _("the transaction was not prepared for '{command}'. " ++ "Rerun 'dnf {command} download [OPTIONS]'").format(command=self.opts.command) ++ raise CliError(msg) ++ if os.path.lexists(self.magic_symlink): ++ raise CliError(_("upgrade is already scheduled")) ++ dnf.util.ensure_dir(self.datadir) ++ # FUTURE: checkRPMDBStatus(self.state.download_transaction_id) ++ ++ def check_upgrade(self): ++ if not os.path.lexists(self.magic_symlink): ++ logger.info(_("trigger file does not exist. exiting quietly.")) ++ raise SystemExit(0) ++ if os.readlink(self.magic_symlink) != self.datadir: ++ logger.info(_("another upgrade tool is running. exiting quietly.")) ++ raise SystemExit(0) ++ # Delete symlink ASAP to avoid reboot loops ++ dnf.yum.misc.unlink_f(self.magic_symlink) ++ command = self.state.upgrade_command ++ if not command: ++ command = self.opts.command ++ self._check_state_version(command) ++ if not self.state.upgrade_status == 'ready': ++ msg = _("use 'dnf {command} reboot' to begin the upgrade").format(command=command) ++ raise CliError(msg) ++ ++ # == run_*: run the action/prep the transaction =========================== ++ ++ def run_prepare(self): ++ # make the magic symlink ++ os.symlink(self.datadir, self.magic_symlink) ++ # set upgrade_status so that the upgrade can run ++ with self.state as state: ++ state.upgrade_status = 'ready' ++ ++ def run_reboot(self): ++ self.run_prepare() ++ ++ if not self.opts.tid[0] == "reboot": ++ return ++ ++ self.log_status(_("Rebooting to perform upgrade."), ++ REBOOT_REQUESTED_ID) ++ reboot() ++ ++ def run_download(self): ++ # Mark everything in the world for upgrade/sync ++ if self.opts.distro_sync: ++ self.base.distro_sync() ++ else: ++ self.base.upgrade_all() ++ ++ if self.opts.command not in ['offline-upgrade', 'offline-distrosync']: ++ # Mark all installed groups and environments for upgrade ++ self.base.read_comps() ++ installed_groups = [g.id for g in self.base.comps.groups if self.base.history.group.get(g.id)] ++ if installed_groups: ++ self.base.env_group_upgrade(installed_groups) ++ installed_environments = [g.id for g in self.base.comps.environments if self.base.history.env.get(g.id)] ++ if installed_environments: ++ self.base.env_group_upgrade(installed_environments) ++ ++ with self.state as state: ++ state.download_status = 'downloading' ++ state.target_releasever = self.base.conf.releasever ++ state.destdir = self.base.conf.destdir ++ ++ def run_upgrade(self): ++ # change the upgrade status (so we can detect crashed upgrades later) ++ command = '' ++ with self.state as state: ++ state.upgrade_status = 'incomplete' ++ command = state.upgrade_command ++ if command == 'offline-upgrade': ++ msg = _("Starting offline upgrade. This will take a while.") ++ elif command == 'offline-distrosync': ++ msg = _("Starting offline distrosync. This will take a while.") ++ else: ++ msg = _("Starting system upgrade. This will take a while.") ++ ++ self.log_status(msg, UPGRADE_STARTED_ID) ++ ++ # reset the splash mode and let the user know we're running ++ Plymouth.set_mode() ++ Plymouth.progress(0) ++ Plymouth.message(msg) ++ ++ # disable screen blanking ++ disable_blanking() ++ ++ self.replay = TransactionReplay(self.base, self.transaction_file) ++ self.replay.run() ++ ++ def run_clean(self): ++ logger.info(_("Cleaning up downloaded data...")) ++ # Don't delete persistor, it contains paths for downloaded packages ++ # that are used by dnf during finalizing base to clean them up ++ clear_dir(self.base.conf.cachedir, ++ [dnf.persistor.TempfilePersistor(self.base.conf.cachedir).db_path]) ++ with self.state as state: ++ state.download_status = None ++ state.state_version = None ++ state.upgrade_status = None ++ state.upgrade_command = None ++ state.destdir = None ++ ++ def run_log(self): ++ if self.opts.number: ++ show_log(self.opts.number) ++ else: ++ list_logs() ++ ++ # == resolved_*: do staff after succesful resolvement ===================== ++ ++ def resolved_upgrade(self): ++ """Adjust transaction reasons according to stored values""" ++ self.replay.post_transaction() ++ ++ # == transaction_*: do stuff after a successful transaction =============== ++ ++ def transaction_download(self): ++ transaction = self.base.history.get_current() ++ ++ if not transaction.packages(): ++ logger.info(_("The system-upgrade transaction is empty, your system is already up-to-date.")) ++ return ++ ++ data = serialize_transaction(transaction) ++ try: ++ with open(self.transaction_file, "w") as f: ++ json.dump(data, f, indent=4, sort_keys=True) ++ f.write("\n") ++ ++ print(_("Transaction saved to {}.").format(self.transaction_file)) ++ ++ except OSError as e: ++ raise dnf.cli.CliError(_('Error storing transaction: {}').format(str(e))) ++ ++ # Okay! Write out the state so the upgrade can use it. ++ system_ver = dnf.rpm.detect_releasever(self.base.conf.installroot) ++ with self.state as state: ++ state.download_status = 'complete' ++ state.state_version = STATE_VERSION ++ state.distro_sync = self.opts.distro_sync ++ state.gpgcheck = self.base.conf.gpgcheck ++ state.gpgcheck_repos = [ ++ repo.id for repo in self.base.repos.values() if repo.gpgcheck] ++ state.repo_gpgcheck_repos = [ ++ repo.id for repo in self.base.repos.values() if repo.repo_gpgcheck] ++ state.system_releasever = system_ver ++ state.target_releasever = self.base.conf.releasever ++ state.module_platform_id = self.base.conf.module_platform_id ++ state.enable_disable_repos = self.opts.repos_ed ++ state.destdir = self.base.conf.destdir ++ state.upgrade_command = self.opts.command ++ ++ msg = DOWNLOAD_FINISHED_MSG.format(command=self.opts.command) ++ logger.info(msg) ++ self.log_status(_("Download finished."), DOWNLOAD_FINISHED_ID) ++ ++ def transaction_upgrade(self): ++ Plymouth.message(_("Upgrade complete! Cleaning up and rebooting...")) ++ self.log_status(_("Upgrade complete! Cleaning up and rebooting..."), ++ UPGRADE_FINISHED_ID) ++ self.run_clean() ++ if self.opts.tid[0] == "upgrade": ++ reboot() ++ ++ ++class OfflineUpgradeCommand(SystemUpgradeCommand): ++ aliases = ('offline-upgrade',) ++ summary = _("Prepare offline upgrade of the system") ++ ++ ++class OfflineDistrosyncCommand(SystemUpgradeCommand): ++ aliases = ('offline-distrosync',) ++ summary = _("Prepare offline distrosync of the system") +diff --git a/tests/test_system_upgrade.py b/tests/test_system_upgrade.py +new file mode 100644 +index 0000000..6ef4c21 +--- /dev/null ++++ b/tests/test_system_upgrade.py +@@ -0,0 +1,502 @@ ++# test_system_upgrade.py - unit tests for system-upgrade plugin ++ ++import system_upgrade ++ ++from system_upgrade import PLYMOUTH, CliError ++ ++import os ++import tempfile ++import shutil ++import gettext ++ ++from dnf.callback import (PKG_CLEANUP, PKG_DOWNGRADE, PKG_INSTALL, ++ PKG_OBSOLETE, PKG_REINSTALL, PKG_REMOVE, PKG_UPGRADE, ++ PKG_VERIFY, TRANS_POST) ++ ++import unittest ++ ++from tests.support import mock ++patch = mock.patch ++ ++ ++@patch('system_upgrade.call', return_value=0) ++class PlymouthTestCase(unittest.TestCase): ++ def setUp(self): ++ self.ply = system_upgrade.PlymouthOutput() ++ self.msg = "Hello, plymouth." ++ self.msg_args = (PLYMOUTH, "display-message", "--text", self.msg) ++ ++ def test_ping(self, call): ++ self.ply.ping() ++ call.assert_called_once_with((PLYMOUTH, "--ping")) ++ self.assertTrue(self.ply.alive) ++ ++ def test_ping_when_dead(self, call): ++ call.return_value = 1 ++ self.ply.ping() ++ self.assertFalse(self.ply.alive) ++ call.return_value = 0 ++ self.ply.ping() ++ self.assertEqual(call.call_count, 2) ++ self.assertTrue(self.ply.alive) ++ ++ def test_message(self, call): ++ self.ply.message(self.msg) ++ call.assert_called_once_with(self.msg_args) ++ ++ def test_hide_message(self, call): ++ messages = ("first", "middle", "BONUS", "last") ++ for m in messages: ++ self.ply.message(m) ++ ++ def hidem(m): ++ return mock.call((PLYMOUTH, "hide-message", "--text", m)) ++ ++ def dispm(m): ++ return mock.call((PLYMOUTH, "display-message", "--text", m)) ++ m1, m2, m3, m4 = messages ++ call.assert_has_calls([ ++ dispm(m1), ++ hidem(m1), dispm(m2), ++ hidem(m2), dispm(m3), ++ hidem(m3), dispm(m4), ++ ]) ++ ++ def test_message_dupe(self, call): ++ self.ply.message(self.msg) ++ self.ply.message(self.msg) ++ call.assert_called_once_with(self.msg_args) ++ ++ def test_message_dead(self, call): ++ call.return_value = 1 ++ self.ply.message(self.msg) ++ self.assertFalse(self.ply.alive) ++ self.ply.message("not even gonna bother") ++ call.assert_called_once_with(self.msg_args) ++ ++ def test_progress(self, call): ++ self.ply.progress(27) ++ call.assert_called_once_with( ++ (PLYMOUTH, "system-update", "--progress", str(27))) ++ ++ @patch('system_upgrade.check_output', ++ return_value="this plymouth does support --system-upgrade mode") ++ def test_mode(self, check_output, call): ++ self.ply.set_mode() ++ call.assert_called_once_with((PLYMOUTH, "change-mode", "--system-upgrade")) ++ ++ @patch('system_upgrade.check_output', ++ return_value="this plymouth doesn't support system-upgrade mode") ++ def test_mode_no_system_upgrade_plymouth(self, check_output, call): ++ self.ply.set_mode() ++ call.assert_called_once_with((PLYMOUTH, "change-mode", "--updates")) ++ ++ def test_mode_no_plymouth(self, call): ++ call.side_effect = OSError(2, 'No such file or directory') ++ self.ply.set_mode() ++ self.assertFalse(self.ply.alive) ++ ++ ++@patch('system_upgrade.call', return_value=0) ++class PlymouthTransactionProgressTestCase(unittest.TestCase): ++ actions = (PKG_CLEANUP, PKG_DOWNGRADE, PKG_INSTALL, PKG_OBSOLETE, ++ PKG_REINSTALL, PKG_REMOVE, PKG_UPGRADE, PKG_VERIFY, ++ TRANS_POST) ++ ++ # pylint: disable=protected-access ++ def setUp(self): ++ system_upgrade.Plymouth = system_upgrade.PlymouthOutput() ++ self.display = system_upgrade.PlymouthTransactionProgress() ++ self.pkg = "testpackage" ++ ++ def test_display(self, call): ++ for action in self.actions: ++ self.display.progress(self.pkg, action, 0, 100, 1, 1000) ++ msg = self.display._fmt_event(self.pkg, action, 1, 1000) ++ # updating plymouth display means two plymouth calls ++ call.assert_has_calls([ ++ mock.call((PLYMOUTH, "system-update", "--progress", "0")), ++ mock.call((PLYMOUTH, "display-message", "--text", msg)) ++ ], any_order=True) ++ ++ def test_filter_calls(self, call): ++ action = PKG_INSTALL ++ # first display update -> set percentage and text ++ self.display.progress(self.pkg, action, 0, 100, 1, 1000) ++ msg1 = self.display._fmt_event(self.pkg, action, 1, 1000) ++ call.assert_has_calls([ ++ mock.call((PLYMOUTH, "system-update", "--progress", "0")), ++ mock.call((PLYMOUTH, "display-message", "--text", msg1)), ++ ]) ++ ++ # event progress on the same transaction item. ++ # no new calls to plymouth because the percentage and text don't change ++ for te_cur in range(1, 100): ++ self.display.progress(self.pkg, action, te_cur, 100, 1, 1000) ++ call.assert_has_calls([ ++ mock.call((PLYMOUTH, "system-update", "--progress", "0")), ++ mock.call((PLYMOUTH, "display-message", "--text", msg1)), ++ ]) ++ ++ # new item: new message ("[2/1000] ..."), but percentage still 0.. ++ self.display.progress(self.pkg, action, 0, 100, 2, 1000) ++ # old message hidden, new message displayed. no new percentage. ++ msg2 = self.display._fmt_event(self.pkg, action, 2, 1000) ++ call.assert_has_calls([ ++ mock.call((PLYMOUTH, "system-update", "--progress", "0")), ++ mock.call((PLYMOUTH, "display-message", "--text", msg1)), ++ mock.call((PLYMOUTH, "hide-message", "--text", msg1)), ++ mock.call((PLYMOUTH, "display-message", "--text", msg2)), ++ ]) ++ ++ ++TESTLANG = "zh_CN" ++TESTLANG_MO = "po/%s.mo" % TESTLANG ++ ++ ++@unittest.skipUnless(os.path.exists(TESTLANG_MO), "make %s first" % ++ TESTLANG_MO) ++# @unittest.skip("There is no translation yet to system-upgrade") ++class I18NTestCaseBase(unittest.TestCase): ++ @classmethod ++ @unittest.skip("There is no translation yet to system-upgrade") ++ def setUpClass(cls): ++ cls.localedir = tempfile.mkdtemp(prefix='system_upgrade_test_i18n-') ++ cls.msgdir = os.path.join(cls.localedir, TESTLANG + "/LC_MESSAGES") ++ cls.msgfile = "dnf-plugins-extras" + ".mo" ++ os.makedirs(cls.msgdir) ++ shutil.copy2(TESTLANG_MO, os.path.join(cls.msgdir, cls.msgfile)) ++ ++ @classmethod ++ def tearDownClass(cls): ++ shutil.rmtree(cls.localedir) ++ ++ def setUp(self): ++ self.t = gettext.translation("dnf-plugins-extras", self.localedir, ++ languages=[TESTLANG], fallback=True) ++ self.gettext = self.t.gettext ++ ++ ++class I18NTestCase(I18NTestCaseBase): ++ @unittest.skip("There is no translation yet to system-upgrade") ++ def test_selftest(self): ++ self.assertIn(self.msgfile, os.listdir(self.msgdir)) ++ self.assertIn(TESTLANG, os.listdir(self.localedir)) ++ t = gettext.translation("dnf-plugins-extras", self.localedir, ++ languages=[TESTLANG], fallback=False) ++ info = t.info() ++ self.assertIn("language", info) ++ self.assertEqual(info["language"], TESTLANG.replace("_", "-")) ++ ++ @unittest.skip("There is no translation yet to system-upgrade") ++ def test_fallback(self): ++ msg = "THIS STRING DOES NOT EXIST" ++ trans_msg = self.gettext(msg) ++ self.assertEqual(msg, trans_msg) ++ ++ @unittest.skip("There is no translation yet to system-upgrade") ++ def test_translation(self): ++ msg = "the color of the sky" ++ trans_msg = self.gettext(msg) ++ self.assertNotEqual(msg, trans_msg) ++ ++ ++class StateTestCase(unittest.TestCase): ++ @classmethod ++ def setUpClass(cls): ++ cls.statedir = tempfile.mkdtemp(prefix="system_upgrade_test_state-") ++ cls.StateClass = system_upgrade.State ++ ++ def setUp(self): ++ self.state = self.StateClass(os.path.join(self.statedir, "state")) ++ ++ def test_bool_value(self): ++ with self.state: ++ self.state.distro_sync = True ++ del self.state ++ self.state = self.StateClass(os.path.join(self.statedir, "state")) ++ self.assertIs(self.state.distro_sync, True) ++ ++ @classmethod ++ def tearDownClass(cls): ++ shutil.rmtree(cls.statedir) ++ ++ ++class UtilTestCase(unittest.TestCase): ++ def setUp(self): ++ self.tmpdir = tempfile.mkdtemp(prefix='system_upgrade_test_util-') ++ self.dirs = ["dir1", "dir2"] ++ self.files = ["file1", "dir2/file2"] ++ for d in self.dirs: ++ os.makedirs(os.path.join(self.tmpdir, d)) ++ for f in self.files: ++ with open(os.path.join(self.tmpdir, f), 'wt') as fobj: ++ fobj.write("hi there\n") ++ ++ def test_self_test(self): ++ for d in self.dirs: ++ self.assertTrue(os.path.isdir(os.path.join(self.tmpdir, d))) ++ for f in self.files: ++ self.assertTrue(os.path.exists(os.path.join(self.tmpdir, f))) ++ ++ def test_clear_dir(self): ++ self.assertTrue(os.path.isdir(self.tmpdir)) ++ system_upgrade.clear_dir(self.tmpdir) ++ self.assertTrue(os.path.isdir(self.tmpdir)) ++ self.assertEqual(os.listdir(self.tmpdir), []) ++ ++ def tearDown(self): ++ shutil.rmtree(self.tmpdir) ++ ++ ++class CommandTestCaseBase(unittest.TestCase): ++ def setUp(self): ++ self.datadir = tempfile.mkdtemp(prefix="system_upgrade_test_datadir-") ++ self.installroot = tempfile.TemporaryDirectory(prefix="system_upgrade_test_installroot-") ++ system_upgrade.SystemUpgradeCommand.DATADIR = self.datadir ++ self.cli = mock.MagicMock() ++ # the installroot is not strictly necessary for the test, but ++ # releasever detection is accessing host system files without it, and ++ # this fails on permissions in COPR srpm builds (e.g. from rpm-gitoverlay) ++ self.cli.base.conf.installroot = self.installroot.name ++ self.command = system_upgrade.SystemUpgradeCommand(cli=self.cli) ++ self.command.base.conf.cachedir = os.path.join(self.datadir, "cache") ++ self.command.base.conf.destdir = None ++ ++ def tearDown(self): ++ shutil.rmtree(self.datadir) ++ self.installroot.cleanup() ++ ++ ++class CommandTestCase(CommandTestCaseBase): ++ # self-tests for the command test cases ++ def test_state(self): ++ # initial state: no status ++ self.assertIsNone(self.command.state.download_status) ++ self.assertIsNone(self.command.state.upgrade_status) ++ ++ ++class CleanCommandTestCase(CommandTestCaseBase): ++ def test_pre_configure_clean(self): ++ with self.command.state as state: ++ state.destdir = "/grape/wine" ++ self.command.pre_configure_clean() ++ self.assertEqual(self.command.base.conf.destdir, "/grape/wine") ++ ++ def test_configure_clean(self): ++ self.cli.demands.root_user = None ++ self.command.configure_clean() ++ self.assertTrue(self.cli.demands.root_user) ++ ++ def test_run_clean(self): ++ with self.command.state as state: ++ state.download_status = "complete" ++ state.upgrade_status = "ready" ++ # make sure the datadir and state info is set up OK ++ self.assertEqual(self.command.state.download_status, "complete") ++ self.assertEqual(self.command.state.upgrade_status, "ready") ++ # run cleanup ++ self.command.run_clean() ++ # state is cleared ++ self.assertIsNone(self.command.state.download_status) ++ self.assertIsNone(self.command.state.upgrade_status) ++ ++ ++class RebootCheckCommandTestCase(CommandTestCaseBase): ++ def setUp(self): ++ super(RebootCheckCommandTestCase, self).setUp() ++ self.magic_symlink = self.datadir + '/symlink' ++ self.command.magic_symlink = self.magic_symlink ++ ++ def test_pre_configure_reboot(self): ++ with self.command.state as state: ++ state.destdir = "/grape/wine" ++ self.command.pre_configure_reboot() ++ self.assertEqual(self.command.base.conf.destdir, "/grape/wine") ++ ++ def test_configure_reboot(self): ++ self.cli.demands.root_user = None ++ self.command.configure_reboot() ++ self.assertTrue(self.cli.demands.root_user) ++ ++ def check_reboot(self, status='complete', lexists=False, command='system-upgrade', ++ state_command='system-upgrade'): ++ with patch('system_upgrade.os.path.lexists') as lexists_func: ++ self.command.state.state_version = 2 ++ self.command.state.download_status = status ++ self.command.opts = mock.MagicMock() ++ self.command.opts.command = command ++ self.command.state.upgrade_command = state_command ++ lexists_func.return_value = lexists ++ self.command.check_reboot() ++ ++ def test_check_reboot_ok(self): ++ self.check_reboot(status='complete', lexists=False) ++ ++ def test_check_reboot_different_command(self): ++ with self.assertRaises(CliError): ++ self.check_reboot(status='complete', lexists=False, command='system-upgrade', ++ state_command='offline-upgrade') ++ ++ def test_check_reboot_no_download(self): ++ with self.assertRaises(CliError): ++ self.check_reboot(status=None, lexists=False) ++ ++ def test_check_reboot_link_exists(self): ++ with self.assertRaises(CliError): ++ self.check_reboot(status='complete', lexists=True) ++ ++ def test_run_prepare(self): ++ self.command.run_prepare() ++ self.assertEqual(os.readlink(self.magic_symlink), self.datadir) ++ self.assertEqual(self.command.state.upgrade_status, 'ready') ++ ++ @patch('system_upgrade.SystemUpgradeCommand.run_prepare') ++ @patch('system_upgrade.SystemUpgradeCommand.log_status') ++ @patch('system_upgrade.reboot') ++ def test_run_reboot(self, reboot, log_status, run_prepare): ++ self.command.opts = mock.MagicMock() ++ self.command.opts.tid = ["reboot"] ++ self.command.run_reboot() ++ run_prepare.assert_called_once_with() ++ self.assertEqual(system_upgrade.REBOOT_REQUESTED_ID, ++ log_status.call_args[0][1]) ++ self.assertTrue(reboot.called) ++ ++ @patch('system_upgrade.SystemUpgradeCommand.run_prepare') ++ @patch('system_upgrade.SystemUpgradeCommand.log_status') ++ @patch('system_upgrade.reboot') ++ def test_reboot_prepare_only(self, reboot, log_status, run_prepare): ++ self.command.opts = mock.MagicMock() ++ self.command.opts.tid = [None] ++ self.command.run_reboot() ++ run_prepare.assert_called_once_with() ++ self.assertFalse(log_status.called) ++ self.assertFalse(reboot.called) ++ ++ ++class DownloadCommandTestCase(CommandTestCase): ++ def test_pre_configure_download_default(self): ++ self.command.opts = mock.MagicMock() ++ self.command.opts.destdir = None ++ self.command.base.conf.destdir = None ++ self.command.pre_configure_download() ++ self.assertEqual(self.command.base.conf.cachedir, self.datadir) ++ ++ def test_pre_configure_download_destdir(self): ++ self.command.opts = mock.MagicMock() ++ self.command.opts.destdir = self.datadir ++ self.command.pre_configure_download() ++ self.assertEqual(self.command.base.conf.destdir, self.datadir) ++ ++ def test_configure_download(self): ++ self.command.opts = mock.MagicMock() ++ self.command.opts.tid = "download" ++ self.command.configure() ++ self.assertTrue(self.cli.demands.root_user) ++ self.assertTrue(self.cli.demands.resolving) ++ self.assertTrue(self.cli.demands.sack_activation) ++ self.assertTrue(self.cli.demands.available_repos) ++ ++ def test_transaction_download(self): ++ pkg = mock.MagicMock() ++ repo = mock.MagicMock() ++ repo.id = 'test' ++ pkg.name = "kernel" ++ pkg.repo = repo ++ self.cli.base.transaction.install_set = [pkg] ++ self.command.opts = mock.MagicMock() ++ self.command.opts.distro_sync = True ++ self.command.opts.command = "system_upgrade" ++ self.command.opts.repos_ed = [] ++ self.cli.demands.allow_erasing = "allow_erasing" ++ self.command.base.conf.best = True ++ self.command.base.conf.releasever = "35" ++ self.command.base.conf.gpgcheck = True ++ self.command.opts.destdir = self.datadir ++ self.command.base.conf.install_weak_deps = True ++ self.command.base.conf.module_platform_id = '' ++ self.command.pre_configure_download() ++ self.command.transaction_download() ++ with system_upgrade.State(self.command.state.statefile) as state: ++ self.assertEqual(state.state_version, system_upgrade.STATE_VERSION) ++ self.assertEqual(state.download_status, "complete") ++ self.assertEqual(state.distro_sync, True) ++ self.assertEqual(state.destdir, self.datadir) ++ self.assertEqual(state.upgrade_command, "system_upgrade") ++ ++ def test_transaction_download_offline_upgrade(self): ++ pkg = mock.MagicMock() ++ repo = mock.MagicMock() ++ repo.id = 'test' ++ pkg.name = "kernel" ++ pkg.repo = repo ++ self.cli.base.transaction.install_set = [pkg] ++ self.command.opts = mock.MagicMock() ++ self.command.opts.distro_sync = True ++ self.command.opts.command = "offline-upgrade" ++ self.command.opts.repos_ed = [] ++ self.cli.demands.allow_erasing = "allow_erasing" ++ self.command.base.conf.best = True ++ self.command.base.conf.releasever = "35" ++ self.command.base.conf.gpgcheck = True ++ self.command.opts.destdir = self.datadir ++ self.command.base.conf.install_weak_deps = True ++ self.command.base.conf.module_platform_id = '' ++ self.command.pre_configure_download() ++ self.command.transaction_download() ++ with system_upgrade.State(self.command.state.statefile) as state: ++ self.assertEqual(state.download_status, "complete") ++ self.assertEqual(state.distro_sync, False) ++ self.assertEqual(state.destdir, self.datadir) ++ self.assertEqual(state.upgrade_command, "offline-upgrade") ++ ++ ++class UpgradeCommandTestCase(CommandTestCase): ++ def test_pre_configure_upgrade(self): ++ with self.command.state as state: ++ state.destdir = "/grape/wine" ++ state.target_releasever = "35" ++ self.command.pre_configure_upgrade() ++ self.assertEqual(self.command.base.conf.destdir, "/grape/wine") ++ self.assertEqual(self.command.base.conf.releasever, "35") ++ ++ def test_configure_upgrade(self): ++ # write state like download would have ++ with self.command.state as state: ++ state.download_status = "complete" ++ state.distro_sync = True ++ state.allow_erasing = True ++ state.best = True ++ # okay, now configure upgrade ++ self.command.opts = mock.MagicMock() ++ self.command.opts.tid = "upgrade" ++ self.command.configure() ++ # did we reset the depsolving flags? ++ self.assertTrue(self.command.opts.distro_sync) ++ self.assertTrue(self.cli.demands.allow_erasing) ++ self.assertTrue(self.command.base.conf.best) ++ # are we on autopilot? ++ self.assertTrue(self.command.base.conf.assumeyes) ++ self.assertTrue(self.cli.demands.cacheonly) ++ ++ ++class LogCommandTestCase(CommandTestCase): ++ def test_configure_log(self): ++ self.command.opts = mock.MagicMock() ++ self.command.opts.tid = "log" ++ self.command.configure() ++ ++ def test_run_log_list(self): ++ self.command.opts = mock.MagicMock() ++ self.command.opts.number = None ++ with patch('system_upgrade.list_logs') as list_logs: ++ self.command.run_log() ++ list_logs.assert_called_once_with() ++ ++ def test_run_log_prev(self): ++ with patch('system_upgrade.show_log') as show_log: ++ self.command.opts = mock.MagicMock() ++ self.command.opts.number = -2 ++ self.command.run_log() ++ show_log.assert_called_once_with(-2) +-- +2.37.3 + diff --git a/SOURCES/0026-Add-a-warning-when-using-system-upgrade-on-RHEL.patch b/SOURCES/0026-Add-a-warning-when-using-system-upgrade-on-RHEL.patch new file mode 100644 index 0000000..1bac21b --- /dev/null +++ b/SOURCES/0026-Add-a-warning-when-using-system-upgrade-on-RHEL.patch @@ -0,0 +1,78 @@ +From e52655aa9c7c9ad334639990d612da574b57736b Mon Sep 17 00:00:00 2001 +From: Jan Kolarik +Date: Fri, 30 Sep 2022 11:36:26 +0000 +Subject: [PATCH 1/3] Add a warning when using `system-upgrade` on RHEL + +--- + dnf-plugins-core.spec | 3 +-- + doc/system-upgrade.rst | 6 ++++-- + plugins/system_upgrade.py | 4 ++++ + 3 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec +index 0e1c9e3..a5ec165 100644 +--- a/dnf-plugins-core.spec ++++ b/dnf-plugins-core.spec +@@ -148,14 +148,13 @@ Summary: Core Plugins for DNF + %{?python_provide:%python_provide python3-%{name}} + BuildRequires: python3-dbus + BuildRequires: python3-devel ++BuildRequires: python3-distro + BuildRequires: python3-dnf >= %{dnf_lowest_compatible} + BuildRequires: python3-systemd + BuildRequires: pkgconfig(systemd) + BuildRequires: systemd + %{?systemd_ordering} +-%if 0%{?fedora} + Requires: python3-distro +-%endif + Requires: python3-dbus + Requires: python3-dnf >= %{dnf_lowest_compatible} + Requires: python3-hawkey >= %{hawkey_version} +diff --git a/doc/system-upgrade.rst b/doc/system-upgrade.rst +index 3110460..87b7319 100644 +--- a/doc/system-upgrade.rst ++++ b/doc/system-upgrade.rst +@@ -27,13 +27,15 @@ DNF system-upgrades plugin provides three commands: ``system-upgrade``, ``offlin + ``offline-distrosync``. Only ``system-upgrade`` command requires increase of distribution major + version (``--releasever``) compared to installed version. + +-``dnf system-upgrade`` can be used to upgrade a Fedora system to a new major +-release. It replaces fedup (the old Fedora Upgrade tool). Before you proceed ensure that your system ++``dnf system-upgrade`` is a recommended way to upgrade a system to a new major release. ++It replaces fedup (the old Fedora Upgrade tool). Before you proceed ensure that your system + is fully upgraded (``dnf --refresh upgrade``). + + The ``system-upgrade`` command also performes additional actions necessary for the upgrade of the + system, for example an upgrade of groups and environments. + ++.. WARNING:: The ``system-upgrade`` command is not supported on the RHEL distribution. ++ + -------- + Synopsis + -------- +diff --git a/plugins/system_upgrade.py b/plugins/system_upgrade.py +index fee6762..0baf978 100644 +--- a/plugins/system_upgrade.py ++++ b/plugins/system_upgrade.py +@@ -20,6 +20,7 @@ + """system_upgrade.py - DNF plugin to handle major-version system upgrades.""" + + from subprocess import call, Popen, check_output, CalledProcessError ++import distro + import json + import os + import os.path +@@ -451,6 +452,9 @@ class SystemUpgradeCommand(dnf.cli.Command): + + def configure_download(self): + if 'system-upgrade' == self.opts.command or 'fedup' == self.opts.command: ++ if distro.id() == 'rhel': ++ logger.warning(_('WARNING: this operation is not supported on the RHEL distribution. ' ++ 'Proceed at your own risk.')) + help_url = get_url_from_os_release() + if help_url: + msg = _('Additional information for System Upgrade: {}') +-- +2.38.1 + diff --git a/SOURCES/0027-offline-upgrade-Add-security-filters.patch b/SOURCES/0027-offline-upgrade-Add-security-filters.patch new file mode 100644 index 0000000..339d81f --- /dev/null +++ b/SOURCES/0027-offline-upgrade-Add-security-filters.patch @@ -0,0 +1,61 @@ +From 3a18b7241708a3c5fd1b4b92a2f9908a826e815d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tarc=C3=ADsio=20Ladeia=20de=20Oliveira?= + +Date: Thu, 20 Oct 2022 22:16:59 -0300 +Subject: [PATCH 1/2] [offline-upgrade] Add security filters (RhBug:1939975) + +Add support for security filter options that are available in the main +`dnf` commands, that is, `--advisory`, `--bugfix`, `--security`, and +`--enhancement`. + += changelog = +msg: [offline-upgrade] Add support for security filters +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1939975 +--- + plugins/system_upgrade.py | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/plugins/system_upgrade.py b/plugins/system_upgrade.py +index 0baf978..ef1de73 100644 +--- a/plugins/system_upgrade.py ++++ b/plugins/system_upgrade.py +@@ -467,6 +467,9 @@ class SystemUpgradeCommand(dnf.cli.Command): + logger.error(_("Operation aborted.")) + sys.exit(1) + check_release_ver(self.base.conf, target=self.opts.releasever) ++ elif 'offline-upgrade' == self.opts.command: ++ self.cli._populate_update_security_filter(self.opts) ++ + self.cli.demands.root_user = True + self.cli.demands.resolving = True + self.cli.demands.available_repos = True +-- +2.38.1 + + +From dad20a478e100bd0ac3a8d7d51dad75baca90c7f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tarc=C3=ADsio=20Ladeia=20de=20Oliveira?= + +Date: Thu, 20 Oct 2022 22:27:22 -0300 +Subject: [PATCH 2/2] Add myself as contributor in AUTHORS + +--- + AUTHORS | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/AUTHORS b/AUTHORS +index 33512fd..cd4b5be 100644 +--- a/AUTHORS ++++ b/AUTHORS +@@ -32,6 +32,7 @@ DNF-PLUGINS-CORE CONTRIBUTORS + Neal Gompa + Paul Howarth + Rickard Dybeck ++ Tarcísio Ladeia de Oliveira + Tomas Babej + Vladan Kudlac + Wieland Hoffmann +-- +2.38.1 + diff --git a/SOURCES/0028-system-upgrade-Show-warning-always-for-a-downstream.patch b/SOURCES/0028-system-upgrade-Show-warning-always-for-a-downstream.patch new file mode 100644 index 0000000..03999e3 --- /dev/null +++ b/SOURCES/0028-system-upgrade-Show-warning-always-for-a-downstream.patch @@ -0,0 +1,62 @@ +From dfbda502c5c46daf84e00179478de01e452f9dae Mon Sep 17 00:00:00 2001 +From: Jan Kolarik +Date: Fri, 16 Dec 2022 05:55:19 +0000 +Subject: [PATCH] system-upgrade: Show warning always for a downstream + +As the distro package is not available in the BaseOS, the warning implementation will be shown always, but only in related downstreams. + += changelog = +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2152846 +--- + dnf-plugins-core.spec | 3 ++- + plugins/system_upgrade.py | 6 ++---- + 2 files changed, 4 insertions(+), 5 deletions(-) + +diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec +index a5ec165..0e1c9e3 100644 +--- a/dnf-plugins-core.spec ++++ b/dnf-plugins-core.spec +@@ -148,13 +148,14 @@ Summary: Core Plugins for DNF + %{?python_provide:%python_provide python3-%{name}} + BuildRequires: python3-dbus + BuildRequires: python3-devel +-BuildRequires: python3-distro + BuildRequires: python3-dnf >= %{dnf_lowest_compatible} + BuildRequires: python3-systemd + BuildRequires: pkgconfig(systemd) + BuildRequires: systemd + %{?systemd_ordering} ++%if 0%{?fedora} + Requires: python3-distro ++%endif + Requires: python3-dbus + Requires: python3-dnf >= %{dnf_lowest_compatible} + Requires: python3-hawkey >= %{hawkey_version} +diff --git a/plugins/system_upgrade.py b/plugins/system_upgrade.py +index ef1de73..4f7620f 100644 +--- a/plugins/system_upgrade.py ++++ b/plugins/system_upgrade.py +@@ -20,7 +20,6 @@ + """system_upgrade.py - DNF plugin to handle major-version system upgrades.""" + + from subprocess import call, Popen, check_output, CalledProcessError +-import distro + import json + import os + import os.path +@@ -452,9 +451,8 @@ class SystemUpgradeCommand(dnf.cli.Command): + + def configure_download(self): + if 'system-upgrade' == self.opts.command or 'fedup' == self.opts.command: +- if distro.id() == 'rhel': +- logger.warning(_('WARNING: this operation is not supported on the RHEL distribution. ' +- 'Proceed at your own risk.')) ++ logger.warning(_('WARNING: this operation is not supported on the RHEL distribution. ' ++ 'Proceed at your own risk.')) + help_url = get_url_from_os_release() + if help_url: + msg = _('Additional information for System Upgrade: {}') +-- +2.39.0 + diff --git a/SOURCES/0029-Update-translations.patch b/SOURCES/0029-Update-translations.patch new file mode 100644 index 0000000..08781e6 --- /dev/null +++ b/SOURCES/0029-Update-translations.patch @@ -0,0 +1,3803 @@ +From ad97fc64d718ab5aed5e44608a761f2eaf1050f7 Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Wed, 8 Mar 2023 11:22:51 +0100 +Subject: [PATCH] Update translations + +--- + po/dnf-plugins-core.pot | 343 ++++++++++++++++++++----- + po/fr.po | 399 +++++++++++++++++++++++------ + po/ja.po | 417 +++++++++++++++++++++++------- + po/ko.po | 548 ++++++++++++++++++++++++++++------------ + po/zh_CN.po | 388 ++++++++++++++++++++++------ + 5 files changed, 1642 insertions(+), 453 deletions(-) + +diff --git a/po/dnf-plugins-core.pot b/po/dnf-plugins-core.pot +index 3ec9a50..aba1e70 100644 +--- a/po/dnf-plugins-core.pot ++++ b/po/dnf-plugins-core.pot +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2022-02-28 11:53+0100\n" ++"POT-Creation-Date: 2023-02-28 12:21+0100\n" + "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" + "Last-Translator: FULL NAME \n" + "Language-Team: LANGUAGE \n" +@@ -67,16 +67,21 @@ msgstr "" + msgid "Failed to open: '%s', not a valid source rpm file." + msgstr "" + +-#: plugins/builddep.py:204 plugins/builddep.py:220 plugins/builddep.py:237 ++#: plugins/builddep.py:204 plugins/builddep.py:224 plugins/builddep.py:241 + msgid "Not all dependencies satisfied" + msgstr "" + +-#: plugins/builddep.py:211 ++#: plugins/builddep.py:208 ++msgid "" ++"Warning: -D or --define arguments have no meaning for source rpm packages." ++msgstr "" ++ ++#: plugins/builddep.py:215 + #, python-format + msgid "Failed to open: '%s', not a valid spec file: %s" + msgstr "" + +-#: plugins/builddep.py:230 plugins/repoclosure.py:118 ++#: plugins/builddep.py:234 plugins/repoclosure.py:118 + #, python-format + msgid "no package matched: %s" + msgstr "" +@@ -201,27 +206,27 @@ msgstr[1] "" + msgid "Could not save repo to repofile %s: %s" + msgstr "" + +-#: plugins/copr.py:64 ++#: plugins/copr.py:70 + msgid "y" + msgstr "" + +-#: plugins/copr.py:64 ++#: plugins/copr.py:70 + msgid "yes" + msgstr "" + +-#: plugins/copr.py:65 ++#: plugins/copr.py:71 + msgid "n" + msgstr "" + +-#: plugins/copr.py:65 ++#: plugins/copr.py:71 + msgid "no" + msgstr "" + +-#: plugins/copr.py:84 ++#: plugins/copr.py:92 + msgid "Interact with Copr repositories." + msgstr "" + +-#: plugins/copr.py:86 ++#: plugins/copr.py:94 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -242,63 +247,63 @@ msgid "" + " " + msgstr "" + +-#: plugins/copr.py:112 ++#: plugins/copr.py:120 + msgid "List all installed Copr repositories (default)" + msgstr "" + +-#: plugins/copr.py:114 ++#: plugins/copr.py:122 + msgid "List enabled Copr repositories" + msgstr "" + +-#: plugins/copr.py:116 ++#: plugins/copr.py:124 + msgid "List disabled Copr repositories" + msgstr "" + +-#: plugins/copr.py:118 ++#: plugins/copr.py:126 + msgid "List available Copr repositories by user NAME" + msgstr "" + +-#: plugins/copr.py:120 ++#: plugins/copr.py:128 + msgid "Specify an instance of Copr to work with" + msgstr "" + +-#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 ++#: plugins/copr.py:164 plugins/copr.py:236 plugins/copr.py:263 + msgid "Error: " + msgstr "" + +-#: plugins/copr.py:155 ++#: plugins/copr.py:165 + msgid "" + "specify Copr hub either with `--hub` or using `copr_hub/copr_username/" + "copr_projectname` format" + msgstr "" + +-#: plugins/copr.py:158 ++#: plugins/copr.py:168 + msgid "multiple hubs specified" + msgstr "" + +-#: plugins/copr.py:223 plugins/copr.py:227 ++#: plugins/copr.py:237 plugins/copr.py:241 + msgid "exactly two additional parameters to copr command are required" + msgstr "" + +-#: plugins/copr.py:232 ++#: plugins/copr.py:246 + msgid "Too many arguments." + msgstr "" + +-#: plugins/copr.py:235 ++#: plugins/copr.py:249 + msgid "" + "Bad format of optional chroot. The format is distribution-version-" + "architecture." + msgstr "" + +-#: plugins/copr.py:250 ++#: plugins/copr.py:264 + msgid "use format `copr_username/copr_projectname` to reference copr project" + msgstr "" + +-#: plugins/copr.py:252 ++#: plugins/copr.py:266 + msgid "bad copr project format" + msgstr "" + +-#: plugins/copr.py:266 ++#: plugins/copr.py:280 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -314,71 +319,102 @@ msgid "" + "Bugzilla. In case of problems, contact the owner of this repository.\n" + msgstr "" + +-#: plugins/copr.py:283 ++#: plugins/copr.py:297 + msgid "Repository successfully enabled." + msgstr "" + +-#: plugins/copr.py:288 ++#: plugins/copr.py:302 + msgid "Repository successfully disabled." + msgstr "" + +-#: plugins/copr.py:292 ++#: plugins/copr.py:306 + msgid "Repository successfully removed." + msgstr "" + +-#: plugins/copr.py:296 plugins/copr.py:697 ++#: plugins/copr.py:310 plugins/copr.py:721 + msgid "Unknown subcommand {}." + msgstr "" + +-#: plugins/copr.py:353 ++#: plugins/copr.py:367 + msgid "" + "* These coprs have repo file with an old format that contains no information " + "about Copr hub - the default one was assumed. Re-enable the project to fix " + "this." + msgstr "" + +-#: plugins/copr.py:366 ++#: plugins/copr.py:380 + msgid "Can't parse repositories for username '{}'." + msgstr "" + +-#: plugins/copr.py:369 ++#: plugins/copr.py:383 + msgid "List of {} coprs" + msgstr "" + +-#: plugins/copr.py:374 ++#: plugins/copr.py:388 + msgid "No description given" + msgstr "" + +-#: plugins/copr.py:386 ++#: plugins/copr.py:400 + msgid "Can't parse search for '{}'." + msgstr "" + +-#: plugins/copr.py:389 ++#: plugins/copr.py:403 + msgid "Matched: {}" + msgstr "" + +-#: plugins/copr.py:394 ++#: plugins/copr.py:408 + msgid "No description given." + msgstr "" + +-#: plugins/copr.py:416 ++#: plugins/copr.py:430 + msgid "Safe and good answer. Exiting." + msgstr "" + +-#: plugins/copr.py:423 ++#: plugins/copr.py:437 + msgid "This command has to be run under the root user." + msgstr "" + +-#: plugins/copr.py:485 ++#: plugins/copr.py:487 ++#, python-brace-format ++msgid "Request to {0} failed: {1} - {2}" ++msgstr "" ++ ++#: plugins/copr.py:489 ++msgid "It wasn't possible to enable this project.\n" ++msgstr "" ++ ++#: plugins/copr.py:494 ++#, python-brace-format ++msgid "Repository '{0}' does not exist in project '{1}'." ++msgstr "" ++ ++#: plugins/copr.py:497 + msgid "" +-"This repository does not have any builds yet so you cannot enable it now." ++"\n" ++"Available repositories: " ++msgstr "" ++ ++#: plugins/copr.py:499 ++#, python-brace-format ++msgid "" ++"\n" ++"\n" ++"If you want to enable a non-default repository, use the following command:\n" ++" 'dnf copr enable {0} '\n" ++"But note that the installed repo file will likely need a manual modification." + msgstr "" + +-#: plugins/copr.py:488 +-msgid "Such repository does not exist." ++#: plugins/copr.py:505 ++#, python-brace-format ++msgid "Project {0} does not exist." + msgstr "" + +-#: plugins/copr.py:532 ++#: plugins/copr.py:508 ++#, python-brace-format ++msgid "Failed to connect to {0}: {1}" ++msgstr "" ++ ++#: plugins/copr.py:555 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -395,44 +431,44 @@ msgid "" + "These repositories have been enabled automatically." + msgstr "" + +-#: plugins/copr.py:553 ++#: plugins/copr.py:576 + msgid "Do you want to keep them enabled?" + msgstr "" + +-#: plugins/copr.py:586 ++#: plugins/copr.py:609 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" + msgstr "" + +-#: plugins/copr.py:597 ++#: plugins/copr.py:620 + msgid "Failed to disable copr repo {}/{}" + msgstr "" + +-#: plugins/copr.py:615 plugins/copr.py:652 ++#: plugins/copr.py:638 plugins/copr.py:675 + msgid "Unknown response from server." + msgstr "" + +-#: plugins/copr.py:637 ++#: plugins/copr.py:660 + msgid "Interact with Playground repository." + msgstr "" + +-#: plugins/copr.py:643 ++#: plugins/copr.py:666 + msgid "Enabling a Playground repository." + msgstr "" + +-#: plugins/copr.py:644 ++#: plugins/copr.py:667 + msgid "Do you want to continue?" + msgstr "" + +-#: plugins/copr.py:687 ++#: plugins/copr.py:711 + msgid "Playground repositories successfully enabled." + msgstr "" + +-#: plugins/copr.py:690 ++#: plugins/copr.py:714 + msgid "Playground repositories successfully disabled." + msgstr "" + +-#: plugins/copr.py:694 ++#: plugins/copr.py:718 + msgid "Playground repositories successfully updated." + msgstr "" + +@@ -845,18 +881,18 @@ msgid "Bad Action Line \"%s\": %s" + msgstr "" + + #. unsupported state, skip it +-#: plugins/post-transaction-actions.py:130 ++#: plugins/post-transaction-actions.py:133 + #, python-format + msgid "Bad Transaction State: %s" + msgstr "" + +-#: plugins/post-transaction-actions.py:157 +-#: plugins/post-transaction-actions.py:159 ++#: plugins/post-transaction-actions.py:160 ++#: plugins/post-transaction-actions.py:162 + #, python-format + msgid "post-transaction-actions: %s" + msgstr "" + +-#: plugins/post-transaction-actions.py:161 ++#: plugins/post-transaction-actions.py:164 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" + msgstr "" +@@ -1027,31 +1063,43 @@ msgstr "" + msgid "Pass either --old or --new, not both!" + msgstr "" + +-#: plugins/repomanage.py:89 ++#: plugins/repomanage.py:61 ++msgid "Pass either --oldonly or --new, not both!" ++msgstr "" ++ ++#: plugins/repomanage.py:63 ++msgid "Pass either --old or --oldonly, not both!" ++msgstr "" ++ ++#: plugins/repomanage.py:100 + msgid "No files to process" + msgstr "" + +-#: plugins/repomanage.py:96 ++#: plugins/repomanage.py:107 + msgid "Could not open {}" + msgstr "" + +-#: plugins/repomanage.py:180 ++#: plugins/repomanage.py:223 + msgid "Print the older packages" + msgstr "" + +-#: plugins/repomanage.py:182 ++#: plugins/repomanage.py:225 ++msgid "Print the older packages. Exclude the newest packages." ++msgstr "" ++ ++#: plugins/repomanage.py:227 + msgid "Print the newest packages" + msgstr "" + +-#: plugins/repomanage.py:184 ++#: plugins/repomanage.py:229 + msgid "Space separated output, not newline" + msgstr "" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:231 + msgid "Newest N packages to keep - defaults to 1" + msgstr "" + +-#: plugins/repomanage.py:189 ++#: plugins/repomanage.py:234 + msgid "Path to directory" + msgstr "" + +@@ -1153,6 +1201,175 @@ msgstr "" + msgid "New leaves:" + msgstr "" + ++#. Translators: This string is only used in unit tests. ++#: plugins/system_upgrade.py:45 ++msgid "the color of the sky" ++msgstr "" ++ ++#: plugins/system_upgrade.py:57 ++msgid "Need a --releasever greater than the current system version." ++msgstr "" ++ ++#. Translators: do not change "reboot" here ++#: plugins/system_upgrade.py:59 ++#, python-brace-format ++msgid "" ++"Download complete! Use 'dnf {command} reboot' to start the upgrade.\n" ++"To remove cached metadata and transaction use 'dnf {command} clean'" ++msgstr "" ++ ++#: plugins/system_upgrade.py:62 ++msgid "Sorry, you need to use 'download --releasever' instead of '--network'" ++msgstr "" ++ ++#: plugins/system_upgrade.py:71 ++msgid "Reboot turned off, not rebooting." ++msgstr "" ++ ++#: plugins/system_upgrade.py:122 ++#, python-format ++msgid "Screen blanking can't be disabled: %s" ++msgstr "" ++ ++#: plugins/system_upgrade.py:142 ++#, python-format ++msgid "Failed loading state file: %s, continuing with empty state." ++msgstr "" ++ ++#: plugins/system_upgrade.py:289 ++msgid "The following boots appear to contain upgrade logs:" ++msgstr "" ++ ++#: plugins/system_upgrade.py:299 ++msgid "-- no logs were found --" ++msgstr "" ++ ++#: plugins/system_upgrade.py:314 ++msgid "Cannot find logs with this index." ++msgstr "" ++ ++#: plugins/system_upgrade.py:323 ++msgid "Unable to match systemd journal entry" ++msgstr "" ++ ++#: plugins/system_upgrade.py:344 ++msgid "Prepare system for upgrade to a new release" ++msgstr "" ++ ++#: plugins/system_upgrade.py:360 ++msgid "keep installed packages if the new release's version is older" ++msgstr "" ++ ++#: plugins/system_upgrade.py:364 ++msgid "which logs to show" ++msgstr "" ++ ++#: plugins/system_upgrade.py:398 ++#, python-brace-format ++msgid "Incompatible version of data. Rerun 'dnf {command} download [OPTIONS]'" ++msgstr "" ++ ++#: plugins/system_upgrade.py:434 ++msgid "Command 'offline-distrosync' cannot be used with --no-downgrade option" ++msgstr "" ++ ++#: plugins/system_upgrade.py:454 ++msgid "" ++"WARNING: this operation is not supported on the RHEL distribution. Proceed " ++"at your own risk." ++msgstr "" ++ ++#: plugins/system_upgrade.py:458 ++msgid "Additional information for System Upgrade: {}" ++msgstr "" ++ ++#: plugins/system_upgrade.py:461 ++msgid "" ++"Before you continue ensure that your system is fully upgraded by running " ++"\"dnf --refresh upgrade\". Do you want to continue" ++msgstr "" ++ ++#: plugins/system_upgrade.py:465 ++msgid "Operation aborted." ++msgstr "" ++ ++#: plugins/system_upgrade.py:526 ++msgid "system is not ready for upgrade" ++msgstr "" ++ ++#: plugins/system_upgrade.py:529 ++#, python-brace-format ++msgid "" ++"the transaction was not prepared for '{command}'. Rerun 'dnf {command} " ++"download [OPTIONS]'" ++msgstr "" ++ ++#: plugins/system_upgrade.py:533 ++msgid "upgrade is already scheduled" ++msgstr "" ++ ++#: plugins/system_upgrade.py:539 ++msgid "trigger file does not exist. exiting quietly." ++msgstr "" ++ ++#: plugins/system_upgrade.py:542 ++msgid "another upgrade tool is running. exiting quietly." ++msgstr "" ++ ++#: plugins/system_upgrade.py:551 ++#, python-brace-format ++msgid "use 'dnf {command} reboot' to begin the upgrade" ++msgstr "" ++ ++#: plugins/system_upgrade.py:569 ++msgid "Rebooting to perform upgrade." ++msgstr "" ++ ++#: plugins/system_upgrade.py:602 ++msgid "Starting offline upgrade. This will take a while." ++msgstr "" ++ ++#: plugins/system_upgrade.py:604 ++msgid "Starting offline distrosync. This will take a while." ++msgstr "" ++ ++#: plugins/system_upgrade.py:606 ++msgid "Starting system upgrade. This will take a while." ++msgstr "" ++ ++#: plugins/system_upgrade.py:622 ++msgid "Cleaning up downloaded data..." ++msgstr "" ++ ++#: plugins/system_upgrade.py:652 ++msgid "" ++"The system-upgrade transaction is empty, your system is already up-to-date." ++msgstr "" ++ ++#: plugins/system_upgrade.py:661 ++msgid "Transaction saved to {}." ++msgstr "" ++ ++#: plugins/system_upgrade.py:664 ++msgid "Error storing transaction: {}" ++msgstr "" ++ ++#: plugins/system_upgrade.py:686 ++msgid "Download finished." ++msgstr "" ++ ++#: plugins/system_upgrade.py:689 plugins/system_upgrade.py:690 ++msgid "Upgrade complete! Cleaning up and rebooting..." ++msgstr "" ++ ++#: plugins/system_upgrade.py:699 ++msgid "Prepare offline upgrade of the system" ++msgstr "" ++ ++#: plugins/system_upgrade.py:704 ++msgid "Prepare offline distrosync of the system" ++msgstr "" ++ + #: plugins/versionlock.py:33 + #, python-format + msgid "Unable to read version lock configuration: %s" +diff --git a/po/fr.po b/po/fr.po +index f70bfb2..153eb56 100644 +--- a/po/fr.po ++++ b/po/fr.po +@@ -7,14 +7,15 @@ + # Jean-Baptiste Holcroft , 2019. #zanata, 2020. + # Julien Humbert , 2020. + # Sundeep Anand , 2021. +-# Transtats , 2022. ++# Transtats , 2022, 2023. ++# blutch112 , 2022. + msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2022-02-28 11:53+0100\n" +-"PO-Revision-Date: 2022-03-09 12:39+0000\n" +-"Last-Translator: Ludek Janda \n" ++"POT-Creation-Date: 2023-02-28 12:21+0100\n" ++"PO-Revision-Date: 2023-03-06 13:48+0000\n" ++"Last-Translator: Transtats \n" + "Language-Team: French \n" + "Language: fr\n" +@@ -22,7 +23,7 @@ msgstr "" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=2; plural=n > 1;\n" +-"X-Generator: Weblate 4.11.2\n" ++"X-Generator: Weblate 4.15.2\n" + + #: plugins/builddep.py:45 + msgid "[PACKAGE|PACKAGE.spec]" +@@ -73,16 +74,23 @@ msgstr "Aucun paquet correspondant à installer : « %s »" + msgid "Failed to open: '%s', not a valid source rpm file." + msgstr "Échec d’ouverture : « %s », n’est pas un fichier source rpm valide." + +-#: plugins/builddep.py:204 plugins/builddep.py:220 plugins/builddep.py:237 ++#: plugins/builddep.py:204 plugins/builddep.py:224 plugins/builddep.py:241 + msgid "Not all dependencies satisfied" + msgstr "Toutes les dépendances ne sont pas satisfaites" + +-#: plugins/builddep.py:211 ++#: plugins/builddep.py:208 ++msgid "" ++"Warning: -D or --define arguments have no meaning for source rpm packages." ++msgstr "" ++"Attention : les arguments -D ou --define n'ont aucune signification pour les " ++"paquets rpm source." ++ ++#: plugins/builddep.py:215 + #, python-format + msgid "Failed to open: '%s', not a valid spec file: %s" + msgstr "Échec à l’ouverture de « %s », %s n’est pas un fichier spec valide" + +-#: plugins/builddep.py:230 plugins/repoclosure.py:118 ++#: plugins/builddep.py:234 plugins/repoclosure.py:118 + #, python-format + msgid "no package matched: %s" + msgstr "aucun paquet ne correspond à : %s" +@@ -219,27 +227,27 @@ msgstr[1] "La configuration des dépôts a échoué" + msgid "Could not save repo to repofile %s: %s" + msgstr "Sauvegarde impossible du dépôt dans le fichier du dépôt %s : %s" + +-#: plugins/copr.py:64 ++#: plugins/copr.py:70 + msgid "y" + msgstr "o" + +-#: plugins/copr.py:64 ++#: plugins/copr.py:70 + msgid "yes" + msgstr "oui" + +-#: plugins/copr.py:65 ++#: plugins/copr.py:71 + msgid "n" + msgstr "n" + +-#: plugins/copr.py:65 ++#: plugins/copr.py:71 + msgid "no" + msgstr "non" + +-#: plugins/copr.py:84 ++#: plugins/copr.py:92 + msgid "Interact with Copr repositories." + msgstr "Interagit avec les dépôts Copr." + +-#: plugins/copr.py:86 ++#: plugins/copr.py:94 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -277,31 +285,31 @@ msgstr "" + " copr search tests\n" + " " + +-#: plugins/copr.py:112 ++#: plugins/copr.py:120 + msgid "List all installed Copr repositories (default)" + msgstr "Lister tous les dépôts Copr installés (par défaut)" + +-#: plugins/copr.py:114 ++#: plugins/copr.py:122 + msgid "List enabled Copr repositories" + msgstr "Lister les dépôts Copr activés" + +-#: plugins/copr.py:116 ++#: plugins/copr.py:124 + msgid "List disabled Copr repositories" + msgstr "Lister les dépôts Copr désactivés" + +-#: plugins/copr.py:118 ++#: plugins/copr.py:126 + msgid "List available Copr repositories by user NAME" + msgstr "Lister les dépôts Copr disponibles par NOM d’utilisateur" + +-#: plugins/copr.py:120 ++#: plugins/copr.py:128 + msgid "Specify an instance of Copr to work with" + msgstr "Précisez une instance Copr avec laquelle travailler" + +-#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 ++#: plugins/copr.py:164 plugins/copr.py:236 plugins/copr.py:263 + msgid "Error: " + msgstr "Erreur : " + +-#: plugins/copr.py:155 ++#: plugins/copr.py:165 + msgid "" + "specify Copr hub either with `--hub` or using `copr_hub/copr_username/" + "copr_projectname` format" +@@ -309,19 +317,19 @@ msgstr "" + "précisez un hub Copr soit via `--hub` ou en utilisant le format `hub_copr/" + "utilisateur_copr/projet_copr`" + +-#: plugins/copr.py:158 ++#: plugins/copr.py:168 + msgid "multiple hubs specified" + msgstr "de multiples hubs ont été renseignés" + +-#: plugins/copr.py:223 plugins/copr.py:227 ++#: plugins/copr.py:237 plugins/copr.py:241 + msgid "exactly two additional parameters to copr command are required" + msgstr "la commande copr requiert exactement deux paramètres additionnels" + +-#: plugins/copr.py:232 ++#: plugins/copr.py:246 + msgid "Too many arguments." + msgstr "Trop d'arguments." + +-#: plugins/copr.py:235 ++#: plugins/copr.py:249 + msgid "" + "Bad format of optional chroot. The format is distribution-version-" + "architecture." +@@ -329,17 +337,17 @@ msgstr "" + "Mauvais format du chroot optionnel. Le format est distribution-version-" + "architecture." + +-#: plugins/copr.py:250 ++#: plugins/copr.py:264 + msgid "use format `copr_username/copr_projectname` to reference copr project" + msgstr "" + "utilisez le format `copr_username/copr_projectname` pour faire référence au " + "projet copr" + +-#: plugins/copr.py:252 ++#: plugins/copr.py:266 + msgid "bad copr project format" + msgstr "mauvais format de projet copr" + +-#: plugins/copr.py:266 ++#: plugins/copr.py:280 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -368,23 +376,23 @@ msgstr "" + "de Fedora.\n" + "En cas de problèmes, contactez le propriétaire de ce dépôt.\n" + +-#: plugins/copr.py:283 ++#: plugins/copr.py:297 + msgid "Repository successfully enabled." + msgstr "Activation du dépôt réussie." + +-#: plugins/copr.py:288 ++#: plugins/copr.py:302 + msgid "Repository successfully disabled." + msgstr "Désactivation du dépôt réussie." + +-#: plugins/copr.py:292 ++#: plugins/copr.py:306 + msgid "Repository successfully removed." + msgstr "Suppression du dépôt réussie." + +-#: plugins/copr.py:296 plugins/copr.py:697 ++#: plugins/copr.py:310 plugins/copr.py:721 + msgid "Unknown subcommand {}." + msgstr "Sous-commande inconnue {}." + +-#: plugins/copr.py:353 ++#: plugins/copr.py:367 + msgid "" + "* These coprs have repo file with an old format that contains no information " + "about Copr hub - the default one was assumed. Re-enable the project to fix " +@@ -394,51 +402,89 @@ msgstr "" + "aucune information à propos de Copr hub - celui par défaut a été utilisé. " + "Réactivez le projet pour résoudre le problème." + +-#: plugins/copr.py:366 ++#: plugins/copr.py:380 + msgid "Can't parse repositories for username '{}'." + msgstr "" + "Ne peut analyser les dépôts pour y chercher le nom d’utilisateur « {} »." + +-#: plugins/copr.py:369 ++#: plugins/copr.py:383 + msgid "List of {} coprs" + msgstr "Liste de {} coprs" + +-#: plugins/copr.py:374 ++#: plugins/copr.py:388 + msgid "No description given" + msgstr "Aucune description fournie" + +-#: plugins/copr.py:386 ++#: plugins/copr.py:400 + msgid "Can't parse search for '{}'." + msgstr "Impossible d’analyser la recherche pour « {} »." + +-#: plugins/copr.py:389 ++#: plugins/copr.py:403 + msgid "Matched: {}" + msgstr "Correspondance : {}" + +-#: plugins/copr.py:394 ++#: plugins/copr.py:408 + msgid "No description given." + msgstr "Pas de description fournie." + +-#: plugins/copr.py:416 ++#: plugins/copr.py:430 + msgid "Safe and good answer. Exiting." + msgstr "Réponse sûre et exacte. Fin." + +-#: plugins/copr.py:423 ++#: plugins/copr.py:437 + msgid "This command has to be run under the root user." + msgstr "Cette commande requiert les privilèges du super utilisateur." + +-#: plugins/copr.py:485 ++#: plugins/copr.py:487 ++#, python-brace-format ++msgid "Request to {0} failed: {1} - {2}" ++msgstr "La demande à {0} a échoué : {1} - {2}" ++ ++#: plugins/copr.py:489 ++msgid "It wasn't possible to enable this project.\n" ++msgstr "Il n'a pas été possible d'activer ce projet.\n" ++ ++#: plugins/copr.py:494 ++#, python-brace-format ++msgid "Repository '{0}' does not exist in project '{1}'." ++msgstr "Le référentiel '{0}' n'existe pas dans le projet '{1}'." ++ ++#: plugins/copr.py:497 + msgid "" +-"This repository does not have any builds yet so you cannot enable it now." ++"\n" ++"Available repositories: " ++msgstr "" ++"\n" ++"Dépôts disponibles : " ++ ++#: plugins/copr.py:499 ++#, python-brace-format ++msgid "" ++"\n" ++"\n" ++"If you want to enable a non-default repository, use the following command:\n" ++" 'dnf copr enable {0} '\n" ++"But note that the installed repo file will likely need a manual modification." + msgstr "" +-"Ce dépôt ne contient pas encore d’exécutables vous ne pouvez donc pas " +-"l’activer." ++"\n" ++"\n" ++"Si vous voulez activer un référentiel autre que celui par défaut, utilisez " ++"la commande suivante :\n" ++" 'dnf copr enable {0} '\n" ++"Mais notez que le fichier repo installé devra probablement être modifié " ++"manuellement." + +-#: plugins/copr.py:488 +-msgid "Such repository does not exist." +-msgstr "Ce dépôt n’existe pas." ++#: plugins/copr.py:505 ++#, python-brace-format ++msgid "Project {0} does not exist." ++msgstr "Le projet {0} n'existe pas." + +-#: plugins/copr.py:532 ++#: plugins/copr.py:508 ++#, python-brace-format ++msgid "Failed to connect to {0}: {1}" ++msgstr "Échec de la connexion à {0} : {1}" ++ ++#: plugins/copr.py:555 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -467,44 +513,44 @@ msgstr "" + "\n" + "Ces dépôts ont été activés automatiquement." + +-#: plugins/copr.py:553 ++#: plugins/copr.py:576 + msgid "Do you want to keep them enabled?" + msgstr "Souhaitez-vous les maintenir activés ?" + +-#: plugins/copr.py:586 ++#: plugins/copr.py:609 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" + msgstr "Échec de la suppression du dépôt Copr {0}/{1}/{2}" + +-#: plugins/copr.py:597 ++#: plugins/copr.py:620 + msgid "Failed to disable copr repo {}/{}" + msgstr "Échec de la désactivation du dépôt copr {}/{}" + +-#: plugins/copr.py:615 plugins/copr.py:652 ++#: plugins/copr.py:638 plugins/copr.py:675 + msgid "Unknown response from server." + msgstr "Réponse inconnue du serveur." + +-#: plugins/copr.py:637 ++#: plugins/copr.py:660 + msgid "Interact with Playground repository." + msgstr "Interagit avec le dépôt Playground." + +-#: plugins/copr.py:643 ++#: plugins/copr.py:666 + msgid "Enabling a Playground repository." + msgstr "Activation d’un dépôt Playground." + +-#: plugins/copr.py:644 ++#: plugins/copr.py:667 + msgid "Do you want to continue?" + msgstr "Souhaitez-vous continuer ?" + +-#: plugins/copr.py:687 ++#: plugins/copr.py:711 + msgid "Playground repositories successfully enabled." + msgstr "Activation des dépôts Playground réussie." + +-#: plugins/copr.py:690 ++#: plugins/copr.py:714 + msgid "Playground repositories successfully disabled." + msgstr "Désactivation des dépôts Playground réussie." + +-#: plugins/copr.py:694 ++#: plugins/copr.py:718 + msgid "Playground repositories successfully updated." + msgstr "Mise à jour des dépôts Playground réussie." + +@@ -887,7 +933,7 @@ msgstr "" + + #: plugins/modulesync.py:166 + msgid "No mach for argument '{}'" +-msgstr "Pas de correspondance pour l'argument '{}'" ++msgstr "Aucune correspondance pour l'argument '{}'" + + #. TODO(jmracek) Shell we end with an error or with RC 1? + #: plugins/modulesync.py:198 +@@ -954,18 +1000,18 @@ msgid "Bad Action Line \"%s\": %s" + msgstr "Mauvaise ligne d’action « %s » : %s" + + #. unsupported state, skip it +-#: plugins/post-transaction-actions.py:130 ++#: plugins/post-transaction-actions.py:133 + #, python-format + msgid "Bad Transaction State: %s" + msgstr "Mauvais état de transaction : %s" + +-#: plugins/post-transaction-actions.py:157 +-#: plugins/post-transaction-actions.py:159 ++#: plugins/post-transaction-actions.py:160 ++#: plugins/post-transaction-actions.py:162 + #, python-format + msgid "post-transaction-actions: %s" + msgstr "post-transaction-actions : %s" + +-#: plugins/post-transaction-actions.py:161 ++#: plugins/post-transaction-actions.py:164 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" + msgstr "post-transaction-actions : mauvaise commande « %s » : %s" +@@ -1152,31 +1198,43 @@ msgstr "Gère un dossier de paquets rpm" + msgid "Pass either --old or --new, not both!" + msgstr "Passez soit --old, soit --new, mais pas les deux !" + +-#: plugins/repomanage.py:89 ++#: plugins/repomanage.py:61 ++msgid "Pass either --oldonly or --new, not both!" ++msgstr "Passez soit --oldonly, soit --new, mais pas les deux !" ++ ++#: plugins/repomanage.py:63 ++msgid "Pass either --old or --oldonly, not both!" ++msgstr "Passez --old ou --oldonly, mais pas les deux !" ++ ++#: plugins/repomanage.py:100 + msgid "No files to process" + msgstr "Aucun fichier à traiter" + +-#: plugins/repomanage.py:96 ++#: plugins/repomanage.py:107 + msgid "Could not open {}" + msgstr "Ouverture de {} impossible" + +-#: plugins/repomanage.py:180 ++#: plugins/repomanage.py:223 + msgid "Print the older packages" + msgstr "Afficher les paquets plus anciens" + +-#: plugins/repomanage.py:182 ++#: plugins/repomanage.py:225 ++msgid "Print the older packages. Exclude the newest packages." ++msgstr "Afficher les anciens paquets. Exclure les paquets les plus récents." ++ ++#: plugins/repomanage.py:227 + msgid "Print the newest packages" + msgstr "Afficher les paquets les plus récents" + +-#: plugins/repomanage.py:184 ++#: plugins/repomanage.py:229 + msgid "Space separated output, not newline" + msgstr "Sorties séparées par des espaces plutôt que des retours à la ligne" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:231 + msgid "Newest N packages to keep - defaults to 1" + msgstr "N paquets les plus récents à conserver — par défaut 1" + +-#: plugins/repomanage.py:189 ++#: plugins/repomanage.py:234 + msgid "Path to directory" + msgstr "Chemin vers le répertoire" + +@@ -1287,6 +1345,199 @@ msgstr "comps.xml pour le dépôt %s sauvegardé" + msgid "New leaves:" + msgstr "Nouvelles feuilles :" + ++#. Translators: This string is only used in unit tests. ++#: plugins/system_upgrade.py:45 ++msgid "the color of the sky" ++msgstr "la couleur du ciel" ++ ++#: plugins/system_upgrade.py:57 ++msgid "Need a --releasever greater than the current system version." ++msgstr "Besoin d'un --releasever supérieur à la version actuelle du système." ++ ++#. Translators: do not change "reboot" here ++#: plugins/system_upgrade.py:59 ++#, python-brace-format ++msgid "" ++"Download complete! Use 'dnf {command} reboot' to start the upgrade.\n" ++"To remove cached metadata and transaction use 'dnf {command} clean'" ++msgstr "" ++"Téléchargement terminé ! Utilisez 'dnf {command} reboot' pour démarrer la " ++"mise à jour.\n" ++"Pour supprimer les métadonnées mises en cache et les transactions, utilisez " ++"'dnf {command} clean'’" ++ ++#: plugins/system_upgrade.py:62 ++msgid "Sorry, you need to use 'download --releasever' instead of '--network'" ++msgstr "" ++"Désolé, vous devez utiliser 'download --releasever' au lieu de '--network'’" ++ ++#: plugins/system_upgrade.py:71 ++msgid "Reboot turned off, not rebooting." ++msgstr "Redémarrage désactivé, pas de redémarrage." ++ ++#: plugins/system_upgrade.py:122 ++#, python-format ++msgid "Screen blanking can't be disabled: %s" ++msgstr "L'effacement d'écran ne peut pas être désactivé : %s" ++ ++#: plugins/system_upgrade.py:142 ++#, python-format ++msgid "Failed loading state file: %s, continuing with empty state." ++msgstr "" ++"Échec du chargement du fichier d'état : %s, continuer avec un état vide." ++ ++#: plugins/system_upgrade.py:289 ++msgid "The following boots appear to contain upgrade logs:" ++msgstr "" ++"Les démarrages suivants semblent contenir des journaux de mise à niveau :" ++ ++#: plugins/system_upgrade.py:299 ++msgid "-- no logs were found --" ++msgstr "-- aucun journal n'a été trouvé --" ++ ++#: plugins/system_upgrade.py:314 ++msgid "Cannot find logs with this index." ++msgstr "Impossible de trouver des journaux avec cet index." ++ ++#: plugins/system_upgrade.py:323 ++msgid "Unable to match systemd journal entry" ++msgstr "Impossible de faire correspondre l'entrée du journal de systemd" ++ ++#: plugins/system_upgrade.py:344 ++msgid "Prepare system for upgrade to a new release" ++msgstr "Préparer le système pour la mise à niveau vers une nouvelle version" ++ ++#: plugins/system_upgrade.py:360 ++msgid "keep installed packages if the new release's version is older" ++msgstr "" ++"Conserver les paquets installés si la version de la nouvelle version est " ++"plus ancienne" ++ ++#: plugins/system_upgrade.py:364 ++msgid "which logs to show" ++msgstr "Quels journaux afficher" ++ ++#: plugins/system_upgrade.py:398 ++#, python-brace-format ++msgid "Incompatible version of data. Rerun 'dnf {command} download [OPTIONS]'" ++msgstr "" ++"Version incompatible des données. Relancez 'dnf {command} download " ++"[OPTIONS]'’" ++ ++#: plugins/system_upgrade.py:434 ++msgid "Command 'offline-distrosync' cannot be used with --no-downgrade option" ++msgstr "" ++"La commande 'offline-distrosync' ne peut pas être utilisée avec l'option " ++"--no-downgrade" ++ ++#: plugins/system_upgrade.py:454 ++msgid "" ++"WARNING: this operation is not supported on the RHEL distribution. Proceed " ++"at your own risk." ++msgstr "" ++"AVERTISSEMENT : cette opération n'est pas prise en charge sur la " ++"distribution RHEL. Procédez à vos propres risques." ++ ++#: plugins/system_upgrade.py:458 ++msgid "Additional information for System Upgrade: {}" ++msgstr "Informations supplémentaires pour la mise à niveau du système : {}" ++ ++#: plugins/system_upgrade.py:461 ++msgid "" ++"Before you continue ensure that your system is fully upgraded by running " ++"\"dnf --refresh upgrade\". Do you want to continue" ++msgstr "" ++"Avant de continuer, assurez-vous que votre système est entièrement mis à " ++"jour en exécutant \"dnf --refresh upgrade\". Voulez-vous continuer" ++ ++#: plugins/system_upgrade.py:465 ++msgid "Operation aborted." ++msgstr "Opération avortée." ++ ++#: plugins/system_upgrade.py:526 ++msgid "system is not ready for upgrade" ++msgstr "Le système n'est pas prêt pour la mise à niveau" ++ ++#: plugins/system_upgrade.py:529 ++#, python-brace-format ++msgid "" ++"the transaction was not prepared for '{command}'. Rerun 'dnf {command} " ++"download [OPTIONS]'" ++msgstr "" ++"La transaction n'a pas été préparée pour '{command}'. Relancez 'dnf {command}" ++" download [OPTIONS]'" ++ ++#: plugins/system_upgrade.py:533 ++msgid "upgrade is already scheduled" ++msgstr "la mise à niveau est déjà prévue" ++ ++#: plugins/system_upgrade.py:539 ++msgid "trigger file does not exist. exiting quietly." ++msgstr "Le fichier de déclenchement n'existe pas. Il se termine tranquillement." ++ ++#: plugins/system_upgrade.py:542 ++msgid "another upgrade tool is running. exiting quietly." ++msgstr "" ++"Un autre outil de mise à niveau est en cours d'exécution. il se termine " ++"tranquillement." ++ ++#: plugins/system_upgrade.py:551 ++#, python-brace-format ++msgid "use 'dnf {command} reboot' to begin the upgrade" ++msgstr "Utilisez 'dnf {command} reboot' pour commencer la mise à jour" ++ ++#: plugins/system_upgrade.py:569 ++msgid "Rebooting to perform upgrade." ++msgstr "Redémarrage pour effectuer la mise à niveau." ++ ++#: plugins/system_upgrade.py:602 ++msgid "Starting offline upgrade. This will take a while." ++msgstr "" ++"Je commence la mise à jour hors ligne. Cela va prendre un certain temps." ++ ++#: plugins/system_upgrade.py:604 ++msgid "Starting offline distrosync. This will take a while." ++msgstr "" ++"Démarrage de la distrosync hors ligne. Cela va prendre un certain temps." ++ ++#: plugins/system_upgrade.py:606 ++msgid "Starting system upgrade. This will take a while." ++msgstr "" ++"Je commence la mise à jour du système. Cela va prendre un certain temps." ++ ++#: plugins/system_upgrade.py:622 ++msgid "Cleaning up downloaded data..." ++msgstr "Nettoyage des données téléchargées..." ++ ++#: plugins/system_upgrade.py:652 ++msgid "" ++"The system-upgrade transaction is empty, your system is already up-to-date." ++msgstr "La transaction system-upgrade est vide, votre système est déjà à jour." ++ ++#: plugins/system_upgrade.py:661 ++msgid "Transaction saved to {}." ++msgstr "Transaction enregistrée vers {}." ++ ++#: plugins/system_upgrade.py:664 ++msgid "Error storing transaction: {}" ++msgstr "Erreur lors du stockage de la transaction : {}" ++ ++#: plugins/system_upgrade.py:686 ++msgid "Download finished." ++msgstr "Téléchargement terminé." ++ ++#: plugins/system_upgrade.py:689 plugins/system_upgrade.py:690 ++msgid "Upgrade complete! Cleaning up and rebooting..." ++msgstr "Mise à jour terminée ! Nettoyage et redémarrage..." ++ ++#: plugins/system_upgrade.py:699 ++msgid "Prepare offline upgrade of the system" ++msgstr "Préparer la mise à niveau hors ligne du système" ++ ++#: plugins/system_upgrade.py:704 ++msgid "Prepare offline distrosync of the system" ++msgstr "Préparer la distrosynchronisation hors ligne du système" ++ + #: plugins/versionlock.py:33 + #, python-format + msgid "Unable to read version lock configuration: %s" +@@ -1361,6 +1612,12 @@ msgstr "" + "La sous-commande '{}' est obsolète. Utilisez plutôt la sous-commande " + "'exclude'." + ++#~ msgid "" ++#~ "This repository does not have any builds yet so you cannot enable it now." ++#~ msgstr "" ++#~ "Ce dépôt ne contient pas encore d’exécutables vous ne pouvez donc pas " ++#~ "l’activer." ++ + #~ msgid "" + #~ "\n" + #~ "These repositories have been enabled automatically.\n" +diff --git a/po/ja.po b/po/ja.po +index c5c4691..2119fbe 100644 +--- a/po/ja.po ++++ b/po/ja.po +@@ -1,15 +1,15 @@ + # Ooyama Yosiyuki , 2015. #zanata +-# Ludek Janda , 2018. #zanata, 2021. ++# Ludek Janda , 2018. #zanata, 2021, 2023. + # Casey Jones , 2020. + # Sundeep Anand , 2021. +-# Transtats , 2022. ++# Transtats , 2022, 2023. + msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2022-02-28 11:53+0100\n" +-"PO-Revision-Date: 2022-03-09 12:39+0000\n" +-"Last-Translator: Transtats \n" ++"POT-Creation-Date: 2023-02-28 12:21+0100\n" ++"PO-Revision-Date: 2023-03-06 13:48+0000\n" ++"Last-Translator: Ludek Janda \n" + "Language-Team: Japanese \n" + "Language: ja\n" +@@ -17,7 +17,7 @@ msgstr "" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=1; plural=0;\n" +-"X-Generator: Weblate 4.11.2\n" ++"X-Generator: Weblate 4.15.2\n" + + #: plugins/builddep.py:45 + msgid "[PACKAGE|PACKAGE.spec]" +@@ -69,16 +69,22 @@ msgid "Failed to open: '%s', not a valid source rpm file." + msgstr "" + "開くことに失敗しました: '%s'、有効なソース rpm ファイルではありません。" + +-#: plugins/builddep.py:204 plugins/builddep.py:220 plugins/builddep.py:237 ++#: plugins/builddep.py:204 plugins/builddep.py:224 plugins/builddep.py:241 + msgid "Not all dependencies satisfied" + msgstr "すべての依存関係が満たされているわけではない" + +-#: plugins/builddep.py:211 ++#: plugins/builddep.py:208 ++msgid "" ++"Warning: -D or --define arguments have no meaning for source rpm packages." ++msgstr "警告: -D または --define 引数には、ソース rpm " ++"パッケージに対する意味はありません。" ++ ++#: plugins/builddep.py:215 + #, python-format + msgid "Failed to open: '%s', not a valid spec file: %s" + msgstr "開くことに失敗しました: '%s'、有効なスペックファイルではありません: %s" + +-#: plugins/builddep.py:230 plugins/repoclosure.py:118 ++#: plugins/builddep.py:234 plugins/repoclosure.py:118 + #, python-format + msgid "no package matched: %s" + msgstr "一致するパッケージはありません: %s" +@@ -209,27 +215,27 @@ msgstr[0] "repo の設定に失敗しました" + msgid "Could not save repo to repofile %s: %s" + msgstr "repofile %s に repo を保存できませんでした: %s" + +-#: plugins/copr.py:64 ++#: plugins/copr.py:70 + msgid "y" + msgstr "y" + +-#: plugins/copr.py:64 ++#: plugins/copr.py:70 + msgid "yes" + msgstr "はい" + +-#: plugins/copr.py:65 ++#: plugins/copr.py:71 + msgid "n" + msgstr "n" + +-#: plugins/copr.py:65 ++#: plugins/copr.py:71 + msgid "no" + msgstr "いいえ" + +-#: plugins/copr.py:84 ++#: plugins/copr.py:92 + msgid "Interact with Copr repositories." + msgstr "Copr リポジトリーとの対話。" + +-#: plugins/copr.py:86 ++#: plugins/copr.py:94 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -267,32 +273,32 @@ msgstr "" + " copr search tests\n" + " " + +-#: plugins/copr.py:112 ++#: plugins/copr.py:120 + msgid "List all installed Copr repositories (default)" + msgstr "" + "インストール済みのすべての Copr リポジトリーを一覧表示します (デフォルト)" + +-#: plugins/copr.py:114 ++#: plugins/copr.py:122 + msgid "List enabled Copr repositories" + msgstr "有効化された Copr リポジトリーを一覧表示します" + +-#: plugins/copr.py:116 ++#: plugins/copr.py:124 + msgid "List disabled Copr repositories" + msgstr "無効化された Copr リポジトリーを一覧表示します" + +-#: plugins/copr.py:118 ++#: plugins/copr.py:126 + msgid "List available Copr repositories by user NAME" + msgstr "利用可能な Copr リポジトリーをユーザー NAME ごとに一覧表示します" + +-#: plugins/copr.py:120 ++#: plugins/copr.py:128 + msgid "Specify an instance of Copr to work with" + msgstr "作業する Copr のインスタンスを指定します" + +-#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 ++#: plugins/copr.py:164 plugins/copr.py:236 plugins/copr.py:263 + msgid "Error: " + msgstr "エラー: " + +-#: plugins/copr.py:155 ++#: plugins/copr.py:165 + msgid "" + "specify Copr hub either with `--hub` or using `copr_hub/copr_username/" + "copr_projectname` format" +@@ -300,36 +306,37 @@ msgstr "" + "`--hub` または `copr_hub/copr_username/copr_projectname` フォーマットを使っ" + "て、Copr ハブを指定します" + +-#: plugins/copr.py:158 ++#: plugins/copr.py:168 + msgid "multiple hubs specified" + msgstr "複数のハブが指定されています" + +-#: plugins/copr.py:223 plugins/copr.py:227 ++#: plugins/copr.py:237 plugins/copr.py:241 + msgid "exactly two additional parameters to copr command are required" + msgstr "copr コマンドに厳密に 2 つの追加パラメーターが必要です" + +-#: plugins/copr.py:232 ++#: plugins/copr.py:246 + msgid "Too many arguments." + msgstr "引数が多すぎます。" + +-#: plugins/copr.py:235 ++#: plugins/copr.py:249 + msgid "" + "Bad format of optional chroot. The format is distribution-version-" + "architecture." +-msgstr "オプションの chroot の形式が無効です。正しい形式は distribution-version-" ++msgstr "" ++"オプションの chroot の形式が無効です。正しい形式は distribution-version-" + "architecture です。" + +-#: plugins/copr.py:250 ++#: plugins/copr.py:264 + msgid "use format `copr_username/copr_projectname` to reference copr project" + msgstr "" + "copr プロジェクトを参照するには `copr_username/copr_projectname` 形式を使用し" + "ます" + +-#: plugins/copr.py:252 ++#: plugins/copr.py:266 + msgid "bad copr project format" + msgstr "不正な copr プロジェクト形式" + +-#: plugins/copr.py:266 ++#: plugins/copr.py:280 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -358,23 +365,23 @@ msgstr "" + "Fedora Bugzilla でこれらのパッケージに関するバグ報告をしないでください。\n" + "問題が発生した場合は、このリポジトリーのオーナーに連絡してください。\n" + +-#: plugins/copr.py:283 ++#: plugins/copr.py:297 + msgid "Repository successfully enabled." + msgstr "リポジトリが正常に有効化されました。" + +-#: plugins/copr.py:288 ++#: plugins/copr.py:302 + msgid "Repository successfully disabled." + msgstr "リポジトリが正常に無効化されました。" + +-#: plugins/copr.py:292 ++#: plugins/copr.py:306 + msgid "Repository successfully removed." + msgstr "リポジトリーが正常に削除されました。" + +-#: plugins/copr.py:296 plugins/copr.py:697 ++#: plugins/copr.py:310 plugins/copr.py:721 + msgid "Unknown subcommand {}." + msgstr "不明なサブコマンド {}。" + +-#: plugins/copr.py:353 ++#: plugins/copr.py:367 + msgid "" + "* These coprs have repo file with an old format that contains no information " + "about Copr hub - the default one was assumed. Re-enable the project to fix " +@@ -384,49 +391,87 @@ msgstr "" + "ファイルがあります。デフォルトは仮定です。これを修正するには、プロジェクトを" + "再度有効化してください。" + +-#: plugins/copr.py:366 ++#: plugins/copr.py:380 + msgid "Can't parse repositories for username '{}'." + msgstr "ユーザー名 '{}' のリポジトリーを解析できません。" + +-#: plugins/copr.py:369 ++#: plugins/copr.py:383 + msgid "List of {} coprs" + msgstr "{} coprs の一覧" + +-#: plugins/copr.py:374 ++#: plugins/copr.py:388 + msgid "No description given" + msgstr "説明がありません" + +-#: plugins/copr.py:386 ++#: plugins/copr.py:400 + msgid "Can't parse search for '{}'." + msgstr "'{}' の検索を解析できません。" + +-#: plugins/copr.py:389 ++#: plugins/copr.py:403 + msgid "Matched: {}" + msgstr "一致: {}" + +-#: plugins/copr.py:394 ++#: plugins/copr.py:408 + msgid "No description given." + msgstr "説明が与えられていません。" + +-#: plugins/copr.py:416 ++#: plugins/copr.py:430 + msgid "Safe and good answer. Exiting." + msgstr "安全で優れた回答。終了中。" + +-#: plugins/copr.py:423 ++#: plugins/copr.py:437 + msgid "This command has to be run under the root user." + msgstr "このコマンドは root ユーザーの下で実行する必要があります。" + +-#: plugins/copr.py:485 ++#: plugins/copr.py:487 ++#, python-brace-format ++msgid "Request to {0} failed: {1} - {2}" ++msgstr "{0} へのリクエストに失敗しました: {1} - {2}" ++ ++#: plugins/copr.py:489 ++msgid "It wasn't possible to enable this project.\n" ++msgstr "このプロジェクトを有効にすることができませんでした。\n" ++ ++#: plugins/copr.py:494 ++#, python-brace-format ++msgid "Repository '{0}' does not exist in project '{1}'." ++msgstr "'{0}' リポジトリーはプロジェクト '{1}' に存在しません。" ++ ++#: plugins/copr.py:497 + msgid "" +-"This repository does not have any builds yet so you cannot enable it now." ++"\n" ++"Available repositories: " + msgstr "" +-"このリポジトリーにはまだビルドがありませんので、今すぐ有効化できません。" ++"\n" ++"利用可能なリポジトリー: " ++ ++#: plugins/copr.py:499 ++#, python-brace-format ++msgid "" ++"\n" ++"\n" ++"If you want to enable a non-default repository, use the following command:\n" ++" 'dnf copr enable {0} '\n" ++"But note that the installed repo file will likely need a manual modification." ++msgstr "" ++"\n" ++"\n" ++"デフォルト以外のリポジトリーを有効にする場合は、以下のコマンドを使用します:\n" ++" 'dnf copr enable {0} '\n" ++"ただし、インストールされているリポジトリーファイルを手動で変更する必要がある" ++"可能性があることに注意してください。" + +-#: plugins/copr.py:488 +-msgid "Such repository does not exist." +-msgstr "そのようなリポジトリーは存在しません。" ++#: plugins/copr.py:505 ++#, python-brace-format ++msgid "Project {0} does not exist." ++msgstr "プロジェクト {0} は存在しません。" ++ ++#: plugins/copr.py:508 ++#, python-brace-format ++msgid "Failed to connect to {0}: {1}" ++msgstr "{0} への接続に失敗しました: {1}" + +-#: plugins/copr.py:532 ++#: plugins/copr.py:555 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -444,8 +489,8 @@ msgid "" + msgstr "" + "有効化した Copr リポジトリーの管理者は\n" + "他のリポジトリーに依存するように決めました。\n" +-"そのようなリポジトリーは通常、主な Corp " +-"レジストリー(ランタイム依存関係を提供) から RPM を\n" ++"そのようなリポジトリーは通常、主な Corp レジストリー(ランタイム依存関係を提" ++"供) から RPM を\n" + "正常にインストールするために必要です。\n" + "\n" + "上記の品質とバグ報告についての注意点がここでも適用\n" +@@ -456,44 +501,44 @@ msgstr "" + "\n" + "これらのリポジトリーは自動的に有効になっています。" + +-#: plugins/copr.py:553 ++#: plugins/copr.py:576 + msgid "Do you want to keep them enabled?" + msgstr "有効にしておきますか?" + +-#: plugins/copr.py:586 ++#: plugins/copr.py:609 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" + msgstr "copr repo {0}/{1}/{2} の削除に失敗しました" + +-#: plugins/copr.py:597 ++#: plugins/copr.py:620 + msgid "Failed to disable copr repo {}/{}" + msgstr "copr repo {}/{} の無効化に失敗しました" + +-#: plugins/copr.py:615 plugins/copr.py:652 ++#: plugins/copr.py:638 plugins/copr.py:675 + msgid "Unknown response from server." + msgstr "サーバーからの不明な応答です。" + +-#: plugins/copr.py:637 ++#: plugins/copr.py:660 + msgid "Interact with Playground repository." + msgstr "Playground リポジトリーとの対話。" + +-#: plugins/copr.py:643 ++#: plugins/copr.py:666 + msgid "Enabling a Playground repository." + msgstr "Playgroundのリポジトリーの有効化。" + +-#: plugins/copr.py:644 ++#: plugins/copr.py:667 + msgid "Do you want to continue?" + msgstr "続行しますか?" + +-#: plugins/copr.py:687 ++#: plugins/copr.py:711 + msgid "Playground repositories successfully enabled." + msgstr "Playground リポジトリーが正常に有効化されました。" + +-#: plugins/copr.py:690 ++#: plugins/copr.py:714 + msgid "Playground repositories successfully disabled." + msgstr "Playground リポジトリーが正常に無効化されました。" + +-#: plugins/copr.py:694 ++#: plugins/copr.py:718 + msgid "Playground repositories successfully updated." + msgstr "Playground リポジトリーが正常に更新されました。" + +@@ -822,7 +867,8 @@ msgstr "履歴データを移行中..." + #: plugins/modulesync.py:37 + msgid "" + "Download packages from modules and/or create a repository with modular data" +-msgstr "モジュールからパッケージをダウンロードしたり、モジュラーデータでリポジトリー" ++msgstr "" ++"モジュールからパッケージをダウンロードしたり、モジュラーデータでリポジトリー" + "を作成したりします" + + #: plugins/modulesync.py:44 +@@ -839,8 +885,9 @@ msgstr "ソースパッケージを含むリポジトリーを有効にします + + #: plugins/modulesync.py:49 + msgid "enable repositories with debug-info and debug-source packages" +-msgstr "debug-info パッケージおよび debug-source " +-"パッケージでリポジトリーを有効にします" ++msgstr "" ++"debug-info パッケージおよび debug-source パッケージでリポジトリーを有効にしま" ++"す" + + #: plugins/modulesync.py:53 + msgid "download only packages from newest modules" +@@ -855,8 +902,9 @@ msgstr[0] "引数に一致するものが見つかりませんでした: '{}'" + msgid "" + "Creation of repository failed with return code {}. All downloaded content " + "was kept on the system" +-msgstr "リポジトリーの作成は戻りコード {} " +-"で失敗しました。ダウンロードされたコンテンツはすべてシステムに保持されました" ++msgstr "" ++"リポジトリーの作成は戻りコード {} で失敗しました。ダウンロードされたコンテン" ++"ツはすべてシステムに保持されました" + + #: plugins/modulesync.py:144 + #, python-brace-format +@@ -866,8 +914,9 @@ msgstr "モジュール '{1}' のアーティファクト '{0}' に一致する + #: plugins/modulesync.py:162 + #, python-brace-format + msgid "No match for package name '{0}' in profile {1} from module {2}" +-msgstr "モジュール {2} からのプロファイル {1} のパッケージ名 '{0}' " +-"に一致するものはありません" ++msgstr "" ++"モジュール {2} からのプロファイル {1} のパッケージ名 '{0}' に一致するものはあ" ++"りません" + + #: plugins/modulesync.py:166 + msgid "No mach for argument '{}'" +@@ -884,8 +933,8 @@ msgid "" + "No installed package found for package name \"{pkg}\" specified in needs-" + "restarting file \"{file}\"." + msgstr "" +-"needs-restarting ファイル \"{file}\" に指定されている \"{pkg}\" " +-"というパッケージのインストール済みパッケージが見つかりません。" ++"needs-restarting ファイル \"{file}\" に指定されている \"{pkg}\" というパッ" ++"ケージのインストール済みパッケージが見つかりません。" + + #: plugins/needs_restarting.py:220 + msgid "determine updated binaries that need restarting" +@@ -932,18 +981,18 @@ msgid "Bad Action Line \"%s\": %s" + msgstr "不正なアクション行 \"%s\": %s" + + #. unsupported state, skip it +-#: plugins/post-transaction-actions.py:130 ++#: plugins/post-transaction-actions.py:133 + #, python-format + msgid "Bad Transaction State: %s" + msgstr "不正なトランザクション状態: %s" + +-#: plugins/post-transaction-actions.py:157 +-#: plugins/post-transaction-actions.py:159 ++#: plugins/post-transaction-actions.py:160 ++#: plugins/post-transaction-actions.py:162 + #, python-format + msgid "post-transaction-actions: %s" + msgstr "post-transaction-actions: %s" + +-#: plugins/post-transaction-actions.py:161 ++#: plugins/post-transaction-actions.py:164 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" + msgstr "post-transaction-actions: 不正なコマンド \"%s\": %s" +@@ -1126,33 +1175,45 @@ msgstr "rpm パッケージのディレクトリーを管理します" + + #: plugins/repomanage.py:59 + msgid "Pass either --old or --new, not both!" +-msgstr "--old または --new のいずれかを渡します。両方ではありません。" ++msgstr "--old または --new のいずれかを渡します、両方ではありません!" ++ ++#: plugins/repomanage.py:61 ++msgid "Pass either --oldonly or --new, not both!" ++msgstr "--oldonly または --new のいずれかを渡します、両方ではありません!" ++ ++#: plugins/repomanage.py:63 ++msgid "Pass either --old or --oldonly, not both!" ++msgstr "--old または --oldonly のいずれかを渡します、両方ではありません!" + +-#: plugins/repomanage.py:89 ++#: plugins/repomanage.py:100 + msgid "No files to process" + msgstr "処理するファイルはありません" + +-#: plugins/repomanage.py:96 ++#: plugins/repomanage.py:107 + msgid "Could not open {}" + msgstr "{} を開くことができません" + +-#: plugins/repomanage.py:180 ++#: plugins/repomanage.py:223 + msgid "Print the older packages" + msgstr "古いパッケージを印刷します" + +-#: plugins/repomanage.py:182 ++#: plugins/repomanage.py:225 ++msgid "Print the older packages. Exclude the newest packages." ++msgstr "古いパッケージを出力します。最新のパッケージを除外します。" ++ ++#: plugins/repomanage.py:227 + msgid "Print the newest packages" + msgstr "最新のパッケージを印刷します" + +-#: plugins/repomanage.py:184 ++#: plugins/repomanage.py:229 + msgid "Space separated output, not newline" + msgstr "スペースで区切られた出力で、改行ではありません" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:231 + msgid "Newest N packages to keep - defaults to 1" + msgstr "維持する最新の N パッケージ - デフォルトは 1 に設定されます" + +-#: plugins/repomanage.py:189 ++#: plugins/repomanage.py:234 + msgid "Path to directory" + msgstr "ディレクトリーへのパス" + +@@ -1259,6 +1320,186 @@ msgid "New leaves:" + msgstr "" + "新規のリーフパッケージ (他のパッケージから依存されていないパッケージ) :" + ++#. Translators: This string is only used in unit tests. ++#: plugins/system_upgrade.py:45 ++msgid "the color of the sky" ++msgstr "Sky の色" ++ ++#: plugins/system_upgrade.py:57 ++msgid "Need a --releasever greater than the current system version." ++msgstr "現在のシステムバージョンよりも大きい --releasever が必要です。" ++ ++#. Translators: do not change "reboot" here ++#: plugins/system_upgrade.py:59 ++#, python-brace-format ++msgid "" ++"Download complete! Use 'dnf {command} reboot' to start the upgrade.\n" ++"To remove cached metadata and transaction use 'dnf {command} clean'" ++msgstr "" ++"ダウンロードが完了しました! 'dnf {command} reboot' " ++"を使用して、アップグレードを開始します。\n" ++"キャッシュしたメタデータやトランザクションを削除するには、'dnf {command} " ++"clean' を使用します』" ++ ++#: plugins/system_upgrade.py:62 ++msgid "Sorry, you need to use 'download --releasever' instead of '--network'" ++msgstr "申し訳ございません。'--network' の代わりに 'download --releasever' " ++"を使用する必要があります』" ++ ++#: plugins/system_upgrade.py:71 ++msgid "Reboot turned off, not rebooting." ++msgstr "再起動ではなく、再起動をオフにしました。" ++ ++#: plugins/system_upgrade.py:122 ++#, python-format ++msgid "Screen blanking can't be disabled: %s" ++msgstr "空白の画面は無効にできません: %s" ++ ++#: plugins/system_upgrade.py:142 ++#, python-format ++msgid "Failed loading state file: %s, continuing with empty state." ++msgstr "状態ファイルの読み込みに失敗: %s、空の状態で続行。" ++ ++#: plugins/system_upgrade.py:289 ++msgid "The following boots appear to contain upgrade logs:" ++msgstr "以下のブートには、アップグレードログが含まれているように見えます:" ++ ++#: plugins/system_upgrade.py:299 ++msgid "-- no logs were found --" ++msgstr "-- ログが見つかりませんでした --" ++ ++#: plugins/system_upgrade.py:314 ++msgid "Cannot find logs with this index." ++msgstr "このインデックスのログが見つかりません。" ++ ++#: plugins/system_upgrade.py:323 ++msgid "Unable to match systemd journal entry" ++msgstr "systemd ジャーナルエントリーにマッチできない" ++ ++#: plugins/system_upgrade.py:344 ++msgid "Prepare system for upgrade to a new release" ++msgstr "新しいリリースへのアップグレードに向けたシステムの準備" ++ ++#: plugins/system_upgrade.py:360 ++msgid "keep installed packages if the new release's version is older" ++msgstr "新しいリリースのバージョンが古い場合は、インストール済みパッケージを維持しま" ++"す" ++ ++#: plugins/system_upgrade.py:364 ++msgid "which logs to show" ++msgstr "表示するログ" ++ ++#: plugins/system_upgrade.py:398 ++#, python-brace-format ++msgid "Incompatible version of data. Rerun 'dnf {command} download [OPTIONS]'" ++msgstr "互換性のないバージョンのデータ。'dnf {command} download [OPTIONS]' " ++"を再実行します』" ++ ++#: plugins/system_upgrade.py:434 ++msgid "Command 'offline-distrosync' cannot be used with --no-downgrade option" ++msgstr "コマンド 'offline-distrosync' は --no-downgrade オプションと併用できません" ++ ++#: plugins/system_upgrade.py:454 ++msgid "" ++"WARNING: this operation is not supported on the RHEL distribution. Proceed " ++"at your own risk." ++msgstr "警告: この操作は RHEL ディストリビューションではサポートされていません。自己" ++"責任で続行してください。" ++ ++#: plugins/system_upgrade.py:458 ++msgid "Additional information for System Upgrade: {}" ++msgstr "システムアップグレードの追加情報: {}" ++ ++#: plugins/system_upgrade.py:461 ++msgid "" ++"Before you continue ensure that your system is fully upgraded by running " ++"\"dnf --refresh upgrade\". Do you want to continue" ++msgstr "続行する前に、dnf --refresh upgrade を実行して、システムが完全にアップグレー" ++"ドされていることを確認します。続行しますか" ++ ++#: plugins/system_upgrade.py:465 ++msgid "Operation aborted." ++msgstr "操作が中断されました。" ++ ++#: plugins/system_upgrade.py:526 ++msgid "system is not ready for upgrade" ++msgstr "システムがアップグレードの準備ができていません" ++ ++#: plugins/system_upgrade.py:529 ++#, python-brace-format ++msgid "" ++"the transaction was not prepared for '{command}'. Rerun 'dnf {command} " ++"download [OPTIONS]'" ++msgstr "" ++"トランザクションは '{command}' に対して準備されていません。'dnf {command} " ++"download [OPTIONS]' を再実行します』" ++ ++#: plugins/system_upgrade.py:533 ++msgid "upgrade is already scheduled" ++msgstr "アップグレードはすでにスケジュールされています" ++ ++#: plugins/system_upgrade.py:539 ++msgid "trigger file does not exist. exiting quietly." ++msgstr "トリガーファイルは存在しません。間もなく終了します。" ++ ++#: plugins/system_upgrade.py:542 ++msgid "another upgrade tool is running. exiting quietly." ++msgstr "別のアップグレードツールが実行中で、警告なしで終了します。" ++ ++#: plugins/system_upgrade.py:551 ++#, python-brace-format ++msgid "use 'dnf {command} reboot' to begin the upgrade" ++msgstr "'dnf {command} reboot' を使用してアップグレードを開始します" ++ ++#: plugins/system_upgrade.py:569 ++msgid "Rebooting to perform upgrade." ++msgstr "再起動してアップグレードを実行します。" ++ ++#: plugins/system_upgrade.py:602 ++msgid "Starting offline upgrade. This will take a while." ++msgstr "オフラインアップグレードの開始。これには時間がかかります。" ++ ++#: plugins/system_upgrade.py:604 ++msgid "Starting offline distrosync. This will take a while." ++msgstr "オフラインの distrosync の開始。これには時間がかかります。" ++ ++#: plugins/system_upgrade.py:606 ++msgid "Starting system upgrade. This will take a while." ++msgstr "システムのアップグレードを開始します。これには時間がかかります。" ++ ++#: plugins/system_upgrade.py:622 ++msgid "Cleaning up downloaded data..." ++msgstr "ダウンロードしたデータのクリーンアップ中..." ++ ++#: plugins/system_upgrade.py:652 ++msgid "" ++"The system-upgrade transaction is empty, your system is already up-to-date." ++msgstr "システムアップグレードトランザクションは空で、システムはすでに最新です。" ++ ++#: plugins/system_upgrade.py:661 ++msgid "Transaction saved to {}." ++msgstr "{} に保存されているトランザクション。" ++ ++#: plugins/system_upgrade.py:664 ++msgid "Error storing transaction: {}" ++msgstr "トランザクションの保存エラー: {}" ++ ++#: plugins/system_upgrade.py:686 ++msgid "Download finished." ++msgstr "ダウンロードが完了しました。" ++ ++#: plugins/system_upgrade.py:689 plugins/system_upgrade.py:690 ++msgid "Upgrade complete! Cleaning up and rebooting..." ++msgstr "アップグレードの完了! クリーンアップおよび再起動を行っています..." ++ ++#: plugins/system_upgrade.py:699 ++msgid "Prepare offline upgrade of the system" ++msgstr "システムのオフラインアップグレードの準備" ++ ++#: plugins/system_upgrade.py:704 ++msgid "Prepare offline distrosync of the system" ++msgstr "システムのオフラインの distrosync を準備します" ++ + #: plugins/versionlock.py:33 + #, python-format + msgid "Unable to read version lock configuration: %s" +@@ -1323,8 +1564,14 @@ msgstr "パッケージ仕様をそのまま使用し、解析を試みないで + + #: plugins/versionlock.py:160 + msgid "Subcommand '{}' is deprecated. Use 'exclude' subcommand instead." +-msgstr "サブコマンド '{}' は非推奨になりました。代わりに 'exclude' " +-"サブコマンドを使用してください。" ++msgstr "" ++"サブコマンド '{}' は非推奨になりました。代わりに 'exclude' サブコマンドを使用" ++"してください。" ++ ++#~ msgid "" ++#~ "This repository does not have any builds yet so you cannot enable it now." ++#~ msgstr "" ++#~ "このリポジトリーにはまだビルドがありませんので、今すぐ有効化できません。" + + #~ msgid "" + #~ "\n" +diff --git a/po/ko.po b/po/ko.po +index 307ccc7..1b615d4 100644 +--- a/po/ko.po ++++ b/po/ko.po +@@ -1,13 +1,14 @@ + # Ludek Janda , 2018. #zanata, 2020. + # simmon , 2021. + # Kim InSoo , 2022. ++# 김인수 , 2022, 2023. + msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2022-02-28 11:53+0100\n" +-"PO-Revision-Date: 2022-03-02 04:16+0000\n" +-"Last-Translator: Kim InSoo \n" ++"POT-Creation-Date: 2023-02-28 12:21+0100\n" ++"PO-Revision-Date: 2023-03-03 04:20+0000\n" ++"Last-Translator: 김인수 \n" + "Language-Team: Korean \n" + "Language: ko\n" +@@ -15,7 +16,7 @@ msgstr "" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=1; plural=0;\n" +-"X-Generator: Weblate 4.11\n" ++"X-Generator: Weblate 4.15.2\n" + + #: plugins/builddep.py:45 + msgid "[PACKAGE|PACKAGE.spec]" +@@ -28,7 +29,7 @@ msgstr "'%s'는 'MACRO EXPR' 형식이 아닙니다" + + #: plugins/builddep.py:90 + msgid "packages with builddeps to install" +-msgstr "설치 할 builddeps가 있는 꾸러미(package)" ++msgstr "설치 할 builddeps가 있는 꾸러미" + + #: plugins/builddep.py:93 + msgid "define a macro for spec file parsing" +@@ -36,7 +37,7 @@ msgstr "특정한 파일 구문분석을 위해 매크로를 정의한다" + + #: plugins/builddep.py:95 + msgid "skip build dependencies not available in repositories" +-msgstr "저장소에서 사용 할 수 없는 구성 의존성을 건너띄기 한다" ++msgstr "저장소에서 사용 할 수 없는 구성 의존성을 건너 뛰기 한다" + + #: plugins/builddep.py:98 + msgid "treat commandline arguments as spec files" +@@ -44,7 +45,7 @@ msgstr "명령줄 인수를 지정한 파일로 다룬다" + + #: plugins/builddep.py:100 + msgid "treat commandline arguments as source rpm" +-msgstr "명령줄 인수를 rpm 소스로 다룬다" ++msgstr "원천 rpm으로 명령줄 인수를 다룬다" + + #: plugins/builddep.py:144 + msgid "RPM: {}" +@@ -52,42 +53,48 @@ msgstr "RPM: {}" + + #: plugins/builddep.py:153 + msgid "Some packages could not be found." +-msgstr "몇몇 꾸러미(packages)를 찾을 수 없습니다." ++msgstr "몇몇 꾸러미를 찾을 수 없습니다." + + #. No provides, no files + #. Richdeps can have no matches but it could be correct (solver must decide later) + #: plugins/builddep.py:173 + #, python-format + msgid "No matching package to install: '%s'" +-msgstr "설치: '%s' 꾸러미(package)가 일치하지 않습니다" ++msgstr "설치: '%s' 꾸러미가 일치하지 않습니다" + + #: plugins/builddep.py:191 + #, python-format + msgid "Failed to open: '%s', not a valid source rpm file." + msgstr "여는데 실패하였습니다: '%s', 유효한 rpm 파일 출처가 아닙니다." + +-#: plugins/builddep.py:204 plugins/builddep.py:220 plugins/builddep.py:237 ++#: plugins/builddep.py:204 plugins/builddep.py:224 plugins/builddep.py:241 + msgid "Not all dependencies satisfied" + msgstr "모든 의존성을 만족하지 않습니다" + +-#: plugins/builddep.py:211 ++#: plugins/builddep.py:208 ++msgid "" ++"Warning: -D or --define arguments have no meaning for source rpm packages." ++msgstr "경고: -D 또는 --define 인수는 원천 rpm 꾸러미를 위해 의미를 가지고 있지 " ++"않습니다." ++ ++#: plugins/builddep.py:215 + #, python-format + msgid "Failed to open: '%s', not a valid spec file: %s" + msgstr "여는데 실패하였습니다 '%s', 지정한 파일: %s가 유효하지 않습니다" + +-#: plugins/builddep.py:230 plugins/repoclosure.py:118 ++#: plugins/builddep.py:234 plugins/repoclosure.py:118 + #, python-format + msgid "no package matched: %s" +-msgstr "일치하는 꾸러미(package) 없음: %s" ++msgstr "일치하는 꾸러미 없음: %s" + + #: plugins/changelog.py:37 + #, python-brace-format + msgid "Not a valid date: \"{0}\"." +-msgstr "유효한 날자가 아닙니다: \"{0}\"." ++msgstr "유효한 날짜가 아닙니다: \"{0}\"." + + #: plugins/changelog.py:43 + msgid "Show changelog data of packages" +-msgstr "꾸러미(packages)의 변화 기록자료를 보여줍니다" ++msgstr "꾸러미의 변화 기록자료를 보여줍니다" + + #: plugins/changelog.py:51 + msgid "" +@@ -99,19 +106,19 @@ msgstr "" + + #: plugins/changelog.py:55 + msgid "show given number of changelog entries per package" +-msgstr "주어진 수의 꾸러미(package) 마다 변화기록 항목을 보여줍니다" ++msgstr "주어진 수의 꾸러미 마다 변화기록 항목을 보여줍니다" + + #: plugins/changelog.py:58 + msgid "" + "show only new changelog entries for packages, that provide an upgrade for " + "some of already installed packages." + msgstr "" +-"몇몇 이미 설치된 꾸러미(package)들의 최신화를 제공하는 꾸러미를 위하여 새로" +-"운 변화기록만을 보여줍니다." ++"몇몇 이미 설치된 꾸러미들의 최신화를 제공하는 꾸러미를 위하여 새로운 변화기록" ++"만을 보여줍니다." + + #: plugins/changelog.py:60 + msgid "PACKAGE" +-msgstr "꾸러미(package)" ++msgstr "꾸러미" + + #: plugins/changelog.py:81 plugins/debuginfo-install.py:90 + #, python-format +@@ -146,7 +153,7 @@ msgstr "{prog} 환경 선택과 저장소 관리" + + #: plugins/config_manager.py:45 + msgid "repo to modify" +-msgstr "수정할 repo" ++msgstr "수정하려는 저장소" + + #: plugins/config_manager.py:48 + msgid "save the current options (useful with --setopt)" +@@ -202,29 +209,29 @@ msgstr[0] "저장소 구성에 실패했습니다" + #: plugins/config_manager.py:217 + #, python-format + msgid "Could not save repo to repofile %s: %s" +-msgstr "repofile에 repo를 저장할 수 없습니다. %s: %s" ++msgstr "repofile에 repo를 저장 할 수 없습니다. %s: %s" + +-#: plugins/copr.py:64 ++#: plugins/copr.py:70 + msgid "y" + msgstr "y" + +-#: plugins/copr.py:64 ++#: plugins/copr.py:70 + msgid "yes" + msgstr "예" + +-#: plugins/copr.py:65 ++#: plugins/copr.py:71 + msgid "n" + msgstr "n" + +-#: plugins/copr.py:65 ++#: plugins/copr.py:71 + msgid "no" + msgstr "아니" + +-#: plugins/copr.py:84 ++#: plugins/copr.py:92 + msgid "Interact with Copr repositories." + msgstr "Copr 저장소와 상호 작용하십시오." + +-#: plugins/copr.py:86 ++#: plugins/copr.py:94 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -262,31 +269,31 @@ msgstr "" + " copr search tests\n" + " " + +-#: plugins/copr.py:112 ++#: plugins/copr.py:120 + msgid "List all installed Copr repositories (default)" + msgstr "설치된 모든 Copr 저장소 나열 (기본값)" + +-#: plugins/copr.py:114 ++#: plugins/copr.py:122 + msgid "List enabled Copr repositories" + msgstr "사용 가능한 Copr 저장소 목록" + +-#: plugins/copr.py:116 ++#: plugins/copr.py:124 + msgid "List disabled Copr repositories" + msgstr "비활성화 된 Copr 저장소 목록" + +-#: plugins/copr.py:118 ++#: plugins/copr.py:126 + msgid "List available Copr repositories by user NAME" + msgstr "사용자가 사용할 수있는 Copr 저장소를 나열합니다. NAME" + +-#: plugins/copr.py:120 ++#: plugins/copr.py:128 + msgid "Specify an instance of Copr to work with" + msgstr "일하는 Copr의 예를 지정합니다" + +-#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 ++#: plugins/copr.py:164 plugins/copr.py:236 plugins/copr.py:263 + msgid "Error: " + msgstr "오류: " + +-#: plugins/copr.py:155 ++#: plugins/copr.py:165 + msgid "" + "specify Copr hub either with `--hub` or using `copr_hub/copr_username/" + "copr_projectname` format" +@@ -294,35 +301,35 @@ msgstr "" + "Corp hub를 `--hub` 또는 사용하기 `copr_hub/copr_username/copr_projectname`형" + "식으로 지정합니다" + +-#: plugins/copr.py:158 ++#: plugins/copr.py:168 + msgid "multiple hubs specified" + msgstr "지정된 여러 허브" + +-#: plugins/copr.py:223 plugins/copr.py:227 ++#: plugins/copr.py:237 plugins/copr.py:241 + msgid "exactly two additional parameters to copr command are required" + msgstr "copr 명령에 정확히 두 개의 추가 매개 변수가 필요합니다" + +-#: plugins/copr.py:232 ++#: plugins/copr.py:246 + msgid "Too many arguments." + msgstr "너무 많은 인수." + +-#: plugins/copr.py:235 ++#: plugins/copr.py:249 + msgid "" + "Bad format of optional chroot. The format is distribution-version-" + "architecture." + msgstr "선택적인 chroot의 나쁜 형식. 형식은 배포-버전-구조입니다." + +-#: plugins/copr.py:250 ++#: plugins/copr.py:264 + msgid "use format `copr_username/copr_projectname` to reference copr project" + msgstr "" + "copr 프로젝트를 참조하기 위해`copr_username / copr_projectname` 형식을 사용하" + "십시오" + +-#: plugins/copr.py:252 ++#: plugins/copr.py:266 + msgid "bad copr project format" + msgstr "나쁜 copr 프로젝트 형식" + +-#: plugins/copr.py:266 ++#: plugins/copr.py:280 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -352,23 +359,23 @@ msgstr "" + "페도라 버그질라에 이들 꾸러미에 대한 파일 결점 보고를 제출하지 마세요.\n" + "이들 문제는, 이들 저장소 소유자와 접촉하세요.\n" + +-#: plugins/copr.py:283 ++#: plugins/copr.py:297 + msgid "Repository successfully enabled." + msgstr "저장소가 사용 설정되었습니다." + +-#: plugins/copr.py:288 ++#: plugins/copr.py:302 + msgid "Repository successfully disabled." + msgstr "저장소가 사용 중지되었습니다." + +-#: plugins/copr.py:292 ++#: plugins/copr.py:306 + msgid "Repository successfully removed." + msgstr "저장소가 제거되었습니다." + +-#: plugins/copr.py:296 plugins/copr.py:697 ++#: plugins/copr.py:310 plugins/copr.py:721 + msgid "Unknown subcommand {}." + msgstr "알 수없는 부속 명령 {}." + +-#: plugins/copr.py:353 ++#: plugins/copr.py:367 + msgid "" + "* These coprs have repo file with an old format that contains no information " + "about Copr hub - the default one was assumed. Re-enable the project to fix " +@@ -377,48 +384,88 @@ msgstr "" + "* 이들 coprs은 Copr hub에 대하여 어떤 정보도 포함하지 않는 오래된 형태의 저장" + "소 파일을 갖고 있습니다. 이 문제를 수정하기 위하여 프로젝트를 재활성화하세요." + +-#: plugins/copr.py:366 ++#: plugins/copr.py:380 + msgid "Can't parse repositories for username '{}'." + msgstr "사용자 이름 '{}'에 대한 리포지토리를 구문 분석 할 수 없습니다." + +-#: plugins/copr.py:369 ++#: plugins/copr.py:383 + msgid "List of {} coprs" + msgstr "{} 명의 경찰 목록" + +-#: plugins/copr.py:374 ++#: plugins/copr.py:388 + msgid "No description given" + msgstr "설명이 없습니다" + +-#: plugins/copr.py:386 ++#: plugins/copr.py:400 + msgid "Can't parse search for '{}'." + msgstr "'{}'에 대한 검색을 구문 분석 할 수 없습니다." + +-#: plugins/copr.py:389 ++#: plugins/copr.py:403 + msgid "Matched: {}" + msgstr "일치하는 항목 : {}" + +-#: plugins/copr.py:394 ++#: plugins/copr.py:408 + msgid "No description given." + msgstr "설명이 없습니다." + +-#: plugins/copr.py:416 ++#: plugins/copr.py:430 + msgid "Safe and good answer. Exiting." + msgstr "안전하고 좋은 대답. 나가기." + +-#: plugins/copr.py:423 ++#: plugins/copr.py:437 + msgid "This command has to be run under the root user." + msgstr "이 명령은 루트 사용자로 실행해야합니다." + +-#: plugins/copr.py:485 ++#: plugins/copr.py:487 ++#, python-brace-format ++msgid "Request to {0} failed: {1} - {2}" ++msgstr "{0}에 대한 요청이 실패함: {1} - {2}" ++ ++#: plugins/copr.py:489 ++msgid "It wasn't possible to enable this project.\n" ++msgstr "이와 같은 프로젝트를 활성화 할 수 없습니다.\n" ++ ++#: plugins/copr.py:494 ++#, python-brace-format ++msgid "Repository '{0}' does not exist in project '{1}'." ++msgstr "저장소 '{0}'는 프로젝트 '{1}'에 존재하지 않습니다." ++ ++#: plugins/copr.py:497 + msgid "" +-"This repository does not have any builds yet so you cannot enable it now." +-msgstr "이 저장소에는 빌드가 아직 없으므로 지금 사용할 수 없습니다." ++"\n" ++"Available repositories: " ++msgstr "" ++"\n" ++"사용 가능한 저장소: " + +-#: plugins/copr.py:488 +-msgid "Such repository does not exist." +-msgstr "이러한 저장소는 존재하지 않습니다." ++#: plugins/copr.py:499 ++#, python-brace-format ++msgid "" ++"\n" ++"\n" ++"If you want to enable a non-default repository, use the following command:\n" ++" 'dnf copr enable {0} '\n" ++"But note that the installed repo file will likely need a manual modification." ++msgstr "" ++"\n" ++"\n" ++"만약 기본설정되지 않은 저장소를 활성화 하고자 한다면, 다음 명령을 사용하세" ++"요: \n" ++" 'dnf copr enable {0} ' \n" ++"하지만 설치된 저장소 파일은 수동으로 수정해야 할 필요가 있다는 점을 참고하세" ++"요." ++ ++#: plugins/copr.py:505 ++#, python-brace-format ++msgid "Project {0} does not exist." ++msgstr "프로젝트 {0}가 존재하지 않습니다." + +-#: plugins/copr.py:532 ++#: plugins/copr.py:508 ++#, python-brace-format ++msgid "Failed to connect to {0}: {1}" ++msgstr "연결 하는데 실패함 {0}: {1}" ++ ++#: plugins/copr.py:555 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -447,50 +494,50 @@ msgstr "" + "\n" + "이들 저장소는 자동으로 활성화 됩니다." + +-#: plugins/copr.py:553 ++#: plugins/copr.py:576 + msgid "Do you want to keep them enabled?" + msgstr "계속 사용하길 원하시나요?" + +-#: plugins/copr.py:586 ++#: plugins/copr.py:609 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" + msgstr "copr repo {0}/{1}/{2} 제거를 실패하였습니다" + +-#: plugins/copr.py:597 ++#: plugins/copr.py:620 + msgid "Failed to disable copr repo {}/{}" + msgstr "copr repo {} / {}를 사용 중지를 실패하였습니다" + +-#: plugins/copr.py:615 plugins/copr.py:652 ++#: plugins/copr.py:638 plugins/copr.py:675 + msgid "Unknown response from server." + msgstr "서버에서 알 수없는 응답." + +-#: plugins/copr.py:637 ++#: plugins/copr.py:660 + msgid "Interact with Playground repository." + msgstr "놀이터 저장소와 상호 작용하십시오." + +-#: plugins/copr.py:643 ++#: plugins/copr.py:666 + msgid "Enabling a Playground repository." + msgstr "동작 저장소와 활용하기." + +-#: plugins/copr.py:644 ++#: plugins/copr.py:667 + msgid "Do you want to continue?" + msgstr "계속하기를 원하십니까?" + +-#: plugins/copr.py:687 ++#: plugins/copr.py:711 + msgid "Playground repositories successfully enabled." + msgstr "놀이터 저장소를 사용하도록 설정했습니다." + +-#: plugins/copr.py:690 ++#: plugins/copr.py:714 + msgid "Playground repositories successfully disabled." + msgstr "놀이터 저장소가 사용 중지되었습니다." + +-#: plugins/copr.py:694 ++#: plugins/copr.py:718 + msgid "Playground repositories successfully updated." + msgstr "놀이터 저장소가 성공적으로 업데이트되었습니다." + + #: plugins/debug.py:53 + msgid "dump information about installed rpm packages to file" +-msgstr "설치된 rpm 꾸러미(package)에 대한 정보를 파일에 덤프하십시오" ++msgstr "설치된 rpm 꾸러미에 대한 정보를 파일에 덤프하세요" + + #: plugins/debug.py:67 + msgid "do not attempt to dump the repository contents." +@@ -507,7 +554,7 @@ msgstr "작성된 출력 : %s" + + #: plugins/debug.py:172 + msgid "restore packages recorded in debug-dump file" +-msgstr "디버그 덤프 파일에 기록 된 꾸러미(package) 복원" ++msgstr "디버그 덤프 파일에 기록 된 꾸러미 복원" + + #: plugins/debug.py:185 + msgid "output commands that would be run to stdout." +@@ -544,7 +591,7 @@ msgstr "덤프 파일의 이름" + #: plugins/debug.py:273 + #, python-format + msgid "Package %s is not available" +-msgstr "꾸러미(package) %s 사용 할 수 없습니다" ++msgstr "꾸러미 %s를 사용 할 수 없습니다" + + #: plugins/debug.py:283 + #, python-format +@@ -553,39 +600,32 @@ msgstr "잘못된 dnf 디버그 파일 : %s" + + #: plugins/debuginfo-install.py:56 + msgid "install debuginfo packages" +-msgstr "디버그정보 꾸러미(package) 설치" ++msgstr "디버그정보 꾸러미 설치" + + #: plugins/debuginfo-install.py:180 + #, python-format + msgid "" + "Could not find debuginfo package for the following available packages: %s" + msgstr "" +-"다음 사용가능한 꾸러미(package): %s 를 위하여 디버그정보 꾸러미를 찾을 수 없" +-"습니다" ++"다음 사용가능한 꾸러미를 위하여 디버그정보 꾸러미를 찾을 수 없습니다: %s" + + #: plugins/debuginfo-install.py:185 + #, python-format + msgid "" + "Could not find debugsource package for the following available packages: %s" +-msgstr "" +-"다음 가용한 꾸러미(package): %s 를 위하여 디버그자원 꾸러미(package)를 찾을 " +-"수 없습니다" ++msgstr "다음 가용한 꾸러미: %s 를 위하여 디버그자원 꾸러미를 찾을 수 없습니다" + + #: plugins/debuginfo-install.py:190 + #, python-format + msgid "" + "Could not find debuginfo package for the following installed packages: %s" +-msgstr "" +-"다음 설치된 꾸러미(package): %s 를 위한 디버그정보 꾸러미(package)를 찾을 수 " +-"없습니다" ++msgstr "다음 설치된 꾸러미를 위한 디버그정보 꾸러미를 찾을 수 없습니다: %s" + + #: plugins/debuginfo-install.py:195 + #, python-format + msgid "" + "Could not find debugsource package for the following installed packages: %s" +-msgstr "" +-"다음 설치된 꾸러미(package): %s 를 위하여 디버그자원 꾸러미(package)를 찾을 " +-"수 없습니다" ++msgstr "다음 설치된 꾸러미: %s 를 위하여 디버그자원 꾸러미를 찾을 수 없습니다" + + #: plugins/debuginfo-install.py:199 + msgid "Unable to find a match" +@@ -605,15 +645,15 @@ msgstr "대신 src.rpm을 내려받으세요" + + #: plugins/download.py:55 + msgid "download the -debuginfo package instead" +-msgstr "대신 -debuginfo 꾸러미(package)를 내려받아요" ++msgstr "대신 -debuginfo 꾸러미를 내려받아요" + + #: plugins/download.py:57 + msgid "download the -debugsource package instead" +-msgstr "대신 -debuginfo 꾸러미(package)를 내려받으세요" ++msgstr "대신 -debuginfo 꾸러미를 내려받으세요" + + #: plugins/download.py:60 + msgid "limit the query to packages of given architectures." +-msgstr "요청를 주어진 구조 꾸러미(package)로 제한하십시오." ++msgstr "요청를 제공된 구조의 꾸러미로 제한합니다." + + #: plugins/download.py:62 plugins/modulesync.py:51 + msgid "resolve and download needed dependencies" +@@ -647,17 +687,17 @@ msgstr "엄격한 설정으로 인해 종료됩니다." + + #: plugins/download.py:261 + msgid "Error in resolve of packages:" +-msgstr "꾸러미(package) 해결 오류 :" ++msgstr "꾸러미 해결 오류 :" + + #: plugins/download.py:279 + #, python-format + msgid "No source rpm defined for %s" +-msgstr "소스 rpm이 정의되지 않았습니다. %s" ++msgstr "%s를 위한 원천 rpm이 정의되지 않음" + + #: plugins/download.py:296 plugins/download.py:309 + #, python-format + msgid "No package %s available." +-msgstr "가용한 꾸러미(package) %s가 없습니다." ++msgstr "가용한 꾸러미 %s가 없습니다." + + #: plugins/groups_manager.py:49 + msgid "Invalid group id" +@@ -679,7 +719,7 @@ msgstr "" + + #: plugins/groups_manager.py:79 + msgid "create and edit groups metadata file" +-msgstr "그룹 메타데이타 파일 생성하고 수정합니다" ++msgstr "그룹 메타자료 파일을 생성하고 수정합니다" + + #: plugins/groups_manager.py:90 + msgid "load groups metadata from file" +@@ -695,7 +735,7 @@ msgstr "그룹 메타파일을 파일에 적재하고 저장합니다" + + #: plugins/groups_manager.py:97 + msgid "print the result metadata to stdout" +-msgstr "결과 메타데이타를 표준출력으로 출력한다" ++msgstr "결과 메타자료를 표준출력에 출력합니다" + + #: plugins/groups_manager.py:100 + msgid "group id" +@@ -731,23 +771,23 @@ msgstr "그룹 사용자를 보이지 않게 표시" + + #: plugins/groups_manager.py:123 + msgid "add packages to the mandatory section" +-msgstr "꾸러미(package)를 필 수 부분에 추가합니다" ++msgstr "꾸러미를 필수 부분에 추가합니다" + + #: plugins/groups_manager.py:125 + msgid "add packages to the optional section" +-msgstr "꾸러미(package)를 선택 부분에 추가합니다" ++msgstr "꾸러미를 선택 부분에 추가합니다" + + #: plugins/groups_manager.py:127 + msgid "remove packages from the group instead of adding them" +-msgstr "추가하기 대신에 그룹에서 꾸러미(package)를 제거합니다" ++msgstr "추가하기 대신에 그룹에서 꾸러미를 제거합니다" + + #: plugins/groups_manager.py:129 + msgid "include also direct dependencies for packages" +-msgstr "꾸러미(package)를 위해 직접적인 의존성을 포함한다" ++msgstr "꾸러미를 위해 직접적인 의존성을 포함한다" + + #: plugins/groups_manager.py:132 + msgid "package specification" +-msgstr "꾸러미(package) 사양" ++msgstr "꾸러미 사양" + + #: plugins/groups_manager.py:156 + msgid "Can't edit group without specifying it (use --id or --name)" +@@ -767,7 +807,7 @@ msgstr "일치하는 인수가 없습니다 :{}" + + #: plugins/groups_manager.py:298 + msgid "Can't remove packages from non-existent group" +-msgstr "존재하지 않는 그룹에서 꾸러미(package)를 제거 할 수 없습니다" ++msgstr "존재하지 않는 그룹에서 꾸러미를 제거 할 수 없습니다" + + #: plugins/groups_manager.py:307 + msgid "" +@@ -779,7 +819,7 @@ msgstr "" + + #: plugins/leaves.py:32 + msgid "List installed packages not required by any other package" +-msgstr "다른 꾸러미(package)에서 필요하지 않은 설치된 꾸러미(packages) 나열" ++msgstr "다른 꾸러미에서 필요하지 않은 설치된 꾸러미 나열" + + #: plugins/local.py:122 + msgid "Unable to create a directory '{}' due to '{}'" +@@ -812,23 +852,24 @@ msgstr "기록 데이터 마이그레이션 중 ..." + #: plugins/modulesync.py:37 + msgid "" + "Download packages from modules and/or create a repository with modular data" +-msgstr "모듈에서 꾸러미를 내려 받기와/또는 모듈식 자료를 갖고 있는 저장소를 생성" ++msgstr "" ++"모듈에서 꾸러미를 내려 받기와/또는 모듈식 자료를 갖고 있는 저장소를 생성" + + #: plugins/modulesync.py:44 + msgid "MODULE" +-msgstr "모듈" ++msgstr "MODULE" + + #: plugins/modulesync.py:45 + msgid "modules to download" +-msgstr "내려받아야 할 모듈" ++msgstr "내려받기 할 모듈" + + #: plugins/modulesync.py:47 + msgid "enable repositories with source packages" +-msgstr "원천 꾸러미와 함께 저장소를 활성화" ++msgstr "원천 꾸러미로 저장소 활성화" + + #: plugins/modulesync.py:49 + msgid "enable repositories with debug-info and debug-source packages" +-msgstr "디버그-정보와 디버그-원천 꾸러미와 함께 저장소 활성화" ++msgstr "debug-info와 debug-source 꾸러미로 저장소 활성화" + + #: plugins/modulesync.py:53 + msgid "download only packages from newest modules" +@@ -837,28 +878,30 @@ msgstr "최신 모듈에서 꾸러미만 내려받기" + #: plugins/modulesync.py:85 + msgid "Unable to find a match for argument: '{}'" + msgid_plural "Unable to find a match for arguments: '{}'" +-msgstr[0] "인수와 일치하는 항목을 찾을 수 없습니다: '{}'" ++msgstr[0] "인수와 일치 항목을 찾을 수 없음: '{}'" + + #: plugins/modulesync.py:107 + msgid "" + "Creation of repository failed with return code {}. All downloaded content " + "was kept on the system" +-msgstr "반환 코드 {}로 인하여 저장소 생성에 실패함. 모두 내려받기된 내용은 " +-"시스템에서 보관됩니다" ++msgstr "" ++"반환 코드 {}로 인하여 저장소 생성에 실패함. 모두 내려받기된 내용은 시스템에" ++"서 보관됩니다" + + #: plugins/modulesync.py:144 + #, python-brace-format + msgid "No match for artifact '{0}' from module '{1}'" +-msgstr "모듈 '{1}'에서 인위 결과물 '{0}'과 일치하는 부분이 없습니다" ++msgstr "모듈 '{1}' 에서 인위 결과물 '{0}'과 일치하는 부분이 없습니다" + + #: plugins/modulesync.py:162 + #, python-brace-format + msgid "No match for package name '{0}' in profile {1} from module {2}" +-msgstr "모듈 {2}에서 프로파일 {1}인 꾸러미 이름 '{0}'과 일치하는 부분이 없습니다" ++msgstr "" ++"모듈 {2}에서 프로파일 {1}인 꾸러미 이름 '{0}'과 일치하는 부분이 없습니다" + + #: plugins/modulesync.py:166 + msgid "No mach for argument '{}'" +-msgstr "인수와 일치하는 항목이 없습니다 '{}'" ++msgstr "인수 '{}'와 일치하는 항목이 없습니다" + + #. TODO(jmracek) Shell we end with an error or with RC 1? + #: plugins/modulesync.py:198 +@@ -870,8 +913,9 @@ msgstr "필요사항 {}를 만족 할 수 없음" + msgid "" + "No installed package found for package name \"{pkg}\" specified in needs-" + "restarting file \"{file}\"." +-msgstr "재시작이 필요한 파일 \"{file}\" 에 지정한 꾸러미 이름 \"{pkg}\"을 위하여 " +-"설치된 꾸러미를 찾을 수 없습니다." ++msgstr "" ++"재시작이 필요한 파일 \"{file}\" 에 지정한 꾸러미 이름 \"{pkg}\"을 위하여 설치" ++"된 꾸러미를 찾을 수 없습니다." + + #: plugins/needs_restarting.py:220 + msgid "determine updated binaries that need restarting" +@@ -917,18 +961,18 @@ msgid "Bad Action Line \"%s\": %s" + msgstr "잘못된 동작 선 \"%s\": %s" + + #. unsupported state, skip it +-#: plugins/post-transaction-actions.py:130 ++#: plugins/post-transaction-actions.py:133 + #, python-format + msgid "Bad Transaction State: %s" + msgstr "잘못된 연결 상태: %s" + +-#: plugins/post-transaction-actions.py:157 +-#: plugins/post-transaction-actions.py:159 ++#: plugins/post-transaction-actions.py:160 ++#: plugins/post-transaction-actions.py:162 + #, python-format + msgid "post-transaction-actions: %s" + msgstr "연결 후 동작: %s" + +-#: plugins/post-transaction-actions.py:161 ++#: plugins/post-transaction-actions.py:164 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" + msgstr "연결 후 동작: 잘못된 명령 \"%s\": %s" +@@ -943,7 +987,7 @@ msgstr "재구 축은 해결되지 않은 종속성으로 종료되었습니다. + + #: plugins/repoclosure.py:153 + msgid "check packages of the given archs, can be specified multiple times" +-msgstr "지정된 아치의 꾸러미(package)를 검사하고 여러 번 지정할 수 있습니다" ++msgstr "지정된 아치의 꾸러미를 검사하고 여러 번 지정할 수 있습니다" + + #: plugins/repoclosure.py:156 + msgid "Specify repositories to check" +@@ -951,11 +995,11 @@ msgstr "점검 할 저장소를 지정하세요" + + #: plugins/repoclosure.py:158 + msgid "Check only the newest packages in the repos" +-msgstr "저장소 최신 꾸러미(package)만 확인하세요" ++msgstr "저장소 최신 꾸러미만 확인하세요" + + #: plugins/repoclosure.py:161 + msgid "Check closure for this package only" +-msgstr "이 꾸러미(package)의 폐쇄만 확인하세요" ++msgstr "이 꾸러미의 폐쇄만 확인하세요" + + #: plugins/repodiff.py:45 + msgid "List differences between two sets of repositories" +@@ -985,12 +1029,12 @@ msgstr "크기 변화에 대한 추가 자료를 출력합니다." + msgid "" + "Compare packages also by arch. By default packages are compared just by name." + msgstr "" +-"구조에 의해 꾸러미(package) 또한 비교합니다. 기본적으로 꾸러미(package)는 이" +-"름으로만 비교됩니다." ++"구조에 의해 꾸러미 또한 비교합니다. 기본적으로 꾸러미는 이름으로만 비교됩니" ++"다." + + #: plugins/repodiff.py:72 + msgid "Output a simple one line message for modified packages." +-msgstr "수정된 꾸러미(pacakage)지를 위해 단순히 한 줄 메시지를 출력합니다." ++msgstr "수정된 꾸러미를 위해 단순히 한 줄 메시지를 출력합니다." + + #: plugins/repodiff.py:74 + msgid "" +@@ -1008,11 +1052,11 @@ msgstr "크기 변화: {} bytes" + + #: plugins/repodiff.py:184 + msgid "Added package : {}" +-msgstr "추가된 꾸러미(package) : {}" ++msgstr "추가된 꾸러미 : {}" + + #: plugins/repodiff.py:187 + msgid "Removed package: {}" +-msgstr "제거된 꾸러미(package): {}" ++msgstr "제거된 꾸러미: {}" + + #: plugins/repodiff.py:190 + msgid "Obsoleted by : {}" +@@ -1024,7 +1068,7 @@ msgid "" + "Upgraded packages" + msgstr "" + "\n" +-"향상된 꾸러미(package)" ++"향상된 꾸러미" + + #: plugins/repodiff.py:200 + msgid "" +@@ -1040,7 +1084,7 @@ msgid "" + "Modified packages" + msgstr "" + "\n" +-"변형된 꾸러미(package)" ++"변형된 꾸러미" + + #: plugins/repodiff.py:212 + msgid "" +@@ -1052,35 +1096,35 @@ msgstr "" + + #: plugins/repodiff.py:213 + msgid "Added packages: {}" +-msgstr "추가된 꾸러미(package): {}" ++msgstr "추가된 꾸러미: {}" + + #: plugins/repodiff.py:214 + msgid "Removed packages: {}" +-msgstr "제거된 꾸러미(package): {}" ++msgstr "제거된 꾸러미: {}" + + #: plugins/repodiff.py:216 + msgid "Upgraded packages: {}" +-msgstr "향상된 꾸러미(package): {}" ++msgstr "향상된 꾸러미: {}" + + #: plugins/repodiff.py:217 + msgid "Downgraded packages: {}" +-msgstr "하향설치된 꾸러미: {}" ++msgstr "하향 설치된 꾸러미: {}" + + #: plugins/repodiff.py:219 + msgid "Modified packages: {}" +-msgstr "변형된 꾸러미(package): {}" ++msgstr "변형된 꾸러미: {}" + + #: plugins/repodiff.py:222 + msgid "Size of added packages: {}" +-msgstr "크기가 증가된 꾸러미(package): {}" ++msgstr "크기가 증가된 꾸러미: {}" + + #: plugins/repodiff.py:223 + msgid "Size of removed packages: {}" +-msgstr "크기가 제거된 꾸러미(package): {}" ++msgstr "크기가 제거된 꾸러미: {}" + + #: plugins/repodiff.py:225 + msgid "Size of modified packages: {}" +-msgstr "크기가 변형된 꾸러미(package): {}" ++msgstr "크기가 변형된 꾸러미: {}" + + #: plugins/repodiff.py:228 + msgid "Size of upgraded packages: {}" +@@ -1096,7 +1140,7 @@ msgstr "크기 변경: {}" + + #: plugins/repograph.py:50 + msgid "Output a full package dependency graph in dot format" +-msgstr "도트 형식의 전체 꾸러미(package) 종속성 그래프 출력" ++msgstr "도트 형식의 전체 꾸러미 종속성 그래프 출력" + + #: plugins/repograph.py:110 + #, python-format +@@ -1105,43 +1149,55 @@ msgstr "아무것도 제공하지 않습니다 : '%s'" + + #: plugins/repomanage.py:45 + msgid "Manage a directory of rpm packages" +-msgstr "rpm 꾸러미(package) 디렉토리 관리" ++msgstr "rpm 꾸러미 디렉토리 관리" + + #: plugins/repomanage.py:59 + msgid "Pass either --old or --new, not both!" + msgstr "--old 또는 --new 중 하나를 전달하세요!" + +-#: plugins/repomanage.py:89 ++#: plugins/repomanage.py:61 ++msgid "Pass either --oldonly or --new, not both!" ++msgstr "--oldonly 또는 --new 중 하나를 전달하세요!" ++ ++#: plugins/repomanage.py:63 ++msgid "Pass either --old or --oldonly, not both!" ++msgstr "--old 또는 --oldonly 중 하나를 전달하세요!" ++ ++#: plugins/repomanage.py:100 + msgid "No files to process" + msgstr "처리 할 파일 없음" + +-#: plugins/repomanage.py:96 ++#: plugins/repomanage.py:107 + msgid "Could not open {}" + msgstr "{}을 열 수 없습니다" + +-#: plugins/repomanage.py:180 ++#: plugins/repomanage.py:223 + msgid "Print the older packages" +-msgstr "이전 꾸러미(package) 인쇄" ++msgstr "이전 꾸러미 인쇄" + +-#: plugins/repomanage.py:182 ++#: plugins/repomanage.py:225 ++msgid "Print the older packages. Exclude the newest packages." ++msgstr "이전 꾸러미를 출력합니다. 최신 꾸러미는 제외합니다." ++ ++#: plugins/repomanage.py:227 + msgid "Print the newest packages" +-msgstr "최신 꾸러미(package) 인쇄" ++msgstr "최신 꾸러미 출력" + +-#: plugins/repomanage.py:184 ++#: plugins/repomanage.py:229 + msgid "Space separated output, not newline" + msgstr "공백으로 구분 된 출력이 아닌 개행 문자" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:231 + msgid "Newest N packages to keep - defaults to 1" +-msgstr "보관할 최신 N 꾸러미(package) - 기본값은 1입니다" ++msgstr "보관하려는 최신 N 꾸러미 - 기본값은 1입니다" + +-#: plugins/repomanage.py:189 ++#: plugins/repomanage.py:234 + msgid "Path to directory" + msgstr "디렉토리 경로" + + #: plugins/reposync.py:55 + msgid "download all packages from remote repo" +-msgstr "원격 저장소에서 모든 꾸러미(package)를 내려받아요" ++msgstr "원격 저장소에서 모든 꾸러미를 내려받아요" + + #: plugins/reposync.py:64 + msgid "download only packages for this ARCH" +@@ -1153,7 +1209,7 @@ msgstr "저장소에 더 이상 존재하지 않는 로컬 꾸러미(package) + + #: plugins/reposync.py:68 + msgid "download all the metadata." +-msgstr "모든 메타데이타 내려받기." ++msgstr "모든 메타자료 내려받기." + + #: plugins/reposync.py:70 + msgid "Remove packages that fail GPG signature checking after downloading" +@@ -1168,8 +1224,8 @@ msgid "" + "where to store downloaded repository metadata. Defaults to the value of --" + "download-path." + msgstr "" +-"내려받은 저장소 메타데이타를 저장하기 위한 장소. --download-path의 값으로 기" +-"본 지정합니다." ++"내려받은 저장소 메타자료를 저장하기 위한 장소. --download-path의 값으로 기본 " ++"지정합니다." + + #: plugins/reposync.py:78 + msgid "download only newest packages per-repo" +@@ -1202,7 +1258,7 @@ msgstr "다중 저장소와 함께 --norepath를 사용 할 수 없습니다" + #: plugins/reposync.py:132 + #, python-format + msgid "Failed to get mirror for metadata: %s" +-msgstr "메타데이타에 대한 연결주소 얻기를 실패하였습니다:%s" ++msgstr "메타자료에 대한 연결주소 얻기를 실패하였습니다:%s" + + #: plugins/reposync.py:149 + msgid "Failed to get mirror for the group file." +@@ -1237,7 +1293,182 @@ msgstr "저장소에 대한 comps.xml %s 저장된" + + #: plugins/show_leaves.py:54 + msgid "New leaves:" +-msgstr "독립 꾸러미(package):" ++msgstr "독립 꾸러미:" ++ ++#. Translators: This string is only used in unit tests. ++#: plugins/system_upgrade.py:45 ++msgid "the color of the sky" ++msgstr "하늘의 색" ++ ++#: plugins/system_upgrade.py:57 ++msgid "Need a --releasever greater than the current system version." ++msgstr "현재 시스템 버전 보다 큰 --releasever가 필요합니다." ++ ++#. Translators: do not change "reboot" here ++#: plugins/system_upgrade.py:59 ++#, python-brace-format ++msgid "" ++"Download complete! Use 'dnf {command} reboot' to start the upgrade.\n" ++"To remove cached metadata and transaction use 'dnf {command} clean'" ++msgstr "" ++"내려받기 완료! 향상을 시작하려면 'dnf {command} reboot'를 사용하세요.\n" ++"캐쉬된 메타자료와 연결을 제거하려면 'dnf {command} clean'을 사용하세요" ++ ++#: plugins/system_upgrade.py:62 ++msgid "Sorry, you need to use 'download --releasever' instead of '--network'" ++msgstr "죄송합니다, '--network' 대신에 'download --releasever'를 사용해야 합니다" ++ ++#: plugins/system_upgrade.py:71 ++msgid "Reboot turned off, not rebooting." ++msgstr "다시 기동하지 않고, 재시작이 꺼졌습니다." ++ ++#: plugins/system_upgrade.py:122 ++#, python-format ++msgid "Screen blanking can't be disabled: %s" ++msgstr "화면 비우기를 비활성화 할 수 없습니다: %s" ++ ++#: plugins/system_upgrade.py:142 ++#, python-format ++msgid "Failed loading state file: %s, continuing with empty state." ++msgstr "상태 파일: %s를 적재 중 실패함, 공백 상태로 유지됨." ++ ++#: plugins/system_upgrade.py:289 ++msgid "The following boots appear to contain upgrade logs:" ++msgstr "다음 기동은 향상된 기록을 포함하여 나타납니다:" ++ ++#: plugins/system_upgrade.py:299 ++msgid "-- no logs were found --" ++msgstr "-- 어떤 기록도 찾을 수 없음 --" ++ ++#: plugins/system_upgrade.py:314 ++msgid "Cannot find logs with this index." ++msgstr "이 표시가 있는 기록을 찾을 수 없습니다." ++ ++#: plugins/system_upgrade.py:323 ++msgid "Unable to match systemd journal entry" ++msgstr "systemd journal 항목과 일치 할 수 없음" ++ ++#: plugins/system_upgrade.py:344 ++msgid "Prepare system for upgrade to a new release" ++msgstr "새로운 출시로 향상하기 위해 시스템을 준비합니다" ++ ++#: plugins/system_upgrade.py:360 ++msgid "keep installed packages if the new release's version is older" ++msgstr "만약 신규 출시의 버전이 오래되었으면 설치된 꾸러미를 유지합니다" ++ ++#: plugins/system_upgrade.py:364 ++msgid "which logs to show" ++msgstr "표시 할 어떤 기록" ++ ++#: plugins/system_upgrade.py:398 ++#, python-brace-format ++msgid "Incompatible version of data. Rerun 'dnf {command} download [OPTIONS]'" ++msgstr "호환되지 않는 자료 버전. 'dnf {command} download [OPTIONS]' 되돌리기" ++ ++#: plugins/system_upgrade.py:434 ++msgid "Command 'offline-distrosync' cannot be used with --no-downgrade option" ++msgstr "명령 'offline-distrosync'은 --no-downgrade 옵션과 함께 사용 될 수 없습니다" ++ ++#: plugins/system_upgrade.py:454 ++msgid "" ++"WARNING: this operation is not supported on the RHEL distribution. Proceed " ++"at your own risk." ++msgstr "경고: 이와 같은 동작은 RHEL 배포판에서 지원되지 않습니다. 자신의 책임 하에 " ++"진행하세요." ++ ++#: plugins/system_upgrade.py:458 ++msgid "Additional information for System Upgrade: {}" ++msgstr "시스템 향상을 위한 추가 정보: {}" ++ ++#: plugins/system_upgrade.py:461 ++msgid "" ++"Before you continue ensure that your system is fully upgraded by running " ++"\"dnf --refresh upgrade\". Do you want to continue" ++msgstr "계속하기 전에 dnf --refresh upgrade\" 실행하여 시스템을 완전히 향상 되도록 " ++"해주세요. 계속 하길 원하세요" ++ ++#: plugins/system_upgrade.py:465 ++msgid "Operation aborted." ++msgstr "작업이 중지됩니다." ++ ++#: plugins/system_upgrade.py:526 ++msgid "system is not ready for upgrade" ++msgstr "시스템이 향상을 위해 준비되지 않았습니다" ++ ++#: plugins/system_upgrade.py:529 ++#, python-brace-format ++msgid "" ++"the transaction was not prepared for '{command}'. Rerun 'dnf {command} " ++"download [OPTIONS]'" ++msgstr "" ++"연결이 '{command}'을 위해 준비되지 않았습니다. 'dnf {command} download " ++"[OPTIONS]'을 되돌립니다" ++ ++#: plugins/system_upgrade.py:533 ++msgid "upgrade is already scheduled" ++msgstr "향상은 이미 계획되어 있습니다" ++ ++#: plugins/system_upgrade.py:539 ++msgid "trigger file does not exist. exiting quietly." ++msgstr "트리거 파일이 존재하지 않습니다. 바로 종료하기." ++ ++#: plugins/system_upgrade.py:542 ++msgid "another upgrade tool is running. exiting quietly." ++msgstr "다른 향상 도구가 동작 중입니다. 바로 종료하기." ++ ++#: plugins/system_upgrade.py:551 ++#, python-brace-format ++msgid "use 'dnf {command} reboot' to begin the upgrade" ++msgstr "'dnf {command} reboot' 사용하여 향상을 시작합니다" ++ ++#: plugins/system_upgrade.py:569 ++msgid "Rebooting to perform upgrade." ++msgstr "향상을 수행하기 위해서 재시작 중." ++ ++#: plugins/system_upgrade.py:602 ++msgid "Starting offline upgrade. This will take a while." ++msgstr "오프라인 향상 시작하기. 이는 시간이 좀 걸립니다." ++ ++#: plugins/system_upgrade.py:604 ++msgid "Starting offline distrosync. This will take a while." ++msgstr "오프라인 distrosync 시작 중. 이는 시간이 좀 걸립니다." ++ ++#: plugins/system_upgrade.py:606 ++msgid "Starting system upgrade. This will take a while." ++msgstr "시스템 향상이 시작 중. 이는 시간이 좀 걸립니다." ++ ++#: plugins/system_upgrade.py:622 ++msgid "Cleaning up downloaded data..." ++msgstr "내려받기된 자료를 정리 중..." ++ ++#: plugins/system_upgrade.py:652 ++msgid "" ++"The system-upgrade transaction is empty, your system is already up-to-date." ++msgstr "시스템-향상 연결이 비워 있으며, 시스템은 이미 최신화 되었습니다." ++ ++#: plugins/system_upgrade.py:661 ++msgid "Transaction saved to {}." ++msgstr "연결이 {}로 저장되었습니다." ++ ++#: plugins/system_upgrade.py:664 ++msgid "Error storing transaction: {}" ++msgstr "저장 중 연결 오류: {}" ++ ++#: plugins/system_upgrade.py:686 ++msgid "Download finished." ++msgstr "내려받기 완료됨." ++ ++#: plugins/system_upgrade.py:689 plugins/system_upgrade.py:690 ++msgid "Upgrade complete! Cleaning up and rebooting..." ++msgstr "향상 성공! 정리하고 재시작하기..." ++ ++#: plugins/system_upgrade.py:699 ++msgid "Prepare offline upgrade of the system" ++msgstr "시스템의 오프라인 향상을 준비합니다" ++ ++#: plugins/system_upgrade.py:704 ++msgid "Prepare offline distrosync of the system" ++msgstr "시스템의 오프라인 distrosync를 준비합니다" + + #: plugins/versionlock.py:33 + #, python-format +@@ -1303,8 +1534,13 @@ msgstr "꾸러미(package) 사양을 그대로 사용하며, 구문 분석을 + + #: plugins/versionlock.py:160 + msgid "Subcommand '{}' is deprecated. Use 'exclude' subcommand instead." +-msgstr "하위명령 '{}'는 더 이상 사용하지 않습니다. 대신에 하위명령 'exclude'를 " +-"사용합니다." ++msgstr "" ++"하위명령 '{}'는 더 이상 사용하지 않습니다. 대신에 하위명령 'exclude'를 사용합" ++"니다." ++ ++#~ msgid "" ++#~ "This repository does not have any builds yet so you cannot enable it now." ++#~ msgstr "이 저장소에는 빌드가 아직 없으므로 지금 사용할 수 없습니다." + + #~ msgid "" + #~ "\n" +diff --git a/po/zh_CN.po b/po/zh_CN.po +index 5e5627e..973d486 100644 +--- a/po/zh_CN.po ++++ b/po/zh_CN.po +@@ -7,13 +7,13 @@ + # Hongqiao Chen , 2020. + # Sundeep Anand , 2021. + # Qiyu Yan , 2021. +-# Transtats , 2022. ++# Transtats , 2022, 2023. + msgid "" + msgstr "" + "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" +-"POT-Creation-Date: 2022-02-28 11:53+0100\n" +-"PO-Revision-Date: 2022-03-09 12:39+0000\n" ++"POT-Creation-Date: 2023-02-28 12:21+0100\n" ++"PO-Revision-Date: 2023-03-06 13:48+0000\n" + "Last-Translator: Transtats \n" + "Language-Team: Chinese (Simplified) \n" +@@ -22,7 +22,7 @@ msgstr "" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=1; plural=0;\n" +-"X-Generator: Weblate 4.11.2\n" ++"X-Generator: Weblate 4.15.2\n" + + #: plugins/builddep.py:45 + msgid "[PACKAGE|PACKAGE.spec]" +@@ -73,16 +73,21 @@ msgstr "没有匹配的软件包可以安装: '%s'" + msgid "Failed to open: '%s', not a valid source rpm file." + msgstr "打开文件失败: '%s',不是有效的源码 RPM 文件。" + +-#: plugins/builddep.py:204 plugins/builddep.py:220 plugins/builddep.py:237 ++#: plugins/builddep.py:204 plugins/builddep.py:224 plugins/builddep.py:241 + msgid "Not all dependencies satisfied" + msgstr "没有满足全部的依赖关系" + +-#: plugins/builddep.py:211 ++#: plugins/builddep.py:208 ++msgid "" ++"Warning: -D or --define arguments have no meaning for source rpm packages." ++msgstr "警告:-D 或 --define 参数对源 rpm 软件包没有意义。" ++ ++#: plugins/builddep.py:215 + #, python-format + msgid "Failed to open: '%s', not a valid spec file: %s" + msgstr "打开失败: '%s', 不是有效的 spec 文件: %s" + +-#: plugins/builddep.py:230 plugins/repoclosure.py:118 ++#: plugins/builddep.py:234 plugins/repoclosure.py:118 + #, python-format + msgid "no package matched: %s" + msgstr "无匹配软件包: %s" +@@ -208,27 +213,27 @@ msgstr[0] "配置仓库失败" + msgid "Could not save repo to repofile %s: %s" + msgstr "无法保存仓库至仓库文件 %s:%s" + +-#: plugins/copr.py:64 ++#: plugins/copr.py:70 + msgid "y" + msgstr "y" + +-#: plugins/copr.py:64 ++#: plugins/copr.py:70 + msgid "yes" + msgstr "是" + +-#: plugins/copr.py:65 ++#: plugins/copr.py:71 + msgid "n" + msgstr "n" + +-#: plugins/copr.py:65 ++#: plugins/copr.py:71 + msgid "no" + msgstr "否" + +-#: plugins/copr.py:84 ++#: plugins/copr.py:92 + msgid "Interact with Copr repositories." + msgstr "与 Copr 仓库交互。" + +-#: plugins/copr.py:86 ++#: plugins/copr.py:94 + msgid "" + "\n" + " enable name/project [chroot]\n" +@@ -266,31 +271,31 @@ msgstr "" + " copr search tests\n" + " " + +-#: plugins/copr.py:112 ++#: plugins/copr.py:120 + msgid "List all installed Copr repositories (default)" + msgstr "列出所有安装的 Copr 仓库(默认)" + +-#: plugins/copr.py:114 ++#: plugins/copr.py:122 + msgid "List enabled Copr repositories" + msgstr "列出启动的 Copr 仓库" + +-#: plugins/copr.py:116 ++#: plugins/copr.py:124 + msgid "List disabled Copr repositories" + msgstr "列出禁用的 Copr 仓库" + +-#: plugins/copr.py:118 ++#: plugins/copr.py:126 + msgid "List available Copr repositories by user NAME" + msgstr "按照用户 NAME 列出可用的 Copr 仓库" + +-#: plugins/copr.py:120 ++#: plugins/copr.py:128 + msgid "Specify an instance of Copr to work with" + msgstr "指定需要使用的 Copr 实例" + +-#: plugins/copr.py:154 plugins/copr.py:222 plugins/copr.py:249 ++#: plugins/copr.py:164 plugins/copr.py:236 plugins/copr.py:263 + msgid "Error: " + msgstr "错误: " + +-#: plugins/copr.py:155 ++#: plugins/copr.py:165 + msgid "" + "specify Copr hub either with `--hub` or using `copr_hub/copr_username/" + "copr_projectname` format" +@@ -298,33 +303,33 @@ msgstr "" + "使用 `--hub` 或使用 `copr_hub/copr_username/copr_projectname` 格式指定 Copr " + "hub" + +-#: plugins/copr.py:158 ++#: plugins/copr.py:168 + msgid "multiple hubs specified" + msgstr "指定多个 hub" + +-#: plugins/copr.py:223 plugins/copr.py:227 ++#: plugins/copr.py:237 plugins/copr.py:241 + msgid "exactly two additional parameters to copr command are required" + msgstr "Copr 命令要求有且仅有两个额外参数" + +-#: plugins/copr.py:232 ++#: plugins/copr.py:246 + msgid "Too many arguments." + msgstr "参数过多。" + +-#: plugins/copr.py:235 ++#: plugins/copr.py:249 + msgid "" + "Bad format of optional chroot. The format is distribution-version-" + "architecture." + msgstr "可选 chroot 的错误格式。格式为 distribution-version-architecture。" + +-#: plugins/copr.py:250 ++#: plugins/copr.py:264 + msgid "use format `copr_username/copr_projectname` to reference copr project" + msgstr "使用格式 `copr_username/copr_projectname` 来引用 Copr 项目" + +-#: plugins/copr.py:252 ++#: plugins/copr.py:266 + msgid "bad copr project format" + msgstr "错误的 Copr 项目格式" + +-#: plugins/copr.py:266 ++#: plugins/copr.py:280 + msgid "" + "\n" + "Enabling a Copr repository. Please note that this repository is not part\n" +@@ -352,23 +357,23 @@ msgstr "" + "请不要在 Fedora Bugzilla 中报告这些软件包中出现的\n" + "问题。当出现问题时,请联系仓库的所有者。\n" + +-#: plugins/copr.py:283 ++#: plugins/copr.py:297 + msgid "Repository successfully enabled." + msgstr "启用软件仓库成功。" + +-#: plugins/copr.py:288 ++#: plugins/copr.py:302 + msgid "Repository successfully disabled." + msgstr "禁用软件仓库成功。" + +-#: plugins/copr.py:292 ++#: plugins/copr.py:306 + msgid "Repository successfully removed." + msgstr "软件仓库已成功删除。" + +-#: plugins/copr.py:296 plugins/copr.py:697 ++#: plugins/copr.py:310 plugins/copr.py:721 + msgid "Unknown subcommand {}." + msgstr "未知的子命令 {}。" + +-#: plugins/copr.py:353 ++#: plugins/copr.py:367 + msgid "" + "* These coprs have repo file with an old format that contains no information " + "about Copr hub - the default one was assumed. Re-enable the project to fix " +@@ -377,48 +382,86 @@ msgstr "" + "* 这些 coprs 有使用旧格式的 repo 文件,它们没有包括 Copr hub 的信息 - 假设使" + "用默认值。重新启用项目来解决这个问题。" + +-#: plugins/copr.py:366 ++#: plugins/copr.py:380 + msgid "Can't parse repositories for username '{}'." + msgstr "无法为用户名 username '{}' 解析仓库。" + +-#: plugins/copr.py:369 ++#: plugins/copr.py:383 + msgid "List of {} coprs" + msgstr "{} Coprs 列表" + +-#: plugins/copr.py:374 ++#: plugins/copr.py:388 + msgid "No description given" + msgstr "没有给出描述" + +-#: plugins/copr.py:386 ++#: plugins/copr.py:400 + msgid "Can't parse search for '{}'." + msgstr "无法解析针对 '{}' 的搜索。" + +-#: plugins/copr.py:389 ++#: plugins/copr.py:403 + msgid "Matched: {}" + msgstr "匹配:{}" + +-#: plugins/copr.py:394 ++#: plugins/copr.py:408 + msgid "No description given." + msgstr "没有给出描述。" + +-#: plugins/copr.py:416 ++#: plugins/copr.py:430 + msgid "Safe and good answer. Exiting." + msgstr "安全及明智的答案。退出。" + +-#: plugins/copr.py:423 ++#: plugins/copr.py:437 + msgid "This command has to be run under the root user." + msgstr "该命令必须以 root 用户运行。" + +-#: plugins/copr.py:485 ++#: plugins/copr.py:487 ++#, python-brace-format ++msgid "Request to {0} failed: {1} - {2}" ++msgstr "请求 {0} 失败:{1} - {2}" ++ ++#: plugins/copr.py:489 ++msgid "It wasn't possible to enable this project.\n" ++msgstr "无法启用此项目。\n" ++ ++#: plugins/copr.py:494 ++#, python-brace-format ++msgid "Repository '{0}' does not exist in project '{1}'." ++msgstr "仓库 '{0}' 在项目 '{1}' 中不存在。" ++ ++#: plugins/copr.py:497 + msgid "" +-"This repository does not have any builds yet so you cannot enable it now." +-msgstr "该仓库尚未包含任何构建所以您现在无法启用它。" ++"\n" ++"Available repositories: " ++msgstr "" ++"\n" ++"可用软件仓库: " + +-#: plugins/copr.py:488 +-msgid "Such repository does not exist." +-msgstr "该软件仓库不存在。" ++#: plugins/copr.py:499 ++#, python-brace-format ++msgid "" ++"\n" ++"\n" ++"If you want to enable a non-default repository, use the following command:\n" ++" 'dnf copr enable {0} '\n" ++"But note that the installed repo file will likely need a manual modification." ++msgstr "" ++"\n" ++"\n" ++"如果需要启用一个非默认的仓库,使用以下命令 :\n" ++" 'dnf copr enable {0} '\n" ++"但请注意,安装的 repo 文件将来可能需要手动修改。" + +-#: plugins/copr.py:532 ++#: plugins/copr.py:505 ++#, python-brace-format ++msgid "Project {0} does not exist." ++msgstr "项目 {0} 不存在。" ++ ++#: plugins/copr.py:508 ++#, python-brace-format ++msgid "Failed to connect to {0}: {1}" ++msgstr "连接到 {0} 失败:{1}" ++ ++#: plugins/copr.py:555 + #, python-brace-format + msgid "" + "Maintainer of the enabled Copr repository decided to make\n" +@@ -447,44 +490,44 @@ msgstr "" + "\n" + "这些仓库已被自动启用。" + +-#: plugins/copr.py:553 ++#: plugins/copr.py:576 + msgid "Do you want to keep them enabled?" + msgstr "您需要保持它们被启用吗?" + +-#: plugins/copr.py:586 ++#: plugins/copr.py:609 + #, python-brace-format + msgid "Failed to remove copr repo {0}/{1}/{2}" +-msgstr "删除 copr 仓库 {0}/{1}/{2} 失败" ++msgstr "无法删除 copr 存储库 {0}/{1}/{2}" + +-#: plugins/copr.py:597 ++#: plugins/copr.py:620 + msgid "Failed to disable copr repo {}/{}" +-msgstr "无法禁用 Copr 软件仓库 {}/{}" ++msgstr "无法禁用 Copr 存储库 {}/{}" + +-#: plugins/copr.py:615 plugins/copr.py:652 ++#: plugins/copr.py:638 plugins/copr.py:675 + msgid "Unknown response from server." + msgstr "来自服务器的未知响应。" + +-#: plugins/copr.py:637 ++#: plugins/copr.py:660 + msgid "Interact with Playground repository." + msgstr "与 Playground 仓库交互。" + +-#: plugins/copr.py:643 ++#: plugins/copr.py:666 + msgid "Enabling a Playground repository." + msgstr "启用 Playground 仓库。" + +-#: plugins/copr.py:644 ++#: plugins/copr.py:667 + msgid "Do you want to continue?" + msgstr "您希望继续吗?" + +-#: plugins/copr.py:687 ++#: plugins/copr.py:711 + msgid "Playground repositories successfully enabled." + msgstr "启用 Playground 仓库成功。" + +-#: plugins/copr.py:690 ++#: plugins/copr.py:714 + msgid "Playground repositories successfully disabled." + msgstr "禁用 Playground 仓库成功。" + +-#: plugins/copr.py:694 ++#: plugins/copr.py:718 + msgid "Playground repositories successfully updated." + msgstr "更新 Playground 仓库成功。" + +@@ -737,7 +780,7 @@ msgstr "软件包规格" + + #: plugins/groups_manager.py:156 + msgid "Can't edit group without specifying it (use --id or --name)" +-msgstr "没有指定组(使用 --id 或 --name)就无法编辑组" ++msgstr "没有指定它(使用 --id 或 --name)就不能编辑组" + + #: plugins/groups_manager.py:190 + msgid "Can't load file \"{}\": {}" +@@ -791,7 +834,7 @@ msgstr "迁移 yum 的历史、分组以及 yumdb 数据至 dnf" + + #: plugins/migrate.py:54 + msgid "Migrating history data..." +-msgstr "正在迁移历史数据…" ++msgstr "正在迁移历史数据..." + + #: plugins/modulesync.py:37 + msgid "" +@@ -821,7 +864,7 @@ msgstr "只从最新的模块中下载软件包" + #: plugins/modulesync.py:85 + msgid "Unable to find a match for argument: '{}'" + msgid_plural "Unable to find a match for arguments: '{}'" +-msgstr[0] "找不到与参数:'{}'相匹配的项" ++msgstr[0] "找不到与参数匹配的项:'{}'" + + #: plugins/modulesync.py:107 + msgid "" +@@ -832,12 +875,12 @@ msgstr "创建存储库会失败,并显示返回码 {}。所有下载的内容 + #: plugins/modulesync.py:144 + #, python-brace-format + msgid "No match for artifact '{0}' from module '{1}'" +-msgstr "没有与模块 '{1}' 的工件 '{0}' 相匹配的项" ++msgstr "没有与来自模块 '{1}' 的工件 '{0}' 相匹配的项" + + #: plugins/modulesync.py:162 + #, python-brace-format + msgid "No match for package name '{0}' in profile {1} from module {2}" +-msgstr "没有与模块 {2} 中配置文件 {1} 的软件包名称 '{0}' 相匹配的项" ++msgstr "没有与来自模块 {2} 中配置集 {1} 的软件包名称 '{0}' 相匹配的项" + + #: plugins/modulesync.py:166 + msgid "No mach for argument '{}'" +@@ -853,8 +896,9 @@ msgstr "无法满足要求 {}" + msgid "" + "No installed package found for package name \"{pkg}\" specified in needs-" + "restarting file \"{file}\"." +-msgstr "未找到在需要重新启动文件 \"{file}\" 中指定的软件包名为 \"{pkg}\" " +-"的已安装的软件包。" ++msgstr "" ++"未找到在需要重新启动的文件 \"{file}\" 中指定的软件包名为 \"{pkg}\" 的已安装的" ++"软件包。" + + #: plugins/needs_restarting.py:220 + msgid "determine updated binaries that need restarting" +@@ -899,18 +943,18 @@ msgid "Bad Action Line \"%s\": %s" + msgstr "错误的操作行“ %s”: %s" + + #. unsupported state, skip it +-#: plugins/post-transaction-actions.py:130 ++#: plugins/post-transaction-actions.py:133 + #, python-format + msgid "Bad Transaction State: %s" + msgstr "错误的事务状态: %s" + +-#: plugins/post-transaction-actions.py:157 +-#: plugins/post-transaction-actions.py:159 ++#: plugins/post-transaction-actions.py:160 ++#: plugins/post-transaction-actions.py:162 + #, python-format + msgid "post-transaction-actions: %s" + msgstr "事物后的操作: %s" + +-#: plugins/post-transaction-actions.py:161 ++#: plugins/post-transaction-actions.py:164 + #, python-format + msgid "post-transaction-actions: Bad Command \"%s\": %s" + msgstr "事物后的操作 : 无效的命令 \"%s\": %s" +@@ -1087,33 +1131,45 @@ msgstr "管理 RPM 软件包目录" + + #: plugins/repomanage.py:59 + msgid "Pass either --old or --new, not both!" +-msgstr "传入 --old 或者 --new,不可同时传入!" ++msgstr "传递 --old 或者 --new,而不是两者都传递!" + +-#: plugins/repomanage.py:89 ++#: plugins/repomanage.py:61 ++msgid "Pass either --oldonly or --new, not both!" ++msgstr "传递 --oldonly 或 --new,而不是两者都传递!" ++ ++#: plugins/repomanage.py:63 ++msgid "Pass either --old or --oldonly, not both!" ++msgstr "传递 --old 或 --oldonly,而不是两者都传递!" ++ ++#: plugins/repomanage.py:100 + msgid "No files to process" + msgstr "没有可处理的文件" + +-#: plugins/repomanage.py:96 ++#: plugins/repomanage.py:107 + msgid "Could not open {}" + msgstr "无法打开 {}" + +-#: plugins/repomanage.py:180 ++#: plugins/repomanage.py:223 + msgid "Print the older packages" + msgstr "打印较旧的软件包" + +-#: plugins/repomanage.py:182 ++#: plugins/repomanage.py:225 ++msgid "Print the older packages. Exclude the newest packages." ++msgstr "打印旧的软件包。排除最新的软件包。" ++ ++#: plugins/repomanage.py:227 + msgid "Print the newest packages" + msgstr "打印最新的软件包" + +-#: plugins/repomanage.py:184 ++#: plugins/repomanage.py:229 + msgid "Space separated output, not newline" + msgstr "用空格分割输出,而不是新行" + +-#: plugins/repomanage.py:186 ++#: plugins/repomanage.py:231 + msgid "Newest N packages to keep - defaults to 1" + msgstr "要保留的最新的 N 个软件包 - 默认值为 1" + +-#: plugins/repomanage.py:189 ++#: plugins/repomanage.py:234 + msgid "Path to directory" + msgstr "指向目录的路径" + +@@ -1215,6 +1271,178 @@ msgstr "仓库 %s 的 comps.xml 已保存" + msgid "New leaves:" + msgstr "新增保留项:" + ++#. Translators: This string is only used in unit tests. ++#: plugins/system_upgrade.py:45 ++msgid "the color of the sky" ++msgstr "sky 的颜色" ++ ++#: plugins/system_upgrade.py:57 ++msgid "Need a --releasever greater than the current system version." ++msgstr "需要大于当前系统版本的 --releasever。" ++ ++#. Translators: do not change "reboot" here ++#: plugins/system_upgrade.py:59 ++#, python-brace-format ++msgid "" ++"Download complete! Use 'dnf {command} reboot' to start the upgrade.\n" ++"To remove cached metadata and transaction use 'dnf {command} clean'" ++msgstr "" ++"下载完成!使用 'dnf {command} reboot' 启动升级。 \n" ++" 要删除缓存的元数据和事务,请使用 'dnf {command} clean'" ++ ++#: plugins/system_upgrade.py:62 ++msgid "Sorry, you need to use 'download --releasever' instead of '--network'" ++msgstr "您需要使用 'download --releasever' 而不是 '-network'" ++ ++#: plugins/system_upgrade.py:71 ++msgid "Reboot turned off, not rebooting." ++msgstr "重启被关闭,没有重新启动。" ++ ++#: plugins/system_upgrade.py:122 ++#, python-format ++msgid "Screen blanking can't be disabled: %s" ++msgstr "无法禁用屏幕空白:%s" ++ ++#: plugins/system_upgrade.py:142 ++#, python-format ++msgid "Failed loading state file: %s, continuing with empty state." ++msgstr "加载状态文件失败:%s,继续为空状态。" ++ ++#: plugins/system_upgrade.py:289 ++msgid "The following boots appear to contain upgrade logs:" ++msgstr "以下引导会包含升级日志:" ++ ++#: plugins/system_upgrade.py:299 ++msgid "-- no logs were found --" ++msgstr "-- 没有找到日志 --" ++ ++#: plugins/system_upgrade.py:314 ++msgid "Cannot find logs with this index." ++msgstr "无法找到使用此索引的日志。" ++ ++#: plugins/system_upgrade.py:323 ++msgid "Unable to match systemd journal entry" ++msgstr "无法与 systemd 日志条目匹配" ++ ++#: plugins/system_upgrade.py:344 ++msgid "Prepare system for upgrade to a new release" ++msgstr "准备系统以升级到新版本" ++ ++#: plugins/system_upgrade.py:360 ++msgid "keep installed packages if the new release's version is older" ++msgstr "如果新版本中的版本更旧,保留安装的软件包" ++ ++#: plugins/system_upgrade.py:364 ++msgid "which logs to show" ++msgstr "要显示的日志" ++ ++#: plugins/system_upgrade.py:398 ++#, python-brace-format ++msgid "Incompatible version of data. Rerun 'dnf {command} download [OPTIONS]'" ++msgstr "不兼容的数据版本。重新运行 'dnf {command} download [OPTIONS]'" ++ ++#: plugins/system_upgrade.py:434 ++msgid "Command 'offline-distrosync' cannot be used with --no-downgrade option" ++msgstr "命令 'offline-distrosync' 无法与 --no-downgrade 选项一起使用" ++ ++#: plugins/system_upgrade.py:454 ++msgid "" ++"WARNING: this operation is not supported on the RHEL distribution. Proceed " ++"at your own risk." ++msgstr "警告:在 RHEL 发行版上不支持此操作。您需要自性承担相关的风险。" ++ ++#: plugins/system_upgrade.py:458 ++msgid "Additional information for System Upgrade: {}" ++msgstr "系统升级的额外信息:{}" ++ ++#: plugins/system_upgrade.py:461 ++msgid "" ++"Before you continue ensure that your system is fully upgraded by running " ++"\"dnf --refresh upgrade\". Do you want to continue" ++msgstr "在继续请,确定您的系统已通过运行 \"dnf --refresh upgrade\" " ++"完全升级。您要继续操作" ++ ++#: plugins/system_upgrade.py:465 ++msgid "Operation aborted." ++msgstr "操作中止。" ++ ++#: plugins/system_upgrade.py:526 ++msgid "system is not ready for upgrade" ++msgstr "系统还未就绪进行升级" ++ ++#: plugins/system_upgrade.py:529 ++#, python-brace-format ++msgid "" ++"the transaction was not prepared for '{command}'. Rerun 'dnf {command} " ++"download [OPTIONS]'" ++msgstr "事务没有为 '{command}' 准备。重新运行 'dnf {command} download [OPTIONS]'" ++ ++#: plugins/system_upgrade.py:533 ++msgid "upgrade is already scheduled" ++msgstr "升级已被调度" ++ ++#: plugins/system_upgrade.py:539 ++msgid "trigger file does not exist. exiting quietly." ++msgstr "触发器文件不存在。静默退出。" ++ ++#: plugins/system_upgrade.py:542 ++msgid "another upgrade tool is running. exiting quietly." ++msgstr "另一个升级工具正在运行。静默退出。" ++ ++#: plugins/system_upgrade.py:551 ++#, python-brace-format ++msgid "use 'dnf {command} reboot' to begin the upgrade" ++msgstr "使用 'dnf {command} reboot' 开始升级" ++ ++#: plugins/system_upgrade.py:569 ++msgid "Rebooting to perform upgrade." ++msgstr "重启以执行升级。" ++ ++#: plugins/system_upgrade.py:602 ++msgid "Starting offline upgrade. This will take a while." ++msgstr "启动离线升级。这将需要一段时间。" ++ ++#: plugins/system_upgrade.py:604 ++msgid "Starting offline distrosync. This will take a while." ++msgstr "启动离线 distrosync。这将需要一段时间。" ++ ++#: plugins/system_upgrade.py:606 ++msgid "Starting system upgrade. This will take a while." ++msgstr "启动系统升级。这需要一段时间。" ++ ++#: plugins/system_upgrade.py:622 ++msgid "Cleaning up downloaded data..." ++msgstr "清理下载的数据..." ++ ++#: plugins/system_upgrade.py:652 ++msgid "" ++"The system-upgrade transaction is empty, your system is already up-to-date." ++msgstr "system-upgrade 事务为空,您的系统已经为最新版本。" ++ ++#: plugins/system_upgrade.py:661 ++msgid "Transaction saved to {}." ++msgstr "事务已保存到 {}。" ++ ++#: plugins/system_upgrade.py:664 ++msgid "Error storing transaction: {}" ++msgstr "存储事务时出现错误:{}" ++ ++#: plugins/system_upgrade.py:686 ++msgid "Download finished." ++msgstr "下载已完成。" ++ ++#: plugins/system_upgrade.py:689 plugins/system_upgrade.py:690 ++msgid "Upgrade complete! Cleaning up and rebooting..." ++msgstr "升级完成!清理并重启..." ++ ++#: plugins/system_upgrade.py:699 ++msgid "Prepare offline upgrade of the system" ++msgstr "准备系统的离线升级" ++ ++#: plugins/system_upgrade.py:704 ++msgid "Prepare offline distrosync of the system" ++msgstr "准备系统的离线 distrosync" ++ + #: plugins/versionlock.py:33 + #, python-format + msgid "Unable to read version lock configuration: %s" +@@ -1281,6 +1509,10 @@ msgstr "按原样使用程序包规格,请勿尝试解析它们" + msgid "Subcommand '{}' is deprecated. Use 'exclude' subcommand instead." + msgstr "子命令 '{}' 已被弃用。改为使用 'exclude' 子命令。" + ++#~ msgid "" ++#~ "This repository does not have any builds yet so you cannot enable it now." ++#~ msgstr "该仓库尚未包含任何构建所以您现在无法启用它。" ++ + #~ msgid "" + #~ "\n" + #~ "You are about to enable a Playground repository.\n" +-- +2.39.2 + diff --git a/SOURCES/0030-versionlock-Use-only-most-specif-NEVRA-RhBug-1961217.patch b/SOURCES/0030-versionlock-Use-only-most-specif-NEVRA-RhBug-1961217.patch new file mode 100644 index 0000000..b6a6ad4 --- /dev/null +++ b/SOURCES/0030-versionlock-Use-only-most-specif-NEVRA-RhBug-1961217.patch @@ -0,0 +1,88 @@ +From ee0e1ca0751d29adcc4788334ce8fd74b4d772c9 Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Wed, 19 May 2021 16:52:57 +0200 +Subject: [PATCH] versionlock: Store full NEVRA + +--- + plugins/versionlock.py | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/plugins/versionlock.py b/plugins/versionlock.py +index 77b7f91..8a3994e 100644 +--- a/plugins/versionlock.py ++++ b/plugins/versionlock.py +@@ -312,5 +312,4 @@ def _match(ent, patterns): + + def pkgtup2spec(name, arch, epoch, version, release): + # we ignore arch +- e = "" if epoch in (None, "") else "%s:" % epoch +- return "%s-%s%s-%s.*" % (name, e, version, release) ++ return "%s-%s:%s-%s.*" % (name, epoch or "0", version, release) +-- +2.40.1 + + +From da25d50a8753b0a648a2653e2fb9e33eb372f73f Mon Sep 17 00:00:00 2001 +From: Marek Blaha +Date: Wed, 19 May 2021 16:53:37 +0200 +Subject: [PATCH] versionlock: Use only the most specific NEVRA (RhBug:1961217) + +When matching patterns from versionlock.list file accept only the most +specific possible NEVRA. +The problem with current implementation (using of all possible variants) +is following (also see the referenced bug): + +$ dnf repoquery procps-ng +procps-ng-0:3.3.17-1.fc34.1.x86_64 +procps-ng-0:3.3.17-1.fc34.x86_64 <-- this one is installed + +See the `.1` minorbump part of the release after %{dist} in +`procps-ng-0:3.3.17-1.fc34.1.x86_64` + +$ dnf versionlock procps-ng +Adding versionlock on: procps-ng-0:3.3.17-1.fc34.* + +Now both of the available procps-ng version could be matched by this +pattern: +- procps-ng-0:3.3.17-1.fc34.x86_64 (when `*` is considered arch) +- procps-ng-0:3.3.17-1.fc34.1.x86_64 (when `*` is matched against + release part, and arch is considered not present) + +That results in versionlock allowing upgrade to a newer version than the +locked one. + += changelog = +msg: Versionlock works correctly with packages with minorbump part of release +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1961217 +--- + plugins/versionlock.py | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/plugins/versionlock.py b/plugins/versionlock.py +index 8a3994e..32c51da 100644 +--- a/plugins/versionlock.py ++++ b/plugins/versionlock.py +@@ -89,7 +89,9 @@ class VersionLock(dnf.Plugin): + pat = pat[1:] + excl = 1 + +- possible_nevras = dnf.subject.Subject(pat).get_nevra_possibilities() ++ possible_nevras = dnf.subject.Subject(pat).get_nevra_possibilities( ++ forms=[hawkey.FORM_NEVRA, hawkey.FORM_NEVR, hawkey.FORM_NEV, ++ hawkey.FORM_NA, hawkey.FORM_NAME]) + if possible_nevras: + count[excl] += 1 + else: +@@ -102,6 +104,8 @@ class VersionLock(dnf.Plugin): + else: + locked_names.add(nevra.name) + locked_query = locked_query.union(pat_query) ++ if pat_query: ++ break + + if count[1]: + logger.debug(APPLY_EXCLUDE.format(locklist_fn, count[1])) +-- +2.40.1 + diff --git a/SOURCES/0031-Fix-boot-time-derivation-for-systems-with-no-rtc.patch b/SOURCES/0031-Fix-boot-time-derivation-for-systems-with-no-rtc.patch new file mode 100644 index 0000000..b5083ff --- /dev/null +++ b/SOURCES/0031-Fix-boot-time-derivation-for-systems-with-no-rtc.patch @@ -0,0 +1,55 @@ +From 23a6123348f0a387768ebdfdaaded900a083039e Mon Sep 17 00:00:00 2001 +From: Todd Lewis +Date: Wed, 16 Nov 2022 10:45:39 -0500 +Subject: [PATCH] Fix boot time derivation for systems with no rtc + +That addresses https://bugzilla.redhat.com/show_bug.cgi?id=2137935 +--- + plugins/needs_restarting.py | 24 +++++++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py +index 91dbe66..03831fa 100644 +--- a/plugins/needs_restarting.py ++++ b/plugins/needs_restarting.py +@@ -34,6 +34,7 @@ import functools + import os + import re + import stat ++import time + + + # For which package updates we should recommend a reboot +@@ -199,7 +200,28 @@ class ProcessStart(object): + + @staticmethod + def get_boot_time(): +- return int(os.stat('/proc/1').st_mtime) ++ """ ++ We have two sources from which to derive the boot time. These values vary ++ depending on containerization, existence of a Real Time Clock, etc. ++ For our purposes we want the latest derived value. ++ - st_mtime of /proc/1 ++ Reflects the time the first process was run after booting ++ This works for all known cases except machines without ++ a RTC - they awake at the start of the epoch. ++ - /proc/uptime ++ Seconds field of /proc/uptime subtracted from the current time ++ Works for machines without RTC iff the current time is reasonably correct. ++ Does not work on containers which share their kernel with the ++ host - there the host kernel uptime is returned ++ """ ++ ++ proc_1_boot_time = int(os.stat('/proc/1').st_mtime) ++ if os.path.isfile('/proc/uptime'): ++ with open('/proc/uptime', 'rb') as f: ++ uptime = f.readline().strip().split()[0].strip() ++ proc_uptime_boot_time = int(time.time() - float(uptime)) ++ return max(proc_1_boot_time, proc_uptime_boot_time) ++ return proc_1_boot_time + + @staticmethod + def get_sc_clk_tck(): +-- +libgit2 1.3.2 + diff --git a/SOURCES/0032-Doc-update-for-reposync-RhBug-2132383-2182004.patch b/SOURCES/0032-Doc-update-for-reposync-RhBug-2132383-2182004.patch new file mode 100644 index 0000000..471c4d3 --- /dev/null +++ b/SOURCES/0032-Doc-update-for-reposync-RhBug-2132383-2182004.patch @@ -0,0 +1,34 @@ +From a83af3db9f1aaf698be5455a01814849e39307d8 Mon Sep 17 00:00:00 2001 +From: Jaroslav Mracek +Date: Mon, 27 Mar 2023 10:24:59 +0200 +Subject: [PATCH] Documentation update for reposync (RhBug:2132383,2182004) + +The update describe the behavior when `-n` and `--download-metadata` +is used. + +https://bugzilla.redhat.com/show_bug.cgi?id=2132383 +https://bugzilla.redhat.com/show_bug.cgi?id=2182004 +--- + doc/reposync.rst | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/doc/reposync.rst b/doc/reposync.rst +index 0df00b9..bbf714c 100644 +--- a/doc/reposync.rst ++++ b/doc/reposync.rst +@@ -46,7 +46,11 @@ All general DNF options are accepted. Namely, the ``--repoid`` option can be use + Delete local packages no longer present in repository. + + ``--download-metadata`` +- Download all repository metadata. Downloaded copy is instantly usable as a repository, no need to run createrepo_c on it. ++ Download all repository metadata. Downloaded copy is instantly usable as a repository, no need to run createrepo_c ++ on it. When the option is used with `--newest-only`, only latest packages will be downloaded, but metadata will ++ still contain older packages. It might be useful to update metadata using `createrepo_c --update` to remove ++ the packages with missing RPM files from metadata. Otherwise, DNF ends with an error due to the missing files ++ whenever it tries to download older packages. + + ``-g, --gpgcheck`` + Remove packages that fail GPG signature checking after downloading. Exit code is ``1`` if at least one package was removed. +-- +libgit2 1.3.2 + diff --git a/SOURCES/0033-Add-fix-and-test-assertion-for-no-systemd-unit-exist.patch b/SOURCES/0033-Add-fix-and-test-assertion-for-no-systemd-unit-exist.patch new file mode 100644 index 0000000..7439956 --- /dev/null +++ b/SOURCES/0033-Add-fix-and-test-assertion-for-no-systemd-unit-exist.patch @@ -0,0 +1,88 @@ +From b086bfe09cf0eec67ea830e0e0f3482c6b6b2aa9 Mon Sep 17 00:00:00 2001 +From: Andy Baugh +Date: Fri, 28 Apr 2023 10:52:16 -0500 +Subject: [PATCH] Add fix and test assertion for "no systemd unit exists for + pid" + += changelog = +msg: Catch exception in needs-restarting.py when no systemd unit exists for pid +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2122587 +related: None +--- + plugins/needs_restarting.py | 18 ++++++++++++++---- + tests/test_needs_restarting.py | 15 +++++++++++++-- + 2 files changed, 27 insertions(+), 6 deletions(-) + +diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py +index 03831fa..8dbc965 100644 +--- a/plugins/needs_restarting.py ++++ b/plugins/needs_restarting.py +@@ -138,10 +138,20 @@ def get_service_dbus(pid): + systemd_manager_object, + 'org.freedesktop.systemd1.Manager' + ) +- service_proxy = bus.get_object( +- 'org.freedesktop.systemd1', +- systemd_manager_interface.GetUnitByPID(pid) +- ) ++ service_proxy = None ++ try: ++ service_proxy = bus.get_object( ++ 'org.freedesktop.systemd1', ++ systemd_manager_interface.GetUnitByPID(pid) ++ ) ++ except dbus.DBusException as e: ++ # There is no unit for the pid. Usually error is 'NoUnitForPid'. ++ # Considering what we do at the bottom (just return if not service) ++ # Then there's really no reason to exit here on that exception. ++ # Log what's happened then move on. ++ msg = str(e) ++ logger.warning("Failed to get systemd unit for PID {}: {}".format(pid, msg)) ++ return + service_properties = dbus.Interface( + service_proxy, dbus_interface="org.freedesktop.DBus.Properties") + name = service_properties.Get( +diff --git a/tests/test_needs_restarting.py b/tests/test_needs_restarting.py +index 0ad70a5..7b629b4 100644 +--- a/tests/test_needs_restarting.py ++++ b/tests/test_needs_restarting.py +@@ -20,6 +20,8 @@ from __future__ import absolute_import + from __future__ import print_function + from __future__ import unicode_literals + ++from unittest.mock import patch, Mock ++import dbus + import needs_restarting + import tests.support + +@@ -29,8 +31,6 @@ MM_FILE = '7fc4e1168000-7fc4e1169000 rw-s 1096dd000 00:05 7749' \ + ' /dev/dri/card0' + SO_FILE = '30efe06000-30efe07000 r--p 00006000 08:02 139936' \ + ' /usr/lib64/libSM.so.6.0.1' +- +- + class NeedsRestartingTest(tests.support.TestCase): + def test_smap2opened_file(self): + func = needs_restarting.smap2opened_file +@@ -46,6 +46,17 @@ class NeedsRestartingTest(tests.support.TestCase): + self.assertTrue(ofile.deleted) + self.assertEqual(ofile.name, '/usr/lib64/libXfont.so.1.4.1;5408628d') + ++ def test_get_service_dbus_nounitforpid(self): ++ func = needs_restarting.get_service_dbus ++ # So, This is gonna look kinda screwy unless you are aware of what ++ # this proxies interface is actually doing. The GetUnitByPid function ++ # is normally "dynamically" defined by the get_dbus_method at runtime. ++ # As such there's no actual way to mock it out in any meaningful way ++ # without create=True. ++ with patch( "dbus.proxies.Interface.GetUnitByPID", create=True, side_effect=dbus.DBusException('org.freedesktop.systemd1.NoUnitForPID: PID 1234 does not belong to any loaded unit.') ), \ ++ patch( "dbus.SystemBus", return_value=Mock(spec=dbus.Bus) ), \ ++ patch( "dbus.bus.BusConnection.__new__", side_effect=dbus.DBusException("Never should hit this exception if mock above works")): ++ self.assertIsNone(func(1234)) + + class OpenedFileTest(tests.support.TestCase): + def test_presumed_name(self): +-- +2.40.1 + diff --git a/SOURCES/0034-Fix-zlib-reboot-requirement-RhBug-2092033.patch b/SOURCES/0034-Fix-zlib-reboot-requirement-RhBug-2092033.patch new file mode 100644 index 0000000..5012638 --- /dev/null +++ b/SOURCES/0034-Fix-zlib-reboot-requirement-RhBug-2092033.patch @@ -0,0 +1,51 @@ +From b5e6219b12773b76f634641752fa6f194608e1ff Mon Sep 17 00:00:00 2001 +From: Nicola Sella +Date: Wed, 21 Jun 2023 15:21:57 +0200 +Subject: [PATCH] Fix zlib reboot requirement (RhBug:2092033) + +--- + plugins/needs_restarting.py | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py +index 8dbc965..3197fe1 100644 +--- a/plugins/needs_restarting.py ++++ b/plugins/needs_restarting.py +@@ -42,6 +42,8 @@ import time + NEED_REBOOT = ['kernel', 'kernel-rt', 'glibc', 'linux-firmware', + 'systemd', 'dbus', 'dbus-broker', 'dbus-daemon'] + ++NEED_REBOOT_DEPENDS_ON_DBUS = ['zlib'] ++ + def get_options_from_dir(filepath, base): + """ + Provide filepath as string if single dir or list of strings +@@ -277,15 +279,24 @@ class NeedsRestartingCommand(dnf.cli.Command): + NEED_REBOOT.extend(opt) + if self.opts.reboothint: + need_reboot = set() ++ need_reboot_depends_on_dbus = set() + installed = self.base.sack.query().installed() + for pkg in installed.filter(name=NEED_REBOOT): + if pkg.installtime > process_start.boot_time: + need_reboot.add(pkg.name) +- if need_reboot: ++ ++ dbus_installed = installed.filter(name=['dbus', 'dbus-daemon', 'dbus-broker']) ++ if len(dbus_installed) != 0: ++ for pkg in installed.filter(name=NEED_REBOOT_DEPENDS_ON_DBUS): ++ if pkg.installtime > process_start.boot_time: ++ need_reboot_depends_on_dbus.add(pkg.name) ++ if need_reboot or need_reboot_depends_on_dbus: + print(_('Core libraries or services have been updated ' + 'since boot-up:')) + for name in sorted(need_reboot): + print(' * %s' % name) ++ for name in sorted(need_reboot_depends_on_dbus): ++ print(' * %s (dependency of dbus. Recommending reboot of dbus)' % name) + print() + print(_('Reboot is required to fully utilize these updates.')) + print(_('More information:'), +-- +2.40.1 + diff --git a/SOURCES/0035-Fix-for-issue-with-binary-garbage-in-smaps-files.patch b/SOURCES/0035-Fix-for-issue-with-binary-garbage-in-smaps-files.patch new file mode 100644 index 0000000..e39b3be --- /dev/null +++ b/SOURCES/0035-Fix-for-issue-with-binary-garbage-in-smaps-files.patch @@ -0,0 +1,75 @@ +From 1a29f3ab2f4719f40510dc08f12f4795ad358e93 Mon Sep 17 00:00:00 2001 +From: Andy Baugh +Date: Tue, 6 Jun 2023 16:37:42 +0000 +Subject: [PATCH] Fix for strange issue with binary garbage in smaps files + += changelog = +msg: Avoid issue with garbage smaps chars in needs-restarting.py +type: bugfix +resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2212953 +related: None +--- + plugins/needs_restarting.py | 2 +- + tests/test_needs_restarting.py | 14 +++++++++++++- + 2 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py +index 3197fe1..64d4d0f 100644 +--- a/plugins/needs_restarting.py ++++ b/plugins/needs_restarting.py +@@ -76,7 +76,7 @@ def list_opened_files(uid): + try: + if uid is not None and uid != owner_uid(smaps): + continue +- with open(smaps, 'r') as smaps_file: ++ with open(smaps, 'r', errors='replace') as smaps_file: + lines = smaps_file.readlines() + except EnvironmentError: + logger.warning("Failed to read PID %d's smaps.", pid) +diff --git a/tests/test_needs_restarting.py b/tests/test_needs_restarting.py +index 7b629b4..d7dd6d5 100644 +--- a/tests/test_needs_restarting.py ++++ b/tests/test_needs_restarting.py +@@ -1,3 +1,4 @@ ++# coding: utf-8 + # Copyright (C) 2014 Red Hat, Inc. + # + # This copyrighted material is made available to anyone wishing to use, +@@ -15,15 +16,15 @@ + # Red Hat, Inc. + # + +- + from __future__ import absolute_import + from __future__ import print_function + from __future__ import unicode_literals + + from unittest.mock import patch, Mock + import dbus + import needs_restarting + import tests.support ++import tempfile + + DEL_FILE = '3dcf000000-3dcf032000 r-xp 00000000 08:02 140759 ' \ + ' /usr/lib64/libXfont.so.1.4.1;5408628d (deleted)' +@@ -58,6 +59,17 @@ class NeedsRestartingTest(tests.support.TestCase): + patch( "dbus.bus.BusConnection.__new__", side_effect=dbus.DBusException("Never should hit this exception if mock above works")): + self.assertIsNone(func(1234)) + ++ def test_list_opened_files_garbage_filename(self): ++ tempObj = tempfile.NamedTemporaryFile() ++ tempFile = tempObj.name ++ with open(tempFile, 'wb') as bogusFile: ++ bogusFile.write(b'151e7f7b7000-151e7f7b8000 r--p 00006000 fd:01 14744 /usr/lib64/lib\xe5Evil-13.37.so') ++ smaps = [[1234,tempObj.name]] ++ with patch("needs_restarting.list_smaps", return_value=smaps): ++ ofiles = list(needs_restarting.list_opened_files(None)); ++ self.assertEqual(ofiles[0].presumed_name, '/usr/lib64/lib�Evil-13.37.so') ++ ++ + class OpenedFileTest(tests.support.TestCase): + def test_presumed_name(self): + ofile = needs_restarting.OpenedFile( +-- +libgit2 1.6.4 + diff --git a/SOURCES/0036-needs-restarting-Add-microcode_ctl-to-a-reboot-list.patch b/SOURCES/0036-needs-restarting-Add-microcode_ctl-to-a-reboot-list.patch new file mode 100644 index 0000000..dc43c48 --- /dev/null +++ b/SOURCES/0036-needs-restarting-Add-microcode_ctl-to-a-reboot-list.patch @@ -0,0 +1,40 @@ +From e1af3642a7811229567284f6901d393a6ce28b62 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= +Date: Thu, 23 Nov 2023 16:26:06 +0100 +Subject: [PATCH] needs-restarting: Add microcode_ctl to a reboot list +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 9f46488c6b1ac553989a3fd8a9ea18271451c5e8 upstream. + +To fully update CPU microcode, a reboot is needed because the +microcode update should be applied before starting a kernel and other +process. + +Therefore recommend a reboot after installing or updating +microcode_ctl package. + +https://issues.redhat.com/browse/RHEL-17356 +Signed-off-by: Petr Písař +--- + plugins/needs_restarting.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py +index 64d4d0f..92cde0a 100644 +--- a/plugins/needs_restarting.py ++++ b/plugins/needs_restarting.py +@@ -40,7 +40,8 @@ import time + # For which package updates we should recommend a reboot + # Mostly taken from https://access.redhat.com/solutions/27943 + NEED_REBOOT = ['kernel', 'kernel-rt', 'glibc', 'linux-firmware', +- 'systemd', 'dbus', 'dbus-broker', 'dbus-daemon'] ++ 'systemd', 'dbus', 'dbus-broker', 'dbus-daemon', ++ 'microcode_ctl'] + + NEED_REBOOT_DEPENDS_ON_DBUS = ['zlib'] + +-- +2.43.0 + diff --git a/SPECS/dnf-plugins-core.spec b/SPECS/dnf-plugins-core.spec new file mode 100644 index 0000000..180adab --- /dev/null +++ b/SPECS/dnf-plugins-core.spec @@ -0,0 +1,1723 @@ +%{?!dnf_lowest_compatible: %global dnf_lowest_compatible 4.7.0-6} +%global dnf_plugins_extra 2.0.0 +%global hawkey_version 0.63.0-6 +%global yum_utils_subpackage_name dnf-utils +%if 0%{?rhel} > 7 +%global yum_utils_subpackage_name yum-utils +%endif + +%define __cmake_in_source_build 1 + +%if 0%{?rhel} && 0%{?rhel} <= 7 +%bcond_with python3 +%else +%bcond_without python3 +%endif + +%if 0%{?rhel} > 7 || 0%{?fedora} > 29 +%bcond_with python2 +%else +%bcond_without python2 +%endif + +%if 0%{?rhel} > 7 || 0%{?fedora} > 30 +%bcond_without yumcompatibility +%else +%bcond_with yumcompatibility +%endif + +%if 0%{?rhel} && 0%{?rhel} <= 7 +%bcond_with yumutils +%else +%bcond_without yumutils +%endif + +Name: dnf-plugins-core +Version: 4.0.21 +Release: 25%{?dist} +Summary: Core Plugins for DNF +License: GPLv2+ +URL: https://github.com/rpm-software-management/dnf-plugins-core +Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz +Patch1: 0001-versionlock-Do-not-exclude-locked-obsoleters-RhBug1957280.patch +Patch2: 0002-repomanage-Allow-running-only-with-metadata.patch +Patch3: 0003-repomanage-Enhance-repomanage-documentation-RhBug1898293.patch +Patch4: 0004-copr-dont-traceback-on-empty-lines-in-etcos-release.patch +Patch5: 0005-reposync-Use-fail_fastFalse-when-downloading-packages-RhBug2009894.patch +Patch6: 0006-copr-migrate-all-calls-to-APIv3.patch +Patch7: 0007-groups-manager-More-benevolent-resolving-of-packages-RhBug2013633.patch +Patch8: 0008-versionlock-fix-multi-pkg-lock-RhBug2013324.patch +Patch9: 0009-Update-documentation-for-adding-specific-version-RhBug2013332.patch +Patch10: 0010-needs-restarting-Fix-wrong-boot-time-RhBug1960437.patch +Patch11: 0011-Add-new-command-modulesync-RhBug1868047.patch +Patch12: 0012-Update-translations-RhBug-2017271.patch +Patch13: 0013-repomanage-Use-modules-only-from-repo-they-are-handl.patch +Patch14: 0014-feat-repomanage-Add-new-option-oldonly.patch +Patch15: 0015-Skip-all-non-rpm-tsi-for-transaction_action-plugins-.patch +Patch16: 0016-Fix-dnf-copr-enable-on-Fedora-35.patch +Patch17: 0017-Disable-dnf-playground-command.patch +Patch18: 0018-Fix-baseurl-for-centos-stream-chroot.patch +Patch19: 0019-Silence-a-deprecation-warning-in-plugins-copr.py.patch +Patch20: 0020-Shorter-verification-that-the-project-exists.patch +Patch21: 0021-Better-error-message-for-dnf-copr-enable.patch +Patch22: 0022-copr-allow-specifying-protocol-as-part-of-hub.patch +Patch23: 0023-copr-Guess-EPEL-chroots-for-CentOS-Stream-RhBug-2058.patch +Patch24: 0024-builddep-Warning-when-using-macros-with-source-rpms-.patch +Patch25: 0025-Move-system-upgrade-plugin-to-core-RhBug-2054235.patch +Patch26: 0026-Add-a-warning-when-using-system-upgrade-on-RHEL.patch +Patch27: 0027-offline-upgrade-Add-security-filters.patch +Patch28: 0028-system-upgrade-Show-warning-always-for-a-downstream.patch +Patch29: 0029-Update-translations.patch +Patch30: 0030-versionlock-Use-only-most-specif-NEVRA-RhBug-1961217.patch +Patch31: 0031-Fix-boot-time-derivation-for-systems-with-no-rtc.patch +Patch32: 0032-Doc-update-for-reposync-RhBug-2132383-2182004.patch +Patch33: 0033-Add-fix-and-test-assertion-for-no-systemd-unit-exist.patch +Patch34: 0034-Fix-zlib-reboot-requirement-RhBug-2092033.patch +Patch35: 0035-Fix-for-issue-with-binary-garbage-in-smaps-files.patch +Patch36: 0036-needs-restarting-Add-microcode_ctl-to-a-reboot-list.patch + + +BuildArch: noarch +BuildRequires: cmake +BuildRequires: gettext +# Documentation +%if %{with python3} +BuildRequires: %{_bindir}/sphinx-build-3 +Requires: python3-%{name} = %{version}-%{release} +%else +BuildRequires: %{_bindir}/sphinx-build +Requires: python2-%{name} = %{version}-%{release} +%endif +Provides: dnf-command(builddep) +Provides: dnf-command(changelog) +Provides: dnf-command(config-manager) +Provides: dnf-command(copr) +Provides: dnf-command(debug-dump) +Provides: dnf-command(debug-restore) +Provides: dnf-command(debuginfo-install) +Provides: dnf-command(download) +Provides: dnf-command(groups-manager) +Provides: dnf-command(repoclosure) +Provides: dnf-command(repograph) +Provides: dnf-command(repomanage) +Provides: dnf-command(reposync) +Provides: dnf-command(repodiff) +Provides: dnf-command(system-upgrade) +Provides: dnf-command(offline-upgrade) +Provides: dnf-command(offline-distrosync) +Provides: dnf-plugins-extras-debug = %{version}-%{release} +Provides: dnf-plugins-extras-repoclosure = %{version}-%{release} +Provides: dnf-plugins-extras-repograph = %{version}-%{release} +Provides: dnf-plugins-extras-repomanage = %{version}-%{release} +Provides: dnf-plugin-builddep = %{version}-%{release} +Provides: dnf-plugin-config-manager = %{version}-%{release} +Provides: dnf-plugin-debuginfo-install = %{version}-%{release} +Provides: dnf-plugin-download = %{version}-%{release} +Provides: dnf-plugin-generate_completion_cache = %{version}-%{release} +Provides: dnf-plugin-needs_restarting = %{version}-%{release} +Provides: dnf-plugin-groups-manager = %{version}-%{release} +Provides: dnf-plugin-repoclosure = %{version}-%{release} +Provides: dnf-plugin-repodiff = %{version}-%{release} +Provides: dnf-plugin-repograph = %{version}-%{release} +Provides: dnf-plugin-repomanage = %{version}-%{release} +Provides: dnf-plugin-reposync = %{version}-%{release} +Provides: dnf-plugin-system-upgrade = %{version}-%{release} +%if %{with yumcompatibility} +Provides: yum-plugin-copr = %{version}-%{release} +Provides: yum-plugin-changelog = %{version}-%{release} +Provides: yum-plugin-auto-update-debug-info = %{version}-%{release} +%endif +Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} + +%description +Core Plugins for DNF. This package enhances DNF with builddep, config-manager, +copr, debug, debuginfo-install, download, needs-restarting, groups-manager, repoclosure, +repograph, repomanage, reposync, changelog and repodiff commands. Additionally +provides generate_completion_cache passive plugin. + +%if %{with python2} +%package -n python2-%{name} +Summary: Core Plugins for DNF +%{?python_provide:%python_provide python2-%{name}} +BuildRequires: python2-dnf >= %{dnf_lowest_compatible} +%if 0%{?rhel} && 0%{?rhel} <= 7 +BuildRequires: dbus-python +%else +BuildRequires: python2-dbus +%endif +BuildRequires: python2-devel +%if 0%{?fedora} +Requires: python2-distro +%endif +Requires: python2-dnf >= %{dnf_lowest_compatible} +Requires: python2-hawkey >= %{hawkey_version} +%if 0%{?rhel} && 0%{?rhel} <= 7 +Requires: dbus-python +Requires: python-dateutil +%else +Requires: python2-dbus +Requires: python2-dateutil +%endif +Provides: python2-dnf-plugins-extras-debug = %{version}-%{release} +Provides: python2-dnf-plugins-extras-repoclosure = %{version}-%{release} +Provides: python2-dnf-plugins-extras-repograph = %{version}-%{release} +Provides: python2-dnf-plugins-extras-repomanage = %{version}-%{release} +Obsoletes: python2-dnf-plugins-extras-debug < %{dnf_plugins_extra} +Obsoletes: python2-dnf-plugins-extras-repoclosure < %{dnf_plugins_extra} +Obsoletes: python2-dnf-plugins-extras-repograph < %{dnf_plugins_extra} +Obsoletes: python2-dnf-plugins-extras-repomanage < %{dnf_plugins_extra} + +Conflicts: %{name} <= 0.1.5 +# let the both python plugin versions be updated simultaneously +Conflicts: python3-%{name} < %{version}-%{release} +Conflicts: python-%{name} < %{version}-%{release} + +%description -n python2-%{name} +Core Plugins for DNF, Python 2 interface. This package enhances DNF with builddep, +config-manager, copr, degug, debuginfo-install, download, needs-restarting, +groups-manager, repoclosure, repograph, repomanage, reposync, changelog, +repodiff, system-upgrade, offline-upgrade and offline-distrosync commands. +Additionally provides generate_completion_cache passive plugin. +%endif + +%if %{with python3} +%package -n python3-%{name} +Summary: Core Plugins for DNF +%{?python_provide:%python_provide python3-%{name}} +BuildRequires: python3-dbus +BuildRequires: python3-devel +BuildRequires: python3-dnf >= %{dnf_lowest_compatible} +BuildRequires: python3-systemd +BuildRequires: pkgconfig(systemd) +BuildRequires: systemd +%{?systemd_ordering} +%if 0%{?fedora} +Requires: python3-distro +%endif +Requires: python3-dbus +Requires: python3-dnf >= %{dnf_lowest_compatible} +Requires: python3-hawkey >= %{hawkey_version} +Requires: python3-dateutil +Requires: python3-systemd +Provides: python3-dnf-plugins-extras-debug = %{version}-%{release} +Provides: python3-dnf-plugins-extras-repoclosure = %{version}-%{release} +Provides: python3-dnf-plugins-extras-repograph = %{version}-%{release} +Provides: python3-dnf-plugins-extras-repomanage = %{version}-%{release} +Provides: python3-dnf-plugin-system-upgrade = %{version}-%{release} +Obsoletes: python3-dnf-plugins-extras-debug < %{dnf_plugins_extra} +Obsoletes: python3-dnf-plugins-extras-repoclosure < %{dnf_plugins_extra} +Obsoletes: python3-dnf-plugins-extras-repograph < %{dnf_plugins_extra} +Obsoletes: python3-dnf-plugins-extras-repomanage < %{dnf_plugins_extra} +Obsoletes: python3-dnf-plugin-system-upgrade < %{version}-%{release} + +Conflicts: %{name} <= 0.1.5 +# let the both python plugin versions be updated simultaneously +Conflicts: python2-%{name} < %{version}-%{release} +Conflicts: python-%{name} < %{version}-%{release} + +%description -n python3-%{name} +Core Plugins for DNF, Python 3 interface. This package enhances DNF with builddep, +config-manager, copr, debug, debuginfo-install, download, needs-restarting, +groups-manager, repoclosure, repograph, repomanage, reposync, changelog, +repodiff, system-upgrade, offline-upgrade and offline-distrosync commands. +Additionally provides generate_completion_cache passive plugin. +%endif + +%if %{with yumutils} +%package -n %{yum_utils_subpackage_name} +%if "%{yum_utils_subpackage_name}" == "dnf-utils" +Conflicts: yum-utils < 1.1.31-520 +%if 0%{?rhel} != 7 +Provides: yum-utils = %{version}-%{release} +%endif +%else +Provides: dnf-utils = %{version}-%{release} +Obsoletes: dnf-utils < %{version}-%{release} +%endif +Requires: dnf >= %{dnf_lowest_compatible} +Requires: %{name} = %{version}-%{release} +%if %{with python3} +Requires: python3-dnf >= %{dnf_lowest_compatible} +%else +Requires: python2-dnf >= %{dnf_lowest_compatible} +%endif +Summary: Yum-utils CLI compatibility layer + +%description -n %{yum_utils_subpackage_name} +As a Yum-utils CLI compatibility layer, supplies in CLI shims for +debuginfo-install, repograph, package-cleanup, repoclosure, repomanage, +repoquery, reposync, repotrack, repodiff, builddep, config-manager, debug, +download and yum-groups-manager that use new implementations using DNF. +%endif + +%if 0%{?rhel} == 0 && %{with python2} +%package -n python2-dnf-plugin-leaves +Summary: Leaves Plugin for DNF +Requires: python2-%{name} = %{version}-%{release} +Provides: python2-dnf-plugins-extras-leaves = %{version}-%{release} +%if !%{with python3} +Provides: dnf-command(leaves) +Provides: dnf-plugin-leaves = %{version}-%{release} +Provides: dnf-plugins-extras-leaves = %{version}-%{release} +%endif +Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} +Conflicts: python3-dnf-plugin-leaves < %{version}-%{release} +Obsoletes: python2-dnf-plugins-extras-leaves < %{dnf_plugins_extra} + +%description -n python2-dnf-plugin-leaves +Leaves Plugin for DNF, Python 2 version. List all installed packages +not required by any other installed package. +%endif + +%if 0%{?rhel} == 0 && %{with python3} +%package -n python3-dnf-plugin-leaves +Summary: Leaves Plugin for DNF +Requires: python3-%{name} = %{version}-%{release} +Provides: python3-dnf-plugins-extras-leaves = %{version}-%{release} +Provides: dnf-command(leaves) +Provides: dnf-plugin-leaves = %{version}-%{release} +Provides: dnf-plugins-extras-leaves = %{version}-%{release} +Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} +Conflicts: python2-dnf-plugin-leaves < %{version}-%{release} +Obsoletes: python3-dnf-plugins-extras-leaves < %{dnf_plugins_extra} + +%description -n python3-dnf-plugin-leaves +Leaves Plugin for DNF, Python 3 version. List all installed packages +not required by any other installed package. +%endif + +%if 0%{?rhel} == 0 && %{with python2} +%package -n python2-dnf-plugin-local +Summary: Local Plugin for DNF +Requires: %{_bindir}/createrepo_c +Requires: python2-%{name} = %{version}-%{release} +%if !%{with python3} +Provides: dnf-plugin-local = %{version}-%{release} +Provides: dnf-plugins-extras-local = %{version}-%{release} +%endif +Provides: python2-dnf-plugins-extras-local = %{version}-%{release} +Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} +Conflicts: python3-dnf-plugin-local < %{version}-%{release} +Obsoletes: python2-dnf-plugins-extras-local < %{dnf_plugins_extra} + +%description -n python2-dnf-plugin-local +Local Plugin for DNF, Python 2 version. Automatically copy all downloaded packages to a +repository on the local filesystem and generating repo metadata. +%endif + +%if %{with python3} && 0%{?rhel} == 0 +%package -n python3-dnf-plugin-local +Summary: Local Plugin for DNF +Requires: %{_bindir}/createrepo_c +Requires: python3-%{name} = %{version}-%{release} +Provides: dnf-plugin-local = %{version}-%{release} +Provides: python3-dnf-plugins-extras-local = %{version}-%{release} +Provides: dnf-plugins-extras-local = %{version}-%{release} +Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} +Conflicts: python2-dnf-plugin-local < %{version}-%{release} +Obsoletes: python3-dnf-plugins-extras-local < %{dnf_plugins_extra} + +%description -n python3-dnf-plugin-local +Local Plugin for DNF, Python 3 version. Automatically copy all downloaded +packages to a repository on the local filesystem and generating repo metadata. +%endif + +%if %{with python2} +%package -n python2-dnf-plugin-migrate +Summary: Migrate Plugin for DNF +Requires: python2-%{name} = %{version}-%{release} +Requires: yum +Provides: dnf-plugin-migrate = %{version}-%{release} +Provides: python2-dnf-plugins-extras-migrate = %{version}-%{release} +Provides: dnf-command(migrate) +Provides: dnf-plugins-extras-migrate = %{version}-%{release} +Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} +Obsoletes: python2-dnf-plugins-extras-migrate < %{dnf_plugins_extra} +Obsoletes: python-dnf-plugins-extras-migrate < %{dnf_plugins_extra} + +%description -n python2-dnf-plugin-migrate +Migrate Plugin for DNF, Python 2 version. Migrates history, group and yumdb data from yum to dnf. +%endif + +%if %{with python2} +%package -n python2-dnf-plugin-post-transaction-actions +Summary: Post transaction actions Plugin for DNF +Requires: python2-%{name} = %{version}-%{release} +%if !%{with python3} +Provides: dnf-plugin-post-transaction-actions = %{version}-%{release} +%endif +Conflicts: python3-dnf-plugin-post-transaction-actions < %{version}-%{release} + +%description -n python2-dnf-plugin-post-transaction-actions +Post transaction actions Plugin for DNF, Python 2 version. Plugin runs actions +(shell commands) after transaction is completed. Actions are defined in action +files. +%endif + +%if %{with python3} +%package -n python3-dnf-plugin-post-transaction-actions +Summary: Post transaction actions Plugin for DNF +Requires: python3-%{name} = %{version}-%{release} +Provides: dnf-plugin-post-transaction-actions = %{version}-%{release} +Conflicts: python2-dnf-plugin-post-transaction-actions < %{version}-%{release} + +%description -n python3-dnf-plugin-post-transaction-actions +Post transaction actions Plugin for DNF, Python 3 version. Plugin runs actions +(shell commands) after transaction is completed. Actions are defined in action +files. +%endif + +%if 0%{?rhel} == 0 && %{with python2} +%package -n python2-dnf-plugin-show-leaves +Summary: Leaves Plugin for DNF +Requires: python2-%{name} = %{version}-%{release} +Requires: python2-dnf-plugin-leaves = %{version}-%{release} +%if !%{with python3} +Provides: dnf-plugin-show-leaves = %{version}-%{release} +Provides: dnf-command(show-leaves) +Provides: dnf-plugins-extras-show-leaves = %{version}-%{release} +%endif +Provides: python2-dnf-plugins-extras-show-leaves = %{version}-%{release} +Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} +Conflicts: python3-dnf-plugin-show-leaves < %{version}-%{release} +Obsoletes: python2-dnf-plugins-extras-show-leaves < %{dnf_plugins_extra} + +%description -n python2-dnf-plugin-show-leaves +Show-leaves Plugin for DNF, Python 2 version. List all installed +packages that are no longer required by any other installed package +after a transaction. +%endif + +%if 0%{?rhel} == 0 && %{with python3} +%package -n python3-dnf-plugin-show-leaves +Summary: Show-leaves Plugin for DNF +Requires: python3-%{name} = %{version}-%{release} +Requires: python3-dnf-plugin-leaves = %{version}-%{release} +Provides: dnf-plugin-show-leaves = %{version}-%{release} +Provides: python3-dnf-plugins-extras-show-leaves = %{version}-%{release} +Provides: dnf-command(show-leaves) +Provides: dnf-plugins-extras-show-leaves = %{version}-%{release} +Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} +Conflicts: python2-dnf-plugin-show-leaves < %{version}-%{release} +Obsoletes: python3-dnf-plugins-extras-show-leaves < %{dnf_plugins_extra} + +%description -n python3-dnf-plugin-show-leaves +Show-leaves Plugin for DNF, Python 3 version. List all installed +packages that are no longer required by any other installed package +after a transaction. +%endif + +%if %{with python2} +%package -n python2-dnf-plugin-versionlock +Summary: Version Lock Plugin for DNF +Requires: python2-%{name} = %{version}-%{release} +%if !%{with python3} +Provides: dnf-plugin-versionlock = %{version}-%{release} +Provides: dnf-command(versionlock) +Provides: dnf-plugins-extras-versionlock = %{version}-%{release} +%if %{with yumcompatibility} +Provides: yum-plugin-versionlock = %{version}-%{release} +%endif +%endif +Provides: python2-dnf-plugins-extras-versionlock = %{version}-%{release} +Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} +Conflicts: python3-dnf-plugin-versionlock < %{version}-%{release} +Obsoletes: python2-dnf-plugins-extras-versionlock < %{dnf_plugins_extra} + +%description -n python2-dnf-plugin-versionlock +Version lock plugin takes a set of name/versions for packages and excludes all other +versions of those packages. This allows you to e.g. protect packages from being +updated by newer versions. +%endif + +%if %{with python3} +%package -n python3-dnf-plugin-versionlock +Summary: Version Lock Plugin for DNF +Requires: python3-%{name} = %{version}-%{release} +Provides: dnf-plugin-versionlock = %{version}-%{release} +Provides: python3-dnf-plugins-extras-versionlock = %{version}-%{release} +Provides: dnf-command(versionlock) +%if %{with yumcompatibility} +Provides: yum-plugin-versionlock = %{version}-%{release} +%endif +Provides: dnf-plugins-extras-versionlock = %{version}-%{release} +Conflicts: dnf-plugins-extras-common-data < %{dnf_plugins_extra} +Conflicts: python2-dnf-plugin-versionlock < %{version}-%{release} +Obsoletes: python3-dnf-plugins-extras-versionlock < %{dnf_plugins_extra} + +%description -n python3-dnf-plugin-versionlock +Version lock plugin takes a set of name/versions for packages and excludes all other +versions of those packages. This allows you to e.g. protect packages from being +updated by newer versions. +%endif + +%if %{with python3} +%package -n python3-dnf-plugin-modulesync +Summary: Download module metadata and packages and create repository +Requires: python3-%{name} = %{version}-%{release} +Requires: createrepo_c >= 0.17.4 +Provides: dnf-plugin-modulesync = %{version}-%{release} +Provides: dnf-command(modulesync) + +%description -n python3-dnf-plugin-modulesync +Download module metadata from all enabled repositories, module artifacts and profiles of matching modules and create +repository. +%endif + +%prep +%autosetup -p1 +%if %{with python2} +mkdir build-py2 +%endif +%if %{with python3} +mkdir build-py3 +%endif + +%build +%if %{with python2} +pushd build-py2 + %cmake ../ -DPYTHON_DESIRED:FILEPATH=%{__python2} -DWITHOUT_LOCAL:str=0%{?rhel} + %make_build + make doc-man +popd +%endif +%if %{with python3} +pushd build-py3 + %cmake ../ -DPYTHON_DESIRED:FILEPATH=%{__python3} -DWITHOUT_LOCAL:str=0%{?rhel} + %make_build + make doc-man +popd +%endif + +%install +%if %{with python2} +pushd build-py2 + %make_install +popd +%endif +%if %{with python3} +pushd build-py3 + %make_install +popd +%endif + +%if %{with python3} +mkdir -p %{buildroot}%{_unitdir}/system-update.target.wants/ +pushd %{buildroot}%{_unitdir}/system-update.target.wants/ + ln -sr ../dnf-system-upgrade.service +popd + +ln -sf %{_mandir}/man8/dnf-system-upgrade.8.gz %{buildroot}%{_mandir}/man8/dnf-offline-upgrade.8.gz +ln -sf %{_mandir}/man8/dnf-system-upgrade.8.gz %{buildroot}%{_mandir}/man8/dnf-offline-distrosync.8.gz +%endif + +%find_lang %{name} +%if %{with yumutils} + %if %{with python3} + mv %{buildroot}%{_libexecdir}/dnf-utils-3 %{buildroot}%{_libexecdir}/dnf-utils + %else + mv %{buildroot}%{_libexecdir}/dnf-utils-2 %{buildroot}%{_libexecdir}/dnf-utils + %endif +%endif +rm -vf %{buildroot}%{_libexecdir}/dnf-utils-* + +%if %{with yumutils} +mkdir -p %{buildroot}%{_bindir} +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/debuginfo-install +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/needs-restarting +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/find-repos-of-install +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/repo-graph +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/package-cleanup +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/repoclosure +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/repodiff +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/repomanage +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/repoquery +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/reposync +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/repotrack +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yum-builddep +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yum-config-manager +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yum-debug-dump +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yum-debug-restore +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yum-groups-manager +ln -sf %{_libexecdir}/dnf-utils %{buildroot}%{_bindir}/yumdownloader +# These commands don't have a dedicated man page, so let's just point them +# to the utils page which contains their descriptions. +ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/man1/find-repos-of-install.1.gz +ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/man1/repoquery.1.gz +ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/man1/repotrack.1.gz +%endif + +%check +%if %{with python2} + pushd build-py2 + ctest -VV + popd +%endif +%if %{with python3} + pushd build-py3 + ctest -VV + popd +%endif + +%files +%{_mandir}/man8/dnf-builddep.* +%{_mandir}/man8/dnf-changelog.* +%{_mandir}/man8/dnf-config-manager.* +%{_mandir}/man8/dnf-copr.* +%{_mandir}/man8/dnf-debug.* +%{_mandir}/man8/dnf-debuginfo-install.* +%{_mandir}/man8/dnf-download.* +%{_mandir}/man8/dnf-generate_completion_cache.* +%{_mandir}/man8/dnf-groups-manager.* +%{_mandir}/man8/dnf-needs-restarting.* +%{_mandir}/man8/dnf-repoclosure.* +%{_mandir}/man8/dnf-repodiff.* +%{_mandir}/man8/dnf-repograph.* +%{_mandir}/man8/dnf-repomanage.* +%{_mandir}/man8/dnf-reposync.* +%{_mandir}/man8/dnf-system-upgrade.* +%{_mandir}/man8/dnf-offline-upgrade.* +%{_mandir}/man8/dnf-offline-distrosync.* +%if %{with yumcompatibility} +%{_mandir}/man1/yum-changelog.* +%{_mandir}/man8/yum-copr.* +%else +%exclude %{_mandir}/man1/yum-changelog.* +%exclude %{_mandir}/man8/yum-copr.* +%endif + +%if %{with python2} +%files -n python2-%{name} -f %{name}.lang +%license COPYING +%doc AUTHORS README.rst +%ghost %attr(644,-,-) %{_var}/cache/dnf/packages.db +%config(noreplace) %{_sysconfdir}/dnf/plugins/copr.conf +%config(noreplace) %{_sysconfdir}/dnf/plugins/copr.d +%config(noreplace) %{_sysconfdir}/dnf/plugins/debuginfo-install.conf +%{python2_sitelib}/dnf-plugins/builddep.* +%{python2_sitelib}/dnf-plugins/changelog.* +%{python2_sitelib}/dnf-plugins/config_manager.* +%{python2_sitelib}/dnf-plugins/copr.* +%{python2_sitelib}/dnf-plugins/debug.* +%{python2_sitelib}/dnf-plugins/debuginfo-install.* +%{python2_sitelib}/dnf-plugins/download.* +%{python2_sitelib}/dnf-plugins/generate_completion_cache.* +%{python2_sitelib}/dnf-plugins/groups_manager.* +%{python2_sitelib}/dnf-plugins/needs_restarting.* +%{python2_sitelib}/dnf-plugins/repoclosure.* +%{python2_sitelib}/dnf-plugins/repodiff.* +%{python2_sitelib}/dnf-plugins/repograph.* +%{python2_sitelib}/dnf-plugins/repomanage.* +%{python2_sitelib}/dnf-plugins/reposync.* +%{python2_sitelib}/dnfpluginscore/ +%endif + +%if %{with python3} +%files -n python3-%{name} -f %{name}.lang +%license COPYING +%doc AUTHORS README.rst +%ghost %attr(644,-,-) %{_var}/cache/dnf/packages.db +%config(noreplace) %{_sysconfdir}/dnf/plugins/copr.conf +%config(noreplace) %{_sysconfdir}/dnf/plugins/copr.d +%config(noreplace) %{_sysconfdir}/dnf/plugins/debuginfo-install.conf +%{python3_sitelib}/dnf-plugins/builddep.py +%{python3_sitelib}/dnf-plugins/changelog.py +%{python3_sitelib}/dnf-plugins/config_manager.py +%{python3_sitelib}/dnf-plugins/copr.py +%{python3_sitelib}/dnf-plugins/debug.py +%{python3_sitelib}/dnf-plugins/debuginfo-install.py +%{python3_sitelib}/dnf-plugins/download.py +%{python3_sitelib}/dnf-plugins/generate_completion_cache.py +%{python3_sitelib}/dnf-plugins/groups_manager.py +%{python3_sitelib}/dnf-plugins/needs_restarting.py +%{python3_sitelib}/dnf-plugins/repoclosure.py +%{python3_sitelib}/dnf-plugins/repodiff.py +%{python3_sitelib}/dnf-plugins/repograph.py +%{python3_sitelib}/dnf-plugins/repomanage.py +%{python3_sitelib}/dnf-plugins/reposync.py +%{python3_sitelib}/dnf-plugins/system_upgrade.py +%{python3_sitelib}/dnf-plugins/__pycache__/builddep.* +%{python3_sitelib}/dnf-plugins/__pycache__/changelog.* +%{python3_sitelib}/dnf-plugins/__pycache__/config_manager.* +%{python3_sitelib}/dnf-plugins/__pycache__/copr.* +%{python3_sitelib}/dnf-plugins/__pycache__/debug.* +%{python3_sitelib}/dnf-plugins/__pycache__/debuginfo-install.* +%{python3_sitelib}/dnf-plugins/__pycache__/download.* +%{python3_sitelib}/dnf-plugins/__pycache__/generate_completion_cache.* +%{python3_sitelib}/dnf-plugins/__pycache__/groups_manager.* +%{python3_sitelib}/dnf-plugins/__pycache__/needs_restarting.* +%{python3_sitelib}/dnf-plugins/__pycache__/repoclosure.* +%{python3_sitelib}/dnf-plugins/__pycache__/repodiff.* +%{python3_sitelib}/dnf-plugins/__pycache__/repograph.* +%{python3_sitelib}/dnf-plugins/__pycache__/repomanage.* +%{python3_sitelib}/dnf-plugins/__pycache__/reposync.* +%{python3_sitelib}/dnf-plugins/__pycache__/system_upgrade.* +%{python3_sitelib}/dnfpluginscore/ +%{_unitdir}/dnf-system-upgrade.service +%{_unitdir}/dnf-system-upgrade-cleanup.service +%{_unitdir}/system-update.target.wants/dnf-system-upgrade.service +%endif + +%if %{with yumutils} +%files -n %{yum_utils_subpackage_name} +%{_libexecdir}/dnf-utils +%{_bindir}/debuginfo-install +%{_bindir}/needs-restarting +%{_bindir}/find-repos-of-install +%{_bindir}/package-cleanup +%{_bindir}/repo-graph +%{_bindir}/repoclosure +%{_bindir}/repodiff +%{_bindir}/repomanage +%{_bindir}/repoquery +%{_bindir}/reposync +%{_bindir}/repotrack +%{_bindir}/yum-builddep +%{_bindir}/yum-config-manager +%{_bindir}/yum-debug-dump +%{_bindir}/yum-debug-restore +%{_bindir}/yum-groups-manager +%{_bindir}/yumdownloader +%{_mandir}/man1/debuginfo-install.* +%{_mandir}/man1/needs-restarting.* +%{_mandir}/man1/repo-graph.* +%{_mandir}/man1/repoclosure.* +%{_mandir}/man1/repodiff.* +%{_mandir}/man1/repomanage.* +%{_mandir}/man1/reposync.* +%{_mandir}/man1/yum-builddep.* +%{_mandir}/man1/yum-config-manager.* +%{_mandir}/man1/yum-debug-dump.* +%{_mandir}/man1/yum-debug-restore.* +%{_mandir}/man1/yum-groups-manager.* +%{_mandir}/man1/yumdownloader.* +%{_mandir}/man1/package-cleanup.* +%{_mandir}/man1/dnf-utils.* +%{_mandir}/man1/yum-utils.* +# These are only built with yumutils bcond. +%{_mandir}/man1/find-repos-of-install.* +%{_mandir}/man1/repoquery.* +%{_mandir}/man1/repotrack.* +%else +# These are built regardless of yumutils bcond so we need to exclude them. +%exclude %{_mandir}/man1/debuginfo-install.* +%exclude %{_mandir}/man1/needs-restarting.* +%exclude %{_mandir}/man1/repo-graph.* +%exclude %{_mandir}/man1/repoclosure.* +%exclude %{_mandir}/man1/repodiff.* +%exclude %{_mandir}/man1/repomanage.* +%exclude %{_mandir}/man1/reposync.* +%exclude %{_mandir}/man1/yum-builddep.* +%exclude %{_mandir}/man1/yum-config-manager.* +%exclude %{_mandir}/man1/yum-debug-dump.* +%exclude %{_mandir}/man1/yum-debug-restore.* +%exclude %{_mandir}/man1/yum-groups-manager.* +%exclude %{_mandir}/man1/yumdownloader.* +%exclude %{_mandir}/man1/package-cleanup.* +%exclude %{_mandir}/man1/dnf-utils.* +%exclude %{_mandir}/man1/yum-utils.* +%endif + +%if 0%{?rhel} == 0 + +%if %{with python2} +%files -n python2-dnf-plugin-leaves +%{python2_sitelib}/dnf-plugins/leaves.* +%{_mandir}/man8/dnf-leaves.* +%endif + +%if %{with python3} +%files -n python3-dnf-plugin-leaves +%{python3_sitelib}/dnf-plugins/leaves.* +%{python3_sitelib}/dnf-plugins/__pycache__/leaves.* +%{_mandir}/man8/dnf-leaves.* +%endif + +%else +%exclude %{_mandir}/man8/dnf-leaves.* +%if %{with python2} +%exclude %{python2_sitelib}/dnf-plugins/leaves.* +%endif +%if %{with python3} +%exclude %{python3_sitelib}/dnf-plugins/leaves.* +%exclude %{python3_sitelib}/dnf-plugins/__pycache__/leaves.* +%endif +%endif +# endif 0%%{?rhel} == 0 + +%if 0%{?rhel} == 0 && %{with python2} +%files -n python2-dnf-plugin-local +%config(noreplace) %{_sysconfdir}/dnf/plugins/local.conf +%{python2_sitelib}/dnf-plugins/local.* +%{_mandir}/man8/dnf-local.* +%endif + +%if %{with python3} && 0%{?rhel} == 0 +%files -n python3-dnf-plugin-local +%config(noreplace) %{_sysconfdir}/dnf/plugins/local.conf +%{python3_sitelib}/dnf-plugins/local.* +%{python3_sitelib}/dnf-plugins/__pycache__/local.* +%{_mandir}/man8/dnf-local.* +%endif + +%if %{with python2} +%files -n python2-dnf-plugin-migrate +%{python2_sitelib}/dnf-plugins/migrate.* +%{_mandir}/man8/dnf-migrate.* +%else +%exclude %{_mandir}/man8/dnf-migrate.* +%endif + +%if %{with python2} +%files -n python2-dnf-plugin-post-transaction-actions +%config(noreplace) %{_sysconfdir}/dnf/plugins/post-transaction-actions.conf +%config(noreplace) %{_sysconfdir}/dnf/plugins/post-transaction-actions.d +%{python2_sitelib}/dnf-plugins/post-transaction-actions.* +%{_mandir}/man8/dnf-post-transaction-actions.* +%endif + +%if %{with python3} +%files -n python3-dnf-plugin-post-transaction-actions +%config(noreplace) %{_sysconfdir}/dnf/plugins/post-transaction-actions.conf +%config(noreplace) %{_sysconfdir}/dnf/plugins/post-transaction-actions.d +%{python3_sitelib}/dnf-plugins/post-transaction-actions.* +%{python3_sitelib}/dnf-plugins/__pycache__/post-transaction-actions.* +%{_mandir}/man8/dnf-post-transaction-actions.* +%endif + +%if 0%{?rhel} == 0 + +%if %{with python2} +%files -n python2-dnf-plugin-show-leaves +%{python2_sitelib}/dnf-plugins/show_leaves.* +%{_mandir}/man8/dnf-show-leaves.* +%endif + +%if %{with python3} +%files -n python3-dnf-plugin-show-leaves +%{python3_sitelib}/dnf-plugins/show_leaves.* +%{python3_sitelib}/dnf-plugins/__pycache__/show_leaves.* +%{_mandir}/man8/dnf-show-leaves.* +%endif + +%else +%exclude %{_mandir}/man8/dnf-show-leaves.* +%if %{with python2} +%exclude %{python2_sitelib}/dnf-plugins/show_leaves.* +%endif +%if %{with python3} +%exclude %{python3_sitelib}/dnf-plugins/show_leaves.* +%exclude %{python3_sitelib}/dnf-plugins/__pycache__/show_leaves.* +%endif +%endif +# endif 0%%{?rhel} == 0 + +%if %{with python2} +%files -n python2-dnf-plugin-versionlock +%config(noreplace) %{_sysconfdir}/dnf/plugins/versionlock.conf +%config(noreplace) %{_sysconfdir}/dnf/plugins/versionlock.list +%{python2_sitelib}/dnf-plugins/versionlock.* +%{_mandir}/man8/dnf-versionlock.* +%if %{with yumcompatibility} +%{_mandir}/man8/yum-versionlock.* +%{_mandir}/man5/yum-versionlock.* +%else +%exclude %{_mandir}/man8/yum-versionlock.* +%exclude %{_mandir}/man5/yum-versionlock.* +%endif +%endif + +%if %{with python3} +%files -n python3-dnf-plugin-versionlock +%config(noreplace) %{_sysconfdir}/dnf/plugins/versionlock.conf +%config(noreplace) %{_sysconfdir}/dnf/plugins/versionlock.list +%{python3_sitelib}/dnf-plugins/versionlock.* +%{python3_sitelib}/dnf-plugins/__pycache__/versionlock.* +%{_mandir}/man8/dnf-versionlock.* +%if %{with yumcompatibility} +%{_mandir}/man8/yum-versionlock.* +%{_mandir}/man5/yum-versionlock.* +%else +%exclude %{_mandir}/man8/yum-versionlock.* +%exclude %{_mandir}/man5/yum-versionlock.* +%endif +%endif + +%if %{with python3} +%files -n python3-dnf-plugin-modulesync +%{python3_sitelib}/dnf-plugins/modulesync.* +%{python3_sitelib}/dnf-plugins/__pycache__/modulesync.* +%{_mandir}/man8/dnf-modulesync.* +%endif + +%changelog +* Mon Jan 15 2024 Petr Pisar - 4.0.21-25 +- Add microcode_ctl to a reboot list (RHEL-17356) + +* Mon Oct 16 2023 Jaroslav Rohel - 4.0.21-24 +- Fix for strange issue with binary garbage in smaps files (RHEL-6392, RhBug:2212953) + +* Tue Jun 27 2023 Jaroslav Rohel - 4.0.21-23 +- Add patch: Fix zlib reboot requirement (RhBug:2092033) + +* Wed May 31 2023 Nicola Sella - 4.0.21-22 +- Add fix and test assertion for "no systemd unit exists for pid" + +* Fri May 19 2023 Jaroslav Rohel - 4.0.21-21 +- Remove patch: "reposync: Implement --safe-write-path option (RhBug:1898089,2203766)" (RhBug:2208444) + +* Wed May 17 2023 Jaroslav Rohel - 4.0.21-20 +- versionlock: Use only the most specific NEVRA (RhBug:1961217) +- Fix boot time derivation for systems with no rtc (RhBug:2166444,2182157) +- Doc update for reposync (RhBug:2132383,2182004) +- reposync: Implement --safe-write-path option (RhBug:1898089,2203766) + +* Wed Mar 08 2023 Marek Blaha - 4.0.21-19 +- Update translations + +* Thu Jan 05 2023 Nicola Sella - 4.0.21-18 +- Show downstream warning during system-upgrade + +* Wed Nov 30 2022 Nicola Sella - 4.0.21-17 +- offline-upgrade: add support for security filters (RhBug:1939975,2139324) +- Move system-upgrade plugin to core (RhBug:2054235) + +* Wed Oct 26 2022 Nicola Sella - 4.0.21-16 +- Move system-upgrade plugin to core (RhBug:2054235) + +* Tue Sep 13 2022 Lukas Hrazky - 4.0.21-15 +- builddep: Warning when using macros with source rpms (RhBug:2077820) + +* Tue Jul 19 2022 Lukas Hrazky - 4.0.21-14 +- [copr] Guess EPEL chroots for CentOS Stream + +* Tue Jun 14 2022 Lukas Hrazky - 4.0.21-13 +- [copr] Fix 'dnf copr enable' on Fedora 35 +- [copr] Disable dnf playground command +- [copr] Fix baseurl for centos stream chroot +- [copr] Silence a deprecation warning in plugins/copr.py +- [copr] Shorter verification that the project exists +- [copr] Better error message for dnf copr enable +- [copr] allow specifying protocol as part of --hub + +* Tue Jun 14 2022 Lukas Hrazky - 4.0.21-12 +- [repomanage] Use modules only from repo they are handling +- [repomanage] Add new option --oldonly +- Skip all non rpm tsi for transaction_action plugins +- Update translations + +* Fri Jan 14 2022 Pavla Kratochvilova - 4.0.21-10 +- Rebuild with new release number + +* Tue Jan 11 2022 Pavla Kratochvilova - 4.0.21-9 +- Add new command modulesync (RhBug:1868047) + +* Thu Jan 06 2022 Pavla Kratochvilova - 4.0.21-8 +- [needs-restarting] Fix wrong boot time (RhBug:1960437,2022389) + +* Wed Dec 1 2021 Pavla Kratochvilova - 4.0.21-7 +- [groups-manager] Use full NEVRA for matching packages instead of only name (RhBug:2013633) +- [versionlock] Fix: Multiple package-name-spec arguments don't lock (RhBug:2013324) +- [versionlock] Update documentation for adding specifi version (RhBug:2013332) + +* Tue Nov 23 2021 Pavla Kratochvilova - 4.0.21-6 +- Increase dependency on dnf as it's required by reposync (RhBug:2023739) + +* Fri Nov 12 2021 Pavla Kratochvilova - 4.0.21-5 +- [copr] Migrate all calls to APIv3 (RhBug:2021821) + +* Tue Nov 09 2021 Pavla Kratochvilova - 4.0.21-4 +- [reposync] Don't stop downloading packages on the first error (RhBug:2009894) +- [copr] Fix traceback of copr search (RhBug:2019868) + +* Tue Jul 27 2021 Pavla Kratochvilova - 4.0.21-2 +- [versionlock] Locking obsoleted package does not make the obsoleter unavailable (RhBug:1957280) +- [repomanage] Allow running with metadata only +- [repomanage] Enhance repomanage documentation (RhBug:1898293) + +* Wed May 19 2021 Pavla Kratochvilova - 4.0.21-1 +- Update to 4.0.21 +- [repomanage] Don't use cached metadata (RhBug:1899852) +- [needs-restarting] fix -r in nspawn containers (RhBug:1913962,1914251) +- doc: add packages to needs-restarting conf +- Set blacklist subcommand as deprecated +- Removed dependency on dnf.yum.misc.Checksum class (RhBug:1935465) +- Bugs fixed (RhBug:1914827,1916782) + +* Fri Jan 15 2021 Nicola Sella - 4.0.18-3 +- [reposync] Check GPG signatures of downloaded packages (RhBug:1856818) + +* Tue Dec 8 2020 Marek Blaha - 4.0.18-2 +- Introduce groups-manager plugin (RhBug:1826016) +- [needs-restarting] add -s to list services (RhBug:1772939) + +* Tue Nov 10 2020 Nicola Sella - 4.0.18-1 +- Update to 4.0.18 +- [needs-restarting] Fix plugin fail if needs-restarting.d does not exist +- [needs-restarting] add kernel-rt to reboot list +- Fix debug-restore command +- [config-manager] enable/disable comma separated pkgs (RhBug:1830530) +- [debug] Use standard demands.resolving for transaction handling +- [debug] Do not remove install-only packages (RhBug:1844533) +- return error when dnf download failed +- README: Reference Fedora Weblate instead of Zanata +- [reposync] Add latest NEVRAs per stream to download (RhBug: 1833074) +- copr: don't try to list runtime dependencies + +* Wed Aug 05 2020 Nicola Sella - 4.0.17-5 +- [reposync] Add latest NEVRAs per stream to download (RhBug: 1833074) + +* Tue Jul 28 2020 Marek Blaha - 4.0.17-4 +- Debug-restore command do not remove installonly packages (RhBug:1844533) +- Update translations (RhBug:1820546) + +* Fri Jul 17 2020 Nicola Sella - 4.0.17-3 +- Fix debug-restore command (RhBug:1844533) + +* Thu Jun 11 2020 Nicola Sella - 4.0.17-2 +- [needs-restarting] Fix plugin fail if needs-restarting.d does not exist + +* Wed Jun 10 2020 Nicola Sella - 4.0.17-1 +- [repomanage] Add modular support (RhBug:1804720) +- [needs-restarting] add options using .conf file (RhBug:1810123) + +* Wed Jun 03 2020 Nicola Sella - 4.0.16-1 +- Update to 4.0.16 +- [versionlock] Take obsoletes into account (RhBug:1627124) +- Move args "--set-enabled", "--set-disabled" from DNF (RhBug:1727882) +- Add missing arguments --set-enabled/--set-diabled into error message +- Warn when --enablerepo/--disablerepo args were passed (RhBug:1727882) +- [copr] add support for enabling/disabling runtime dependencies +- [copr] no-liability text to be always printed + +* Mon Apr 06 2020 Ales Matej - 4.0.15-1 +- Update to 4.0.15 +- Fix: config_manager respect config file location during save +- Fix conflict for dnf download --resolve (RhBug:1787908) +- Fix: don't open stdin if versionlock is missing (RhBug:1785563) +- config-manager calls parser error when without options (RhBug:1782822) +- Update reposync.py with --norepopath option +- Support remote files in dnf builddep +- [versionlock] Prevent conflicting/duplicate entries (RhBug:1782052) +- [download] Respect repo priority (RhBug:1800342) +- [doc] Skip creating and installing migrate documentation for Python 3+ + +* Fri Jan 31 2020 Marek Blaha - 4.0.12-3 +- [translations] Update translations from zanata (RhBug:1754960) + +* Mon Jan 13 2020 Ales Matej - 4.0.12-2 +- [config-manager] Allow use of --set-enabled without arguments (RhBug:1679213) +- [reposync] Fix --delete with multiple repos (RhBug:1774103) +- Redesign reposync --latest for modular system (RhBug:1775434) + +* Mon Nov 25 2019 Ales Matej - 4.0.12-1 +- Update to 4.0.12 +- [reposync] Add --urls option (RhBug:1686602) +- [versionlock] Add --raw option (RhBug:1645564) +- [doc] move manpages for plugins to "dnf-PLUGIN" (RhBug:1706386) +- Add new plugin post-transaction-actions (RhBug:967264) +- [builddep] Add --skip-unavailable switch (RhBug:1628634) +- [versionlock] Don't apply excludes on @System (RhBug:1726712) +- [reposync] Ignore only modular excludes (RhBug:1750273) + +* Thu Nov 14 2019 Ales Matej - 4.0.11-1 +- Update to 4.0.11 +- [spec] Specify attributes for ghost file (RhBug:1754463) +- download: add the --debugsource option (RhBug:1637008) +- Fix incorrect handling richdeps in buildep (RhBug:1756902) + +* Tue Oct 22 2019 Ales Matej - 4.0.10-1 +- Update to 4.0.10 +- debuginfo-install: Update both debuginfo and debugsource for updated package (RhBug:1586084) +- copr: Support multilib repofiles (RhBug:1393664) +- copr: Fix disable if copr instance has non-default port +- copr: Fix repoid when using subdirectories in copr project + +* Wed Aug 14 2019 Pavla Kratochvilova - 4.0.8-3 +- Generate yum-utils(1) instead of symlinking (RhBug:1676418) + +* Tue Aug 06 2019 Pavla Kratochvilova - 4.0.8-2 +- Update localizations from zanata (RhBug:1689984) +- Rename dnf-utils to yum-utils (RhBug:1722093) +- [builddep] Report all rpm errors (RhBug:1724668) +- [config-manager] Behaviour of --setopt (RhBug:1702678) + +* Tue Jun 11 2019 Pavla Kratochvilova - 4.0.8-1 +- Update to 4.0.8 +- [reposync] Enable timestamp preserving for downloaded data (RhBug:1688537) +- [reposync] Download packages from all streams (RhBug:1714788) +- Make yum-copr manpage available (RhBug:1673902) +- [needs-restarting] Add --reboothint option (RhBug:1192946) (RhBug:1639468) +- Set the cost of ``_dnf_local`` repo to 500, to make it preferred to normal + repos + +* Mon May 13 2019 Pavla Kratochvilova - 4.0.7-1 +- Update to 4.0.7 +- Use improved config parser that preserves order of data +- Fix: copr disable command traceback (RhBug:1693551) +- [doc] state repoid as repo identifier of config-manager (RhBug:1686779) +- [leaves] Show multiply satisfied dependencies as leaves +- [download] Fix downloading an rpm from a URL (RhBug:1678582) +- [download] Do not download src without ``--source`` (RhBug:1666648) +- [download] Fix problem with downloading src pkgs (RhBug:1649627) +- [download] Fix download of src when not the latest requested (RhBug:1649627) + +* Tue Jan 08 2019 Daniel Mach - 4.0.2.2-3 +- reposync: fix-up path traversal prevention (RhBug: 1600722) + +* Fri Jan 04 2019 Jaroslav Mracek - 4.0.2.2-1 +- Add option for reposync +- Add changelog plugin + +* Mon Dec 17 2018 Daniel Mach - 4.0.2.1-1 +- zanata update +- Attribute repo.metadata._comps_fn does not exist anymore +- [download] Fix traceback when local rpm / url is passed +- Run transaction hook only if transaction +- [versionlock] Accept more NEVRA forms in the deletion code (RhBug:1654529) +- [spec] Obsolete yum-utils < 1.1.31-513 (RhBug: 1579322) + +* Fri Nov 23 2018 Jaroslav Mracek - 4.0.2-1 +- Added repodif command +- copr: fix enabling Rawhide repository +- Add needs-restarting CLI shim +- [reposync] Fix traceback with --quiet option +- [versionlock] Accept more pkgspec forms + +* Mon Oct 15 2018 Jaroslav Mracek - 4.0.0-1 +- Update to 4.0.0 +- Enhance documentation +- [repoclosure] check every --pkg attribute separately +- [repoclosure] Now accepts nevra as a argument of --pkg option +- [reposync] enhancements (RhBug:1550063,1582152,1550064,1405789,1598068) +- package-cleanup: remove --oldkernels +- Download only packages with unique NEVRAs (RhBug:1612874) + +* Tue Sep 25 2018 Jaroslav Mracek - 3.0.4-1 +- [copr] Huge upgrade of copr plugin +- [spec] Disable building python2 modules on Fedora 30+ +- Add characters into repo URL sanitization (RhBug:1615416) +- copr: add support for multiple copr instances (RhBug:1478208) +- Redirect repo progress to std error (RhBug:1626011) +- Resolves: rhbz#1578787 - repodiff command not available in dnf-utils + +* Wed Aug 01 2018 Charalampos Stratakis - 3.0.1-3 +- Rebuild for platform-python + +* Fri Jun 29 2018 Jaroslav Mracek 3.0.1-2 +- Rebuilt for Python 3.7 + +* Tue Jun 26 2018 Jaroslav Mracek 3.0.1-1 +- Enhanced documentation +- Resolves: rhbz#1576594 +- Resolves: rhbz#1530081 +- Resolves: rhbz#1547897 +- Resolves: rhbz#1550006 +- Resolves: rhbz#1431491 +- Resolves: rhbz#1516857 +- Resolves: rhbz#1499623 +- Resolves: rhbz#1489724 + +* Mon Jun 18 2018 Miro Hrončok - 2.1.5-5 +- Rebuilt for Python 3.7 + +* Sat Feb 10 2018 Igor Gnatenko - 2.1.5-4 +- Conflict with any yum-utils + +* Fri Feb 09 2018 Igor Gnatenko - 2.1.5-3 +- Escape macros in %%changelog + +* Wed Feb 07 2018 Fedora Release Engineering - 2.1.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Fri Oct 06 2017 Igor Gnatenko - 2.1.5-1 +- Fix download command (RHBZ #1498426) + +* Mon Oct 02 2017 Jaroslav Mracek 2.1.4-1 +- Added four new options for ``list`` subcommand of ``copr`` plugin +- Resolves: rhbz#1476834 - [abrt] dnf: arch(): config.py:908:arch:TypeError: unhashable type: 'list' + +* Wed Jul 26 2017 Fedora Release Engineering - 2.1.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Mon Jul 24 2017 Jaroslav Mracek 2.1.3-1 +- Solve conflict with migrate plugin (RhBug:1470843) (Jaroslav Mracek) +- Move copying to dnf (RhBug:1279001) (Ondřej Sojka) +- Return 1 if dnf config-manager --add-repo fails (RhBug:1439514) (Jaroslav + Mracek) +- bump minimal dnf version to 2.6.0 (Igor Gnatenko) +- trivial: remove whitespace at end of line (Igor Gnatenko) + +* Sun Jul 02 2017 Igor Gnatenko - 2.1.2-2 +- Fix crash in COPR plugin + +* Sat Jul 01 2017 Igor Gnatenko - 2.1.2-1 +- debuginfo-install: install only requested packages +- Unify user confirmation in copr with dnf itself + +* Mon Jun 12 2017 Jaroslav Mracek 2.1.1-1 +- bump version to 2.1.1 + update release notes (Jaroslav Mracek) +- Enhance versionlock documentation (Jaroslav Mracek) +- Fix typos in args.ingex to args.index (RhBug:1458446) (Jaroslav Mracek) +- dont run versionlock on non-transactional operations (Jan Silhan) + +* Mon May 22 2017 Jaroslav Mracek 2.1.0-1 +- bump version to 2.1.0 + update release notes (Jaroslav Mracek) +- Adjust the dnf-utils subpackage to be more accurate (Neal Gompa) +- Add new sub-package dnf-utils (RhBug:1381917) (Jaroslav Mracek) +- Fix two renamed functions by dnf privatization (Jaroslav Mracek) + +* Tue May 02 2017 Jaroslav Mracek 2.0.0-1 +- update release notes (Jaroslav Mracek) +- po: Update translations (Igor Gnatenko) +- Fix incorrect exclude of locked version in versionlock (Jaroslav Mracek) +- po: Update translations (Igor Gnatenko) +- Setup selectively provides for python2 packages (Jaroslav Mracek) +- Build python3 packages only if with_python3 (Jaroslav Mracek) +- Search only according nevra in versionlock (Jaroslav Mracek) +- Solve a problem in performance of versionlock (RhBug:1431493) (Jaroslav + Mracek) +- Repoclosure exit with 1 if unsatisfied dependencies (RhBug:1416782) (Jaroslav + Rohel) +- Not raise an Error if strict=False and --url for download command (Jaroslav + Mracek) +- Check argument if it is a file ending with .rpm (RhBug:1436570) (Jaroslav + Mracek) +- update link to "What I can build in Copr? documentation page (clime) +- po: Update translations (Igor Gnatenko) +- Create dir for local plugin if path not exist (Jaroslav Mracek) +- Correct some PEP8 violations after plugin import (Jaroslav Mracek) +- Add debug into dnf-plugins-core (Jaroslav Mracek) +- Added latest doc changes from plugins-extras upstream (Jaroslav Mracek) +- bump version to 2.0.0 (Jaroslav Mracek) +- Add migrate plugin into dnf-plugins-core (Jaroslav Mracek) +- Add man pages for transfered plugins (Jaroslav Mracek) +- Add provide dnf-plugin-* for each plugin (Jaroslav Mracek) +- Correct some PEP8 violations (Jaroslav Mracek) +- Add local into dnf-plugins-core (Jaroslav Mracek) +- Add leaves and show-leaves into dnf-plugins-core (Jaroslav Mracek) +- Add versionlock into dnf-plugins-core (Jaroslav Mracek) +- Add repograph into dnf-plugins-core (Jaroslav Mracek) +- Add repoclosure into dnf-plugins-core (Jaroslav Mracek) +- Add repomanage into dnf-plugins-core (Jaroslav Mracek) +- Add --archlist option for dnf download command (Jaroslav Mracek) +- Change code that provides package location for download command (Jaroslav + Mracek) +- po: update translations (Igor Gnatenko) +- po: add sv translations (Igor Gnatenko) + +* Tue Mar 21 2017 Igor Gnatenko 1.1.0-1 +- dnf dowload --resolve should download everytime requested packages + (RhBug:1276611) (stepasm) +- builddep: install requirements by provides (RhBug:1332830) (Igor Gnatenko) +- builddep: do not check GPG key of SRPM (RhBug:1431486) (Igor Gnatenko) +- builddep: properly check for nosrc.rpm (Igor Gnatenko) +- po: Update translations (RhBug:1429087) (Igor Gnatenko) +- Remove noroot plugin that was move into dnf itself (Jaroslav Mracek) + +* Mon Feb 20 2017 Jaroslav Mracek 1.0.2-1 +- bump version to 1.0.2 + update release notes (Jaroslav Mracek) +- download: add --urlprotocols option (Dusty Mabe) +- download: add --url cli option (RhBug:1250115) (Dusty Mabe) +- download: refactor download code (Dusty Mabe) +- copr: Tweak wording to be more generic (Neal Gompa) +- Automatic commit of package [dnf-plugins-core] release [1.0.1-1]. (Jaroslav + Mracek) +- bump version to 1.0.1 + update release notes (Jaroslav Mracek) + +* Thu Feb 16 2017 Igor Gnatenko - 1.0.1-2 +- Rebuild due to infra breakage + +* Fri Feb 10 2017 Jaroslav Mracek 1.0.1-1 +- bump version to 1.0.1 + update release notes (Jaroslav Mracek) +- setup SideCI to ignore some PEP8 violations (Jaroslav Mracek) +- spec: define all configs as (noreplace) (Igor Gnatenko) +- spec: include __pycache__ files (Igor Gnatenko) +- builddep: print errors from RPM SPEC parser (Petr Spacek) + +* Fri Feb 10 2017 Fedora Release Engineering - 1.0.0-0.rc1.2.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Tue Dec 13 2016 Stratakis Charalampos - 1.0.0-0.rc1.2 +- Rebuild for Python 3.6 + +* Thu Sep 29 2016 Michal Luscon 1.0.0-0.rc1.1 +- doc: open rpmspec in utf-8 mode (Igor Gnatenko) +- cls.chroot_config inside _guess_chroot returns None (RhBug: 1361003) (Michael + Goodwin) +- builddep: adjust to new config (dnf-2.0) (Michal Luscon) +- Change minimal required version (Jaroslav Mracek) +- introduced config-manager --dump-variables (RhBug:1360752) (Michael Mraka) +- Fix string puzzle in translatable message (Luigi Toscano) +- Added alias to 'builddep'->'build-dep' (RhBug:1350604) (stepasm) +- reposync should keep packages (RhBug:1325350) (Michael Mraka) +- Change usage of add_remote_rpm according to new API (Jaroslav Mracek) +- Remove lib.py from plugins-core (Jaroslav Mracek) +- Delete repoquery from dnf-plugins-core (Jaroslav Mracek) +- removed protected_packages plugin (Jan Silhan) +- repoquery: add --requires-pre switch (RhBug:1303117) (Michal Luscon) +- spec: bump version to 1.0.0 (Igor Gnatenko) +- Automatic commit of package [dnf-plugins-core] release [0.1.21-2]. (Igor + Gnatenko) +- Automatic commit of package [dnf-plugins-core] release [0.1.21-1]. (Igor + Gnatenko) +- spec: explicitly conflict with python-%%{name} with different version (Igor + Gnatenko) +- updated plugin to read_config() change (RhBug:1193823) (Michael Mraka) +- repoquery: sourcerpm does not contain epoch (RhBug:1335959) (Michael Mraka) +- enforce-api: use api method transaction (Michal Luscon) +- enforce-api: apply changes from Base class (Michal Luscon) +- copr: Read the %%distro_arch macro to determine Mageia chroot arch (Neal + Gompa (ニール・ゴンパ)) +- copr: Remove unnecessary function calls/options and simplify conditional + (Neal Gompa (ニール・ゴンパ)) +- copr: Add Mageia chroot selection support (Neal Gompa (ニール・ゴンパ)) +- copr: Simplify and fix up reading copr chroot config override (Neal Gompa + (ニール・ゴンパ)) +- autoglob feature has been moved to filter() (RhBug:1279538) (Michael Mraka) + +* Fri May 27 2016 Igor Gnatenko 0.1.21-2 +- spec: explicitly conflict with python-%%{name} with different version (Igor + Gnatenko) + +* Thu May 19 2016 Igor Gnatenko 0.1.21-1 +- doc: release notes 0.1.21 (Igor Gnatenko) +- spec: correctly set up requirements for python subpkg (Igor Gnatenko) +- spec: improve python packaging according to new guidelines & compat with EL7 + (Igor Gnatenko) +- tests/support: set priority and cost in RepoStub (Igor Gnatenko) +- repoquery: sourcerpm does not contain epoch (RhBug:1335959) (Michael Mraka) +- enforce-api: use api method transaction (Michal Luscon) +- enforce-api: apply changes from Base class (Michal Luscon) +- copr: Read the %%distro_arch macro to determine Mageia chroot arch (Neal + Gompa (ニール・ゴンパ)) +- copr: Remove unnecessary function calls/options and simplify conditional + (Neal Gompa (ニール・ゴンパ)) +- copr: Add Mageia chroot selection support (Neal Gompa (ニール・ゴンパ)) +- copr: Simplify and fix up reading copr chroot config override (Neal Gompa + (ニール・ゴンパ)) +- zanata update (Jan Silhan) +- Add link for other project documentation pages (Jaroslav Mracek) +- autoglob feature has been moved to filter() (RhBug:1279538) (Michael Mraka) +- support globs in --what (RhBug:1303311) (Michael Mraka) +- repoquery: fix typo (there -> that, and plural form) (Luigi Toscano) +- copr: fix string - singular is required (Luigi Toscano) +- doc: release notes updated to vallid plugins version (Jan Šilhan) + +* Tue Apr 05 2016 Michal Luscon 0.1.20-1 +- doc: release notes 0.1.20 (Igor Gnatenko) +- copr: Properly detect reposdir and add chroot override capability (Neal Gompa + (ニール・ゴンパ)) +- config_manager: Use new API in dnfpluginscore.lib for determining reposdir + (Neal Gompa (ニール・ゴンパ)) +- dnfpluginscore.lib: Add get_reposdir() API function (Neal Gompa (ニール・ゴンパ)) +- Fix typo (Eduardo Mayorga Téllez) + +* Tue Mar 22 2016 Miroslav Suchý 0.1.19-1 +- spec: correct requires on F22 + EPEL (Miroslav Suchý) + +* Tue Mar 22 2016 Miroslav Suchý 0.1.18-1 +- Add myself as contributor in AUTHORS (Neal Gompa (ニール・ゴンパ)) +- copr: copr.fedoraproject.org -> copr.fedorainfracloud.org (Neal Gompa + (ニール・ゴンパ)) +- copr: fix traceback when trying to enable non-existing project (RhBug: + 1304615) (Jakub Kadlčík) +- README: mention translation fixes should be made on Zanata (Jan Šilhan) + +* Thu Feb 25 2016 Michal Luscon 0.1.17-1 +- enable debuginfo repos if autoupdate is on (RhBug:1024701) (Michael Mraka) +- fixed string suffix removal (Michael Mraka) +- install latest debuginfo by default (Michael Mraka) +- Enable strings for translation (RhBug:1302214) (Parag Nemade) + +* Mon Jan 25 2016 Jan Silhan 0.1.16-1 +- zanata update (Jan Silhan) +- AUTHORS: updated (Jan Silhan) +- run noroot in non cli mode (RhBug:1297511) (Jan Silhan) +- Sanitize repos containing a tilde in the URL (François RIGAULT) +- contributor added (clime) +- latest-limit option moved to base set of options making it compatible with + --queryformat and other output formatters (RhBug: 1292475) (clime) +- builddep: do not download source package (Jeff Smith) +- repoquery: keep --autoremove as secret option (Jan Silhan) +- cosmetic: repoquery: remove unused imports (Jan Silhan) +- doc: repoquery: --recent (Jan Silhan) +- doc: renamed autoremove to unneeded and extended docs (Jan Silhan) + +* Fri Dec 18 2015 Michal Luscon 0.1.15-1 +- Make it possible to specify the source package name as parameter in stub + constructor. (Alexander Todorov) +- Add --debuginfo to download (Alexander Todorov) +- resolve local RPMs when downloading. useful with --source (Alexander Todorov) +- spec: ensure python*-dnf-plugins-core versions are the same (RhBug:1283448) + (Jan Silhan) +- reimplemented config file writing (RhBug:1253237) (Michael Mraka) + +* Mon Nov 16 2015 Michal Luscon 0.1.14-1 +- zanata update (Jan Silhan) +- repoquery: do not require loading metadata when we want to query system only + (Jan Silhan) +- repoquery: fix unicode tracebacks (Michal Luscon) +- repoquery: use new methods recent, extras, unneeded (Michal Luscon) +- repoquery: use new api methods duplicated and latest (RhBug:1231572) (Michal + Luscon) +- Exit with non-zero status if strict and package not found (alde) +- Fix cmdline conversion to unicode (RhBug:1265210) (Michal Domonkos) +- Remove extra 'l' in test class name (Alexander Todorov) +- copr: PEP formating (Miroslav Suchý) +- copr: allow to use staging instance of Copr for testing (Miroslav Suchý) +- do not use @ in repoid (RhBug:1280416) (Miroslav Suchý) +- reverts unintentional releaser from e035152 (Jan Silhan) +- don't look for builddeps on source packages (RhBug:1272936) (Michael Mraka) +- Fix hawkey version constraint (Neal Gompa (ニール・ゴンパ)) + +* Wed Oct 14 2015 Jan Silhan 0.1.13-1 +- updated: release notes for 0.1.13 (Jan Silhan) +- Remove kickstart plugin from core plugins (Neal Gompa + (ニール・ゴンパ)) +- read file as utf-8 in Py3 (RhBug:1267808) (Miroslav Suchý) +- playground: check if repo actually exists for our version of OS (Miroslav + Suchý) +- add Catalan (Robert Antoni Buj Gelonch) +- repoquery: Fix UnicodeEncodeError with --info (RhBug:1264125) (Jaroslav + Mracek) +- lookup builddeps in source package for given package name (RhBug:1265622) + (Michael Mraka) +- functions moved to library (Michael Mraka) +- functions to return name of source and debuginfo package (Michael Mraka) +- try -debuginfo first then -debuginfo (RhBug:1159614) (Michael + Mraka) +- Automatic commit of package [dnf-plugins-core] release [0.1.12-2]. (Michal + Luscon) +- doc: release notes 0.1.12 (Michal Luscon) + +* Tue Sep 22 2015 Michal Luscon 0.1.12-2 +- add python2-dnf requirements + +* Tue Sep 22 2015 Michal Luscon 0.1.12-1 +- repoquery: add globbing support to whatrequires/whatprovides. + (RhBug:1249073) (Valentina Mukhamedzhanova) +- needs_restarting: Rewrite a warning message (Wieland Hoffmann) +- Remove extra quotation mark in comment (Alexander Todorov) + +* Tue Sep 01 2015 Michal Luscon 0.1.11-1 +- dnf donwload checks for duplicate packages (rhBug:1250114) (Adam Salih) +- Extend repoquery --arch option. You can now pass multiple archs separated by + commas (RhBug:1186381) (Adam Salih) +- download plugin now prints not valid packages (RhBug:1225784) (Adam Salih) +- correct typo (Adam Salih) +- dnf now accepts more than one key (RhBug:1233728) (Adam Salih) +- description should be print unwrapped (Adam Salih) +- alternative to pkgnarrow (RhBug:1199601) (Adam Salih) +- sort output alphabetically, tree accepts switches --enhances --suggests + --provides --suplements --recommends (RhBug:1156778) (Adam Salih) + +* Mon Aug 10 2015 Jan Silhan 0.1.10-1 +- generate_completion_cache: use list for each insert (fixes regression + introduced in e020c96) (Igor Gnatenko) +- generate_completion_cache: store NEVRA insted of NA (RhBug:1226663) (Igor + Gnatenko) +- repoquery: weak deps queries (RhBug:1184930) (Michal Luscon) +- builddep requires an argument (Michael Mraka) +- disable c++ checks in rpmbuild (Michael Mraka) +- path may contain unicode (RhBug:1234099) (Michael Mraka) +- fail if no package match (RhBug:1241126) (Michael Mraka) +- make --spec and --srpm mutually exclusive (Michael Mraka) +- handle error message in python3 (RhBug:1218299) (Michael Mraka) +- options to recognize spec/srpm files (RhBug:1241135) (Michael Mraka) +- copr: set chmod to rw-r--r-- on repo files (Miroslav Suchý) +- [copr] refactor duplicated lines (Jakub Kadlčík) +- [copr] allow utf-8 user input (RhBug:1244125) (Jakub Kadlčík) +- [copr] fix regression with handling `search` and `list` subcommands (Valentin + Gologuzov) +- [copr] terminate execution when failed to parse project name (Valentin + Gologuzov) +- [copr] unused import (Valentin Gologuzov) +- [copr] subcommand `disable` now only set `enabled=0`, repo file could be + deleted by new subcommand `remove` (Valentin Gologuzov) + +* Wed Jun 24 2015 Michal Luscon 0.1.9-1 +- repoquery: add srpm option (RhBug:1186382) (Vladan Kudlac) +- create repo files readable by users (RhBug:1228693) (Michael Mraka) +- copr: use librepo instead of python-request (Miroslav Suchý) +- --tree now works with --conflicts --obsoletes --requires and --whatrequires + (RhBug:1128424) (RhBug:1186689) (Adam Salih) +- url for copr repos changed (RhBug:1227190) (Miroslav Suchý) +- repoquery: fixed conflicts package format (Adam Salih) +- document that globs can be used in dnf config-manager (Michael Mraka) + + +* Wed Jun 17 2015 Fedora Release Engineering - 0.1.8-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed May 06 2015 Michal Luscon 0.1.8-1 +- spec: fix an upgrade path from dnf-plugins-core <= 0.1.5 (Radek Holy) + +* Thu Apr 30 2015 Michal Luscon 0.1.7-1 +- doc: release notes dnf-plugins-core-0.1.7 (Michal Luscon) +- spec: fix Conflicts of the new plugins (Radek Holy) +- spec: allow DNF 1.x.x (Radek Holy) +- AUTHORS: filled in missing email address (Jan Silhan) +- download: enabling source repos when desired only (Jan Silhan) +- download: using enable_source_repos from lib (Jan Silhan) +- lib: inform user when enabling disabled repo (Jan Silhan) +- AUTHORS: made 2 categories (Jan Silhan) +- fixed typos and missing demand (Michael Mraka) +- changed warning paragraph (Michael Mraka) +- AUTHORS: updated (Jan Silhan) +- debuginfo-install: don't consider src packages as candidates for installation + (RhBug:1215154) (Lubomir Rintel) +- documentation warning about build deps in srpm (Michael Mraka) +- fixed builddep tests (Michael Mraka) +- builddep: enable source repos only when needed (Michael Mraka) +- fixed builldep documentation (Michael Mraka) +- mark appropriate dnfpluginscore.lib as API (Michael Mraka) +- fixed builddep configure test (Michael Mraka) +- moved enable_{source|debug}_repos() to dnfpluginscore.lib (Michael Mraka) +- builddep: add feature to get builddeps from remote packages (RhBug:1074585) + (Igor Gnatenko) +- doc: repoquery: doesn't print 'No match for argument:...' garbage (Jan + Silhan) +- updated repoquery documentation (Michael Mraka) +- implemented repoquery --latest-limit (Michael Mraka) +- implemented repoquery --unsatisfied (Michael Mraka) +- builddep: Support defining macros for parsing spec files (David Michael) +- removed redundant argument (Michael Mraka) +- doc: update repoquery docs with --resolve (Tim Lauridsen) +- repoquery: add --resolve option (RhBug:1156487) (Tim Lauridsen) +- spec: dnf version upper boundaries (Jan Silhan) +- spec: added plugin command provides (Related:RhBug:1208773) (Jan Silhan) +- make --repo cumulative (Michael Mraka) +- rename --repoid to --repo (Michael Mraka) +- don't delete local repo packages after download (RhBug:1186948) (Michael + Mraka) +- doc: replaced last references pointing to akozumpl (Jan Silhan) + +* Wed Apr 08 2015 Michal Luscon 0.1.6-3 +- doc: release notes 0.1.6 (Michal Luscon) +- initialize to use tito (Michal Luscon) +- prepare repo for tito build system (Michal Luscon) +- migrate raw_input() to Python3 (RhBug:1208399) (Miroslav Suchý) +- require dnf 0.6.5+ which contains duplicated/installonly queries (Michael Mraka) +- implemented --duplicated and --installonly (Michael Mraka) +- create --destdir if not exist (Michael Mraka) +- repoquery: Added -s/--source switch, test case and documentation for querying source rpm name (Parag Nemade) +- repoquery: Added documentation and test case for file switch (Parag Nemade) +- spec: ship man pages in dnf-plugins-core metapackage (Jan Silhan) +- debuginfo-install: support cases where src.rpm name != binary package name (Petr Spacek) +- spec: added empty %%files directive to generate rpm (Jan Silhan) +- spec: adapt to pykickstart f23 package split (Jan Silhan) +- spec: requires >= dnf version not = (Jan Silhan) +- spec: python3 source code by default in f23+ (RhBug:1194725,1198442) (Jan Silhan) +- use dnfpluginscore.lib.urlopen() (RhBug:1193047) (Miroslav Suchý) +- implemented functionality of yum-config-manager (Michael Mraka) +- repoquery: Added --file switch to show who owns the given file (RhBug:1196952) (Parag Nemade) +- debuginfo-install: accept packages names specified as NEVRA (RhBug:1171046) (Petr Spacek) +- repoquery: accept package names specified as NEVRA (RhBug:1179366) (Petr Spacek) +- download: fix typo in 'No source rpm definded' (Petr Spacek) +- download: accept package names ending with .src too (Petr Spacek) +- download: Do not disable user-enabled repos (thanks Spacekpe) (Jan Silhan) +- Add README to tests/ directory (Petr Spacek) +- AUTHORS: updated (Jan Silhan) +- download: fix package download on Python 3 (Petr Spacek) + +* Tue Mar 10 2015 Jan Silhan - 0.1.6-2 +- man pages moved into dnf-plugins-core subpackage + +* Fri Mar 6 2015 Jan Silhan - 0.1.6-1 +- fixed python(3)-dnf dependency in f23 + +* Thu Feb 5 2015 Jan Silhan - 0.1.5-1 +- updated package url (Michael Mraka) +- also dnf_version could be specified on rpmbuild commandline (Michael Mraka) +- simple script to build test package (Michael Mraka) +- let gitrev be specified on rpmbuild commandline (Michael Mraka) +- assign default GITREV value (Michael Mraka) +- standard way to find out latest commit (Michael Mraka) +- debuginfo-install: fix handling of subpackages with non-zero epoch (Petr Spacek) +- debuginfo-install: Make laywers happier by assigning copyright to Red Hat (Petr Spacek) +- debuginfo-install: remove dead code uncovered by variable renaming (Petr Spacek) +- debuginfo-install: clearly separate source and debug package names (Petr Spacek) +- debuginfo-install: use descriptive parameter name in _is_available() (Petr Spacek) +- repoquery: add -l option to list files contained in the package (Petr Spacek) +- 1187773 - replace undefined variable (Miroslav Suchý) +- download: fixed unicode location error (RhBug:1178239) (Jan Silhan) +- builddep recognizes nosrc.rpm pkgs (RhBug:1166126) (Jan Silhan) +- builddep: added nosignatures flag to rpm transaction set (Jan Silhan) +- builddep: more verbose output of non-matching packages (RhBug:1155211) (Jan Silhan) +- package: archive script is the same as in dnf (Jan Silhan) +- spec: exclude __pycache__ dir (Igor Gnatenko) + +* Fri Dec 5 2014 Jan Silhan - 0.1.4-1 +- revert of commit 80ae3f4 (Jan Silhan) +- transifex update (Jan Silhan) +- spec: binded to current dnf version (Jan Silhan) +- generate_completion_cache: use sqlite instead of text files (Igor Gnatenko) +- logging: renamed log file (Related:RhBug:1074715) (Jan Silhan) +- Add reposync. (RhBug:1139738) (Ales Kozumplik) +- download: fix traceback if rpm package has no defined sourcerpm (RhBug: 1144003) (Tim Lauridsen) +- lint: ignore warnings of a test accessing protected attribute. (Ales Kozumplik) +- repoquery lint: logger is not used. (Ales Kozumplik) +- repoquery: support querying of weak deps. (Ales Kozumplik) +- needs_restarting: fix typo (Miroslav Suchý) +- copr: migrate copr plugin form urlgrabber to python-request (Miroslav Suchý) +- Add needs-restarting command. (Ales Kozumplik) + +* Thu Sep 4 2014 Jan Silhan - 0.1.3-1 +- repoquery: output times in UTC. (Ales Kozumplik) +- repoquery: missing help messages. (Ales Kozumplik) +- repoquery: add --info. (RhBug:1135984) (Ales Kozumplik) +- add Jan to AUTHORS. (Ales Kozumplik) +- spec: extended package description with plugin names and commands (Related:RhBug:1132335) (Jan Silhan) +- copr: check for 'ok' in 'output' for json data (RhBug:1134378) (Igor Gnatenko) +- README: changed references to new repo location (Jan Silhan) +- transifex update (Jan Silhan) +- copr: convert key to unicode before guessing lenght (Miroslav Suchý) +- Add pnemade to AUTHORS (Ales Kozumplik) +- debuginfo-install: Use logger as module level variable and not instance attribute since dnf-0.6.0 release (RhBug:1130559) (Parag Nemade) +- copr: Use logger as module level variable and not instance attribute since dnf-0.6.0 release (RhBug:1130559) (Parag Nemade) +- copr: implement help command (Igor Gnatenko) +- debuginfo-install: fix indenting (Igor Gnatenko) +- debuginfo-install: use srpm basename for debuginfo (Igor Gnatenko) + +* Mon Jul 28 2014 Aleš Kozumplík - 0.1.2-1 +- BashCompletionCache: error strings are unicoded (RhBug:1118809) (Jan Silhan) +- transifex update (Jan Silhan) +- debuginfo-install: remove some pylint warnings (Igor Gnatenko) +- debuginfo-install: fix installing when installed version not found in repos, optimize performance (RhBug: 1108321) (Ig +- fix: copr plugin message for repo without builds (RhBug:1116389) (Adam Samalik) +- logging: remove messages about initialization. (Ales Kozumplik) + +* Thu Jul 3 2014 Aleš Kozumplík - 0.1.1-2 +- packaging: add protected_packages.py to the package. (Ales Kozumplik) + +* Thu Jul 3 2014 Aleš Kozumplík - 0.1.1-1 +- protected_packages: prevent removal of the running kernel. (RhBug:1049310) (Ales Kozumplik) +- packaging: create and own /etc/dnf/protected.d. (Ales Kozumplik) +- doc: add documentation for protected_packages. (Ales Kozumplik) +- doc: rename: generate-completion-cache -> generate_completion_cache. (Ales Kozumplik) +- add protected_packages (RhBug:1111855) (Ales Kozumplik) +- build: add python-requests to requires (RHBZ: 1104088) (Miroslav Suchý) +- doc: typo: fix double 'plugin' in release notes. (Ales Kozumplik) + +* Wed Jun 4 2014 Aleš Kozumplík - 0.1.0-1 +- pylint: fix all pylint builddep problems. (Ales Kozumplik) +- builddep: better error reporting on deps that actually don't exist. (Ales Kozumplik) +- builddep: load available repos. (RhBug:1103906) (Ales Kozumplik) +- tests: stop argparse from printing to stdout when tests run. (Ales Kozumplik) +- packaging: all the manual pages with a glob. (Ales Kozumplik) +- fix: packaging problem with query.py. (Ales Kozumplik) +- doc: add reference documentation for repoquery. (Ales Kozumplik) +- repoquery: support --provides, --requires etc. (Ales Kozumplik) +- repoquery: make the CLI more compatible with Yum's repoquery. (Ales Kozumplik) +- repoquery: some cleanups in the plugin and the tests. (Ales Kozumplik) +- rename: query->repoquery. (RhBug:1045078) (Ales Kozumplik) +- add pylint script for dnf-core-plugins. (Ales Kozumplik) +- tests: repoquery: fix unit tests. (Ales Kozumplik) +- add query tool (Tim Lauridsen) + +* Wed May 28 2014 Aleš Kozumplík - 0.0.8-1 +- build: add sphinx to build requires. (Ales Kozumplik) +- doc: packaging: add license block to each .rst. (Ales Kozumplik) +- tests: stray print() in test_download.py. (Ales Kozumplik) +- doc: put each synopsis on new line (Miroslav Suchý) +- doc: cosmetic: project name in the documentation. (Ales Kozumplik) +- doc: cleanups, form, style. (Ales Kozumplik) +- doc: add documentation and man pages (Tim Lauridsen) +- copr: remove repofile if failed to enable repo (Igor Gnatenko) +- copr: honor -y and --assumeno (Miroslav Suchý) +- py3: absolute imports and unicode literals everywhere. (Ales Kozumplik) +- debuginfo-install: doesn't install latest pkgs (RhBug: 1096507) (Igor Gnatenko) +- debuginfo-install: fix description (Igor Gnatenko) +- debuginfo-install: fix logger debug messages (Igor Gnatenko) +- build: install the download plugin (Tim Lauridsen) +- download: update the download plugin with --source, --destdir & --resolve options (Tim Lauridsen) +- Add a special ArgumentParser to parsing plugin cmd arguments and options (Tim Lauridsen) +- tests: add __init__.py to make tests a module and use abs imports (Tim Lauridsen) +- build: simplify plugins/CMakeLists.txt. (Ales Kozumplik) +- dnf.cli.commands.err_mini_usage() changed name. (Ales Kozumplik) +- kickstart: do not include kickstart errors into own messages. (Radek Holy) + +* Wed Apr 23 2014 Aleš Kozumplík - 0.0.7-1 +- build: gettext is also needed as a buildreq (Tim Lauridsen) +- copr: use usage & summary class attributes, to work with dnf 0.5.0 use shared lib dnfpluginscore for translation wrapp +- build: add cmake as buildreq (Tim Lauridsen) +- generate-completion-cache: fix shared lib name (Tim Lauridsen) +- make .spec use gitrev in the source file add helper script for building source archive (Tim Lauridsen) +- Added transifex config (Tim Lauridsen) +- tests: use cli logger in kickstart test (Tim Lauridsen) +- Added translation .pot file Added da translation files so we have something to build & install (Tim Lauridsen) +- Added CMake files Added CMake build to .spec & and added translation files handling (Tim Lauridsen) +- make plugins use shared lib added translation wrappers added missing usage & summary PEP8 fixes (Tim Lauridsen) +- added shared dnfpluginscore lib (Tim Lauridsen) +- copr: C:139, 0: Unnecessary parens after 'print' keyword (superfluous-parens) (Miroslav Suchý) +- copr: W: 23, 0: Unused import gettext (unused-import) (Miroslav Suchý) +- copr: C: 33, 0: No space allowed before : (Miroslav Suchý) +- copr: some python3 migration (Miroslav Suchý) +- copr: get rid of dnf i18n imports (Miroslav Suchý) +- remove dnf.yum.i18n imports. (Ales Kozumplik) +- copr: Fix the playground upgrade command. (Tadej Janež) +- copr: implement search function (Igor Gnatenko) +- better format output (Miroslav Suchý) +- implement playground plugin (Miroslav Suchý) +- move removing of repo into method (Miroslav Suchý) +- check root only for actions which really need root (Miroslav Suchý) +- move repo downloading into separate method (Miroslav Suchý) +- define copr url as class attribute (Miroslav Suchý) +- better wording of warning (Miroslav Suchý) +- move question to function argument (Miroslav Suchý) +- move guessing chroot into function (Miroslav Suchý) +- copr: use common lib use Command.usage & summary cleanup imports & PEP8 fixes (Tim Lauridsen) +- builddep: added usage & summary & fix some PEP8 issues (Tim Lauridsen) +- kickstart: use new public Command.usage & Command.summary api (Tim Lauridsen) +- fix resource leak in builddep.py. (Ales Kozumplik) +- refactor: command plugins use demands mechanism. (Ales Kozumplik) +- noroot: move to the new 'demands' mechanism to check the need of root. (Ales Kozumplik) +- tests: fix locale independence. (Radek Holy) +- [copr] correctly specify chroot when it should be guessed (Miroslav Suchý) + +* Mon Mar 17 2014 Aleš Kozumplík - 0.0.6-1 +- clenaup: remove commented out code (Miroslav Suchý) +- copr: list: print description (Igor Gnatenko) +- builddep: rpm error messages sink. (Ales Kozumplik) +- builddep: improve error handling on an command argument (RhBug:1074436) (Ales Kozumplik) +- copr: handling case when no argument is passed on cli (Miroslav Suchý) +- copr: delete excess argument (Igor Gnatenko) +- add copr plugin (Miroslav Suchý) +- debuginfo-install: check for root with dnf api (Igor Gnatenko) +- packaging: fix bogus dates. (Ales Kozumplik) + +* Wed Feb 26 2014 Aleš Kozumplík - 0.0.5-2 +- packaging: add debuginfo-install.py (Ales Kozumplik) + +* Wed Feb 26 2014 Aleš Kozumplík - 0.0.5-1 +- packaging: add builddep.py to the RPM. (Ales Kozumplik) + +* Tue Feb 25 2014 Radek Holý - 0.0.4-1 +- refactor: use Base.install instead of installPkgs in kickstart plugin. (Radek Holy) +- refactor: move kickstart arguments parsing to standalone method. (Radek Holy) +- tests: test effects instead of mock calls. (Radek Holy) +- Add debuginfo-install plugin. (RhBug:1045770) (Igor Gnatenko) +- builddep: needs to be run under root. (RhBug:1065851) (Ales Kozumplik) + +* Thu Feb 6 2014 Aleš Kozumplík - 0.0.3-1 +- tests: import mock through support so its simpler for the test cases. (Ales Kozumplik) +- packaging: fix typos in the spec. (Ales Kozumplik) +- [completion_cache] Cache installed packages, update the cache less frequently (Elad Alfassa) +- Add bash completion to dnf (Elad Alfassa) +- packaging: missing buildrequire (Ales Kozumplik) + +* Mon Jan 13 2014 Aleš Kozumplík - 0.0.2-1 +- First release. + +* Wed Jan 8 2014 Cristian Ciupitu - 0.0.1-4 +- Spec updates. + +* Tue Jan 7 2014 Aleš Kozumplík - 0.0.1-3 +- Spec updates. + +* Mon Jan 6 2014 Aleš Kozumplík - 0.0.1-2 +- Spec updates. + +* Fri Dec 20 2013 Aleš Kozumplík - 0.0.1-1 +- The initial package version.