teichmann@492: #!/usr/bin/env python teichmann@492: # -*- coding: UTF-8 -*- teichmann@492: # teichmann@492: # Copyright (C) 2010 by Intevation GmbH teichmann@492: # Authors: teichmann@492: # Sascha L. Teichmann teichmann@492: # teichmann@492: # This program is free software under the GPL (>=v2) teichmann@492: # Read the file COPYING coming with the software for details. teichmann@492: teichmann@492: import sys teichmann@492: import os teichmann@492: import re teichmann@492: import traceback teichmann@492: teichmann@492: from datetime import datetime teichmann@492: teichmann@492: from lxml import etree teichmann@492: teichmann@492: import PyRSS2Gen as RSS2 teichmann@492: teichmann@492: BASE_URL = "http://saegewerk2.wald.intevation.org/buildlogs" teichmann@492: LINK_URL = "%s/details.py?treepkg=%%s" % BASE_URL teichmann@492: ITEM_URL = "%s/details.py?treepkg=%%s#%%s" % BASE_URL teichmann@492: teichmann@492: TITLE = "Saegewerk - %s" teichmann@492: DESCRIPTION = "Build errors of '%s'" teichmann@492: MESSAGE = "%s: error building %s rev. %s" teichmann@492: TTL = 7 teichmann@492: teichmann@492: START = re.compile( teichmann@492: r"start:\s+(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})") teichmann@492: STATUS = re.compile(r"status:\s+(.+)") teichmann@492: teichmann@492: INVALID_LABEL = re.compile(r"[^a-zA-Z0-9_]") teichmann@492: teichmann@492: def make_valid_label(l): teichmann@492: return INVALID_LABEL.sub("_", l) teichmann@492: teichmann@492: def to_datetime(m): teichmann@492: m = map(int, m.groups()) teichmann@492: return datetime( teichmann@492: year=m[0], month=m[1], day=m[2], teichmann@492: hour=m[3], minute=m[4], second=m[5]) teichmann@492: teichmann@492: def usage(msg, code=1): teichmann@492: print >> sys.stderr, "%s " % sys.argv[0] teichmann@492: print >> sys.stderr, "%s" % msg teichmann@492: sys.exit(code) teichmann@492: teichmann@492: def main(): teichmann@492: if len(sys.argv) < 2: teichmann@492: usage("missing treepkgs directory") teichmann@492: teichmann@492: treepkgs_dir = sys.argv[1] teichmann@492: if not os.path.isdir(treepkgs_dir): teichmann@492: usage("'%s' is not a directory" % treepkgs_dir) teichmann@492: teichmann@492: for treepkg in os.listdir(treepkgs_dir): teichmann@492: treepkg_dir = os.path.join(treepkgs_dir, treepkg) teichmann@492: if not os.path.isdir(treepkg_dir): continue teichmann@492: treepkg_xml = os.path.join(treepkg_dir, "treepkg.xml") teichmann@492: if not os.path.isfile(treepkg_xml): continue teichmann@492: try: teichmann@492: f = open(treepkg_xml, "rb") teichmann@492: try: treepkg_dom = etree.parse(f) teichmann@492: finally: f.close() teichmann@492: except: teichmann@492: traceback.print_exc(file=sys.stderr) teichmann@492: continue teichmann@492: description = ''.join( teichmann@492: treepkg_dom.xpath('/treepkg/description/text()')) teichmann@492: teichmann@492: tracks_dir = os.path.join(treepkg_dir, "tracks") teichmann@492: if not os.path.isdir(tracks_dir): continue teichmann@492: teichmann@492: items = [] teichmann@492: teichmann@492: for track in os.listdir(tracks_dir): teichmann@492: track_dir = os.path.join(tracks_dir, track, "pkg") teichmann@492: if not os.path.isdir(track_dir): continue teichmann@492: teichmann@492: track_label = make_valid_label(track) teichmann@492: teichmann@492: for revision in os.listdir(track_dir): teichmann@492: revision_dir = os.path.join(track_dir, revision) teichmann@492: if not os.path.isdir(revision_dir): continue teichmann@492: status_file = os.path.join(revision_dir, "status") teichmann@492: if not os.path.isfile(status_file): continue teichmann@492: start, status = None, None teichmann@492: try: teichmann@492: f = open(status_file, "r") teichmann@492: try: teichmann@492: while True: teichmann@492: line = f.readline() teichmann@492: if not line: break teichmann@492: m = STATUS.match(line) teichmann@492: if m: status = m.group(1); continue teichmann@492: m = START.match(line) teichmann@492: if m: start = to_datetime(m) teichmann@492: finally: teichmann@492: f.close() teichmann@492: except: teichmann@492: traceback.print_exc(file=sys.stderr) teichmann@492: continue teichmann@492: if status != "error" or not start: continue teichmann@492: teichmann@492: label = ''.join([ teichmann@492: track_label, teichmann@492: make_valid_label(revision), teichmann@492: start.strftime("%Y%m%d%H%M%S")]) teichmann@492: teichmann@492: link = ITEM_URL % (treepkg, label) teichmann@492: msg = MESSAGE % (description, track, revision) teichmann@492: item = RSS2.RSSItem( teichmann@492: title = msg, teichmann@492: link = link, teichmann@492: description = msg, teichmann@492: guid = RSS2.Guid(link, isPermaLink=0), teichmann@492: pubDate = start teichmann@492: ) teichmann@492: items.append(item) teichmann@492: teichmann@492: items.sort(key=lambda x: x.pubDate) teichmann@492: teichmann@492: rss = RSS2.RSS2( teichmann@492: title = TITLE % description, teichmann@492: link = LINK_URL % treepkg, teichmann@492: description = DESCRIPTION % description, teichmann@492: pubDate = datetime.utcnow(), teichmann@492: ttl = TTL, teichmann@492: items = items) teichmann@492: teichmann@492: pid, idx = os.getpid(), 0 teichmann@492: while True: teichmann@492: tmp_f = os.path.join( teichmann@492: treepkg_dir, "rss.xml.tmp%d-%d" % (pid, idx)) teichmann@492: if not os.path.exists(tmp_f): break teichmann@492: idx += 1 teichmann@492: teichmann@492: try: teichmann@492: f = open(tmp_f, "wb") teichmann@492: try: rss.write_xml(f, encoding="UTF-8") teichmann@492: finally: f.close() teichmann@492: teichmann@492: rss_xml = os.path.join(treepkg_dir, "rss.xml") teichmann@492: teichmann@492: os.rename(tmp_f, rss_xml) teichmann@492: except: teichmann@492: traceback.print_exc(file=sys.stderr) teichmann@492: if os.path.exists(tmp_f): teichmann@492: try: os.remove(tmp_f) teichmann@492: except: pass teichmann@492: teichmann@492: if __name__ == '__main__': teichmann@492: main()