Gentoo Archives: gentoo-portage-dev

From: "Michał Górny" <mgorny@g.o>
To: gentoo-portage-dev@l.g.o
Cc: "Michał Górny" <mgorny@g.o>
Subject: [gentoo-portage-dev] [PATCH 4/3] portage.package.ebuild.config: Support path groups from install-mask.conf
Date: Tue, 31 May 2016 15:58:55
Message-Id: 20160531155834.21608-1-mgorny@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH 0/3] INSTALL_MASK redesign, part I by "Michał Górny"
1 ---
2 .../package/ebuild/_config/InstallMaskManager.py | 59 ++++++++++++++++++++++
3 pym/portage/package/ebuild/config.py | 34 ++++++++++++-
4 pym/portage/util/configparser.py | 19 ++++++-
5 3 files changed, 110 insertions(+), 2 deletions(-)
6 create mode 100644 pym/portage/package/ebuild/_config/InstallMaskManager.py
7
8 diff --git a/pym/portage/package/ebuild/_config/InstallMaskManager.py b/pym/portage/package/ebuild/_config/InstallMaskManager.py
9 new file mode 100644
10 index 0000000..96cb539
11 --- /dev/null
12 +++ b/pym/portage/package/ebuild/_config/InstallMaskManager.py
13 @@ -0,0 +1,59 @@
14 +# Copyright 2010-2016 Gentoo Foundation
15 +# Distributed under the terms of the GNU General Public License v2
16 +
17 +__all__ = (
18 + 'InstallMaskManager',
19 +)
20 +
21 +import sys
22 +
23 +from portage import os
24 +from portage.localization import _
25 +from portage.util import writemsg
26 +from portage.util.configparser import (SafeConfigParser, ConfigParserError,
27 + MultiValueConfigParserDict, read_configs)
28 +
29 +
30 +class InstallMaskManager(object):
31 + def __init__(self, repositories, abs_user_config, user_config=True):
32 + self._groups = {}
33 +
34 + # read repository defined groups
35 + self._read_config_from_repositories(repositories)
36 +
37 + if user_config:
38 + self._read_config(os.path.join(abs_user_config, 'install-mask.conf'), True)
39 +
40 + def _read_config_from_repositories(self, repositories):
41 + for r in repositories.repos_with_profiles():
42 + self._read_config(os.path.join(r.location, 'metadata', 'install-mask.conf'))
43 +
44 + def _read_config(self, path, is_user_config=False):
45 + # use separate parsers to detect collisions properly
46 + cfp_kwargs = {}
47 + if sys.hexversion >= 0x03020000:
48 + cfp_kwargs['strict'] = False
49 + parser = SafeConfigParser(dict_type=MultiValueConfigParserDict,
50 + **cfp_kwargs)
51 + try:
52 + read_configs(parser, [path])
53 + except ConfigParserError as e:
54 + writemsg(
55 + _("!!! Error while reading %s: %s\n") % (path, e),
56 + noiselevel=-1)
57 + return
58 +
59 + for sname in parser.sections():
60 + if not is_user_config and sname in self._groups:
61 + writemsg(
62 + _("!!! Error while reading %s: duplicate group %s found\n") % (path, sname),
63 + noiselevel=-1)
64 + continue
65 + if not parser.has_option(sname, 'path'):
66 + continue
67 +
68 + paths = parser.get(sname, 'path').split('\n')
69 + self._groups[sname] = paths
70 +
71 + def expand_group(self, gname):
72 + return self._groups[gname]
73 diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py
74 index 9d13703..dfbd7f2 100644
75 --- a/pym/portage/package/ebuild/config.py
76 +++ b/pym/portage/package/ebuild/config.py
77 @@ -60,6 +60,7 @@ from portage.package.ebuild._config.features_set import features_set
78 from portage.package.ebuild._config.KeywordsManager import KeywordsManager
79 from portage.package.ebuild._config.LicenseManager import LicenseManager
80 from portage.package.ebuild._config.UseManager import UseManager
81 +from portage.package.ebuild._config.InstallMaskManager import InstallMaskManager
82 from portage.package.ebuild._config.LocationsManager import LocationsManager
83 from portage.package.ebuild._config.MaskManager import MaskManager
84 from portage.package.ebuild._config.VirtualsManager import VirtualsManager
85 @@ -277,6 +278,7 @@ class config(object):
86 # force instantiation of lazy immutable objects when cloning, so
87 # that they're not instantiated more than once
88 self._keywords_manager_obj = clone._keywords_manager
89 + self._install_mask_manager_obj = clone._install_mask_manager
90 self._mask_manager_obj = clone._mask_manager
91
92 # shared mutable attributes
93 @@ -329,6 +331,7 @@ class config(object):
94 else:
95 # lazily instantiated objects
96 self._keywords_manager_obj = None
97 + self._install_mask_manager_obj = None
98 self._mask_manager_obj = None
99 self._virtuals_manager_obj = None
100
101 @@ -1032,6 +1035,15 @@ class config(object):
102 return self._keywords_manager_obj
103
104 @property
105 + def _install_mask_manager(self):
106 + if self._install_mask_manager_obj is None:
107 + self._install_mask_manager_obj = InstallMaskManager(
108 + self.repositories,
109 + self._locations_manager.abs_user_config,
110 + user_config=self.local_config)
111 + return self._install_mask_manager_obj
112 +
113 + @property
114 def _mask_manager(self):
115 if self._mask_manager_obj is None:
116 self._mask_manager_obj = MaskManager(self.repositories,
117 @@ -1774,7 +1786,8 @@ class config(object):
118 _eapi_cache.clear()
119
120 # Prepare the final value of INSTALL_MASK
121 - install_mask = self.get("INSTALL_MASK", "").split()
122 + install_mask = list(self._replace_install_mask_groups(
123 + self.get("INSTALL_MASK", "").split()))
124 if 'nodoc' in self.features:
125 install_mask.append("/usr/share/doc")
126 if 'noinfo' in self.features:
127 @@ -1782,6 +1795,25 @@ class config(object):
128 if 'noman' in self.features:
129 install_mask.append("/usr/share/man")
130 self.install_mask = install_mask
131 + print(install_mask)
132 +
133 + def _replace_install_mask_groups(self, vals):
134 + for v in vals:
135 + if v.startswith('@') or v.startswith('-@'):
136 + neg = '-' if v.startswith('-') else ''
137 + gname = v[2:] if neg else v[1:]
138 + for p in self._expand_install_mask_group(gname):
139 + yield '%s%s' % (neg, p)
140 + else:
141 + yield v
142 +
143 + def _expand_install_mask_group(self, gname):
144 + try:
145 + return self._install_mask_manager.expand_group(gname)
146 + except KeyError:
147 + writemsg(_("!!! Undefined INSTALL_MASK group: '%s'!\n")
148 + % gname, noiselevel=-1)
149 + return ()
150
151 def _grab_pkg_env(self, penv, container, protected_keys=None):
152 if protected_keys is None:
153 diff --git a/pym/portage/util/configparser.py b/pym/portage/util/configparser.py
154 index c4c92a6..290bc5e 100644
155 --- a/pym/portage/util/configparser.py
156 +++ b/pym/portage/util/configparser.py
157 @@ -2,7 +2,8 @@
158 # Distributed under the terms of the GNU General Public License v2
159
160 __all__ = ['ConfigParserError', 'NoOptionError', 'ParsingError',
161 - 'RawConfigParser', 'SafeConfigParser', 'read_configs']
162 + 'RawConfigParser', 'SafeConfigParser', 'read_configs',
163 + 'MultiValueConfigParserDict']
164
165 # the following scary compatibility thing provides two classes:
166 # - SafeConfigParser that provides safe interpolation for values,
167 @@ -74,3 +75,19 @@ def read_configs(parser, paths):
168 read_file(p, **kwargs)
169 else:
170 raise TypeError("Unsupported type %r of element %r of 'paths' argument" % (type(p), p))
171 +
172 +
173 +class MultiValueConfigParserDict(dict):
174 + """
175 + A special variant of dict that stores all subsequent values assigned
176 + to its keys as a list, and returns this list when retrieved. Meant
177 + to be used with ConfigParser to process multi-key config files.
178 + """
179 +
180 + def __setitem__(self, k, v):
181 + if isinstance(v, list):
182 + if not k in self:
183 + super(MultiValueConfigParserDict, self).__setitem__(k, [])
184 + self[k].extend(v)
185 + else:
186 + super(MultiValueConfigParserDict, self).__setitem__(k, v)
187 --
188 2.8.3

Replies