Rev 1428: Merge tags support. in http://people.samba.org/bzr/jelmer/bzr-svn/trunk

Jelmer Vernooij jelmer at samba.org
Thu Jul 3 22:18:45 BST 2008


At http://people.samba.org/bzr/jelmer/bzr-svn/trunk

------------------------------------------------------------
revno: 1428
revision-id: jelmer at samba.org-20080703211843-5twv11n03hlqcedq
parent: jelmer at samba.org-20080703173958-z5y00jn963j3absk
parent: jelmer at samba.org-20080703211244-2vlo1z5fshvrq1li
committer: Jelmer Vernooij <jelmer at samba.org>
branch nick: 0.4
timestamp: Thu 2008-07-03 23:18:43 +0200
message:
  Merge tags support.
modified:
  NEWS                           news-20061231030336-h9fhq245ie0de8bs-1
  branch.py                      svnbranch.py-20051017135706-11c749eb0dab04a7
  layout.py                      layout.py-20080323165407-y9qw8nx4oykvoe1k-1
  mapping3/__init__.py           __init__.py-20080502174630-9324zh25kka98vlw-1
  mapping3/scheme.py             scheme.py-20060516195850-95181aae6b272f9e
  repository.py                  repository.py-20060306123302-1f8c5069b3fe0265
  tests/test_branch.py           test_branch.py-20060508162215-74ffeb5d608f8e20
  tests/test_repository.py       test_repos.py-20060508151940-ddc49a59257ca712
  tests/test_scheme.py           test_scheme.py-20060621221855-va2xabhlxpmc9llx-1
    ------------------------------------------------------------
    revno: 1427.1.7
    revision-id: jelmer at samba.org-20080703211244-2vlo1z5fshvrq1li
    parent: jelmer at samba.org-20080703211228-3bvk5itd516n75px
    committer: Jelmer Vernooij <jelmer at samba.org>
    branch nick: tags
    timestamp: Thu 2008-07-03 23:12:44 +0200
    message:
      Support proper Bazaar tags.
    modified:
      NEWS                           news-20061231030336-h9fhq245ie0de8bs-1
    ------------------------------------------------------------
    revno: 1427.1.6
    revision-id: jelmer at samba.org-20080703211228-3bvk5itd516n75px
    parent: jelmer at samba.org-20080703203944-ro3eh9caweh59aav
    committer: Jelmer Vernooij <jelmer at samba.org>
    branch nick: tags
    timestamp: Thu 2008-07-03 23:12:28 +0200
    message:
      Support setting tags.
    modified:
      branch.py                      svnbranch.py-20051017135706-11c749eb0dab04a7
      tests/test_branch.py           test_branch.py-20060508162215-74ffeb5d608f8e20
    ------------------------------------------------------------
    revno: 1427.1.5
    revision-id: jelmer at samba.org-20080703203944-ro3eh9caweh59aav
    parent: jelmer at samba.org-20080703203327-5bplovdvone200dp
    committer: Jelmer Vernooij <jelmer at samba.org>
    branch nick: tags
    timestamp: Thu 2008-07-03 22:39:44 +0200
    message:
      Implement tag lookup.
    modified:
      branch.py                      svnbranch.py-20051017135706-11c749eb0dab04a7
      tests/test_branch.py           test_branch.py-20060508162215-74ffeb5d608f8e20
    ------------------------------------------------------------
    revno: 1427.1.4
    revision-id: jelmer at samba.org-20080703203327-5bplovdvone200dp
    parent: jelmer at samba.org-20080703201334-n4gkcyfsndegaoi2
    committer: Jelmer Vernooij <jelmer at samba.org>
    branch nick: tags
    timestamp: Thu 2008-07-03 22:33:27 +0200
    message:
      Support deleting tags.
    modified:
      branch.py                      svnbranch.py-20051017135706-11c749eb0dab04a7
      mapping3/__init__.py           __init__.py-20080502174630-9324zh25kka98vlw-1
      mapping3/scheme.py             scheme.py-20060516195850-95181aae6b272f9e
      tests/test_branch.py           test_branch.py-20060508162215-74ffeb5d608f8e20
      tests/test_scheme.py           test_scheme.py-20060621221855-va2xabhlxpmc9llx-1
    ------------------------------------------------------------
    revno: 1427.1.3
    revision-id: jelmer at samba.org-20080703201334-n4gkcyfsndegaoi2
    parent: jelmer at samba.org-20080703185323-pfj2a2qtitnh6zop
    committer: Jelmer Vernooij <jelmer at samba.org>
    branch nick: tags
    timestamp: Thu 2008-07-03 22:13:34 +0200
    message:
      Implement get_tag_dict for subversion branches.
    modified:
      branch.py                      svnbranch.py-20051017135706-11c749eb0dab04a7
      layout.py                      layout.py-20080323165407-y9qw8nx4oykvoe1k-1
      repository.py                  repository.py-20060306123302-1f8c5069b3fe0265
      tests/test_branch.py           test_branch.py-20060508162215-74ffeb5d608f8e20
    ------------------------------------------------------------
    revno: 1427.1.2
    revision-id: jelmer at samba.org-20080703185323-pfj2a2qtitnh6zop
    parent: jelmer at samba.org-20080703184844-6s1i7aakg9glmmfh
    committer: Jelmer Vernooij <jelmer at samba.org>
    branch nick: tags
    timestamp: Thu 2008-07-03 20:53:23 +0200
    message:
      Add find_tags.
    modified:
      repository.py                  repository.py-20060306123302-1f8c5069b3fe0265
      tests/test_repository.py       test_repos.py-20060508151940-ddc49a59257ca712
    ------------------------------------------------------------
    revno: 1427.1.1
    revision-id: jelmer at samba.org-20080703184844-6s1i7aakg9glmmfh
    parent: jelmer at samba.org-20080703173958-z5y00jn963j3absk
    committer: Jelmer Vernooij <jelmer at samba.org>
    branch nick: tags
    timestamp: Thu 2008-07-03 20:48:44 +0200
    message:
      Implement get_tags, skip tags in get_branches.
    modified:
      mapping3/__init__.py           __init__.py-20080502174630-9324zh25kka98vlw-1
