Browse Source

Deal with thin packs appropriately.

Jelmer Vernooij 16 years ago
parent
commit
14711851a1
3 changed files with 41 additions and 7 deletions
  1. 33 1
      dulwich/object_store.py
  2. 7 5
      dulwich/pack.py
  3. 1 1
      dulwich/server.py

+ 33 - 1
dulwich/object_store.py

@@ -18,6 +18,7 @@
 
 from objects import (
         ShaFile,
+        hex_to_sha,
         )
 import os, tempfile
 from pack import (
@@ -27,6 +28,7 @@ from pack import (
         PackData, 
         )
 import tempfile
+import urllib2
 PACKDIR = 'pack'
 
 class ObjectStore(object):
@@ -86,6 +88,23 @@ class ObjectStore(object):
         type, uncomp = self.get_raw(sha)
         return ShaFile.from_raw_string(type, uncomp)
 
+    def move_in_thin_pack(self, path):
+        """Move a specific file containing a pack into the pack directory.
+
+        :note: The file should be on the same file system as the 
+            packs directory.
+
+        :param path: Path to the pack file.
+        """
+        p = PackData(path)
+        temppath = os.path.join(self.pack_dir(), sha_to_hex(urllib2.randombytes(20))+".temppack")
+        write_pack(temppath, p.iterobjects(self.get_raw), len(p))
+        pack_sha = PackIndex(temppath+".idx").objects_sha1()
+        os.rename(temppath+".pack", 
+            os.path.join(self.pack_dir(), "pack-%s.pack" % pack_sha))
+        os.rename(temppath+".idx", 
+            os.path.join(self.pack_dir(), "pack-%s.idx" % pack_sha))
+
     def move_in_pack(self, path):
         """Move a specific file containing a pack into the pack directory.
 
@@ -95,12 +114,25 @@ class ObjectStore(object):
         :param path: Path to the pack file.
         """
         p = PackData(path)
-        entries = p.sorted_entries(self.get_raw)
+        entries = p.sorted_entries()
         basename = os.path.join(self.pack_dir(), 
             "pack-%s" % iter_sha1(entry[0] for entry in entries))
         write_pack_index_v2(basename+".idx", entries, p.calculate_checksum())
         os.rename(path, basename + ".pack")
 
+    def add_thin_pack(self):
+        """Add a new thin pack to this object store.
+
+        Thin packs are packs that contain deltas with parents that exist 
+        in a different pack.
+        """
+        fd, path = tempfile.mkstemp(dir=self.pack_dir(), suffix=".pack")
+        f = os.fdopen(fd, 'w')
+        def commit():
+            if os.path.getsize(path) > 0:
+                self.move_in_thin_pack(path)
+        return f, commit
+
     def add_pack(self):
         """Add a new pack to this object store. 
 

+ 7 - 5
dulwich/pack.py

@@ -848,8 +848,6 @@ class Pack(object):
         return (self.idx.object_index(sha1) is not None)
 
     def get_raw(self, sha1, resolve_ref=None):
-        if resolve_ref is None:
-            resolve_ref = self.get_raw
         offset = self.idx.object_index(sha1)
         if offset is None:
             raise KeyError(sha1)
@@ -864,12 +862,16 @@ class Pack(object):
         type, uncomp = self.get_raw(sha1)
         return ShaFile.from_raw_string(type, uncomp)
 
-    def iterobjects(self):
+    def iterobjects(self, get_raw=None):
+        if get_raw is None:
+            def get_raw(x):
+                raise KeyError(x)
         for offset, type, obj in self.data.iterobjects():
             assert isinstance(offset, int)
             yield ShaFile.from_raw_string(
-                    *resolve_object(offset, type, obj, self.get_raw, 
-                self.data.get_object_at))
+                    *resolve_object(offset, type, obj, 
+                        get_raw, 
+                    self.data.get_object_at))
 
 
 def load_packs(path):

+ 1 - 1
dulwich/server.py

@@ -63,7 +63,7 @@ class GitBackend(Backend):
         self.get_refs = self.repo.get_refs
 
     def apply_pack(self, refs, read):
-        fd, commit = self.repo.object_store.add_pack()
+        fd, commit = self.repo.object_store.add_thin_pack()
         fd.write(read())
         fd.close()
         commit()