#!/usr/bin/env python """ script that applies a number of SVN changesets to a wc this can be used to merge a specified set of revisions from an SVN trunk back into a branch (for 'dot' releases) """ import py import sys import os import time BRANCH = 'https://codespeak.net/svn/py/branch/bugfix-0.9.0' TRUNK = 'https://codespeak.net/svn/py/trunk' TEST_INTERVAL = 0 # 0 for never, 1 for always, else every 1/x time # bugfixes REVISIONS = [39340, 40002, 40702, 40831, 40832, 40834, 40934, 41224, 41480, 43299, 43575, 44248, 44648, 44655, 45294, 45295, 45483, 45484, 45518, 45519, 45535, 45538, 45541, 45545, 45547, 45548, 45549, 45646, 45647, 45648, 45649, 45655, 45671, 45901, 45906, 47277, 49423, 49974, 50606, 50645, 50755, 51285, 51292, 52481] #, 51329] # small features REVISIONS += [39106, 39655, 40737, 40738, 40739, 45994, 46692] #REVISIONS += [39106, 39655, 40737, 40738, 40739] # merges REVISIONS += [52000, 52001] # greenlet-based networking #REVISIONS += [39937, 39974, 39975, 39983, 40705, 40706, 40719, 40720, 40982, # 41606, 45550, 51056] # docs typos, etc. REVISIONS += [38967, 38969, 39982, 39994, 40001, 45539, 46010] # fixes for problems after merge #REVISIONS += [45539, ] # 39982] # XXX skipped - REVISIONS += [39928, 40702, 40737, 40738, 40739, 40753, 41080, # 41620, 41655, 41855, 41860, 45994, 46692, 46770, # 46771, 51092, 46772, 46794, 47548, 48347, 50574, # 45539, 46010, 46011, 51033, 51034] REVISIONS.sort() def log(*args): sys.stdout.write(' '.join([str(a) for a in args]) + '\n') sys.stdout.flush() def apply_patch(branch, patch): log(patch) try: pin, pout = os.popen2('patch -p0 -N') try: pin.write(patch) finally: pin.close() try: data = pout.read() finally: pin.close() pout.close() except Exception, e: log('PATCH FAILED!', e) raise def run_tests(path): print >>py.std.sys.stderr, py.std.os.getcwd() py.std.os.system('py/bin/py.test --boxed') reg_patch = py.std.re.compile('^\-\-\-.*') def get_patches(diff): sep = ('________________________________________' '___________________________\n') for chunk in diff.split(sep): sep2 = ('==========================================' '=========================\n') for part in chunk.split(sep2): ispatch = True if not reg_patch.match(part): ispatch = False yield (ispatch, part) def get_diff(trunk, rev): fp = trunk._svnpopenauth('svn diff -r %d:%d %s' % (rev - 1, rev, trunk)) try: diff = fp.read() finally: fp.close() return diff def mrg(branchurl, trunkurl, revisions, test_interval): tempdir = py.path.local('/tmp/mrgr') # py.test.ensuretemp('mrgr') log('checking out', branchurl) branch = py.path.svnwc(tempdir.join('branch')) branch.checkout(branchurl, rev=revisions[0]) os.chdir(branch.strpath) log('checking out', trunkurl) trunk = py.path.svnurl(trunkurl) log('starting merge') for i, rev in enumerate(revisions): log('=' * 79) log('revision', rev) branch.update(rev) def ftime(t): return time.strftime('%Y/%m/%d %H:%M:%S', time.localtime(t)) logmsg = '\n\n'.join(['%s - %s\n\n%s\n\n' % (ftime(l.date), l.author, l.msg) for l in trunk.log(rev-1, rev)]) diff = get_diff(trunk, rev) logfile = tempdir.join('log-%d' % (rev,)) logfile.write(logmsg + '\n' + ('-' * 79) + '\n' + diff) #difffile = tempdir.join('diff-%d' % (rev,)) #difffile.write(diff) patches = get_patches(diff) for ispatch, patch in patches: if not ispatch: log('SKIPPING NON-PATCH PART') log('-' * 79) log(patch) log('-' * 79) else: log('GOING TO PATCH') log('-' * 79) apply_patch(branch, patch) log('-' * 79) log('=' * 79) if test_interval > 0 and i % test_interval == test_interval - 1: run_tests(branch) if test_interval > 1 and i % test_interval != test_interval - 1: # run tests always after last rev run_tests(branch) if __name__ == '__main__': mrg(BRANCH, TRUNK, REVISIONS, TEST_INTERVAL)