=== modified file 'NEWS'
--- a/NEWS	2008-07-01 15:58:38 +0000
+++ b/NEWS	2008-07-03 21:12:44 +0000
@@ -28,6 +28,8 @@
   
    * Add new "dpush" command that works similar to git-svn's dcommit.
 
+   * Support proper Bazaar tags. (#81102)
+
   BUG FIXES
 
    * More efficient use of mutter.

=== modified file 'branch.py'
--- a/branch.py	2008-07-01 21:10:34 +0000
+++ b/branch.py	2008-07-03 21:12:28 +0000
@@ -19,9 +19,10 @@
 from bzrlib.branch import Branch, BranchFormat, BranchCheckResult, PullResult
 from bzrlib.bzrdir import BzrDir
 from bzrlib.errors import (NoSuchFile, DivergedBranches, NoSuchRevision, 
-                           NotBranchError, UnstackableBranchFormat)
+                           NoSuchTag, NotBranchError, UnstackableBranchFormat)
 from bzrlib.inventory import (Inventory)
 from bzrlib.revision import is_null, ensure_null, NULL_REVISION
+from bzrlib.tag import BasicTags
 from bzrlib.workingtree import WorkingTree
 
 from bzrlib.plugins.svn import core
@@ -51,6 +52,76 @@
         pass
 
 
