---
 .../package/ebuild/_config/InstallMaskManager.py   | 59 ++++++++++++++++++++++
 pym/portage/package/ebuild/config.py               | 34 ++++++++++++-
 pym/portage/util/configparser.py                   | 19 ++++++-
 3 files changed, 110 insertions(+), 2 deletions(-)
 create mode 100644 pym/portage/package/ebuild/_config/InstallMaskManager.py

diff --git a/pym/portage/package/ebuild/_config/InstallMaskManager.py 
b/pym/portage/package/ebuild/_config/InstallMaskManager.py
new file mode 100644
index 0000000..96cb539
--- /dev/null
+++ b/pym/portage/package/ebuild/_config/InstallMaskManager.py
@@ -0,0 +1,59 @@
+# Copyright 2010-2016 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = (
+       'InstallMaskManager',
+)
+
+import sys
+
+from portage import os
+from portage.localization import _
+from portage.util import writemsg
+from portage.util.configparser import (SafeConfigParser, ConfigParserError,
+       MultiValueConfigParserDict, read_configs)
+
+
+class InstallMaskManager(object):
+       def __init__(self, repositories, abs_user_config, user_config=True):
+               self._groups = {}
+
+               # read repository defined groups
+               self._read_config_from_repositories(repositories)
+
+               if user_config:
+                       self._read_config(os.path.join(abs_user_config, 
'install-mask.conf'), True)
+
+       def _read_config_from_repositories(self, repositories):
+               for r in repositories.repos_with_profiles():
+                       self._read_config(os.path.join(r.location, 'metadata', 
'install-mask.conf'))
+
+       def _read_config(self, path, is_user_config=False):
+               # use separate parsers to detect collisions properly
+               cfp_kwargs = {}
+               if sys.hexversion >= 0x03020000:
+                       cfp_kwargs['strict'] = False
+               parser = SafeConfigParser(dict_type=MultiValueConfigParserDict,
+                       **cfp_kwargs)
+               try:
+                       read_configs(parser, [path])
+               except ConfigParserError as e:
+                       writemsg(
+                               _("!!! Error while reading %s: %s\n") % (path, 
e),
+                               noiselevel=-1)
+                       return
+
+               for sname in parser.sections():
+                       if not is_user_config and sname in self._groups:
+                               writemsg(
+                                       _("!!! Error while reading %s: 
duplicate group %s found\n") % (path, sname),
+                                       noiselevel=-1)
+                               continue
+                       if not parser.has_option(sname, 'path'):
+                               continue
+
+                       paths = parser.get(sname, 'path').split('\n')
+                       self._groups[sname] = paths
+
+       def expand_group(self, gname):
+               return self._groups[gname]
diff --git a/pym/portage/package/ebuild/config.py 
b/pym/portage/package/ebuild/config.py
index 9d13703..dfbd7f2 100644
--- a/pym/portage/package/ebuild/config.py
+++ b/pym/portage/package/ebuild/config.py
@@ -60,6 +60,7 @@ from portage.package.ebuild._config.features_set import 
features_set
 from portage.package.ebuild._config.KeywordsManager import KeywordsManager
 from portage.package.ebuild._config.LicenseManager import LicenseManager
 from portage.package.ebuild._config.UseManager import UseManager
+from portage.package.ebuild._config.InstallMaskManager import 
InstallMaskManager
 from portage.package.ebuild._config.LocationsManager import LocationsManager
 from portage.package.ebuild._config.MaskManager import MaskManager
 from portage.package.ebuild._config.VirtualsManager import VirtualsManager
@@ -277,6 +278,7 @@ class config(object):
                        # force instantiation of lazy immutable objects when 
cloning, so
                        # that they're not instantiated more than once
                        self._keywords_manager_obj = clone._keywords_manager
+                       self._install_mask_manager_obj = 
clone._install_mask_manager
                        self._mask_manager_obj = clone._mask_manager
 
                        # shared mutable attributes
@@ -329,6 +331,7 @@ class config(object):
                else:
                        # lazily instantiated objects
                        self._keywords_manager_obj = None
+                       self._install_mask_manager_obj = None
                        self._mask_manager_obj = None
                        self._virtuals_manager_obj = None
 
@@ -1032,6 +1035,15 @@ class config(object):
                return self._keywords_manager_obj
 
        @property
+       def _install_mask_manager(self):
+               if self._install_mask_manager_obj is None:
+                       self._install_mask_manager_obj = InstallMaskManager(
+                               self.repositories,
+                               self._locations_manager.abs_user_config,
+                               user_config=self.local_config)
+               return self._install_mask_manager_obj
+
+       @property
        def _mask_manager(self):
                if self._mask_manager_obj is None:
                        self._mask_manager_obj = MaskManager(self.repositories,
@@ -1774,7 +1786,8 @@ class config(object):
                _eapi_cache.clear()
 
                # Prepare the final value of INSTALL_MASK
-               install_mask = self.get("INSTALL_MASK", "").split()
+               install_mask = list(self._replace_install_mask_groups(
+                       self.get("INSTALL_MASK", "").split()))
                if 'nodoc' in self.features:
                        install_mask.append("/usr/share/doc")
                if 'noinfo' in self.features:
@@ -1782,6 +1795,25 @@ class config(object):
                if 'noman' in self.features:
                        install_mask.append("/usr/share/man")
                self.install_mask = install_mask
+               print(install_mask)
+
+       def _replace_install_mask_groups(self, vals):
+               for v in vals:
+                       if v.startswith('@') or v.startswith('-@'):
+                               neg = '-' if v.startswith('-') else ''
+                               gname = v[2:] if neg else v[1:]
+                               for p in self._expand_install_mask_group(gname):
+                                       yield '%s%s' % (neg, p)
+                       else:
+                               yield v
+
+       def _expand_install_mask_group(self, gname):
+               try:
+                       return self._install_mask_manager.expand_group(gname)
+               except KeyError:
+                       writemsg(_("!!! Undefined INSTALL_MASK group: '%s'!\n")
+                               % gname, noiselevel=-1)
+                       return ()
 
        def _grab_pkg_env(self, penv, container, protected_keys=None):
                if protected_keys is None:
diff --git a/pym/portage/util/configparser.py b/pym/portage/util/configparser.py
index c4c92a6..290bc5e 100644
--- a/pym/portage/util/configparser.py
+++ b/pym/portage/util/configparser.py
@@ -2,7 +2,8 @@
 # Distributed under the terms of the GNU General Public License v2
 
 __all__ = ['ConfigParserError', 'NoOptionError', 'ParsingError',
-       'RawConfigParser', 'SafeConfigParser', 'read_configs']
+       'RawConfigParser', 'SafeConfigParser', 'read_configs',
+       'MultiValueConfigParserDict']
 
 # the following scary compatibility thing provides two classes:
 # - SafeConfigParser that provides safe interpolation for values,
@@ -74,3 +75,19 @@ def read_configs(parser, paths):
                        read_file(p, **kwargs)
                else:
                        raise TypeError("Unsupported type %r of element %r of 
'paths' argument" % (type(p), p))
+
+
+class MultiValueConfigParserDict(dict):
+       """
+       A special variant of dict that stores all subsequent values assigned
+       to its keys as a list, and returns this list when retrieved. Meant
+       to be used with ConfigParser to process multi-key config files.
+       """
+
+       def __setitem__(self, k, v):
+               if isinstance(v, list):
+                       if not k in self:
+                               super(MultiValueConfigParserDict, 
self).__setitem__(k, [])
+                       self[k].extend(v)
+               else:
+                       super(MultiValueConfigParserDict, self).__setitem__(k, 
v)
-- 
2.8.3


Reply via email to