[Yum-devel] [PATCH RFC] Add new metadata type to comps

Bill Nottingham notting at redhat.com
Wed Aug 1 18:47:45 UTC 2012


James Antill (james at fedoraproject.org) said: 
> > >  From the backend POV, this looks fine to me (I assume the anaconda guys
> > > are happy with the APIs they need?)
> > 
> > It's still being discussed.
> 
>  *nods*

Discussions there centered mainly around naming; the name of 'environment'
was considered better than 'install class'. Updated patch attached.

> > >  From the UI POV though I think we need to integrate it into the current
> > > groups. So you could just do: yum install @blah ... to get an
> > > "installclass" group. I assume there are no plans to have installclasses
> > > with the same name as a normal group (so we can treat that as a WTF)?
> > 
> > Hadn't ruled that out one way or another - the other option would be to pick
> > a new magic starting character other than '@'.
> 
>  I saw that suggestion in the anaconda thread, and I'm pretty sure it's
> a terrible idea to have another magic character.

anaconda seems greatly in favor of (from a kickstart perspective) of
treating it as a new item separate from groups, with a different delimiting
character.

> > >  Also are you sure you want to keep the feature that is display_order?
> > 
> > Can maybe drop it and just say for anaconda UI purposes it follows file
> > ordering.
> 
>  Well I was assuming just using lexicographic order instead. Is there a
> need to change the order (to always have minimal at the top or
> something)? If so I guess just keep display_order, but given how we
> never use it for groups and that users don't expect it I thought it
> might be a good idea to not carry it forwards.

I would like to have ordering of some sort; if file ordering can't be
preserved, then keeping display_order is best.

Comments, concerns, other?

Bill
-------------- next part --------------
>From 39bb217e5cb57c5fb20b6a73380b7502b2318bea Mon Sep 17 00:00:00 2001
From: Bill Nottingham <notting at redhat.com>
Date: Wed, 18 Jul 2012 15:19:34 -0400
Subject: [PATCH] Add support for parsing 'environments' to the comps file.

Environments are a construct for use in anaconda for installing the
system. They consist of:
- id
- name
- description
- display order
- a list of groups that make up that environment
- a list of groups that are options for that environment

Expected usage case is that anaconda will offer for you to pick an
environment, and once you've done so, offer you the list of options
to optionally install.
---
 yum/comps.py |  197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 197 insertions(+)

diff --git a/yum/comps.py b/yum/comps.py
index 65f6d5e..880d373 100755
--- a/yum/comps.py
+++ b/yum/comps.py
@@ -272,6 +272,128 @@ class Group(CompsObj):
         return msg      
 
 
+class Environment(CompsObj):
+    """ Environment object parsed from group data in each repo, and merged """
+
+    def __init__(self, elem=None):
+        self.name = ""
+        self.environmentid = None
+        self.description = ""
+        self.translated_name = {}
+        self.translated_description = {}
+        self.display_order = 1024
+        self._groups = {}
+        self._options = {}
+
+        if elem:
+            self.parse(elem)
+
+    def _groupiter(self):
+        return self._groups.keys()
+
+    groups = property(_groupiter)
+
+    def _optioniter(self):
+        return self._options.keys()
+
+    options = property(_optioniter)
+
+    def parse(self, elem):
+        for child in elem:
+            if child.tag == 'id':
+                myid = child.text
+                if self.environmentid is not None:
+                    raise CompsException
+                self.environmentid = myid
+
+            elif child.tag == 'name':
+                text = child.text
+                if text:
+                    text = text.encode('utf8')
+
+                lang = child.attrib.get(lang_attr)
+                if lang:
+                    self.translated_name[lang] = text
+                else:
+                    self.name = text
+
+            elif child.tag == 'description':
+                text = child.text
+                if text:
+                    text = text.encode('utf8')
+
+                lang = child.attrib.get(lang_attr)
+                if lang:
+                    self.translated_description[lang] = text
+                else:
+                    self.description = text
+
+            elif child.tag == 'grouplist':
+                self.parse_group_list(child)
+
+            elif child.tag == 'optionlist':
+                self.parse_option_list(child)
+
+            elif child.tag == 'display_order':
+                self.display_order = parse_number(child.text)
+
+    def parse_group_list(self, grouplist_elem):
+        for child in grouplist_elem:
+            if child.tag == 'groupid':
+                groupid = child.text
+                self._groups[groupid] = 1
+
+    def parse_option_list(self, optionlist_elem):
+        for child in optionlist_elem:
+            if child.tag == 'groupid':
+                optionid = child.text
+                self._options[optionid] = 1
+
+    def add(self, obj):
+        """Add another category object to this object"""
+
+        for grp in obj.groups:
+            self._groups[grp] = 1
+
+        for grp in obj.options:
+            self._options[grp] = 1
+
+        # name and description translations
+        for lang in obj.translated_name:
+            if lang not in self.translated_name:
+                self.translated_name[lang] = obj.translated_name[lang]
+
+        for lang in obj.translated_description:
+            if lang not in self.translated_description:
+                self.translated_description[lang] = obj.translated_description[lang]
+
+    def xml(self):
+        """write out an xml stanza for the environment object"""
+        msg ="""
+  <environment>
+   <id>%s</id>
+   <display_order>%s</display_order>\n""" % (self.environmentid, self.display_order)
+
+        msg +="""   <name>%s</name>\n""" % self.name
+        for (lang, val) in self.translated_name.items():
+            msg += """   <name xml:lang="%s">%s</name>\n""" % (lang, val)
+
+        msg += """   <description>%s</description>\n""" % self.description
+        for (lang, val) in self.translated_description.items():
+            msg += """    <description xml:lang="%s">%s</description>\n""" % (lang, val)
+
+        msg += """    <grouplist>\n"""
+        for grp in self.groups:
+            msg += """     <groupid>%s</groupid>\n""" % grp
+        msg += """    </grouplist>\n"""
+        msg += """    <optionlist>\n"""
+        for grp in self.options:
+            msg += """     <optionid>%s</optionid>\n""" % grp
+        msg += """    </optionlist>\n"""
+        msg += """  </environment>\n"""
+
+        return msg
+
 class Category(CompsObj):
     """ Category object parsed from group data in each repo. and merged. """
 
