X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=fernanda.py;h=be6d767a168fb3eef59ce0b80ba8403d7e32b342;hb=9540d873fa78598454af57f5f8a4875969ed0439;hp=0de0234be1522e147c79b5e216cb2c14aebfd108;hpb=c846e77a848d60dd115f00faa0d9a854161d99eb;p=dak.git diff --git a/fernanda.py b/fernanda.py index 0de0234b..be6d767a 100755 --- a/fernanda.py +++ b/fernanda.py @@ -1,8 +1,8 @@ #!/usr/bin/env python # Script to automate some parts of checking NEW packages -# Copyright (C) 2000, 2001, 2002 James Troup -# $Id: fernanda.py,v 1.4 2002-10-16 02:47:32 troup Exp $ +# Copyright (C) 2000, 2001, 2002, 2003 James Troup +# $Id: fernanda.py,v 1.10 2003-11-10 23:01:17 troup Exp $ # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -35,15 +35,54 @@ import errno, os, re, sys import utils -import apt_pkg +import apt_pkg, apt_inst +import pg, db_access + +################################################################################ + +re_package = re.compile(r"^(.+?)_.*"); +re_doc_directory = re.compile(r".*/doc/([^/]*).*"); + +re_contrib = re.compile('^contrib/') +re_nonfree = re.compile('^non\-free/') + +re_arch = re.compile("Architecture: .*") +re_builddep = re.compile("Build-Depends: .*") +re_builddepind = re.compile("Build-Depends-Indep: .*") + +re_localhost = re.compile("localhost\.localdomain") +re_version = re.compile('^(.*)\((.*)\)') + +re_newlinespace = re.compile('\n') +re_spacestrip = re.compile('(\s)') + +################################################################################ + +# Colour definitions + +# Main +main_colour = "\033[36m"; +# Contrib +contrib_colour = "\033[33m"; +# Non-Free +nonfree_colour = "\033[31m"; +# Arch +arch_colour = "\033[32m"; +# End +end_colour = "\033[0m"; +# Bold +bold_colour = "\033[1m"; +# Bad maintainer +maintainer_colour = arch_colour; ################################################################################ Cnf = None; projectB = None; -re_package = re.compile(r"^(.+?)_.*"); -re_doc_directory = re.compile(r".*/doc/([^/]*).*"); +Cnf = utils.get_conf() +projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"])) +db_access.init(Cnf, projectB); ################################################################################ @@ -59,6 +98,193 @@ PACKAGE can be a .changes, .dsc, .deb or .udeb filename.""" ################################################################################ +def get_depends_parts(depend) : + v_match = re_version.match(depend) + if v_match: + d_parts = { 'name' : v_match.group(1), 'version' : v_match.group(2) } + else : + d_parts = { 'name' : depend , 'version' : '' } + return d_parts + +def get_or_list(depend) : + or_list = depend.split("|"); + return or_list + +def get_comma_list(depend) : + dep_list = depend.split(","); + return dep_list + +def split_depends (d_str) : + # creates a list of lists of dictionaries of depends (package,version relation) + + d_str = re_spacestrip.sub('',d_str); + depends_tree = []; + # first split depends string up amongs comma delimiter + dep_list = get_comma_list(d_str); + d = 0; + while d < len(dep_list): + # put depends into their own list + depends_tree.append([dep_list[d]]); + d += 1; + d = 0; + while d < len(depends_tree): + k = 0; + # split up Or'd depends into a multi-item list + depends_tree[d] = get_or_list(depends_tree[d][0]); + while k < len(depends_tree[d]): + # split depends into {package, version relation} + depends_tree[d][k] = get_depends_parts(depends_tree[d][k]); + k += 1; + d += 1; + return depends_tree; + +def read_control (filename): + recommends = []; + depends = []; + section = ''; + maintainer = ''; + arch = ''; + + deb_file = utils.open_file(filename); + try: + extracts = apt_inst.debExtractControl(deb_file); + control = apt_pkg.ParseSection(extracts); + except: + print "can't parse control info"; + control = ''; + + deb_file.close(); + + control_keys = control.keys(); + + if control.has_key("Depends"): + depends_str = control.Find("Depends"); + # create list of dependancy lists + depends = split_depends(depends_str); + + if control.has_key("Recommends"): + recommends_str = control.Find("Recommends"); + recommends = split_depends(recommends_str); + + if control.has_key("Section"): + section_str = control.Find("Section"); + + c_match = re_contrib.search(section_str) + nf_match = re_nonfree.search(section_str) + if c_match : + # contrib colour + section = contrib_colour + section_str + end_colour + elif nf_match : + # non-free colour + section = nonfree_colour + section_str + end_colour + else : + # main + section = main_colour + section_str + end_colour + if control.has_key("Architecture"): + arch_str = control.Find("Architecture") + arch = arch_colour + arch_str + end_colour + + if control.has_key("Maintainer"): + maintainer = control.Find("Maintainer") + localhost = re_localhost.search(maintainer) + if localhost: + #highlight bad email + maintainer = maintainer_colour + maintainer + end_colour; + + return (control, control_keys, section, depends, recommends, arch, maintainer) + +def read_dsc (dsc_filename): + dsc = {}; + + dsc_file = utils.open_file(dsc_filename); + try: + dsc = utils.parse_changes(dsc_filename); + except: + print "can't parse control info" + dsc_file.close(); + + filecontents = strip_pgp_signature(dsc_filename); + + if dsc.has_key("build-depends"): + builddep = split_depends(dsc["build-depends"]); + builddepstr = create_depends_string(builddep); + filecontents = re_builddep.sub("Build-Depends: "+builddepstr, filecontents); + + if dsc.has_key("build-depends-indep"): + builddepindstr = create_depends_string(split_depends(dsc["build-depends-indep"])); + filecontents = re_builddepind.sub("Build-Depends-Indep: "+builddepindstr, filecontents); + + if dsc.has_key("architecture") : + if (dsc["architecture"] != "any"): + newarch = arch_colour + dsc["architecture"] + end_colour; + filecontents = re_arch.sub("Architecture: " + newarch, filecontents); + + return filecontents; + +def create_depends_string (depends_tree): + # just look up unstable for now. possibly pull from .changes later + suite = "unstable"; + result = ""; + comma_count = 1; + for l in depends_tree: + if (comma_count >= 2): + result += ", "; + or_count = 1 + for d in l: + if (or_count >= 2 ): + result += " | " + # doesn't do version lookup yet. + + q = projectB.query("SELECT DISTINCT(b.package), b.version, c.name, su.suite_name FROM binaries b, files fi, location l, component c, bin_associations ba, suite su WHERE b.package='%s' AND b.file = fi.id AND fi.location = l.id AND l.component = c.id AND ba.bin=b.id AND ba.suite = su.id AND su.suite_name='%s' ORDER BY b.version desc" % (d['name'], suite)); + ql = q.getresult(); + if ql: + i = ql[0]; + + if i[2] == "contrib": + result += contrib_colour + d['name']; + elif i[2] == "non-free": + result += nonfree_colour + d['name']; + else : + result += main_colour + d['name']; + + if d['version'] != '' : + result += " (%s)" % (d['version']); + result += end_colour; + else: + result += bold_colour + d['name']; + if d['version'] != '' : + result += " (%s)" % (d['version']); + result += end_colour; + or_count += 1; + comma_count += 1; + return result; + +def output_deb_info(filename): + (control, control_keys, section, depends, recommends, arch, maintainer) = read_control(filename); + + if control == '': + print "no control info" + else: + for key in control_keys : + output = " " + key + ": " + if key == 'Depends': + output += create_depends_string(depends); + elif key == 'Recommends': + output += create_depends_string(recommends); + elif key == 'Section': + output += section; + elif key == 'Architecture': + output += arch; + elif key == 'Maintainer': + output += maintainer; + elif key == 'Description': + desc = control.Find(key); + desc = re_newlinespace.sub('\n ', desc); + output += desc; + else: + output += control.Find(key); + print output; + def do_command (command, filename): o = os.popen("%s %s" % (command, filename)); print o.read(); @@ -82,10 +308,8 @@ def print_copyright (deb_filename): def check_dsc (dsc_filename): print "---- .dsc file for %s ----" % (dsc_filename); - dsc_file = utils.open_file(dsc_filename); - for line in dsc_file.readlines(): - print line[:-1]; - print; + (dsc) = read_dsc(dsc_filename) + print dsc def check_deb (deb_filename): filename = os.path.basename(deb_filename); @@ -96,7 +320,8 @@ def check_deb (deb_filename): is_a_udeb = 0; print "---- control file for %s ----" % (filename); - do_command ("dpkg -I", deb_filename); + #do_command ("dpkg -I", deb_filename); + output_deb_info(deb_filename) if is_a_udeb: print "---- skipping lintian check for µdeb ----"; @@ -104,6 +329,8 @@ def check_deb (deb_filename): else: print "---- lintian check for %s ----" % (filename); do_command ("lintian", deb_filename); + print "---- linda check for %s ----" % (filename); + do_command ("linda", deb_filename); print "---- contents of %s ----" % (filename); do_command ("dpkg -c", deb_filename); @@ -117,13 +344,38 @@ def check_deb (deb_filename): print "---- file listing of %s ----" % (filename); do_command ("ls -l", deb_filename); -def display_changes (changes_filename): - print "---- .changes file for %s ----" % (changes_filename); - file = utils.open_file (changes_filename); +# Read a file, strip the signature and return the modified contents as +# a string. +def strip_pgp_signature (filename): + file = utils.open_file (filename); + contents = ""; + inside_signature = 0; + skip_next = 0; for line in file.readlines(): - print line[:-1] - print ; + if line[:-1] == "": + continue; + if inside_signature: + continue; + if skip_next: + skip_next = 0; + continue; + if line.startswith("-----BEGIN PGP SIGNED MESSAGE"): + skip_next = 1; + continue; + if line.startswith("-----BEGIN PGP SIGNATURE"): + inside_signature = 1; + continue; + if line.startswith("-----END PGP SIGNATURE"): + inside_signature = 0; + continue; + contents += line; file.close(); + return contents; + +# Display the .changes [without the signature] +def display_changes (changes_filename): + print "---- .changes file for %s ----" % (changes_filename); + print strip_pgp_signature(changes_filename); def check_changes (changes_filename): display_changes(changes_filename); @@ -140,7 +392,7 @@ def check_changes (changes_filename): def main (): global Cnf, projectB, db_files, waste, excluded; - Cnf = utils.get_conf() +# Cnf = utils.get_conf() Arguments = [('h',"help","Fernanda::Options::Help")]; for i in [ "help" ]: @@ -158,7 +410,8 @@ def main (): for file in args: try: # Pipe output for each argument through less - less_fd = os.popen("less -", 'w', 0); + less_fd = os.popen("less -R -", 'w', 0); + # -R added to display raw control chars for colour sys.stdout = less_fd; try: