/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: 2019-05-20 03:57:29 UTC
  • mto: This revision was merged to the branch mainline in revision 7328.
  • Revision ID: jelmer@jelmer.uk-20190520035729-9rxvefxkvbbivygy
use default_user_agent function.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
from __future__ import absolute_import
20
20
 
21
21
import gzip
22
 
from io import BytesIO
23
22
import re
24
23
 
25
24
from .. import (
48
47
    PermissionDenied,
49
48
    UninitializableFormat,
50
49
    )
51
 
from ..revision import NULL_REVISION
52
50
from ..revisiontree import RevisionTree
53
51
from ..sixish import (
54
52
    text_type,
61
59
 
62
60
from . import (
63
61
    lazy_check_versions,
64
 
    is_github_url,
65
62
    user_agent_for_github,
66
63
    )
67
64
lazy_check_versions()
92
89
    )
93
90
from .repository import (
94
91
    GitRepository,
95
 
    GitRepositoryFormat,
96
92
    )
97
93
from .refs import (
98
94
    branch_name_to_ref,
125
121
 
126
122
try:
127
123
    import urllib.parse as urlparse
128
 
    from urllib.parse import splituser
 
124
    from urllib.parse import splituser, splitnport
129
125
except ImportError:
130
126
    import urlparse
131
 
    from urllib import splituser
 
127
    from urllib import splituser, splitnport
132
128
 
133
129
# urlparse only supports a limited number of schemes by default
134
130
register_urlparse_netloc_protocol('git')
167
163
    :param url: Git URL
168
164
    :return: Tuple with host, port, username, path.
169
165
    """
170
 
    parsed_url = urlparse.urlparse(url)
171
 
    path = urlparse.unquote(parsed_url.path)
 
166
    (scheme, netloc, loc, _, _) = urlparse.urlsplit(url)
 
167
    path = urlparse.unquote(loc)
172
168
    if path.startswith("/~"):
173
169
        path = path[1:]
174
 
    return ((parsed_url.hostname or '', parsed_url.port, parsed_url.username, path))
 
170
    (username, hostport) = splituser(netloc)
 
171
    (host, port) = splitnport(hostport, None)
 
172
    return (host, port, username, path)
175
173
 
176
174
 
177
175
class RemoteGitError(BzrError):
202
200
                message.endswith(' not found.'))):
203
201
        return NotBranchError(url, message)
204
202
    if message == "HEAD failed to update":
205
 
        base_url = urlutils.strip_segment_parameters(url)
 
203
        base_url, _ = urlutils.split_segment_parameters(url)
206
204
        return HeadUpdateFailed(base_url)
207
205
    if message.startswith('access denied or repository not exported:'):
208
 
        extra, path = message.split(':', 1)
209
 
        return PermissionDenied(path.strip(), extra)
 
206
        extra, path = message.split(': ', 1)
 
207
        return PermissionDenied(path, extra)
210
208
    if message.endswith('You are not allowed to push code to this project.'):
211
209
        return PermissionDenied(url, message)
212
210
    if message.endswith(' does not appear to be a git repository'):
213
211
        return NotBranchError(url, message)
214
 
    if re.match('(.+) is not a valid repository name',
215
 
                message.splitlines()[0]):
216
 
        return NotBranchError(url, message)
217
212
    m = re.match(r'Permission to ([^ ]+) denied to ([^ ]+)\.', message)
218
213
    if m:
219
214
        return PermissionDenied(m.group(1), 'denied to %s' % m.group(2))
453
448
        else:
454
449
            pb = None
455
450
 
456
 
        def get_changed_refs_wrapper(remote_refs):
457
 
            if self._refs is not None:
458
 
                update_refs_container(self._refs, remote_refs)
459
 
            return get_changed_refs(remote_refs)
 
451
        def get_changed_refs_wrapper(refs):
 
452
            # TODO(jelmer): This drops symref information
 
453
            self._refs = remote_refs_dict_to_container(refs)
 
454
            return get_changed_refs(refs)
460
455
        try:
461
456
            return self._client.send_pack(
462
457
                self._client_path, get_changed_refs_wrapper,
472
467
        refname = self._get_selected_ref(name, ref)
473
468
        if refname != b'HEAD' and refname in self.get_refs_container():
474
469
            raise AlreadyBranchError(self.user_url)
475
 
        ref_chain, unused_sha = self.get_refs_container().follow(
476
 
            self._get_selected_ref(name))
477
 
        if ref_chain and ref_chain[0] == b'HEAD':
478
 
            refname = ref_chain[1]
 
470
        if refname in self.get_refs_container():
 
471
            ref_chain, unused_sha = self.get_refs_container().follow(
 
472
                self._get_selected_ref(None))
 
473
            if ref_chain[0] == b'HEAD':
 
474
                refname = ref_chain[1]
479
475
        repo = self.open_repository()
480
476
        return RemoteGitBranch(self, repo, refname)
481
477
 
555
551
 
556
552
    def push_branch(self, source, revision_id=None, overwrite=False,
557
553
                    remember=False, create_prefix=False, lossy=False,
558
 
                    name=None, tag_selector=None):
 
554
                    name=None):
559
555
        """Push the source branch into this ControlDir."""
560
556
        if revision_id is None:
561
557
            # No revision supplied by the user, default to the branch
570
566
        push_result.branch_push_result = None
571
567
        repo = self.find_repository()
572
568
        refname = self._get_selected_ref(name)
573
 
        ref_chain, old_sha = self.get_refs_container().follow(refname)
574
 
        if ref_chain:
575
 
            actual_refname = ref_chain[-1]
576
 
        else:
577
 
            actual_refname = refname
578
569
        if isinstance(source, GitBranch) and lossy:
579
570
            raise errors.LossyPushToSameVCS(source.controldir, self)
580
571
        source_store = get_object_store(source.repository)
581
572
        fetch_tags = source.get_config_stack().get('branch.fetch_tags')
582
 
        def get_changed_refs(remote_refs):
583
 
            if self._refs is not None:
584
 
                update_refs_container(self._refs, remote_refs)
 
573
        def get_changed_refs(refs):
 
574
            self._refs = remote_refs_dict_to_container(refs)
585
575
            ret = {}
586
576
            # TODO(jelmer): Unpeel if necessary
587
577
            push_result.new_original_revid = revision_id
594
584
                    raise errors.NoRoundtrippingSupport(
595
585
                        source, self.open_branch(name=name, nascent_ok=True))
596
586
            if not overwrite:
597
 
                if remote_divergence(old_sha, new_sha, source_store):
 
587
                if remote_divergence(ret.get(refname), new_sha,
 
588
                                     source_store):
598
589
                    raise DivergedBranches(
599
590
                        source, self.open_branch(name, nascent_ok=True))
600
 
            ret[actual_refname] = new_sha
 
591
            ret[refname] = new_sha
601
592
            if fetch_tags:
602
593
                for tagname, revid in viewitems(source.tags.get_tag_dict()):
603
 
                    if tag_selector and not tag_selector(tagname):
604
 
                        continue
605
594
                    if lossy:
606
 
                        try:
607
 
                            new_sha = source_store._lookup_revision_sha1(revid)
608
 
                        except KeyError:
609
 
                            if source.repository.has_revision(revid):
610
 
                                raise
 
595
                        new_sha = source_store._lookup_revision_sha1(revid)
611
596
                    else:
612
597
                        try:
613
598
                            new_sha = repo.lookup_bzr_revision_id(revid)[0]
622
607
                generate_pack_data = source_store.generate_pack_data
623
608
            new_refs = self.send_pack(get_changed_refs, generate_pack_data)
624
609
        push_result.new_revid = repo.lookup_foreign_revision_id(
625
 
            new_refs[actual_refname])
626
 
        if old_sha is not None:
627
 
            push_result.old_revid = repo.lookup_foreign_revision_id(old_sha)
628
 
        else:
629
 
            push_result.old_revid = NULL_REVISION
630
 
        if self._refs is not None:
631
 
            update_refs_container(self._refs, new_refs)
 
610
            new_refs[refname])
 
611
        try:
 
612
            old_remote = self._refs[refname]
 
613
        except KeyError:
 
614
            old_remote = ZERO_SHA
 
615
        push_result.old_revid = repo.lookup_foreign_revision_id(old_remote)
 
616
        self._refs = remote_refs_dict_to_container(new_refs)
632
617
        push_result.target_branch = self.open_branch(name)
633
 
        if old_sha is not None:
 
618
        if old_remote != ZERO_SHA:
634
619
            push_result.branch_push_result = GitBranchPushResult()
635
620
            push_result.branch_push_result.source_branch = source
636
621
            push_result.branch_push_result.target_branch = (
666
651
 
667
652
    def _idx_load_or_generate(self, path):
668
653
        if not os.path.exists(path):
669
 
            with ui.ui_factory.nested_progress_bar() as pb:
 
654
            pb = ui.ui_factory.nested_progress_bar()
 
655
            try:
670
656
                def report_progress(cur, total):
671
657
                    pb.update("generating index", cur, total)
672
 
                self.data.create_index(path, progress=report_progress)
 
658
                self.data.create_index(path,
 
659
                                       progress=report_progress)
 
660
            finally:
 
661
                pb.finished()
673
662
        return load_pack_index(path)
674
663
 
675
664
    def __del__(self):
688
677
        url = urlutils.URL.from_string(transport.external_url())
689
678
        url.user = url.quoted_user = None
690
679
        url.password = url.quoted_password = None
691
 
        url = urlutils.strip_segment_parameters(str(url))
692
 
        super(BzrGitHttpClient, self).__init__(url, *args, **kwargs)
 
680
        super(BzrGitHttpClient, self).__init__(str(url), *args, **kwargs)
693
681
 
694
682
    def _http_request(self, url, headers=None, data=None,
695
683
                      allow_compression=False):
704
692
            `redirect_location` properties, and `read` is a consumable read
705
693
            method for the response data.
706
694
        """
707
 
        if is_github_url(url):
708
 
            headers['User-agent'] = user_agent_for_github()
 
695
        headers['User-agent'] = user_agent_for_github()
709
696
        headers["Pragma"] = "no-cache"
710
697
        if allow_compression:
711
698
            headers["Accept-Encoding"] = "gzip"
714
701
 
715
702
        response = self.transport.request(
716
703
            ('GET' if data is None else 'POST'),
717
 
            url,
718
704
            body=data,
719
705
            headers=headers, retries=8)
720
706
 
722
708
            raise NotGitRepository()
723
709
        elif response.status != 200:
724
710
            raise GitProtocolError("unexpected http resp %d for %s" %
725
 
                                   (response.status, url))
 
711
                                   (response.code, url))
