Cope with unknown hosts in dead host list.
[amitay/build-farm.git] / import-and-analyse.py
old mode 100644 (file)
new mode 100755 (executable)
index de7f08d..ee389df
@@ -10,16 +10,11 @@ some mail chastising the possible culprits when the build fails, based
 on recent commits.
 """
 
-from buildfarm import (
-    BuildFarm,
-    hostdb,
-    )
-import commands
+from buildfarm import data
+from buildfarm.sqldb import StormCachingBuildFarm
 from email.mime.text import MIMEText
 import logging
 import optparse
-import os
-import re
 import smtplib
 
 parser = optparse.OptionParser("import-and-analyse [options]")
@@ -28,71 +23,11 @@ parser.add_option("--verbose", help="Be verbose", action="count")
 
 (opts, args) = parser.parse_args()
 
-UNPACKED_DIR = "/home/ftp/pub/unpacked"
-
-# we open readonly here as only apache(www-run) has write access
-buildfarm = BuildFarm()
-db = buildfarm.builds
-hostsdb = buildfarm.hostdb
+buildfarm = StormCachingBuildFarm(timeout=40.0)
 
 smtp = smtplib.SMTP()
 smtp.connect()
 
-class Log(object):
-
-    def __init__(self):
-        self.change_log = None
-        self.committers = set()
-        self.authors = set()
-        self.recipients = None
-
-
-def get_log_git(tree, cur, old):
-    cmd = "cd %s/%s && git log --pretty=full %s..%s ./" % (UNPACKED_DIR, tree, old, cur)
-
-    log = Log()
-
-    log.change_log = commands.getoutput(cmd)
-    #print log.change_log
-
-    # get the list of possible culprits
-    log2 = log.change_log
-
-    for m in re.findall("[\n]*Author: [^<]*<([^>]+)>\nCommit: [^<]*<([^>]+)>\n(.*)$", log.change_log):
-        author = m.group(1)
-        committer = m.group(2)
-
-        # handle cherry-picks from svnmirror repo
-        author = author.replace("0c0555d6-39d7-0310-84fc-f1cc0bd64818", "samba.org")
-
-        # for now only send reports to samba.org addresses.
-        if not "@samba.org" in author:
-            author = None
-
-        if author:
-            log.authors.add(author)
-        if committer:
-            log.committers.add(committer)
-
-    # Add a URL to the diffs for each change
-    log.change_log = re.sub("([\n]*commit ([0-9a-f]+))", "\\1\nhttp:\/\/build.samba.org\/?function=diff;tree=%s;revision=\\2" % tree, log.change_log)
-
-    all = set()
-    all.update(log.authors)
-    all.update(log.committers)
-    log.recipients = all
-    return log
-
-
-def get_log(tree, cur, old):
-    treedir = os.path.join(UNPACKED_DIR, tree)
-
-    if os.path.exists(os.path.join(treedir, ".git")):
-        return get_log_git(tree, cur, old)
-    else:
-        raise Exception("Unknown vcs for %s" % treedir)
-
-
 def check_and_send_mails(tree, host, compiler, cur, old):
     t = buildfarm.trees[tree]
 
@@ -102,22 +37,24 @@ def check_and_send_mails(tree, host, compiler, cur, old):
     (old_rev, old_rev_timestamp) = old.revision_details()
     old_status = old.status()
 
-    if opts.dry_run:
-        print "rev=%s status=%s" % (cur_rev, cur_status)
-        print "old rev=%s status=%s" % (old_rev, old_status)
-
     if not cur_status.regressed_since(old_status):
-        if opts.dry_run:
-            print "the build didn't get worse since %r" % old_status
+        if opts.verbose >= 3:
+            print "... hasn't regressed since %s: %s" % (old_rev, old_status)
         return
 
-    log = get_log(tree, cur, old)
-    if not log:
-        if opts.dry_run:
-            print "no log"
-        return
+    recipients = set()
+    change_log = ""
 
-    recipients = ",".join(log.recipients.keys())
+    for rev in t.get_branch().log(from_rev=cur.revision, exclude_revs=set([old.revision])):
+        recipients.add(rev.author)
+        recipients.add(rev.committer)
+        change_log += """
+revision: %s
+author: %s
+committer: %s
+message:
+    %s
+""" % (rev.revision, rev.author, rev.committer, rev.message)
 
     body = """
 Broken build for tree %(tree)s on host %(host)s with compiler %(compiler)s
