Răsfoiți Sursa

Add RefsContainer.follow() method. Addresses issue #438.

Jelmer Vernooij 8 ani în urmă
părinte
comite
c71bcc9075
4 a modificat fișierele cu 27 adăugiri și 20 ștergeri
  1. 2 0
      NEWS
  2. 17 12
      dulwich/refs.py
  3. 3 3
      dulwich/repo.py
  4. 5 5
      dulwich/tests/test_refs.py

+ 2 - 0
NEWS

@@ -9,6 +9,8 @@
 
   * Add `dulwich.config.parse_submodules` function.
 
+  * Add `RefsContainer.follow` method. (#438)
+
 0.13.0	2016-04-24
 
  IMPROVEMENTS

+ 17 - 12
dulwich/refs.py

@@ -196,23 +196,25 @@ class RefsContainer(object):
         """
         raise NotImplementedError(self.read_loose_ref)
 
-    def _follow(self, name):
+    def follow(self, name):
         """Follow a reference name.
 
-        :return: a tuple of (refname, sha), where refname is the name of the
-            last reference in the symbolic reference chain
+        :return: a tuple of (refnames, sha), wheres refnames are the names of
+            references in the chain
         """
         contents = SYMREF + name
         depth = 0
+        refnames = []
         while contents.startswith(SYMREF):
             refname = contents[len(SYMREF):]
+            refnames.append(refname)
             contents = self.read_ref(refname)
             if not contents:
                 break
             depth += 1
             if depth > 5:
                 raise KeyError(name)
-        return refname, contents
+        return refnames, contents
 
     def __contains__(self, refname):
         if self.read_ref(refname):
@@ -224,7 +226,7 @@ class RefsContainer(object):
 
         This method follows all symbolic references.
         """
-        _, sha = self._follow(name)
+        _, sha = self.follow(name)
         if sha is None:
             raise KeyError(name)
         return sha
@@ -317,9 +319,10 @@ class DictRefsContainer(RefsContainer):
     def set_if_equals(self, name, old_ref, new_ref):
         if old_ref is not None and self._refs.get(name, None) != old_ref:
             return False
-        realname, _ = self._follow(name)
-        self._check_refname(realname)
-        self._refs[realname] = new_ref
+        realnames, _ = self.follow(name)
+        for realname in realnames:
+            self._check_refname(realname)
+            self._refs[realname] = new_ref
         return True
 
     def add_if_new(self, name, ref):
@@ -567,8 +570,9 @@ class DiskRefsContainer(RefsContainer):
         """
         self._check_refname(name)
         try:
-            realname, _ = self._follow(name)
-        except KeyError:
+            realnames, _ = self.follow(name)
+            realname = realnames[-1]
+        except (KeyError, IndexError):
             realname = name
         filename = self.refpath(realname)
         ensure_dir_exists(os.path.dirname(filename))
@@ -603,10 +607,11 @@ class DiskRefsContainer(RefsContainer):
         :return: True if the add was successful, False otherwise.
         """
         try:
-            realname, contents = self._follow(name)
+            realnames, contents = self.follow(name)
             if contents is not None:
                 return False
-        except KeyError:
+            realname = realnames[-1]
+        except (KeyError, IndexError):
             realname = name
         self._check_refname(realname)
         filename = self.refpath(realname)

+ 3 - 3
dulwich/repo.py

@@ -833,9 +833,9 @@ class Repo(BaseRepo):
             pass
 
         # Update target head
-        head, head_sha = self.refs._follow(b'HEAD')
-        if head is not None and head_sha is not None:
-            target.refs.set_symbolic_ref(b'HEAD', head)
+        head_chain, head_sha = self.refs.follow(b'HEAD')
+        if head_chain and head_sha is not None:
+            target.refs.set_symbolic_ref(b'HEAD', head_chain[-1])
             target[b'HEAD'] = head_sha
 
             if not bare:

+ 5 - 5
dulwich/tests/test_refs.py

@@ -367,13 +367,13 @@ class DiskRefsContainerTests(RefsContainerTests, TestCase):
         self.assertEqual(nines, refs[b'refs/heads/master'])
 
     def test_follow(self):
-        self.assertEqual((b'refs/heads/master',
+        self.assertEqual(([b'HEAD', b'refs/heads/master'],
                           b'42d06bd4b77fed026b154d16493e5deab78f02ec'),
-                         self._refs._follow(b'HEAD'))
-        self.assertEqual((b'refs/heads/master',
+                         self._refs.follow(b'HEAD'))
+        self.assertEqual(([b'refs/heads/master'],
                           b'42d06bd4b77fed026b154d16493e5deab78f02ec'),
-                         self._refs._follow(b'refs/heads/master'))
-        self.assertRaises(KeyError, self._refs._follow, b'refs/heads/loop')
+                         self._refs.follow(b'refs/heads/master'))
+        self.assertRaises(KeyError, self._refs.follow, b'refs/heads/loop')
 
     def test_delitem(self):
         RefsContainerTests.test_delitem(self)