+class SubversionTags(BasicTags):
+    def __init__(self, branch, layout=None, project=""):
+        self.branch = branch
+        self.repository = branch.repository
+        self.layout = layout or self.repository.get_layout()
+        self.project = project
+
+    def set_tag(self, tag_name, tag_target):
+        path = self.layout.get_tag_path(tag_name, self.project)
+        parent = urlutils.dirname(path)
+        (from_bp, from_revnum, mapping) = self.repository.lookup_revision_id(tag_target)
+        conn = self.repository.transport.connections.get(urlutils.join(self.repository.base, parent))
+        deletefirst = (conn.check_path(urlutils.basename(path), self.repository.get_latest_revnum()) != core.NODE_NONE)
+        try:
+            ci = conn.get_commit_editor({"svn:log": "Add tag %s" % tag_name})
+            try:
+                root = ci.open_root()
+                if deletefirst:
+                    root.delete_entry(urlutils.basename(path))
+                root.add_directory(urlutils.basename(path), urlutils.join(self.repository.base, from_bp), from_revnum)
+                root.close()
+            except:
+                ci.abort()
+                raise
+            ci.close()
+        finally:
+            self.repository.transport.add_connection(conn)
+
+    def lookup_tag(self, tag_name):
+        try:
+            return self.get_tag_dict()[tag_name]
+        except KeyError:
+            raise NoSuchTag(tag_name)
+
+    def get_tag_dict(self):
+        return self.repository.find_tags(project=self.project, 
+                                         layout=self.layout)
+
+    def get_reverse_tag_dict(self):
+        """Returns a dict with revisions as keys
+           and a list of tags for that revision as value"""
+        d = self.get_tag_dict()
+        rev = {}
+        for key in d:
+            try:
+                rev[d[key]].append(key)
+            except KeyError:
+                rev[d[key]] = [key]
+        return rev
+
+    def delete_tag(self, tag_name):
+        path = self.layout.get_tag_path(tag_name, self.project)
+        parent = urlutils.dirname(path)
+        conn = self.repository.transport.connections.get(urlutils.join(self.repository.base, parent))
+        if conn.check_path(urlutils.basename(path), self.repository.get_latest_revnum()) != core.NODE_DIR:
+            raise NoSuchTag(tag_name)
+        try:
+            ci = conn.get_commit_editor({"svn:log": "Remove tag %s" % tag_name})
+            try:
+                root = ci.open_root()
+                root.delete_entry(urlutils.basename(path))
+                root.close()
+            except:
+                ci.abort()
+                raise
+            ci.close()
+        finally:
+            self.repository.transport.add_connection(conn)
+
+
 class SvnBranch(Branch):
     """Maps to a Branch in a Subversion repository """
     def __init__(self, repository, branch_path):
@@ -62,8 +133,8 @@
         :param revnum: Subversion revision number of the branch to 
             look at; none for latest.
         """
+        self.repository = repository
         super(SvnBranch, self).__init__()
-        self.repository = repository
         assert isinstance(self.repository, SvnRepository)
         self.control_files = FakeControlFiles()
         self._format = SvnBranchFormat()
@@ -86,6 +157,9 @@
         if not self.mapping.is_branch(branch_path):
             raise NotSvnBranchPath(branch_path, mapping=self.mapping)
 
+    def _make_tags(self):
+        return SubversionTags(self)
+
     def set_branch_path(self, branch_path):
         """Change the branch path for this branch.
 

=== modified file 'layout.py'
--- a/layout.py	2008-07-01 19:26:24 +0000
+++ b/layout.py	2008-07-03 20:13:34 +0000
@@ -70,7 +70,7 @@
         """
         raise NotImplementedError
 
-    def get_tags(self, project="", revnum=None):
+    def get_tags(self, revnum, project="", pb=None):
         """Retrieve a list of paths that refer to tags in a specific revision.
 
         :result: Iterator over tuples with (project, branch path)

=== modified file 'mapping3/__init__.py'
--- a/mapping3/__init__.py	2008-07-02 00:25:10 +0000
+++ b/mapping3/__init__.py	2008-07-03 20:33:27 +0000
@@ -82,7 +82,7 @@
             type = "branch"
         return (type, "", bp, rp)
 
-    def get_branches(self, revnum, project="", pb=None):
+    def _get_root_paths(self, revnum, verify_fn, project="", pb=None):
         def check_path(path):
             return self.repository.transport.check_path(path, revnum) == NODE_DIR
         def find_children(path):
@@ -100,7 +100,17 @@
                 pb.update("finding branches", idx, len(self.scheme.branch_list))
             for bp in expand_branch_pattern([], pattern.split("/"), check_path,
                     find_children):
-                yield "", bp, bp.split("/")[-1]
+                if verify_fn(bp):
+                    yield "", bp, bp.split("/")[-1]
+
+    def get_branches(self, revnum, project="", pb=None):
+        return self._get_root_paths(revnum, self.scheme.is_branch, project, pb)
+
+    def get_tags(self, revnum, project="", pb=None):
+        return self._get_root_paths(revnum, self.scheme.is_tag, project, pb)
+
+    def get_tag_path(self, name, project=""):
+        return self.scheme.get_tag_path(name)
 
     def is_branch_parent(self, path):
         # Na, na, na...

