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 |