Mercurial > gub
view bin/gub-tester @ 3455:f50975335ad8
Support testing user-checked-out trees again; 3rd option in gub-tester help.
Oops, actually remove old test-gub.
author | Jan Nieuwenhuizen <janneke@gnu.org> |
---|---|
date | Wed, 09 May 2007 17:02:27 +0200 |
parents | 07510997bd2f |
children | 3d758d262724 |
line wrap: on
line source
#!/usr/bin/python def argv0_relocation (): import os, sys bindir = os.path.dirname (sys.argv[0]) prefix = os.path.dirname (bindir) sys.path.insert (0, prefix) argv0_relocation () import sys import re import os import smtplib import email.MIMEText import email.Message import email.MIMEMultipart import optparse import time import dbhash from gub import repository from gub import oslog ################################################################ # utils. def system (c): print c if os.system (c): raise Exception ('barf') def read_tail (file, amount=10240): f = open (file) f.seek (0, 2) length = f.tell() f.seek (- min (length, amount), 1) return f.read () def canonicalize_string (target): canonicalize = re.sub ('[ \t\n]', '_', target) canonicalize = re.sub ('[^a-zA-Z0-9-]+', '_', canonicalize) return canonicalize log_file = None ################################################################ # def result_message (parts, subject='') : """Concatenate PARTS to a Message object.""" if not parts: parts.append ('(empty)') parts = [email.MIMEText.MIMEText (p) for p in parts if p] msg = parts[0] if len (parts) > 1: msg = email.MIMEMultipart.MIMEMultipart () for p in parts: msg.attach (p) msg['Subject'] = subject msg.epilogue = '' return msg def opt_parser (): if os.environ.has_key ('EMAIL'): address = os.environ['EMAIL'] else: try: address = '%s@localhost' % os.getlogin () except OSError: address = 'root@localhost' p = optparse.OptionParser (usage='gub-tester [options] command command ... ') p.address = [address] examples = '''Examples: gub-tester --repository=downloads/lilypond.git \\ gub --branch=lilypond:master lilypond gub-tester --url=http://bazaar.launchpad.net/~yaffut/yaffut/yaffut.bzr \\ 'make all check' bzr branch http://bazaar.launchpad.net/~yaffut/yaffut/yaffut.bzr cd yaffut.bzr && gub-tester 'make all check' ''' def format_examples (self): return examples if p.__dict__.has_key ('epilog'): p.formatter.format_epilog = format_examples p.epilog = examples else: p.formatter.format_description = format_examples p.description = examples p.add_option ('-t', '--to', action='append', dest='address', default=[], help='where to send error report') p.add_option ('--dry-run', dest='dry_run', default=False, action='store_true', help='do not run any commands') p.add_option ('--append-diff', dest='append_diff', default=False, action='store_true', help='append diff since last successful run') p.add_option ('--bcc', action='append', dest='bcc_address', default=[], help='BCC for error report') p.add_option ('-f', '--from', action='store', dest='sender', default=address, help='whom to list as sender') p.add_option ('--branch', action='store', dest='branch', default='HEAD', help='which branch to fetch [GIT repositories]') p.add_option ('--url', action='store', dest='url', default=None, help='where to fetch sources') p.add_option ('--update', action='store_true', dest='update', default=False, help='checkout or update sources') p.add_option ('--revision', action='store', dest='revision', default=None, help='what revision to fetch') p.add_option ('--repository', action='store', dest='repository', default='.', help='where to download/cache repository') p.add_option ('--tag-repo', action='store', dest='tag_repo', default='', help='where to push success tags.') p.add_option ('--quiet', action='store_true', dest='be_quiet', default=False, help='only send mail when there was an error.') p.add_option ('--dependent', action='store_true', dest='is_dependent', default=False, help='test targets depend on each other') p.add_option ('--posthook', action='append', dest='posthooks', default=[], help='commands to execute after successful tests.') p.add_option ('--test-self', action='store_true', dest='test_self', default=False, help='run a cursory self test.') p.add_option ('-s', '--smtp', action='store', dest='smtp', default='localhost', help='SMTP server to use.') p.add_option ('--result-directory', action='store', dest='result_dir', help='Where to store databases test results', default='log') p.add_option ('-v', '--verbose', action='count', dest='verbose', default=0) return p def get_db (options, name): name = options.result_dir + '/%s.db' % name db_file = os.path.join (options.result_dir, name) db = dbhash.open (db_file, 'c') return db def test_target (repo, options, target, last_patch): canonicalize = canonicalize_string (target) release_hash = repo.get_checksum () done_db = get_db (options, canonicalize) if done_db.has_key (release_hash): log_file.info ('release %(release_hash)s has already been checked' % locals ()) return None logfile = 'test-%(canonicalize)s.log' % locals () logfile = os.path.join (options.result_dir, logfile) cmd = 'nice time sh -c "(%(target)s)" > %(logfile)s 2>&1' % locals () log_file.command (cmd) if options.dry_run: return ('SUCCESS', ['dryrun']) stat = os.system (cmd) base_tag = 'success-%(canonicalize)s-' % locals () result = 'unknown' attachments = [] body = read_tail (logfile, 10240).split ('\n') if stat: result = 'FAIL' attachments = ['error for\n\n\t%s\n\n\n%s' % (target, '\n'.join (body[-0:]))] if options.append_diff: attachments += [repo.get_diff_from_tag (base_tag)] else: if 0: # FIXME: find in archives, what did this do? # format of last_patch? # canonicalize_target vs canonicalize_string? print last_patch tag = base_tag + canonicalize_string (last_patch['date']) repo.tag (tag) log_file.log ('tagging with %s' % tag) if options.tag_repo: repo.push (tag, options.tag_repo) result = 'SUCCESS' attachments = ['success for\n\n\t%s\n\n%s' % (target, '\n'.join (body[-10:]))] log_file.info ('%s: %s' % (target, result)) done_db[release_hash] = time.ctime () return (result, attachments) def send_message (options, msg): if not options.address: log_file.info ('No recipients for result mail') # FIXME: what about env[EMAIL]? return COMMASPACE = ', ' msg['From'] = options.sender msg['To'] = COMMASPACE.join (options.address) if options.bcc_address: msg['BCC'] = COMMASPACE.join (options.bcc_address) msg['X-Autogenerated'] = 'lilypond' connection = smtplib.SMTP (options.smtp) connection.sendmail (options.sender, options.address, msg.as_string ()) def send_result_by_mail (options, parts, subject='Autotester result'): msg = result_message (parts, subject) send_message (options, msg) def print_results (options, parts, subject='Autotester result'): print '\n===\n\nSUBJECT: ', subject print '\n---\n'.join (parts) print 'END RESULT\n===' def real_main (options, args, handle_result): global log_file log = 'log/gub-tester.log' if options.dry_run: log = '/dev/stdout' log_file = oslog.Os_commands (log, options.verbose) log_file.info (' *** %s' % time.ctime ()) log_file.info (' *** Starting tests:\n %s' % '\n '.join (args)) repo = repository.get_repository_proxy (options.repository, options.url, options.revision, options.branch) if (not repo.is_downloaded () or options.update or options.revision): repo.download () repo.update_workdir ('.') log_file.info ('Repository %s' % str (repo)) last_patch = repo.get_revision_description () release_hash = repo.get_checksum () release_id = ''' Last patch of this release: %(last_patch)s\n Checksum of revision: %(release_hash)s ''' % locals () summary_body = '\n\n' results = {} failures = 0 for a in args: result_tup = test_target (repo, options, a, last_patch) if not result_tup: continue (result, atts) = result_tup results[a] = result_tup success = result.startswith ('SUCCESS') if not (options.be_quiet and success): handle_result (options, atts, subject='Autotester: %s %s' % (result, a)) summary_body += '%s\n %s\n' % (a, result) if not success: failures += 1 if options.is_dependent: break if (results and len (args) > 1 and (failures > 0 or not options.be_quiet)): handle_result (options, [summary_body, release_id], subject='Autotester: summary') if failures == 0 and results: for p in options.posthooks: os.system (p) def test_self (options, args): self_test_dir = 'test-gub-test.darcs' system ('rm -rf %s ' % self_test_dir) system ('mkdir %s ' % self_test_dir) os.chdir (self_test_dir) system ('mkdir log') system ('''echo '#!/bin/sh true' > foo.sh''') system ('darcs init') system ('echo author > _darcs/prefs/author') system ('darcs add foo.sh') system ('darcs record -am "add bla"') options.repository = os.getcwd () real_main (options, ['false', 'true', 'sh foo.sh'], print_results) system ('''echo '#!/bin/sh true' > foo.sh''') system ('darcs record -am "change bla"') real_main (options, ['sh foo.sh'], print_results) def main (): (options, args) = opt_parser ().parse_args () if not os.path.isdir (options.result_dir): os.makedirs (options.result_dir) options.result_dir = os.path.abspath (options.result_dir) if options.test_self: test_self (options, args) else: real_main (options, args, send_result_by_mail) if __name__ == '__main__': main ()