=== modified file 'mapping3/scheme.py'
--- a/mapping3/scheme.py	2008-06-05 17:26:28 +0000
+++ b/mapping3/scheme.py	2008-07-03 20:33:27 +0000
@@ -15,7 +15,7 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 """Branching scheme implementations."""
 
-from bzrlib import ui
+from bzrlib import ui, urlutils
 from bzrlib.errors import BzrError
 from bzrlib.trace import mutter
 
@@ -47,6 +47,13 @@
         """
         raise NotImplementedError
 
+    def get_tag_path(self, name):
+        """Find the path for a tag.
+
+        :param name: Tag name.
+        """
+        raise NotImplementedError
+
     @staticmethod
     def find_scheme(name):
         """Find a branching scheme by name.
@@ -246,6 +253,12 @@
              "*/" * level + "branches/*",
              "*/" * level + "tags/*"])
 
+    def get_tag_path(self, name):
+        # Only implemented for level 0
+        if self.level == 0:
+            return urlutils.join("tags", name)
+        raise NotImplementedError
+
     def is_branch(self, path):
         """See BranchingScheme.is_branch()."""
         parts = path.strip("/").split("/")

=== modified file 'repository.py'
--- a/repository.py	2008-07-03 17:39:58 +0000
+++ b/repository.py	2008-07-03 20:13:34 +0000
@@ -728,6 +728,30 @@
             pb.finished()
         return branches
 
