/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
1
# Copyright (C) 2006-2017 Canonical Ltd
0.4.4 by Martin Pool
Start forming xmlrpc requests
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
0.4.4 by Martin Pool
Start forming xmlrpc requests
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.4.4 by Martin Pool
Start forming xmlrpc requests
16
6379.6.3 by Jelmer Vernooij
Use absolute_import.
17
from __future__ import absolute_import
18
0.4.4 by Martin Pool
Start forming xmlrpc requests
19
0.4.17 by Martin Pool
Allow xmlrpc service url to be overridden by $BZR_LP_XMLRPC_URL
20
import os
4505.4.1 by Jonathan Lange
Trap gaierror and reraise appropriate ConnectionError.
21
import socket
6791.2.3 by Jelmer Vernooij
Fix more imports.
22
try:
23
    from urllib.parse import urlsplit, urlunsplit
24
except ImportError:
7143.11.1 by Jelmer Vernooij
Remove some unused imports.
25
    from urlparse import urlsplit, urlunsplit  # noqa: F401
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
26
import urllib
6973.12.9 by Jelmer Vernooij
More fixes.
27
try:
28
    from xmlrpc.client import (
29
        __version__ as xmlrpc_version,
30
        Fault,
31
        ProtocolError,
32
        ServerProxy,
33
        Transport,
34
        )
35
except ImportError:  # python < 3
36
    from xmlrpclib import (
37
        __version__ as xmlrpc_version,
38
        Fault,
39
        ProtocolError,
40
        Transport,
41
        ServerProxy,
42
        )
