105
99
def _ensure_dir_exists(self, path):
106
100
for n in range(path.count("/")):
107
dirname = "/".join(path.split("/")[:n+1])
101
dirname = "/".join(path.split("/")[:n + 1])
109
103
self.transport.mkdir(dirname)
110
104
except FileExists:
134
128
keys.add(b"HEAD")
136
iter_files = list(self.transport.clone("refs").iter_files_recursive())
130
iter_files = list(self.transport.clone(
131
"refs").iter_files_recursive())
137
132
for filename in iter_files:
138
133
unquoted_filename = urlutils.unquote_to_bytes(filename)
139
134
refname = osutils.pathjoin(b"refs", unquoted_filename)
182
177
"""Return the cached peeled value of a ref, if available.
184
179
:param name: Name of the ref to peel
185
:return: The peeled value of the ref. If the ref is known not point to a
186
tag, this will be the SHA the ref refers to. If the ref may point to
187
a tag, but no cached information is available, None is returned.
180
:return: The peeled value of the ref. If the ref is known not point to
181
a tag, this will be the SHA the ref refers to. If the ref may point
182
to a tag, but no cached information is available, None is returned.
189
184
self.get_packed_refs()
190
185
if self._peeled_refs is None or name not in self._packed_refs:
222
217
return header + next(iter(f)).rstrip(b"\r\n")
224
219
# Read only the first 40 bytes
225
return header + f.read(40-len(SYMREF))
220
return header + f.read(40 - len(SYMREF))
227
222
def _remove_packed_ref(self, name):
228
223
if self._packed_refs is None:
257
252
self._ensure_dir_exists(urlutils.quote_from_bytes(name))
259
254
transport = self.worktree_transport
260
transport.put_bytes(urlutils.quote_from_bytes(name), SYMREF + other + b'\n')
255
transport.put_bytes(urlutils.quote_from_bytes(
256
name), SYMREF + other + b'\n')
262
258
def set_if_equals(self, name, old_ref, new_ref):
263
259
"""Set a refname to new_ref only if it currently equals old_ref.
282
278
transport = self.transport
283
279
self._ensure_dir_exists(urlutils.quote_from_bytes(realname))
284
transport.put_bytes(urlutils.quote_from_bytes(realname), new_ref+b"\n")
280
transport.put_bytes(urlutils.quote_from_bytes(
281
realname), new_ref + b"\n")
287
284
def add_if_new(self, name, ref):
308
305
transport = self.transport
309
306
self._ensure_dir_exists(urlutils.quote_from_bytes(realname))
310
transport.put_bytes(urlutils.quote_from_bytes(realname), ref+b"\n")
307
transport.put_bytes(urlutils.quote_from_bytes(realname), ref + b"\n")
313
310
def remove_if_equals(self, name, old_ref):
317
314
perform an atomic compare-and-delete operation.
319
316
:param name: The refname to delete.
320
:param old_ref: The old sha the refname must refer to, or None to delete
317
:param old_ref: The old sha the refname must refer to, or None to
318
delete unconditionally.
322
319
:return: True if the delete was successful, False otherwise.
324
321
self._check_refname(name)
359
356
self._ensure_dir_exists(urlutils.quote_from_bytes(name))
360
357
lockname = urlutils.quote_from_bytes(name + b".lock")
362
local_path = self.transport.local_abspath(urlutils.quote_from_bytes(name))
359
local_path = transport.local_abspath(
360
urlutils.quote_from_bytes(name))
363
361
except NotLocalUrl:
364
362
# This is racy, but what can we do?
365
if self.transport.has(lockname):
363
if transport.has(lockname):
366
364
raise LockContention(name)
367
lock_result = self.transport.put_bytes(lockname, b'Locked by brz-git')
368
return LogicalLockResult(lambda: self.transport.delete(lockname))
365
transport.put_bytes(lockname, b'Locked by brz-git')
366
return LogicalLockResult(lambda: transport.delete(lockname))
371
369
gf = GitFile(local_path, 'wb')
377
self.transport.delete(lockname)
375
transport.delete(lockname)
378
376
except NoSuchFile:
379
377
raise LockBroken(lockname)
380
# GitFile.abort doesn't care if the lock has already disappeared
378
# GitFile.abort doesn't care if the lock has already
382
381
return LogicalLockResult(unlock)
413
412
self._controltransport = self.transport.clone('.git')
415
self._controltransport = self.transport.clone(urlutils.quote_from_bytes(path))
414
self._controltransport = self.transport.clone(
415
urlutils.quote_from_bytes(path))
416
416
commondir = self.get_named_file(COMMONDIR)
417
417
if commondir is not None:
429
429
if refs_text is not None:
430
430
refs_container = InfoRefsContainer(BytesIO(refs_text))
432
head = TransportRefsContainer(self._commontransport).read_loose_ref("HEAD")
432
head = TransportRefsContainer(
433
self._commontransport).read_loose_ref("HEAD")
436
437
refs_container._refs["HEAD"] = head
438
439
refs_container = TransportRefsContainer(
439
self._commontransport, self._controltransport)
440
self._commontransport, self._controltransport)
440
441
super(TransportRepo, self).__init__(object_store,
443
444
def controldir(self):
444
445
return self._controltransport.local_abspath('.')
592
# FIXME: Never invalidates.
593
if not self._pack_cache:
594
self._update_pack_cache()
595
return self._pack_cache.values()
597
591
def _update_pack_cache(self):
598
for pack in self._load_packs():
599
self._pack_cache[pack._basename] = pack
593
pack_dir_contents = self._pack_names()
594
for name in pack_dir_contents:
595
if name.startswith("pack-") and name.endswith(".pack"):
596
# verify that idx exists first (otherwise the pack was not yet
598
idx_name = os.path.splitext(name)[0] + ".idx"
599
if idx_name in pack_dir_contents:
600
pack_files.add(os.path.splitext(name)[0])
603
for basename in pack_files:
604
pack_name = basename + ".pack"
605
if basename not in self._pack_cache:
607
size = self.pack_transport.stat(pack_name).st_size
608
except TransportNotPossible:
609
f = self.pack_transport.get(pack_name)
610
pd = PackData(pack_name, f)
613
pack_name, self.pack_transport.get(pack_name),
615
idxname = basename + ".idx"
616
idx = load_pack_index_file(
617
idxname, self.pack_transport.get(idxname))
618
pack = Pack.from_objects(pd, idx)
619
pack._basename = basename
620
self._pack_cache[basename] = pack
621
new_packs.append(pack)
622
# Remove disappeared pack files
623
for f in set(self._pack_cache) - pack_files:
624
self._pack_cache.pop(f).close()
601
627
def _pack_names(self):
608
634
# Hmm, warn about running 'git update-server-info' ?
611
# TODO(jelmer): Move to top-level after dulwich
612
# 0.19.7 is released.
613
from dulwich.object_store import read_packs_file
615
638
return read_packs_file(f)
616
639
except NoSuchFile:
619
642
def _remove_pack(self, pack):
620
643
self.pack_transport.delete(os.path.basename(pack.index.path))
621
644
self.pack_transport.delete(pack.data.filename)
623
def _load_packs(self):
625
for name in self._pack_names():
626
if name.startswith("pack-") and name.endswith(".pack"):
628
size = self.pack_transport.stat(name).st_size
629
except TransportNotPossible:
630
f = self.pack_transport.get(name)
631
pd = PackData(name, f, size=len(contents))
633
pd = PackData(name, self.pack_transport.get(name),
635
idxname = name.replace(".pack", ".idx")
636
idx = load_pack_index_file(idxname, self.pack_transport.get(idxname))
637
pack = Pack.from_objects(pd, idx)
638
pack._basename = idxname[:-4]
646
del self._pack_cache[os.path.basename(pack._basename)]
642
650
def _iter_loose_objects(self):
643
651
for base in self.transport.list_dir('.'):
644
652
if len(base) != 2:
646
654
for rest in self.transport.list_dir(base):
647
yield (base+rest).encode(sys.getfilesystemencoding())
655
yield (base + rest).encode(sys.getfilesystemencoding())
649
657
def _split_loose_object(self, sha):
650
658
return (sha[:2], sha[2:])
674
682
path = urlutils.quote_from_bytes(osutils.pathjoin(dir, file))
675
683
if self.transport.has(path):
676
return # Already there, no need to write again
684
return # Already there, no need to write again
677
685
self.transport.put_bytes(path, obj.as_legacy_object())
679
687
def move_in_pack(self, f):
688
696
p = PackData("", f, len(f.getvalue()))
689
697
entries = p.sorted_entries()
690
basename = "pack-%s" % iter_sha1(entry[0] for entry in entries).decode('ascii')
698
basename = "pack-%s" % iter_sha1(entry[0]
699
for entry in entries).decode('ascii')
691
700
p._filename = basename + ".pack"
693
702
self.pack_transport.put_file(basename + ".pack", f)
699
708
idxfile = self.pack_transport.get(basename + ".idx")
700
idx = load_pack_index_file(basename+".idx", idxfile)
709
idx = load_pack_index_file(basename + ".idx", idxfile)
701
710
final_pack = Pack.from_objects(p, idx)
702
711
final_pack._basename = basename
703
self._add_known_pack(basename, final_pack)
712
self._add_cached_pack(basename, final_pack)
704
713
return final_pack
706
715
def move_in_thin_pack(self, f):
715
724
p = Pack('', resolve_ext_ref=self.get_raw)
716
725
p._data = PackData.from_file(f, len(f.getvalue()))
718
p._idx_load = lambda: MemoryPackIndex(p.data.sorted_entries(), p.data.get_stored_checksum())
727
p._idx_load = lambda: MemoryPackIndex(
728
p.data.sorted_entries(), p.data.get_stored_checksum())
720
730
pack_sha = p.index.objects_sha1()
722
732
datafile = self.pack_transport.open_write_stream(
723
"pack-%s.pack" % pack_sha.decode('ascii'))
733
"pack-%s.pack" % pack_sha.decode('ascii'))
725
735
entries, data_sum = write_pack_objects(datafile, p.pack_tuples())