diff options
-rw-r--r-- | checkbump.py | 187 |
1 files changed, 102 insertions, 85 deletions
diff --git a/checkbump.py b/checkbump.py index 89008bc..dce2c18 100644 --- a/checkbump.py +++ b/checkbump.py @@ -4,21 +4,77 @@ from ConfigParser import ConfigParser from contextlib import closing from datetime import datetime +from jinja2 import Template +from logging import getLogger, Formatter, StreamHandler, INFO from subprocess import Popen, PIPE -from urllib2 import urlopen +from time import strftime +from urllib import urlencode +from urllib2 import urlopen, URLError from portage import portagetree from portage.versions import pkgsplit, vercmp import os, sys +# logging formatters +LOG_FORMATTER = "[%(asctime)s] %(name)s.%(levelname)s: %(message)s" +LOG_DATEFORMAT = "%Y-%m-%d %H:%M:%S %Z" -class PackageException(Exception): - pass +HTML_TEMPLATE = Template('''\ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Version bump checker - {{ config_file }}</title> + <meta http-equiv="content-type" content="text/html;charset=utf-8" /> + </head> + <body> + <h1>Version bump checker</h1> + <h2>{{ config_file }}</h2> + <table border="1"> + <tr> + <th>Package</th> + <th>Bugs</th> + <th>Our version</th> + <th>Upstream version</th> + <th>Up-to-date?</th> + </tr> + {%- for package in packages %} + <tr> + <td><a href="{{ package.url }}">{{ package.atom }}</a></td> + <td><a href="http://bugs.gentoo.org/buglist.cgi?quicksearch={{ package.atom }}">Bugs</a></td> + {%- if package.error %} + <td colspan="3">Failed!</td> + {%- else %} + <td>{{ package.gentoo_version }}</td> + <td>{{ package.upstream_version }}</td> + <td bgcolor="{{ package.up2date and 'green">yes' or 'red">no' }}</td> + {%- endif %} + </tr> + {%- else %} + <tr> + <td colspan="4">No packages available!</td> + </tr> + {%- endfor %} + </table> + <hr /> + <p>Last update: {{ last_update }}</p> + </body> +</html> +''') + +# setup logging +logger = getLogger('checkbump') +logger.setLevel(INFO) +_log_handler = StreamHandler(sys.stderr) +_log_handler.setFormatter(Formatter(LOG_FORMATTER, LOG_DATEFORMAT)) +logger.addHandler(_log_handler) class Package(object): + error = False + def __init__(self, atom, url): self.atom = atom self.url = url @@ -26,29 +82,33 @@ class Package(object): try: with closing(urlopen(url)) as fp: self._content = fp.read() - except: - raise PackageException('Fetch failed: %r' % url) + except URLError, err: + self.error = True + logger.error('fetch failed %r - %r' % (atom, err.reason)) @property def gentoo_version(self): - portage = portagetree() - versions = portage.dep_match(self.atom) - if len(versions) == 0: - raise PackageException('Package not found: %r' % self.atom) - last_atom = versions[-1] - cp, pv, rev = pkgsplit(last_atom) - return pv + if not self.error: + portage = portagetree() + versions = portage.dep_match(self.atom) + if len(versions) == 0: + raise Exception('package not found %r' % self.atom) + last_atom = versions[-1] + cp, pv, rev = pkgsplit(last_atom) + return pv @property def up2date(self): - return vercmp(self.gentoo_version, self.upstream_version) == 0 + if not self.error: + return vercmp(self.gentoo_version, self.upstream_version) == 0 def run_command(self, command): - p = Popen(command, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) - stdout, stderr = p.communicate(self._content) - if p.returncode != os.EX_OK: - raise PackageException('Command failed: %r' % command) - self.upstream_version += stdout.strip() + if not self.error: + p = Popen(command, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate(self._content) + if p.returncode != os.EX_OK: + raise Exception('command failed: %r' % command) + self.upstream_version += stdout.strip() class PackageList(list): @@ -57,12 +117,12 @@ class PackageList(list): self._parser = ConfigParser() parsed_file = self._parser.read(ini_file) if not len(parsed_file) == 1: - raise PackageException('Failed to load config: %r' % ini_file) + raise Exception('failed to load config %r' % ini_file) list.__init__(self) atoms = self._parser.sections() atoms.sort() for atom in atoms: - print >> sys.stderr, 'Fetching: %s' % atom + logger.info('fetching %r' % atom) url = None commands = None for name, value in self._parser.items(atom): @@ -71,79 +131,36 @@ class PackageList(list): elif name == 'command': commands = value if url is None or commands is None: - raise PackageException('Invalid url/command: %r' % atom) + raise Exception('invalid url/command %r' % atom) package = Package(atom, url) for command in commands.split('\n'): package.run_command(command.strip()) self.append(package) -class HTMLReport(object): - - def __init__(self, ini_file): - self._ini_file = ini_file - self._pkg_list = PackageList(self._ini_file) - - def _header(self): - return """\ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> - <head> - <title>Version bump checker</title> - <meta http-equiv="content-type" content="text/html;charset=utf-8" /> - </head> - <body> - <h1>Version bump checker</h1> - <table border="1"> - <tr> - <th>Package</th> - <th>Our version</th> - <th>Upstream version</th> - <th>Up-to-date?</th> - </tr> +def generate_html(config_file, pkg_list): + logger.info('generating html') + return HTML_TEMPLATE.render( + config_file = config_file, + packages = pkg_list, + last_update = strftime(LOG_DATEFORMAT) + ) -<!-- init packages --> -""" +def main(argv): + logger.info('starting ...') + if len(argv) != 1: + logger.error('invalid number of arguments.') + return 1 + pkg_list = PackageList(argv[0]) + config_file = os.path.splitext(os.path.basename(argv[0]))[0] + sys.stdout.write(generate_html(config_file, pkg_list)) - def _footer(self): - return """\ - -<!-- end packages --> - </table> - <hr /> - <p> - Last update: %s UTC - </p> - </body> -</html> -""" % datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') - - def _package(self, pkg): - return """\ -<tr> - <td>%(atom)s</td> - <td>%(gentoo_version)s</td> - <td>%(upstream_version)s</td> - <td bgcolor="%(color)s">%(up2date)s</td> -</tr> -""" % { - 'atom': pkg.atom, - 'gentoo_version': pkg.gentoo_version, - 'upstream_version': pkg.upstream_version, - 'color': pkg.up2date and 'green' or 'red', - 'up2date': pkg.up2date and 'Yes' or 'No', - } - - def __str__(self): - tmp = self._header() - for pkg in self._pkg_list: - tmp += self._package(pkg) - tmp += self._footer() - return tmp - - if __name__ == '__main__': - print HTMLReport('sci-electronics.ini') + try: + sys.exit(main(sys.argv[1:])) + except KeyboardInterrupt: + logger.info('interrupted.') + except Exception, err: + logger.error(str(err)) |