bos@128: #!/usr/bin/env python
bos@128: #
bos@128: # Adapter for using interdiff with mercurial's extdiff extension.
bos@128: #
bos@128: # Copyright 2006 Bryan O'Sullivan <bos@serpentine.com>
bos@128: #
bos@128: # This software may be used and distributed according to the terms of
bos@128: # the GNU General Public License, incorporated herein by reference.
bos@128: 
bos@128: import os
bos@128: import shutil
bos@128: import sys
bos@128: import tempfile
bos@128: 
bos@128: if len(sys.argv) < 4:
bos@128:     print >> sys.stderr, ('usage: %s srcrepo destrepo cset-to-omit [...]' %
bos@128:                           os.path.basename(sys.argv[0]))
bos@128:     sys.exit(1)
bos@128: 
bos@128: srcrepo, destrepo = sys.argv[1], sys.argv[2]
bos@128: omit = sys.argv[3:]
bos@128:     
bos@128: changemap = {}
bos@128: revs = []
bos@128: 
bos@128: parent = None
bos@128: 
bos@128: sys.stdout.write('gathering history...')
bos@128: sys.stdout.flush()
bos@128: 
bos@128: for line in os.popen("hg --cwd %r log -r0:tip --template '{rev}:{node} {parents}\n'" % srcrepo):
bos@128:     changes = line.split()
bos@128:     cset = changes[0].split(':')[1]
bos@128:     rev = len(revs)
bos@128:     changemap[cset] = rev
bos@128:     if len(changes) >= 2:
bos@128:         p1 = int(changes[1].split(':', 1)[0])
bos@128:     if len(changes) == 3:
bos@128:         p2 = int(changes[2].split(':', 1)[0])
bos@128:     else:
bos@128:         p2 = None
bos@128:     if len(changes) == 1:
bos@128:         p1 = parent
bos@128:     revs.append((cset, p1, p2))
bos@128:     parent = rev
bos@128: 
bos@128: sys.stdout.write(' %d revs\n' % len(revs))
bos@128: 
bos@128: def findrev(r):
bos@128:     try:
bos@128:         i = int(r)
bos@128:         if str(i) == r:
bos@128:             rev = i
bos@128:         if rev < 0:
bos@128:             rev += len(revs)
bos@128:         if rev < 0 or rev > len(revs):
bos@128:             print >> sys.stderr, 'bad changeset: %r' % r
bos@128:             sys.exit(1)
bos@128:         cset = revs[rev][0]
bos@128:     except ValueError:
bos@128:         cset = r
bos@128:         matches = [changemap[c] for c in changemap if c.startswith(cset)]
bos@128:         if len(matches) != 1:
bos@128:             print >> sys.stderr, 'bad changeset: %r' % r
bos@128:             sys.exit(1)
bos@128:         rev = matches[0]
bos@128:     return rev
bos@128: 
bos@128: def run(cmd):
bos@128:     print cmd
bos@128:     ret = os.system(cmd)
bos@128:     if ret:
bos@128:         print >> sys.stderr, 'failure:', cmd
bos@128:         sys.exit(1)
bos@128: 
bos@128: omit = map(findrev, omit)
bos@128: omit.sort()
bos@128: newrevs = revs[:omit[0]]
bos@128: tip = len(newrevs) - 1
bos@128: run('hg clone -q -r%s %r %r' % (tip, srcrepo, destrepo))
bos@128:     
bos@128: os.environ['HGMERGE'] = 'true'
bos@128: 
bos@128: patchdir = tempfile.mkdtemp(prefix='replay.')
bos@128: try:
bos@128:     run('hg --cwd %r export --git -o %r%s%%R %d:tip' %
bos@128:         (srcrepo, patchdir, os.sep, omit[0]+1))
bos@128:     for rev in xrange(omit[0], len(revs)):
bos@128:         if rev in omit:
bos@128:             print 'omit', rev
bos@128:             newrevs.append((None, revs[rev][1], None))
bos@128:             continue
bos@128:         _, p1, p2 = revs[rev]
bos@128:         np1 = newrevs[p1][1]
bos@128:         if tip != np1:
bos@128:             run('hg --cwd %r update -q -C %s' % (destrepo, np1))
bos@128:         np2 = None
bos@128:         if p2:
bos@128:             np2 = newrevs[p2][1]
bos@128:             run('hg --cwd %r merge -q %s' % (destrepo, np2))
bos@128:             print >> sys.stderr, 'XXX - cannot handle merges properly yet'
bos@128:         run('hg --cwd %r import -q -f %r%s%d' % (destrepo, patchdir, os.sep, rev))
bos@128:         tip = len(newrevs) - 1
bos@128:         newrevs.append((None, tip, np2))
bos@128: finally:
bos@128:     print 'cleaning up ...'
bos@128:     #shutil.rmtree(patchdir)