[yum-commits] 2 commits - plugins/copr yum-utils.spec

James Antill james at osuosl.org
Tue Sep 23 06:12:14 UTC 2014


 plugins/copr/copr.conf |    2 
 plugins/copr/copr.py   |  327 +++++++++++++++++++++++++++++++++++++++++++++++++
 yum-utils.spec         |   16 ++
 3 files changed, 345 insertions(+)

New commits:
commit 012cfc643fd09275bc8932d15a3fcd9a1a17c107
Author: James Antill <james at and.org>
Date:   Tue Sep 23 02:12:01 2014 -0400

    Add copr plugin to specfile.

diff --git a/yum-utils.spec b/yum-utils.spec
index ff56353..904b032 100644
--- a/yum-utils.spec
+++ b/yum-utils.spec
@@ -363,6 +363,15 @@ Requires: puppet
 %description -n yum-plugin-puppetverify
 Supplies checksums for files in packages from puppet's state file. 
 
+%package -n yum-plugin-copr
+Summary: Yum plugin to add copr command
+Group: System Environment/Base
+Provides: yum-copr = %{version}-%{release}
+Requires: yum >= 3.4.3
+
+%description -n yum-plugin-copr
+This plugin adds the command copr, for adding/listing/searching copr repos.
+
 %prep
 %setup -q
 
@@ -398,6 +407,7 @@ plugins="\
  fs-snapshot \
  ps \
  puppetverify \
+ copr \
 "
 
 %if %{package_yum_updatesd}
@@ -666,6 +676,12 @@ fi
 %config(noreplace) %{_sysconfdir}/yum/pluginconf.d/puppetverify.conf
 %{pluginhome}/puppetverify.*
 
+%files -n yum-plugin-copr
+%defattr(-, root, root)
+%doc COPYING
+%config(noreplace) %{_sysconfdir}/yum/pluginconf.d/copr.conf
+%{pluginhome}/copr.*
+
 %changelog
 * Thu Aug 10 2011 Tim Lauridsen <timlau at fedoraproject.org> 
 - mark as 1.1.31
commit 07cdd8fdb7f3399bec0adc1b3caedf73bcaf5a2e
Author: James Antill <james at and.org>
Date:   Tue Sep 23 01:56:57 2014 -0400

    Initial port of DNF copr plugin to yum API.

