add "bisect" operation - close #10

This commit is contained in:
Josh Holtrop 2012-04-09 10:53:31 -04:00
parent 2b2589369f
commit 2f069625d1
2 changed files with 107 additions and 0 deletions

6
README
View File

@ -16,6 +16,12 @@ path and automatically alias 'svn' to it if so:
Implemented subcommands:
add <file>...
- add files as usual; add recursive contents of directories
bisect <operation>
operations:
- init initialize a new bisect operation
- bad mark the current revision as bad - containing the change sought
- good mark the current revision as good - older than the change sought
- reset terminate the bisect operation and return to the original revision
branch[es] [[-d] <branch_name>]
- with no arguments, list branches with '*' by the current one
- with -d, delete <branch>

101
jsvn
View File

@ -18,6 +18,12 @@
# Implemented subcommands:
# add <file>...
# - add files as usual; add recursive contents of directories
# bisect <operation>
# operations:
# - init initialize a new bisect operation
# - bad mark the current revision as bad - containing the change sought
# - good mark the current revision as good - older than the change sought
# - reset terminate the bisect operation and return to the original revision
# branch[es] [[-d] <branch_name>]
# - with no arguments, list branches with '*' by the current one
# - with -d, delete <branch>
@ -299,6 +305,13 @@ def get_svn_wc_root(svn):
return m.group(1)
return ''
def get_svn_wc_revision(svn):
for line in Popen([svn, 'info'], stdout=PIPE).communicate()[0].split('\n'):
m = re.match(r'Revision: (\d+)$', line)
if m is not None:
return int(m.group(1))
return 0
def getSVNRelPath(svn):
url = getSVNURL(svn)
parts = url.split('/')
@ -464,6 +477,93 @@ def add(argv, svn, out):
Popen([svn, 'add', path], stdout=out).wait()
return RET_OK
def bisect(argv, svn, out):
def usage():
sys.stderr.write('''Usage: bisect <operation>
Operations:
init initialize a new bisect operation
bad mark the current revision as bad - containing the change sought
good mark the current revision as good - older than the change sought
reset terminate the bisect operation and return to the original revision
''')
return RET_ERR
if len(argv) < 2:
return usage()
action = argv[1]
if action not in ('init', 'bad', 'good', 'reset'):
return usage()
wc_root = get_svn_wc_root(svn)
bisect_dir = '%s/.svn/bisect' % wc_root
def get_rev_from_file(fname):
path = '%s/%s' % (bisect_dir, fname)
if not os.path.exists(path):
return -1
fh = open(path, 'r')
line = fh.readline()
fh.close()
m = re.match('(\d+)$', line)
if m is None:
return -2
return int(m.group(1))
def write_rev_to_file(fname, rev):
fh = open('%s/%s' % (bisect_dir, fname), 'w')
fh.write(str(rev) + '\n')
fh.close()
def rm_bisect_files():
for f in os.listdir(bisect_dir):
os.unlink('%s/%s' % (bisect_dir, f))
def get_revs_between(start, end):
revs = []
proc = Popen([svn, 'log', '-r%d:%d' % (start, end)], stdout=PIPE)
for line in iter(proc.stdout.readline, ''):
m = re.match(r'r(\d+).*\|.*\|.*\|', line)
if m is not None:
rev = int(m.group(1))
if rev > start and rev < end:
revs.append(rev)
return revs
def do_bisect():
good_rev = get_rev_from_file('good')
bad_rev = get_rev_from_file('bad')
if good_rev < 0 or bad_rev < 0:
return
revs = get_revs_between(good_rev, bad_rev)
if len(revs) < 1:
if get_svn_wc_revision(svn) != bad_rev:
update(['update', '-r%d' % bad_rev], svn, out)
out.write('The first bad revision is %d\n' % get_svn_wc_revision(svn))
return
rev = revs[len(revs) / 2]
update(['update', '-r%d' % rev], svn, out)
out.write('Bisect: inspecting revision %d, %d revisions remaining\n'
% (rev, len(revs)))
def init_err():
sys.stderr.write('Error: did you bisect init first?\n')
return RET_ERR
if action == 'init':
if not os.path.exists(bisect_dir):
os.mkdir(bisect_dir)
rm_bisect_files()
write_rev_to_file('start', get_svn_wc_revision(svn))
out.write('Initialized for bisect\n')
elif action == 'bad':
if get_rev_from_file('start') < 0:
return init_err()
write_rev_to_file('bad', get_svn_wc_revision(svn))
do_bisect()
elif action == 'good':
if get_rev_from_file('start') < 0:
return init_err()
write_rev_to_file('good', get_svn_wc_revision(svn))
do_bisect()
elif action == 'reset':
rev = get_rev_from_file('start')
if rev < 0:
return init_err()
rm_bisect_files()
update(['update', '-r%d' % rev], svn, out)
return RET_OK
def branch(argv, svn, out):
origin = getSVNTopLevel(svn)
root = getSVNRoot(svn)
@ -1051,6 +1151,7 @@ def main(argv):
handlers = {
'add': add,
'bisect': bisect,
'branch': branch,
'externals': externals,
'switch': switch,