Rev 452: Fix mainline_revision_parent(). in http://people.samba.org/bzr/jelmer/bzr-svn/bzr.dev

Jelmer Vernooij jelmer at samba.org
Wed May 16 14:28:10 BST 2007


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

------------------------------------------------------------
revno: 452
revision-id: jelmer at samba.org-20070516132803-atj347dynttwtwvv
parent: jelmer at samba.org-20070516091932-yfr4vawpgkhhl4my
committer: Jelmer Vernooij <jelmer at samba.org>
branch nick: main
timestamp: Wed 2007-05-16 14:28:03 +0100
message:
  Fix mainline_revision_parent().
modified:
  repository.py                  repository.py-20060306123302-1f8c5069b3fe0265
  tests/test_repos.py            test_repos.py-20060508151940-ddc49a59257ca712
=== modified file 'repository.py'
--- a/repository.py	2007-05-02 00:52:38 +0000
+++ b/repository.py	2007-05-16 13:28:03 +0000
@@ -310,10 +310,23 @@
     def _mainline_revision_parent(self, path, revnum):
         assert isinstance(path, basestring)
         assert isinstance(revnum, int)
-        for (branch, rev) in self.follow_branch(path, revnum):
-            if rev < revnum:
-                return self.generate_revision_id(rev, branch)
-        return None
+
+        if not self.scheme.is_branch(path) and \
+           not self.scheme.is_tag(path):
+            raise NoSuchRevision(self, self.generate_revision_id(revnum, path))
+
+        it = self.follow_branch(path, revnum)
+        # the first tuple returned should match the one specified. 
+        # if it's not, then the branch, revnum didn't change in the specified 
+        # revision and so it is invalid
+        if (path, revnum) != it.next():
+            raise NoSuchRevision(self, self.generate_revision_id(revnum, path))
+        try:
+            (branch, rev) = it.next()
+            return self.generate_revision_id(rev, branch)
+        except StopIteration:
+            # The specified revision was the first one in the branch
+            return None
 
     def revision_parents(self, revision_id, merged_data=None):
         parent_ids = []
@@ -441,13 +454,30 @@
         return bzrlib.xml5.serializer_v5.write_inventory_to_string(
             self.get_inventory(revision_id))
 
+    """Get the sha1 for the XML representation of an inventory.
+
+    :param revision_id: Revision id of the inventory for which to return the 
+        SHA1.
+    :return: XML string
+    """
     def get_inventory_sha1(self, revision_id):
         return osutils.sha_string(self.get_inventory_xml(revision_id))
 
+    """Return the XML representation of a revision.
+
+    :param revision_id: Revision for which to return the XML.
+    :return: XML string
+    """
     def get_revision_xml(self, revision_id):
         return bzrlib.xml5.serializer_v5.write_revision_to_string(
             self.get_revision(revision_id))
 
+    """Yield all the branches found between the start of history 
+    and a specified revision number.
+
+    :param revnum: Revision number up to which to search.
+    :return: iterator over branches in the range 0..revnum
+    """
     def follow_history(self, revnum):
         while revnum >= 0:
             yielded_paths = []
@@ -457,12 +487,20 @@
                     bp = self.scheme.unprefix(p)[0]
                     if not bp in yielded_paths:
                         if not paths.has_key(bp) or paths[bp][0] != 'D':
+                            assert revnum > 0 or bp == ""
                             yield (bp, revnum)
                         yielded_paths.append(bp)
                 except NotBranchError:
                     pass
             revnum -= 1
 
+    """Follow the history of a branch. Will yield all the 
+    left-hand side ancestors of a specified revision.
+    
+    :param branch_path: Subversion path to search.
+    :param revnum: Revision number in Subversion to start.
+    :return: iterator over the ancestors
+    """
     def follow_branch(self, branch_path, revnum):
         assert branch_path is not None
         assert isinstance(revnum, int) and revnum >= 0
@@ -472,14 +510,27 @@
         branch_path = branch_path.strip("/")
 
         while revnum >= 0:
-            paths = self._log.get_revision_paths(revnum, branch_path)
-            if paths == {}:
-                revnum -= 1
-                continue
-            yield (branch_path, revnum)
-            # FIXME: what if one of the parents of branch_path was moved?
+            paths = self._log.get_revision_paths(revnum)
+
+            yielded = False
+            # If something underneath branch_path changed, there is a 
+            # revision there, so yield it.
+            for p in paths:
+                if p.startswith(branch_path+"/") or branch_path == "":
+                    yield (branch_path, revnum)
+                    yielded = True
+                    break
+            
+            # If there are no special cases, just go try the 
+            # next revnum in history
+            revnum -= 1
+
+            # Make sure we get the right location for next time, if 
+            # the branch itself was copied
             if (paths.has_key(branch_path) and 
                 paths[branch_path][0] in ('R', 'A')):
+                if not yielded:
+                    yield (branch_path, revnum+1)
                 if paths[branch_path][1] is None:
                     return
                 if not self.scheme.is_branch(paths[branch_path][1]) and \
@@ -491,8 +542,27 @@
                 revnum = paths[branch_path][2]
                 branch_path = paths[branch_path][1]
                 continue
