From 784f1580709eae996134923b9fd5f557202d59cb Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Tue, 12 Mar 2013 03:30:04 +0100 Subject: Plugins/Packages/Layman: add support for layman overlays In combination with the PortageCollection the Packages plugin could now handle layman overlays. The Portage collection evaluates the dependencies with respect to the configured overlays. --- schemas/packages.xsd | 1 + src/lib/Bcfg2/Server/Plugins/Packages/Layman.py | 133 +++++++++++++++++++++++ src/lib/Bcfg2/Server/Plugins/Packages/Portage.py | 8 ++ 3 files changed, 142 insertions(+) create mode 100644 src/lib/Bcfg2/Server/Plugins/Packages/Layman.py diff --git a/schemas/packages.xsd b/schemas/packages.xsd index 7819a1ba0..e4724fabe 100644 --- a/schemas/packages.xsd +++ b/schemas/packages.xsd @@ -15,6 +15,7 @@ + diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Layman.py b/src/lib/Bcfg2/Server/Plugins/Packages/Layman.py new file mode 100644 index 000000000..947fa0319 --- /dev/null +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Layman.py @@ -0,0 +1,133 @@ +import os +import layman +import Bcfg2.Server.Plugin + +class LaymanSource(Bcfg2.Server.Plugin.Debuggable): + basegroups = ['portage', 'gentoo', 'emerge'] + ptype = 'layman' + cclass = 'Portage' + + def __init__(self, basepath, xsource, setup): + Bcfg2.Server.Plugin.Debuggable.__init__(self) + self.basepath = basepath + self.xsource = xsource + self.setup = setup + + self.url = xsource.get('url', 'http://www.gentoo.org/proj/en/overlays/repositories.xml') + self.name = xsource.get('name', '') + self.priority = xsource.get('priority', 0) + self.cachefile = None + self.gpgkeys = [] + self.recommended = False + self.essentialpkgs = set() + self.arches = [item.text for item in xsource.findall('Arch')] + + self.url_map = [dict(version=None, component=None, arch=arch, + url=self.url, baseurl=self.url) for arch in self.arches] + + #: A list of the the names of packages that are blacklisted + #: from this source + self.blacklist = [item.text for item in xsource.findall('Blacklist')] + + #: A list of the the names of packages that are whitelisted in + #: this source + self.whitelist = [item.text for item in xsource.findall('Whitelist')] + + + # configure layman + base = os.path.join(basepath, 'layman') + storage = os.path.join(base, 'overlays') + config = layman.config.OptionConfig(options = { + 'storage': os.path.join(base, 'overlays'), + 'cache': os.path.join(base, 'cache'), + 'installed': os.path.join(base, 'installed.xml'), + 'local_list': os.path.join(base, 'overlays.xml'), + 'overlays': [self.url] + }) + self.api = layman.LaymanAPI(config) + + # path + self.dir = os.path.join(storage, self.name) + + # build the set of conditions to see if this source applies to + # a given set of metadata + self.conditions = [] + self.groups = [] # provided for some limited backwards compat + for el in xsource.iterancestors(): + if el.tag == "Group": + if el.get("negate", "false").lower() == "true": + self.conditions.append(lambda m, el=el: + el.get("name") not in m.groups) + else: + self.groups.append(el.get("name")) + self.conditions.append(lambda m, el=el: + el.get("name") in m.groups) + elif el.tag == "Client": + if el.get("negate", "false").lower() == "true": + self.conditions.append(lambda m, el=el: + el.get("name") != m.hostname) + else: + self.conditions.append(lambda m, el=el: + el.get("name") == m.hostname) + + def get_repo_name(self, url_map): + return self.name + + def save_state(self): + pass + + def load_state(self): + pass + + def filter_unknown(self, unknown): + filtered = set([u for u in unknown if u.startswith('choice')]) + unknown.difference_update(filtered) + + def get_urls(self): + return self.url + urls = property(get_urls) + + def magic_groups_match(self, metadata): + if self.setup.cfp.getboolean("global", "magic_groups", + default=True) == False: + return True + else: + for group in self.basegroups: + if group in metadata.groups: + return True + return False + + def setup_data(self, force_update=False): + self.api.fetch_remote_list() + if not self.api.is_repo(self.name): + self.logger.error("Packages: Layman overlay '%s' not" + " found" % self.name) + return False + + if not self.api.is_installed(self.name): + self.logger.info("Packages: Adding layman overlay '%s'" % + self.name) + if not self.api.add_repos(self.name): + self.logger.error("Packages: Failed adding layman" + " overlay '%s'" % self.name) + return False + + if force_update: + if not self.api.sync(self.name): + self.logger.error("Packages: Failed syncing layman" + " overlay '%s'" % self.name) + return False + + return True + + def applies(self, metadata): + # check base groups + if not self.magic_groups_match(metadata): + return False + + # check Group/Client tags from sources.xml + for condition in self.conditions: + if not condition(metadata): + return False + + return True diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Portage.py b/src/lib/Bcfg2/Server/Plugins/Packages/Portage.py index 938ddad4d..ac074f879 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Portage.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Portage.py @@ -5,6 +5,7 @@ import os import lxml.etree import Bcfg2.Server.Plugin from Bcfg2.Server.Plugins.Packages.Collection import Collection +from Bcfg2.Server.Plugins.Packages.Layman import LaymanSource _portage_python = '/usr/lib/portage/pym/' @@ -149,6 +150,13 @@ class PortageCollection(Collection): env = portage.settings.configdict['backupenv'] + # add layman overlays + env['PORTDIR_OVERLAY'] = '' + for overlay in self: + if isinstance(overlay, LaymanSource): + env['PORTDIR_OVERLAY'] += ' ' + env['PORTDIR_OVERLAY'] += overlay.dir + portage.settings = portage.package.ebuild.config.config( config_root=portage.settings['PORTAGE_CONFIGROOT'], target_root=portage.settings['ROOT'], -- cgit v1.2.3-1-g7c22