Gentoo Archives: gentoo-commits

From: "Fabian Groffen (grobian)" <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r11614 - in main/branches/prefix: bin doc/config pym/_emerge pym/portage pym/portage/sets
Date: Fri, 03 Oct 2008 17:09:04
Message-Id: E1KlnrN-0007Rl-1F@stork.gentoo.org
1 Author: grobian
2 Date: 2008-10-03 16:50:31 +0000 (Fri, 03 Oct 2008)
3 New Revision: 11614
4
5 Modified:
6 main/branches/prefix/bin/glsa-check
7 main/branches/prefix/doc/config/sets.docbook
8 main/branches/prefix/pym/_emerge/__init__.py
9 main/branches/prefix/pym/portage/glsa.py
10 main/branches/prefix/pym/portage/sets/__init__.py
11 Log:
12 Merged from trunk -r11580:11593
13
14 | 11581 | implement set arguments to reconfigure and create package |
15 | genone | sets on the commandline |
16
17 | 11582 | disable redefintion errors when updating the set definitions |
18 | genone | |
19
20 | 11583 | Properly process set arguments inside set expressions |
21 | genone | |
22
23 | 11584 | Add operator logic to sets.conf |
24 | genone | |
25
26 | 11585 | use ignorelist to avoid potential infite loop |
27 | genone | |
28
29 | 11586 | update set config documentation to include extend, remove and |
30 | genone | intersect options |
31
32 | 11587 | document AgeSet handler class |
33 | genone | |
34
35 | 11588 | account for DTD changes wrt 'revised' element (patch by |
36 | genone | Robert Buchholz <rbu@g.o>) |
37
38 | 11589 | also accept glsa-2.dtd as valid for GLSAs (patch by Robert |
39 | genone | Buchholz <rbu@g.o>) |
40
41 | 11590 | print dates in a consistent format (patch by Robert Buchholz |
42 | genone | <rbu@g.o>) |
43
44 | 11591 | sort summarylist output (patch by Robert Buchholz |
45 | genone | <rbu@g.o>) |
46
47 | 11592 | use summarylist for output of test mode when --verbose is |
48 | genone | given (patch by Robert Buchholz <rbu@g.o>) |
49
50 | 11593 | add support for slot dependencies (original patch by Robert |
51 | genone | Buchholz <rbu@g.o>) |
52
53
54 Modified: main/branches/prefix/bin/glsa-check
55 ===================================================================
56 --- main/branches/prefix/bin/glsa-check 2008-10-02 16:57:45 UTC (rev 11613)
57 +++ main/branches/prefix/bin/glsa-check 2008-10-03 16:50:31 UTC (rev 11614)
58 @@ -169,6 +169,7 @@
59 fd2.write(green("[U]")+" means the system is not affected and\n")
60 fd2.write(red("[N]")+" indicates that the system might be affected.\n\n")
61
62 + myglsalist.sort()
63 for myid in myglsalist:
64 try:
65 myglsa = Glsa(myid, portage.settings, vardb, portdb)
66 @@ -275,13 +276,13 @@
67 sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
68 continue
69 if myglsa.isVulnerable():
70 - if verbose:
71 - outputlist.append(str(myglsa.nr)+" ( "+myglsa.title+" ) ")
72 - else:
73 - outputlist.append(str(myglsa.nr))
74 + outputlist.append(str(myglsa.nr))
75 if len(outputlist) > 0:
76 sys.stderr.write("This system is affected by the following GLSAs:\n")
77 - sys.stdout.write("\n".join(outputlist)+"\n")
78 + if verbose:
79 + summarylist(outputlist)
80 + else:
81 + sys.stdout.write("\n".join(outputlist)+"\n")
82 else:
83 sys.stderr.write("This system is not affected by any of the listed GLSAs\n")
84 sys.exit(0)
85
86 Modified: main/branches/prefix/doc/config/sets.docbook
87 ===================================================================
88 --- main/branches/prefix/doc/config/sets.docbook 2008-10-02 16:57:45 UTC (rev 11613)
89 +++ main/branches/prefix/doc/config/sets.docbook 2008-10-03 16:50:31 UTC (rev 11614)
90 @@ -49,12 +49,21 @@
91 isn't stricly required, but it should always be used as the default
92 handler might be changed in future versions.</para></footnote>.
93 That option defines which handler class should be used to
94 - create the set. Other universal options available for single sets are
95 - <varname>name</varname> (which is usually not needed as the name
96 + create the set. Other universal options available for single sets are:
97 + <itemizedlist>
98 + <listitem><varname>name</varname> (which is usually not needed as the name
99 of the set is generated from the section name if <varname>name</varname>
100 - is missing) and <varname>world-candidate</varname>, which determines if
101 - given package should be added to the <varname>world</varname> set. Some
102 - handler classes might require additional options for their configuration,
103 + is missing)</listitem>
104 + <listitem><varname>world-candidate</varname>, which determines if
105 + given package should be added to the <varname>world</varname> set</listitem>
106 + <listitem><varname>extend</varname> to include the contents of other package sets
107 + </listitem>
108 + <listitem><varname>remove</varname> to remove the contents of other package sets
109 + </listitem>
110 + <listitem><varname>intersect</varname> to only include packages that are also
111 + included in one or more other package sets</listitem>
112 + </itemizedlist>
113 + Some handler classes might require additional options for their configuration,
114 these will be covered later in this chapter.
115 </para>
116 <para>
117 @@ -83,8 +92,10 @@
118 sets each section still requires the <varname>class</varname> option,
119 but to indicate that the section should generate multiple sets it's
120 also necessary to set the <varname>multiset</varname> option to
121 - <parameter>true</parameter>. The <varname>world-candidate</varname>
122 - option is also supported like with single sets.
123 + <parameter>true</parameter>. The <varname>world-candidate</varname>,
124 + <varname>extend</varname>, <varname>remove</varname> and
125 + <varname>intersect</varname> options are also supported like with
126 + single sets (they'll apply to all sets generated by the section).
127 </para>
128 <para>
129 As it doesn't make much sense to specify a single name for multiple sets
130 @@ -386,6 +397,32 @@
131 </sect3>
132 </sect2>
133
134 + <sect2 id='config-set-classes-AgeSet'>
135 + <title>portage.sets.dbapi.AgeSet</title>
136 + <para>
137 + Package sets created by this class will include installed packages that
138 + have been installed before / after a given date.
139 + </para>
140 +
141 + <sect3>
142 + <title>Single Set Configuration</title>
143 + <para>
144 + In single set configurations this class supports the following options:
145 + <itemizedlist>
146 + <listitem><varname>age</varname>: Optional, defaults to 7. Specifies
147 + the number of days passed since installation to use as cut-off point.
148 + </listitem>
149 + <listitem><varname>mode</varname>: Optional, defaults to "older". Must
150 + be either "older" or "newer" to select packages installed either
151 + before resp. after the cut-off-date given by <varname>age</varname>.
152 + E.g. the defaults will select all installed packages that have been
153 + installed more than one week ago.
154 + </listitem>
155 + </itemizedlist>
156 + </para>
157 + </sect3>
158 + </sect2>
159 +
160 <sect2 id='config-set-classes-CategorySet'>
161 <title>portage.sets.dbapi.CategorySet</title>
162 <para>
163
164 Modified: main/branches/prefix/pym/_emerge/__init__.py
165 ===================================================================
166 --- main/branches/prefix/pym/_emerge/__init__.py 2008-10-02 16:57:45 UTC (rev 11613)
167 +++ main/branches/prefix/pym/_emerge/__init__.py 2008-10-03 16:50:31 UTC (rev 11614)
168 @@ -13452,25 +13452,8 @@
169 retval = os.EX_OK
170 setconfig = root_config.setconfig
171
172 - # display errors that occured while loading the SetConfig instance
173 - for e in setconfig.errors:
174 - print colorize("BAD", "Error during set creation: %s" % e)
175 -
176 sets = setconfig.getSets()
177
178 - # emerge relies on the existance of sets with names "world" and "system"
179 - required_sets = ("world", "system")
180 -
181 - for s in required_sets:
182 - if s not in sets:
183 - msg = ["emerge: incomplete set configuration, " + \
184 - "no \"%s\" set defined" % s]
185 - msg.append(" sets defined: %s" % ", ".join(sets))
186 - for line in msg:
187 - sys.stderr.write(line + "\n")
188 - retval = 1
189 - unmerge_actions = ("unmerge", "prune", "clean", "depclean")
190 -
191 # In order to know exactly which atoms/sets should be added to the
192 # world file, the depgraph performs set expansion later. It will get
193 # confused about where the atoms came from if it's not allowed to
194 @@ -13485,12 +13468,65 @@
195 myfiles = newargs
196 del newargs
197 newargs = []
198 -
199 +
200 + # separators for set arguments
201 + ARG_START = "{"
202 + ARG_END = "}"
203 +
204 # WARNING: all operators must be of equal length
205 IS_OPERATOR = "/@"
206 DIFF_OPERATOR = "-@"
207 UNION_OPERATOR = "+@"
208
209 + for i in range(0, len(myfiles)):
210 + if myfiles[i].startswith(SETPREFIX):
211 + start = 0
212 + end = 0
213 + x = myfiles[i][len(SETPREFIX):]
214 + newset = ""
215 + while x:
216 + start = x.find(ARG_START)
217 + end = x.find(ARG_END)
218 + if start > 0 and start < end:
219 + namepart = x[:start]
220 + argpart = x[start+1:end]
221 +
222 + # TODO: implement proper quoting
223 + args = argpart.split(",")
224 + options = {}
225 + for a in args:
226 + if "=" in a:
227 + k, v = a.split("=", 1)
228 + options[k] = v
229 + else:
230 + options[a] = "True"
231 + setconfig.update(namepart, options)
232 + newset += (x[:start-len(namepart)]+namepart)
233 + x = x[end+len(ARG_END):]
234 + else:
235 + newset += x
236 + x = ""
237 + myfiles[i] = SETPREFIX+newset
238 +
239 + sets = setconfig.getSets()
240 +
241 + # display errors that occured while loading the SetConfig instance
242 + for e in setconfig.errors:
243 + print colorize("BAD", "Error during set creation: %s" % e)
244 +
245 + # emerge relies on the existance of sets with names "world" and "system"
246 + required_sets = ("world", "system")
247 +
248 + for s in required_sets:
249 + if s not in sets:
250 + msg = ["emerge: incomplete set configuration, " + \
251 + "no \"%s\" set defined" % s]
252 + msg.append(" sets defined: %s" % ", ".join(sets))
253 + for line in msg:
254 + sys.stderr.write(line + "\n")
255 + retval = 1
256 + unmerge_actions = ("unmerge", "prune", "clean", "depclean")
257 +
258 for a in myfiles:
259 if a.startswith(SETPREFIX):
260 # support simple set operations (intersection, difference and union)
261
262 Modified: main/branches/prefix/pym/portage/glsa.py
263 ===================================================================
264 --- main/branches/prefix/pym/portage/glsa.py 2008-10-02 16:57:45 UTC (rev 11613)
265 +++ main/branches/prefix/pym/portage/glsa.py 2008-10-03 16:50:31 UTC (rev 11614)
266 @@ -226,6 +226,8 @@
267 rValue = opMapping[versionNode.getAttribute("range")] \
268 + pkgname \
269 + "-" + getText(versionNode, format="strip")
270 + if "slot" in versionNode.attributes and versionNode.getAttribute("slot") != "*":
271 + rValue += ":"+versionNode.getAttribute("slot")
272 return str(rValue)
273
274 def makeVersion(versionNode):
275 @@ -239,8 +241,11 @@
276 @rtype: String
277 @return: the version string
278 """
279 - return opMapping[versionNode.getAttribute("range")] \
280 + rValue = opMapping[versionNode.getAttribute("range")] \
281 + getText(versionNode, format="strip")
282 + if "slot" in versionNode.attributes and versionNode.getAttribute("slot") != "*":
283 + rValue += ":"+versionNode.getAttribute("slot")
284 + return rValue
285
286 def match(atom, dbapi, match_type="default"):
287 """
288 @@ -283,9 +288,9 @@
289 @return: a list with the matching versions
290 """
291 if match_type == "default" or not hasattr(dbapi, "xmatch"):
292 - mylist = dbapi.match(re.sub("-r[0-9]+$", "", revisionAtom[2:]))
293 + mylist = dbapi.match(re.sub(r'-r[0-9]+(:[^ ]+)?$', r'\1', revisionAtom[2:]))
294 else:
295 - mylist = dbapi.xmatch(match_type, re.sub("-r[0-9]+$", "", revisionAtom[2:]))
296 + mylist = dbapi.xmatch(match_type, re.sub(r'-r[0-9]+(:[^ ]+)?$', r'\1', revisionAtom[2:]))
297 rValue = []
298 for v in mylist:
299 r1 = pkgsplit(v)[-1][1:]
300 @@ -353,6 +358,32 @@
301 rValue += "-"+c_pv[3]
302 return rValue
303
304 +def format_date(datestr):
305 + """
306 + Takes a date (announced, revised) date from a GLSA and formats
307 + it as readable text (i.e. "January 1, 2008").
308 +
309 + @type date: String
310 + @param date: the date string to reformat
311 + @rtype: String
312 + @return: a reformatted string, or the original string
313 + if it cannot be reformatted.
314 + """
315 + splitdate = datestr.split("-", 2)
316 + if len(splitdate) != 3:
317 + return datestr
318 +
319 + # This cannot raise an error as we use () instead of []
320 + splitdate = (int(x) for x in splitdate)
321 +
322 + from datetime import date
323 + try:
324 + d = date(*splitdate)
325 + except ValueError:
326 + return datestr
327 +
328 + # TODO We could format to local date format '%x' here?
329 + return d.strftime("%B %d, %Y")
330
331 # simple Exception classes to catch specific errors
332 class GlsaTypeException(Exception):
333 @@ -432,7 +463,11 @@
334 self.DOM = xml.dom.minidom.parse(myfile)
335 if not self.DOM.doctype:
336 raise GlsaTypeException(None)
337 - elif self.DOM.doctype.systemId != "http://www.gentoo.org/dtd/glsa.dtd":
338 + elif self.DOM.doctype.systemId == "http://www.gentoo.org/dtd/glsa.dtd":
339 + self.dtdversion = 0
340 + elif self.DOM.doctype.systemId == "http://www.gentoo.org/dtd/glsa-2.dtd":
341 + self.dtdversion = 2
342 + else:
343 raise GlsaTypeException(self.DOM.doctype.systemId)
344 myroot = self.DOM.getElementsByTagName("glsa")[0]
345 if self.type == "id" and myroot.getAttribute("id") != self.nr:
346 @@ -441,9 +476,27 @@
347 # the simple (single, required, top-level, #PCDATA) tags first
348 self.title = getText(myroot.getElementsByTagName("title")[0], format="strip")
349 self.synopsis = getText(myroot.getElementsByTagName("synopsis")[0], format="strip")
350 - self.announced = getText(myroot.getElementsByTagName("announced")[0], format="strip")
351 - self.revised = getText(myroot.getElementsByTagName("revised")[0], format="strip")
352 + self.announced = format_date(getText(myroot.getElementsByTagName("announced")[0], format="strip"))
353
354 + count = 1
355 + # Support both formats of revised:
356 + # <revised>December 30, 2007: 02</revised>
357 + # <revised count="2">2007-12-30</revised>
358 + revisedEl = myroot.getElementsByTagName("revised")[0]
359 + self.revised = getText(revisedEl, format="strip")
360 + if (revisedEl.attributes.has_key("count")):
361 + count = revisedEl.getAttribute("count")
362 + elif (self.revised.find(":") >= 0):
363 + (self.revised, count) = self.revised.split(":")
364 +
365 + self.revised = format_date(self.revised)
366 +
367 + try:
368 + self.count = int(count)
369 + except ValueError:
370 + # TODO should this rais a GlsaFormatException?
371 + self.count = 1
372 +
373 # now the optional and 0-n toplevel, #PCDATA tags and references
374 try:
375 self.access = getText(myroot.getElementsByTagName("access")[0], format="strip")
376 @@ -499,7 +552,7 @@
377 outstream.write((width*"=")+"\n")
378 outstream.write(wrap(self.synopsis, width, caption="Synopsis: ")+"\n")
379 outstream.write("Announced on: %s\n" % self.announced)
380 - outstream.write("Last revised on: %s\n\n" % self.revised)
381 + outstream.write("Last revised on: %s : %02d\n\n" % (self.revised, self.count))
382 if self.glsatype == "ebuild":
383 for k in self.packages.keys():
384 pkg = self.packages[k]
385 @@ -565,7 +618,7 @@
386 @rtype: Boolean
387 @returns: True if the GLSA was applied, False if not
388 """
389 - return (self.nr in get_applied_glsas())
390 + return (self.nr in get_applied_glsas(self.config))
391
392 def inject(self):
393 """
394
395 Modified: main/branches/prefix/pym/portage/sets/__init__.py
396 ===================================================================
397 --- main/branches/prefix/pym/portage/sets/__init__.py 2008-10-02 16:57:45 UTC (rev 11613)
398 +++ main/branches/prefix/pym/portage/sets/__init__.py 2008-10-03 16:50:31 UTC (rev 11614)
399 @@ -33,8 +33,30 @@
400 self._parsed = False
401 self.active = []
402
403 - def _parse(self):
404 - if self._parsed:
405 + def update(self, setname, options):
406 + self.errors = []
407 + if not setname in self.psets:
408 + options["name"] = setname
409 +
410 + # for the unlikely case that there is already a section with the requested setname
411 + import random
412 + while setname in self.sections():
413 + setname = "%08d" % random.randint(0, 10**10)
414 +
415 + self.add_section(setname)
416 + for k, v in options.items():
417 + self.set(setname, k, v)
418 + else:
419 + section = self.psets[setname].creator
420 + if self.has_option(section, "multiset") and self.getboolean(section, "multiset"):
421 + self.errors.append("Invalid request to reconfigure set '%s' generated by multiset section '%s'" % (setname, section))
422 + return
423 + for k, v in options.items():
424 + self.set(section, k, v)
425 + self._parse(update=True)
426 +
427 + def _parse(self, update=False):
428 + if self._parsed and not update:
429 return
430 for sname in self.sections():
431 # find classname for current section, default to file based sets
432 @@ -64,7 +86,7 @@
433 self.errors.append("Configuration error in section '%s': %s" % (sname, str(e)))
434 continue
435 for x in newsets:
436 - if x in self.psets:
437 + if x in self.psets and not update:
438 self.errors.append("Redefinition of set '%s' (sections: '%s', '%s')" % (x, self.psets[x].creator, sname))
439 newsets[x].creator = sname
440 if self.has_option(sname, "world-candidate") and not self.getboolean(sname, "world-candidate"):
441 @@ -78,7 +100,7 @@
442 setname = self.get(sname, "name")
443 except NoOptionError:
444 setname = sname
445 - if setname in self.psets:
446 + if setname in self.psets and not update:
447 self.errors.append("Redefinition of set '%s' (sections: '%s', '%s')" % (setname, self.psets[setname].creator, sname))
448 if hasattr(setclass, "singleBuilder"):
449 try:
450 @@ -101,14 +123,38 @@
451 def getSetAtoms(self, setname, ignorelist=None):
452 myset = self.getSets()[setname]
453 myatoms = myset.getAtoms()
454 +
455 + extend = set()
456 + remove = set()
457 + intersect = set()
458 +
459 if ignorelist is None:
460 ignorelist = set()
461 + if not setname in ignorelist:
462 + if self.has_option(myset.creator, "extend"):
463 + extend.update(self.get(myset.creator, "extend").split())
464 + if self.has_option(myset.creator, "remove"):
465 + remove.update(self.get(myset.creator, "remove").split())
466 + if self.has_option(myset.creator, "intersect"):
467 + intersect.update(self.get(myset.creator, "intersect").split())
468 +
469 ignorelist.add(setname)
470 for n in myset.getNonAtoms():
471 - if n[0] == SETPREFIX and n[1:] in self.psets:
472 - if n[1:] not in ignorelist:
473 - myatoms.update(self.getSetAtoms(n[1:],
474 - ignorelist=ignorelist))
475 + if n.startswith(SETPREFIX) and n[len(SETPREFIX):] in self.psets:
476 + extend.add(n[len(SETPREFIX):])
477 +
478 + for s in ignorelist:
479 + extend.discard(s)
480 + remove.discard(s)
481 + intersect.discard(s)
482 +
483 + for s in extend:
484 + myatoms.update(self.getSetAtoms(s, ignorelist=ignorelist))
485 + for s in remove:
486 + myatoms.difference_update(self.getSetAtoms(s, ignorelist=ignorelist))
487 + for s in intersect:
488 + myatoms.intersection_update(self.getSetAtoms(s, ignorelist=ignorelist))
489 +
490 return myatoms
491
492 def load_default_config(settings, trees):