From 4e5b4a39c432395b62470176c84b96db44b8d34f Mon Sep 17 00:00:00 2001 From: Izhar Firdaus Date: Mon, 23 Jun 2008 22:49:54 +0800 Subject: - cleanup at chitin package - created yum-plugin folder --- chitin/parser.py | 237 ++------------------------------------- chitin/utils.py | 74 ++++++++++++ yum-plugin/chitin.py | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 397 insertions(+), 225 deletions(-) create mode 100644 chitin/utils.py create mode 100644 yum-plugin/chitin.py diff --git a/chitin/parser.py b/chitin/parser.py index 27e79cd..006d3a5 100644 --- a/chitin/parser.py +++ b/chitin/parser.py @@ -14,143 +14,40 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -# Copyright Red Hat Inc. 2007, 2008 -# -# Author: Izhar Firdaus -# Examples: -# -# yum oci-install oneclickinstall-XML-metadata-file -# yum oci-query details oneclickinstall-XML-metadata-file -# yum oci-query repositories oneclickinstall-XML-metadata-file -# yum oci-query packages oneclickinstall-XML-metadata-file # +# Parser library for One Click Install metadata XML +# +# @author Izhar Firdaus from xml.etree.ElementTree import ElementTree,Element -import re - -from yum.plugins import PluginYumExit,TYPE_CORE,TYPE_INTERACTIVE -from yum import logginglevels -import yum.i18n, tempfile -_ = yum.i18n._ +import re, tempfile +from chitin.utils import attrsfilter,get_child_value ocins='http://opensuse.org/Standards/One_Click_Install' -#distro='fedora' -#release='9' - -## Use this for now -distro='openSUSE' -release='Factory' - - -requires_api_version = '2.5' -plugin_type = (TYPE_INTERACTIVE,) - - -def attrsfilter(elements,keywords,operation='or'): - """ - Function to filter elements by its attributes - - @param elements A list of elements to be filtered - @param keywords A dictionary containing required tags and its values - @param operation A string, either 'or' or 'and', for operation selection - - @return A list of filtered elements by attributes - """ - retval = [] - if not keywords: return elements - if operation == 'or': - for element in elements: - for key in keywords: - if element.attrib.has_key(key): - if element.attrib[key] == keywords[key]: - retval.append(element) - break - elif operation == 'and': - for element in elements: - for key in keywords: - if not element.attrib.has_key(key): break - if element.attrib[key] != keywords[key]: break - retval.append(element) - return retval - -def get_element_tag(element): - """ - Function to get the element tag without namespace - - @param element An element which will be extracted the tag name - - @return A string, containing the tag name without namespace - """ - tag = re.match('{.*?}(.*)',element.tag) - if tag: - return tag.group(1) - else: - return tag - -def get_child_value(element,childname): - """ - Function to get the value of an element's child element - - @param element An element to be queried - @param childname A string, containing the tagname of the child - - @return A string containing child's text value if child is a leaf element, - or a ElementTree element if child is a parent to 1 or more elements - """ - for c in element.getchildren(): - if get_element_tag(c) == childname: - if c.getchildren(): - return c - else: - return c.text - - -def add_tmp_repo(base,name,repourls): - """ - Function to add temporary repository - @param base The YumBase object for the operation - @param name The repository name - @param repourls A list of urls for the repository - - @return None - """ - tfo = tempfile.NamedTemporaryFile() - repoid = name - repoconfig = """ -[%s] -name=%s -failovermethod=priority -baseurl=%s -enabled=1 -""" % (name,name,'\n'.join(repourls)) - tfo.file.write(repoconfig) - tfo.file.close() - base.getReposFromConfigFile(tfo.name) - -class OCIMetapackage: +class Metapackage: """ - Parser class for OCI Metapackage XML. + Parser class for Chitin Metapackage XML. """ - def __init__(self,element,distversion): + def __init__(self,xmlfile,distversion): """ - @param element ElementTree object which stores the XML file + @param xmlfile One Click Install XML file @param distversion A string containing '$distro $release' @return None """ - self.element = element + self.element = ElementTree(Element('metapackage'),open(xmlfile)) self.distversion = distversion def getGroup(self): """ - Function to get Group element from OCI Metadata + Function to get Group element from Chitin Metadata @return 'group' Element of the current distversion """ for group in self.element.getiterator('{%s}%s' % (ocins,'group')): - if group.attrib['distversion'] == self.distversion: + if group.attrib['distversion'].lower() == self.distversion.lower(): return group def getRepositories(self,*args,**kwargs): @@ -199,113 +96,3 @@ class OCIMetapackage: urls.sort(sorturl) return [ url[0] for url in urls ] -class OCIQuery: - def __init__(self,distro,release): - self.distro = distro - self.release = release - - def getNames(self): - return ['oci-query'] - - def getUsage(self): - return "[details|repositories|packages] [OCI file]" - - def getSummary(self): - return "Query data from OneClickInstall metadata" - - def doCheck(self, base, basecmd, extcmds): - pass - - def getRepos(self): # so we can act as a "conduit" - return self.repos - - def show_pkg(self, msg, pkg, md, disp=None): - print msg, pkg, md - - def show_pkg_exit(self): - pass - - def doCommand(self, base, basecmd, extcmds): - action = extcmds[0] - param = extcmds[1:] - metapackages = [] - for mp in param: - et = ElementTree(Element('metapackage'),open(mp)) - metapackages.append(OCIMetapackage(et,'%s %s' % (self.distro,self.release))) - - if action == 'details': - for oci in metapackages: - print '=======================' - print 'Metadata' - print '=======================' - for c in oci.getGroup().getchildren(): - tagname = get_element_tag(c) - if tagname in ['name','summary','description']: - print tagname,':',c.text - if action == 'repositories': - for oci in metapackages: - print '========================' - print 'Repositories' - print '========================' - for r in oci.getRepositories(): - print get_child_value(r,'name') - print oci.getRepoURL(get_child_value(r,'name')) - if action == 'packages': - for oci in metapackages: - print '========================' - print 'Packages' - print '========================' - for p in oci.getProducts(): - print p.getchildren()[0].text - print '' - return 0, [''] - -class OCIInstall: - def __init__(self,distro,release): - self.distro = distro - self.release = release - - def getNames(self): - return ['oci-install'] - - def getUsage(self): - return "[OCI file]" - - def getSummary(self): - return "Install packages from OneClickInstall metadata" - - def doCheck(self, base, basecmd, extcmds): - pass - - def getRepos(self): # so we can act as a "conduit" - return self.repos - - def show_pkg(self, msg, pkg, md, disp=None): - print msg, pkg, md - - def show_pkg_exit(self): - pass - - def doCommand(self, base, basecmd, extcmds): - packages = [] - repositories = [] - for mp in extcmds: - et = ElementTree(Element('metapackage'),open(mp)) - oci = OCIMetapackage(et,'%s %s' % (self.distro,self.release)) - for p in oci.getProducts(): - packages.append(get_child_value(p,'name')) - for r in oci.getRepositories(): - repositories.append((get_child_value(r,'name'),oci.getRepoURL(get_child_value(r,'name')))) - print packages - print repositories - - base.verbose_logger.log(logginglevels.INFO_2, - _("Setting up Install Process")) - try: - return base.installPkgs(packages) - except yum.Errors.YumBaseError, e: - return 1, [str(e)] - -def config_hook(conduit): - conduit.registerCommand(OCIQuery(distro,release)) - conduit.registerCommand(OCIInstall(distro,release)) diff --git a/chitin/utils.py b/chitin/utils.py new file mode 100644 index 0000000..b10bfc3 --- /dev/null +++ b/chitin/utils.py @@ -0,0 +1,74 @@ +#!/usr/bin/python + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +def attrsfilter(elements,keywords,operation='or'): + """ + Function to filter elements by its attributes + + @param elements A list of elements to be filtered + @param keywords A dictionary containing required tags and its values + @param operation A string, either 'or' or 'and', for operation selection + + @return A list of filtered elements by attributes + """ + retval = [] + if not keywords: return elements + if operation == 'or': + for element in elements: + for key in keywords: + if element.attrib.has_key(key): + if element.attrib[key] == keywords[key]: + retval.append(element) + break + elif operation == 'and': + for element in elements: + for key in keywords: + if not element.attrib.has_key(key): break + if element.attrib[key] != keywords[key]: break + retval.append(element) + return retval + +def get_element_tag(element): + """ + Function to get the element tag without namespace + + @param element An element which will be extracted the tag name + + @return A string, containing the tag name without namespace + """ + tag = re.match('{.*?}(.*)',element.tag) + if tag: + return tag.group(1) + else: + return tag + +def get_child_value(element,childname): + """ + Function to get the value of an element's child element + + @param element An element to be queried + @param childname A string, containing the tagname of the child + + @return A string containing child's text value if child is a leaf element, + or a ElementTree element if child is a parent to 1 or more elements + """ + for c in element.getchildren(): + if get_element_tag(c) == childname: + if c.getchildren(): + return c + else: + return c.text + diff --git a/yum-plugin/chitin.py b/yum-plugin/chitin.py new file mode 100644 index 0000000..1653085 --- /dev/null +++ b/yum-plugin/chitin.py @@ -0,0 +1,311 @@ +#!/usr/bin/python + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# Copyright Red Hat Inc. 2007, 2008 +# +# Author: Izhar Firdaus +# Examples: +# +# yum chitin-install oneclickinstall-XML-metadata-file +# yum chitin-query details oneclickinstall-XML-metadata-file +# yum chitin-query repositories oneclickinstall-XML-metadata-file +# yum chitin-query packages oneclickinstall-XML-metadata-file +# + + +from xml.etree.ElementTree import ElementTree,Element +import re + +from yum.plugins import PluginYumExit,TYPE_CORE,TYPE_INTERACTIVE +from yum import logginglevels +import yum.i18n, tempfile +_ = yum.i18n._ + +ocins='http://opensuse.org/Standards/One_Click_Install' +#distro='fedora' +#release='9' + +## Use this for now +distro='openSUSE' +release='Factory' + + +requires_api_version = '2.5' +plugin_type = (TYPE_INTERACTIVE,) + + +def attrsfilter(elements,keywords,operation='or'): + """ + Function to filter elements by its attributes + + @param elements A list of elements to be filtered + @param keywords A dictionary containing required tags and its values + @param operation A string, either 'or' or 'and', for operation selection + + @return A list of filtered elements by attributes + """ + retval = [] + if not keywords: return elements + if operation == 'or': + for element in elements: + for key in keywords: + if element.attrib.has_key(key): + if element.attrib[key] == keywords[key]: + retval.append(element) + break + elif operation == 'and': + for element in elements: + for key in keywords: + if not element.attrib.has_key(key): break + if element.attrib[key] != keywords[key]: break + retval.append(element) + return retval + +def get_element_tag(element): + """ + Function to get the element tag without namespace + + @param element An element which will be extracted the tag name + + @return A string, containing the tag name without namespace + """ + tag = re.match('{.*?}(.*)',element.tag) + if tag: + return tag.group(1) + else: + return tag + +def get_child_value(element,childname): + """ + Function to get the value of an element's child element + + @param element An element to be queried + @param childname A string, containing the tagname of the child + + @return A string containing child's text value if child is a leaf element, + or a ElementTree element if child is a parent to 1 or more elements + """ + for c in element.getchildren(): + if get_element_tag(c) == childname: + if c.getchildren(): + return c + else: + return c.text + + +def add_tmp_repo(base,name,repourls): + """ + Function to add temporary repository + + @param base The YumBase object for the operation + @param name The repository name + @param repourls A list of urls for the repository + + @return None + """ + tfo = tempfile.NamedTemporaryFile() + repoid = name + repoconfig = """ +[%s] +name=%s +failovermethod=priority +baseurl=%s +enabled=1 +""" % (name,name,'\n'.join(repourls)) + tfo.file.write(repoconfig) + tfo.file.close() + base.getReposFromConfigFile(tfo.name) + +class OCIMetapackage: + """ + Parser class for OCI Metapackage XML. + """ + def __init__(self,element,distversion): + """ + @param element ElementTree object which stores the XML file + @param distversion A string containing '$distro $release' + + @return None + """ + self.element = element + self.distversion = distversion + + def getGroup(self): + """ + Function to get Group element from OCI Metadata + + @return 'group' Element of the current distversion + """ + for group in self.element.getiterator('{%s}%s' % (ocins,'group')): + if group.attrib['distversion'] == self.distversion: + return group + + def getRepositories(self,*args,**kwargs): + """ + Function to get 'repository' elements from the current distversion group + + @kwargs Keyword arguments for filtering results + + @return A list containing a filtered list of 'repository' Elements + """ + repos = self.getGroup().getiterator('{%s}%s' % (ocins,'repository')) + return attrsfilter(repos,kwargs) + + def getProducts(self,*args,**kwargs): + """ + Function to get 'product' elements from the current distversion group + + @kwargs Keyword arguments for filtering results + + @return A list containing a filtered list of 'product' Elements + """ + products = self.getGroup().getiterator('{%s}%s' % (ocins,'product')) + return attrsfilter(products,kwargs) + + def getRepoURL(self,reponame): + """ + Function to get 'url' values from current distversion group, and requested reponame + + @param reponame The repository name + + @return A list of URLs from the requested repository, sorted higher score first + """ + repos = self.getRepositories() + urls = [] + for r in repos: + if get_child_value(r,'name') == reponame: + for url in r.getiterator('{%s}%s' % (ocins,'url')): + priority = 0 + if url.attrib.has_key('score'): priority = int(url.attrib['score']) + urls.append((url.text.strip(),priority)) + def sorturl(x,y): + if x[1] <= y[1]: + return +1 + else: + return -1 + urls.sort(sorturl) + return [ url[0] for url in urls ] + +class OCIQuery: + def __init__(self,distro,release): + self.distro = distro + self.release = release + + def getNames(self): + return ['oci-query'] + + def getUsage(self): + return "[details|repositories|packages] [OCI file]" + + def getSummary(self): + return "Query data from OneClickInstall metadata" + + def doCheck(self, base, basecmd, extcmds): + pass + + def getRepos(self): # so we can act as a "conduit" + return self.repos + + def show_pkg(self, msg, pkg, md, disp=None): + print msg, pkg, md + + def show_pkg_exit(self): + pass + + def doCommand(self, base, basecmd, extcmds): + action = extcmds[0] + param = extcmds[1:] + metapackages = [] + for mp in param: + et = ElementTree(Element('metapackage'),open(mp)) + metapackages.append(OCIMetapackage(et,'%s %s' % (self.distro,self.release))) + + if action == 'details': + for oci in metapackages: + print '=======================' + print 'Metadata' + print '=======================' + for c in oci.getGroup().getchildren(): + tagname = get_element_tag(c) + if tagname in ['name','summary','description']: + print tagname,':',c.text + if action == 'repositories': + for oci in metapackages: + print '========================' + print 'Repositories' + print '========================' + for r in oci.getRepositories(): + print get_child_value(r,'name') + print oci.getRepoURL(get_child_value(r,'name')) + if action == 'packages': + for oci in metapackages: + print '========================' + print 'Packages' + print '========================' + for p in oci.getProducts(): + print p.getchildren()[0].text + print '' + return 0, [''] + +class OCIInstall: + def __init__(self,distro,release): + self.distro = distro + self.release = release + + def getNames(self): + return ['oci-install'] + + def getUsage(self): + return "[OCI file]" + + def getSummary(self): + return "Install packages from OneClickInstall metadata" + + def doCheck(self, base, basecmd, extcmds): + pass + + def getRepos(self): # so we can act as a "conduit" + return self.repos + + def show_pkg(self, msg, pkg, md, disp=None): + print msg, pkg, md + + def show_pkg_exit(self): + pass + + def doCommand(self, base, basecmd, extcmds): + packages = [] + repositories = [] + for mp in extcmds: + et = ElementTree(Element('metapackage'),open(mp)) + oci = OCIMetapackage(et,'%s %s' % (self.distro,self.release)) + for p in oci.getProducts(): + packages.append(get_child_value(p,'name')) + for r in oci.getRepositories(): + repositories.append((get_child_value(r,'name'),oci.getRepoURL(get_child_value(r,'name')))) + print packages + print repositories + + base.verbose_logger.log(logginglevels.INFO_2, + _("Setting up Install Process")) + try: + return base.installPkgs(packages) + except yum.Errors.YumBaseError, e: + return 1, [str(e)] + +def config_hook(conduit): + conduit.registerCommand(OCIQuery(distro,release)) + conduit.registerCommand(OCIInstall(distro,release)) -- cgit