Skip ^{} tags.
[jelmer/dulwich-libgit2.git] / dulwich / object_store.py
index 00895be3b33ffb3154269ae7c7c181db3cf7d04a..5e444613b1c3e4fc58f910ecacc22e6e5671e90c 100644 (file)
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
 
-from objects import (
-        ShaFile,
-        )
-import os, tempfile
-from pack import (
-        iter_sha1, 
-        load_packs, 
-        write_pack_index_v2,
-        PackData, 
-        )
+import os
 import tempfile
+import urllib2
+
+from dulwich.objects import (
+    hex_to_sha,
+    sha_to_hex,
+    ShaFile,
+    )
+from dulwich.pack import (
+    iter_sha1, 
+    load_packs, 
+    write_pack,
+    write_pack_data,
+    write_pack_index_v2,
+    PackData, 
+    )
+
 PACKDIR = 'pack'
 
 class ObjectStore(object):
@@ -35,6 +42,12 @@ class ObjectStore(object):
         self.path = path
         self._packs = None
 
+    def determine_wants_all(self, refs):
+           return [sha for (ref, sha) in refs.iteritems() if not sha in self and not ref.endswith("^{}")]
+
+    def iter_shas(self, shas):
+        return ObjectStoreIterator(self, shas)
+
     def pack_dir(self):
         return os.path.join(self.path, PACKDIR)
 
@@ -53,15 +66,27 @@ class ObjectStore(object):
             self._packs = list(load_packs(self.pack_dir()))
         return self._packs
 
-    def _get_shafile(self, sha):
+    def _get_shafile_path(self, sha):
         dir = sha[:2]
         file = sha[2:]
         # Check from object dir
-        path = os.path.join(self.path, dir, file)
+        return os.path.join(self.path, dir, file)
+
+    def _get_shafile(self, sha):
+        path = self._get_shafile_path(sha)
         if os.path.exists(path):
           return ShaFile.from_file(path)
         return None
 
+    def _add_shafile(self, sha, o):
+        path = self._get_shafile_path(sha)
+        f = os.path.open(path, 'w')
+        try:
+            f.write(o._header())
+            f.write(o._text)
+        finally:
+            f.close()
+
     def get_raw(self, sha):
         """Obtain the raw text for an object.
         
@@ -86,6 +111,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 +137,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. 
 
@@ -120,3 +175,56 @@ class ObjectStore(object):
         f, commit = self.add_pack()
         write_pack_data(f, objects, len(objects))
         commit()
+
+
+class ObjectImporter(object):
+
+    def __init__(self, count):
+        self.count = count
+
+    def add_object(self, object):
+        raise NotImplementedError(self.add_object)
+
+    def finish(self, object):
+        raise NotImplementedError(self.finish)
+
+
+class ObjectIterator(object):
+
+    def iterobjects(self):
+        raise NotImplementedError(self.iterobjects)
+
+
+class ObjectStoreIterator(ObjectIterator):
+
+    def __init__(self, store, shas):
+        self.store = store
+        self.shas = shas
+
+    def __iter__(self):
+        return ((self.store[sha], path) for sha, path in self.shas)
+
+    def iterobjects(self):
+        for o, path in self:
+            yield o
+
+    def __contains__(self, needle):
+        """Check if an object is present.
+
+        :param needle: SHA1 of the object to check for
+        """
+        # FIXME: This could be more efficient
+        for sha, path in self.shas:
+            if sha == needle:
+                return True
+        return False
+
+    def __getitem__(self, key):
+        """Find an object by SHA1."""
+        return self.store[key]
+
+    def __len__(self):
+        """Return the number of objects."""
+        return len(self.shas)
+
+