on recent commits.
"""
-from buildfarm import (
- data,
- hostdb,
- open_hostdb,
+from buildfarm.build import (
+ BuildDiff,
+ MissingRevisionInfo,
+ NoSuchBuildError,
)
-import commands
+from buildfarm import BuildFarm
+from buildfarm.web import build_uri
from email.mime.text import MIMEText
-import logging
import optparse
-import os
-import re
+import resource
import smtplib
-dry_run = True
-
parser = optparse.OptionParser("import-and-analyse [options]")
parser.add_option("--dry-run", help="Will cause the script to send output to stdout instead of to sendmail.", action="store_true")
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
-db = data.BuildResultStore(os.path.abspath(os.path.dirname(__file__)), True)
-hostsdb = open_hostdb()
+resource.setrlimit(resource.RLIMIT_RSS, (300000, 300000))
+resource.setrlimit(resource.RLIMIT_DATA, (300000, 300000))
-compilers = db.compilers
-hosts = hostsdb.hosts()
-trees = db.trees
+buildfarm = BuildFarm(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)
+def check_and_send_mails(cur, old):
- 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 = trees[tree]
-
- (cur_rev, cur_rev_timestamp) = cur.revision_details()
- cur_status = cur.status()
+ if cur.tree is "waf":
+ # no point sending emails, as the email addresses are invalid
+ return
- (old_rev, old_rev_timestamp) = old.revision_details()
- old_status = old.status()
+ if cur.tree is "samba_3_waf":
+ # no emails for this until it stabilises a bit
+ return
- if dry_run:
- print "rev=%s status=%s" % (cur_rev, cur_status)
- print "old rev=%s status=%s" % (old_rev, old_status)
+ t = buildfarm.trees[cur.tree]
+ diff = BuildDiff(t, old, cur)
- if not cur_status.regressed_since(old_status):
- if dry_run:
- print "the build didn't get worse since %r" % old_status
+ if not diff.is_regression():
+ if opts.verbose >= 3:
+ print "... hasn't regressed since %s: %s" % (diff.old_rev, diff.old_status)
return
- log = get_log(tree, cur, old)
- if not log:
- if dry_run:
- print "no log"
- return
+ recipients = set()
+ change_log = ""
- recipients = ",".join(log.recipients.keys())
+ for rev in diff.revisions():
+ 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
Build status for new revision %(cur_rev)s is %(cur_status)s
Build status for old revision %(old_rev)s was %(old_status)s
-See http://build.samba.org/?function=View+Build;host=%(host)s;tree=%(tree)s;compiler=%(compiler)s
+See %(build_link)s
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}
+ """ % {
+ "tree": cur.tree, "host": cur.host, "compiler": cur.compiler,
+ "change_log": change_log,
+ "scm": t.scm,
+ "branch": t.branch,
+ "cur_rev": diff.new_rev,
+ "old_rev": diff.old_rev,
+ "cur_status": diff.new_status,
+ "old_status": diff.old_status,
+ "build_link": build_uri("http://build.samba.org/build.cgi", cur)
+ }
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["Subject"] = "BUILD of %s:%s BROKEN on %s with %s AT REVISION %s" % (cur.tree, t.branch, cur.host, cur.compiler, diff.new_rev)
msg["From"] = "\"Build Farm\" <build@samba.org>"
- msg["To"] = recipients
- smtp.send(msg["From"], [msg["To"]], msg.as_string())
-
-
-for host in hosts:
- for tree in trees:
- for compiler in compilers:
- retry = 0
- if opts.verbose >= 2:
- print "Looking for a log file for %s %s %s..." % (host, compiler, tree)
-
- # By building the log file name this way, using only the list of
- # hosts, trees and compilers as input, we ensure we
- # control the inputs
- try:
- build = db.get_build(host, tree, compiler)
- except data.NoSuchBuildError:
- continue
-
- if opts.verbose >= 2:
- print "Processing %s..." % build
-
- db.upload_build(build)
-
- (rev, commit_rev, rev_timestamp) = db.revision_details()
-
- try:
- prev_rev = db.get_previous_revision(tree, host, compiler, rev)
- except hostdb.NoSuchBuild:
- # Can't send a nastygram until there are 2 builds..
- continue
- else:
- prev_build = db.get_build(tree, host, compiler, prev_rev)
- check_and_send_mails(tree, host, compiler, build.status(), prev_build.status())
+ 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 build in buildfarm.builds:
+ continue
+
+ if not opts.dry_run:
+ old_build = build
+ try:
+ build = buildfarm.builds.upload_build(old_build)
+ except MissingRevisionInfo:
+ print "No revision info in %r, skipping" % build
+ continue
+
+ try:
+ rev = build.revision_details()
+ except MissingRevisionInfo:
+ print "No revision info in %r, skipping" % build
+ continue
+
+ if opts.verbose >= 2:
+ print "%s... " % build,
+ print str(build.status())
+
+ try:
+ if opts.dry_run:
+ # Perhaps this is a dry run and rev is not in the database yet?
+ prev_build = buildfarm.builds.get_latest_build(build.tree, build.host, build.compiler)
+ else:
+ prev_build = buildfarm.builds.get_previous_build(build.tree, build.host, build.compiler, rev)
+ except 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..
+ else:
+ check_and_send_mails(build, prev_build)
+ if not opts.dry_run:
+ old_build.remove()
+ buildfarm.commit()
smtp.quit()