diff options
author | dann frazier <dannf@debian.org> | 2006-08-17 00:30:54 +0000 |
---|---|---|
committer | dann frazier <dannf@debian.org> | 2006-08-17 00:30:54 +0000 |
commit | 83af1b5d5c8f7e018a003469f86f711158deb252 (patch) | |
tree | 1f0a82c943f1f2d1b8ac70f1c56631591208ac23 /scripts | |
parent | 8a0c0175a017301b997cfa0a8fc67b2f0888cf4c (diff) |
while i'm reorganizing, might as well move the scripts & dsa-texts
out of the active issues directory
ok - should be done for now - let me know if you'd prefer a different
organization
git-svn-id: svn+ssh://svn.debian.org/svn/kernel-sec@551 e094ebfe-e918-0410-adfb-c712417f3574
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/deb822.py | 182 | ||||
-rwxr-xr-x | scripts/html-report | 160 | ||||
-rwxr-xr-x | scripts/sync-pkg-list | 32 | ||||
-rwxr-xr-x | scripts/ubuntu-todo | 2 | ||||
-rwxr-xr-x | scripts/verify-report.pl | 70 |
5 files changed, 446 insertions, 0 deletions
diff --git a/scripts/deb822.py b/scripts/deb822.py new file mode 100755 index 00000000..a6432cc5 --- /dev/null +++ b/scripts/deb822.py @@ -0,0 +1,182 @@ +#!/usr/bin/python + +## Version: 0.20051107 + +import re, string + +class deb822: + def __init__(self, fp): + self.map = {} + self.keys = [] + single = re.compile("^(?P<key>\S+):\s+(?P<data>\S.*)$") + multi = re.compile("^(?P<key>\S+):\s*$") + multidata = re.compile("^\s(?P<data>.*)$") + ws = re.compile("^\s*$") + + curkey = None + content = "" + for line in fp.readlines(): + if ws.match(line): + if curkey: + self.map[curkey] = content[:-1] + curkey = None + content = "" + continue + + m = single.match(line) + if m: + if curkey: + self.map[curkey] = content[:-1] + curkey = m.group('key') + self.keys.append(curkey) + self.map[curkey] = m.group('data') + curkey = None + content = "" + continue + + m = multi.match(line) + if m: + if curkey: + self.map[curkey] = content[:-1] + curkey = m.group('key') + self.keys.append(curkey) + content = "\n" + continue + + m = multidata.match(line) + if m: + content = content + line + continue + + if curkey: + self.map[curkey] = content[:-1] + + def dump(self, fd): + for key in self.keys: + fd.write(key + ": " + self.map[key] + "\n") + + def isSingleLine(self, s): + if s.count("\n"): + return False + else: + return True + + def isMultiLine(self, s): + return not self.isSingleLine(s) + + def _mergeFields(self, s1, s2): + if not s2: + return s1 + if not s1: + return s2 + + if self.isSingleLine(s1) and self.isSingleLine(s2): + ## some fields are delimited by a single space, others + ## a comma followed by a space. this heuristic assumes + ## that there are multiple items in one of the string fields + ## so that we can pick up on the delimiter being used + delim = ' ' + if (s1 + s2).count(', '): + delim = ', ' + + L = (s1 + delim + s2).split(delim) + L.sort() + + prev = merged = L[0] + + for item in L[1:]: + ## skip duplicate entries + if item == prev: + continue + merged = merged + delim + item + prev = item + return merged + + if self.isMultiLine(s1) and self.isMultiLine(s2): + for item in s2.splitlines(True): + if item not in s1.splitlines(True): + s1 = s1 + "\n" + item + return s1 + + raise ValueError + + def mergeFields(self, key, d1, d2 = None): + ## this method can work in two ways - abstract that away + if d2 == None: + x1 = self + x2 = d1 + else: + x1 = d1 + x2 = d2 + + ## we only have to do work if both objects contain our key + ## otherwise, we just take the one that does, or raise an + ## exception if neither does + if key in x1.keys and key in x1.keys: + merged = self._mergeFields(x1.map[key], x2.map[key]) + elif key in x1.keys: + merged = x1[key] + elif key in x2.keys: + merged = x2[key] + else: + raise KeyError + + ## back to the two different ways - if this method was called + ## upon an object, update that object in place. + ## return nothing in this case, to make the author notice a + ## problem if she assumes the object itself will not be modified + if d2 == None: + self.map[key] = merged + return None + + return merged + + def hasField(self, key): + if key in self.keys: + return True + return False + + def addField(self, key, value): + if key in self.keys: + ## key is already there + raise KeyError + else: + self.keys.append(key) + self.map[key] = value + +## methods that changes and dsc files have in common +class _dscchanges(deb822): + """A base class; not intended for direct use""" + +## Specialty class for dealing with .dsc files +class dsc(_dscchanges): + def files(self): + fileList = [] + + for fileEntry in self.map["Files"].splitlines(): + file = {} + if fileEntry: + fields = fileEntry.split() + file["md5sum"] = fields[0] + file["size"] = fields[1] + file["name"] = fields[2] + fileList.append(file) + + return fileList + +class changes(_dscchanges): + def files(self): + fileList = [] + + for fileEntry in self.map["Files"].splitlines(): + file = {} + if fileEntry: + fields = fileEntry.split() + file["md5sum"] = fields[0] + file["size"] = fields[1] + file["section"] = fields[2] + file["priority"] = fields[3] + file["name"] = fields[4] + fileList.append(file) + + return fileList diff --git a/scripts/html-report b/scripts/html-report new file mode 100755 index 00000000..38ca25e5 --- /dev/null +++ b/scripts/html-report @@ -0,0 +1,160 @@ +#!/usr/bin/python2.4 + +import os, os.path, sys +import deb822, re + +TrackerDir = ".." + +## get an unsorted list of tracked issues +def trackedIssues(dir): + ignores = [ re.compile('~$'), + re.compile('^#.*#$'), + re.compile('^00'), + re.compile('\.patch$')] + + validpaths = [] + for f in os.listdir(dir): + nogood = False + for i in ignores: + if i.search(f): + nogood = True + break + if nogood: + continue + else: + validpaths.append(f) + + issues = [] + for f in validpaths: + path = os.path.join(dir, f) + if os.path.isfile(path): + issues.append(f) + return issues + +def trackedVersions(dir): + pkglist = os.path.join(dir, '00pkglist') + f = open(pkglist, 'r') + return f.read().split('\n')[:-1] + +def issueStatus(issue, version): + path = os.path.join(TrackerDir, issue) + i = deb822.deb822(open(path, 'r')) + if i.hasField(version): + return i.map[version] + else: + return None + +def statusMatrix(issues, versions): + Di = {} + for i in issues: + Dv = {} + for v in versions: + Dv[v] = issueStatus(i, v) + Di[i] = Dv + return Di + +## remaining functions create the HTML +def htmlHeader(): + sys.stdout.write('<html>\n') + sys.stdout.write('<head>\n') + sys.stdout.write(' <title>Debian Kernel Patch Tracker Status</title>\n') + sys.stdout.write('</head>\n') + sys.stdout.write('<body>\n') + sys.stdout.write('<h1><center>Debian Kernel Patch Tracker Status</center></h1>') + key = ''' + <table border=1> + <tr> + <td>Key</td> + </tr> + <tr> + <td bgcolor="green">Fixed or N/A - version is listed if specified</td> + </tr> + <tr> + <td bgcolor="lightgreen">Pending - version is listed if specified</td> + </tr> + <tr> + <td bgcolor="yellow">Needed</td> + </tr> + <tr> + <td bgcolor="orange">Ignored for a reason</td> + </tr> + </table>''' + sys.stdout.write(key) + sys.stdout.write('<BR>\n') + + +def htmlFooter(): + sys.stdout.write(' </body>\n') + sys.stdout.write('</html>\n') + +def tableHeader(columns): + ## populateTable() will assume columns should be filled out + ## in sort() order, so make sure our column names match + columns.sort() + sys.stdout.write("<table border=1>\n") + sys.stdout.write(" <tr>\n") + sys.stdout.write(" <td> </td>\n") + for c in columns: + sys.stdout.write(" <td>"+c+"</td>\n") + sys.stdout.write(" </tr>\n") + +def tableFooter(): + sys.stdout.write("</table>\n") + +## Parse a status string, and return an html table entry +def statusCell(status): + if not status: + return '<td color="grey">Unknown</td>' + + statusRe = re.compile("(?P<status>\S+)(\s*\((?P<ver>.*)\))?(\s*\[(?P<name>.*)\])?$") + + m = statusRe.match(status) + if m: + d = m.groupdict() + ver = name = "" + if d.has_key('ver') and d['ver']: + ver = d['ver'] + if d.has_key('name') and d['name']: + name = d['name'] + + if d['status'] == 'N/A': + return '<td bgcolor="green">N/A</td>' + elif d['status'] == "released": + return '<td bgcolor="green">' + ver + '</td>' + elif d['status'] == "pending": + return '<td bgcolor="lightgreen">' + ver + '</td>' + elif d['status'] == "needed": + return '<td bgcolor="yellow">' + ver + '</td>' + elif d['status'] == "ignored": + return '<td bgcolor="orange">' + ver + '</td>' + else: + return '<td bgcolor="grey">Unknown</td>' + +def populateTable(matrix): + issues = matrix.keys() + issues.sort() + + for i in issues: + versions = matrix[i].keys() + versions.sort() + sys.stdout.write(' <tr>\n') + sys.stdout.write(' <td>' + i + '</td>\n') + for v in versions: + cell = statusCell(matrix[i][v].strip()) + if cell: + sys.stdout.write(cell) + else: + sys.stderr.write("Error in field: " + i + ", " + v + "\n") + sys.stdout.write(' </tr>\n') + +if __name__ == '__main__': + ## Doing this in a separate stage means some unnecessary duplicate + ## opens & closes... but oh well - our data set isn't very large + issues = trackedIssues(TrackerDir) + versions = trackedVersions(TrackerDir) + + htmlHeader() + tableHeader(versions) + populateTable(statusMatrix(issues, versions)) + tableFooter() + htmlFooter() diff --git a/scripts/sync-pkg-list b/scripts/sync-pkg-list new file mode 100755 index 00000000..7702f6e9 --- /dev/null +++ b/scripts/sync-pkg-list @@ -0,0 +1,32 @@ +#!/usr/bin/python + +import sys +import deb822 +from optparse import OptionParser + +if __name__ == '__main__': + parser = OptionParser() + parser.add_option("-p", "--pkglist", dest="pkglist", + help="File containing list of packages being tracked", + metavar="PACKAGELIST") + (options, args) = parser.parse_args() + + if not options.pkglist: + sys.stderr.write("A package list must be specified, see --help") + sys.exit(1) + + f = open(options.pkglist, 'r') + pkglist = f.read().split() + f.close() + + for file in args: + f = open(file, 'r') + d = deb822.deb822(f) + f.close + for pkg in pkglist: + if not d.hasField(pkg): + d.addField(pkg, "") + f = open(file, 'w') + d.dump(f) + f.close() + diff --git a/scripts/ubuntu-todo b/scripts/ubuntu-todo new file mode 100755 index 00000000..a8f5c439 --- /dev/null +++ b/scripts/ubuntu-todo @@ -0,0 +1,2 @@ +#!/bin/sh -e +egrep '(hoary|breezy|dapper|edgy).*(needed|pending)' * diff --git a/scripts/verify-report.pl b/scripts/verify-report.pl new file mode 100755 index 00000000..b810b9c7 --- /dev/null +++ b/scripts/verify-report.pl @@ -0,0 +1,70 @@ +#!/usr/bin/perl -w +# Analyse patch-tracker entries +# Problems reported to stderr +# Suggested entrie printed to stdout +# Must be run in directory with patch-tracker entries +# +# (C) 2006 Horms <horms@verge.net.au> +# Released under the terms of the GNU GPL v2 + +use strict; + +my $BOILERPLATE = "00boilerplate"; + +sub readfile { + my ($file) = (@_); + my $l = []; + my $h = {}; + my $key = undef; + + open BP, "<$file" or die "Could not open \"$file\" for reading\n"; + while (<BP>) { + if (m/(^[a-zA-Z0-9.-]+:)(.*)/ and $1 ne "http:") { + $key = $1; + push @$l , $1; + $h->{"$1"} = $2 . "\n"; + } + elsif (defined $key) { + $h->{"$key"} .= $_; + } + else { + print STDERR "Leading crap: $_"; + } + } + close BP; + + return ($l, $h); +} + +{ + my $bp_l; + my $bp_h; + my $l; + my $h; + + ($bp_l, $bp_h) = readfile($BOILERPLATE); + + foreach my $f (@ARGV) { + ($l, $h) = readfile($f); + my $log_p = (scalar @ARGV > 1) ? "$f: " : ""; + for my $i (@$bp_l) { + if (defined $h->{"$i"}) { + print $i . $h->{"$i"}; + delete $h->{"$i"}; + } + else { + print STDERR $log_p . "Missing Field: \"$i\"\n"; + print $i . " XXX\n"; + } + } + for my $i (keys %$h) { + print STDERR $log_p . "Extra Feild: \"$i\"\n"; + if (defined $h->{"$i"}) { + print $i . $h->{"$i"}; + } + else { + print $i . " XXX\n"; + } + } + } +} |