#!/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

BRANCH = 'https://codespeak.net/svn/py/branch/bugfix-0.9.0'
TRUNK = 'https://codespeak.net/svn/py/trunk'

# bugfixes
REVISIONS = [39340, 40002, 40702, 40831, 40832, 40834, 40934, 41224, 41480,
             43299, 43575, 44248, 44648, 44655, 45294, 45295, 45483, 45484,
             45518, 45519, 45535, 45538, 45514, 45545, 45547, 45548, 45549,
             45646, 45647, 45648, 45649, 45655, 45671, 45901, 45906, 47277,
             49423, 49974, 50606, 50645, 50755, 51285, 51292, 51329]

# small features
REVISIONS += [39106, 39655, 39982, 40702, 40737, 40738, 40739, 40753, 41080,
              41620, 41655, 41855, 41860, 45994, 46692, 46770, 46771, 51092,
              46772, 46794, 47584, 48347, 50574]

# merges
REVISIONS += [45539, 46010, 46011, 51033, 51034, 52000, 52001]

# docs typos, etc.
REVISIONS += [38967, 38969, 39994, 40001]

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):
    py.std.os.system('py.test')

def mrg(branchurl, trunkurl, revisions):
    tempdir = 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 rev in revisions:
        log('=' * 79)
        log('revision', rev)
        branch.update(rev)
        diff = get_diff(trunk, rev)
        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)
        run_tests(branch)

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

if __name__ == '__main__':
    mrg(BRANCH, TRUNK, REVISIONS)