726
712
 
727
713
        # TODO: Optimization available by adding `preload_content=False` to the
728
714
        # request and just passing the `read` method on instead of going via
730
716
        # before issuing the next to still allow for connection reuse from the
731
717
        # pool.
732
718
        if response.getheader("Content-Encoding") == "gzip":
733
 
            read = gzip.GzipFile(fileobj=BytesIO(response.read())).read
 
719
            read = gzip.GzipFile(fileobj=response).read
734
720
        else:
735
721
            read = response.read
736
722
 
738
724
 
739
725
            def __init__(self, response):
740
726
                self._response = response
741
 
                self.status = response.status
 
727
                self.status = response.code
742
728
                self.content_type = response.getheader("Content-Type")
743
 
                self.redirect_location = response._actual.geturl()
 
729
                self.redirect_location = response.geturl()
744
730
 
745
731
            def readlines(self):
746
732
                return self._response.readlines()
747
733
 
748
734
            def close(self):
749
 
                pass
 
735
                self._response.close()
750
736
 
751
737
        return WrapResponse(response), read
752
738
 
753
739
 
754
 
def _git_url_and_path_from_transport(external_url):
755
 
    url = urlutils.strip_segment_parameters(external_url)
756
 
    return urlparse.urlsplit(url)
757
 
 
758
 
 
759
740
class RemoteGitControlDirFormat(GitControlDirFormat):
760
741
    """The .git directory control format."""