0.4.13 by Martin Pool
Update xmlrpc api to pass product name as a parameter.
43
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
44
from ... import (
2900.2.21 by Vincent Ladeuil
Make lp_registration aware of authentication config.
45
    errors,
4505.6.3 by Jonathan Lange
Don't bother lazy importing.
46
    urlutils,
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
47
    __version__ as _breezy_version,
2900.2.21 by Vincent Ladeuil
Make lp_registration aware of authentication config.
48
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
49
from ...transport.http import _urllib2_wrappers
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
50
7240.5.3 by Jelmer Vernooij
Move LAUNCHPAD_DOMAINS constant.
51
from .lp_api import (
7240.5.7 by Jelmer Vernooij
Move DEFAULT_INSTANCE.
52
    DEFAULT_INSTANCE,
7240.5.3 by Jelmer Vernooij
Move LAUNCHPAD_DOMAINS constant.
53
    LAUNCHPAD_DOMAINS,
54
    LAUNCHPAD_BAZAAR_DOMAINS,
55
    )
56
4505.6.5 by Jonathan Lange
Factor out some code that guesses a branch's URL.
57
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
58
# for testing, do
59
'''
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
60
export BRZ_LP_XMLRPC_URL=http://xmlrpc.staging.launchpad.net/bazaar/
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
61
'''
0.4.13 by Martin Pool
Update xmlrpc api to pass product name as a parameter.
62
6729.6.1 by Jelmer Vernooij
Move urlutils errors.
63
64
class InvalidURL(errors.PathError):
65
66
    _fmt = 'Invalid url supplied to transport: "%(path)s"%(extra)s'
67
68
3193.5.2 by Tim Penhey
Updated the tests to handle unknown launchpad instances.
69
class InvalidLaunchpadInstance(errors.BzrError):
70
71
    _fmt = "%(lp_instance)s is not a valid Launchpad instance."
72
73
    def __init__(self, lp_instance):
74
        errors.BzrError.__init__(self, lp_instance=lp_instance)
75
76
3955.3.5 by Jonathan Lange
Add an untested plugin, make the error handling a little nicer.
77
class NotLaunchpadBranch(errors.BzrError):
78
4031.2.8 by Jonathan Lange
Say "registered on", not "hosted on".
79
    _fmt = "%(url)s is not registered on Launchpad."
3955.3.5 by Jonathan Lange
Add an untested plugin, make the error handling a little nicer.
80
81
    def __init__(self, url):
82
        errors.BzrError.__init__(self, url=url)
83
84
6973.12.9 by Jelmer Vernooij
More fixes.
85
class XMLRPCTransport(Transport):
4776.2.2 by Vincent Ladeuil
Start testing the XMLRPC transport re-implemented on top of _urllib2_wrappers.
86
4776.3.1 by Vincent Ladeuil
Fix python2.4 compatibility with xmlrpclib.
87
    def __init__(self, scheme):
6973.12.9 by Jelmer Vernooij
More fixes.
88
        Transport.__init__(self)
4776.2.2 by Vincent Ladeuil
Start testing the XMLRPC transport re-implemented on top of _urllib2_wrappers.
89
        self._scheme = scheme
90
        self._opener = _urllib2_wrappers.Opener()
91
        self.verbose = 0
92
93
    def request(self, host, handler, request_body, verbose=0):
94
        self.verbose = verbose
95
        url = self._scheme + "://" + host + handler
96
        request = _urllib2_wrappers.Request("POST", url, request_body)
6883.17.1 by Jelmer Vernooij
Only add default HTTP headers if they're not present yet.
97
        request.add_header("User-Agent", self.user_agent)
4776.2.2 by Vincent Ladeuil
Start testing the XMLRPC transport re-implemented on top of _urllib2_wrappers.
98
        request.add_header("Content-Type", "text/xml")
99
100
        response = self._opener.open(request)
101
        if response.code != 200:
6973.12.9 by Jelmer Vernooij
More fixes.
102
            raise ProtocolError(host + handler, response.code,
103
                                response.msg, response.info())
4776.2.2 by Vincent Ladeuil
Start testing the XMLRPC transport re-implemented on top of _urllib2_wrappers.
104
        return self.parse_response(response)
105
106
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
107
class LaunchpadService(object):
0.4.27 by Martin Pool
doc
108
    """A service to talk to Launchpad via XMLRPC.
3193.5.2 by Tim Penhey
Updated the tests to handle unknown launchpad instances.
109
6622.1.33 by Jelmer Vernooij
Fix more tests (all?)
110
    See http://wiki.bazaar.canonical.com/Specs/LaunchpadRpc for the methods we
111
    can call.
0.4.27 by Martin Pool
doc
112
    """
0.4.6 by Martin Pool
Put the rest of the parameters into the registration request.
113
3211.1.1 by Ian Clatworthy
Extends the launchpad plugin's implementation of lp spec urls (Tim Penhey)
114
    # NB: these should always end in a slash to avoid xmlrpclib appending
0.4.7 by Martin Pool
Start making provision to test using a mock xmlrpc transport.
115
    # '/RPC2'
3955.3.2 by Jonathan Lange
Tighten up the code a little, changing the dev service to use https,
116
    LAUNCHPAD_INSTANCE = {}
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
117
    for instance, domain in LAUNCHPAD_DOMAINS.items():
3955.3.2 by Jonathan Lange
Tighten up the code a little, changing the dev service to use https,
118
        LAUNCHPAD_INSTANCE[instance] = 'https://xmlrpc.%s/bazaar/' % domain
119
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
120
    DEFAULT_SERVICE_URL = LAUNCHPAD_INSTANCE[DEFAULT_INSTANCE]
0.4.13 by Martin Pool
Update xmlrpc api to pass product name as a parameter.
121
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
122
    transport = None
123
    registrant_email = None
124
    registrant_password = None
125
3193.5.1 by Tim Penhey
Mostly working, just need to update the tests for lp://dev
126
    def __init__(self, transport=None, lp_instance=None):
0.4.23 by Martin Pool
(register-branch) fix ordering of parameters and restore transport-level test.
127
        """Construct a new service talking to the launchpad rpc server"""
3193.5.1 by Tim Penhey
Mostly working, just need to update the tests for lp://dev
128
        self._lp_instance = lp_instance
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
129
        if transport is None:
6973.12.11 by Jelmer Vernooij
Fix some more tests.
130
            uri_type = urlutils.parse_url(self.service_url)[0]
4776.2.6 by Vincent Ladeuil
Fixed as per review comments.
131
            transport = XMLRPCTransport(uri_type)
6973.12.9 by Jelmer Vernooij
More fixes.
132
            transport.user_agent = 'Breezy/%s (xmlrpc/%s)' \
7143.15.2 by Jelmer Vernooij
Run autopep8.
133
                % (_breezy_version, xmlrpc_version)
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
134
        self.transport = transport
135
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
136
    @property
137
    def service_url(self):
138
        """Return the http or https url for the xmlrpc server.
139
140
        This does not include the username/password credentials.
141
        """
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
142
        key = 'BRZ_LP_XMLRPC_URL'
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
143
        if key in os.environ:
144
            return os.environ[key]
3193.5.1 by Tim Penhey
Mostly working, just need to update the tests for lp://dev
145
        elif self._lp_instance is not None:
3193.5.2 by Tim Penhey
Updated the tests to handle unknown launchpad instances.
146
            try:
147
                return self.LAUNCHPAD_INSTANCE[self._lp_instance]
148
            except KeyError:
149
                raise InvalidLaunchpadInstance(self._lp_instance)
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
150
        else:
151
            return self.DEFAULT_SERVICE_URL
152
4505.6.2 by Jonathan Lange
Extract a method that gets a service from a URL.
153
    @classmethod
154
    def for_url(cls, url, **kwargs):
155
        """Return the Launchpad service corresponding to the given URL."""
156
        result = urlsplit(url)
157
        lp_instance = result[1]
158
        if lp_instance == '':
159
            lp_instance = None
160
        elif lp_instance not in cls.LAUNCHPAD_INSTANCE:
6729.6.1 by Jelmer Vernooij
Move urlutils errors.
161
            raise InvalidURL(url)
4505.6.2 by Jonathan Lange
Extract a method that gets a service from a URL.
162
        return cls(lp_instance=lp_instance, **kwargs)
163
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
164
    def get_proxy(self):
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
165
        """Return the proxy for XMLRPC requests."""
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
166
        url = self.service_url
6973.12.9 by Jelmer Vernooij
More fixes.
167
        return ServerProxy(url, transport=self.transport)
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
168
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
169
    def send_request(self, method_name, method_params):
170
        proxy = self.get_proxy()
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
171
        method = getattr(proxy, method_name)
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
172
        try:
173
            result = method(*method_params)
6973.12.9 by Jelmer Vernooij
More fixes.
174
        except ProtocolError as e:
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
175
            if e.errcode == 301:
176
                # TODO: This can give a ProtocolError representing a 301 error, whose
177
                # e.headers['location'] tells where to go and e.errcode==301; should
178
                # probably log something and retry on the new url.
179
                raise NotImplementedError("should resend request to %s, but this isn't implemented"
7143.15.2 by Jelmer Vernooij
Run autopep8.
180
                                          % e.headers.get('Location', 'NO-LOCATION-PRESENT'))
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
181
            else:
182
                # we don't want to print the original message because its
183
                # str representation includes the plaintext password.
184
                # TODO: print more headers to help in tracking down failures
185
                raise errors.BzrError("xmlrpc protocol error connecting to %s: %s %s"
7143.15.2 by Jelmer Vernooij
Run autopep8.
186
                                      % (self.service_url, e.errcode, e.errmsg))
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
187
        except socket.gaierror as e:
4505.4.1 by Jonathan Lange
Trap gaierror and reraise appropriate ConnectionError.
188
            raise errors.ConnectionError(
189
                "Could not resolve '%s'" % self.domain,
190
                orig_error=e)
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
191
        return result
192
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
193
    @property
194
    def domain(self):
195
        if self._lp_instance is None:
7240.5.7 by Jelmer Vernooij
Move DEFAULT_INSTANCE.
196
            instance = DEFAULT_INSTANCE
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
197
        else:
198
            instance = self._lp_instance
7240.5.3 by Jelmer Vernooij
Move LAUNCHPAD_DOMAINS constant.
199
        return LAUNCHPAD_DOMAINS[instance]
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
200
4505.6.5 by Jonathan Lange
Factor out some code that guesses a branch's URL.
201
    def _guess_branch_path(self, branch_url, _request_factory=None):
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
202
        scheme, hostinfo, path = urlsplit(branch_url)[:3]
3955.3.8 by Jonathan Lange
Support lp URL shortcuts.
203
        if _request_factory is None:
204
            _request_factory = ResolveLaunchpadPathRequest
205
        if scheme == 'lp':
206
            resolve = _request_factory(path)
3955.3.9 by Jonathan Lange
Catch errors.
207
            try:
208
                result = resolve.submit(self)
6973.12.9 by Jelmer Vernooij
More fixes.
209
            except Fault as fault:
6729.6.1 by Jelmer Vernooij
Move urlutils errors.
210
                raise InvalidURL(branch_url, str(fault))
3955.3.8 by Jonathan Lange
Support lp URL shortcuts.
211
            branch_url = result['urls'][0]
212
            path = urlsplit(branch_url)[2]
213
        else:
7240.5.3 by Jelmer Vernooij
Move LAUNCHPAD_DOMAINS constant.
214
            if hostinfo not in LAUNCHPAD_BAZAAR_DOMAINS:
3955.3.5 by Jonathan Lange
Add an untested plugin, make the error handling a little nicer.
215
                raise NotLaunchpadBranch(branch_url)
4505.6.5 by Jonathan Lange
Factor out some code that guesses a branch's URL.
216
        return path.lstrip('/')
217
218
    def get_web_url_from_branch_url(self, branch_url, _request_factory=None):
219
        """Get the Launchpad web URL for the given branch URL.
220
6729.6.1 by Jelmer Vernooij
Move urlutils errors.
221
        :raise InvalidURL: if 'branch_url' cannot be identified as a
4505.6.5 by Jonathan Lange
Factor out some code that guesses a branch's URL.
222
            Launchpad branch URL.
223
        :return: The URL of the branch on Launchpad.
224
        """
225
        path = self._guess_branch_path(branch_url, _request_factory)
3955.3.7 by Jonathan Lange
Test the launchpad-open command. Fix up some minor bugs.
226
        return urlutils.join('https://code.%s' % self.domain, path)
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
227
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
228
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
229
class BaseRequest(object):
230
    """Base request for talking to a XMLRPC server."""
231
232
    # Set this to the XMLRPC method name.
233
    _methodname = None
234
235
    def _request_params(self):
236
        """Return the arguments to pass to the method"""
237
        raise NotImplementedError(self._request_params)
238
239
    def submit(self, service):
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
240
        """Submit request to Launchpad XMLRPC server.
241
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
242
        :param service: LaunchpadService indicating where to send the request.
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
243
        """
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
244
        return service.send_request(self._methodname, self._request_params())
0.4.19 by test at canonical
add possibility to link to a bug when registering a branch. factor out some common functionality from BranchRegistrationRequest.
245
246
1668.1.12 by Martin Pool
(launchpad plugin) Improved --dry-run that uses a dummy xmlrpc service.
247
class DryRunLaunchpadService(LaunchpadService):
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
248
    """Service that just absorbs requests without sending to server."""
249
250
    def send_request(self, method_name, method_params):
251
        pass
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
252
253
2898.4.3 by James Henstridge
Make launchpad_transport_indirect() use XMLRPC to resolve the lp: URL.
254
class ResolveLaunchpadPathRequest(BaseRequest):
255
    """Request to resolve the path component of an lp: URL."""
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
256
2898.4.3 by James Henstridge
Make launchpad_transport_indirect() use XMLRPC to resolve the lp: URL.
257
    _methodname = 'resolve_lp_path'
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
258
259
    def __init__(self, path):
3246.4.1 by Daniel Watkins
Replaced problematic assertion with exception call.
260
        if not path:
6729.6.1 by Jelmer Vernooij
Move urlutils errors.
261
            raise InvalidURL(url=path, extra="You must specify a project.")
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
262
        self.path = path
263
264
    def _request_params(self):
265
        """Return xmlrpc request parameters"""
266
        return (self.path,)