387
388
def _remove_loose_object(self, sha):
388
389
os.remove(self._get_shafile_path(sha))
390
def move_in_thin_pack(self, path):
391
def _complete_thin_pack(self, f, path, copier, indexer):
391
392
"""Move a specific file containing a pack into the pack directory.
393
394
:note: The file should be on the same file system as the
397
:param f: Open file object for the pack.
396
398
:param path: Path to the pack file.
399
:param copier: A PackStreamCopier to use for writing pack data.
400
:param indexer: A PackIndexer for indexing the pack.
398
data = ThinPackData(self.get_raw, path)
400
# Write index for the thin pack (do we really need this?)
401
temppath = os.path.join(self.pack_dir,
402
sha_to_hex(urllib2.randombytes(20))+".tempidx")
403
data.create_index_v2(temppath)
404
p = Pack.from_objects(data, load_pack_index(temppath))
402
entries = list(indexer)
404
# Update the header with the new number of objects.
406
write_pack_header(f, len(entries) + len(indexer.ext_refs()))
408
# Rescan the rest of the pack, computing the SHA with the new header.
409
new_sha = compute_file_sha(f, end_ofs=-20)
412
for ext_sha in indexer.ext_refs():
413
type_num, data = self.get_raw(ext_sha)
415
crc32 = write_pack_object(f, type_num, data, sha=new_sha)
416
entries.append((ext_sha, offset, crc32))
417
pack_sha = new_sha.digest()
423
pack_base_name = os.path.join(
424
self.pack_dir, 'pack-' + iter_sha1(e[0] for e in entries))
425
os.rename(path, pack_base_name + '.pack')
428
index_file = GitFile(pack_base_name + '.idx', 'wb')
407
# Write a full pack version
408
temppath = os.path.join(self.pack_dir,
409
sha_to_hex(urllib2.randombytes(20))+".temppack")
410
write_pack(temppath, ((o, None) for o in p.iterobjects()), len(p))
430
write_pack_index_v2(index_file, entries, pack_sha)
414
pack_sha = load_pack_index(temppath+".idx").objects_sha1()
415
newbasename = os.path.join(self.pack_dir, "pack-%s" % pack_sha)
416
os.rename(temppath+".pack", newbasename+".pack")
417
os.rename(temppath+".idx", newbasename+".idx")
418
final_pack = Pack(newbasename)
435
# Add the pack to the store and return it.
436
final_pack = Pack(pack_base_name)
437
final_pack.check_length_and_checksum()
419
438
self._add_known_pack(final_pack)
420
439
return final_pack
441
def add_thin_pack(self, read_all, read_some):
442
"""Add a new thin pack to this object store.
444
Thin packs are packs that contain deltas with parents that exist outside
445
the pack. They should never be placed in the object store directly, and
446
always indexed and completed as they are copied.
448
:param read_all: Read function that blocks until the number of requested
450
:param read_some: Read function that returns at least one byte, but may
451
not return the number of bytes requested.
452
:return: A Pack object pointing at the now-completed thin pack in the
453
objects/pack directory.
455
fd, path = tempfile.mkstemp(dir=self.path, prefix='tmp_pack_')
456
f = os.fdopen(fd, 'w+b')
459
indexer = PackIndexer(f, resolve_ext_ref=self.get_raw)
460
copier = PackStreamCopier(read_all, read_some, f,
463
return self._complete_thin_pack(f, path, copier, indexer)
422
467
def move_in_pack(self, path):
423
468
"""Move a specific file containing a pack into the pack directory.
649
677
def tree_lookup_path(lookup_obj, root_sha, path):
650
"""Lookup an object in a Git tree.
678
"""Look up an object in a Git tree.
652
680
:param lookup_obj: Callback for retrieving object by SHA1
653
681
:param root_sha: SHA1 of the root tree
654
682
:param path: Path to lookup
683
:return: A tuple of (mode, SHA) of the resulting path.
656
parts = path.split("/")
660
obj = lookup_obj(sha)
661
if not isinstance(obj, Tree):
662
raise NotTreeError(sha)
685
tree = lookup_obj(root_sha)
686
if not isinstance(tree, Tree):
687
raise NotTreeError(root_sha)
688
return tree.lookup_path(lookup_obj, path)
669
691
class MissingObjectFinder(object):