From d71715961d413a30f1c9cbc4e95fb86a52240df3 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 27 Jun 2012 10:37:08 -0400 Subject: [PATCH 1/5] add resolve_reference() --- jsvn | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/jsvn b/jsvn index 615bacd..37af82c 100755 --- a/jsvn +++ b/jsvn @@ -320,6 +320,26 @@ def get_next_stash_idx(svn): idx = stash_ids[-1] + 1 return idx +# return (URL, path) tuple containing the full URL to the ref and the +# repo-relative path (ex: /branches/XXX) +# if ref is an actual file, URL is returned as an empty string +# tags resolve before branches +def resolve_reference(svn, ref): + if os.path.exists(ref): + return ('', ref) + if ref == 'trunk': + return (get_svn_root_url(svn) + '/trunk', '/trunk') + tl = get_svn_tag_list(svn) + if ref in tl: + path = '/tags/' + ref + return (get_svn_root_url(svn) + path, path) + bl = get_svn_branch_list(svn) + if ref in bl: + path = '/branches/' + ref + return (get_svn_root_url(svn) + path, path) + # ref was not an actual file, 'trunk', a tag name, or a branch name + return ('', ref) + ########################################################################### # Subcommand Handlers # ########################################################################### From e2ccd9c7cb8a13e22bddc3be8f73939bcd0665df Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 27 Jun 2012 10:45:33 -0400 Subject: [PATCH 2/5] diff: allow ".." syntax for specifying references --- jsvn | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/jsvn b/jsvn index 37af82c..fe5e877 100755 --- a/jsvn +++ b/jsvn @@ -709,6 +709,22 @@ def lockable(argv, svn, out): return RET_OK def diff(argv, svn, out): + for i, v in enumerate(argv): + m = re.match('(.*)(\.\.\.?)(.*)$', v) + if m is not None: + ref1, operator, ref2 = m.group(1, 2, 3) + url1, path1 = resolve_reference(svn, ref1) + if url1 == '': + sys.stderr.write('Could not resolve reference "%s"\n' % ref1) + return RET_ERR + url2, path2 = resolve_reference(svn, ref2) + if url2 == '': + sys.stderr.write('Could not resolve reference "%s"\n' % ref2) + return RET_ERR + if operator == '..': + # show the direct difference between the two refs + argv = argv[:i] + [url1, url2] + argv[i + 1:] + break pout = Popen([svn] + argv, stdout=PIPE).stdout for line in iter(pout.readline, ''): colordiff(out, line) From ac52eabb090b71cc4ad618a33411f8bbeb040257 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 27 Jun 2012 11:06:32 -0400 Subject: [PATCH 3/5] diff: allow "..." syntax for specifying references --- jsvn | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/jsvn b/jsvn index fe5e877..5b75829 100755 --- a/jsvn +++ b/jsvn @@ -340,6 +340,19 @@ def resolve_reference(svn, ref): # ref was not an actual file, 'trunk', a tag name, or a branch name return ('', ref) +def find_branched_revision(svn, branch_url, branch_path, base_path): + p = Popen([svn, 'log', '-v', branch_url], stdout=PIPE) + search_path = branch_path + for line in iter(p.stdout.readline, ''): + m = re.match('\s+A\s+(.*?)\s+\(from\s+(.*?):(\d+)\)\s*$', line) + if m is not None: + new_path, old_path, rev = m.group(1, 2, 3) + if new_path == search_path: + if old_path == base_path: + return int(rev) + search_path = old_path + return -1 + ########################################################################### # Subcommand Handlers # ########################################################################### @@ -710,7 +723,7 @@ def lockable(argv, svn, out): def diff(argv, svn, out): for i, v in enumerate(argv): - m = re.match('(.*)(\.\.\.?)(.*)$', v) + m = re.match('(.*?)(\.\.\.?)(.*)$', v) if m is not None: ref1, operator, ref2 = m.group(1, 2, 3) url1, path1 = resolve_reference(svn, ref1) @@ -721,10 +734,17 @@ def diff(argv, svn, out): if url2 == '': sys.stderr.write('Could not resolve reference "%s"\n' % ref2) return RET_ERR - if operator == '..': - # show the direct difference between the two refs - argv = argv[:i] + [url1, url2] + argv[i + 1:] - break + if operator == '...': + # amend url1 to include the pegged revision from where ref2 + # originally branched from it + r = find_branched_revision(svn, url2, path2, path1) + if r < 0: + sys.stderr.write(('Could not find revision where "%s" ' + + 'branched from "%s"\n') % (ref2, ref1)) + return RET_ERR + url1 += '@%d' % r + argv = argv[:i] + [url1, url2] + argv[i + 1:] + break pout = Popen([svn] + argv, stdout=PIPE).stdout for line in iter(pout.readline, ''): colordiff(out, line) From 1150cede62e47f359749280699003e4d97611e06 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 27 Jun 2012 11:12:53 -0400 Subject: [PATCH 4/5] log: allow ".." syntax for specifying references --- jsvn | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/jsvn b/jsvn index 5b75829..23c3e60 100755 --- a/jsvn +++ b/jsvn @@ -728,12 +728,10 @@ def diff(argv, svn, out): ref1, operator, ref2 = m.group(1, 2, 3) url1, path1 = resolve_reference(svn, ref1) if url1 == '': - sys.stderr.write('Could not resolve reference "%s"\n' % ref1) - return RET_ERR + continue url2, path2 = resolve_reference(svn, ref2) if url2 == '': - sys.stderr.write('Could not resolve reference "%s"\n' % ref2) - return RET_ERR + continue if operator == '...': # amend url1 to include the pegged revision from where ref2 # originally branched from it @@ -751,6 +749,23 @@ def diff(argv, svn, out): return RET_OK def log(argv, svn, out): + for i, v in enumerate(argv): + m = re.match('(.*)(\.\.)(.*)$', v) + if m is not None: + ref1, operator, ref2 = m.group(1, 2, 3) + url1, path1 = resolve_reference(svn, ref1) + if url1 == '': + continue + url2, path2 = resolve_reference(svn, ref2) + if url2 == '': + continue + r = find_branched_revision(svn, url2, path2, path1) + if r < 0: + sys.stderr.write(('Could not find revision where "%s" ' + + 'branched from "%s"\n') % (ref2, ref1)) + return RET_ERR + argv = argv[:i] + ['-rHEAD:%d' % (r + 1), url2] + argv[i + 1:] + break mode = 'normal' pout = Popen([svn] + argv, stdout=PIPE).stdout for line in iter(pout.readline, ''): From a989cf6fd7fb870a784111de4031cfa39eced907 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 27 Jun 2012 11:19:01 -0400 Subject: [PATCH 5/5] README: document ../... reference syntax for diff/log --- README | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README b/README index dbb6a34..ac7a97d 100644 --- a/README +++ b/README @@ -2,8 +2,8 @@ Josh's SVN wrapper script This wrapper script to Subversion supplements normal svn behavior by adding additional functionality or modifying the output of the default -svn subcommands. Much of the functionality implemented here was inspired -by the way that git works. +svn subcommands (simplification and colorization). Much of the functionality +implemented here was inspired by the way that git works. It is recommended to put this script in your $PATH as 'jsvn' or something other than 'svn' and to make an alias svn='jsvn'. @@ -27,6 +27,11 @@ Implemented subcommands: - with -d, delete - otherwise, create a new branch from the current one - also switch to the new branch if -s is given + diff + - allow specifying ref1..ref2 syntax to show the diff between two references + - references can be tag names, branch names, or 'trunk' + - allow specifying ref1...ref2 syntax to show the diff between the common + ancestor of ref1 and ref2 and ref2's HEAD tag[s] [[-d] ] | [-m ] - with no arguments, list tags - with -d, delete @@ -36,6 +41,9 @@ Implemented subcommands: - switch to 'trunk', branch name, or tag name without having to specify the full URL - falls back to Subversion "switch" if doesn't exist + log + - allow specifying ref1..ref2 syntax to show the log entries for + ref2 which are not a part of ref1 merge - merge branch into the current WC path - falls back to Subversion "merge" if doesn't exist @@ -79,13 +87,6 @@ Implemented subcommands: - delete stash object - defaults to the newest stash object created -The following subcommands are executed using their native handler, but -have their output simplified and/or colorized: - - diff - - log - - status - - update - If the subcommand name begins with two leading underscores ("__"), the underscores will be stripped and the command will be handled by native Subversion without any jsvn processing.