/usr/bin/xx-svn-review is in xxdiff-scripts 1:4.0+hg453+dfsg-2.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | #!/usr/bin/python
"""
Usage: REV1 REV2
Export two SVN revisions and review them.
"""
import sys, os, tempfile, logging, re, shutil
from StringIO import StringIO
from subprocess import *
from os.path import *
from xml.etree import ElementTree
from urlparse import urljoin
def get_repository_root():
"Get the root URL of the repository."
p = Popen(('svn', 'info', '--xml'), shell=0, stdout=PIPE)
out, _ = p.communicate()
doc = ElementTree.XML(out)
return doc.find('.//root').text
def get_changeset_files(r1, r2):
"Get the list of files affected between two revisions."
if r1 > r2:
r1, r2 = r2, r1
logcmd = ('svn', 'log', '-r%d:%d' % (r1+1, r2), '-v', '--xml')
p = Popen(logcmd, shell=0, stdout=PIPE)
out, _ = p.communicate()
doc = ElementTree.XML(out)
return set(node.text for node in doc.findall('.//path'))
def insuredir(dn):
if not exists(dn):
os.makedirs(dn)
def main():
import optparse
parser = optparse.OptionParser(__doc__.strip())
parser.add_option('-u', '--url', action='store_true',
help="Specify the external URL to checkout.")
parser.add_option('-f', '--full', action='store_true',
help="Checkout the full list of files, not just the files affected.")
opts, args = parser.parse_args()
logging.basicConfig(level=logging.INFO, format='%(levelname)-8s: %(message)s')
if len(args) < 2:
parser.error("Usage: REV1 REV2 [FILE ...]")
r1, r2 = map(int, args[0:2])
filenames = args[2:]
if not opts.url:
if not isdir(join(os.getcwd(), '.svn')):
parser.error("You must invoke this command from a working directory.")
p = Popen(('svn', 'info'), shell=0, stdout=PIPE)
out, _ = p.communicate()
mo = re.search('^URL: (.*)', out, re.MULTILINE)
url = mo.group(1)
if not opts.full:
repo_root = get_repository_root()
filenames = get_changeset_files(r1, r2)
try:
tempdir = tempfile.mkdtemp(prefix=basename(sys.argv[0]))
for r in r1, r2:
rootdir = join(tempdir, 'r%s' % r)
logging.info("Checking out %s in '%s'" % (r, rootdir))
# Simple full checkout.
if opts.full:
cmd = ('svn', 'checkout', '-r%s' % r, url, rootdir)
ret = call(cmd, shell=0, cwd=tempdir)
if ret != 0:
raise SystemExit("Error: checking out revision '%s'" % r)
else:
for fn in sorted(filenames):
outfn = rootdir + fn
url = repo_root + fn
logging.info(url)
insuredir(dirname(outfn))
cmd = ('svn', 'export', '-q', '-r%s' % r, url, outfn)
logging.debug(cmd)
if call(cmd, cwd=tempdir, stderr=PIPE) != 0:
logging.warn("Error on file '%s'." % url)
diffcmd = ('xxdiff', '--exclude=.svn', '-r', join(tempdir, 'r%s' % r1), join(tempdir, 'r%s' % r2))
logging.debug(' '.join(diffcmd))
r = call(diffcmd, shell=0, cwd=tempdir)
finally:
shutil.rmtree(tempdir)
if __name__ == '__main__':
main()
|