Explorar o código

Simplify and fix prerequisite handling in create_bundle_from_repo

Fix bug where have_objects.append() was called on a set instead of using .add().

Simplify prerequisite validation to only accept 40-byte hex bytestrings,
rejecting invalid types and lengths with clear error messages.
Jelmer Vernooij hai 2 meses
pai
achega
e9c177574a
Modificáronse 2 ficheiros con 79 adicións e 26 borrados
  1. 16 26
      dulwich/bundle.py
  2. 63 0
      tests/test_bundle.py

+ 16 - 26
dulwich/bundle.py

@@ -272,32 +272,22 @@ def create_bundle_from_repo(
     bundle_prerequisites = []
     have_objects = set()
     for prereq in prerequisites:
-        if isinstance(prereq, str):
-            prereq = prereq.encode("utf-8")
-        if isinstance(prereq, bytes):
-            if len(prereq) == 40:  # SHA1 hex string
-                try:
-                    # Validate it's actually hex
-                    bytes.fromhex(prereq.decode("utf-8"))
-                    # Store hex in bundle and for pack generation
-                    bundle_prerequisites.append((prereq, b""))
-                    have_objects.add(prereq)
-                except ValueError:
-                    # Not a valid hex string, invalid prerequisite
-                    raise ValueError(f"Invalid prerequisite format: {prereq!r}")
-            elif len(prereq) == 20:
-                # Binary SHA, convert to hex for both bundle and pack generation
-                hex_prereq = prereq.hex().encode("ascii")
-                bundle_prerequisites.append((hex_prereq, b""))
-                have_objects.add(hex_prereq)
-            else:
-                # Invalid length
-                raise ValueError(f"Invalid prerequisite SHA length: {len(prereq)}")
-        else:
-            # Assume it's already a binary SHA
-            hex_prereq = prereq.hex().encode("ascii")
-            bundle_prerequisites.append((hex_prereq, b""))
-            have_objects.append(hex_prereq)
+        if not isinstance(prereq, bytes):
+            raise TypeError(
+                f"Invalid prerequisite type: {type(prereq)}, expected bytes"
+            )
+        if len(prereq) != 40:
+            raise ValueError(
+                f"Invalid prerequisite SHA length: {len(prereq)}, expected 40 hex characters"
+            )
+        try:
+            # Validate it's actually hex
+            bytes.fromhex(prereq.decode("utf-8"))
+        except ValueError:
+            raise ValueError(f"Invalid prerequisite format: {prereq!r}")
+        # Store hex in bundle and for pack generation
+        bundle_prerequisites.append((prereq, b""))
+        have_objects.add(prereq)
 
     # Generate pack data containing all objects needed for the refs
     pack_count, pack_objects = repo.generate_pack_data(

+ 63 - 0
tests/test_bundle.py

@@ -449,3 +449,66 @@ class BundleTests(TestCase):
         # Verify capabilities are included
         self.assertEqual(bundle.capabilities, capabilities)
         self.assertEqual(bundle.version, 3)
+
+    def test_create_bundle_with_hex_bytestring_prerequisite(self) -> None:
+        """Test creating a bundle with prerequisite as 40-byte hex bytestring."""
+        repo = MemoryRepo()
+
+        # Create minimal objects
+        blob = Blob.from_string(b"Hello world")
+        repo.object_store.add_object(blob)
+
+        tree = Tree()
+        tree.add(b"hello.txt", 0o100644, blob.id)
+        repo.object_store.add_object(tree)
+
+        commit = Commit()
+        commit.tree = tree.id
+        commit.message = b"Initial commit"
+        commit.author = commit.committer = b"Test User <test@example.com>"
+        commit.commit_time = commit.author_time = 1234567890
+        commit.commit_timezone = commit.author_timezone = 0
+        repo.object_store.add_object(commit)
+
+        repo.refs[b"refs/heads/master"] = commit.id
+
+        # Create another blob to use as prerequisite
+        prereq_blob = Blob.from_string(b"prerequisite")
+
+        # Use blob.id directly (40-byte hex bytestring)
+        bundle = create_bundle_from_repo(repo, prerequisites=[prereq_blob.id])
+
+        # Verify the prerequisite was added correctly
+        self.assertEqual(len(bundle.prerequisites), 1)
+        self.assertEqual(bundle.prerequisites[0][0], prereq_blob.id)
+
+    def test_create_bundle_with_hex_bytestring_prerequisite_simple(self) -> None:
+        """Test creating a bundle with prerequisite as 40-byte hex bytestring."""
+        repo = MemoryRepo()
+
+        # Create minimal objects
+        blob = Blob.from_string(b"Hello world")
+        repo.object_store.add_object(blob)
+
+        tree = Tree()
+        tree.add(b"hello.txt", 0o100644, blob.id)
+        repo.object_store.add_object(tree)
+
+        commit = Commit()
+        commit.tree = tree.id
+        commit.message = b"Initial commit"
+        commit.author = commit.committer = b"Test User <test@example.com>"
+        commit.commit_time = commit.author_time = 1234567890
+        commit.commit_timezone = commit.author_timezone = 0
+        repo.object_store.add_object(commit)
+
+        repo.refs[b"refs/heads/master"] = commit.id
+
+        # Use a 40-byte hex bytestring as prerequisite
+        prereq_hex = b"aa" * 20
+
+        bundle = create_bundle_from_repo(repo, prerequisites=[prereq_hex])
+
+        # Verify the prerequisite was added correctly
+        self.assertEqual(len(bundle.prerequisites), 1)
+        self.assertEqual(bundle.prerequisites[0][0], prereq_hex)