@@ -376,6 +498,7 @@ class Category(CompsObj):
 class Comps(object):
     def __init__(self, overwrite_groups=False):
         self._groups = {}
+        self._environments = {}
         self._categories = {}
         self.compscount = 0
         self.overwrite_groups = overwrite_groups
@@ -388,12 +511,18 @@ class Comps(object):
         grps.sort(key=lambda x: (x.display_order, x.name))
         return grps
         
+    def get_environments(self):
+        environments = self._environments.values()
+        environments.sort(key=lambda x: (x.display_order, x.name))
+        return environments
+
     def get_categories(self):
         cats = self._categories.values()
         cats.sort(key=lambda x: (x.display_order, x.name))
         return cats
     
     groups = property(get_groups)
+    environments = property(get_environments)
     categories = property(get_categories)
     
     def has_group(self, grpid):
@@ -447,6 +576,57 @@ class Comps(object):
 
         return returns.values()
 
+    def has_environment(self, environmentid):
+        exists = self.return_environments(environmentid)
+
+        if exists:
+            return True
+
+        return False
+
+    def return_environment(self, environmentid):
+        """Return the first group which matches"""
+        environments = self.return_environments(environmentid)
+        if environments:
+            return environments[0]
+
+        return None
+
+    def return_environments(self, env_pattern, case_sensitive=False):
+        """return all environments which match either by glob or exact match"""
+        returns = {}
+
+        for item in env_pattern.split(','):
+            item = item.strip()
+            if item in self._environments:
+                env = self._environments[item]
+                returns[env.environmentid] = env
+                continue
+
+            if case_sensitive:
+                match = re.compile(fnmatch.translate(item)).match
+            else:
+                match = re.compile(fnmatch.translate(item), flags=re.I).match
+
+            done = False
+            for env in self.environments:
+                for name in env.name, env.environmentid, env.ui_name:
+                    if match(name):
+                        done = True
+                        returns[env.environmentid] = env
+                        break
+            if done:
+                continue
+
+            # If we didn't match to anything in the current locale, try others
+            for env in self.environments:
+                for name in env.translated_name.values():
+                    if match(name):
+                        returns[env.environmentid] = env
+                        break
+
+        return returns.values()
+
     #  This is close to returnPackages() etc. API ... need to std. these names
     # the above return_groups uses different, but equal, API.
     def return_categories(self, pattern, ignore_case=True):
@@ -490,6 +670,13 @@ class Comps(object):
         else:
             self._groups[group.groupid] = group
 
+    def add_environment(self, environment):
+        if environment.environmentid in self._environments:
+            env = self._environments[environment.environmentid]
+            env.add(environment)
+        else:
+            self._environments[environment.environmentid] = environment
+
     def add_category(self, category):
         if category.categoryid in self._categories:
             thatcat = self._categories[category.categoryid]
@@ -520,6 +707,9 @@ class Comps(object):
                 if elem.tag == "group":
                     group = Group(elem)
                     self.add_group(group)
+                if elem.tag == "environment":
+                    environment = Environment(elem)
+                    self.add_environment(environment)
                 if elem.tag == "category":
                     category = Category(elem)
                     self.add_category(category)
@@ -595,6 +785,13 @@ def main():
             for pkg in group.packages:
                 print '  ' + pkg
         
+        for environment in p.environments:
+            print environment.name
+            for group in environment.groups:
+                print '  ' + group
+            for group in environment.options:
+                print '  *' + group
+
         for category in p.categories:
             print category.name
             for group in category.groups:
-- 
1.7.10.4



More information about the Yum-devel mailing list