| # Copyright 2007 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| # $Id$ |
| |
| import os |
| from ConfigParser import SafeConfigParser, NoOptionError |
| from portage import load_mod |
| from portage.const import USER_CONFIG_PATH, GLOBAL_CONFIG_PATH |
| |
| SETPREFIX = "@" |
| |
| def get_boolean(options, name, default): |
| if not name in options: |
| return default |
| elif options[name].lower() in ("1", "yes", "on", "true"): |
| return True |
| elif options[name].lower() in ("0", "no", "off", "false"): |
| return False |
| else: |
| raise SetConfigError("invalid value '%s' for option '%s'" % (options[name], name)) |
| |
| class SetConfigError(Exception): |
| pass |
| |
| class SetConfig(SafeConfigParser): |
| def __init__(self, paths, settings, trees): |
| SafeConfigParser.__init__(self) |
| self.read(paths) |
| self.errors = [] |
| self.psets = {} |
| self.trees = trees |
| self.settings = settings |
| self._parsed = False |
| self.active = [] |
| |
| def _parse(self): |
| if self._parsed: |
| return |
| for sname in self.sections(): |
| # find classname for current section, default to file based sets |
| if not self.has_option(sname, "class"): |
| classname = "portage.sets.files.StaticFileSet" |
| else: |
| classname = self.get(sname, "class") |
| |
| # try to import the specified class |
| try: |
| setclass = load_mod(classname) |
| except (ImportError, AttributeError): |
| self.errors.append("Could not import '%s' for section '%s'" % (classname, sname)) |
| continue |
| # prepare option dict for the current section |
| optdict = {} |
| for oname in self.options(sname): |
| optdict[oname] = self.get(sname, oname) |
| |
| # create single or multiple instances of the given class depending on configuration |
| if self.has_option(sname, "multiset") and self.getboolean(sname, "multiset"): |
| if hasattr(setclass, "multiBuilder"): |
| newsets = {} |
| try: |
| newsets = setclass.multiBuilder(optdict, self.settings, self.trees) |
| except SetConfigError, e: |
| self.errors.append("Configuration error in section '%s': %s" % (sname, str(e))) |
| continue |
| for x in newsets: |
| if x in self.psets: |
| self.errors.append("Redefinition of set '%s' (sections: '%s', '%s')" % (setname, self.psets[setname].creator, sname)) |
| newsets[x].creator = sname |
| if self.has_option(sname, "world-candidate") and not self.getboolean(sname, "world-candidate"): |
| newsets[x].world_candidate = False |
| self.psets.update(newsets) |
| else: |
| self.errors.append("Section '%s' is configured as multiset, but '%s' doesn't support that configuration" % (sname, classname)) |
| continue |
| else: |
| try: |
| setname = self.get(sname, "name") |
| except NoOptionError: |
| setname = sname |
| if setname in self.psets: |
| self.errors.append("Redefinition of set '%s' (sections: '%s', '%s')" % (setname, self.psets[setname].creator, sname)) |
| if hasattr(setclass, "singleBuilder"): |
| try: |
| self.psets[setname] = setclass.singleBuilder(optdict, self.settings, self.trees) |
| self.psets[setname].creator = sname |
| if self.has_option(sname, "world-candidate") and not self.getboolean(sname, "world-candidate"): |
| self.psets[setname].world_candidate = False |
| except SetConfigError, e: |
| self.errors.append("Configuration error in section '%s': %s" % (sname, str(e))) |
| continue |
| else: |
| self.errors.append("'%s' does not support individual set creation, section '%s' must be configured as multiset" % (classname, sname)) |
| continue |
| self._parsed = True |
| |
| def getSets(self): |
| self._parse() |
| return self.psets.copy() |
| |
| def getSetAtoms(self, setname, ignorelist=None): |
| myset = self.getSets()[setname] |
| myatoms = myset.getAtoms() |
| if ignorelist is None: |
| ignorelist = set() |
| ignorelist.add(setname) |
| for n in myset.getNonAtoms(): |
| if n[0] == SETPREFIX and n[1:] in self.psets: |
| if n[1:] not in ignorelist: |
| myatoms.update(self.getSetAtoms(n[1:], |
| ignorelist=ignorelist)) |
| return myatoms |
| |
| def load_default_config(settings, trees): |
| setconfigpaths = [os.path.join(GLOBAL_CONFIG_PATH, "sets.conf")] |
| setconfigpaths.append(os.path.join(settings["PORTDIR"], "sets.conf")) |
| setconfigpaths += [os.path.join(x, "sets.conf") for x in settings["PORTDIR_OVERLAY"].split()] |
| setconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"], |
| USER_CONFIG_PATH.lstrip(os.path.sep), "sets.conf")) |
| return SetConfig(setconfigpaths, settings, trees) |
| |
| # adhoc test code |
| if __name__ == "__main__": |
| import portage |
| sc = load_default_config(portage.settings, portage.db["/"]) |
| l, e = sc.getSets() |
| for x in l: |
| print x+":" |
| print "DESCRIPTION = %s" % l[x].getMetadata("Description") |
| for n in sorted(l[x].getAtoms()): |
| print "- "+n |
| print |