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] Split @selected into @selected-packages and @selected-sets
Date: Sun, 30 Nov 2014 23:04:51
Message-Id: 1417388678-22901-1-git-send-email-mgorny@gentoo.org
1 Split the big @selected set into separate @selected-packages for plain
2 packages and @selected-sets for subsets. The @selected set is still
3 provided as compatibility wrapper for both, though the new sets are
4 preferred for more flexibility.
5 ---
6 bin/regenworld | 4 +-
7 cnf/sets/portage.conf | 7 +-
8 doc/config/sets.docbook | 18 +++--
9 man/emerge.1 | 16 +++--
10 pym/portage/_sets/__init__.py | 8 +++
11 pym/portage/_sets/files.py | 149 ++++++++++++++++++++++++++++--------------
12 6 files changed, 137 insertions(+), 65 deletions(-)
13
14 diff --git a/bin/regenworld b/bin/regenworld
15 index e07424d..eef4cfd 100755
16 --- a/bin/regenworld
17 +++ b/bin/regenworld
18 @@ -11,7 +11,7 @@ if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".porta
19 import portage
20 portage._internal_caller = True
21 from portage import os
22 -from portage._sets.files import StaticFileSet, WorldSelectedSet
23 +from portage._sets.files import StaticFileSet, WorldSelectedPackagesSet
24
25 import re
26 import tempfile
27 @@ -105,7 +105,7 @@ for mykey in biglist:
28 if not worldlist:
29 pass
30 else:
31 - existing_set = WorldSelectedSet(eroot)
32 + existing_set = WorldSelectedPackagesSet(eroot)
33 existing_set.load()
34
35 if not existing_set:
36 diff --git a/cnf/sets/portage.conf b/cnf/sets/portage.conf
37 index fd2c387..8ffcedc 100644
38 --- a/cnf/sets/portage.conf
39 +++ b/cnf/sets/portage.conf
40 @@ -9,10 +9,15 @@
41 class = portage.sets.base.DummyPackageSet
42 packages = @selected @system
43
44 -# Not much that could be changed for world, so better leave it alone
45 [selected]
46 class = portage.sets.files.WorldSelectedSet
47
48 +[selected-packages]
49 +class = portage.sets.files.WorldSelectedPackagesSet
50 +
51 +[selected-sets]
52 +class = portage.sets.files.WorldSelectedSetsSet
53 +
54 # Same as for world, though later portage versions might use a different class
55 [system]
56 class = portage.sets.profiles.PackagesSystemSet
57 diff --git a/doc/config/sets.docbook b/doc/config/sets.docbook
58 index 8f74412..cf8dcf3 100644
59 --- a/doc/config/sets.docbook
60 +++ b/doc/config/sets.docbook
61 @@ -71,9 +71,9 @@
62 class = portage.sets.base.DummyPackageSet
63 packages = @selected @system
64
65 - # The selected set
66 - [selected]
67 - class = portage.sets.files.WorldSelectedSet
68 + # The selected-packages set
69 + [selected-packages]
70 + class = portage.sets.files.WorldSelectedPackagesSet
71
72 # The classic system set
73 [system]
74 @@ -247,8 +247,16 @@
75 </sect3>
76 </sect2>
77
78 - <sect2 id='config-set-classes-WorldSelectedSet'>
79 - <title>portage.sets.files.WorldSelectedSet</title>
80 + <sect2 id='config-set-classes-WorldSelectedPackagesSet'>
81 + <title>portage.sets.files.WorldSelectedPackagesSet</title>
82 + <para>
83 + A minor variation of <classname>StaticFileSet</classname>, mainly for implementation
84 + reasons. It should never be used in user configurations as it's already configured
85 + by default, doesn't support any options and will eventually be removed in a future version.
86 + </para>
87 +
88 + <sect2 id='config-set-classes-WorldSelectedSetsSet'>
89 + <title>portage.sets.files.WorldSelectedSetsSet</title>
90 <para>
91 A minor variation of <classname>StaticFileSet</classname>, mainly for implementation
92 reasons. It should never be used in user configurations as it's already configured
93 diff --git a/man/emerge.1 b/man/emerge.1
94 index a206e8e..91697b4 100644
95 --- a/man/emerge.1
96 +++ b/man/emerge.1
97 @@ -61,13 +61,15 @@ would like to query the owners of one or more files or directories.
98 .TP
99 .BR set
100 A \fIset\fR is a convenient shorthand for a large group of
101 -packages. Three sets are currently always available: \fBselected\fR,
102 -\fBsystem\fR and \fBworld\fR. \fBselected\fR contains the user-selected
103 -"world" packages that are listed in \fB/var/lib/portage/world\fR,
104 -and nested sets that may be listed
105 -in \fB/var/lib/portage/world_sets\fR. \fBsystem\fR refers to a set of
106 -packages deemed necessary for your system to run properly. \fBworld\fR
107 -encompasses both the \fBselected\fR and \fBsystem\fR sets. [See
108 +packages. Five sets are currently always available: \fBselected-packages\fR,
109 +\fBselected-sets\fR, \fBselected\fR, \fBsystem\fR and \fBworld\fR.
110 +\fBselected-packages\fR contains the user-selected "world" packages that
111 +are listed in \fB/var/lib/portage/world\fR, while \fBselected-sets\fR
112 +contains the nested sets that may be listed in \fB/var/lib/portage/world_sets\fR.
113 +\fBsystem\fR refers to a set of packages deemed necessary for your system
114 +to run properly. \fBselected\fR encompasses both the \fBselected-packages\fR
115 +and \fBselected-sets\fR sets, while \fBworld\fR encompasses the \fBselected\fR
116 +and \fBsystem\fR sets. [See
117 \fBFILES\fR below for more information.] Other sets can exist depending
118 on the current configuration. The default set configuration is located
119 in the \fB/usr/share/portage/config/sets\fR directory.
120 diff --git a/pym/portage/_sets/__init__.py b/pym/portage/_sets/__init__.py
121 index 75d1df7..a652227 100644
122 --- a/pym/portage/_sets/__init__.py
123 +++ b/pym/portage/_sets/__init__.py
124 @@ -121,6 +121,14 @@ class SetConfig(object):
125 parser.add_section("selected")
126 parser.set("selected", "class", "portage.sets.files.WorldSelectedSet")
127
128 + parser.remove_section("selected-packages")
129 + parser.add_section("selected-packages")
130 + parser.set("selected-packages", "class", "portage.sets.files.WorldSelectedPackagesSet")
131 +
132 + parser.remove_section("selected-sets")
133 + parser.add_section("selected-sets")
134 + parser.set("selected-sets", "class", "portage.sets.files.WorldSelectedSetsSet")
135 +
136 parser.remove_section("system")
137 parser.add_section("system")
138 parser.set("system", "class", "portage.sets.profiles.PackagesSystemSet")
139 diff --git a/pym/portage/_sets/files.py b/pym/portage/_sets/files.py
140 index 2fb64de..e76fa83 100644
141 --- a/pym/portage/_sets/files.py
142 +++ b/pym/portage/_sets/files.py
143 @@ -20,7 +20,8 @@ from portage.env.loaders import ItemFileLoader, KeyListFileLoader
144 from portage.env.validators import ValidAtomValidator
145 from portage import cpv_getkey
146
147 -__all__ = ["StaticFileSet", "ConfigFileSet", "WorldSelectedSet"]
148 +__all__ = ["StaticFileSet", "ConfigFileSet", "WorldSelectedSet",
149 + "WorldSelectedPackagesSet", "WorldSelectedSetsSet"]
150
151 class StaticFileSet(EditablePackageSet):
152 _operations = ["merge", "unmerge"]
153 @@ -205,41 +206,59 @@ class ConfigFileSet(PackageSet):
154 multiBuilder = classmethod(multiBuilder)
155
156 class WorldSelectedSet(EditablePackageSet):
157 - description = "Set of packages that were directly installed by the user"
158 -
159 + description = "Set of packages and subsets that were directly installed by the user"
160 +
161 def __init__(self, eroot):
162 super(WorldSelectedSet, self).__init__(allow_repo=True)
163 - # most attributes exist twice as atoms and non-atoms are stored in
164 - # separate files
165 + self._pkgset = WorldSelectedPackagesSet(eroot)
166 + self._setset = WorldSelectedSetsSet(eroot)
167 +
168 + def write(self):
169 + self._pkgset._atoms = self._atoms
170 + self._pkgset.write()
171 + self._setset._nonatoms = self._nonatoms
172 + self._setset.write()
173 +
174 + def load(self):
175 + self._pkgset.load()
176 + self._setset.load()
177 + self._setAtoms(self._pkgset._atoms | self._pkgset._nonatoms)
178 +
179 + def lock(self):
180 + self._pkgset.lock()
181 + self._setset.lock()
182 +
183 + def unlock(self):
184 + self._pkgset.unlock()
185 + self._setset.unlock()
186 +
187 + def cleanPackage(self, vardb, cpv):
188 + self._pkgset.cleanPackage(vardb, cpv)
189 +
190 + def singleBuilder(self, options, settings, trees):
191 + return WorldSelectedSet(settings["EROOT"])
192 + singleBuilder = classmethod(singleBuilder)
193 +
194 +class WorldSelectedPackagesSet(EditablePackageSet):
195 + description = "Set of packages that were directly installed by the user"
196 +
197 + def __init__(self, eroot):
198 + super(WorldSelectedPackagesSet, self).__init__(allow_repo=True)
199 self._lock = None
200 self._filename = os.path.join(eroot, WORLD_FILE)
201 self.loader = ItemFileLoader(self._filename, self._validate)
202 self._mtime = None
203 -
204 - self._filename2 = os.path.join(eroot, WORLD_SETS_FILE)
205 - self.loader2 = ItemFileLoader(self._filename2, self._validate2)
206 - self._mtime2 = None
207 -
208 +
209 def _validate(self, atom):
210 return ValidAtomValidator(atom, allow_repo=True)
211
212 - def _validate2(self, setname):
213 - return setname.startswith(SETPREFIX)
214 -
215 def write(self):
216 write_atomic(self._filename,
217 "".join(sorted("%s\n" % x for x in self._atoms)))
218
219 - write_atomic(self._filename2,
220 - "".join(sorted("%s\n" % x for x in self._nonatoms)))
221 -
222 def load(self):
223 atoms = []
224 - nonatoms = []
225 atoms_changed = False
226 - # load atoms and non-atoms from different files so the worldfile is
227 - # backwards-compatible with older versions and other PMs, even though
228 - # it's supposed to be private state data :/
229 try:
230 mtime = os.stat(self._filename).st_mtime
231 except (OSError, IOError):
232 @@ -261,36 +280,8 @@ class WorldSelectedSet(EditablePackageSet):
233 else:
234 atoms.extend(self._atoms)
235
236 - changed2, nonatoms = self._load2()
237 - atoms_changed |= changed2
238 -
239 if atoms_changed:
240 - self._setAtoms(atoms+nonatoms)
241 -
242 - def _load2(self):
243 - changed = False
244 - try:
245 - mtime = os.stat(self._filename2).st_mtime
246 - except (OSError, IOError):
247 - mtime = None
248 - if (not self._loaded or self._mtime2 != mtime):
249 - try:
250 - data, errors = self.loader2.load()
251 - for fname in errors:
252 - for e in errors[fname]:
253 - self.errors.append(fname+": "+e)
254 - except EnvironmentError as e:
255 - if e.errno != errno.ENOENT:
256 - raise
257 - del e
258 - data = {}
259 - nonatoms = list(data)
260 - self._mtime2 = mtime
261 - changed = True
262 - else:
263 - nonatoms = list(self._nonatoms)
264 -
265 - return changed, nonatoms
266 + self._setAtoms(atoms)
267
268 def _ensure_dirs(self):
269 ensure_dirs(os.path.dirname(self._filename), gid=portage_gid, mode=0o2750, mask=0o2)
270 @@ -338,5 +329,63 @@ class WorldSelectedSet(EditablePackageSet):
271 self.replace(newworldlist)
272
273 def singleBuilder(self, options, settings, trees):
274 - return WorldSelectedSet(settings["EROOT"])
275 + return WorldSelectedPackagesSet(settings["EROOT"])
276 + singleBuilder = classmethod(singleBuilder)
277 +
278 +class WorldSelectedSetsSet(EditablePackageSet):
279 + description = "Set of sets that were directly installed by the user"
280 +
281 + def __init__(self, eroot):
282 + super(WorldSelectedSetsSet, self).__init__(allow_repo=True)
283 + self._lock = None
284 + self._filename = os.path.join(eroot, WORLD_SETS_FILE)
285 + self.loader = ItemFileLoader(self._filename, self._validate)
286 + self._mtime = None
287 +
288 + def _validate(self, setname):
289 + return setname.startswith(SETPREFIX)
290 +
291 + def write(self):
292 + write_atomic(self._filename,
293 + "".join(sorted("%s\n" % x for x in self._nonatoms)))
294 +
295 + def load(self):
296 + atoms_changed = False
297 + try:
298 + mtime = os.stat(self._filename).st_mtime
299 + except (OSError, IOError):
300 + mtime = None
301 + if (not self._loaded or self._mtime != mtime):
302 + try:
303 + data, errors = self.loader.load()
304 + for fname in errors:
305 + for e in errors[fname]:
306 + self.errors.append(fname+": "+e)
307 + except EnvironmentError as e:
308 + if e.errno != errno.ENOENT:
309 + raise
310 + del e
311 + data = {}
312 + nonatoms = list(data)
313 + self._mtime = mtime
314 + atoms_changed = True
315 + else:
316 + nonatoms = list(self._nonatoms)
317 +
318 + if atoms_changed:
319 + self._setAtoms(nonatoms)
320 +
321 + def lock(self):
322 + if self._lock is not None:
323 + raise AssertionError("already locked")
324 + self._lock = lockfile(self._filename, wantnewlockfile=1)
325 +
326 + def unlock(self):
327 + if self._lock is None:
328 + raise AssertionError("not locked")
329 + unlockfile(self._lock)
330 + self._lock = None
331 +
332 + def singleBuilder(self, options, settings, trees):
333 + return WorldSelectedSetsSet(settings["EROOT"])
334 singleBuilder = classmethod(singleBuilder)
335 --
336 2.1.3

Replies