-            revnum -= 1
-
+            
+            # Make sure we get the right location for the next time if 
+            # one of the parents changed
+
+            # Path names need to be sorted so the longer paths 
+            # override the shorter ones
+            path_names = paths.keys()
+            path_names.sort()
+            for p in path_names:
+                if branch_path.startswith(p+"/"):
+                    assert paths[p][1] is not None and paths[p][0] in ('A', 'R'), "Parent didn't exist yet, but child wasn't added !?"
+
+                    revnum = paths[p][2]
+                    branch_path = paths[p][1] + branch_path[len(p):]
+
+    """Return all the changes that happened in a branch 
+    between branch_path and revnum. 
+
+    :return: iterator that returns tuples with branch path, 
+    changed paths and revision number.
+    """
     def follow_branch_history(self, branch_path, revnum):
         assert branch_path is not None
         if not self.scheme.is_branch(branch_path) and \
@@ -500,7 +570,6 @@
             raise errors.NotSvnBranchPath(branch_path, revnum)
 
         for (bp, paths, revnum) in self._log.follow_path(branch_path, revnum):
-            # FIXME: what if one of the parents of branch_path was moved?
             if (paths.has_key(bp) and 
                 paths[bp][1] is not None and 
                 not self.scheme.is_branch(paths[bp][1]) and
@@ -518,11 +587,22 @@
                      
             yield (bp, paths, revnum)
 
+    """Check whether a signature exists for a particular revision id.
+
+    :param revision_id: Revision id for which the signatures should be looked up.
+    :return: False, as no signatures are stored for revisions in Subversion 
+        at the moment.
+    """
     def has_signature_for_revision_id(self, revision_id):
         # TODO: Retrieve from SVN_PROP_BZR_SIGNATURE 
         return False # SVN doesn't store GPG signatures. Perhaps 
                      # store in SVN revision property?
 
+    """Return the signature text for a particular revision.
+
+    :param revision_id: Id of the revision for which to return the signature.
+    :raises NoSuchRevision: Always
+    """
     def get_signature_text(self, revision_id):
         # TODO: Retrieve from SVN_PROP_BZR_SIGNATURE 
         # SVN doesn't store GPG signatures

=== modified file 'tests/test_repos.py'
--- a/tests/test_repos.py	2007-05-02 11:57:15 +0000
+++ b/tests/test_repos.py	2007-05-16 13:28:03 +0000
@@ -2006,7 +2006,7 @@
         repos.set_branching_scheme(NoBranchingScheme())
         self.assertEquals(None, repos._mainline_revision_parent("", 0))
 
-    def test_mainline_revision_parent_null(self):
+    def test_mainline_revision_parent_first(self):
         repos_url = self.make_client('d', 'dc')
         repos = Repository.open(repos_url)
         repos.set_branching_scheme(NoBranchingScheme())
@@ -2039,8 +2039,25 @@
         self.client_commit("dc", "Initial commit")
         self.client_copy("dc/py", "dc/de")
         self.client_commit("dc", "Incremental commit")
-        repos = Repository.open(repos_url)
-        repos.set_branching_scheme(TrunkBranchingScheme())
+        self.build_tree({'dc/de/trunk/adir/afile': "bla"})
+        self.client_commit("dc", "Change de")
+        repos = Repository.open(repos_url)
+        repos.set_branching_scheme(TrunkBranchingScheme(1))
+        self.assertEquals(repos.generate_revision_id(1, "py/trunk"), \
+                repos._mainline_revision_parent("de/trunk", 3))
+
+    def test_mainline_revision_copied(self):
+        repos_url = self.make_client('d', 'dc')
+        self.build_tree({'dc/py/trunk/adir/afile': "data", 
+                         'dc/py/trunk/adir/stationary': None})
+        self.client_add("dc/py")
+        self.client_commit("dc", "Initial commit")
+        self.build_tree({'dc/de':None})
+        self.client_add("dc/de")
+        self.client_copy("dc/py/trunk", "dc/de/trunk")
+        self.client_commit("dc", "Copy trunk")
+        repos = Repository.open(repos_url)
+        repos.set_branching_scheme(TrunkBranchingScheme(1))
         self.assertEquals(repos.generate_revision_id(1, "py/trunk"), \
                 repos._mainline_revision_parent("de/trunk", 2))
 
@@ -2056,9 +2073,19 @@
         self.client_commit("dc", "Another incremental commit")
         repos = Repository.open(repos_url)
         repos.set_branching_scheme(TrunkBranchingScheme(1))
-        self.assertEquals(repos.generate_revision_id(2, "de/trunk"), \
+        self.assertEquals(repos.generate_revision_id(1, "py/trunk"), \
                 repos._mainline_revision_parent("de/trunk", 3))
 
+    def test_mainline_revision_missing(self):
+        repos_url = self.make_client('d', 'dc')
+        repos = Repository.open(repos_url)
+        self.build_tree({'dc/py/trunk/adir/afile': "data", 
+                         'dc/py/trunk/adir/stationary': None})
+        self.client_add("dc/py")
+        self.client_commit("dc", "Initial commit")
+        self.assertRaises(NoSuchRevision, 
+                lambda: repos._mainline_revision_parent("trunk", 1))
+
     def test_fetch_crosscopy(self):
         repos_url = self.make_client('d', 'dc')
         self.build_tree({'dc/trunk/adir/afile': "data", 




More information about the bazaar-commits mailing list