|
@@ -237,21 +237,10 @@ class BaseObjectStore(object):
|
|
|
return self.iter_shas(self.find_missing_objects(have, want))
|
|
|
|
|
|
|
|
|
-class DiskObjectStore(BaseObjectStore):
|
|
|
- """Git-style object store that exists on disk."""
|
|
|
-
|
|
|
- def __init__(self, path):
|
|
|
- """Open an object store.
|
|
|
+class PackBasedObjectStore(BaseObjectStore):
|
|
|
|
|
|
- :param path: Path of the object store.
|
|
|
- """
|
|
|
- self.path = path
|
|
|
+ def __init__(self):
|
|
|
self._pack_cache = None
|
|
|
- self.pack_dir = os.path.join(self.path, PACKDIR)
|
|
|
-
|
|
|
- def contains_loose(self, sha):
|
|
|
- """Check if a particular object is present by SHA1 and is loose."""
|
|
|
- return self._get_shafile(sha) is not None
|
|
|
|
|
|
def contains_packed(self, sha):
|
|
|
"""Check if a particular object is present by SHA1 and is packed."""
|
|
@@ -260,10 +249,15 @@ class DiskObjectStore(BaseObjectStore):
|
|
|
return True
|
|
|
return False
|
|
|
|
|
|
- def __iter__(self):
|
|
|
- """Iterate over the SHAs that are present in this store."""
|
|
|
- iterables = self.packs + [self._iter_shafile_shas()]
|
|
|
- return itertools.chain(*iterables)
|
|
|
+ def _load_packs(self):
|
|
|
+ raise NotImplementedError(self._load_packs)
|
|
|
+
|
|
|
+ def _add_known_pack(self, pack):
|
|
|
+ """Add a newly appeared pack to the cache by path.
|
|
|
+
|
|
|
+ """
|
|
|
+ if self._pack_cache is not None:
|
|
|
+ self._pack_cache.append(pack)
|
|
|
|
|
|
@property
|
|
|
def packs(self):
|
|
@@ -272,6 +266,72 @@ class DiskObjectStore(BaseObjectStore):
|
|
|
self._pack_cache = self._load_packs()
|
|
|
return self._pack_cache
|
|
|
|
|
|
+ def _iter_loose_objects(self):
|
|
|
+ raise NotImplementedError(self._iter_loose_objects)
|
|
|
+
|
|
|
+ def _get_loose_object(self, sha):
|
|
|
+ raise NotImplementedError(self._get_loose_object)
|
|
|
+
|
|
|
+ def __iter__(self):
|
|
|
+ """Iterate over the SHAs that are present in this store."""
|
|
|
+ iterables = self.packs + [self._iter_loose_objects()]
|
|
|
+ return itertools.chain(*iterables)
|
|
|
+
|
|
|
+ def contains_loose(self, sha):
|
|
|
+ """Check if a particular object is present by SHA1 and is loose."""
|
|
|
+ return self._get_loose_object(sha) is not None
|
|
|
+
|
|
|
+ def get_raw(self, name):
|
|
|
+ """Obtain the raw text for an object.
|
|
|
+
|
|
|
+ :param name: sha for the object.
|
|
|
+ :return: tuple with object type and object contents.
|
|
|
+ """
|
|
|
+ if len(name) == 40:
|
|
|
+ sha = hex_to_sha(name)
|
|
|
+ hexsha = name
|
|
|
+ elif len(name) == 20:
|
|
|
+ sha = name
|
|
|
+ hexsha = None
|
|
|
+ else:
|
|
|
+ raise AssertionError
|
|
|
+ for pack in self.packs:
|
|
|
+ try:
|
|
|
+ return pack.get_raw(sha)
|
|
|
+ except KeyError:
|
|
|
+ pass
|
|
|
+ if hexsha is None:
|
|
|
+ hexsha = sha_to_hex(name)
|
|
|
+ ret = self._get_loose_object(hexsha)
|
|
|
+ if ret is not None:
|
|
|
+ return ret.type, ret.as_raw_string()
|
|
|
+ raise KeyError(hexsha)
|
|
|
+
|
|
|
+ def add_objects(self, objects):
|
|
|
+ """Add a set of objects to this object store.
|
|
|
+
|
|
|
+ :param objects: Iterable over objects, should support __len__.
|
|
|
+ """
|
|
|
+ if len(objects) == 0:
|
|
|
+ # Don't bother writing an empty pack file
|
|
|
+ return
|
|
|
+ f, commit = self.add_pack()
|
|
|
+ write_pack_data(f, objects, len(objects))
|
|
|
+ commit()
|
|
|
+
|
|
|
+
|
|
|
+class DiskObjectStore(PackBasedObjectStore):
|
|
|
+ """Git-style object store that exists on disk."""
|
|
|
+
|
|
|
+ def __init__(self, path):
|
|
|
+ """Open an object store.
|
|
|
+
|
|
|
+ :param path: Path of the object store.
|
|
|
+ """
|
|
|
+ super(DiskObjectStore, self).__init__()
|
|
|
+ self.path = path
|
|
|
+ self.pack_dir = os.path.join(self.path, PACKDIR)
|
|
|
+
|
|
|
def _load_packs(self):
|
|
|
if not os.path.exists(self.pack_dir):
|
|
|
return []
|
|
@@ -285,58 +345,25 @@ class DiskObjectStore(BaseObjectStore):
|
|
|
suffix_len = len(".pack")
|
|
|
return [Pack(f[:-suffix_len]) for _, f in pack_files]
|
|
|
|
|
|
- def _add_known_pack(self, path):
|
|
|
- """Add a newly appeared pack to the cache by path.
|
|
|
-
|
|
|
- """
|
|
|
- if self._pack_cache is not None:
|
|
|
- self._pack_cache.append(Pack(path))
|
|
|
-
|
|
|
def _get_shafile_path(self, sha):
|
|
|
dir = sha[:2]
|
|
|
file = sha[2:]
|
|
|
# Check from object dir
|
|
|
return os.path.join(self.path, dir, file)
|
|
|
|
|
|
- def _iter_shafile_shas(self):
|
|
|
+ def _iter_loose_objects(self):
|
|
|
for base in os.listdir(self.path):
|
|
|
if len(base) != 2:
|
|
|
continue
|
|
|
for rest in os.listdir(os.path.join(self.path, base)):
|
|
|
yield base+rest
|
|
|
|
|
|
- def _get_shafile(self, sha):
|
|
|
+ def _get_loose_object(self, sha):
|
|
|
path = self._get_shafile_path(sha)
|
|
|
if os.path.exists(path):
|
|
|
return ShaFile.from_file(path)
|
|
|
return None
|
|
|
|
|
|
- def get_raw(self, name):
|
|
|
- """Obtain the raw text for an object.
|
|
|
-
|
|
|
- :param name: sha for the object.
|
|
|
- :return: tuple with object type and object contents.
|
|
|
- """
|
|
|
- if len(name) == 40:
|
|
|
- sha = hex_to_sha(name)
|
|
|
- hexsha = name
|
|
|
- elif len(name) == 20:
|
|
|
- sha = name
|
|
|
- hexsha = None
|
|
|
- else:
|
|
|
- raise AssertionError
|
|
|
- for pack in self.packs:
|
|
|
- try:
|
|
|
- return pack.get_raw(sha)
|
|
|
- except KeyError:
|
|
|
- pass
|
|
|
- if hexsha is None:
|
|
|
- hexsha = sha_to_hex(name)
|
|
|
- ret = self._get_shafile(hexsha)
|
|
|
- if ret is not None:
|
|
|
- return ret.type, ret.as_raw_string()
|
|
|
- raise KeyError(hexsha)
|
|
|
-
|
|
|
def move_in_thin_pack(self, path):
|
|
|
"""Move a specific file containing a pack into the pack directory.
|
|
|
|
|
@@ -362,7 +389,7 @@ class DiskObjectStore(BaseObjectStore):
|
|
|
newbasename = os.path.join(self.pack_dir, "pack-%s" % pack_sha)
|
|
|
os.rename(temppath+".pack", newbasename+".pack")
|
|
|
os.rename(temppath+".idx", newbasename+".idx")
|
|
|
- self._add_known_pack(newbasename)
|
|
|
+ self._add_known_pack(Pack(newbasename))
|
|
|
|
|
|
def move_in_pack(self, path):
|
|
|
"""Move a specific file containing a pack into the pack directory.
|
|
@@ -379,7 +406,7 @@ class DiskObjectStore(BaseObjectStore):
|
|
|
write_pack_index_v2(basename+".idx", entries, p.get_stored_checksum())
|
|
|
p.close()
|
|
|
os.rename(path, basename + ".pack")
|
|
|
- self._add_known_pack(basename)
|
|
|
+ self._add_known_pack(Pack(basename))
|
|
|
|
|
|
def add_thin_pack(self):
|
|
|
"""Add a new thin pack to this object store.
|
|
@@ -428,18 +455,6 @@ class DiskObjectStore(BaseObjectStore):
|
|
|
finally:
|
|
|
f.close()
|
|
|
|
|
|
- def add_objects(self, objects):
|
|
|
- """Add a set of objects to this object store.
|
|
|
-
|
|
|
- :param objects: Iterable over objects, should support __len__.
|
|
|
- """
|
|
|
- if len(objects) == 0:
|
|
|
- # Don't bother writing an empty pack file
|
|
|
- return
|
|
|
- f, commit = self.add_pack()
|
|
|
- write_pack_data(f, objects, len(objects))
|
|
|
- commit()
|
|
|
-
|
|
|
|
|
|
class MemoryObjectStore(BaseObjectStore):
|
|
|
"""Object store that keeps all objects in memory."""
|