+    @needs_read_lock
+    def find_tags(self, layout=None, revnum=None, project=None):
+        """Find branches underneath this repository.
+
+        """
+        if layout is None:
+            layout = self.get_layout()
+
+        if revnum is None:
+            revnum = self.get_latest_revnum()
+
+        tags = {}
+        pb = ui.ui_factory.nested_progress_bar()
+        try:
+            for project, bp, nick in layout.get_tags(revnum, project=project, pb=pb):
+                try:
+                    tags[nick] = self.generate_revision_id(revnum, bp, 
+                                                           self.get_mapping())
+                except NotBranchError: # Skip non-directories
+                    pass
+        finally:
+            pb.finished()
+        return tags
+
     def find_branchpaths(self, layout, from_revnum=0, to_revnum=None):
         """Find all branch paths that were changed in the specified revision 
         range.

=== modified file 'tests/test_branch.py'
--- a/tests/test_branch.py	2008-07-01 21:10:09 +0000
+++ b/tests/test_branch.py	2008-07-03 21:12:28 +0000
@@ -19,7 +19,7 @@
 from bzrlib import urlutils
 from bzrlib.branch import Branch
 from bzrlib.bzrdir import BzrDir
-from bzrlib.errors import NoSuchFile, NoSuchRevision, NotBranchError
+from bzrlib.errors import NoSuchFile, NoSuchRevision, NotBranchError, NoSuchTag
 from bzrlib.repository import Repository
 from bzrlib.revision import NULL_REVISION
 from bzrlib.trace import mutter
@@ -27,6 +27,7 @@
 import os
 from unittest import TestCase
 
+from bzrlib.plugins.svn import core
 from bzrlib.plugins.svn.branch import FakeControlFiles, SvnBranchFormat
 from bzrlib.plugins.svn.convert import load_dumpfile
 from bzrlib.plugins.svn.mapping import SVN_PROP_BZR_REVISION_ID
@@ -46,6 +47,84 @@
         branch = Branch.open(repos_url)
         self.assertEqual("", branch.get_branch_path())
 
+    def test_tags_dict(self):
+        repos_url = self.make_repository("a")
+       
+        dc = self.get_commit_editor(repos_url)
+        tags = dc.add_dir("tags")
+        tags.add_dir("tags/foo")
+        dc.add_dir("trunk")
+        dc.close()
+
+        b = Branch.open(repos_url + "/trunk")
+        self.assertEquals(["foo"], b.tags.get_tag_dict().keys())
+
+    def test_tag_set(self):
+        repos_url = self.make_repository('a')
+
+        dc = self.get_commit_editor(repos_url)
+        dc.add_dir("trunk")
+        dc.add_dir("tags")
+        dc.close()
+
+        dc = self.get_commit_editor(repos_url)
+        trunk = dc.open_dir("trunk")
+        trunk.add_file("trunk/bla").modify()
+        dc.close()
+
+        b = Branch.open(repos_url + "/trunk")
+        b.tags.set_tag("mytag", b.repository.generate_revision_id(1, "trunk", b.repository.get_mapping()))
+
+        self.assertEquals(core.NODE_DIR, 
+                b.repository.transport.check_path("tags/mytag", 3))
+
+    def test_tags_delete(self):
+        repos_url = self.make_repository("a")
+       
+        dc = self.get_commit_editor(repos_url)
+        tags = dc.add_dir("tags")
+        tags.add_dir("tags/foo")
+        dc.add_dir("trunk")
+        dc.close()
+
+        b = Branch.open(repos_url + "/trunk")
+        self.assertEquals(["foo"], b.tags.get_tag_dict().keys())
+        b.tags.delete_tag("foo")
+        b = Branch.open(repos_url + "/trunk")
+        self.assertEquals([], b.tags.get_tag_dict().keys())
+
+    def test_tag_lookup(self):
+        repos_url = self.make_repository("a")
+       
+        dc = self.get_commit_editor(repos_url)
+        tags = dc.add_dir("tags")
+        tags.add_dir("tags/foo")
+        dc.add_dir("trunk")
+        dc.close()
+
+        b = Branch.open(repos_url + "/trunk")
+        self.assertEquals(b.repository.generate_revision_id(1, "tags/foo", b.repository.get_mapping()), b.tags.lookup_tag("foo"))
+
+    def test_tag_lookup_nonexistant(self):
+        repos_url = self.make_repository("a")
+
+        dc = self.get_commit_editor(repos_url)
+        dc.add_dir("trunk")
+        dc.close()
+       
+        b = Branch.open(repos_url + "/trunk")
+        self.assertRaises(NoSuchTag, b.tags.lookup_tag, "foo")
+
+    def test_tags_delete_nonexistent(self):
+        repos_url = self.make_repository("a")
+
+        dc = self.get_commit_editor(repos_url)
+        dc.add_dir("trunk")
+        dc.close()
+       
+        b = Branch.open(repos_url + "/trunk")
+        self.assertRaises(NoSuchTag, b.tags.delete_tag, "foo")
+
     def test_get_branch_path_old(self):
         repos_url = self.make_repository("a")
 

=== modified file 'tests/test_repository.py'
--- a/tests/test_repository.py	2008-07-01 12:46:51 +0000
+++ b/tests/test_repository.py	2008-07-03 18:53:23 +0000
@@ -401,6 +401,21 @@
         self.assertEquals(urlutils.join(repos.base, "branches/branchab"), 
                           branches[0].base)
 
+    def test_find_tags(self):
+        repos_url = self.make_client('a', 'dc')
+        self.build_tree({
+            'dc/tags/brancha': None,
+            'dc/tags/branchab': None,
+            'dc/tags/brancha/data': "data", 
+            "dc/tags/branchab/data":"data"})
+        self.client_add("dc/tags")
+        self.client_commit("dc", "My Message")
+        repos = Repository.open(repos_url)
+        set_branching_scheme(repos, TrunkBranchingScheme())
+        tags = repos.find_tags()
+        self.assertEquals({"brancha": repos.generate_revision_id(1, "tags/brancha", repos.get_mapping()),
+                           "branchab": repos.generate_revision_id(1, "tags/branchab", repos.get_mapping())}, tags)
+
     def test_find_branchpaths_moved(self):
         repos_url = self.make_client("a", "dc")
         self.build_tree({

=== modified file 'tests/test_scheme.py'
--- a/tests/test_scheme.py	2008-06-04 15:20:12 +0000
+++ b/tests/test_scheme.py	2008-07-03 20:33:27 +0000
@@ -446,6 +446,15 @@
     def test_is_branch_parent_other(self):
         self.assertFalse(TrunkBranchingScheme().is_branch_parent("trunk/foo"))
 
+    def test_get_tag_path_zero(self):
+        self.assertEquals("tags/foo", 
+                          TrunkBranchingScheme().get_tag_path("foo"))
+
+    def test_get_tag_path_nonzero(self):
+        self.assertRaises(NotImplementedError,
+                          TrunkBranchingScheme(2).get_tag_path, "foo")
+
+
 
 class SingleBranchingSchemeTests(TestCase):
     def test_is_branch(self):




More information about the bazaar-commits mailing list