Package: dak Version: 1.0-8.2 Severity: whishlist Tags: patch Hi,
as discussed on debian-project a while ago[1], I've prepared a patch to add a html-reporting capability to examine-package. I'm submitting this bug with patch to facilitate the tracking of the change. It would be nice if the ftp-master.debian.org information on the new queue could be expanded. I noticed that there are still a couple of bug-bugs (i.e. quite clearly programming errors, e.g. the "Frenanda" typo which adam also spotted, #395803) are still open. The attached patch fixes this as well as the future warning about encoding (displayed at least with python 2.4). Kind regards T. 1. http://lists.debian.org/debian-project/2006/10/msg00287.html -- Thomas Viehmann, http://thomas.viehmann.net/
=== modified file 'dak/examine_package.py' --- dak/examine_package.py 2006-05-18 21:27:34 +0000 +++ dak/examine_package.py 2006-11-12 17:24:50 +0000 @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: latin-1 -*- # Script to automate some parts of checking NEW packages # Copyright (C) 2000, 2001, 2002, 2003, 2006 James Troup <[EMAIL PROTECTED]> @@ -32,7 +33,7 @@ ################################################################################ -import errno, os, pg, re, sys +import errno, os, pg, re, sys, time import apt_pkg, apt_inst import daklib.database, daklib.utils @@ -56,25 +57,6 @@ ################################################################################ -# 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 @@ -89,10 +71,118 @@ Check NEW package(s). -h, --help show this help and exit + -H, --html-output output html page with inspection result PACKAGE can be a .changes, .dsc, .deb or .udeb filename.""" sys.exit(exit_code) +################################################################################ + +def html_header(name): + if name.endswith('.changes'): + name = ' '.join(name.split('_')[:2]) + print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + <html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">""" + print "<title>%s - Debian NEW package overview</title>"%name + print """<link type="text/css" rel="stylesheet" href="style.css"> + <link rel="shortcut icon" href="http://www.debian.org/favicon.ico"> + </head> + <body> + <div align="center"> + <a href="http://www.debian.org/"> + <img src="http://www.debian.org/logos/openlogo-nd-50.png" border="0" hspace="0" vspace="0" alt=""></a> + <a href="http://www.debian.org/"> + <img src="http://www.debian.org/Pics/debian.png" border="0" hspace="0" vspace="0" alt="Debian Project"></a> + </div> + <br /> + <table class="reddy" width="100%"> + <tr> + <td class="reddy"> + <img src="http://www.debian.org/Pics/red-upperleft.png" align="left" border="0" hspace="0" vspace="0" + alt="" width="15" height="16"></td>""" + print """<td rowspan="2" class="reddy">Debian NEW package overview for %s</td>"""%name + print """<td class="reddy"> + <img src="http://www.debian.org/Pics/red-upperright.png" align="right" border="0" hspace="0" vspace="0" + alt="" width="16" height="16"></td> + </tr> + <tr> + <td class="reddy"> + <img src="http://www.debian.org/Pics/red-lowerleft.png" align="left" border="0" hspace="0" vspace="0" + alt="" width="16" height="16"></td> + <td class="reddy"> + <img src="http://www.debian.org/Pics/red-lowerright.png" align="right" border="0" hspace="0" vspace="0" + alt="" width="15" height="16"></td> + </tr> + </table> + """ + +def html_footer(): + print "<p class=\"validate\">Timestamp: %s (UTC)</p>" % (time.strftime("%d.%m.%Y / %H:%M:%S", time.gmtime())) + print """<a href="http://validator.w3.org/check?uri=referer"> + <img border="0" src="http://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01!" height="31" width="88"></a> + <a href="http://jigsaw.w3.org/css-validator/check/referer"> + <img border="0" src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Valid CSS!" + height="31" width="88"></a> + """ + print "</body></html>" + +################################################################################ + +# probably xml.sax.saxutils would work as well + +html_escaping = {'"':'"', '&':'&', '<':'<', '>':'>'} +re_html_escaping = re.compile('|'.join(map(re.escape, html_escaping.keys()))) +def html_escape(s): + return re_html_escaping.sub(lambda x: html_escaping.get(x.group(0)), s) + +def escape_if_needed(s): + if Cnf["Examine-Package::Options::Html-Output"]: + return re_html_escaping.sub(html_escaping.get, s) + else: + return s + +def headline(s, level=2): + if Cnf["Examine-Package::Options::Html-Output"]: + print "<h%d>%s</h%d>" % (level,html_escape(s),level) + else: + print "---- %s ----" % (s) + +# Colour definitions, 'end' isn't really for use + +ansi_colours = { + 'main': "\033[36m", + 'contrib': "\033[33m", + 'nonfree': "\033[31m", + 'arch': "\033[32m", + 'end': "\033[0m", + 'bold': "\033[1m", + 'maintainer': "\033[32m"} + +html_colours = { + 'main': ('<span style="color: aqua">',"</span>"), + 'contrib': ('<span style="color: yellow">',"</span>"), + 'nonfree': ('<span style="color: red">',"</span>"), + 'arch': ('<span style="color: green">',"</span>"), + 'bold': ('<span style="font-weight: bold">',"</span>"), + 'maintainer': ('<span style="color: green">',"</span>")} + +def colour_output(s, colour): + if Cnf["Examine-Package::Options::Html-Output"]: + return ("%s%s%s" % (html_colours[colour][0], html_escape(s), html_colours[colour][1])) + else: + return ("%s%s%s" % (ansi_colours[colour], s, ansi_colours['end'])) + +def print_escaped_text(s): + if Cnf["Examine-Package::Options::Html-Output"]: + print "<pre>%s</pre>" % (s) + else: + print s + +def print_formatted_text(s): + if Cnf["Examine-Package::Options::Html-Output"]: + print "<pre>%s</pre>" % (html_escape(s)) + else: + print s ################################################################################ @@ -148,7 +238,8 @@ extracts = apt_inst.debExtractControl(deb_file) control = apt_pkg.ParseSection(extracts) except: - print "can't parse control info" + print_formatted_text("can't parse control info") + # TV-COMMENT: this will raise exceptions in two lines control = '' deb_file.close() @@ -171,23 +262,25 @@ nf_match = re_nonfree.search(section_str) if c_match : # contrib colour - section = contrib_colour + section_str + end_colour + section = colour_output(section_str, 'contrib') elif nf_match : # non-free colour - section = nonfree_colour + section_str + end_colour + section = colour_output(section_str, 'nonfree') else : # main - section = main_colour + section_str + end_colour + section = colour_output(section_str, 'main') if control.has_key("Architecture"): arch_str = control.Find("Architecture") - arch = arch_colour + arch_str + end_colour + arch = colour_output(arch_str, 'arch') 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 + maintainer = colour_output(maintainer, 'maintainer') + else: + maintainer = escape_if_needed(maintainer) return (control, control_keys, section, depends, recommends, arch, maintainer) @@ -198,10 +291,10 @@ try: dsc = daklib.utils.parse_changes(dsc_filename) except: - print "can't parse control info" + print_formatted_text("can't parse control info") dsc_file.close() - filecontents = strip_pgp_signature(dsc_filename) + filecontents = escape_if_needed(strip_pgp_signature(dsc_filename)) if dsc.has_key("build-depends"): builddep = split_depends(dsc["build-depends"]) @@ -214,7 +307,7 @@ if dsc.has_key("architecture") : if (dsc["architecture"] != "any"): - newarch = arch_colour + dsc["architecture"] + end_colour + newarch = colour_output(dsc["architecture"], 'arch') filecontents = re_arch.sub("Architecture: " + newarch, filecontents) return filecontents @@ -238,21 +331,21 @@ if ql: i = ql[0] + adepends = d['name'] + if d['version'] != '' : + adepends += " (%s)" % (d['version']) + if i[2] == "contrib": - result += contrib_colour + d['name'] + result += colour_output(adepends, "contrib") elif i[2] == "non-free": - result += nonfree_colour + d['name'] + result += colour_output(adepends, "nonfree") else : - result += main_colour + d['name'] - - if d['version'] != '' : - result += " (%s)" % (d['version']) - result += end_colour + result += colour_output(adepends, "main") else: - result += bold_colour + d['name'] + adepends = d['name'] if d['version'] != '' : - result += " (%s)" % (d['version']) - result += end_colour + adepends += " (%s)" % (d['version']) + result += colour_output(adepends, "bold") or_count += 1 comma_count += 1 return result @@ -261,7 +354,7 @@ (control, control_keys, section, depends, recommends, arch, maintainer) = read_control(filename) if control == '': - print "no control info" + print_formatted_text("no control info") else: for key in control_keys : output = " " + key + ": " @@ -278,14 +371,14 @@ elif key == 'Description': desc = control.Find(key) desc = re_newlinespace.sub('\n ', desc) - output += desc + output += escape_if_needed(desc) else: - output += control.Find(key) - print output + output += escape_if_needed(control.Find(key)) + print_escaped_text(output) def do_command (command, filename): o = os.popen("%s %s" % (command, filename)) - print o.read() + print_formatted_text(o.read()) def print_copyright (deb_filename): package = re_package.sub(r'\1', deb_filename) @@ -293,21 +386,21 @@ copyright = o.read()[:-1] if copyright == "": - print "WARNING: No copyright found, please check package manually." + print_formatted_text("WARNING: No copyright found, please check package manually.") return doc_directory = re_doc_directory.sub(r'\1', copyright) if package != doc_directory: - print "WARNING: wrong doc directory (expected %s, got %s)." % (package, doc_directory) + print_formatted_text("WARNING: wrong doc directory (expected %s, got %s)." % (package, doc_directory)) return o = os.popen("ar p %s data.tar.gz | tar xzOf - %s" % (deb_filename, copyright)) - print o.read() + print_formatted_text(o.read()) def check_dsc (dsc_filename): - print "---- .dsc file for %s ----" % (dsc_filename) + headline(".dsc file for %s" % (dsc_filename)) (dsc) = read_dsc(dsc_filename) - print dsc + print_escaped_text(dsc) def check_deb (deb_filename): filename = os.path.basename(deb_filename) @@ -317,29 +410,29 @@ else: is_a_udeb = 0 - print "---- control file for %s ----" % (filename) + headline("control file for %s" % (filename)) #do_command ("dpkg -I", deb_filename) output_deb_info(deb_filename) if is_a_udeb: - print "---- skipping lintian check for µdeb ----" + headline("skipping lintian check for µdeb") print else: - print "---- lintian check for %s ----" % (filename) + headline("lintian check for %s" % (filename)) do_command ("lintian", deb_filename) - print "---- linda check for %s ----" % (filename) + headline("linda check for %s" % (filename)) do_command ("linda", deb_filename) - print "---- contents of %s ----" % (filename) + headline("contents of %s" % (filename)) do_command ("dpkg -c", deb_filename) if is_a_udeb: - print "---- skipping copyright for µdeb ----" + headline("skipping copyright for µdeb") else: - print "---- copyright of %s ----" % (filename) + headline("copyright of %s" % (filename)) print_copyright(deb_filename) - print "---- file listing of %s ----" % (filename) + headline("file listing of %s" % (filename)) do_command ("ls -l", deb_filename) # Read a file, strip the signature and return the modified contents as @@ -372,8 +465,8 @@ # Display the .changes [without the signature] def display_changes (changes_filename): - print "---- .changes file for %s ----" % (changes_filename) - print strip_pgp_signature(changes_filename) + headline(".changes file for %s" % (changes_filename)) + print_formatted_text(strip_pgp_signature(changes_filename)) def check_changes (changes_filename): display_changes(changes_filename) @@ -392,9 +485,10 @@ # Cnf = daklib.utils.get_conf() - Arguments = [('h',"help","Examine-Package::Options::Help")] - for i in [ "help" ]: - if not Cnf.has_key("Frenanda::Options::%s" % (i)): + Arguments = [('h',"help","Examine-Package::Options::Help"), + ('H',"html-output","Examine-Package::Options::Html-Output")] + for i in [ "Help", "Html-Output" ]: + if not Cnf.has_key("Examine-Package::Options::%s" % (i)): Cnf["Examine-Package::Options::%s" % (i)] = "" args = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv) @@ -407,10 +501,19 @@ for file in args: try: - # Pipe output for each argument through less - less_fd = os.popen("less -R -", 'w', 0) - # -R added to display raw control chars for colour - sys.stdout = less_fd + if Options["Html-Output"]: + if Cnf["Examine-Package::HTMLPath"]: + reportname = os.path.basename(file) + if reportname.endswith('.changes'): + reportname = '_'.join(reportname.split('_')[:2]) + reportname += '.html' + sys.stdout = open(os.path.join(Cnf["Examine-Package::HTMLPath"],reportname),"w") + html_header(file) + else: + # Pipe output for each argument through less + less_fd = os.popen("less -R -", 'w', 0) + # -R added to display raw control chars for colour + sys.stdout = less_fd try: if file.endswith(".changes"): @@ -422,9 +525,15 @@ else: daklib.utils.fubar("Unrecognised file type: '%s'." % (file)) finally: - # Reset stdout here so future less invocations aren't FUBAR - less_fd.close() - sys.stdout = stdout_fd + if Options["Html-Output"]: + html_footer() + if sys.stdout != stdout_fd: + sys.stdout.close() + sys.stdout = stdout_fd + else: + # Reset stdout here so future less invocations aren't FUBAR + less_fd.close() + sys.stdout = stdout_fd except IOError, e: if errno.errorcode[e.errno] == 'EPIPE': daklib.utils.warn("[examine-package] Caught EPIPE; skipping.")