/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/remote.py

  • Committer: Jelmer Vernooij
  • Date: 2018-11-16 23:15:15 UTC
  • mfrom: (7180 work)
  • mto: This revision was merged to the branch mainline in revision 7183.
  • Revision ID: jelmer@jelmer.uk-20181116231515-zqd2yn6kj8lfydyp
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
from __future__ import absolute_import
20
20
 
21
 
from io import BytesIO
 
21
import gzip
22
22
import re
23
23
 
24
24
from .. import (
44
44
    NoSuchTag,
45
45
    NotBranchError,
46
46
    NotLocalUrl,
47
 
    NoWorkingTree,
48
47
    PermissionDenied,
49
48
    UninitializableFormat,
50
49
    )
71
70
from .dir import (
72
71
    GitControlDirFormat,
73
72
    GitDir,
74
 
    BareLocalGitControlDirFormat,
75
73
    )
76
74
from .errors import (
77
75
    GitSmartRemoteNotSupported,
100
98
import dulwich.client
101
99
from dulwich.errors import (
102
100
    GitProtocolError,
 
101
    HangupException,
103
102
    )
104
103
from dulwich.pack import (
105
104
    Pack,
116
115
import os
117
116
import select
118
117
import tempfile
119
 
import urllib
120
118
 
121
119
try:
122
120
    import urllib.parse as urlparse
137
135
    def _lookup_revno(self, revid):
138
136
        try:
139
137
            return _quick_lookup_revno(self.source_branch, self.target_branch,
140
 
                revid)
 
138
                                       revid)
141
139
        except GitSmartRemoteNotSupported:
142
140
            return None
143
141
 
193
191
    :param message: Message sent by the remote git server
194
192
    """
195
193
    message = str(message).strip()
196
 
    if (message.startswith("Could not find Repository ") or
197
 
        message == 'Repository not found.' or
198
 
        (message.startswith('Repository ') and message.endswith(' not found.'))):
 
194
    if (message.startswith("Could not find Repository ")
 
195
        or message == 'Repository not found.'
 
196
            or (message.startswith('Repository ') and
 
197
                message.endswith(' not found.'))):
199
198
        return NotBranchError(url, message)
200
199
    if message == "HEAD failed to update":
201
200
        base_url, _ = urlutils.split_segment_parameters(url)
203
202
    if message.startswith('access denied or repository not exported:'):
204
203
        extra, path = message.split(': ', 1)
205
204
        return PermissionDenied(path, extra)
 
205
    if message.endswith('You are not allowed to push code to this project.'):
 
206
        return PermissionDenied(url, message)
 
207
    if message.endswith(' does not appear to be a git repository'):
 
208
        return NotBranchError(url, message)
 
209
    m = re.match(r'Permission to ([^ ]+) denied to ([^ ]+)\.', message)
 
210
    if m:
 
211
        return PermissionDenied(m.group(1), 'denied to %s' % m.group(2))
206
212
    # Don't know, just return it to the user as-is
207
213
    return RemoteGitError(message)
208
214
 
259
265
        if self._host == '':
260
266
            # return dulwich.client.LocalGitClient()
261
267
            return dulwich.client.SubprocessGitClient()
262
 
        return dulwich.client.TCPGitClient(self._host, self._port,
263
 
            report_activity=self._report_activity)
 
268
        return dulwich.client.TCPGitClient(
 
269
            self._host, self._port, report_activity=self._report_activity)
264
270
 
265
271
 
266
272
class SSHSocketWrapper(object):
285
291
        self.bzr_ssh_vendor = ssh._get_ssh_vendor()
286
292
 
287
293
    def run_command(self, host, command, username=None, port=None):
288
 
        connection = self.bzr_ssh_vendor.connect_ssh(username=username,
289
 
            password=None, port=port, host=host, command=command)
 
294
        connection = self.bzr_ssh_vendor.connect_ssh(
 
295
            username=username, password=None, port=port, host=host,
 
296
            command=command)
290
297
        (kind, io_object) = connection.get_sock_or_pipes()
291
298
        if kind == 'socket':
292
299
            return SSHSocketWrapper(io_object)
294
301
            raise AssertionError("Unknown io object kind %r'" % kind)
295
302
 
296
303
 
297
 
#dulwich.client.get_ssh_vendor = DulwichSSHVendor
 
304
# dulwich.client.get_ssh_vendor = DulwichSSHVendor
298
305
 
299
306
 
300
307
class SSHGitSmartTransport(GitSmartTransport):
313
320
            self._client = None
314
321
            return ret
315
322
        location_config = config.LocationConfig(self.base)
316
 
        client = dulwich.client.SSHGitClient(self._host, self._port, self._username,
 
323
        client = dulwich.client.SSHGitClient(
 
324
            self._host, self._port, self._username,
317
325
            report_activity=self._report_activity)
318
326
        # Set up alternate pack program paths
319
327
        upload_pack = location_config.get_user_option('git_upload_pack')
350
358
    def progress(self, text):
351
359
        text = text.rstrip(b"\r\n")
352
360
        text = text.decode('utf-8')
353
 
        if text.startswith('error: '):
 
361
        if text.lower().startswith('error: '):
354
362
            trace.show_error('git: %s', text[len(b'error: '):])
355
363
        else:
356
364
            trace.mutter("git: %s", text)
383
391
    def _gitrepository_class(self):
384
392
        return RemoteGitRepository
385
393
 
386
 
    def archive(self, format, committish, write_data, progress=None, write_error=None,
387
 
                subdirs=None, prefix=None):
388
 
        if format not in ('tar', 'zip'):
389
 
            raise errors.NoSuchExportFormat(format)
 
394
    def archive(self, format, committish, write_data, progress=None,
 
395
                write_error=None, subdirs=None, prefix=None):
390
396
        if progress is None:
391
397
            pb = ui.ui_factory.nested_progress_bar()
392
398
            progress = DefaultProgressReporter(pb).progress
393
399
        else:
394
400
            pb = None
 
401
        def progress_wrapper(message):
 
402
            if message.startswith(b"fatal: Unknown archive format \'"):
 
403
                format = message.strip()[len(b"fatal: Unknown archive format '"):-1]
 
404
                raise errors.NoSuchExportFormat(format.decode('ascii'))
 
405
            return progress(message)
395
406
        try:
396
 
            self._client.archive(self._client_path, committish,
397
 
                write_data, progress, write_error, format=format,
398
 
                subdirs=subdirs, prefix=prefix)
 
407
            self._client.archive(
 
408
                self._client_path, committish, write_data, progress_wrapper,
 
409
                write_error,
 
410
                format=(format.encode('ascii') if format else None),
 
411
                subdirs=subdirs,
 
412
                prefix=(prefix.encode('utf-8') if prefix else None))
399
413
        except GitProtocolError as e:
400
414
            raise parse_git_error(self.transport.external_url(), e)
401
415
        finally:
402
416
            if pb is not None:
403
417
                pb.finished()
404
418
 
405
 
    def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
 
419
    def fetch_pack(self, determine_wants, graph_walker, pack_data,
 
420
                   progress=None):
406
421
        if progress is None:
407
422
            pb = ui.ui_factory.nested_progress_bar()
408
423
            progress = DefaultProgressReporter(pb).progress
409
424
        else:
410
425
            pb = None
411
426
        try:
412
 
            result = self._client.fetch_pack(self._client_path, determine_wants,
413
 
                graph_walker, pack_data, progress)
 
427
            result = self._client.fetch_pack(
 
428
                self._client_path, determine_wants, graph_walker, pack_data,
 
429
                progress)
414
430
            if result.refs is None:
415
431
                result.refs = {}
416
 
            self._refs = remote_refs_dict_to_container(result.refs, result.symrefs)
 
432
            self._refs = remote_refs_dict_to_container(
 
433
                result.refs, result.symrefs)
417
434
            return result
418
435
        except GitProtocolError as e:
419
436
            raise parse_git_error(self.transport.external_url(), e)
427
444
            progress = DefaultProgressReporter(pb).progress
428
445
        else:
429
446
            pb = None
 
447
 
430
448
        def get_changed_refs_wrapper(refs):
431
449
            # TODO(jelmer): This drops symref information
432
450
            self._refs = remote_refs_dict_to_container(refs)
433
451
            return get_changed_refs(refs)
434
452
        try:
435
 
            return self._client.send_pack(self._client_path,
436
 
                    get_changed_refs_wrapper, generate_pack_data, progress)
 
453
            return self._client.send_pack(
 
454
                self._client_path, get_changed_refs_wrapper,
 
455
                generate_pack_data, progress)
437
456
        except GitProtocolError as e:
438
457
            raise parse_git_error(self.transport.external_url(), e)
439
458
        finally:
446
465
        if refname != b'HEAD' and refname in self.get_refs_container():
447
466
            raise AlreadyBranchError(self.user_url)
448
467
        if refname in self.get_refs_container():
449
 
            ref_chain, unused_sha = self.get_refs_container().follow(self._get_selected_ref(None))
 
468
            ref_chain, unused_sha = self.get_refs_container().follow(
 
469
                self._get_selected_ref(None))
450
470
            if ref_chain[0] == b'HEAD':
451
471
                refname = ref_chain[1]
452
472
        repo = self.open_repository()
454
474
 
455
475
    def destroy_branch(self, name=None):
456
476
        refname = self._get_selected_ref(name)
 
477
 
457
478
        def get_changed_refs(old_refs):
458
479
            ret = dict(old_refs)
459
 
            if not refname in ret:
 
480
            if refname not in ret:
460
481
                raise NotBranchError(self.user_url)
461
482
            ret[refname] = dulwich.client.ZERO_SHA
462
483
            return ret
 
484
 
463
485
        def generate_pack_data(have, want, ofs_delta=False):
464
486
            return pack_objects_to_data([])
465
487
        self.send_pack(get_changed_refs, generate_pack_data)
483
505
    def open_repository(self):
484
506
        return RemoteGitRepository(self)
485
507
 
 
508
    def get_branch_reference(self, name=None):
 
509
        ref = branch_name_to_ref(name)
 
510
        val = self.get_refs_container().read_ref(ref)
 
511
        if val.startswith(SYMREF):
 
512
            return val[len(SYMREF):]
 
513
        return None
 
514
 
486
515
    def open_branch(self, name=None, unsupported=False,
487
 
            ignore_fallbacks=False, ref=None, possible_transports=None,
488
 
            nascent_ok=False):
 
516
                    ignore_fallbacks=False, ref=None, possible_transports=None,
 
517
                    nascent_ok=False):
489
518
        repo = self.open_repository()
490
519
        ref = self._get_selected_ref(name, ref)
491
 
        if not nascent_ok and ref not in self.get_refs_container():
 
520
        try:
 
521
            if not nascent_ok and ref not in self.get_refs_container():
 
522
                raise NotBranchError(
 
523
                    self.root_transport.base, controldir=self)
 
524
        except NotGitRepository:
492
525
            raise NotBranchError(self.root_transport.base,
493
 
                    controldir=self)
 
526
                                 controldir=self)
494
527
        ref_chain, unused_sha = self.get_refs_container().follow(ref)
495
528
        return RemoteGitBranch(self, repo, ref_chain[-1])
496
529
 
507
540
        if self._refs is not None:
508
541
            return self._refs
509
542
        result = self.fetch_pack(lambda x: None, None,
510
 
            lambda x: None, lambda x: trace.mutter("git: %s" % x))
 
543
                                 lambda x: None,
 
544
                                 lambda x: trace.mutter("git: %s" % x))
511
545
        self._refs = remote_refs_dict_to_container(
512
 
                result.refs, result.symrefs)
 
546
            result.refs, result.symrefs)
513
547
        return self._refs
514
548
 
515
549
    def push_branch(self, source, revision_id=None, overwrite=False,
541
575
                if lossy:
542
576
                    new_sha = source_store._lookup_revision_sha1(revision_id)
543
577
                else:
544
 
                    new_sha = repo.lookup_bzr_revision_id(revision_id)[0]
 
578
                    try:
 
579
                        new_sha = repo.lookup_bzr_revision_id(revision_id)[0]
 
580
                    except errors.NoSuchRevision:
 
581
                        raise errors.NoRoundtrippingSupport(
 
582
                            source, self.open_branch(name=name, nascent_ok=True))
545
583
                if not overwrite:
546
 
                    if remote_divergence(ret.get(refname), new_sha, source_store):
 
584
                    if remote_divergence(ret.get(refname), new_sha,
 
585
                                         source_store):
547
586
                        raise DivergedBranches(
548
 
                                source, self.open_branch(name, nascent_ok=True))
 
587
                            source, self.open_branch(name, nascent_ok=True))
549
588
                ret[refname] = new_sha
550
589
                return ret
551
590
            if lossy:
554
593
                generate_pack_data = source_store.generate_pack_data
555
594
            new_refs = self.send_pack(get_changed_refs, generate_pack_data)
556
595
        push_result.new_revid = repo.lookup_foreign_revision_id(
557
 
                new_refs[refname])
 
596
            new_refs[refname])
558
597
        try:
559
598
            old_remote = self._refs[refname]
560
599
        except KeyError:
565
604
        if old_remote != ZERO_SHA:
566
605
            push_result.branch_push_result = GitBranchPushResult()
567
606
            push_result.branch_push_result.source_branch = source
568
 
            push_result.branch_push_result.target_branch = push_result.target_branch
 
607
            push_result.branch_push_result.target_branch = (
 
608
                push_result.target_branch)
569
609
            push_result.branch_push_result.local_branch = None
570
 
            push_result.branch_push_result.master_branch = push_result.target_branch
 
610
            push_result.branch_push_result.master_branch = (
 
611
                push_result.target_branch)
571
612
            push_result.branch_push_result.old_revid = push_result.old_revid
572
613
            push_result.branch_push_result.new_revid = push_result.new_revid
573
 
            push_result.branch_push_result.new_original_revid = push_result.new_original_revid
 
614
            push_result.branch_push_result.new_original_revid = (
 
615
                push_result.new_original_revid)
574
616
        if source.get_push_location() is None or remember:
575
617
            source.set_push_location(push_result.target_branch.base)
576
618
        return push_result
600
642
                def report_progress(cur, total):
601
643
                    pb.update("generating index", cur, total)
602
644
                self.data.create_index(path,
603
 
                    progress=report_progress)
 
645
                                       progress=report_progress)
604
646
            finally:
605
647
                pb.finished()
606
648
        return load_pack_index(path)
618
660
 
619
661
    def __init__(self, transport, *args, **kwargs):
620
662
        self.transport = transport
621
 
        super(BzrGitHttpClient, self).__init__(transport.external_url(), *args, **kwargs)
 
663
        super(BzrGitHttpClient, self).__init__(
 
664
            transport.external_url(), *args, **kwargs)
622
665
 
623
666
    def _http_request(self, url, headers=None, data=None,
624
667
                      allow_compression=False):
673
716
                self.content_type = response.getheader("Content-Type")
674
717
                self.redirect_location = response.geturl()
675
718
 
 
719
            def readlines(self):
 
720
                return self._response.readlines()
 
721
 
676
722
            def close(self):
677
723
                self._response.close()
678
724
 
718
764
        else:
719
765
            raise NotBranchError(transport.base)
720
766
        if not _found:
721
 
            pass # TODO(jelmer): Actually probe for something
 
767
            pass  # TODO(jelmer): Actually probe for something
722
768
        return RemoteGitDir(transport, self, client, client_path)
723
769
 
724
770
    def get_format_description(self):
732
778
            external_url = transport.external_url()
733
779
        except InProcessTransport:
734
780
            raise NotBranchError(path=transport.base)
735
 
        return (external_url.startswith("http:") or
736
 
                external_url.startswith("https:") or
737
 
                external_url.startswith("git+") or
738
 
                external_url.startswith("git:"))
 
781
        return (external_url.startswith("http:")
 
782
                or external_url.startswith("https:")
 
783
                or external_url.startswith("git+")
 
784
                or external_url.startswith("git:"))
739
785
 
740
786
 
741
787
class GitRemoteRevisionTree(RevisionTree):
755
801
        # git-upload-archive(1) generaly only supports refs. So let's see if we
756
802
        # can find one.
757
803
        reverse_refs = {
758
 
                v: k for (k, v) in
759
 
                self._repository.controldir.get_refs_container().as_dict().items()}
 
804
            v: k for (k, v) in
 
805
            self._repository.controldir.get_refs_container().as_dict().items()}
760
806
        try:
761
807
            committish = reverse_refs[commit]
762
808
        except KeyError:
764
810
            # Let's hope for the best.
765
811
            committish = commit
766
812
        self._repository.archive(
767
 
                format, committish, f.write,
768
 
                subdirs=([subdir] if subdir else None),
769
 
                prefix=(root+'/') if root else '')
 
813
            format, committish, f.write,
 
814
            subdirs=([subdir] if subdir else None),
 
815
            prefix=(root + '/') if root else '')
770
816
        f.seek(0)
771
817
        return osutils.file_iterator(f)
772
818
 
 
819
    def is_versioned(self, path, file_id=None):
 
820
        raise GitSmartRemoteNotSupported(self.is_versioned, self)
 
821
 
 
822
    def has_filename(self, path):
 
823
        raise GitSmartRemoteNotSupported(self.has_filename, self)
 
824
 
 
825
    def get_file_text(self, path, file_id=None):
 
826
        raise GitSmartRemoteNotSupported(self.get_file_text, self)
 
827
 
773
828
 
774
829
class RemoteGitRepository(GitRepository):
775
830
 
785
840
 
786
841
    def fetch_pack(self, determine_wants, graph_walker, pack_data,
787
842
                   progress=None):
788
 
        return self.controldir.fetch_pack(determine_wants, graph_walker,
789
 
                                          pack_data, progress)
 
843
        return self.controldir.fetch_pack(
 
844
            determine_wants, graph_walker, pack_data, progress)
790
845
 
791
846
    def send_pack(self, get_changed_refs, generate_pack_data):
792
847
        return self.controldir.send_pack(get_changed_refs, generate_pack_data)
796
851
        fd, path = tempfile.mkstemp(suffix=".pack")
797
852
        try:
798
853
            self.fetch_pack(determine_wants, graph_walker,
799
 
                lambda x: os.write(fd, x), progress)
 
854
                            lambda x: os.write(fd, x), progress)
800
855
        finally:
801
856
            os.close(fd)
802
857
        if os.path.getsize(path) == 0:
804
859
        return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
805
860
 
806
861
    def lookup_bzr_revision_id(self, bzr_revid, mapping=None):
807
 
        # This won't work for any round-tripped bzr revisions, but it's a start..
 
862
        # This won't work for any round-tripped bzr revisions, but it's a
 
863
        # start..
808
864
        try:
809
865
            return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
810
866
        except InvalidRevisionId:
840
896
 
841
897
    def _set_ref(self, name, sha):
842
898
        ref = tag_name_to_ref(name)
 
899
 
843
900
        def get_changed_refs(old_refs):
844
901
            ret = dict(old_refs)
845
902
            if sha == dulwich.client.ZERO_SHA and ref not in ret:
846
903
                raise NoSuchTag(name)
847
904
            ret[ref] = sha
848
905
            return ret
 
906
 
849
907
        def generate_pack_data(have, want, ofs_delta=False):
850
908
            return pack_objects_to_data([])
851
909
        self.repository.send_pack(get_changed_refs, generate_pack_data)
856
914
    def __init__(self, controldir, repository, name):
857
915
        self._sha = None
858
916
        super(RemoteGitBranch, self).__init__(controldir, repository, name,
859
 
                RemoteGitBranchFormat())
 
917
                                              RemoteGitBranchFormat())
860
918
 
861
919
    def last_revision_info(self):
862
920
        raise GitSmartRemoteNotSupported(self.last_revision_info, self)
889
947
 
890
948
    def _synchronize_history(self, destination, revision_id):
891
949
        """See Branch._synchronize_history()."""
892
 
        destination.generate_revision_history(self.last_revision())
 
950
        if revision_id is None:
 
951
            revision_id = self.last_revision()
 
952
        destination.generate_revision_history(revision_id)
893
953
 
894
954
    def _get_parent_location(self):
895
955
        return None
920
980
                raise TypeError(tag_name)
921
981
            yield (ref_name, tag_name, peeled, unpeeled)
922
982
 
 
983
    def set_last_revision_info(self, revno, revid):
 
984
        self.generate_revision_history(revid)
 
985
 
 
986
    def generate_revision_history(self, revision_id, last_rev=None,
 
987
                                  other_branch=None):
 
988
        sha = self.lookup_bzr_revision_id(revision_id)[0]
 
989
        def get_changed_refs(old_refs):
 
990
            return {self.ref: sha}
 
991
        def generate_pack_data(have, want, ofs_delta=False):
 
992
            return pack_objects_to_data([])
 
993
        self.repository.send_pack(get_changed_refs, generate_pack_data)
 
994
        self._sha = sha
 
995
 
923
996
 
924
997
def remote_refs_dict_to_container(refs_dict, symrefs_dict={}):
925
998
    base = {}