[MERGE] revno / revision-info fixups
Matthew D. Fuller
fullermd at over-yonder.net
Mon Jun 22 11:05:23 BST 2009
This rolls up and supercedes my two previous revno/revision-info fixup
patches, since they overlap and conflict with each other. It includes
all John's changes to the first batch, as well as bringing it up to
date with bzr.dev.
Summary:
- Both commands now have a --tree option to give info about the
working tree's basis revision, rather than the branch's head.
- Both act better when given bad input in one form or another (bad
revision, revision not in history, etc).
- Performance of revision-info when looking up multiple revs will be
significantly better.
- revision-info completely aligns its output, rather than the previous
hardcoded alignment.
--
Matthew Fuller (MF4839) | fullermd at over-yonder.net
Systems/Network Administrator | http://www.over-yonder.net/~fullermd/
On the Internet, nobody can hear you scream.
-------------- next part --------------
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: fullermd at over-yonder.net-20090622095540-\
# s4hqvvcks5tqod83
# target_branch: ../bzr.dev/
# testament_sha1: 48a7fd9fe8464e1a11837563ea85319e444f82ff
# timestamp: 2009-06-22 05:00:33 -0500
# base_revision_id: pqm at pqm.ubuntu.com-20090621043025-one1vuhpnsgdv5tv
#
# Begin patch
=== modified file 'NEWS'
--- NEWS 2009-06-21 04:30:25 +0000
+++ NEWS 2009-06-22 09:55:40 +0000
@@ -16,6 +16,10 @@
tree if the ``--strict`` option is used.
(Vincent Ladeuil, #284038)
+* ``bzr revno`` and ``bzr revision-info`` now have a ``--tree`` option to
+ show revision info for the working tree instead of the branch.
+ (Matthew Fuller, John Arbash Meinel)
+
Bug Fixes
*********
@@ -81,6 +85,11 @@
or ``bzr+ssh://`` is now much faster and involves no VFS operations.
This speeds up commands like ``bzr pull -r 123``. (Andrew Bennetts)
+* ``revision-info`` now properly aligns the revnos/revids in the output
+ and doesn't traceback when given revisions not in the current branch.
+ Performance is also significantly improved when requesting multiple revs
+ at once. (Matthew Fuller, John Arbash Meinel)
+
Documentation
*************
=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py 2009-06-19 09:06:56 +0000
+++ bzrlib/builtins.py 2009-06-22 09:54:39 +0000
@@ -474,11 +474,38 @@
_see_also = ['info']
takes_args = ['location?']
+ takes_options = [
+ Option('tree', help='Show revno of working tree'),
+ ]
@display_command
- def run(self, location=u'.'):
- self.outf.write(str(Branch.open_containing(location)[0].revno()))
- self.outf.write('\n')
+ def run(self, tree=False, location=u'.'):
+ try:
+ wt = WorkingTree.open_containing(location)[0]
+ b = wt.branch
+ wt.lock_read()
+ except (errors.NoWorkingTree, errors.NotLocalUrl):
+ wt = None
+ b = Branch.open_containing(location)[0]
+ b.lock_read()
+ try:
+ if tree:
+ if wt is None:
+ raise errors.NoWorkingTree(location)
+ revid = wt.last_revision()
+ try:
+ revno_t = wt.branch.revision_id_to_dotted_revno(revid)
+ except errors.NoSuchRevision:
+ revno_t = ('???',)
+ revno = ".".join(str(n) for n in revno_t)
+ else:
+ revno = b.revno()
+ finally:
+ if wt is None:
+ b.unlock()
+ else:
+ wt.unlock()
+ self.outf.write(str(revno) + '\n')
class cmd_revision_info(Command):
@@ -494,31 +521,56 @@
short_name='d',
type=unicode,
),
+ Option('tree', help='Show revno of working tree'),
]
@display_command
- def run(self, revision=None, directory=u'.', revision_info_list=[]):
-
- revs = []
- if revision is not None:
- revs.extend(revision)
- if revision_info_list is not None:
- for rev in revision_info_list:
- revs.append(RevisionSpec.from_string(rev))
-
- b = Branch.open_containing(directory)[0]
-
- if len(revs) == 0:
- revs.append(RevisionSpec.from_string('-1'))
-
- for rev in revs:
- revision_id = rev.as_revision_id(b)
- try:
- revno = '%4d' % (b.revision_id_to_revno(revision_id))
- except errors.NoSuchRevision:
- dotted_map = b.get_revision_id_to_revno_map()
- revno = '.'.join(str(i) for i in dotted_map[revision_id])
- print '%s %s' % (revno, revision_id)
+ def run(self, revision=None, directory=u'.', tree=False,
+ revision_info_list=[]):
+
+ try:
+ wt = WorkingTree.open_containing(directory)[0]
+ b = wt.branch
+ wt.lock_read()
+ except (errors.NoWorkingTree, errors.NotLocalUrl):
+ wt = None
+ b = Branch.open_containing(directory)[0]
+ b.lock_read()
+ try:
+ revision_ids = []
+ if revision is not None:
+ revision_ids.extend(rev.as_revision_id(b) for rev in revision)
+ if revision_info_list is not None:
+ for rev_str in revision_info_list:
+ rev_spec = RevisionSpec.from_string(rev_str)
+ revision_ids.append(rev_spec.as_revision_id(b))
+ # No arguments supplied, default to the last revision
+ if len(revision_ids) == 0:
+ if tree:
+ if wt is None:
+ raise errors.NoWorkingTree(directory)
+ revision_ids.append(wt.last_revision())
+ else:
+ revision_ids.append(b.last_revision())
+
+ revinfos = []
+ maxlen = 0
+ for revision_id in revision_ids:
+ try:
+ dotted_revno = b.revision_id_to_dotted_revno(revision_id)
+ revno = '.'.join(str(i) for i in dotted_revno)
+ except errors.NoSuchRevision:
+ revno = '???'
+ maxlen = max(maxlen, len(revno))
+ revinfos.append([revno, revision_id])
+ finally:
+ if wt is None:
+ b.unlock()
+ else:
+ wt.unlock()
+
+ for ri in revinfos:
+ self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
class cmd_add(Command):
=== modified file 'bzrlib/tests/blackbox/test_revision_info.py'
--- bzrlib/tests/blackbox/test_revision_info.py 2009-03-23 14:59:43 +0000
+++ bzrlib/tests/blackbox/test_revision_info.py 2009-06-22 09:49:32 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2004, 2005 Canonical Ltd
+# Copyright (C) 2004, 2005, 2009 Canonical Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -47,9 +47,9 @@
# Expected return values
values = {
- '1' : ' 1 a at r-0-1\n',
+ '1' : '1 a at r-0-1\n',
'1.1.1': '1.1.1 a at r-0-1.1.1\n',
- '2' : ' 2 a at r-0-2\n'
+ '2' : '2 a at r-0-2\n'
}
# Make sure with no arg it defaults to the head
@@ -60,7 +60,9 @@
self.check_output(values['1.1.1'], 'revision-info 1.1.1')
self.check_output(values['2'], 'revision-info 2')
self.check_output(values['1']+values['2'], 'revision-info 1 2')
- self.check_output(values['1']+values['1.1.1']+values['2'],
+ self.check_output(' '+values['1']+\
+ values['1.1.1']+\
+ ' '+values['2'],
'revision-info 1 1.1.1 2')
self.check_output(values['2']+values['1'], 'revision-info 2 1')
@@ -70,7 +72,9 @@
self.check_output(values['1.1.1'], 'revision-info --revision 1.1.1')
self.check_output(values['2'], 'revision-info -r 2')
self.check_output(values['1']+values['2'], 'revision-info -r 1..2')
- self.check_output(values['1']+values['1.1.1']+values['2'],
+ self.check_output(' '+values['1']+\
+ values['1.1.1']+\
+ ' '+values['2'],
'revision-info -r 1..1.1.1..2')
self.check_output(values['2']+values['1'], 'revision-info -r 2..1')
@@ -85,4 +89,40 @@
wt = self.make_branch_and_tree('branch')
wt.commit('Commit one', rev_id='a at r-0-1')
- self.check_output(' 1 a at r-0-1\n', 'revision-info -d branch')
+ self.check_output('1 a at r-0-1\n', 'revision-info -d branch')
+
+ def test_revision_info_tree(self):
+ # Make branch and checkout
+ wt = self.make_branch_and_tree('branch')
+ wt.commit('Commit one', rev_id='a at r-0-1')
+
+ # Make checkout and move the branch forward
+ wt.branch.create_checkout('checkout', lightweight=True)
+ wt.commit('Commit two', rev_id='a at r-0-2')
+
+ # Make sure the checkout gives the right answer for branch and
+ # tree
+ self.check_output('2 a at r-0-2\n', 'revision-info -d checkout')
+ self.check_output('1 a at r-0-1\n', 'revision-info --tree -d checkout')
+
+ def test_revision_info_tree_no_working_tree(self):
+ # Make branch with no tree
+ b = self.make_branch('branch')
+
+ # Try getting the --tree revision-info
+ out,err = self.run_bzr('revision-info --tree -d branch', retcode=3)
+ self.assertEqual('', out)
+ self.assertEqual('bzr: ERROR: No WorkingTree exists for "branch".\n',
+ err)
+
+ def test_revision_info_not_in_history(self):
+ builder = self.make_branch_builder('branch')
+ builder.start_series()
+ builder.build_snapshot('A-id', None, [
+ ('add', ('', 'root-id', 'directory', None))])
+ builder.build_snapshot('B-id', ['A-id'], [])
+ builder.build_snapshot('C-id', ['A-id'], [])
+ builder.finish_series()
+ self.check_output(' 1 A-id\n??? B-id\n 2 C-id\n',
+ 'revision-info -d branch'
+ ' revid:A-id revid:B-id revid:C-id')
=== modified file 'bzrlib/tests/blackbox/test_revno.py'
--- bzrlib/tests/blackbox/test_revno.py 2009-03-23 14:59:43 +0000
+++ bzrlib/tests/blackbox/test_revno.py 2009-06-22 09:33:02 +0000
@@ -22,9 +22,9 @@
import os
from bzrlib.branch import Branch
-from bzrlib.tests import TestCaseInTempDir
+from bzrlib.tests import TestCaseWithTransport
-class TestRevno(TestCaseInTempDir):
+class TestRevno(TestCaseWithTransport):
def test_revno(self):
@@ -50,4 +50,72 @@
self.assertEquals(int(bzr('revno a')), 2)
self.assertEquals(int(bzr('revno a/baz')), 2)
-
+ def test_revno_tree(self):
+ # Make branch and checkout
+ wt = self.make_branch_and_tree('branch')
+ checkout = wt.branch.create_checkout('checkout', lightweight=True)
+
+ # Get the checkout out of date
+ self.build_tree(['branch/file'])
+ wt.add(['file'])
+ wt.commit('mkfile')
+
+ # Make sure revno says we're on 1
+ out,err = self.run_bzr('revno checkout')
+ self.assertEqual('', err)
+ self.assertEqual('1\n', out)
+
+ # Make sure --tree knows it's still on 0
+ out,err = self.run_bzr('revno --tree checkout')
+ self.assertEqual('', err)
+ self.assertEqual('0\n', out)
+
+ def test_revno_tree_no_tree(self):
+ # Make treeless branch
+ b = self.make_branch('branch')
+
+ # Try getting it's --tree revno
+ out,err = self.run_bzr('revno --tree branch', retcode=3)
+ self.assertEqual('', out)
+ self.assertEqual('bzr: ERROR: No WorkingTree exists for "branch".\n',
+ err)
+
+ def test_dotted_revno_tree(self):
+ builder = self.make_branch_builder('branch')
+ builder.start_series()
+ builder.build_snapshot('A-id', None, [
+ ('add', ('', 'root-id', 'directory', None)),
+ ('add', ('file', 'file-id', 'file', 'content\n'))])
+ builder.build_snapshot('B-id', ['A-id'], [])
+ builder.build_snapshot('C-id', ['A-id', 'B-id'], [])
+ builder.finish_series()
+ b = builder.get_branch()
+ co_b = b.create_checkout('checkout_b', lightweight=True,
+ revision_id='B-id')
+ out, err = self.run_bzr('revno checkout_b')
+ self.assertEqual('', err)
+ self.assertEqual('2\n', out)
+ out, err = self.run_bzr('revno --tree checkout_b')
+ self.assertEqual('', err)
+ self.assertEqual('1.1.1\n', out)
+
+ def test_stale_revno_tree(self):
+ builder = self.make_branch_builder('branch')
+ builder.start_series()
+ builder.build_snapshot('A-id', None, [
+ ('add', ('', 'root-id', 'directory', None)),
+ ('add', ('file', 'file-id', 'file', 'content\n'))])
+ builder.build_snapshot('B-id', ['A-id'], [])
+ builder.build_snapshot('C-id', ['A-id'], [])
+ builder.finish_series()
+ b = builder.get_branch()
+ # The branch is now at "C-id", but the checkout is still at "B-id"
+ # which is no longer in the history
+ co_b = b.create_checkout('checkout_b', lightweight=True,
+ revision_id='B-id')
+ out, err = self.run_bzr('revno checkout_b')
+ self.assertEqual('', err)
+ self.assertEqual('2\n', out)
+ out, err = self.run_bzr('revno --tree checkout_b')
+ self.assertEqual('', err)
+ self.assertEqual('???\n', out)
# Begin bundle
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
More information about the bazaar
mailing list