Gentoo Archives: gentoo-commits

From: "Zac Medico (zmedico)" <zmedico@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r12076 - in main/branches/2.1.6: bin pym/portage pym/portage/_sets pym/portage/tests
Date: Mon, 24 Nov 2008 02:57:58
Message-Id: E1L4Re6-0004v0-8J@stork.gentoo.org
1 Author: zmedico
2 Date: 2008-11-24 02:57:53 +0000 (Mon, 24 Nov 2008)
3 New Revision: 12076
4
5 Removed:
6 main/branches/2.1.6/bin/glsa-check
7 main/branches/2.1.6/pym/portage/_sets/dbapi.py
8 main/branches/2.1.6/pym/portage/_sets/libs.py
9 main/branches/2.1.6/pym/portage/_sets/security.py
10 main/branches/2.1.6/pym/portage/_sets/shell.py
11 main/branches/2.1.6/pym/portage/glsa.py
12 main/branches/2.1.6/pym/portage/tests/sets/
13 Log:
14 Remove unused package sets and glsa stuff.
15
16
17 Deleted: main/branches/2.1.6/bin/glsa-check
18 ===================================================================
19 --- main/branches/2.1.6/bin/glsa-check 2008-11-24 02:42:30 UTC (rev 12075)
20 +++ main/branches/2.1.6/bin/glsa-check 2008-11-24 02:57:53 UTC (rev 12076)
21 @@ -1,337 +0,0 @@
22 -#!/usr/bin/python
23 -
24 -# $Header: $
25 -# This program is licensed under the GPL, version 2
26 -
27 -import os
28 -import sys
29 -
30 -try:
31 - import portage
32 -except ImportError:
33 - from os import path as osp
34 - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
35 - import portage
36 -
37 -from portage.output import *
38 -
39 -from getopt import getopt, GetoptError
40 -
41 -__program__ = "glsa-check"
42 -__author__ = "Marius Mauch <genone@g.o>"
43 -__version__ = "1.0"
44 -
45 -optionmap = [
46 -["-l", "--list", "list all unapplied GLSA"],
47 -["-d", "--dump", "--print", "show all information about the given GLSA"],
48 -["-t", "--test", "test if this system is affected by the given GLSA"],
49 -["-p", "--pretend", "show the necessary commands to apply this GLSA"],
50 -["-f", "--fix", "try to auto-apply this GLSA (experimental)"],
51 -["-i", "--inject", "inject the given GLSA into the checkfile"],
52 -["-n", "--nocolor", "disable colors (option)"],
53 -["-e", "--emergelike", "do not use a least-change algorithm (option)"],
54 -["-h", "--help", "show this help message"],
55 -["-V", "--version", "some information about this tool"],
56 -["-v", "--verbose", "print more information (option)"],
57 -["-c", "--cve", "show CAN ids in listing mode (option)"],
58 -["-m", "--mail", "send a mail with the given GLSAs to the administrator"]
59 -]
60 -
61 -# option parsing
62 -args = []
63 -params = []
64 -try:
65 - args, params = getopt(sys.argv[1:], "".join([o[0][1] for o in optionmap]), \
66 - [x[2:] for x in reduce(lambda x,y: x+y, [z[1:-1] for z in optionmap])])
67 -# ["dump", "print", "list", "pretend", "fix", "inject", "help", "verbose", "version", "test", "nocolor", "cve", "mail"])
68 - args = [a for a,b in args]
69 -
70 - for option in ["--nocolor", "-n"]:
71 - if option in args:
72 - nocolor()
73 - args.remove(option)
74 -
75 - verbose = False
76 - for option in ["--verbose", "-v"]:
77 - if option in args:
78 - verbose = True
79 - args.remove(option)
80 -
81 - list_cve = False
82 - for option in ["--cve", "-c"]:
83 - if option in args:
84 - list_cve = True
85 - args.remove(option)
86 -
87 - least_change = True
88 - for option in ["--emergelike", "-e"]:
89 - if option in args:
90 - least_change = False
91 - args.remove(option)
92 -
93 - # sanity checking
94 - if len(args) <= 0:
95 - sys.stderr.write("no option given: what should I do ?\n")
96 - mode="help"
97 - elif len(args) > 1:
98 - sys.stderr.write("please use only one command per call\n")
99 - mode = "help"
100 - else:
101 - # in what mode are we ?
102 - args = args[0]
103 - for m in optionmap:
104 - if args in [o for o in m[:-1]]:
105 - mode = m[1][2:]
106 -
107 -except GetoptError, e:
108 - sys.stderr.write("unknown option given: ")
109 - sys.stderr.write(str(e)+"\n")
110 - mode = "help"
111 -
112 -# we need a set of glsa for most operation modes
113 -if len(params) <= 0 and mode in ["fix", "test", "pretend", "dump", "inject", "mail"]:
114 - sys.stderr.write("\nno GLSA given, so we'll do nothing for now. \n")
115 - sys.stderr.write("If you want to run on all GLSA please tell me so \n")
116 - sys.stderr.write("(specify \"all\" as parameter)\n\n")
117 - mode = "help"
118 -elif len(params) <= 0 and mode == "list":
119 - params.append("new")
120 -
121 -# show help message
122 -if mode == "help":
123 - sys.stderr.write("\nSyntax: glsa-check <option> [glsa-list]\n\n")
124 - for m in optionmap:
125 - sys.stderr.write(m[0] + "\t" + m[1] + " \t: " + m[-1] + "\n")
126 - for o in m[2:-1]:
127 - sys.stderr.write("\t" + o + "\n")
128 - sys.stderr.write("\nglsa-list can contain an arbitrary number of GLSA ids, \n")
129 - sys.stderr.write("filenames containing GLSAs or the special identifiers \n")
130 - sys.stderr.write("'all', 'new' and 'affected'\n")
131 - sys.exit(1)
132 -
133 -# we need root priviledges for write access
134 -if mode in ["fix", "inject"] and os.geteuid() != 0:
135 - sys.stderr.write("\nThis tool needs root access to "+mode+" this GLSA\n\n")
136 - sys.exit(2)
137 -
138 -# show version and copyright information
139 -if mode == "version":
140 - sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n")
141 - sys.stderr.write("Author: " + __author__ + "\n")
142 - sys.stderr.write("This program is licensed under the GPL, version 2\n\n")
143 - sys.exit(0)
144 -
145 -# delay this for speed increase
146 -from portage.glsa import *
147 -
148 -vardb = portage.db[portage.settings["ROOT"]]["vartree"].dbapi
149 -portdb = portage.db["/"]["porttree"].dbapi
150 -
151 -# build glsa lists
152 -completelist = get_glsa_list(portage.settings)
153 -
154 -checklist = get_applied_glsas(portage.settings)
155 -todolist = [e for e in completelist if e not in checklist]
156 -
157 -glsalist = []
158 -if "new" in params:
159 - glsalist = todolist
160 - params.remove("new")
161 -
162 -if "all" in params:
163 - glsalist = completelist
164 - params.remove("all")
165 -if "affected" in params:
166 - # replaced completelist with todolist on request of wschlich
167 - for x in todolist:
168 - try:
169 - myglsa = Glsa(x, portage.settings, vardb, portdb)
170 - except (GlsaTypeException, GlsaFormatException), e:
171 - if verbose:
172 - sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (x, e)))
173 - continue
174 - if myglsa.isVulnerable():
175 - glsalist.append(x)
176 - params.remove("affected")
177 -
178 -# remove invalid parameters
179 -for p in params[:]:
180 - if not (p in completelist or os.path.exists(p)):
181 - sys.stderr.write(("(removing %s from parameter list as it isn't a valid GLSA specification)\n" % p))
182 - params.remove(p)
183 -
184 -glsalist.extend([g for g in params if g not in glsalist])
185 -
186 -def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr):
187 - fd2.write(white("[A]")+" means this GLSA was already applied,\n")
188 - fd2.write(green("[U]")+" means the system is not affected and\n")
189 - fd2.write(red("[N]")+" indicates that the system might be affected.\n\n")
190 -
191 - myglsalist.sort()
192 - for myid in myglsalist:
193 - try:
194 - myglsa = Glsa(myid, portage.settings, vardb, portdb)
195 - except (GlsaTypeException, GlsaFormatException), e:
196 - if verbose:
197 - fd2.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
198 - continue
199 - if myglsa.isApplied():
200 - status = "[A]"
201 - color = white
202 - elif myglsa.isVulnerable():
203 - status = "[N]"
204 - color = red
205 - else:
206 - status = "[U]"
207 - color = green
208 -
209 - if verbose:
210 - access = ("[%-8s] " % myglsa.access)
211 - else:
212 - access=""
213 -
214 - fd1.write(color(myglsa.nr) + " " + color(status) + " " + color(access) + myglsa.title + " (")
215 - if not verbose:
216 - for pkg in myglsa.packages.keys()[:3]:
217 - fd1.write(" " + pkg + " ")
218 - if len(myglsa.packages) > 3:
219 - fd1.write("... ")
220 - else:
221 - for pkg in myglsa.packages.keys():
222 - mylist = vardb.match(portage.dep_getkey(pkg))
223 - if len(mylist) > 0:
224 - pkg = color(" ".join(mylist))
225 - fd1.write(" " + pkg + " ")
226 -
227 - fd1.write(")")
228 - if list_cve:
229 - fd1.write(" "+(",".join([r[:13] for r in myglsa.references if r[:4] in ["CAN-", "CVE-"]])))
230 - fd1.write("\n")
231 - return 0
232 -
233 -if mode == "list":
234 - sys.exit(summarylist(glsalist))
235 -
236 -# dump, fix, inject and fix are nearly the same code, only the glsa method call differs
237 -if mode in ["dump", "fix", "inject", "pretend"]:
238 - for myid in glsalist:
239 - try:
240 - myglsa = Glsa(myid, portage.settings, vardb, portdb)
241 - except (GlsaTypeException, GlsaFormatException), e:
242 - if verbose:
243 - sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
244 - continue
245 - if mode == "dump":
246 - myglsa.dump()
247 - elif mode == "fix":
248 - sys.stdout.write("fixing "+myid+"\n")
249 - mergelist = myglsa.getMergeList(least_change=least_change)
250 - for pkg in mergelist:
251 - sys.stdout.write(">>> merging "+pkg+"\n")
252 - # using emerge for the actual merging as it contains the dependency
253 - # code and we want to be consistent in behaviour. Also this functionality
254 - # will be integrated in emerge later, so it shouldn't hurt much.
255 - emergecmd = "emerge --oneshot " + portage.settings["EMERGE_OPTS"] + " =" + pkg
256 - if verbose:
257 - sys.stderr.write(emergecmd+"\n")
258 - exitcode = os.system(emergecmd)
259 - # system() returns the exitcode in the high byte of a 16bit integer
260 - if exitcode >= 1<<8:
261 - exitcode >>= 8
262 - if exitcode:
263 - sys.exit(exitcode)
264 - myglsa.inject()
265 - elif mode == "pretend":
266 - sys.stdout.write("Checking GLSA "+myid+"\n")
267 - mergelist = myglsa.getMergeList(least_change=least_change)
268 - if mergelist:
269 - sys.stdout.write("The following updates will be performed for this GLSA:\n")
270 - for pkg in mergelist:
271 - oldver = None
272 - for x in vardb.match(portage.dep_getkey(pkg)):
273 - if vardb.aux_get(x, ["SLOT"]) == portdb.aux_get(pkg, ["SLOT"]):
274 - oldver = x
275 - if oldver == None:
276 - raise ValueError("could not find old version for package %s" % pkg)
277 - oldver = oldver[len(portage.dep_getkey(oldver))+1:]
278 - sys.stdout.write(" " + pkg + " (" + oldver + ")\n")
279 - else:
280 - sys.stdout.write("Nothing to do for this GLSA\n")
281 - elif mode == "inject":
282 - sys.stdout.write("injecting " + myid + "\n")
283 - myglsa.inject()
284 - sys.stdout.write("\n")
285 - sys.exit(0)
286 -
287 -# test is a bit different as Glsa.test() produces no output
288 -if mode == "test":
289 - outputlist = []
290 - for myid in glsalist:
291 - try:
292 - myglsa = Glsa(myid, portage.settings, vardb, portdb)
293 - except (GlsaTypeException, GlsaFormatException), e:
294 - if verbose:
295 - sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
296 - continue
297 - if myglsa.isVulnerable():
298 - outputlist.append(str(myglsa.nr))
299 - if len(outputlist) > 0:
300 - sys.stderr.write("This system is affected by the following GLSAs:\n")
301 - if verbose:
302 - summarylist(outputlist)
303 - else:
304 - sys.stdout.write("\n".join(outputlist)+"\n")
305 - else:
306 - sys.stderr.write("This system is not affected by any of the listed GLSAs\n")
307 - sys.exit(0)
308 -
309 -# mail mode as requested by solar
310 -if mode == "mail":
311 - import portage.mail, socket
312 - from StringIO import StringIO
313 - from email.mime.text import MIMEText
314 -
315 - # color doesn't make any sense for mail
316 - nocolor()
317 -
318 - if "PORTAGE_ELOG_MAILURI" in portage.settings:
319 - myrecipient = portage.settings["PORTAGE_ELOG_MAILURI"].split()[0]
320 - else:
321 - myrecipient = "root@localhost"
322 -
323 - if "PORTAGE_ELOG_MAILFROM" in portage.settings:
324 - myfrom = portage.settings["PORTAGE_ELOG_MAILFROM"]
325 - else:
326 - myfrom = "glsa-check"
327 -
328 - mysubject = "[glsa-check] Summary for %s" % socket.getfqdn()
329 -
330 - # need a file object for summarylist()
331 - myfd = StringIO()
332 - myfd.write("GLSA Summary report for host %s\n" % socket.getfqdn())
333 - myfd.write("(Command was: %s)\n\n" % " ".join(sys.argv))
334 - summarylist(glsalist, fd1=myfd, fd2=myfd)
335 - summary = str(myfd.getvalue())
336 - myfd.close()
337 -
338 - myattachments = []
339 - for myid in glsalist:
340 - try:
341 - myglsa = Glsa(myid, portage.settings, vardb, portdb)
342 - except (GlsaTypeException, GlsaFormatException), e:
343 - if verbose:
344 - sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
345 - continue
346 - myfd = StringIO()
347 - myglsa.dump(outstream=myfd)
348 - myattachments.append(MIMEText(str(myfd.getvalue()), _charset="utf8"))
349 - myfd.close()
350 -
351 - mymessage = portage.mail.create_message(myfrom, myrecipient, mysubject, summary, myattachments)
352 - portage.mail.send_mail(portage.settings, mymessage)
353 -
354 - sys.exit(0)
355 -
356 -# something wrong here, all valid paths are covered with sys.exit()
357 -sys.stderr.write("nothing more to do\n")
358 -sys.exit(2)
359
360 Deleted: main/branches/2.1.6/pym/portage/_sets/dbapi.py
361 ===================================================================
362 --- main/branches/2.1.6/pym/portage/_sets/dbapi.py 2008-11-24 02:42:30 UTC (rev 12075)
363 +++ main/branches/2.1.6/pym/portage/_sets/dbapi.py 2008-11-24 02:57:53 UTC (rev 12076)
364 @@ -1,276 +0,0 @@
365 -# Copyright 2007 Gentoo Foundation
366 -# Distributed under the terms of the GNU General Public License v2
367 -# $Id$
368 -
369 -from portage.versions import catpkgsplit, catsplit, pkgcmp, best
370 -from portage.dep import Atom
371 -from portage._sets.base import PackageSet
372 -from portage._sets import SetConfigError, get_boolean
373 -
374 -__all__ = ["CategorySet", "DowngradeSet",
375 - "EverythingSet", "OwnerSet", "VariableSet"]
376 -
377 -class EverythingSet(PackageSet):
378 - _operations = ["merge"]
379 - description = "Package set which contains SLOT " + \
380 - "atoms to match all installed packages"
381 - _filter = None
382 -
383 - def __init__(self, vdbapi):
384 - super(EverythingSet, self).__init__()
385 - self._db = vdbapi
386 -
387 - def load(self):
388 - myatoms = []
389 - db_keys = ["SLOT"]
390 - aux_get = self._db.aux_get
391 - cp_list = self._db.cp_list
392 -
393 - for cp in self._db.cp_all():
394 - cpv_list = cp_list(cp)
395 -
396 - if len(cpv_list) > 1:
397 - for cpv in cpv_list:
398 - slot, = aux_get(cpv, db_keys)
399 - atom = Atom("%s:%s" % (cp, slot))
400 - if self._filter:
401 - if self._filter(atom):
402 - myatoms.append(atom)
403 - else:
404 - myatoms.append(atom)
405 -
406 - else:
407 - atom = Atom(cp)
408 - if self._filter:
409 - if self._filter(atom):
410 - myatoms.append(atom)
411 - else:
412 - myatoms.append(atom)
413 -
414 - self._setAtoms(myatoms)
415 -
416 - def singleBuilder(self, options, settings, trees):
417 - return EverythingSet(trees["vartree"].dbapi)
418 - singleBuilder = classmethod(singleBuilder)
419 -
420 -class OwnerSet(PackageSet):
421 -
422 - _operations = ["merge", "unmerge"]
423 -
424 - description = "Package set which contains all packages " + \
425 - "that own one or more files."
426 -
427 - def __init__(self, vardb=None, files=None):
428 - super(OwnerSet, self).__init__()
429 - self._db = vardb
430 - self._files = files
431 -
432 - def mapPathsToAtoms(self, paths):
433 - rValue = set()
434 - vardb = self._db
435 - aux_get = vardb.aux_get
436 - aux_keys = ["SLOT"]
437 - for link, p in vardb._owners.iter_owners(paths):
438 - cat, pn = catpkgsplit(link.mycpv)[:2]
439 - slot, = aux_get(link.mycpv, aux_keys)
440 - rValue.add("%s/%s:%s" % (cat, pn, slot))
441 - return rValue
442 -
443 - def load(self):
444 - self._setAtoms(self.mapPathsToAtoms(self._files))
445 -
446 - def singleBuilder(cls, options, settings, trees):
447 - if not "files" in options:
448 - raise SetConfigError("no files given")
449 -
450 - import shlex
451 - return cls(vardb=trees["vartree"].dbapi,
452 - files=frozenset(shlex.split(options["files"])))
453 -
454 - singleBuilder = classmethod(singleBuilder)
455 -
456 -class VariableSet(EverythingSet):
457 -
458 - _operations = ["merge", "unmerge"]
459 -
460 - description = "Package set which contains all packages " + \
461 - "that match specified values of a specified variable."
462 -
463 - def __init__(self, vardb, metadatadb=None, variable=None, includes=None, excludes=None):
464 - super(VariableSet, self).__init__(vardb)
465 - self._metadatadb = metadatadb
466 - self._variable = variable
467 - self._includes = includes
468 - self._excludes = excludes
469 -
470 - def _filter(self, atom):
471 - ebuild = best(self._metadatadb.match(atom))
472 - if not ebuild:
473 - return False
474 - values, = self._metadatadb.aux_get(ebuild, [self._variable])
475 - values = values.split()
476 - if self._includes and not self._includes.intersection(values):
477 - return False
478 - if self._excludes and self._excludes.intersection(values):
479 - return False
480 - return True
481 -
482 - def singleBuilder(cls, options, settings, trees):
483 -
484 - variable = options.get("variable")
485 - if variable is None:
486 - raise SetConfigError("missing required attribute: 'variable'")
487 -
488 - includes = options.get("includes", "")
489 - excludes = options.get("excludes", "")
490 -
491 - if not (includes or excludes):
492 - raise SetConfigError("no includes or excludes given")
493 -
494 - metadatadb = options.get("metadata-source", "vartree")
495 - if not metadatadb in trees.keys():
496 - raise SetConfigError("invalid value '%s' for option metadata-source" % metadatadb)
497 -
498 - return cls(trees["vartree"].dbapi,
499 - metadatadb=trees[metadatadb].dbapi,
500 - excludes=frozenset(excludes.split()),
501 - includes=frozenset(includes.split()),
502 - variable=variable)
503 -
504 - singleBuilder = classmethod(singleBuilder)
505 -
506 -class DowngradeSet(PackageSet):
507 -
508 - _operations = ["merge", "unmerge"]
509 -
510 - description = "Package set which contains all packages " + \
511 - "for which the highest visible ebuild version is lower than " + \
512 - "the currently installed version."
513 -
514 - def __init__(self, portdb=None, vardb=None):
515 - super(DowngradeSet, self).__init__()
516 - self._portdb = portdb
517 - self._vardb = vardb
518 -
519 - def load(self):
520 - atoms = []
521 - xmatch = self._portdb.xmatch
522 - xmatch_level = "bestmatch-visible"
523 - cp_list = self._vardb.cp_list
524 - aux_get = self._vardb.aux_get
525 - aux_keys = ["SLOT"]
526 - for cp in self._vardb.cp_all():
527 - for cpv in cp_list(cp):
528 - slot, = aux_get(cpv, aux_keys)
529 - slot_atom = "%s:%s" % (cp, slot)
530 - ebuild = xmatch(xmatch_level, slot_atom)
531 - if not ebuild:
532 - continue
533 - ebuild_split = catpkgsplit(ebuild)[1:]
534 - installed_split = catpkgsplit(cpv)[1:]
535 - if pkgcmp(installed_split, ebuild_split) > 0:
536 - atoms.append(slot_atom)
537 -
538 - self._setAtoms(atoms)
539 -
540 - def singleBuilder(cls, options, settings, trees):
541 - return cls(portdb=trees["porttree"].dbapi,
542 - vardb=trees["vartree"].dbapi)
543 -
544 - singleBuilder = classmethod(singleBuilder)
545 -
546 -class CategorySet(PackageSet):
547 - _operations = ["merge", "unmerge"]
548 -
549 - def __init__(self, category, dbapi, only_visible=True):
550 - super(CategorySet, self).__init__()
551 - self._db = dbapi
552 - self._category = category
553 - self._check = only_visible
554 - if only_visible:
555 - s="visible"
556 - else:
557 - s="all"
558 - self.description = "Package set containing %s packages of category %s" % (s, self._category)
559 -
560 - def load(self):
561 - myatoms = []
562 - for cp in self._db.cp_all():
563 - if catsplit(cp)[0] == self._category:
564 - if (not self._check) or len(self._db.match(cp)) > 0:
565 - myatoms.append(cp)
566 - self._setAtoms(myatoms)
567 -
568 - def _builderGetVisible(cls, options):
569 - return get_boolean(options, "only_visible", True)
570 - _builderGetVisible = classmethod(_builderGetVisible)
571 -
572 - def singleBuilder(cls, options, settings, trees):
573 - if not "category" in options:
574 - raise SetConfigError("no category given")
575 -
576 - category = options["category"]
577 - if not category in settings.categories:
578 - raise SetConfigError("invalid category name '%s'" % category)
579 -
580 - visible = cls._builderGetVisible(options)
581 -
582 - return CategorySet(category, dbapi=trees["porttree"].dbapi, only_visible=visible)
583 - singleBuilder = classmethod(singleBuilder)
584 -
585 - def multiBuilder(cls, options, settings, trees):
586 - rValue = {}
587 -
588 - if "categories" in options:
589 - categories = options["categories"].split()
590 - invalid = set(categories).difference(settings.categories)
591 - if invalid:
592 - raise SetConfigError("invalid categories: %s" % ", ".join(list(invalid)))
593 - else:
594 - categories = settings.categories
595 -
596 - visible = cls._builderGetVisible(options)
597 - name_pattern = options.get("name_pattern", "$category/*")
598 -
599 - if not "$category" in name_pattern and not "${category}" in name_pattern:
600 - raise SetConfigError("name_pattern doesn't include $category placeholder")
601 -
602 - for cat in categories:
603 - myset = CategorySet(cat, trees["porttree"].dbapi, only_visible=visible)
604 - myname = name_pattern.replace("$category", cat)
605 - myname = myname.replace("${category}", cat)
606 - rValue[myname] = myset
607 - return rValue
608 - multiBuilder = classmethod(multiBuilder)
609 -
610 -class AgeSet(EverythingSet):
611 - _operations = ["merge", "unmerge"]
612 -
613 - def __init__(self, vardb, mode="older", age=7):
614 - super(AgeSet, self).__init__(vardb)
615 - self._mode = mode
616 - self._age = age
617 -
618 - def _filter(self, atom):
619 - import time, os
620 -
621 - cpv = self._db.match(atom)[0]
622 - path = self._db.getpath(cpv, filename="COUNTER")
623 - age = (time.time() - os.stat(path).st_mtime) / (3600 * 24)
624 - if ((self._mode == "older" and age <= self._age) \
625 - or (self._mode == "newer" and age >= self._age)):
626 - return False
627 - else:
628 - return True
629 -
630 - def singleBuilder(cls, options, settings, trees):
631 - mode = options.get("mode", "older")
632 - if str(mode).lower() not in ["newer", "older"]:
633 - raise SetConfigError("invalid 'mode' value %s (use either 'newer' or 'older')" % mode)
634 - try:
635 - age = int(options.get("age", "7"))
636 - except ValueError, e:
637 - raise SetConfigError("value of option 'age' is not an integer")
638 - return AgeSet(vardb=trees["vartree"].dbapi, mode=mode, age=age)
639 -
640 - singleBuilder = classmethod(singleBuilder)
641
642 Deleted: main/branches/2.1.6/pym/portage/_sets/libs.py
643 ===================================================================
644 --- main/branches/2.1.6/pym/portage/_sets/libs.py 2008-11-24 02:42:30 UTC (rev 12075)
645 +++ main/branches/2.1.6/pym/portage/_sets/libs.py 2008-11-24 02:57:53 UTC (rev 12076)
646 @@ -1,23 +0,0 @@
647 -# Copyright 2007 Gentoo Foundation
648 -# Distributed under the terms of the GNU General Public License v2
649 -# $Id$
650 -
651 -from portage._sets.base import PackageSet
652 -from portage._sets import get_boolean
653 -from portage.versions import catpkgsplit
654 -
655 -class LibraryConsumerSet(PackageSet):
656 - _operations = ["merge", "unmerge"]
657 -
658 - def __init__(self, vardbapi, debug=False):
659 - super(LibraryConsumerSet, self).__init__()
660 - self.dbapi = vardbapi
661 - self.debug = debug
662 -
663 - def mapPathsToAtoms(self, paths):
664 - rValue = set()
665 - for link, p in self.dbapi._owners.iter_owners(paths):
666 - cat, pn = catpkgsplit(link.mycpv)[:2]
667 - slot = self.dbapi.aux_get(link.mycpv, ["SLOT"])[0]
668 - rValue.add("%s/%s:%s" % (cat, pn, slot))
669 - return rValue
670
671 Deleted: main/branches/2.1.6/pym/portage/_sets/security.py
672 ===================================================================
673 --- main/branches/2.1.6/pym/portage/_sets/security.py 2008-11-24 02:42:30 UTC (rev 12075)
674 +++ main/branches/2.1.6/pym/portage/_sets/security.py 2008-11-24 02:57:53 UTC (rev 12076)
675 @@ -1,89 +0,0 @@
676 -# Copyright 2007 Gentoo Foundation
677 -# Distributed under the terms of the GNU General Public License v2
678 -# $Id$
679 -
680 -import os
681 -import portage.glsa as glsa
682 -from portage.util import grabfile, write_atomic
683 -from portage._sets.base import PackageSet
684 -from portage.versions import catpkgsplit, pkgcmp
685 -from portage._sets import get_boolean
686 -
687 -__all__ = ["SecuritySet", "NewGlsaSet", "NewAffectedSet", "AffectedSet"]
688 -
689 -class SecuritySet(PackageSet):
690 - _operations = ["merge"]
691 - _skip_applied = False
692 -
693 - description = "package set that includes all packages possibly affected by a GLSA"
694 -
695 - def __init__(self, settings, vardbapi, portdbapi, least_change=True):
696 - super(SecuritySet, self).__init__()
697 - self._settings = settings
698 - self._vardbapi = vardbapi
699 - self._portdbapi = portdbapi
700 - self._least_change = least_change
701 -
702 - def getGlsaList(self, skip_applied):
703 - glsaindexlist = glsa.get_glsa_list(self._settings)
704 - if skip_applied:
705 - applied_list = glsa.get_applied_glsas(self._settings)
706 - glsaindexlist = set(glsaindexlist).difference(applied_list)
707 - glsaindexlist = list(glsaindexlist)
708 - glsaindexlist.sort()
709 - return glsaindexlist
710 -
711 - def load(self):
712 - glsaindexlist = self.getGlsaList(self._skip_applied)
713 - atomlist = []
714 - for glsaid in glsaindexlist:
715 - myglsa = glsa.Glsa(glsaid, self._settings, self._vardbapi, self._portdbapi)
716 - #print glsaid, myglsa.isVulnerable(), myglsa.isApplied(), myglsa.getMergeList()
717 - if self.useGlsa(myglsa):
718 - atomlist += ["="+x for x in myglsa.getMergeList(least_change=self._least_change)]
719 - self._setAtoms(self._reduce(atomlist))
720 -
721 - def _reduce(self, atomlist):
722 - mydict = {}
723 - for atom in atomlist[:]:
724 - cpv = self._portdbapi.xmatch("match-all", atom)[0]
725 - slot = self._portdbapi.aux_get(cpv, ["SLOT"])[0]
726 - cps = "/".join(catpkgsplit(cpv)[0:2]) + ":" + slot
727 - if not cps in mydict:
728 - mydict[cps] = (atom, cpv)
729 - else:
730 - other_cpv = mydict[cps][1]
731 - if pkgcmp(catpkgsplit(cpv)[1:], catpkgsplit(other_cpv)[1:]) > 0:
732 - atomlist.remove(mydict[cps][0])
733 - mydict[cps] = (atom, cpv)
734 - return atomlist
735 -
736 - def useGlsa(self, myglsa):
737 - return True
738 -
739 - def updateAppliedList(self):
740 - glsaindexlist = self.getGlsaList(True)
741 - applied_list = glsa.get_applied_glsas(self._settings)
742 - for glsaid in glsaindexlist:
743 - myglsa = glsa.Glsa(glsaid, self._settings, self._vardbapi, self._portdbapi)
744 - if not myglsa.isVulnerable() and not myglsa.nr in applied_list:
745 - myglsa.inject()
746 -
747 - def singleBuilder(cls, options, settings, trees):
748 - least_change = not get_boolean(options, "use_emerge_resolver", False)
749 - return cls(settings, trees["vartree"].dbapi, trees["porttree"].dbapi, least_change=least_change)
750 - singleBuilder = classmethod(singleBuilder)
751 -
752 -class NewGlsaSet(SecuritySet):
753 - _skip_applied = True
754 - description = "Package set that includes all packages possibly affected by an unapplied GLSA"
755 -
756 -class AffectedSet(SecuritySet):
757 - description = "Package set that includes all packages affected by an unapplied GLSA"
758 -
759 - def useGlsa(self, myglsa):
760 - return myglsa.isVulnerable()
761 -
762 -class NewAffectedSet(AffectedSet):
763 - _skip_applied = True
764 - description = "Package set that includes all packages affected by an unapplied GLSA"
765
766 Deleted: main/branches/2.1.6/pym/portage/_sets/shell.py
767 ===================================================================
768 --- main/branches/2.1.6/pym/portage/_sets/shell.py 2008-11-24 02:42:30 UTC (rev 12075)
769 +++ main/branches/2.1.6/pym/portage/_sets/shell.py 2008-11-24 02:57:53 UTC (rev 12076)
770 @@ -1,44 +0,0 @@
771 -# Copyright 2007 Gentoo Foundation
772 -# Distributed under the terms of the GNU General Public License v2
773 -# $Id$
774 -
775 -import subprocess
776 -import os
777 -
778 -from portage._sets.base import PackageSet
779 -from portage._sets import SetConfigError
780 -
781 -__all__ = ["CommandOutputSet"]
782 -
783 -class CommandOutputSet(PackageSet):
784 - """This class creates a PackageSet from the output of a shell command.
785 - The shell command should produce one atom per line, that is:
786 -
787 - >>> atom1
788 - atom2
789 - ...
790 - atomN
791 -
792 - Args:
793 - name: A string that identifies the set.
794 - command: A string or sequence identifying the command to run
795 - (see the subprocess.Popen documentaion for the format)
796 - """
797 - _operations = ["merge", "unmerge"]
798 -
799 - def __init__(self, command):
800 - super(CommandOutputSet, self).__init__()
801 - self._command = command
802 - self.description = "Package set generated from output of '%s'" % self._command
803 -
804 - def load(self):
805 - pipe = subprocess.Popen(self._command, stdout=subprocess.PIPE, shell=True)
806 - if pipe.wait() == os.EX_OK:
807 - text = pipe.stdout.read()
808 - self._setAtoms(text.split("\n"))
809 -
810 - def singleBuilder(self, options, settings, trees):
811 - if not "command" in options:
812 - raise SetConfigError("no command specified")
813 - return CommandOutputSet(options["command"])
814 - singleBuilder = classmethod(singleBuilder)
815
816 Deleted: main/branches/2.1.6/pym/portage/glsa.py
817 ===================================================================
818 --- main/branches/2.1.6/pym/portage/glsa.py 2008-11-24 02:42:30 UTC (rev 12075)
819 +++ main/branches/2.1.6/pym/portage/glsa.py 2008-11-24 02:57:53 UTC (rev 12076)
820 @@ -1,673 +0,0 @@
821 -# Copyright 2003-2007 Gentoo Foundation
822 -# Distributed under the terms of the GNU General Public License v2
823 -# $Id$
824 -
825 -import os
826 -import sys
827 -import urllib
828 -import re
829 -import xml.dom.minidom
830 -
831 -from portage.versions import pkgsplit, catpkgsplit, pkgcmp, best
832 -from portage.util import grabfile
833 -from portage.const import CACHE_PATH
834 -
835 -# Note: the space for rgt and rlt is important !!
836 -# FIXME: use slot deps instead, requires GLSA format versioning
837 -opMapping = {"le": "<=", "lt": "<", "eq": "=", "gt": ">", "ge": ">=",
838 - "rge": ">=~", "rle": "<=~", "rgt": " >~", "rlt": " <~"}
839 -NEWLINE_ESCAPE = "!;\\n" # some random string to mark newlines that should be preserved
840 -SPACE_ESCAPE = "!;_" # some random string to mark spaces that should be preserved
841 -
842 -def get_applied_glsas(settings):
843 - """
844 - Return a list of applied or injected GLSA IDs
845 -
846 - @type settings: portage.config
847 - @param settings: portage config instance
848 - @rtype: list
849 - @return: list of glsa IDs
850 - """
851 - return grabfile(os.path.join(os.sep, settings["ROOT"], CACHE_PATH.lstrip(os.sep), "glsa"))
852 -
853 -
854 -# TODO: use the textwrap module instead
855 -def wrap(text, width, caption=""):
856 - """
857 - Wraps the given text at column I{width}, optionally indenting
858 - it so that no text is under I{caption}. It's possible to encode
859 - hard linebreaks in I{text} with L{NEWLINE_ESCAPE}.
860 -
861 - @type text: String
862 - @param text: the text to be wrapped
863 - @type width: Integer
864 - @param width: the column at which the text should be wrapped
865 - @type caption: String
866 - @param caption: this string is inserted at the beginning of the
867 - return value and the paragraph is indented up to
868 - C{len(caption)}.
869 - @rtype: String
870 - @return: the wrapped and indented paragraph
871 - """
872 - rValue = ""
873 - line = caption
874 - text = text.replace(2*NEWLINE_ESCAPE, NEWLINE_ESCAPE+" "+NEWLINE_ESCAPE)
875 - words = text.split()
876 - indentLevel = len(caption)+1
877 -
878 - for w in words:
879 - if line != "" and line[-1] == "\n":
880 - rValue += line
881 - line = " "*indentLevel
882 - if len(line)+len(w.replace(NEWLINE_ESCAPE, ""))+1 > width:
883 - rValue += line+"\n"
884 - line = " "*indentLevel+w.replace(NEWLINE_ESCAPE, "\n")
885 - elif w.find(NEWLINE_ESCAPE) >= 0:
886 - if len(line.strip()) > 0:
887 - rValue += line+" "+w.replace(NEWLINE_ESCAPE, "\n")
888 - else:
889 - rValue += line+w.replace(NEWLINE_ESCAPE, "\n")
890 - line = " "*indentLevel
891 - else:
892 - if len(line.strip()) > 0:
893 - line += " "+w
894 - else:
895 - line += w
896 - if len(line) > 0:
897 - rValue += line.replace(NEWLINE_ESCAPE, "\n")
898 - rValue = rValue.replace(SPACE_ESCAPE, " ")
899 - return rValue
900 -
901 -def get_glsa_list(myconfig):
902 - """
903 - Returns a list of all available GLSAs in the given repository
904 - by comparing the filelist there with the pattern described in
905 - the config.
906 -
907 - @type myconfig: portage.config
908 - @param myconfig: Portage settings instance
909 -
910 - @rtype: List of Strings
911 - @return: a list of GLSA IDs in this repository
912 - """
913 - rValue = []
914 -
915 - if "GLSA_DIR" in myconfig:
916 - repository = myconfig["GLSA_DIR"]
917 - else:
918 - repository = os.path.join(myconfig["PORTDIR"], "metadata", "glsa")
919 -
920 - if not os.access(repository, os.R_OK):
921 - return []
922 - dirlist = os.listdir(repository)
923 - prefix = "glsa-"
924 - suffix = ".xml"
925 -
926 - for f in dirlist:
927 - try:
928 - if f[:len(prefix)] == prefix:
929 - rValue.append(f[len(prefix):-1*len(suffix)])
930 - except IndexError:
931 - pass
932 - return rValue
933 -
934 -def getListElements(listnode):
935 - """
936 - Get all <li> elements for a given <ol> or <ul> node.
937 -
938 - @type listnode: xml.dom.Node
939 - @param listnode: <ul> or <ol> list to get the elements for
940 - @rtype: List of Strings
941 - @return: a list that contains the value of the <li> elements
942 - """
943 - rValue = []
944 - if not listnode.nodeName in ["ul", "ol"]:
945 - raise GlsaFormatException("Invalid function call: listnode is not <ul> or <ol>")
946 - for li in listnode.childNodes:
947 - if li.nodeType != xml.dom.Node.ELEMENT_NODE:
948 - continue
949 - rValue.append(getText(li, format="strip"))
950 - return rValue
951 -
952 -def getText(node, format):
953 - """
954 - This is the main parser function. It takes a node and traverses
955 - recursive over the subnodes, getting the text of each (and the
956 - I{link} attribute for <uri> and <mail>). Depending on the I{format}
957 - parameter the text might be formatted by adding/removing newlines,
958 - tabs and spaces. This function is only useful for the GLSA DTD,
959 - it's not applicable for other DTDs.
960 -
961 - @type node: xml.dom.Node
962 - @param node: the root node to start with the parsing
963 - @type format: String
964 - @param format: this should be either I{strip}, I{keep} or I{xml}
965 - I{keep} just gets the text and does no formatting.
966 - I{strip} replaces newlines and tabs with spaces and
967 - replaces multiple spaces with one space.
968 - I{xml} does some more formatting, depending on the
969 - type of the encountered nodes.
970 - @rtype: String
971 - @return: the (formatted) content of the node and its subnodes
972 - """
973 - rValue = ""
974 - if format in ["strip", "keep"]:
975 - if node.nodeName in ["uri", "mail"]:
976 - rValue += node.childNodes[0].data+": "+node.getAttribute("link")
977 - else:
978 - for subnode in node.childNodes:
979 - if subnode.nodeName == "#text":
980 - rValue += subnode.data
981 - else:
982 - rValue += getText(subnode, format)
983 - else:
984 - for subnode in node.childNodes:
985 - if subnode.nodeName == "p":
986 - for p_subnode in subnode.childNodes:
987 - if p_subnode.nodeName == "#text":
988 - rValue += p_subnode.data.strip()
989 - elif p_subnode.nodeName in ["uri", "mail"]:
990 - rValue += p_subnode.childNodes[0].data
991 - rValue += " ( "+p_subnode.getAttribute("link")+" )"
992 - rValue += NEWLINE_ESCAPE
993 - elif subnode.nodeName == "ul":
994 - for li in getListElements(subnode):
995 - rValue += "-"+SPACE_ESCAPE+li+NEWLINE_ESCAPE+" "
996 - elif subnode.nodeName == "ol":
997 - i = 0
998 - for li in getListElements(subnode):
999 - i = i+1
1000 - rValue += str(i)+"."+SPACE_ESCAPE+li+NEWLINE_ESCAPE+" "
1001 - elif subnode.nodeName == "code":
1002 - rValue += getText(subnode, format="keep").replace("\n", NEWLINE_ESCAPE)
1003 - if rValue[-1*len(NEWLINE_ESCAPE):] != NEWLINE_ESCAPE:
1004 - rValue += NEWLINE_ESCAPE
1005 - elif subnode.nodeName == "#text":
1006 - rValue += subnode.data
1007 - else:
1008 - raise GlsaFormatException("Invalid Tag found: ", subnode.nodeName)
1009 - if format == "strip":
1010 - rValue = rValue.strip(" \n\t")
1011 - rValue = re.sub("[\s]{2,}", " ", rValue)
1012 - return rValue.encode("utf_8")
1013 -
1014 -def getMultiTagsText(rootnode, tagname, format):
1015 - """
1016 - Returns a list with the text of all subnodes of type I{tagname}
1017 - under I{rootnode} (which itself is not parsed) using the given I{format}.
1018 -
1019 - @type rootnode: xml.dom.Node
1020 - @param rootnode: the node to search for I{tagname}
1021 - @type tagname: String
1022 - @param tagname: the name of the tags to search for
1023 - @type format: String
1024 - @param format: see L{getText}
1025 - @rtype: List of Strings
1026 - @return: a list containing the text of all I{tagname} childnodes
1027 - """
1028 - rValue = []
1029 - for e in rootnode.getElementsByTagName(tagname):
1030 - rValue.append(getText(e, format))
1031 - return rValue
1032 -
1033 -def makeAtom(pkgname, versionNode):
1034 - """
1035 - creates from the given package name and information in the
1036 - I{versionNode} a (syntactical) valid portage atom.
1037 -
1038 - @type pkgname: String
1039 - @param pkgname: the name of the package for this atom
1040 - @type versionNode: xml.dom.Node
1041 - @param versionNode: a <vulnerable> or <unaffected> Node that
1042 - contains the version information for this atom
1043 - @rtype: String
1044 - @return: the portage atom
1045 - """
1046 - rValue = opMapping[versionNode.getAttribute("range")] \
1047 - + pkgname \
1048 - + "-" + getText(versionNode, format="strip")
1049 - try:
1050 - slot = versionNode.getAttribute("slot").strip()
1051 - except KeyError:
1052 - pass
1053 - else:
1054 - if slot and slot != "*":
1055 - rValue += ":" + slot
1056 - return str(rValue)
1057 -
1058 -def makeVersion(versionNode):
1059 - """
1060 - creates from the information in the I{versionNode} a
1061 - version string (format <op><version>).
1062 -
1063 - @type versionNode: xml.dom.Node
1064 - @param versionNode: a <vulnerable> or <unaffected> Node that
1065 - contains the version information for this atom
1066 - @rtype: String
1067 - @return: the version string
1068 - """
1069 - rValue = opMapping[versionNode.getAttribute("range")] \
1070 - + getText(versionNode, format="strip")
1071 - try:
1072 - slot = versionNode.getAttribute("slot").strip()
1073 - except KeyError:
1074 - pass
1075 - else:
1076 - if slot and slot != "*":
1077 - rValue += ":" + slot
1078 - return rValue
1079 -
1080 -def match(atom, dbapi, match_type="default"):
1081 - """
1082 - wrapper that calls revisionMatch() or portage.dbapi.match() depending on
1083 - the given atom.
1084 -
1085 - @type atom: string
1086 - @param atom: a <~ or >~ atom or a normal portage atom that contains the atom to match against
1087 - @type dbapi: portage.dbapi
1088 - @param dbapi: one of the portage databases to use as information source
1089 - @type match_type: string
1090 - @param match_type: if != "default" passed as first argument to dbapi.xmatch
1091 - to apply the wanted visibility filters
1092 -
1093 - @rtype: list of strings
1094 - @return: a list with the matching versions
1095 - """
1096 - if atom[2] == "~":
1097 - return revisionMatch(atom, dbapi, match_type=match_type)
1098 - elif match_type == "default" or not hasattr(dbapi, "xmatch"):
1099 - return dbapi.match(atom)
1100 - else:
1101 - return dbapi.xmatch(match_type, atom)
1102 -
1103 -def revisionMatch(revisionAtom, dbapi, match_type="default"):
1104 - """
1105 - handler for the special >~, >=~, <=~ and <~ atoms that are supposed to behave
1106 - as > and < except that they are limited to the same version, the range only
1107 - applies to the revision part.
1108 -
1109 - @type revisionAtom: string
1110 - @param revisionAtom: a <~ or >~ atom that contains the atom to match against
1111 - @type dbapi: portage.dbapi
1112 - @param dbapi: one of the portage databases to use as information source
1113 - @type match_type: string
1114 - @param match_type: if != "default" passed as first argument to portdb.xmatch
1115 - to apply the wanted visibility filters
1116 -
1117 - @rtype: list of strings
1118 - @return: a list with the matching versions
1119 - """
1120 - if match_type == "default" or not hasattr(dbapi, "xmatch"):
1121 - if ":" in revisionAtom:
1122 - mylist = dbapi.match(re.sub(r'-r[0-9]+(:[^ ]+)?$', r'\1', revisionAtom[2:]))
1123 - else:
1124 - mylist = dbapi.match(re.sub("-r[0-9]+$", "", revisionAtom[2:]))
1125 - else:
1126 - if ":" in revisionAtom:
1127 - mylist = dbapi.xmatch(match_type, re.sub(r'-r[0-9]+(:[^ ]+)?$', r'\1', revisionAtom[2:]))
1128 - else:
1129 - mylist = dbapi.xmatch(match_type, re.sub("-r[0-9]+$", "", revisionAtom[2:]))
1130 - rValue = []
1131 - for v in mylist:
1132 - r1 = pkgsplit(v)[-1][1:]
1133 - r2 = pkgsplit(revisionAtom[3:])[-1][1:]
1134 - if eval(r1+" "+revisionAtom[0:2]+" "+r2):
1135 - rValue.append(v)
1136 - return rValue
1137 -
1138 -
1139 -def getMinUpgrade(vulnerableList, unaffectedList, portdbapi, vardbapi, minimize=True):
1140 - """
1141 - Checks if the systemstate is matching an atom in
1142 - I{vulnerableList} and returns string describing
1143 - the lowest version for the package that matches an atom in
1144 - I{unaffectedList} and is greater than the currently installed
1145 - version or None if the system is not affected. Both
1146 - I{vulnerableList} and I{unaffectedList} should have the
1147 - same base package.
1148 -
1149 - @type vulnerableList: List of Strings
1150 - @param vulnerableList: atoms matching vulnerable package versions
1151 - @type unaffectedList: List of Strings
1152 - @param unaffectedList: atoms matching unaffected package versions
1153 - @type portdbapi: portage.dbapi.porttree.portdbapi
1154 - @param portdbapi: Ebuild repository
1155 - @type vardbapi: portage.dbapi.vartree.vardbapi
1156 - @param vardbapi: Installed package repository
1157 - @type minimize: Boolean
1158 - @param minimize: True for a least-change upgrade, False for emerge-like algorithm
1159 -
1160 - @rtype: String | None
1161 - @return: the lowest unaffected version that is greater than
1162 - the installed version.
1163 - """
1164 - rValue = None
1165 - v_installed = []
1166 - u_installed = []
1167 - for v in vulnerableList:
1168 - v_installed += match(v, vardbapi)
1169 -
1170 - for u in unaffectedList:
1171 - u_installed += match(u, vardbapi)
1172 -
1173 - install_unaffected = True
1174 - for i in v_installed:
1175 - if i not in u_installed:
1176 - install_unaffected = False
1177 -
1178 - if install_unaffected:
1179 - return rValue
1180 -
1181 - for u in unaffectedList:
1182 - mylist = match(u, portdbapi, match_type="match-all")
1183 - for c in mylist:
1184 - c_pv = catpkgsplit(c)
1185 - i_pv = catpkgsplit(best(v_installed))
1186 - if pkgcmp(c_pv[1:], i_pv[1:]) > 0 \
1187 - and (rValue == None \
1188 - or not match("="+rValue, portdbapi) \
1189 - or (minimize ^ (pkgcmp(c_pv[1:], catpkgsplit(rValue)[1:]) > 0)) \
1190 - and match("="+c, portdbapi)) \
1191 - and portdbapi.aux_get(c, ["SLOT"]) == vardbapi.aux_get(best(v_installed), ["SLOT"]):
1192 - rValue = c_pv[0]+"/"+c_pv[1]+"-"+c_pv[2]
1193 - if c_pv[3] != "r0": # we don't like -r0 for display
1194 - rValue += "-"+c_pv[3]
1195 - return rValue
1196 -
1197 -def format_date(datestr):
1198 - """
1199 - Takes a date (announced, revised) date from a GLSA and formats
1200 - it as readable text (i.e. "January 1, 2008").
1201 -
1202 - @type date: String
1203 - @param date: the date string to reformat
1204 - @rtype: String
1205 - @return: a reformatted string, or the original string
1206 - if it cannot be reformatted.
1207 - """
1208 - splitdate = datestr.split("-", 2)
1209 - if len(splitdate) != 3:
1210 - return datestr
1211 -
1212 - # This cannot raise an error as we use () instead of []
1213 - splitdate = (int(x) for x in splitdate)
1214 -
1215 - from datetime import date
1216 - try:
1217 - d = date(*splitdate)
1218 - except ValueError:
1219 - return datestr
1220 -
1221 - # TODO We could format to local date format '%x' here?
1222 - return d.strftime("%B %d, %Y")
1223 -
1224 -# simple Exception classes to catch specific errors
1225 -class GlsaTypeException(Exception):
1226 - def __init__(self, doctype):
1227 - Exception.__init__(self, "wrong DOCTYPE: %s" % doctype)
1228 -
1229 -class GlsaFormatException(Exception):
1230 - pass
1231 -
1232 -class GlsaArgumentException(Exception):
1233 - pass
1234 -
1235 -# GLSA xml data wrapper class
1236 -class Glsa:
1237 - """
1238 - This class is a wrapper for the XML data and provides methods to access
1239 - and display the contained data.
1240 - """
1241 - def __init__(self, myid, myconfig, vardbapi, portdbapi):
1242 - """
1243 - Simple constructor to set the ID, store the config and gets the
1244 - XML data by calling C{self.read()}.
1245 -
1246 - @type myid: String
1247 - @param myid: String describing the id for the GLSA object (standard
1248 - GLSAs have an ID of the form YYYYMM-nn) or an existing
1249 - filename containing a GLSA.
1250 - @type myconfig: portage.config
1251 - @param myconfig: the config that should be used for this object.
1252 - @type vardbapi: portage.dbapi.vartree.vardbapi
1253 - @param vardbapi: installed package repository
1254 - @type portdbapi: portage.dbapi.porttree.portdbapi
1255 - @param portdbapi: ebuild repository
1256 - """
1257 - if re.match(r'\d{6}-\d{2}', myid):
1258 - self.type = "id"
1259 - elif os.path.exists(myid):
1260 - self.type = "file"
1261 - else:
1262 - raise GlsaArgumentException("Given ID "+myid+" isn't a valid GLSA ID or filename.")
1263 - self.nr = myid
1264 - self.config = myconfig
1265 - self.vardbapi = vardbapi
1266 - self.portdbapi = portdbapi
1267 - self.read()
1268 -
1269 - def read(self):
1270 - """
1271 - Here we build the filename from the config and the ID and pass
1272 - it to urllib to fetch it from the filesystem or a remote server.
1273 -
1274 - @rtype: None
1275 - @return: None
1276 - """
1277 - if "GLSA_DIR" in self.config:
1278 - repository = "file://" + self.config["GLSA_DIR"]+"/"
1279 - else:
1280 - repository = "file://" + self.config["PORTDIR"] + "/metadata/glsa/"
1281 - if self.type == "file":
1282 - myurl = "file://"+self.nr
1283 - else:
1284 - myurl = repository + "glsa-%s.xml" % str(self.nr)
1285 - self.parse(urllib.urlopen(myurl))
1286 - return None
1287 -
1288 - def parse(self, myfile):
1289 - """
1290 - This method parses the XML file and sets up the internal data
1291 - structures by calling the different helper functions in this
1292 - module.
1293 -
1294 - @type myfile: String
1295 - @param myfile: Filename to grab the XML data from
1296 - @rtype: None
1297 - @returns: None
1298 - """
1299 - self.DOM = xml.dom.minidom.parse(myfile)
1300 - if not self.DOM.doctype:
1301 - raise GlsaTypeException(None)
1302 - elif self.DOM.doctype.systemId == "http://www.gentoo.org/dtd/glsa.dtd":
1303 - self.dtdversion = 0
1304 - elif self.DOM.doctype.systemId == "http://www.gentoo.org/dtd/glsa-2.dtd":
1305 - self.dtdversion = 2
1306 - else:
1307 - raise GlsaTypeException(self.DOM.doctype.systemId)
1308 - myroot = self.DOM.getElementsByTagName("glsa")[0]
1309 - if self.type == "id" and myroot.getAttribute("id") != self.nr:
1310 - raise GlsaFormatException("filename and internal id don't match:" + myroot.getAttribute("id") + " != " + self.nr)
1311 -
1312 - # the simple (single, required, top-level, #PCDATA) tags first
1313 - self.title = getText(myroot.getElementsByTagName("title")[0], format="strip")
1314 - self.synopsis = getText(myroot.getElementsByTagName("synopsis")[0], format="strip")
1315 - self.announced = format_date(getText(myroot.getElementsByTagName("announced")[0], format="strip"))
1316 -
1317 - count = 1
1318 - # Support both formats of revised:
1319 - # <revised>December 30, 2007: 02</revised>
1320 - # <revised count="2">2007-12-30</revised>
1321 - revisedEl = myroot.getElementsByTagName("revised")[0]
1322 - self.revised = getText(revisedEl, format="strip")
1323 - if (revisedEl.attributes.has_key("count")):
1324 - count = revisedEl.getAttribute("count")
1325 - elif (self.revised.find(":") >= 0):
1326 - (self.revised, count) = self.revised.split(":")
1327 -
1328 - self.revised = format_date(self.revised)
1329 -
1330 - try:
1331 - self.count = int(count)
1332 - except ValueError:
1333 - # TODO should this rais a GlsaFormatException?
1334 - self.count = 1
1335 -
1336 - # now the optional and 0-n toplevel, #PCDATA tags and references
1337 - try:
1338 - self.access = getText(myroot.getElementsByTagName("access")[0], format="strip")
1339 - except IndexError:
1340 - self.access = ""
1341 - self.bugs = getMultiTagsText(myroot, "bug", format="strip")
1342 - self.references = getMultiTagsText(myroot.getElementsByTagName("references")[0], "uri", format="keep")
1343 -
1344 - # and now the formatted text elements
1345 - self.description = getText(myroot.getElementsByTagName("description")[0], format="xml")
1346 - self.workaround = getText(myroot.getElementsByTagName("workaround")[0], format="xml")
1347 - self.resolution = getText(myroot.getElementsByTagName("resolution")[0], format="xml")
1348 - self.impact_text = getText(myroot.getElementsByTagName("impact")[0], format="xml")
1349 - self.impact_type = myroot.getElementsByTagName("impact")[0].getAttribute("type")
1350 - try:
1351 - self.background = getText(myroot.getElementsByTagName("background")[0], format="xml")
1352 - except IndexError:
1353 - self.background = ""
1354 -
1355 - # finally the interesting tags (product, affected, package)
1356 - self.glsatype = myroot.getElementsByTagName("product")[0].getAttribute("type")
1357 - self.product = getText(myroot.getElementsByTagName("product")[0], format="strip")
1358 - self.affected = myroot.getElementsByTagName("affected")[0]
1359 - self.packages = {}
1360 - for p in self.affected.getElementsByTagName("package"):
1361 - name = p.getAttribute("name")
1362 - if name not in self.packages:
1363 - self.packages[name] = []
1364 - tmp = {}
1365 - tmp["arch"] = p.getAttribute("arch")
1366 - tmp["auto"] = (p.getAttribute("auto") == "yes")
1367 - tmp["vul_vers"] = [makeVersion(v) for v in p.getElementsByTagName("vulnerable")]
1368 - tmp["unaff_vers"] = [makeVersion(v) for v in p.getElementsByTagName("unaffected")]
1369 - tmp["vul_atoms"] = [makeAtom(name, v) for v in p.getElementsByTagName("vulnerable")]
1370 - tmp["unaff_atoms"] = [makeAtom(name, v) for v in p.getElementsByTagName("unaffected")]
1371 - self.packages[name].append(tmp)
1372 - # TODO: services aren't really used yet
1373 - self.services = self.affected.getElementsByTagName("service")
1374 - return None
1375 -
1376 - def dump(self, outstream=sys.stdout):
1377 - """
1378 - Dumps a plaintext representation of this GLSA to I{outfile} or
1379 - B{stdout} if it is ommitted. You can specify an alternate
1380 - I{encoding} if needed (default is latin1).
1381 -
1382 - @type outstream: File
1383 - @param outfile: Stream that should be used for writing
1384 - (defaults to sys.stdout)
1385 - """
1386 - width = 76
1387 - outstream.write(("GLSA %s: \n%s" % (self.nr, self.title)).center(width)+"\n")
1388 - outstream.write((width*"=")+"\n")
1389 - outstream.write(wrap(self.synopsis, width, caption="Synopsis: ")+"\n")
1390 - outstream.write("Announced on: %s\n" % self.announced)
1391 - outstream.write("Last revised on: %s : %02d\n\n" % (self.revised, self.count))
1392 - if self.glsatype == "ebuild":
1393 - for k in self.packages.keys():
1394 - pkg = self.packages[k]
1395 - for path in pkg:
1396 - vul_vers = "".join(path["vul_vers"])
1397 - unaff_vers = "".join(path["unaff_vers"])
1398 - outstream.write("Affected package: %s\n" % k)
1399 - outstream.write("Affected archs: ")
1400 - if path["arch"] == "*":
1401 - outstream.write("All\n")
1402 - else:
1403 - outstream.write("%s\n" % path["arch"])
1404 - outstream.write("Vulnerable: %s\n" % vul_vers)
1405 - outstream.write("Unaffected: %s\n\n" % unaff_vers)
1406 - elif self.glsatype == "infrastructure":
1407 - pass
1408 - if len(self.bugs) > 0:
1409 - outstream.write("\nRelated bugs: ")
1410 - for i in range(0, len(self.bugs)):
1411 - outstream.write(self.bugs[i])
1412 - if i < len(self.bugs)-1:
1413 - outstream.write(", ")
1414 - else:
1415 - outstream.write("\n")
1416 - if self.background:
1417 - outstream.write("\n"+wrap(self.background, width, caption="Background: "))
1418 - outstream.write("\n"+wrap(self.description, width, caption="Description: "))
1419 - outstream.write("\n"+wrap(self.impact_text, width, caption="Impact: "))
1420 - outstream.write("\n"+wrap(self.workaround, width, caption="Workaround: "))
1421 - outstream.write("\n"+wrap(self.resolution, width, caption="Resolution: "))
1422 - myreferences = ""
1423 - for r in self.references:
1424 - myreferences += (r.replace(" ", SPACE_ESCAPE)+NEWLINE_ESCAPE+" ")
1425 - outstream.write("\n"+wrap(myreferences, width, caption="References: "))
1426 - outstream.write("\n")
1427 -
1428 - def isVulnerable(self):
1429 - """
1430 - Tests if the system is affected by this GLSA by checking if any
1431 - vulnerable package versions are installed. Also checks for affected
1432 - architectures.
1433 -
1434 - @rtype: Boolean
1435 - @returns: True if the system is affected, False if not
1436 - """
1437 - rValue = False
1438 - for k in self.packages.keys():
1439 - pkg = self.packages[k]
1440 - for path in pkg:
1441 - if path["arch"] == "*" or self.config["ARCH"] in path["arch"].split():
1442 - for v in path["vul_atoms"]:
1443 - rValue = rValue \
1444 - or (len(match(v, self.vardbapi)) > 0 \
1445 - and getMinUpgrade(path["vul_atoms"], path["unaff_atoms"], \
1446 - self.portdbapi, self.vardbapi))
1447 - return rValue
1448 -
1449 - def isApplied(self):
1450 - """
1451 - Looks if the GLSA IDis in the GLSA checkfile to check if this
1452 - GLSA was already applied.
1453 -
1454 - @rtype: Boolean
1455 - @returns: True if the GLSA was applied, False if not
1456 - """
1457 - return (self.nr in get_applied_glsas(self.config))
1458 -
1459 - def inject(self):
1460 - """
1461 - Puts the ID of this GLSA into the GLSA checkfile, so it won't
1462 - show up on future checks. Should be called after a GLSA is
1463 - applied or on explicit user request.
1464 -
1465 - @rtype: None
1466 - @returns: None
1467 - """
1468 - if not self.isApplied():
1469 - checkfile = open(os.path.join(os.sep, self.config["ROOT"], CACHE_PATH.lstrip(os.sep), "glsa"), "a+")
1470 - checkfile.write(self.nr+"\n")
1471 - checkfile.close()
1472 - return None
1473 -
1474 - def getMergeList(self, least_change=True):
1475 - """
1476 - Returns the list of package-versions that have to be merged to
1477 - apply this GLSA properly. The versions are as low as possible
1478 - while avoiding downgrades (see L{getMinUpgrade}).
1479 -
1480 - @type least_change: Boolean
1481 - @param least_change: True if the smallest possible upgrade should be selected,
1482 - False for an emerge-like algorithm
1483 - @rtype: List of Strings
1484 - @return: list of package-versions that have to be merged
1485 - """
1486 - rValue = []
1487 - for pkg in self.packages.keys():
1488 - for path in self.packages[pkg]:
1489 - update = getMinUpgrade(path["vul_atoms"], path["unaff_atoms"], \
1490 - self.portdbapi, self.vardbapi, minimize=least_change)
1491 - if update:
1492 - rValue.append(update)
1493 - return rValue