diff --git a/.gitignore b/.gitignore index ffaf1ce..6e98b30 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /dnf-plugins-core-d8e8044.tar.xz /dnf-plugins-core-c8940d0.tar.xz /dnf-plugins-core-351e094.tar.xz +/dnf-plugins-core-0.1.5.tar.gz diff --git a/dnf-plugins-core-0.1.5-1-to-dnf-plugins-core-0.1.5-2.patch b/dnf-plugins-core-0.1.5-1-to-dnf-plugins-core-0.1.5-2.patch new file mode 100644 index 0000000..de5d18a --- /dev/null +++ b/dnf-plugins-core-0.1.5-1-to-dnf-plugins-core-0.1.5-2.patch @@ -0,0 +1,2115 @@ +diff --git a/AUTHORS b/AUTHORS +index 88003d1..c8ce939 100644 +--- a/AUTHORS ++++ b/AUTHORS +@@ -1,6 +1,7 @@ + Ales Kozumplik + Igor Gnatenko + Jan Silhan ++Michal Mraka + Miroslav Suchý + Parag Nemade + Petr Špaček +diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec +new file mode 100644 +index 0000000..b9e0a38 +--- /dev/null ++++ b/dnf-plugins-core.spec +@@ -0,0 +1,329 @@ ++%{?!dnf_version: %global dnf_version 0.6.4} ++ ++Name: dnf-plugins-core ++Version: 0.1.5 ++Release: 2%{?dist} ++Summary: Core Plugins for DNF ++Group: System Environment/Base ++License: GPLv2+ ++URL: https://github.com/rpm-software-management/dnf-plugins-core ++ ++# source archive is created by running package/archive from a git checkout ++Source0: dnf-plugins-core-%{version}.tar.gz ++ ++BuildArch: noarch ++BuildRequires: cmake ++BuildRequires: dnf = %{dnf_version} ++BuildRequires: gettext ++BuildRequires: pykickstart ++BuildRequires: python-nose ++BuildRequires: python-sphinx ++BuildRequires: python2-devel ++Requires: dnf = %{dnf_version} ++Requires: pykickstart ++Requires: python-requests ++ ++%description ++Core Plugins for DNF. This package enhance DNF with builddep, config-manager, ++copr, debuginfo-install, download, kickstart, needs-restarting, repoquery and ++reposync commands. Additionally provides generate_completion_cache, noroot and ++protected_packages passive plugins. ++ ++%package -n python3-dnf-plugins-core ++Summary: Core Plugins for DNF ++Group: System Environment/Base ++BuildRequires: python3-devel ++BuildRequires: python3-dnf = %{dnf_version} ++BuildRequires: python3-nose ++BuildRequires: python3-sphinx ++Requires: python3-dnf = %{dnf_version} ++ ++%description -n python3-dnf-plugins-core ++Core Plugins for DNF, Python 3 version. This package enhance DNF with builddep, ++config-manager, copr, debuginfo-install, download, kickstart, needs-restarting, ++repoquery and reposync commands. Additionally provides generate_completion_cache, ++noroot and protected_packages passive plugins. ++ ++%prep ++%setup -q -n dnf-plugins-core-%{version} ++rm -rf py3 ++mkdir ../py3 ++cp -a . ../py3/ ++mv ../py3 ./ ++ ++%build ++%cmake . ++make %{?_smp_mflags} ++make doc-man ++pushd py3 ++%cmake -DPYTHON_DESIRED:str=3 . ++make %{?_smp_mflags} ++make doc-man ++popd ++ ++%install ++make install DESTDIR=$RPM_BUILD_ROOT ++%find_lang %{name} ++pushd py3 ++make install DESTDIR=$RPM_BUILD_ROOT ++popd ++ ++%check ++PYTHONPATH=./plugins /usr/bin/nosetests-2.* -s tests/ ++PYTHONPATH=./plugins /usr/bin/nosetests-3.* -s tests/ ++ ++%files -f %{name}.lang ++%doc AUTHORS COPYING README.rst ++%dir %{_sysconfdir}/dnf/protected.d ++%ghost %{_var}/cache/dnf/packages.db ++%{python_sitelib}/dnf-plugins/* ++%{python_sitelib}/dnfpluginscore/ ++%{_mandir}/man8/dnf.plugin.* ++ ++%files -n python3-dnf-plugins-core -f %{name}.lang ++%doc AUTHORS COPYING README.rst ++%dir %{_sysconfdir}/dnf/protected.d ++%ghost %{_var}/cache/dnf/packages.db ++%exclude %{python3_sitelib}/dnf-plugins/__pycache__/ ++%{python3_sitelib}/dnf-plugins/* ++%{python3_sitelib}/dnf-plugins/__pycache__/* ++%{python3_sitelib}/dnfpluginscore/ ++%{_mandir}/man8/dnf.plugin.* ++ ++%changelog ++* Mon Apr 13 2015 Michal Luscon 0.1.5-2 ++- prepare repo for tito build system (Michal Luscon) ++- migrate raw_input() to Python3 (RhBug:1208399) (Miroslav Suchý) ++- 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) ++- debuginfo-install: support cases where src.rpm name != binary package name (Petr Spacek) ++- 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) ++- cosmetic: download: pylint fixes (Jan Silhan) ++- download: Do not disable user-enabled repos (thanks Spacekpe) (Jan Silhan) ++- let pylint ignore unused variables starting with _ (Michael Mraka) ++- updated copyright (Michael Mraka) ++- fixed pylint warning Redefining name from outer scope (Michael Mraka) ++- fixed pylint warning Invalid constant name (Michael Mraka) ++- fixed pylint warnings Line too long (Michael Mraka) ++- pylint fix for Wrong continued indentation (Michael Mraka) ++- updated copyright (Michael Mraka) ++- pylint fix for Specify string format arguments as logging function parameters (Michael Mraka) ++- pylint fix for Method could be a function (Michael Mraka) ++- pylint fix for __init__ method from base class is not called (Michael Mraka) ++- pylint fix for Attribute defined outside __init__ (Michael Mraka) ++- updated copyright (Michael Mraka) ++- pylint fix for __init__ method from base class is not called (Michael Mraka) ++- pylint fix for Wrong continued indentation (Michael Mraka) ++- updated copyright (Michael Mraka) ++- pylint fix for Method could be a function (Michael Mraka) ++- pylint fix for __init__ method from base class is not called (Michael Mraka) ++- updated copyright (Michael Mraka) ++- pylint fix for Unused import (Michael Mraka) ++- pylint fix for __init__ method from base class is not called (Michael Mraka) ++- updated copyright (Michael Mraka) ++- pylint fix for Unused import (Michael Mraka) ++- Add README to tests/ directory (Petr Spacek) ++- AUTHORS: updated (Jan Silhan) ++- download: fix package download on Python 3 (Petr Spacek) ++ ++* 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. +diff --git a/doc/conf.py b/doc/conf.py +index f2741a4..f1976ae 100644 +--- a/doc/conf.py ++++ b/doc/conf.py +@@ -56,7 +56,7 @@ copyright = u'2014, Red Hat, Licensed under GPLv2+' + # The short X.Y version. + + def version_readout(): +- fn = os.path.join(_dirname, '../package/dnf-plugins-core.spec') ++ fn = os.path.join(_dirname, '../dnf-plugins-core.spec') + with open(fn) as f: + lines = f.readlines() + for line in lines: +@@ -242,6 +242,8 @@ AUTHORS=[u'See AUTHORS in your Core DNF Plugins distribution'] + man_pages = [ + ('builddep', 'dnf.plugin.builddep', u'DNF builddep Plugin', + AUTHORS, 8), ++ ('config_manager', 'dnf.plugin.config_manager', ++ u'DNF config-manager Plugin', AUTHORS, 8), + ('copr', 'dnf.plugin.copr', u'DNF copr Plugin', + AUTHORS, 8), + ('debuginfo-install', 'dnf.plugin.debuginfo-install', +diff --git a/doc/config_manager.rst b/doc/config_manager.rst +new file mode 100644 +index 0000000..cdfbf2d +--- /dev/null ++++ b/doc/config_manager.rst +@@ -0,0 +1,79 @@ ++.. ++ 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 config-manager Plugin ++========================== ++ ++Manage main DNF configuration options, toggle which ++repositories are enabled or disabled, and add new repositories. ++ ++-------- ++Synopsis ++-------- ++ ++``dnf config-manager [options] ...`` ++ ++--------- ++Arguments ++--------- ++ ++```` ++ Display / modify specified repository. If not specified display / modify main DNF configuration. ++ ++------- ++Options ++------- ++ ++``--help-cmd`` ++ Show this help. ++ ++``--add-repo=URL`` ++ Add (and enable) the repo from the specified file or url. ++ ++``--dump`` ++ Print dump of current configuration values to stdout. ++ ++``--set-disabled`` ++ Disable the specified repos (automatically saves). ++ ++``--set-enabled`` ++ Enable the specified repos (automatically saves). ++ ++``--save`` ++ Save the current options (useful with --setopt). ++ ++-------- ++Examples ++-------- ++``dnf config-manager --add-repo http://example.com/some/additional.repo`` ++ Download additional.repo and store it in repodir. ++ ++``dnf config-manager --add-repo http://example.com/different/repo`` ++ Create new repo file with http://example.com/different/repo as baseurl and enable it. ++ ++``dnf config-manager`` ++ Display main DNF configuration. ++ ++``dnf config-manager repo`` ++ Display configuration of repo. ++ ++``dnf config-manager --set-enabled repo`` ++ Enable repo and make the change permanent. ++ ++``dnf config-manager --setopt proxy=http://proxy.example.com:3128/ repo1 repo2 --save`` ++ Update proxy setting in repo1 and repo2 and make the change permanent. +diff --git a/doc/download.rst b/doc/download.rst +index d4653d8..9a24b42 100644 +--- a/doc/download.rst ++++ b/doc/download.rst +@@ -42,7 +42,7 @@ Options + Show this help. + + ``--source`` +- Download the source rpm. ++ Download the source rpm. Enables source repositories of all enabled binary repositories. + + ``--destdir`` + Download directory, default is the current directory (the directory must exist). +diff --git a/doc/index.rst b/doc/index.rst +index e1ee869..3c5b459 100644 +--- a/doc/index.rst ++++ b/doc/index.rst +@@ -26,6 +26,7 @@ This documents core plugins of DNF: + + release_notes + builddep ++ config_manager + copr + debuginfo-install + download +diff --git a/doc/repoquery.rst b/doc/repoquery.rst +index 99a8eb7..e14f3ba 100644 +--- a/doc/repoquery.rst ++++ b/doc/repoquery.rst +@@ -25,7 +25,7 @@ Query package information from Yum repositories. + Synopsis + -------- + +-``dnf repoquery [] [] []`` ++``dnf repoquery [] [] []`` + ``dnf repoquery --querytags`` + + ----------- +@@ -38,11 +38,18 @@ Description + Select Options + -------------- + +-Together with ````, control what packages are displayed in the output. If ```` is given, the set of resulting packages is limited to the ones with a matching name (globbing supported), else all packages are considered. ++Together with ````, control what packages are displayed in the output. If ```` is given, the set of resulting packages matching the specification. All packages are considered if no ```` is specified. ++ ++```` ++ Package specification like: name[-[epoch:]version[-release]][.arch]. See ++ http://dnf.readthedocs.org/en/latest/command_ref.html#specifying-packages + + ``--arch `` + Limit the resulting set only to packages of arch ````. + ++``-f ``, ``--file `` ++ Limit the resulting set only to package that owns ````. ++ + ``--repoid `` + Limit the resulting set only to packages from repo identified by ````. + +@@ -71,6 +78,9 @@ The following are mutually exclusive, i.e. at most one can be specified. If no q + ``-l, --list`` + Show list of files in the package. + ++``-s, --source`` ++ Show package source RPM name. ++ + ``--obsoletes`` + Display capabilities that the package obsoletes. Same as ``--qf "%{obsoletes}``. + +@@ -96,6 +106,14 @@ Display requires of all ligttpd packages:: + + dnf repoquery --requires lighttpd + ++Display source rpm of ligttpd package:: ++ ++ dnf repoquery --source lighttpd ++ ++Display package name that owns the given file:: ++ ++ dnf repoquery --file /etc/lighttpd/lighttpd.conf ++ + Display name, architecture and the containing repository of all lighttpd packages:: + + dnf repoquery --queryformat '%{name}.%{arch} : %{reponame}' lighttpd +diff --git a/package/archive b/package/archive +deleted file mode 100755 +index 16f652e..0000000 +--- a/package/archive ++++ /dev/null +@@ -1,11 +0,0 @@ +-#! /bin/bash +- +-GITREV=${1:-$(git rev-parse --short HEAD)} +-# shorten to 7 characters +-GITREV=${GITREV:0:7} +- +-echo $GITREV +- +-TARGET_DIR=$HOME/rpmbuild/SOURCES +-mkdir -p $TARGET_DIR +-git archive ${GITREV} --prefix=dnf-plugins-core/ | xz > $TARGET_DIR/dnf-plugins-core-${GITREV}.tar.xz +diff --git a/package/build-test-rpm b/package/build-test-rpm +deleted file mode 100755 +index 2241c8c..0000000 +--- a/package/build-test-rpm ++++ /dev/null +@@ -1,9 +0,0 @@ +-#!/bin/bash +- +-DIR=$(dirname "$0") +-GITREV=${1:-$(git rev-parse --short HEAD)} +-# shorten long SHA1 from user to 7 characters +-GITREV=${GITREV:0:7} +- +-$DIR/archive "$GITREV" +-rpmbuild -ba --define "gitrev $GITREV" $DIR/*.spec +diff --git a/package/dnf-plugins-core.spec b/package/dnf-plugins-core.spec +deleted file mode 100644 +index ac288a7..0000000 +--- a/package/dnf-plugins-core.spec ++++ /dev/null +@@ -1,268 +0,0 @@ +-%{!?gitrev: %global gitrev c8940d0} +-%{?!dnf_version: %global dnf_version 0.6.3} +- +-Name: dnf-plugins-core +-Version: 0.1.5 +-Release: 1%{?dist} +-Summary: Core Plugins for DNF +-Group: System Environment/Base +-License: GPLv2+ +-URL: https://github.com/rpm-software-management/dnf-plugins-core +- +-# source archive is created by running package/archive from a git checkout +-Source0: dnf-plugins-core-%{gitrev}.tar.xz +- +-BuildArch: noarch +-BuildRequires: cmake +-BuildRequires: dnf = %{dnf_version} +-BuildRequires: gettext +-BuildRequires: pykickstart +-BuildRequires: python-nose +-BuildRequires: python-sphinx +-BuildRequires: python2-devel +-Requires: dnf = %{dnf_version} +-Requires: pykickstart +-Requires: python-requests +- +-%description +-Core Plugins for DNF. This package enhance DNF with builddep, copr, +-debuginfo-install, download, kickstart, needs-restarting, repoquery and +-reposync commands. Additionally provides generate_completion_cache, noroot and +-protected_packages passive plugins. +- +-%package -n python3-dnf-plugins-core +-Summary: Core Plugins for DNF +-Group: System Environment/Base +-BuildRequires: python3-devel +-BuildRequires: python3-dnf = %{dnf_version} +-BuildRequires: python3-nose +-BuildRequires: python3-sphinx +-Requires: python3-dnf = %{dnf_version} +- +-%description -n python3-dnf-plugins-core +-Core Plugins for DNF, Python 3 version. This package enhance DNF with builddep, copr, +-debuginfo-install, download, kickstart, needs-restarting, repoquery and +-reposync commands. Additionally provides generate_completion_cache, noroot and +-protected_packages passive plugins. +- +-%prep +-%setup -q -n dnf-plugins-core +-rm -rf py3 +-mkdir ../py3 +-cp -a . ../py3/ +-mv ../py3 ./ +- +-%build +-%cmake . +-make %{?_smp_mflags} +-make doc-man +-pushd py3 +-%cmake -DPYTHON_DESIRED:str=3 . +-make %{?_smp_mflags} +-make doc-man +-popd +- +-%install +-make install DESTDIR=$RPM_BUILD_ROOT +-%find_lang %{name} +-pushd py3 +-make install DESTDIR=$RPM_BUILD_ROOT +-popd +- +-%check +-PYTHONPATH=./plugins /usr/bin/nosetests-2.* -s tests/ +-PYTHONPATH=./plugins /usr/bin/nosetests-3.* -s tests/ +- +-%files -f %{name}.lang +-%doc AUTHORS COPYING README.rst +-%dir %{_sysconfdir}/dnf/protected.d +-%ghost %{_var}/cache/dnf/packages.db +-%{python_sitelib}/dnf-plugins/* +-%{python_sitelib}/dnfpluginscore/ +-%{_mandir}/man8/dnf.plugin.* +- +-%files -n python3-dnf-plugins-core -f %{name}.lang +-%doc AUTHORS COPYING README.rst +-%dir %{_sysconfdir}/dnf/protected.d +-%ghost %{_var}/cache/dnf/packages.db +-%exclude %{python3_sitelib}/dnf-plugins/__pycache__/ +-%{python3_sitelib}/dnf-plugins/* +-%{python3_sitelib}/dnf-plugins/__pycache__/* +-%{python3_sitelib}/dnfpluginscore/ +-%{_mandir}/man8/dnf.plugin.* +- +-%changelog +- +-* 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. +diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt +index a21777b..1f40737 100644 +--- a/plugins/CMakeLists.txt ++++ b/plugins/CMakeLists.txt +@@ -1,5 +1,6 @@ + INSTALL (FILES builddep.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES debuginfo-install.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) ++INSTALL (FILES config_manager.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES copr.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES download.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) + INSTALL (FILES generate_completion_cache.py DESTINATION ${PYTHON_INSTALL_DIR}/dnf-plugins) +diff --git a/plugins/config_manager.py b/plugins/config_manager.py +new file mode 100644 +index 0000000..812e34a +--- /dev/null ++++ b/plugins/config_manager.py +@@ -0,0 +1,255 @@ ++# ++# 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. ++# ++ ++from __future__ import absolute_import ++from __future__ import unicode_literals ++from dnfpluginscore import _, logger ++ ++import dnf ++import dnf.cli ++import dnf.pycomp ++import dnfpluginscore ++import dnfpluginscore.lib ++import os ++import re ++import shutil ++ ++ ++class ConfigManager(dnf.Plugin): ++ ++ name = 'config-manager' ++ ++ def __init__(self, base, cli): ++ super(ConfigManager, self).__init__(base, cli) ++ self.base = base ++ self.cli = cli ++ if self.cli is not None: ++ self.cli.register_command(ConfigManagerCommand) ++ ++ ++class ConfigManagerCommand(dnf.cli.Command): ++ ++ aliases = ['config-manager'] ++ summary = _('manage dnf configuration options and repositories') ++ usage = '[%s] [%s]' % (_('OPTIONS'), _('KEYWORDS')) ++ ++ def __init__(self, cli): ++ super(ConfigManagerCommand, self).__init__(cli) ++ self.opts = None ++ self.parser = None ++ ++ def configure(self, args): ++ # setup sack and populate it with enabled repos ++ demands = self.cli.demands ++ demands.available_repos = True ++ ++ self.parser = dnfpluginscore.ArgumentParser(self.aliases[0]) ++ self.parser.add_argument( ++ 'repo', nargs='*', ++ help=_('repo to modify')) ++ self.parser.add_argument( ++ '--save', default=False, action='store_true', ++ help=_('save the current options (useful with --setopt)')) ++ self.parser.add_argument( ++ '--set-enabled', default=False, action='store_true', ++ help=_('enable the specified repos (automatically saves)')) ++ self.parser.add_argument( ++ '--set-disabled', default=False, action='store_true', ++ help=_('disable the specified repos (automatically saves)')) ++ self.parser.add_argument( ++ '--add-repo', default=[], action='append', metavar='URL', ++ help=_('add (and enable) the repo from the specified file or url')) ++ self.parser.add_argument( ++ '--dump', default=False, action='store_true', ++ help=_('print current configuration values to stdout')) ++ ++ self.opts = self.parser.parse_args(args) ++ ++ if self.opts.help_cmd: ++ print(self.parser.format_help()) ++ return ++ ++ if (self.opts.save or self.opts.set_enabled or ++ self.opts.set_disabled or self.opts.add_repo): ++ demands.root_user = True ++ ++ ++ def run(self, _args): ++ """Execute the util action here.""" ++ ++ if self.opts.help_cmd: ++ return ++ if self.opts.set_enabled and self.opts.set_disabled: ++ logger.error( ++ _("Error: Trying to enable and disable repos at the same time.")) ++ self.opts.set_enabled = self.opts.set_disabled = False ++ if self.opts.set_enabled and not self.opts.repo: ++ logger.error(_("Error: Trying to enable already enabled repos.")) ++ self.opts.set_enabled = False ++ ++ if self.opts.add_repo: ++ self.add_repo() ++ else: ++ self.modify_repo() ++ ++ def modify_repo(self): ++ """ process --set-enabled, --set-disabled and --setopt options """ ++ ++ sbc = self.base.conf ++ modify = [] ++ if hasattr(self.cli, 'main_setopts') and self.cli.main_setopts: ++ modify = self.cli.main_setopts.items ++ if not self.opts.repo or 'main' in self.opts.repo: ++ if self.opts.dump: ++ print(self.base.output.fmtSection('main')) ++ print(self.base.conf.dump()) ++ if self.opts.save and modify: ++ # modify [main] in dnf.conf ++ dnfpluginscore.lib.write_raw_configfile(dnf.const.CONF_FILENAME, ++ 'main', sbc.substitutions, ++ sbc.cfg.options, ++ sbc.iteritems, ++ sbc.optionobj, ++ modify) ++ ++ if self.opts.set_enabled or self.opts.set_disabled: ++ self.opts.save = True ++ modify.append('enabled') ++ ++ if self.opts.repo: ++ matched = [] ++ for name in self.opts.repo: ++ matched.extend(self.base.repos.get_matching(name)) ++ else: ++ matched = self.base.repos.iter_enabled() ++ ++ if not matched: ++ raise dnf.exceptions.Error(_("No matching repo to modify: %s.") ++ % ', '.join(self.opts.repo)) ++ for repo in sorted(matched): ++ if self.opts.dump: ++ print(self.base.output.fmtSection('repo: ' + repo.id)) ++ if self.opts.set_enabled and not repo.enabled: ++ repo.enable() ++ elif self.opts.set_disabled and repo.enabled: ++ repo.disable() ++ if self.opts.dump: ++ print(repo.dump()) ++ repo_modify = modify[:] ++ if (hasattr(self.cli, 'repo_setopts') ++ and repo.id in self.cli.repo_setopts): ++ repo_modify.extend(self.cli.repo_setopts[repo.id].items) ++ if self.opts.save and modify: ++ dnfpluginscore.lib.write_raw_configfile(repo.repofile, ++ repo.id, ++ sbc.substitutions, ++ repo.cfg.options, ++ repo.iteritems, ++ repo.optionobj, ++ repo_modify) ++ ++ def add_repo(self): ++ """ process --add-repo option """ ++ ++ # put repo file into first reposdir which exists or create it ++ myrepodir = None ++ for rdir in self.base.conf.reposdir: ++ if os.path.exists(rdir): ++ myrepodir = rdir ++ break ++ ++ if not myrepodir: ++ myrepodir = self.base.conf.reposdir[0] ++ dnf.util.ensure_dir(myrepodir) ++ ++ for url in self.opts.add_repo: ++ if dnf.pycomp.urlparse.urlparse(url).scheme == '': ++ url = 'file://' + os.path.abspath(url) ++ logger.info(_('Adding repo from: %s'), url) ++ if url.endswith('.repo'): ++ # .repo file - download, put into reposdir and enable it ++ destname = os.path.basename(url) ++ destname = os.path.join(myrepodir, destname) ++ try: ++ f = dnfpluginscore.lib.urlopen(self, None, url, 'w+') ++ shutil.copy2(f.name, destname) ++ f.close() ++ except IOError as e: ++ logger.error(e) ++ continue ++ else: ++ # just url to repo, create .repo file on our own ++ repoid = sanitize_url_to_fs(url) ++ reponame = 'created by dnf config-manager from %s' % url ++ destname = os.path.join(myrepodir, "%s.repo" % repoid) ++ content = "[%s]\nname=%s\nbaseurl=%s\nenabled=1\n" % \ ++ (repoid, reponame, url) ++ if not save_to_file(destname, content): ++ continue ++ ++ ++def save_to_file(filename, content): ++ try: ++ with open(filename, 'w+') as fd: ++ dnf.pycomp.write_to_file(fd, content) ++ except (IOError, OSError) as e: ++ logger.error(_('Could not save repo to repofile %s: %s'), ++ filename, e) ++ return False ++ return True ++ ++# Regular expressions to sanitise cache filenames ++RE_SCHEME = re.compile(r'^\w+:/*(\w+:|www\.)?') ++RE_SLASH = re.compile(r'[?/:&#|]+') ++RE_BEGIN = re.compile(r'^[,.]*') ++RE_FINAL = re.compile(r'[,.]*$') ++ ++def sanitize_url_to_fs(url): ++ """Return a filename suitable for the filesystem ++ ++ Strips dangerous and common characters to create a filename we ++ can use to store the cache in. ++ """ ++ ++ try: ++ if RE_SCHEME.match(url): ++ if dnf.pycomp.PY3: ++ url = url.encode('idna').decode('utf-8') ++ else: ++ if isinstance(url, str): ++ url = url.decode('utf-8').encode('idna') ++ else: ++ url = url.encode('idna') ++ if isinstance(url, unicode): ++ url = url.encode('utf-8') ++ except (UnicodeDecodeError, UnicodeEncodeError, UnicodeError, TypeError): ++ pass ++ url = RE_SCHEME.sub("", url) ++ url = RE_SLASH.sub("_", url) ++ url = RE_BEGIN.sub("", url) ++ url = RE_FINAL.sub("", url) ++ ++ # limit length of url ++ if len(url) > 250: ++ parts = url[:185].split('_') ++ lastindex = 185-len(parts[-1]) ++ csum = dnf.yum.misc.Checksums(['sha256']) ++ csum.update(url[lastindex:]) ++ url = url[:lastindex] + '_' + csum.hexdigest() ++ ++ return url +diff --git a/plugins/copr.py b/plugins/copr.py +index 3a91ce6..8295855 100644 +--- a/plugins/copr.py ++++ b/plugins/copr.py +@@ -1,6 +1,6 @@ + # supplies the 'copr' command. + # +-# Copyright (C) 2014 Red Hat, Inc. ++# Copyright (C) 2014-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 +@@ -20,6 +20,7 @@ + from __future__ import print_function + from dnfpluginscore import _, logger + from dnf.i18n import ucd ++import dnfpluginscore.lib + + import dnf + import glob +@@ -30,9 +31,14 @@ import requests + import urllib + + +-yes = set([_('yes'), _('y')]) +-no = set([_('no'), _('n'), '']) ++YES = set([_('yes'), _('y')]) ++NO = set([_('no'), _('n'), '']) + ++# compatibility with Py2 and Py3 - rename raw_input() to input() on Py2 ++try: ++ input = raw_input ++except NameError: ++ pass + + class Copr(dnf.Plugin): + """DNF plugin supplying the 'copr' command.""" +@@ -118,8 +124,7 @@ Do you want to continue? [y/N]: """) + #http://copr.fedoraproject.org/api/coprs/ignatenkobrain/ + api_path = "/api/coprs/{}/".format(project_name) + +- opener = urllib.FancyURLopener({}) +- res = opener.open(self.copr_url + api_path) ++ res = dnfpluginscore.lib.urlopen(self, None, self.copr_url + api_path, 'w+') + try: + json_parse = json.loads(res.read()) + except ValueError: +@@ -132,7 +137,7 @@ Do you want to continue? [y/N]: """) + i = 0 + while i < len(json_parse["repos"]): + msg = "{0}/{1} : ".format(project_name, +- json_parse["repos"][i]["name"]) ++ json_parse["repos"][i]["name"]) + desc = json_parse["repos"][i]["description"] + if not desc: + desc = _("No description given") +@@ -143,18 +148,19 @@ Do you want to continue? [y/N]: """) + #http://copr.fedoraproject.org/api/coprs/search/tests/ + api_path = "/api/coprs/search/{}/".format(project_name) + +- opener = urllib.FancyURLopener({}) +- res = opener.open(self.copr_url + api_path) ++ res = dnfpluginscore.lib.urlopen(self, None, self.copr_url + api_path, 'w+') + try: + json_parse = json.loads(res.read()) + except ValueError: +- raise dnf.exceptions.Error(_("Can't parse search for '{}'.").format(project_name)) ++ raise dnf.exceptions.Error(_("Can't parse search for '{}'." ++ ).format(project_name)) + self._check_json_output(json_parse) + section_text = _("Matched: {}").format(project_name) + self._print_match_section(section_text) + i = 0 + while i < len(json_parse["repos"]): +- msg = "{0}/{1} : ".format(json_parse["repos"][i]["username"], json_parse["repos"][i]["coprname"]) ++ 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.") +@@ -175,12 +181,12 @@ Do you want to continue? [y/N]: """) + elif self.base.conf.assumeno and not self.base.conf.assumeyes: + raise dnf.exceptions.Error(_('Safe and good answer. Exiting.')) + +- answer = raw_input(question).lower() ++ answer = input(question).lower() + answer = _(answer) +- while not ((answer in yes) or (answer in no)): +- answer = raw_input(question).lower() ++ while not ((answer in YES) or (answer in NO)): ++ answer = input(question).lower() + answer = _(answer) +- if answer in yes: ++ if answer in YES: + return + else: + raise dnf.exceptions.Error(_('Safe and good answer. Exiting.')) +@@ -256,9 +262,9 @@ Do you want to continue? [y/N]: """) + return output + + @classmethod +- def _check_json_output(cls, json): +- if json["output"] != "ok": +- raise dnf.exceptions.Error("{}".format(json["error"])) ++ def _check_json_output(cls, json_obj): ++ if json_obj["output"] != "ok": ++ raise dnf.exceptions.Error("{}".format(json_obj["error"])) + + + class Playground(dnf.Plugin): +@@ -294,7 +300,7 @@ Do you want to continue? [y/N]: """) + raise dnf.cli.CliError(_("Unknown response from server.")) + for repo in output["repos"]: + project_name = "{0}/{1}".format(repo["username"], +- repo["coprname"]) ++ repo["coprname"]) + repo_filename = "/etc/yum.repos.d/_playground_{}.repo" \ + .format(project_name.replace("/", "-")) + try: +@@ -304,7 +310,8 @@ Do you want to continue? [y/N]: """) + self.copr_url, project_name, chroot) + req = requests.get(api_url) + output2 = self._get_data(req) +- if output2 and ("output" in output2) and (output2["output"] == "ok"): ++ if (output2 and ("output" in output2) ++ and (output2["output"] == "ok")): + self._download_repo(project_name, repo_filename, chroot) + except dnf.exceptions.Error: + # likely 404 and that repo does not exist +diff --git a/plugins/debuginfo-install.py b/plugins/debuginfo-install.py +index 194b24c..4783ed2 100644 +--- a/plugins/debuginfo-install.py ++++ b/plugins/debuginfo-install.py +@@ -23,6 +23,7 @@ from dnfpluginscore import _, logger + + import dnf + import dnf.cli ++import dnf.subject + + + class DebuginfoInstall(dnf.Plugin): +@@ -44,8 +45,8 @@ class DebuginfoInstallCommand(dnf.cli.Command): + summary = _('install debuginfo packages') + usage = "[PACKAGE...]" + +- done = [] +- rejected = [] ++ srcdone = [] ++ reqdone = [] + packages = None + packages_available = None + packages_installed = None +@@ -62,12 +63,11 @@ class DebuginfoInstallCommand(dnf.cli.Command): + self.packages = self.base.sack.query() + self.packages_available = self.packages.available() + self.packages_installed = self.packages.installed() +- for pkg in args: +- pkgs = self.packages_installed.filter(name=pkg) +- if not pkgs: +- pkgs = self.packages_available.filter(name=pkg) +- for pkg in pkgs: +- self._di_install(pkg, None) ++ ++ for pkgspec in args: ++ for pkg in dnf.subject.Subject(pkgspec).get_best_query( ++ self.cli.base.sack): ++ self._di_install(pkg) + + @staticmethod + def _pkgname_src(package): +@@ -84,86 +84,53 @@ class DebuginfoInstallCommand(dnf.cli.Command): + assert "-debuginfo" not in srcname + return "{}-debuginfo".format(srcname) + +- def _is_available(self, package, match_evra): ++ def _dbg_available(self, package, match_evra): + dbgname = self._pkgname_dbg(package) + if match_evra: +- avail = self.packages_available.filter( ++ return self.packages_available.filter( + name="{}".format(dbgname), + epoch=int(package.epoch), + version=str(package.version), + release=str(package.release), + arch=str(package.arch)) + else: +- avail = self.packages_available.filter( ++ return self.packages_available.filter( + name="{}".format(dbgname), + arch=str(package.arch)) +- if len(avail) != 0: +- srcname = self._pkgname_src(package) +- if match_evra: +- return self.packages_available.filter( +- name="{}".format(srcname), +- epoch=int(package.epoch), +- version=str(package.version), +- release=str(package.release), +- arch=str(package.arch)) +- else: +- return self.packages_available.filter( +- name="{}".format(srcname), +- arch=str(package.arch)) +- else: +- return False + +- def _di_install(self, package, require): ++ def _di_install(self, package): + srcname = self._pkgname_src(package) + dbgname = self._pkgname_dbg(package) +- if srcname in self.done \ +- or require in self.done \ +- or package in self.rejected: +- return +- if self._is_available(package, True): +- self.done.append(srcname) +- if require: +- self.done.append(require) +- di = "{0}-{1}:{2}-{3}.{4}".format( +- dbgname, +- package.epoch, +- package.version, +- package.release, +- package.arch) +- self.base.install(di) +- else: +- if self._is_available(package, False): ++ if not srcname in self.srcdone: ++ if self._dbg_available(package, True): ++ di = "{0}-{1}:{2}-{3}.{4}".format( ++ dbgname, ++ package.epoch, ++ package.version, ++ package.release, ++ package.arch) ++ self.base.install(di) ++ elif self._dbg_available(package, False): + di = "{0}.{1}".format(dbgname, package.arch) + self.base.install(di) +- self.done.append(srcname) +- if require: +- self.done.append(require) +- else: +- pass ++ self.srcdone.append(srcname) ++ ++ if package.name in self.reqdone: ++ return ++ self.reqdone.append(package.name) + for req in package.requires: + if str(req).startswith("rpmlib("): + continue +- elif str(req) in self.done: ++ elif str(req) in self.reqdone: + continue + elif str(req).find(".so") != -1: + provides = self.packages_available.filter(provides=req) + for p in provides: +- if str(p.name) in self.done or p in self.rejected: ++ if p.name in self.reqdone: + continue + pkgs = self.packages_installed.filter(name=p.name) +- if len(pkgs) != 0: +- pkgs_avail = self._is_available(pkgs[0], True) +- if not pkgs_avail: +- for x in pkgs: +- logger.debug( +-_("Can't find debuginfo package for: {0}-{1}:{2}-{3}.{4}").format( +- x.name, x.epoch, x.version, x.release, x.arch)) +- self.rejected.append(x) +- pkgs = [] +- else: +- pkgs = pkgs_avail +- for pkg in pkgs: +- self._di_install(pkg, str(req)) ++ for dep in pkgs: ++ self._di_install(dep) + + def _enable_debug_repos(self): + repos = {} +diff --git a/plugins/dnfpluginscore/lib.py b/plugins/dnfpluginscore/lib.py +new file mode 100644 +index 0000000..144d126 +--- /dev/null ++++ b/plugins/dnfpluginscore/lib.py +@@ -0,0 +1,121 @@ ++# ++# 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. ++# ++ ++from dnf.pycomp import PY3 ++ ++import dnf ++import iniparse ++import librepo ++import tempfile ++ ++ ++def current_value(plugin, repo, option): ++ """ ++ Returns current value of the option ++ (set in .repo or dnf.conf or on commandline). ++ """ ++ if (repo is not None and ++ hasattr(repo, option) and getattr(repo, option) is not None): ++ return getattr(repo, option) ++ conf = plugin.base.conf ++ if (hasattr(conf, option) and getattr(conf, option) is not None): ++ return getattr(conf, option) ++ return None ++ ++ ++def urlopen(plugin, repo, url, mode='w+b', **kwargs): ++ """ modified dnf.util.urlopen() which respects proxy setting ++ even for non-repo downloads ++ """ ++ conf = plugin.base.conf ++ ++ def non_repo_handle(): ++ handle = librepo.Handle() ++ handle.useragent = dnf.const.USER_AGENT ++ # see dnf.repo.Repo._handle_new_remote() how to pass ++ handle.maxspeed = conf.throttle if type(conf.throttle) is int \ ++ else int(conf.bandwidth * conf.throttle) ++ handle.proxy = conf.proxy ++ handle.proxyuserpwd = dnf.repo._user_pass_str(conf.proxy_username, ++ conf.proxy_password) ++ handle.sslverifypeer = handle.sslverifyhost = conf.sslverify ++ return handle ++ ++ if PY3 and 'b' not in mode: ++ kwargs.setdefault('encoding', 'utf-8') ++ fo = tempfile.NamedTemporaryFile(mode, **kwargs) ++ if repo: ++ handle = repo.get_handle() ++ else: ++ handle = non_repo_handle() ++ try: ++ librepo.download_url(url, fo.fileno(), handle) ++ except librepo.LibrepoException as e: ++ raise IOError(e.args[1]) ++ fo.seek(0) ++ return fo ++ ++ ++def write_raw_configfile(filename, section_id, substitutions, ++ cfgoptions, items, optionobj, ++ modify=None): ++ """ ++ Code adopted from yum-config-manager writeRawRepoFile(). ++ filename - name of config file (.conf or .repo) ++ section_id - id of modified section (e.g. main, fedora, updates) ++ substitutions - instance of base.conf.substitutions ++ cfgoptions - options parsed from conf file (e.g. base.conf.cfg.options) ++ items - current global or repo settings (e.g. base.conf.iteritems) ++ optionobj - option parse object (e.g. base.conf.optionobj) ++ modify - list of modified options ++ """ ++ ini = iniparse.INIConfig(open(filename)) ++ ++ osection_id = section_id ++ # b/c repoids can have $values in them we need to map both ways to figure ++ # out which one is which ++ if section_id not in ini: ++ for sect in ini: ++ if dnf.conf.parser.substitute(sect, substitutions) == section_id: ++ section_id = sect ++ ++ # Updated the ConfigParser with the changed values ++ cfgopts = cfgoptions(osection_id) ++ for name, value in items(): ++ if value is None: # Proxy ++ continue ++ ++ if modify is not None and name not in modify: ++ continue ++ ++ option = optionobj(name) ++ ovalue = option.tostring(value) ++ # If the value is the same, but just interpreted ... when we don't want ++ # to keep the interpreted values. ++ if (name in ini[section_id] and ++ ovalue == dnf.conf.parser.substitute(ini[section_id][name], ++ substitutions)): ++ ovalue = ini[section_id][name] ++ ++ if name not in cfgopts and option.default == value: ++ continue ++ ++ ini[section_id][name] = ovalue ++ fp = open(filename, "w") ++ fp.write(str(ini)) ++ fp.close() +diff --git a/plugins/download.py b/plugins/download.py +index cbb6e4e..7e8bf41 100644 +--- a/plugins/download.py ++++ b/plugins/download.py +@@ -1,6 +1,6 @@ + # download.py, supplies the 'download' command. + # +-# Copyright (C) 2013-2014 Red Hat, Inc. ++# Copyright (C) 2013-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 +@@ -27,7 +27,6 @@ import dnf.exceptions + import dnf.i18n + import dnf.subject + import dnfpluginscore +-import functools + import hawkey + import itertools + import os +@@ -39,6 +38,7 @@ class Download(dnf.Plugin): + name = 'download' + + def __init__(self, base, cli): ++ super(Download, self).__init__(base, cli) + self.base = base + self.cli = cli + if self.cli is not None: +@@ -51,6 +51,11 @@ class DownloadCommand(dnf.cli.Command): + summary = _('Download package to current directory') + usage = _('PACKAGE...') + ++ def __init__(self, cli): ++ super(DownloadCommand, self).__init__(cli) ++ self.opts = None ++ self.parser = None ++ + def configure(self, args): + # setup sack and populate it with enabled repos + demands = self.cli.demands +@@ -64,13 +69,15 @@ class DownloadCommand(dnf.cli.Command): + # You must only add options not used by dnf already + self.parser = dnfpluginscore.ArgumentParser(self.aliases[0]) + self.parser.add_argument('packages', nargs='+', +- help=_('packages to download')) ++ help=_('packages to download')) + self.parser.add_argument("--source", action='store_true', +- help=_('download the src.rpm instead')) +- self.parser.add_argument('--destdir', +- help=_('download path, default is current dir')) +- self.parser.add_argument('--resolve', action='store_true', +- help=_('resolve and download needed dependencies')) ++ help=_('download the src.rpm instead')) ++ self.parser.add_argument( ++ '--destdir', ++ help=_('download path, default is current dir')) ++ self.parser.add_argument( ++ '--resolve', action='store_true', ++ help=_('resolve and download needed dependencies')) + + # parse the options/args + # list available options/args on errors & exit +@@ -91,8 +98,7 @@ class DownloadCommand(dnf.cli.Command): + else: + dest = dnf.i18n.ucd(os.getcwd()) + +- move = functools.partial(self._move_package, dest) +- map(move, locations) ++ self._move_packages(dest, locations) + + def _download_rpms(self, pkg_specs): + """Download packages to dnf cache.""" +@@ -137,7 +143,8 @@ class DownloadCommand(dnf.cli.Command): + logger.debug(_('Error in resolve')) + return [] + +- def _get_source_packages(self, pkgs): ++ @staticmethod ++ def _get_source_packages(pkgs): + """Get list of source rpm names for a list of packages.""" + source_pkgs = set() + for pkg in pkgs: +@@ -145,31 +152,27 @@ class DownloadCommand(dnf.cli.Command): + source_pkgs.add(pkg.sourcerpm) + logger.debug(' --> Package : %s Source : %s', + str(pkg), pkg.sourcerpm) ++ elif pkg.arch == 'src': ++ source_pkgs.add("%s-%s.src.rpm" % (pkg.name, pkg.evr)) + else: +- logger.info(_("No source rpm definded for %s"), str(pkg)) ++ logger.info(_("No source rpm defined for %s"), str(pkg)) + return list(source_pkgs) + + def _enable_source_repos(self): + """Enable source repositories for enabled binary repositories. + +- binary repositories will be disabled and the dnf sack will be reloaded ++ Don't disable the binary ones because they can contain SRPMs as well ++ (this applies to COPR and to user-managed repos). ++ The dnf sack will be reloaded. + """ +- repo_dict = {} +- # find the source repos for the enabled binary repos ++ # enable the source repos + for repo in self.base.repos.iter_enabled(): +- source_repo = '%s-source' % repo.id +- if source_repo in self.base.repos: +- repo_dict[repo.id] = (repo, self.base.repos[source_repo]) +- else: +- repo_dict[repo.id] = (repo, None) +- # disable the binary & enable the source ones +- for id_ in repo_dict: +- repo, src_repo = repo_dict[id_] +- repo.disable() +- if src_repo: +- logger.info(_('enabled %s repository') % src_repo.id) +- src_repo.enable() +- # reload the sack ++ source_repo_id = '%s-source' % repo.id ++ if source_repo_id in self.base.repos: ++ source_repo = self.base.repos[source_repo_id] ++ logger.info(_('enabled %s repository'), source_repo.id) ++ source_repo.enable() ++ # reload the sack + self.base.fill_sack() + + def _get_query(self, pkg_spec): +@@ -191,8 +194,12 @@ class DownloadCommand(dnf.cli.Command): + release=nevra.release, arch=nevra.arch) + return q + +- def _move_package(self, target, location): ++ @staticmethod ++ def _move_packages(target, locations): + """Move the downloaded package to target.""" +- shutil.copy(location, target) +- os.unlink(location) ++ if not os.path.exists(target): ++ os.makedirs(target) ++ for pkg in locations: ++ shutil.copy(pkg, target) ++ os.unlink(pkg) + return target +diff --git a/plugins/generate_completion_cache.py b/plugins/generate_completion_cache.py +index 7fbb47a..b9df242 100644 +--- a/plugins/generate_completion_cache.py ++++ b/plugins/generate_completion_cache.py +@@ -2,6 +2,7 @@ + # generate_completion_cache.py - generate cache for dnf bash completion + # Copyright © 2013 Elad Alfassa + # Copyright (C) 2014 Igor Gnatenko ++# 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 +@@ -28,6 +29,7 @@ class BashCompletionCache(dnf.Plugin): + name = 'generate_completion_cache' + + def __init__(self, base, cli): ++ super(BashCompletionCache, self).__init__(base, cli) + self.base = base + self.cache_file = "/var/cache/dnf/packages.db" + +@@ -60,7 +62,7 @@ class BashCompletionCache(dnf.Plugin): + cur.execute("delete from available") + avail_pkgs = self.base.sack.query().available() + avail_pkgs_insert = [["{}.{}".format(x.name, x.arch)] +- for x in avail_pkgs if x.arch != "src"] ++ for x in avail_pkgs if x.arch != "src"] + cur.executemany("insert or ignore into available values (?)", + avail_pkgs_insert) + conn.commit() +@@ -80,7 +82,7 @@ class BashCompletionCache(dnf.Plugin): + cur.execute("delete from installed") + inst_pkgs = self.base.sack.query().installed() + inst_pkgs_insert = [["{}.{}".format(x.name, x.arch)] +- for x in inst_pkgs if x.arch != "src"] ++ for x in inst_pkgs if x.arch != "src"] + cur.executemany("insert or ignore into installed values (?)", + inst_pkgs_insert) + conn.commit() +diff --git a/plugins/ghost.py b/plugins/ghost.py +index 1cff03c..ac60780 100644 +--- a/plugins/ghost.py ++++ b/plugins/ghost.py +@@ -1,6 +1,6 @@ + # ghost.py, it's a show about nothing. + # +-# Copyright (C) 2013 Red Hat, Inc. ++# Copyright (C) 2013-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 +@@ -29,6 +29,7 @@ class Ghost(dnf.Plugin): + name = 'ghost' + + def __init__(self, base, cli): ++ super(Ghost, self).__init__(base, cli) + self.base = base + self.cli = cli + if cli is None: +@@ -36,7 +37,8 @@ class Ghost(dnf.Plugin): + else: + self._out('loaded (with CLI)') + +- def _out(self, msg): ++ @staticmethod ++ def _out(msg): + logger.debug('Ghost plugin: %s', msg) + + def config(self): +diff --git a/plugins/noroot.py b/plugins/noroot.py +index 014b226..f82b6a3 100644 +--- a/plugins/noroot.py ++++ b/plugins/noroot.py +@@ -1,6 +1,6 @@ + # noroot.py + # +-# Copyright (C) 2013 Red Hat, Inc. ++# Copyright (C) 2013-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 +@@ -19,7 +19,7 @@ + + from __future__ import absolute_import + from __future__ import unicode_literals +-from dnfpluginscore import logger, _ ++from dnfpluginscore import _ + + import dnf + import dnf.exceptions +@@ -33,6 +33,7 @@ class Noroot(dnf.Plugin): + name = 'noroot' + + def __init__(self, base, cli): ++ super(Noroot, self).__init__(base, cli) + self.base = base + self.cli = cli + +diff --git a/plugins/protected_packages.py b/plugins/protected_packages.py +index b202011..a241eae 100644 +--- a/plugins/protected_packages.py ++++ b/plugins/protected_packages.py +@@ -1,7 +1,7 @@ + # protected_packages.py + # Prevent package removals that could leave the system broken. + # +-# Copyright (C) 2014 Red Hat, Inc. ++# Copyright (C) 2014-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 +@@ -20,7 +20,7 @@ + + from __future__ import absolute_import + from __future__ import unicode_literals +-from dnfpluginscore import _, logger ++from dnfpluginscore import _ + + import dnf + import dnf.exceptions +diff --git a/plugins/repoquery.py b/plugins/repoquery.py +index c4ebccc..ddce24c 100644 +--- a/plugins/repoquery.py ++++ b/plugins/repoquery.py +@@ -24,6 +24,7 @@ from dnfpluginscore import _ + import dnf + import dnf.cli + import dnf.exceptions ++import dnf.subject + import dnfpluginscore + import functools + import hawkey +@@ -62,6 +63,8 @@ def build_format_fn(opts): + return info_format + elif opts.queryfilelist: + return filelist_format ++ elif opts.querysourcerpm: ++ return sourcerpm_format + else: + return rpm2py_format(opts.queryformat).format + +@@ -72,6 +75,9 @@ def info_format(pkg): + def filelist_format(pkg): + return "\n".join(pkg.files) + ++def sourcerpm_format(pkg): ++ return pkg.sourcerpm ++ + def parse_arguments(args): + # Setup ArgumentParser to handle util + parser = dnfpluginscore.ArgumentParser(RepoQueryCommand.aliases[0]) +@@ -81,6 +87,8 @@ def parse_arguments(args): + help=_('show only results from this REPO')) + parser.add_argument('--arch', metavar='ARCH', + help=_('show only results from this ARCH')) ++ parser.add_argument('-f', '--file', metavar='FILE', ++ help=_('show only results that owns FILE')) + parser.add_argument('--whatprovides', metavar='REQ', + help=_('show only results there provides REQ')) + parser.add_argument('--whatrequires', metavar='REQ', +@@ -96,6 +104,9 @@ def parse_arguments(args): + outform.add_argument('-l', "--list", dest='queryfilelist', + default=False, action='store_true', + help=_('show list of files in the package')) ++ outform.add_argument('-s', "--source", dest='querysourcerpm', ++ default=False, action='store_true', ++ help=_('show package source RPM name')) + outform.add_argument('--qf', "--queryformat", dest='queryformat', + default=QFORMAT_DEFAULT, + help=_('format for displaying found packages')) +@@ -193,17 +204,19 @@ class RepoQueryCommand(dnf.cli.Command): + print(QUERY_TAGS) + return + +- q = self.base.sack.query().available() + if opts.key: +- if set(opts.key) & set('*[?'): # is pattern ? +- fdict = {'name__glob': opts.key} +- else: # substring +- fdict = {'name': opts.key} +- q = q.filter(hawkey.ICASE, **fdict) ++ q = dnf.subject.Subject(opts.key, ignore_case=True).get_best_query( ++ self.base.sack, with_provides=False) ++ else: ++ q = self.base.sack.query() ++ # do not show packages from @System repo ++ q = q.available() + if opts.repoid: + q = q.filter(reponame=opts.repoid) + if opts.arch: + q = q.filter(arch=opts.arch) ++ if opts.file: ++ q = q.filter(file=opts.file) + if opts.whatprovides: + q = self.by_provides(self.base.sack, [opts.whatprovides], q) + if opts.whatrequires: +diff --git a/rel-eng/README b/rel-eng/README +new file mode 100644 +index 0000000..c103bdf +--- /dev/null ++++ b/rel-eng/README +@@ -0,0 +1,7 @@ ++Release instructions: ++ ++1. Tag: tito tag ++2. Test: tito build --rpm --offline ++3. Push: git push && git push $ORIGIN $TAG ++4. Release: tito release fedora-git ++ +diff --git a/rel-eng/packages/.readme b/rel-eng/packages/.readme +new file mode 100644 +index 0000000..8999c8d +--- /dev/null ++++ b/rel-eng/packages/.readme +@@ -0,0 +1,3 @@ ++the rel-eng/packages directory contains metadata files ++named after their packages. Each file has the latest tagged ++version and the project's relative directory. +diff --git a/rel-eng/packages/dnf-plugins-core b/rel-eng/packages/dnf-plugins-core +new file mode 100644 +index 0000000..d7b9e19 +--- /dev/null ++++ b/rel-eng/packages/dnf-plugins-core +@@ -0,0 +1 @@ ++0.1.5-2 ./ +diff --git a/rel-eng/releasers.conf b/rel-eng/releasers.conf +new file mode 100644 +index 0000000..ffeb709 +--- /dev/null ++++ b/rel-eng/releasers.conf +@@ -0,0 +1,3 @@ ++[fedora-git] ++releaser = tito.release.FedoraGitReleaser ++branches = f21 +diff --git a/rel-eng/tito.props b/rel-eng/tito.props +new file mode 100644 +index 0000000..c008eb3 +--- /dev/null ++++ b/rel-eng/tito.props +@@ -0,0 +1,5 @@ ++[buildconfig] ++builder = tito.builder.Builder ++tagger = tito.tagger.ReleaseTagger ++changelog_do_not_remove_cherrypick = 1 ++changelog_format = %s (%a) +diff --git a/scripts/lint b/scripts/lint +index 8b4f630..5423164 100755 +--- a/scripts/lint ++++ b/scripts/lint +@@ -21,8 +21,9 @@ disable "-d W0141" # used builtin 'map' function + disable "-d W0142" # used star magic + + VAR_NAMES=--variable-rgx='[a-z_][a-z0-9_]*$' ++DUMMY_NAMES='--dummy-variables-rgx=_.*' + MISC=--max-line-length=82 + +-pylint --rcfile=/dev/null --reports=n $DISABLED "$VAR_NAMES" $MISC $* \ ++pylint --rcfile=/dev/null --reports=n $DISABLED "$VAR_NAMES" "$DUMMY_NAMES" $MISC $* \ + "$TEMPLATE" \ + | egrep -v -f $FALSE_POSITIVES +diff --git a/tests/README b/tests/README +new file mode 100644 +index 0000000..5672629 +--- /dev/null ++++ b/tests/README +@@ -0,0 +1,8 @@ ++To run tests from the source tree, run this ++(working directory = root of the source tree): ++ ++export PYTHONPATH=./plugins ++nosetests tests/ ++ ++You can run tests under specific Python version using nosetests-2.7 ++or nosetests-3.4. +diff --git a/tests/test_config_manager.py b/tests/test_config_manager.py +new file mode 100644 +index 0000000..64c581d +--- /dev/null ++++ b/tests/test_config_manager.py +@@ -0,0 +1,121 @@ ++# 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. ++# ++ ++from __future__ import absolute_import ++from __future__ import unicode_literals ++from tests.support import mock, RepoStub ++ ++import config_manager ++import dnf ++import filecmp ++import iniparse ++import os ++import shutil ++import tempfile ++import unittest ++ ++ ++REPOLABEL = "testrepo" ++REPOCONTENT = """[testrepo] ++name=TestRepo ++baseurl=file:///tmp ++enabled=1 ++""" ++ ++class ConfigManagerBase(mock.MagicMock): ++ conf = dnf.conf.Conf() ++ ++class ConfigManagerCommandTest(unittest.TestCase): ++ ++ def setUp(self): ++ cli = dnf.cli.cli.Cli(ConfigManagerBase()) ++ self.cmd = config_manager.ConfigManagerCommand(cli) ++ self.cmd.base.conf.reposdir = [tempfile.mkdtemp()] ++ ++ self.addCleanup(shutil.rmtree, self.cmd.base.conf.reposdir[0]) ++ ++ def test_add_from_repofile(self): ++ tempfile_kwargs = {'mode': 'w', 'suffix': '.repo', 'delete': False} ++ if dnf.pycomp.PY3: ++ tempfile_kwargs['encoding'] = 'utf8' ++ ++ repofile = tempfile.NamedTemporaryFile(**tempfile_kwargs) ++ dnf.pycomp.write_to_file(repofile, REPOCONTENT) ++ repofile.close() ++ ++ args = ['--add-repo', repofile.name] ++ self.cmd.configure(args) ++ self.cmd.run(args) ++ ++ installed_repofile = os.path.join(self.cmd.base.conf.reposdir[0], ++ os.path.basename(repofile.name)) ++ with open(installed_repofile) as f: ++ added = f.read() ++ ++ self.assertMultiLineEqual(REPOCONTENT, added) ++ ++ def get_matching(x): ++ repo = dnf.repo.Repo(x, '/tmp') ++ repo.repofile = installed_repofile ++ repo.cfg = iniparse.compat.RawConfigParser() ++ repo.cfg.read(installed_repofile) ++ return [repo] ++ self.cmd.base.repos.get_matching = get_matching ++ self.cmd.base.output = dnf.cli.output.Output(self.cmd.base, self.cmd.base.conf) ++ ++ self.subtest_disable(REPOLABEL, installed_repofile) ++ self.subtest_enable(REPOLABEL, installed_repofile) ++ ++ os.unlink(repofile.name) ++ ++ def test_add_from_repourl(self): ++ long_url = 'file:///tmp/%s' % ('/'.join([str(x) for x in range(1,100)])) ++ name = 'tmp_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21' \ ++ + '_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39' \ ++ + '_40_41_42_43_44_45_46_47_48_49_50_51_52_53_54_55_56_57' \ ++ + '_58_59_60_61_62_63__b3085fd1c13941e151ce4afe9d8670774d' \ ++ + 'c8e19395f2a785bc1d210eccc0869b' ++ repofile = name + '.repo' ++ ++ repocontent = "[%s]\nname=created by dnf config-manager from %s\n" \ ++ "baseurl=%s\nenabled=1\n" % (name, long_url, long_url) ++ args = ['--add-repo', long_url] ++ self.cmd.configure(args) ++ self.cmd.run(args) ++ with open(os.path.join(self.cmd.base.conf.reposdir[0], repofile)) as f: ++ added = f.read() ++ ++ self.assertMultiLineEqual(repocontent, added) ++ ++ def subtest_disable(self, label, fname): ++ args = ['--set-disabled', label] ++ self.cmd.configure(args) ++ self.cmd.run(args) ++ ++ with open(fname) as f: ++ added = f.read() ++ disabled = REPOCONTENT.replace("enabled=1", "enabled=0") ++ self.assertMultiLineEqual(disabled, added) ++ ++ def subtest_enable(self, label, fname): ++ args = ['--set-enabled', label] ++ self.cmd.configure(args) ++ self.cmd.run(args) ++ ++ with open(fname) as f: ++ added = f.read() ++ self.assertMultiLineEqual(REPOCONTENT, added) +diff --git a/tests/test_download.py b/tests/test_download.py +index 4158171..7bee1b6 100644 +--- a/tests/test_download.py ++++ b/tests/test_download.py +@@ -170,8 +170,8 @@ class DownloadlCommandTest(unittest.TestCase): + self.assertFalse(repos['foobar-source'].enabled) + self.cmd._enable_source_repos() + self.assertTrue(repos['foo-source'].enabled) +- self.assertFalse(repos['foo'].enabled) +- self.assertFalse(repos['bar'].enabled) ++ self.assertTrue(repos['foo'].enabled) ++ self.assertTrue(repos['bar'].enabled) + self.assertFalse(repos['foobar-source'].enabled) + + def test_get_source_packages(self): +diff --git a/tests/test_repoquery.py b/tests/test_repoquery.py +index 771a583..bf32857 100644 +--- a/tests/test_repoquery.py ++++ b/tests/test_repoquery.py +@@ -46,6 +46,8 @@ EXPECTED_FILELIST_FORMAT = """\ + /var/foobar\ + """ + ++EXPECTED_SOURCERPM_FORMAT = """\ ++foo-1.0.1-1.f20.src.rpm""" + + class PkgStub(object): + def __init__(self): +@@ -81,6 +83,9 @@ class ArgParseTest(unittest.TestCase): + opts, _ = repoquery.parse_arguments(['--provides']) + self.assertEqual(opts.queryformat, '%{provides}') + ++ def test_file(self): ++ opts, _ = repoquery.parse_arguments(['/var/foobar']) ++ self.assertIsNone(opts.file) + + class InfoFormatTest(unittest.TestCase): + def test_info(self): +@@ -94,6 +99,11 @@ class FilelistFormatTest(unittest.TestCase): + self.assertEqual(repoquery.filelist_format(pkg), + EXPECTED_FILELIST_FORMAT) + ++class SourceRPMFormatTest(unittest.TestCase): ++ def test_info(self): ++ pkg = repoquery.PackageWrapper(PkgStub()) ++ self.assertEqual(repoquery.sourcerpm_format(pkg), ++ EXPECTED_SOURCERPM_FORMAT) + + class OutputTest(unittest.TestCase): + def test_output(self): diff --git a/dnf-plugins-core.spec b/dnf-plugins-core.spec index 6e40e07..69ae81a 100644 --- a/dnf-plugins-core.spec +++ b/dnf-plugins-core.spec @@ -1,32 +1,32 @@ -%{!?gitrev: %global gitrev 351e094} -%{?!dnf_version: %global dnf_version 0.6.3} +%{?!dnf_version: %global dnf_version 0.6.4} Name: dnf-plugins-core Version: 0.1.5 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Core Plugins for DNF Group: System Environment/Base License: GPLv2+ URL: https://github.com/rpm-software-management/dnf-plugins-core # source archive is created by running package/archive from a git checkout -Source0: dnf-plugins-core-%{gitrev}.tar.xz +Source0: dnf-plugins-core-%{version}.tar.gz +Patch0: dnf-plugins-core-0.1.5-1-to-dnf-plugins-core-0.1.5-2.patch BuildArch: noarch BuildRequires: cmake -BuildRequires: dnf >= %{dnf_version} +BuildRequires: dnf = %{dnf_version} BuildRequires: gettext BuildRequires: pykickstart BuildRequires: python-nose BuildRequires: python-sphinx BuildRequires: python2-devel -Requires: dnf >= %{dnf_version} +Requires: dnf = %{dnf_version} Requires: pykickstart Requires: python-requests %description -Core Plugins for DNF. This package enhance DNF with builddep, copr, -debuginfo-install, download, kickstart, needs-restarting, repoquery and +Core Plugins for DNF. This package enhance DNF with builddep, config-manager, +copr, debuginfo-install, download, kickstart, needs-restarting, repoquery and reposync commands. Additionally provides generate_completion_cache, noroot and protected_packages passive plugins. @@ -34,19 +34,20 @@ protected_packages passive plugins. Summary: Core Plugins for DNF Group: System Environment/Base BuildRequires: python3-devel -BuildRequires: python3-dnf >= %{dnf_version} +BuildRequires: python3-dnf = %{dnf_version} BuildRequires: python3-nose BuildRequires: python3-sphinx -Requires: python3-dnf >= %{dnf_version} +Requires: python3-dnf = %{dnf_version} %description -n python3-dnf-plugins-core -Core Plugins for DNF, Python 3 version. This package enhance DNF with builddep, copr, -debuginfo-install, download, kickstart, needs-restarting, repoquery and -reposync commands. Additionally provides generate_completion_cache, noroot and -protected_packages passive plugins. +Core Plugins for DNF, Python 3 version. This package enhance DNF with builddep, +config-manager, copr, debuginfo-install, download, kickstart, needs-restarting, +repoquery and reposync commands. Additionally provides generate_completion_cache, +noroot and protected_packages passive plugins. %prep -%setup -q -n dnf-plugins-core +%setup -q -n dnf-plugins-core-%{version} +%patch0 -p1 rm -rf py3 mkdir ../py3 cp -a . ../py3/ @@ -92,6 +93,47 @@ PYTHONPATH=./plugins /usr/bin/nosetests-3.* -s tests/ %{_mandir}/man8/dnf.plugin.* %changelog +* Mon Apr 13 2015 Michal Luscon 0.1.5-2 +- prepare repo for tito build system (Michal Luscon) +- migrate raw_input() to Python3 (RhBug:1208399) (Miroslav Suchý) +- 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) +- debuginfo-install: support cases where src.rpm name != binary package name (Petr Spacek) +- 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) +- cosmetic: download: pylint fixes (Jan Silhan) +- download: Do not disable user-enabled repos (thanks Spacekpe) (Jan Silhan) +- let pylint ignore unused variables starting with _ (Michael Mraka) +- updated copyright (Michael Mraka) +- fixed pylint warning Redefining name from outer scope (Michael Mraka) +- fixed pylint warning Invalid constant name (Michael Mraka) +- fixed pylint warnings Line too long (Michael Mraka) +- pylint fix for Wrong continued indentation (Michael Mraka) +- updated copyright (Michael Mraka) +- pylint fix for Specify string format arguments as logging function parameters (Michael Mraka) +- pylint fix for Method could be a function (Michael Mraka) +- pylint fix for __init__ method from base class is not called (Michael Mraka) +- pylint fix for Attribute defined outside __init__ (Michael Mraka) +- updated copyright (Michael Mraka) +- pylint fix for __init__ method from base class is not called (Michael Mraka) +- pylint fix for Wrong continued indentation (Michael Mraka) +- updated copyright (Michael Mraka) +- pylint fix for Method could be a function (Michael Mraka) +- pylint fix for __init__ method from base class is not called (Michael Mraka) +- updated copyright (Michael Mraka) +- pylint fix for Unused import (Michael Mraka) +- pylint fix for __init__ method from base class is not called (Michael Mraka) +- updated copyright (Michael Mraka) +- pylint fix for Unused import (Michael Mraka) +- Add README to tests/ directory (Petr Spacek) +- AUTHORS: updated (Jan Silhan) +- download: fix package download on Python 3 (Petr Spacek) * Thu Feb 5 2015 Jan Silhan - 0.1.5-1 - updated package url (Michael Mraka) @@ -287,4 +329,3 @@ PYTHONPATH=./plugins /usr/bin/nosetests-3.* -s tests/ * Fri Dec 20 2013 Aleš Kozumplík - 0.0.1-1 - The initial package version. - diff --git a/sources b/sources index 4e7f7e7..b13fb9a 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -0259d83520542c14ef2eb9476c740421 dnf-plugins-core-351e094.tar.xz +16c3091fbb1958744b3eba0aa66f4c3f ./dnf-plugins-core-0.1.5.tar.gz