@@ -132,32 +69,71 @@ See http://build.samba.org/?function=View+Build;host=%(host)s;tree=%(tree)s;comp
 The build may have been broken by one of the following commits:
 
 %(change_log)s
-    """ % {"tree": tree, "host": host, "compiler": compiler, "change_log": log.change_log, "scm": t.scm, "branch": t.branch,
-            "cur_rev": cur_rev, "old_rev": old_rev, "cur_status": cur_status, "old_status": old_status }
+    """ % {
+        "tree": tree, "host": host, "compiler": compiler,
+        "change_log": change_log,
+        "scm": t.scm,
+        "branch": t.branch,
+        "cur_rev": cur_rev,
+        "old_rev": old_rev,
+        "cur_status": cur_status,
+        "old_status": old_status,
+        }
 
     msg = MIMEText(body)
     msg["Subject"] = "BUILD of %s:%s BROKEN on %s with %s AT REVISION %s" % (tree, t.branch, host, compiler, cur_rev)
     msg["From"] = "\"Build Farm\" <build@samba.org>"
-    msg["To"] = recipients
-    smtp.send(msg["From"], [msg["To"]], msg.as_string())
+    msg["To"] = ",".join(recipients)
+    if not opts.dry_run:
+        smtp.sendmail(msg["From"], [msg["To"]], msg.as_string())
+    else:
+        print msg.as_string()
 
 
 for build in buildfarm.get_new_builds():
-    if opts.verbose >= 2:
-        print "Processing %s..." % build
+    if build in buildfarm.builds:
+        continue
+
+    if not opts.dry_run:
+        try:
+            build = buildfarm.builds.upload_build(build)
+        except data.MissingRevisionInfo:
+            print "No revision info in %r, skipping" % build
+            continue
 
-    db.upload_build(build)
+    try:
+        (rev, rev_timestamp) = build.revision_details()
+    except data.MissingRevisionInfo:
+        print "No revision info in %r, skipping" % build
+        continue
 
-    (rev, commit_rev, rev_timestamp) = build.revision_details()
+    if opts.verbose >= 2:
+        print "%s... " % build,
+        print str(build.status())
 
     try:
-        prev_rev = db.get_previous_revision(build.tree, build.host, build.compiler, rev)
-    except hostdb.NoSuchBuild:
+        if opts.dry_run:
+            # Perhaps this is a dry run and rev is not in the database yet?
+            prev_rev = buildfarm.builds.get_latest_revision(build.tree, build.host, build.compiler)
+        else:
+            prev_rev = buildfarm.builds.get_previous_revision(build.tree, build.host, build.compiler, rev)
+    except data.NoSuchBuildError:
+        if opts.verbose >= 1:
+            print "Unable to find previous build for %s,%s,%s" % (build.tree, build.host, build.compiler)
         # Can't send a nastygram until there are 2 builds..
-        continue
     else:
-        prev_build = db.get_build(build.tree, build.host, build.compiler, prev_rev)
-        check_and_send_mails(build.tree, build.host, build.compiler, build, prev_build)
-
+        try:
+            assert prev_rev is not None
+            prev_build = buildfarm.builds.get_build(build.tree, build.host, build.compiler, prev_rev)
+        except data.NoSuchBuildError:
+            if opts.verbose >= 1:
+                print "Previous build %s has disappeared" % prev_build
+        else:
+            check_and_send_mails(build.tree, build.host, build.compiler, build, prev_build)
+
+    if not opts.dry_run:
+        # When the new web script is introduced, kill the build here:
+        # build.remove()
+        buildfarm.commit()
 
 smtp.quit()