Rev 6128: (jelmer) Allow tag implementations to not support ghost revisions. (Jelmer in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Tue Sep 6 10:11:57 UTC 2011


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 6128 [merge]
revision-id: pqm at pqm.ubuntu.com-20110906101154-46kb97u5tdj9enyi
parent: pqm at pqm.ubuntu.com-20110905194835-zadpgrm73dsrxrkd
parent: jelmer at samba.org-20110905211759-de03qv7b88po54n6
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Tue 2011-09-06 10:11:54 +0000
message:
  (jelmer) Allow tag implementations to not support ghost revisions. (Jelmer
   Vernooij)
modified:
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
  bzrlib/tag.py                  tag.py-20070212110532-91cw79inah2cfozx-1
  bzrlib/tests/per_branch/test_tags.py test_tags.py-20070212110545-w2s799hm2jlbsmg5-1
  doc/en/release-notes/bzr-2.5.txt bzr2.5.txt-20110708125756-587p0hpw7oke4h05-1
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2011-09-01 14:36:00 +0000
+++ b/bzrlib/branch.py	2011-09-05 14:16:12 +0000
@@ -1739,6 +1739,14 @@
         """True if this format supports tags stored in the branch"""
         return False  # by default
 
+    def tags_are_versioned(self):
+        """Whether the tag container for this branch versions tags."""
+        return False
+
+    def supports_tags_referencing_ghosts(self):
+        """True if tags can reference ghost revisions."""
+        return True
+
 
 class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
     """A factory for a BranchFormat object, permitting simple lazy registration.

=== modified file 'bzrlib/errors.py'
--- a/bzrlib/errors.py	2011-08-21 13:49:30 +0000
+++ b/bzrlib/errors.py	2011-09-05 10:28:30 +0000
@@ -2349,6 +2349,14 @@
     """
 
 
+class GhostTagsNotSupported(BzrError):
+
+    _fmt = "Ghost tags not supported by format %(format)r."
+
+    def __init__(self, format):
+        self.format = format
+
+
 class BinaryFile(BzrError):
 
     _fmt = "File is binary but should be text."

=== modified file 'bzrlib/tag.py'
--- a/bzrlib/tag.py	2011-08-31 16:48:52 +0000
+++ b/bzrlib/tag.py	2011-09-05 14:16:12 +0000
@@ -47,6 +47,63 @@
     def __init__(self, branch):
         self.branch = branch
 
+    def get_tag_dict(self):
+        """Return a dictionary mapping tags to revision ids.
+        """
+        raise NotImplementedError(self.get_tag_dict)
+
+    def get_reverse_tag_dict(self):
+        """Return a dictionary mapping revision ids to list of tags.
+        """
+        raise NotImplementedError(self.get_reverse_tag_dict)
+
+    def merge_to(self, to_tags, overwrite=False, ignore_master=False):
+        """Merge new tags from this tags container into another.
+
+        :param to_tags: Tags container to merge into
+        :param overwrite: Whether to overwrite existing, divergent, tags.
+        :param ignore_master: Do not modify the tags in the target's master
+            branch (if any).  Default is false (so the master will be updated).
+            New in bzr 2.3.
+        :return: Tuple with tag updates as dictionary and tag conflicts
+        """
+        raise NotImplementedError(self.merge_to)
+
+    def set_tag(self, tag_name, revision):
+        """Set a tag.
+
+        :param tag_name: Tag name
+        :param revision: Revision id
+        :raise GhostTagsNotSupported: if revision is not present in
+            the branch repository
+        """
+        raise NotImplementedError(self.set_tag)
+
+    def lookup_tag(self, tag_name):
+        """Look up a tag.
+
+        :param tag_name: Tag to look up
+        :raise NoSuchTag: Raised when tag does not exist
+        :return: Matching revision id
+        """
+        raise NotImplementedError(self.lookup_tag)
+
+    def delete_tag(self, tag_name):
+        """Delete a tag.
+
+        :param tag_name: Tag to delete
+        :raise NoSuchTag: Raised when tag does not exist
+        """
+        raise NotImplementedError(self.delete_tag)
+
+    def rename_revisions(self, rename_map):
+        """Replace revision ids according to a rename map.
+
+        :param rename_map: Dictionary mapping old revision ids to
+            new revision ids.
+        """
+        raise NotImplementedError(self.rename_revisions)
+
     def has_tag(self, tag_name):
         return self.get_tag_dict().has_key(tag_name)
 
@@ -262,7 +319,7 @@
 
     def rename_revisions(self, rename_map):
         """Rename revisions in this tags dictionary.
-        
+
         :param rename_map: Dictionary mapping old revids to new revids
         """
         reverse_tags = self.get_reverse_tag_dict()

=== modified file 'bzrlib/tests/per_branch/test_tags.py'
--- a/bzrlib/tests/per_branch/test_tags.py	2011-08-31 17:11:32 +0000
+++ b/bzrlib/tests/per_branch/test_tags.py	2011-09-05 21:17:59 +0000
@@ -22,6 +22,7 @@
 
 from bzrlib import (
     branch,
+    bzrdir as _mod_bzrdir,
     errors,
     tests,
     )
@@ -39,13 +40,22 @@
             raise tests.TestSkipped(
                 "format %s doesn't support tags" % branch._format)
 
+    def make_branch_with_revisions(self, relpath, revisions):
+        builder = self.make_branch_builder(relpath)
+        builder.start_series()
+        for revid in revisions:
+            builder.build_commit(rev_id=revid)
+        builder.finish_series()
+        return builder.get_branch()
+
     def test_tags_initially_empty(self):
         b = self.make_branch('b')
         tags = b.tags.get_tag_dict()
         self.assertEqual(tags, {})
 
     def test_make_and_lookup_tag(self):
-        b = self.make_branch('b')
+        b = self.make_branch_with_revisions('b',
+            ['target-revid-1', 'target-revid-2'])
         b.tags.set_tag('tag-name', 'target-revid-1')
         b.tags.set_tag('other-name', 'target-revid-2')
         # then reopen the branch and see they're still there
@@ -62,16 +72,26 @@
         self.assertFalse(b.tags.has_tag('imaginary'))
 
     def test_reverse_tag_dict(self):
-        b = self.make_branch('b')
+        b = self.make_branch_with_revisions('b',
+            ['target-revid-1', 'target-revid-2'])
         b.tags.set_tag('tag-name', 'target-revid-1')
         b.tags.set_tag('other-name', 'target-revid-2')
         # then reopen the branch and check reverse map id->tags list
         b = branch.Branch.open('b')
-        self.assertEqual(b.tags.get_reverse_tag_dict(),
+        self.assertEqual(dict(b.tags.get_reverse_tag_dict()),
             {'target-revid-1': ['tag-name'],
              'target-revid-2': ['other-name'],
             })
 
+    def test_ghost_tag(self):
+        b = self.make_branch('b')
+        if not b._format.supports_tags_referencing_ghosts():
+            self.assertRaises(errors.GhostTagsNotSupported,
+                b.tags.set_tag, "ghost", "idontexist")
+        else:
+            b.tags.set_tag("ghost", "idontexist")
+            self.assertEquals("idontexist", b.tags.lookup_tag("ghost"))
+
     def test_no_such_tag(self):
         b = self.make_branch('b')
         try:
@@ -83,8 +103,8 @@
             self.fail("didn't get expected exception")
 
     def test_merge_tags(self):
-        b1 = self.make_branch('b1')
-        b2 = self.make_branch('b2')
+        b1 = self.make_branch_with_revisions('b1', ['revid', 'revid-1'])
+        b2 = self.make_branch_with_revisions('b2', ['revid-2'])
         # if there are tags in the source and not the destination, then they
         # just go across
         b1.tags.set_tag('tagname', 'revid')
@@ -109,18 +129,18 @@
         self.assertEquals(b2.tags.lookup_tag('conflicts'), 'revid-2')
 
     def test_unicode_tag(self):
-        b1 = self.make_branch('b')
         tag_name = u'\u3070'
         # in anticipation of the planned change to treating revision ids as
         # just 8bit strings
         revid = ('revid' + tag_name).encode('utf-8')
+        b1 = self.make_branch_with_revisions('b', [revid])
         b1.tags.set_tag(tag_name, revid)
         self.assertEquals(b1.tags.lookup_tag(tag_name), revid)
 
     def test_delete_tag(self):
-        b = self.make_branch('b')
         tag_name = u'\N{GREEK SMALL LETTER ALPHA}'
         revid = ('revid' + tag_name).encode('utf-8')
+        b = self.make_branch_with_revisions('b', [revid])
         b.tags.set_tag(tag_name, revid)
         # now try to delete it
         b.tags.delete_tag(tag_name)
@@ -147,9 +167,10 @@
         # Open the same branch twice.  Read-lock one, and then mutate the tags
         # in the second.  The read-locked branch never re-reads the tags, so it
         # never observes the changed/new tags.
-        b1 = self.make_branch('b')
+        b1 = self.make_branch_with_revisions('b',
+            ['rev-1', 'rev-1-changed', 'rev-2'])
         b1.tags.set_tag('one', 'rev-1')
-        b2 = b1.bzrdir.open_branch()
+        b2 = _mod_bzrdir.BzrDir.open('b').open_branch()
         b1.lock_read()
         self.assertEqual({'one': 'rev-1'}, b1.tags.get_tag_dict())
         # Add a tag and modify a tag in b2.  b1 is read-locked and has already
@@ -166,7 +187,8 @@
     def test_unlocked_does_not_cache_tags(self):
         """Unlocked branches do not cache tags."""
         # Open the same branch twice.
-        b1 = self.make_branch('b')
+        b1 = self.make_branch_with_revisions('b',
+            ['rev-1', 'rev-1-changed', 'rev-2'])
         b1.tags.set_tag('one', 'rev-1')
         b2 = b1.bzrdir.open_branch()
         self.assertEqual({'one': 'rev-1'}, b1.tags.get_tag_dict())
@@ -182,7 +204,8 @@
         returns a copy of the cached data so that callers cannot accidentally
         corrupt the cache.
         """
-        b = self.make_branch('b')
+        b = self.make_branch_with_revisions('b',
+            ['rev-1', 'rev-2', 'rev-3'])
         b.tags.set_tag('one', 'rev-1')
         self.addCleanup(b.lock_read().unlock)
         # The first time the data returned will not be in the cache
@@ -196,7 +219,7 @@
         self.assertEqual({'one': 'rev-1'}, b.tags.get_tag_dict())
 
     def make_write_locked_branch_with_one_tag(self):
-        b = self.make_branch('b')
+        b = self.make_branch_with_revisions('b', ['rev-1'])
         b.tags.set_tag('one', 'rev-1')
         self.addCleanup(b.lock_write().unlock)
         # Populate the cache
@@ -462,7 +485,7 @@
             get_tag_name, 'get tag name foo')
         self.assertEquals("foo", self.branch.automatic_tag_name(
             self.branch.last_revision()))
-    
+
     def test_uses_first_return(self):
         get_tag_name_1 = lambda br, revid: "foo1"
         get_tag_name_2 = lambda br, revid: "foo2"

=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- a/doc/en/release-notes/bzr-2.5.txt	2011-09-05 17:18:09 +0000
+++ b/doc/en/release-notes/bzr-2.5.txt	2011-09-06 10:11:54 +0000
@@ -225,6 +225,10 @@
   value in SI format (i.e. "20MB", "1GB") into its integer equivalent. 
   (Shannon Weyrick)
 
+* ``Tags`` containers can now declare whether they support versioned
+  tags and whether tags can refer to ghost tags.
+  (Jelmer Vernooij)
+
 * ``Tags.merge_to`` now returns a dictionary with the updated tags
   and a set of conflicts, rather than just conflicts. (Jelmer Vernooij)
 




More information about the bazaar-commits mailing list