[MERGE] DWIM revspecs

Matthew D. Fuller fullermd at over-yonder.net
Tue Aug 18 09:24:14 BST 2009


On Sat, Jul 25, 2009 at 10:41:11AM -0500 I heard the voice of
Matthew D. Fuller, and lo! it spake thus:
> 
> One additional reason merging it would fail would be that there are
> some test failures I didn't clean up.
> 
> I think the Rightest Answer is probably just to remove those bits of
> testing.  The reason is because they think they're testing bad
> revno's, but with this change what they're ACTUALLY testing now is
> something we can't find among the DWIM choices (which I'm already
> testing in the TRS_dwim tests).  I'm not quite certain of the right
> thing to do, though, so I'd like some second opinions.

Well, based on the extensive feedback received, I've gone ahead and
eliminated some of these tests, and shuffled around others.  There
were some doctests this also required changes to; I'm not really sure
if some of those shouldn't just be eliminated, since they don't add
anything, but I'll let somebody else make that judgement call.

In a full selftest run, this gives one new error in addition to the
bunch I expect from my last full run attempt, but it's in
blackbox.test_serve, so I'm pretty sure it doesn't have anything to do
with this change.


-- 
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-20090818081758-\
#   58e7z40dq5auxjks
# target_branch: file:///home/fullermd/src/bzr/bzr.dev/
# testament_sha1: eba9dba46364f1ee25d0e12d80fd173f7124b5ad
# timestamp: 2009-08-18 03:18:15 -0500
# base_revision_id: pqm at pqm.ubuntu.com-20090818013856-vezgd3arfawq9x2l
# 
# Begin patch
=== modified file 'NEWS'
--- NEWS	2009-08-18 01:38:56 +0000
+++ NEWS	2009-08-18 08:17:58 +0000
@@ -12,6 +12,10 @@
 Improvements
 ************
 
