Merge branch 'smart-ref-spec'

This commit is contained in:
Josh Holtrop 2012-06-27 11:19:10 -04:00
commit 0f4def92e4
2 changed files with 81 additions and 9 deletions

19
README
View File

@ -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 <branch>
- 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] <tag_name>] | [-m <old_tag_name> <new_tag_name>]
- with no arguments, list tags
- with -d, delete <tag>
@ -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 <short_name> doesn't exist
log
- allow specifying ref1..ref2 syntax to show the log entries for
ref2 which are not a part of ref1
merge <branch>
- merge branch <branch> into the current WC path
- falls back to Subversion "merge" if <branch> doesn't exist
@ -79,13 +87,6 @@ Implemented subcommands:
- delete stash object <id>
- <id> 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.

71
jsvn
View File

@ -320,6 +320,39 @@ 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)
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 #
###########################################################################
@ -689,12 +722,50 @@ 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 == '':
continue
url2, path2 = resolve_reference(svn, ref2)
if url2 == '':
continue
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)
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, ''):