#!/usr/bin/env python # Josh's SVN wrapper script # # Recommend putting in path as 'jsvn' or something other than 'svn' and # making an alias svn='jsvn' # # The script detects if you have colorsvn and colordiff and uses them for # appropriate subcommands if so. # # Implemented subcommands: # branch[es] # - with no arguments, list branches with '*' by the current one # - with an argument, create a new branch from the current one # tags # - list tags # switch # - switch to 'trunk', branch name, or tag name without having to specify # the full URL # - falls back to Subversion "switch" if doesn't exist import sys import os import re from subprocess import * PATH = os.environ['PATH'].split(os.pathsep) def findInPath(cmd): for p in PATH: full_path = os.path.join(p, cmd) if os.path.exists(full_path): return full_path return '' def getSVNURL(svn): for line in Popen([svn, 'info'], stdout=PIPE).communicate()[0].split('\n'): m = re.match('^URL:\s*(.*?)\s*$', line) if m is not None: return m.group(1) return '' def getSVNRoot(svn): url = getSVNURL(svn) parts = url.split('/') for i in range(0, len(parts)): if parts[i] in ('trunk', 'tags', 'branches'): return '/'.join(parts[:i]) return '' def getSVNRelPath(svn): url = getSVNURL(svn) parts = url.split('/') for i in range(0, len(parts) - 1): if parts[i] == 'trunk' or i > 0 and parts[i-1] in ('tags', 'branches'): return '/' + '/'.join(parts[i+1:]) return '/' def getSVNTopLevel(svn): url = getSVNURL(svn) parts = url.split('/') for i in range(0, len(parts)): if parts[i] == 'trunk' or i > 0 and parts[i-1] in ('tags', 'branches'): return '/'.join(parts[:i+1]) return '' def getSVNBranchList(svn): colist = [] root = getSVNRoot(svn) lines = Popen([svn, 'ls', root + '/branches'], stdout=PIPE).communicate()[0].split('\n') for line in lines: if re.match(r'^\s*$', line) is None: colist.append(re.sub(r'/$', '', line)) return colist def getSVNTagList(svn): colist = [] root = getSVNRoot(svn) lines = Popen([svn, 'ls', root + '/tags'], stdout=PIPE).communicate()[0].split('\n') for line in lines: if re.match(r'^\s*$', line) is None: colist.append(re.sub(r'/$', '', line)) return colist def branch(argv, svn): if len(argv) < 2: bl = ['trunk'] + getSVNBranchList(svn) current = getSVNTopLevel(svn).split('/')[-1] for b in bl: sys.stdout.write('*' if b == current else ' ') sys.stdout.write(b + '\n') return 0 branch_name = argv[1] origin = getSVNTopLevel(svn) root = getSVNRoot(svn) if origin == '' or root == '': sys.stderr.write("Could not determine origin/root URL\n") return 1 comment = "Created '%s' branch" % branch_name branch_path = root + '/branches/' + branch_name Popen([svn, 'copy', origin, branch_path, '-m', comment]).wait() return 0 def tags(argv, svn): tl = getSVNTagList(svn) for t in tl: sys.stdout.write(t + '\n') return 0 def switch(argv, svn, colorsvn): if len(argv) < 2: return -1 root = getSVNRoot(svn) path = getSVNRelPath(svn) if argv[1] == 'trunk': Popen([svn, 'switch', root + '/trunk' + path]).wait() return 0 bl = getSVNBranchList(svn) if argv[1] in bl: Popen([svn, 'switch', root + '/branches/' + argv[1] + path]).wait() return 0 tl = getSVNTagList(svn) if argv[1] in tl: Popen([svn, 'switch', root + '/tags/' + argv[1] + path]).wait() return 0 return -2 def main(argv): realsvn = findInPath('svn') colorsvn = findInPath('colorsvn') colordiff = findInPath('colordiff') if realsvn == '': sys.stderr.write("Error: 'svn' not found in path\n") return 1 if len(argv) >= 1: if argv[0] == "branch" or argv[0] == "branches": return branch(argv, realsvn) if argv[0] == "switch": r = switch(argv, realsvn, colorsvn) if r >= 0: return r if argv[0] == "tags": return tags(argv, realsvn) if argv[0] == "diff" and colordiff != '': diff_out = Popen([realsvn] + argv, stdout=PIPE).stdout Popen([colordiff], stdin=diff_out).wait() return 0 if colorsvn != '': Popen([colorsvn] + argv).wait() return 0 Popen([realsvn] + argv).wait() return 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))