/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/git/transportgit.py

  • Committer: Jelmer Vernooij
  • Date: 2019-05-29 03:22:34 UTC
  • mfrom: (7303 work)
  • mto: This revision was merged to the branch mainline in revision 7306.
  • Revision ID: jelmer@jelmer.uk-20190529032234-mt3fuws8gq03tapi
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
import sys
25
25
 
26
26
from dulwich.errors import (
27
 
    NotGitRepository,
28
27
    NoIndexPresent,
29
28
    )
30
29
from dulwich.file import (
37
36
from dulwich.object_store import (
38
37
    PackBasedObjectStore,
39
38
    PACKDIR,
 
39
    read_packs_file,
40
40
    )
41
41
from dulwich.pack import (
42
42
    MemoryPackIndex,
56
56
    CONTROLDIR,
57
57
    INDEX_FILENAME,
58
58
    OBJECTDIR,
59
 
    REFSDIR,
60
59
    SYMREF,
61
60
    check_ref_format,
62
61
    read_packed_refs_with_peeled,
69
68
    transport as _mod_transport,
70
69
    urlutils,
71
70
    )
72
 
from ..sixish import (
73
 
    PY3,
74
 
    text_type,
75
 
    )
76
71
from ..errors import (
77
72
    AlreadyControlDirError,
78
73
    FileExists,
79
74
    LockBroken,
80
 
    LockError,
81
75
    LockContention,
82
76
    NotLocalUrl,
83
77
    NoSuchFile,
104
98
 
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])
108
102
            try:
109
103
                self.transport.mkdir(dirname)
110
104
            except FileExists:
133
127
        else:
134
128
            keys.add(b"HEAD")
135
129
        try:
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.
183
178
 
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.
188
183
        """
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")
223
218
            else:
224
219
                # Read only the first 40 bytes
225
 
                return header + f.read(40-len(SYMREF))
 
220
                return header + f.read(40 - len(SYMREF))
226
221
 
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))
258
253
        else:
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')
261
257
 
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.
281
277
        else:
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")
285
282
        return True
286
283
 
287
284
    def add_if_new(self, name, ref):
307
304
        else:
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")
311
308
        return True
312
309
 
313
310
    def remove_if_equals(self, name, old_ref):
317
314
        perform an atomic compare-and-delete operation.
318
315
 
319
316
        :param name: The refname to delete.
320
 
        :param old_ref: The old sha the refname must refer to, or None to delete
321
 
            unconditionally.
 
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.
323
320
        """
324
321
        self._check_refname(name)
347
344
            transport = self.transport
348
345
        lockname = name + b".lock"
349
346
        try:
350
 
            self.transport.delete(urlutils.quote_from_bytes(lockname))
 
347
            transport.delete(urlutils.quote_from_bytes(lockname))
351
348
        except NoSuchFile:
352
349
            pass
353
350
 
359
356
        self._ensure_dir_exists(urlutils.quote_from_bytes(name))
360
357
        lockname = urlutils.quote_from_bytes(name + b".lock")
361
358
        try:
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))
369
367
        else:
370
368
            try:
371
369
                gf = GitFile(local_path, 'wb')
374
372
            else:
375
373
                def unlock():
376
374
                    try:
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
 
379
                    # disappeared
381
380
                    gf.abort()
382
381
                return LogicalLockResult(unlock)
383
382
 
412
411
            else:
413
412
                self._controltransport = self.transport.clone('.git')
414
413
        else:
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:
418
418
            with commondir:
429
429
        if refs_text is not None:
430
430
            refs_container = InfoRefsContainer(BytesIO(refs_text))
431
431
            try:
432
 
                head = TransportRefsContainer(self._commontransport).read_loose_ref("HEAD")
 
432
                head = TransportRefsContainer(
 
433
                    self._commontransport).read_loose_ref("HEAD")
433
434
            except KeyError:
434
435
                pass
435
436
            else:
436
437
                refs_container._refs["HEAD"] = head
437
438
        else:
438
439
            refs_container = TransportRefsContainer(
439
 
                    self._commontransport, self._controltransport)
 
440
                self._commontransport, self._controltransport)
440
441
        super(TransportRepo, self).__init__(object_store,
441
 
                refs_container)
 
442
                                            refs_container)
442
443
 
443
444
    def controldir(self):
444
445
        return self._controltransport.local_abspath('.')
587
588
                ret.append(l)
588
589
            return ret
589
590
 
590
 
    @property
591
 
    def packs(self):
592
 
        # FIXME: Never invalidates.
593
 
        if not self._pack_cache:
594
 
            self._update_pack_cache()
595
 
        return self._pack_cache.values()
596
 
 
597
591
    def _update_pack_cache(self):
598
 
        for pack in self._load_packs():
599
 
            self._pack_cache[pack._basename] = pack
 
592
        pack_files = set()
 
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
 
597
                # fully written)
 
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])
 
601
 
 
602
        new_packs = []
 
603
        for basename in pack_files:
 
604
            pack_name = basename + ".pack"
 
605
            if basename not in self._pack_cache:
 
606
                try:
 
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)
 
611
                else:
 
612
                    pd = PackData(
 
613
                        pack_name, self.pack_transport.get(pack_name),
 
614
                        size=size)
 
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()
 
625
        return new_packs
600
626
 
601
627
    def _pack_names(self):
602
628
        try:
608
634
                # Hmm, warn about running 'git update-server-info' ?
609
635
                return iter([])
610
636
            else:
611
 
                # TODO(jelmer): Move to top-level after dulwich
612
 
                # 0.19.7 is released.
613
 
                from dulwich.object_store import read_packs_file
614
637
                with f:
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)
622
 
 
623
 
    def _load_packs(self):
624
 
        ret = []
625
 
        for name in self._pack_names():
626
 
            if name.startswith("pack-") and name.endswith(".pack"):
627
 
                try:
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))
632
 
                else:
633
 
                    pd = PackData(name, self.pack_transport.get(name),
634
 
                            size=size)
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]
639
 
                ret.append(pack)
640
 
        return ret
 
645
        try:
 
646
            del self._pack_cache[os.path.basename(pack._basename)]
 
647
        except KeyError:
 
648
            pass
641
649
 
642
650
    def _iter_loose_objects(self):
643
651
        for base in self.transport.list_dir('.'):
644
652
            if len(base) != 2:
645
653
                continue
646
654
            for rest in self.transport.list_dir(base):
647
 
                yield (base+rest).encode(sys.getfilesystemencoding())
 
655
                yield (base + rest).encode(sys.getfilesystemencoding())
648
656
 
649
657
    def _split_loose_object(self, sha):
650
658
        return (sha[:2], sha[2:])
673
681
            pass
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())
678
686
 
679
687
    def move_in_pack(self, f):
687
695
        f.seek(0)
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"
692
701
        f.seek(0)
693
702
        self.pack_transport.put_file(basename + ".pack", f)
697
706
        finally:
698
707
            idxfile.close()
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
705
714
 
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()))
717
726
        p._data.pack = p
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())
719
729
 
720
730
        pack_sha = p.index.objects_sha1()
721
731
 
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'))
724
734
        try:
725
735
            entries, data_sum = write_pack_objects(datafile, p.pack_tuples())
726
736
        finally:
732
742
            write_pack_index_v2(idxfile, entries, data_sum)
733
743
        finally:
734
744
            idxfile.close()
735
 
        # TODO(jelmer): Just add new pack to the cache
736
 
        self._flush_pack_cache()
737
745
 
738
746
    def add_pack(self):
739
747
        """Add a new pack to this object store.
742
750
            call when the pack is finished.
743
751
        """
744
752
        f = BytesIO()
 
753
 
745
754
        def commit():
746
755
            if len(f.getvalue()) > 0:
747
756
                return self.move_in_pack(f)
748
757
            else:
749
758
                return None
 
759
 
750
760
        def abort():
751
761
            return None
752
762
        return f, commit, abort