+* Revision specifiers can now be given in a more DWIM form, without
+  needing explicit prefixes for specifiers like tags or revision id's.
+  See ``bzr help revisionspec`` for full details.  (Matthew Fuller)
+
 * A better description of the platform is shown in crash tracebacks, ``bzr
   --version`` and ``bzr selftest``.
   (Martin Pool, #409137)

=== modified file 'bzrlib/help_topics/__init__.py'
--- bzrlib/help_topics/__init__.py	2009-06-19 09:06:56 +0000
+++ bzrlib/help_topics/__init__.py	2009-07-25 15:14:03 +0000
@@ -152,10 +152,16 @@
     out.append(
 """Revision Identifiers
 
-A revision identifier refers to a specific state of a branch's history. It can
-be a revision number, or a keyword followed by ':' and often other
-parameters. Some examples of identifiers are '3', 'last:1', 'before:yesterday'
-and 'submit:'.
+A revision identifier refers to a specific state of a branch's history.  It
+can be expressed in several ways.  It can begin with a keyword to
+unambiguously specify a given lookup type; some examples are 'last:1',
+'before:yesterday' and 'submit:'.
+
+Alternately, it can be given without a keyword, in which case it will be
+checked as a revision number, a tag, a revision id, a date specification, or a
+branch specification, in that order.  For example, 'date:today' could be
+written as simply 'today', though if you have a tag called 'today' that will
+be found first.
 
 If 'REV1' and 'REV2' are revision identifiers, then 'REV1..REV2' denotes a
 revision range. Examples: '3647..3649', 'date:yesterday..-1' and

=== modified file 'bzrlib/option.py'
--- bzrlib/option.py	2009-04-03 20:05:25 +0000
+++ bzrlib/option.py	2009-08-18 08:10:44 +0000
@@ -40,25 +40,25 @@
     each revision specifier supplied.
 
     >>> _parse_revision_str('234')
-    [<RevisionSpec_revno 234>]
+    [<RevisionSpec_dwim 234>]
     >>> _parse_revision_str('234..567')
-    [<RevisionSpec_revno 234>, <RevisionSpec_revno 567>]
+    [<RevisionSpec_dwim 234>, <RevisionSpec_dwim 567>]
     >>> _parse_revision_str('..')
     [<RevisionSpec None>, <RevisionSpec None>]
     >>> _parse_revision_str('..234')
-    [<RevisionSpec None>, <RevisionSpec_revno 234>]
+    [<RevisionSpec None>, <RevisionSpec_dwim 234>]
     >>> _parse_revision_str('234..')
-    [<RevisionSpec_revno 234>, <RevisionSpec None>]
+    [<RevisionSpec_dwim 234>, <RevisionSpec None>]
     >>> _parse_revision_str('234..456..789') # Maybe this should be an error
-    [<RevisionSpec_revno 234>, <RevisionSpec_revno 456>, <RevisionSpec_revno 789>]
+    [<RevisionSpec_dwim 234>, <RevisionSpec_dwim 456>, <RevisionSpec_dwim 789>]
     >>> _parse_revision_str('234....789') #Error ?
-    [<RevisionSpec_revno 234>, <RevisionSpec None>, <RevisionSpec_revno 789>]
+    [<RevisionSpec_dwim 234>, <RevisionSpec None>, <RevisionSpec_dwim 789>]
     >>> _parse_revision_str('revid:test at other.com-234234')
     [<RevisionSpec_revid revid:test at other.com-234234>]
     >>> _parse_revision_str('revid:test at other.com-234234..revid:test at other.com-234235')
     [<RevisionSpec_revid revid:test at other.com-234234>, <RevisionSpec_revid revid:test at other.com-234235>]
     >>> _parse_revision_str('revid:test at other.com-234234..23')
-    [<RevisionSpec_revid revid:test at other.com-234234>, <RevisionSpec_revno 23>]
+    [<RevisionSpec_revid revid:test at other.com-234234>, <RevisionSpec_dwim 23>]
     >>> _parse_revision_str('date:2005-04-12')
     [<RevisionSpec_date date:2005-04-12>]
     >>> _parse_revision_str('date:2005-04-12 12:24:33')
@@ -68,27 +68,23 @@
     >>> _parse_revision_str('date:2005-04-12,12:24:33')
     [<RevisionSpec_date date:2005-04-12,12:24:33>]
     >>> _parse_revision_str('-5..23')
-    [<RevisionSpec_revno -5>, <RevisionSpec_revno 23>]
+    [<RevisionSpec_dwim -5>, <RevisionSpec_dwim 23>]
     >>> _parse_revision_str('-5')
-    [<RevisionSpec_revno -5>]
+    [<RevisionSpec_dwim -5>]
     >>> _parse_revision_str('123a')
-    Traceback (most recent call last):
-      ...
-    NoSuchRevisionSpec: No namespace registered for string: '123a'
+    [<RevisionSpec_dwim 123a>]
     >>> _parse_revision_str('abc')
-    Traceback (most recent call last):
-      ...
-    NoSuchRevisionSpec: No namespace registered for string: 'abc'
+    [<RevisionSpec_dwim abc>]
     >>> _parse_revision_str('branch:../branch2')
     [<RevisionSpec_branch branch:../branch2>]
     >>> _parse_revision_str('branch:../../branch2')
     [<RevisionSpec_branch branch:../../branch2>]
     >>> _parse_revision_str('branch:../../branch2..23')
-    [<RevisionSpec_branch branch:../../branch2>, <RevisionSpec_revno 23>]
+    [<RevisionSpec_branch branch:../../branch2>, <RevisionSpec_dwim 23>]
     >>> _parse_revision_str('branch:..\\\\branch2')
     [<RevisionSpec_branch branch:..\\branch2>]
     >>> _parse_revision_str('branch:..\\\\..\\\\branch2..23')
-    [<RevisionSpec_branch branch:..\\..\\branch2>, <RevisionSpec_revno 23>]
+    [<RevisionSpec_branch branch:..\\..\\branch2>, <RevisionSpec_dwim 23>]
     """
     # TODO: Maybe move this into revisionspec.py
     revs = []
@@ -104,7 +100,7 @@
     parent of the revision.
 
     >>> _parse_change_str('123')
-    (<RevisionSpec_before before:123>, <RevisionSpec_revno 123>)
+    (<RevisionSpec_before before:123>, <RevisionSpec_dwim 123>)
     >>> _parse_change_str('123..124')
     Traceback (most recent call last):
       ...

=== modified file 'bzrlib/revisionspec.py'
--- bzrlib/revisionspec.py	2009-03-23 14:59:43 +0000
+++ bzrlib/revisionspec.py	2009-07-25 15:14:03 +0000
@@ -123,10 +123,10 @@
 
     help_txt = """A parsed revision specification.
 
-    A revision specification can be an integer, in which case it is
-    assumed to be a revno (though this will translate negative values
-    into positive ones); or it can be a string, in which case it is
-    parsed for something like 'date:' or 'revid:' etc.
+    A revision specification is a string, which may be unambiguous about
+    what it represents by giving a prefix like 'date:' or 'revid:' etc,
+    or it may have no prefix, in which case it's tried against several
+    specifier types in sequence to determine what the user meant.
 
     Revision specs are an UI element, and they have been moved out
     of the branch class to leave "back-end" classes unaware of such
@@ -165,17 +165,8 @@
                              spectype.__name__, spec)
                 if spec.startswith(spectype.prefix):
                     return spectype(spec, _internal=True)
-            # RevisionSpec_revno is special cased, because it is the only
-            # one that directly handles plain integers
-            # TODO: This should not be special cased rather it should be
-            # a method invocation on spectype.canparse()
-            global _revno_regex
-            if _revno_regex is None:
-                _revno_regex = re.compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$')
-            if _revno_regex.match(spec) is not None:
-                return RevisionSpec_revno(spec, _internal=True)
-
-            raise errors.NoSuchRevisionSpec(spec)
+            # Otherwise treat it as a DWIM
+            return RevisionSpec_dwim(spec, _internal=True)
 
     def __init__(self, spec, _internal=False):
         """Create a RevisionSpec referring to the Null revision.
@@ -291,16 +282,79 @@
 
 # private API
 
+class RevisionSpec_dwim(RevisionSpec):
+    """Provides a DWIMish revision specifier lookup.
+
+    Note that this does not go in the revspec_registry.  It's solely
+    called from RevisionSpec.from_string().
+    """
+
+    help_txt = None
+    # Default to False to save building the history in the revno case
+    wants_revision_history = False
+
+    # Util
+    def __try_spectype(self, rstype, spec, branch):
+        rs = rstype(spec, _internal=True)
+        # Hit in_history to find out if it exists, or we need to try the
+        # next type.
+        return rs.in_history(branch)
+
+    def _match_on(self, branch, revs):
+        """Run the lookup and see what we can get."""
+        spec = self.spec
+
+        # First, see if it's a revno
+        global _revno_regex
+        if _revno_regex is None:
+            _revno_regex = re.compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$')
+        if _revno_regex.match(spec) is not None:
+            try:
+                return self.__try_spectype(RevisionSpec_revno, spec, branch)
+            except errors.InvalidRevisionSpec:
+                pass
+
+        # It's not a revno, so now we need this
+        self.wants_revision_history = True
+
+        # OK, next let's try for a tag
+        try:
+            return self.__try_spectype(RevisionSpec_tag, spec, branch)
+        except (errors.NoSuchTag, errors.TagsNotSupported):
+            pass
+
+        # Maybe it's a revid?
+        try:
+            return self.__try_spectype(RevisionSpec_revid, spec, branch)
+        except errors.InvalidRevisionSpec:
+            pass
+
+        # Perhaps a date?
+        try:
+            return self.__try_spectype(RevisionSpec_date, spec, branch)
+        except errors.InvalidRevisionSpec:
+            pass
+
+        # OK, last try, maybe it's a branch
+        try:
+            return self.__try_spectype(RevisionSpec_branch, spec, branch)
+        except errors.NotBranchError:
+            pass
+
+        # Well, I dunno what it is.
+        raise errors.InvalidRevisionSpec(self.spec, branch)
+
+
 class RevisionSpec_revno(RevisionSpec):
     """Selects a revision using a number."""
 
     help_txt = """Selects a revision using a number.
 
     Use an integer to specify a revision in the history of the branch.
-    Optionally a branch can be specified. The 'revno:' prefix is optional.
-    A negative number will count from the end of the branch (-1 is the
-    last revision, -2 the previous one). If the negative number is larger
-    than the branch's history, the first revision is returned.
+    Optionally a branch can be specified.  A negative number will count
+    from the end of the branch (-1 is the last revision, -2 the previous
+    one). If the negative number is larger than the branch's history, the
+    first revision is returned.
     Examples::
 
       revno:1                   -> return the first revision of this branch

=== modified file 'bzrlib/tests/test_revisionspec.py'
--- bzrlib/tests/test_revisionspec.py	2009-03-23 14:59:43 +0000
+++ bzrlib/tests/test_revisionspec.py	2009-08-18 07:34:32 +0000
@@ -146,24 +146,38 @@
     def test_object(self):
         self.assertRaises(TypeError, RevisionSpec.from_string, object())
 
-    def test_unregistered_spec(self):
-        self.assertRaises(errors.NoSuchRevisionSpec,
-                          RevisionSpec.from_string, 'foo')
-        self.assertRaises(errors.NoSuchRevisionSpec,
-                          RevisionSpec.from_string, '123a')
-
-
-
-class TestRevnoFromString(TestCase):
-
-    def test_from_string_dotted_decimal(self):
-        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '-1.1')
-        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '.1')
-        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1..1')
-        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1.2..1')
-        self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1.')
-        self.assertIsInstance(RevisionSpec.from_string('1.1'), RevisionSpec_revno)
-        self.assertIsInstance(RevisionSpec.from_string('1.1.3'), RevisionSpec_revno)
+
+class TestRevisionSpec_dwim(TestRevisionSpec):
+
+    # Don't need to test revno's explicitly since TRS_revno already
+    # covers that well for us
+    def test_dwim_spec_revno(self):
+        self.assertInHistoryIs(2, 'r2', '2')
+        self.assertAsRevisionId('alt_r2', '1.1.1')
+
+    def test_dwim_spec_revid(self):
+        self.assertInHistoryIs(2, 'r2', 'r2')
+
+    def test_dwim_spec_tag(self):
+        self.tree.branch.tags.set_tag('footag', 'r1')
+        self.assertAsRevisionId('r1', 'footag')
+        self.tree.branch.tags.delete_tag('footag')
+        self.assertRaises(errors.InvalidRevisionSpec,
+                          self.get_in_history, 'footag')
+
+    def test_dwim_spec_date(self):
+        self.assertAsRevisionId('r1', 'today')
+
+    def test_dwim_spec_branch(self):
+        self.assertInHistoryIs(None, 'alt_r2', 'tree2')
+
+    def test_dwim_spec_nonexistent(self):
+        self.assertInvalid('somethingrandom', invalid_as_revision_id=False)
+        self.assertInvalid('-1.1', invalid_as_revision_id=False)
+        self.assertInvalid('.1', invalid_as_revision_id=False)
+        self.assertInvalid('1..1', invalid_as_revision_id=False)
+        self.assertInvalid('1.2..1', invalid_as_revision_id=False)
+        self.assertInvalid('1.', invalid_as_revision_id=False)
 
 
 class TestRevisionSpec_revno(TestRevisionSpec):

=== modified file 'doc/en/user-guide/specifying_revisions.txt'
--- doc/en/user-guide/specifying_revisions.txt	2009-04-04 02:57:47 +0000
+++ doc/en/user-guide/specifying_revisions.txt	2009-07-25 15:21:25 +0000
@@ -36,17 +36,23 @@
  +----------------------+------------------------------------+
  | *number*             | revision number                    |
  +----------------------+------------------------------------+
- | **revno**:*number*   | positive revision number           |
+ | **revno**:*number*   | revision number                    |
  +----------------------+------------------------------------+
  | **last**:*number*    | negative revision number           |
  +----------------------+------------------------------------+
+ | *guid*               | globally unique revision id        |
+ +----------------------+------------------------------------+
  | **revid**:*guid*     | globally unique revision id        |
  +----------------------+------------------------------------+
  | **before**:*rev*     | leftmost parent of ''rev''         |
  +----------------------+------------------------------------+
- | **date**:*value*     | first entry after a given date     |
- +----------------------+------------------------------------+
- | **tag**:*value*      | revision matching a given tag      |
+ | *date-value*         | first entry after a given date     |
+ +----------------------+------------------------------------+
+ | **date**:*date-value*| first entry after a given date     |
+ +----------------------+------------------------------------+
+ | *tag-name*           | revision matching a given tag      |
+ +----------------------+------------------------------------+
+ | **tag**:*tag-name*   | revision matching a given tag      |
  +----------------------+------------------------------------+
  | **ancestor**:*path*  | last merged revision from a branch |
  +----------------------+------------------------------------+

# Begin bundle
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
+z95jUP9Pl+Kfx8v8XckU4UJBoWrDhA=


More information about the bazaar mailing list