2
0
Эх сурвалжийг харах

Support short ids in parse_commit.

Jelmer Vernooij 6 жил өмнө
parent
commit
3ff25e0972

+ 4 - 0
NEWS

@@ -1,5 +1,9 @@
 0.19.11	UNRELEASED
 
+ IMPROVEMENTS
+
+ * Add support for short ids in parse_commit. (Jelmer Vernooij)
+
 0.19.10	2018-01-15
 
  IMPROVEMENTS

+ 33 - 0
dulwich/objectspec.py

@@ -162,6 +162,29 @@ def parse_commit_range(repo, committishs):
     return iter([parse_commit(repo, committishs)])
 
 
+class AmbiguousShortId(Exception):
+    """The short id is ambiguous."""
+
+    def __init__(self, prefix, options):
+        self.prefix = prefix
+        self.options = options
+
+
+def scan_for_short_id(object_store, prefix):
+    """Scan an object store for a short id."""
+    # TODO(jelmer): This could short-circuit looking for objects
+    # starting with a certain prefix.
+    ret = []
+    for object_id in object_store:
+        if object_id.startswith(prefix):
+            ret.append(object_store[object_id])
+    if not ret:
+        raise KeyError(prefix)
+    if len(ret) == 1:
+        return ret[0]
+    raise AmbiguousShortId(prefix, ret)
+
+
 def parse_commit(repo, committish):
     """Parse a string referring to a single commit.
 
@@ -180,6 +203,16 @@ def parse_commit(repo, committish):
         return repo[parse_ref(repo, committish)]
     except KeyError:
         pass
+    if len(committish) >= 4 and len(committish) < 40:
+        try:
+            int(committish, 16)
+        except ValueError:
+            pass
+        else:
+            try:
+                return scan_for_short_id(repo.object_store, committish)
+            except KeyError:
+                pass
     raise KeyError(committish)
 
 

+ 1 - 1
dulwich/porcelain.py

@@ -225,7 +225,7 @@ def archive(repo, committish=None, outstream=default_bytes_out_stream,
     if committish is None:
         committish = "HEAD"
     with open_repo_closing(repo) as repo_obj:
-        c = repo_obj[committish]
+        c = parse_commit(repo_obj, committish)
         for chunk in tar_stream(
                 repo_obj.object_store, repo_obj.object_store[c.tree],
                 c.commit_time):

+ 20 - 0
dulwich/tests/test_objectspec.py

@@ -28,6 +28,7 @@ from dulwich.objects import (
     )
 from dulwich.objectspec import (
     parse_object,
+    parse_commit,
     parse_commit_range,
     parse_ref,
     parse_refs,
@@ -72,7 +73,26 @@ class ParseCommitRangeTests(TestCase):
         self.assertEqual([c1], list(parse_commit_range(r, c1.id)))
 
 
+class ParseCommitTests(TestCase):
+    """Test parse_commit."""
+
+    def test_nonexistent(self):
+        r = MemoryRepo()
+        self.assertRaises(KeyError, parse_commit, r, "thisdoesnotexist")
+
+    def test_commit_by_sha(self):
+        r = MemoryRepo()
+        [c1] = build_commit_graph(r.object_store, [[1]])
+        self.assertEqual(c1, parse_commit(r, c1.id))
+
+    def test_commit_by_short_sha(self):
+        r = MemoryRepo()
+        [c1] = build_commit_graph(r.object_store, [[1]])
+        self.assertEqual(c1, parse_commit(r, c1.id[:10]))
+
+
 class ParseRefTests(TestCase):
+
     def test_nonexistent(self):
         r = {}
         self.assertRaises(KeyError, parse_ref, r, b"thisdoesnotexist")