diff --git a/plugins/copr/copr.conf b/plugins/copr/copr.conf
new file mode 100644
index 0000000..8e4d76c
--- /dev/null
+++ b/plugins/copr/copr.conf
@@ -0,0 +1,2 @@
+[main]
+enabled=1
diff --git a/plugins/copr/copr.py b/plugins/copr/copr.py
new file mode 100644
index 0000000..6d922ce
--- /dev/null
+++ b/plugins/copr/copr.py
@@ -0,0 +1,327 @@
+# supplies the 'copr' command.
+#
+# Copyright (C) 2014  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.
+#
+
+"""YUM plugin supplying the 'copr' command."""
+
+from urlgrabber import grabber
+
+import yum
+import glob
+import json
+import os
+import platform
+import requests
+import urllib
+
+from yum.i18n import _
+from yum.plugins import TYPE_CORE
+
+requires_api_version = '2.5'
+plugin_type = TYPE_CORE
+
+yes = set([_('yes'), _('y')])
+no = set([_('no'), _('n'), ''])
+
+YError = yum.Errors.YumBaseError
+YCliError = yum.Errors.MiscError
+
+def config_hook(conduit):
+    conduit.registerCommand(CoprCommand())
+    conduit.registerCommand(PlaygroundCommand())
+
+class CoprCommand:
+    """ Copr plugin for DNF """
+
+    def getNames(self):
+        return [self.aliases[0]]
+
+    def getUsage(self):
+        return self.usage
+
+    def getSummary(self):
+        return self.summary[1:]
+
+    def doCheck(self, base, basecmd, extcmds):
+        self.base = base
+
+    copr_url = "https://copr.fedoraproject.org"
+    aliases = ("copr",)
+    summary = _("Interact with Copr repositories.")
+    usage = _("""
+  enable name/project [chroot]
+  disable name/project
+  list name
+  search project
+
+  Examples:
+  copr enable rhscl/perl516 epel-6-x86_64
+  copr enable ignatenkobrain/ocltoys
+  copr disable rhscl/perl516
+  copr list ignatenkobrain
+  copr search tests
+    """)
+
+    def doCommand(self, base, basecmd, extcmds):
+        try:
+            subcommand = extcmds[0]
+            project_name = extcmds[1]
+        except (ValueError, IndexError):
+            base.logger.critical(
+                _('Error: ') +
+                _('exactly two additional parameters to '
+                  'copr command are required'))
+            # FIXME
+            # dnf.cli.commands.err_mini_usage(self.cli, self.cli.base.basecmd)
+            raise YCliError(
+                _('exactly two additional parameters to '
+                  'copr command are required'))
+        try:
+            chroot = extcmds[2]
+        except IndexError:
+            chroot = self._guess_chroot()
+        repo_filename = "/etc/yum.repos.d/_copr_{}.repo" \
+                        .format(project_name.replace("/", "-"))
+        if subcommand == "enable":
+            self._need_root()
+            self._ask_user("""
+You are about to enable a Copr repository. Please note that this
+repository is not part of the main Fedora distribution, and quality
+may vary.
+
+The Fedora Project does not exercise any power over the contents of
+this repository beyond the rules outlined in the Copr FAQ at
+<https://fedorahosted.org/copr/wiki/UserDocs#WhatIcanbuildinCopr>, and
+packages are not held to any quality or securty level.
+
+Please do not file bug reports about these packages in Fedora
+Bugzilla. In case of problems, contact the owner of this repository.
+
+Do you want to continue? [y/N]: """)
+            self._download_repo(project_name, repo_filename, chroot)
+            base.logger.info(_("Repository successfully enabled."))
+        elif subcommand == "disable":
+            self._need_root()
+            self._remove_repo(repo_filename)
+            base.logger.info(_("Repository successfully disabled."))
+        elif subcommand == "list":
+            #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)
+            try:
+                json_parse = json.loads(res.read())
+            except ValueError:
+                raise YError(
+                    _("Can't parse repositories for username '{}'.")
+                    .format(project_name))
+            section_text = _("List of {} coprs").format(project_name)
+            self._print_match_section(section_text)
+            i = 0
+            while i < len(json_parse["repos"]):
+                msg = "{0}/{1} : ".format(project_name,
+                      json_parse["repos"][i]["name"])
+                desc = json_parse["repos"][i]["description"]
+                if not desc:
+                    desc = _("No description given")
+                msg = self.base.fmtKeyValFill(unicode(msg), desc)
+                print(msg)
+                i += 1
+        elif subcommand == "search":
+            #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)
+            try:
+                json_parse = json.loads(res.read())
+            except ValueError:
+                raise YError(_("Can't parse search for '{}'.").format(project_name))
+            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"])
+                desc = json_parse["repos"][i]["description"]
+                if not desc:
+                    desc = _("No description given.")
+                msg = self.base.fmtKeyValFill(unicode(msg), desc)
+                print(msg)
+                i += 1
+        else:
+            raise YError(
+                _('Unknown subcommand {}.').format(subcommand))
+
+        return 0, [basecmd + ' done']
+
+    def _print_match_section(self, text):
+        formatted = self.base.fmtSection(text)
+        print(formatted)
+
+    def _ask_user(self, question):
+        if self.base.conf.assumeyes and not self.base.conf.assumeno:
+            return
+        elif self.base.conf.assumeno and not self.base.conf.assumeyes:
+            raise YError(_('Safe and good answer. Exiting.'))
+
+        answer = raw_input(question).lower()
+        answer = _(answer)
+        while not ((answer in yes) or (answer in no)):
+            answer = raw_input(question).lower()
+            answer = _(answer)
+        if answer in yes:
+            return
+        else:
+            raise YError(_('Safe and good answer. Exiting.'))
+
+    @classmethod
+    def _need_root(cls):
+        # FIXME this should do dnf itself (BZ#1062889)
+        if os.geteuid() != 0:
+            raise YError(
+                _('This command has to be run under the root user.'))
+
+    @classmethod
+    def _guess_chroot(cls):
+        """ Guess which choot is equivalent to this machine """
+        # FIXME Copr should generate non-specific arch repo
+        dist = platform.linux_distribution()
+        if "Fedora" in dist:
+            # x86_64 because repo-file is same for all arch
+            # ($basearch is used)
+            if "Rawhide" in dist:
+                chroot = ("fedora-rawhide-x86_64")
+            else:
+                chroot = ("fedora-{}-x86_64".format(dist[1]))
+        else:
+            chroot = ("epel-%s-x86_64" % dist[1].split(".", 1)[0])
+        return chroot
+
+    @classmethod
+    def _download_repo(cls, project_name, repo_filename, chroot=None):
+        if chroot is None:
+            chroot = cls._guess_chroot()
+        #http://copr.fedoraproject.org/coprs/larsks/rcm/repo/epel-7-x86_64/
+        api_path = "/coprs/{0}/repo/{1}/".format(project_name, chroot)
+        ug = grabber.URLGrabber()
+        # FIXME when we are full on python2 urllib.parse
+        try:
+            ug.urlgrab(cls.copr_url + api_path, filename=repo_filename)
+        except grabber.URLGrabError as e:
+            cls._remove_repo(repo_filename)
+            raise YError(str(e))
+
+    @classmethod
+    def _remove_repo(cls, repo_filename):
+        # FIXME is it Copr repo ?
+        try:
+            os.remove(repo_filename)
+        except OSError as e:
+            raise YError(str(e))
+
+    @classmethod
+    def _get_data(cls, req):
+        """ Wrapper around response from server
+
+        check data and print nice error in case of some error (and return None)
+        otherwise return json object.
+        """
+        try:
+            output = json.loads(req.text)
+        except ValueError:
+            YCliError(_("Unknown response from server."))
+            return
+        if req.status_code != 200:
+            YCliError(_(
+                "Something went wrong:\n {0}\n".format(output["error"])))
+            return
+        return output
+
+
+class PlaygroundCommand(CoprCommand):
+    """ Playground plugin for DNF """
+
+    aliases = ("playground",)
+    summary = _("Interact with Playground repository.")
+    usage = " [enable|disable|upgrade]"
+
+    def _cmd_enable(self, chroot):
+        self._need_root()
+        self._ask_user("""
+You are about to enable a Playground repository.
+
+Do you want to continue? [y/N]: """)
+        api_url = "{0}/api/playground/list/".format(
+            self.copr_url)
+        req = requests.get(api_url)
+        output = self._get_data(req)
+        if output["output"] != "ok":
+            raise YCliError(_("Unknown response from server."))
+        for repo in output["repos"]:
+            project_name = "{0}/{1}".format(repo["username"],
+                repo["coprname"])
+            repo_filename = "/etc/yum.repos.d/_playground_{}.repo" \
+                    .format(project_name.replace("/", "-"))
+            try:
+                # check if that repo exist? but that will result in twice
+                # up calls
+                api_url = "{0}/api/coprs/{1}/detail/{2}/".format(
+                    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"):
+                    self._download_repo(project_name, repo_filename, chroot)
+            except YError:
+                # likely 404 and that repo does not exist
+                pass
+
+    def _cmd_disable(self):
+        self._need_root()
+        for repo_filename in glob.glob('/etc/yum.repos.d/_playground_*.repo'):
+            self._remove_repo(repo_filename)
+
+    def doCommand(self, base, basecmd, extcmds):
+        try:
+            subcommand = extcmds[0]
+        except (ValueError, IndexError):
+            base.logger.critical(
+                _('Error: ') +
+                _('exactly one parameter to '
+                  'playground command are required'))
+            # FIXME:
+            # dnf.cli.commands.err_mini_usage(self.cli, self.cli.base.basecmd)
+            raise YCliError(
+                _('exactly one parameter to '
+                  'playground command are required'))
+        chroot = self._guess_chroot()
+        if subcommand == "enable":
+            self._cmd_enable(chroot)
+            base.logger.info(_("Playground repositories successfully enabled."))
+        elif subcommand == "disable":
+            self._cmd_disable()
+            base.logger.info(_("Playground repositories successfully disabled."))
+        elif subcommand == "upgrade":
+            self._cmd_disable()
+            self._cmd_enable(chroot)
+            base.logger.info(_("Playground repositories successfully updated."))
+        else:
+            raise YError(
+                _('Unknown subcommand {}.').format(subcommand))
+
+        return 0, [basecmd + ' done']


More information about the Yum-commits mailing list