761
742
 
768
749
    def get_branch_format(self):
769
750
        return RemoteGitBranchFormat()
770
751
 
771
 
    @property
772
 
    def repository_format(self):
773
 
        return GitRepositoryFormat()
774
 
 
775
752
    def is_initializable(self):
776
753
        return False
777
754
 
782
759
        """Open this directory.
783
760
 
784
761
        """
785
 
        split_url = _git_url_and_path_from_transport(transport.external_url())
 
762
        # we dont grok readonly - git isn't integrated with transport.
 
763
        url = transport.base
 
764
        if url.startswith('readonly+'):
 
765
            url = url[len('readonly+'):]
 
766
        scheme = urlparse.urlsplit(transport.external_url())[0]
786
767
        if isinstance(transport, GitSmartTransport):
787
768
            client = transport._get_client()
788
 
        elif split_url.scheme in ("http", "https"):
 
769
            client_path = transport._get_path()
 
770
        elif scheme in ("http", "https"):
789
771
            client = BzrGitHttpClient(transport)
790
 
        elif split_url.scheme in ('file', ):
 
772
            client_path, _ = urlutils.split_segment_parameters(transport._path)
 
773
        elif scheme == 'file':
791
774
            client = dulwich.client.LocalGitClient()
 
775
            client_path = transport.local_abspath('.')
792
776
        else:
793
777
            raise NotBranchError(transport.base)
794
778
        if not _found:
795
779
            pass  # TODO(jelmer): Actually probe for something
796
 
        return RemoteGitDir(transport, self, client, split_url.path)
 
780
        return RemoteGitDir(transport, self, client, client_path)
797
781
 
798
782
    def get_format_description(self):
799
783
        return "Remote Git Repository"
853
837
    def get_file_text(self, path):
854
838
        raise GitSmartRemoteNotSupported(self.get_file_text, self)
855
839
 
856
 
    def list_files(self, include_root=False, from_dir=None, recursive=True):
857
 
        raise GitSmartRemoteNotSupported(self.list_files, self)
858
 
 
859
840
 
860
841
class RemoteGitRepository(GitRepository):
861
842
 
1040
1021
    ret = DictRefsContainer(base)
1041
1022
    ret._peeled = peeled
1042
1023
    return ret
1043
 
 
1044
 
 
1045
 
def update_refs_container(container, refs_dict):
1046
 
    peeled = {}
1047
 
    base = {}
1048
 
    for k, v in refs_dict.items():
1049
 
        if is_peeled(k):
1050
 
            peeled[k[:-3]] = v
1051
 
        else:
1052
 
            base[k] = v
1053
 
    container._peeled = peeled
1054
 
    container._refs.update(base)