/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
0.4.7 by Martin Pool
Start making provision to test using a mock xmlrpc transport.
22
from urlparse import urlsplit, urlunsplit
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
23
import urllib
0.4.4 by Martin Pool
Start forming xmlrpc requests
24
import xmlrpclib
0.4.13 by Martin Pool
Update xmlrpc api to pass product name as a parameter.
25
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
26
from ... import (
2900.2.21 by Vincent Ladeuil
Make lp_registration aware of authentication config.
27
    config,
28
    errors,
4505.6.3 by Jonathan Lange
Don't bother lazy importing.
29
    urlutils,
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
30
    __version__ as _breezy_version,
2900.2.21 by Vincent Ladeuil
Make lp_registration aware of authentication config.
31
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
32
from ...transport.http import _urllib2_wrappers
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
33
4505.6.5 by Jonathan Lange
Factor out some code that guesses a branch's URL.
34
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
35
# for testing, do
36
'''
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
37
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
38
'''
0.4.13 by Martin Pool
Update xmlrpc api to pass product name as a parameter.
39
3193.5.2 by Tim Penhey
Updated the tests to handle unknown launchpad instances.
40
class InvalidLaunchpadInstance(errors.BzrError):
41
42
    _fmt = "%(lp_instance)s is not a valid Launchpad instance."
43
44
    def __init__(self, lp_instance):
45
        errors.BzrError.__init__(self, lp_instance=lp_instance)
46
47
3955.3.5 by Jonathan Lange
Add an untested plugin, make the error handling a little nicer.
48
class NotLaunchpadBranch(errors.BzrError):
49
4031.2.8 by Jonathan Lange
Say "registered on", not "hosted on".
50
    _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.
51
52
    def __init__(self, url):
53
        errors.BzrError.__init__(self, url=url)
54
55
4776.2.6 by Vincent Ladeuil
Fixed as per review comments.
56
class XMLRPCTransport(xmlrpclib.Transport):
4776.2.2 by Vincent Ladeuil
Start testing the XMLRPC transport re-implemented on top of _urllib2_wrappers.
57
4776.3.1 by Vincent Ladeuil
Fix python2.4 compatibility with xmlrpclib.
58
    def __init__(self, scheme):
6238.2.24 by Vincent Ladeuil
Fix the last test failure by providing the test ca certs via the config option framework.
59
        xmlrpclib.Transport.__init__(self)
4776.2.2 by Vincent Ladeuil
Start testing the XMLRPC transport re-implemented on top of _urllib2_wrappers.
60
        self._scheme = scheme
61
        self._opener = _urllib2_wrappers.Opener()
62
        self.verbose = 0
63
64
    def request(self, host, handler, request_body, verbose=0):
65
        self.verbose = verbose
66
        url = self._scheme + "://" + host + handler
67
        request = _urllib2_wrappers.Request("POST", url, request_body)
4776.2.4 by Vincent Ladeuil
Note that User-Agent is lost (we use the bzrlib one though).
68
        # FIXME: _urllib2_wrappers will override user-agent with its own
69
        # 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.
70
        request.add_header("Content-Type", "text/xml")
71
72
        response = self._opener.open(request)
73
        if response.code != 200:
74
            raise xmlrpclib.ProtocolError(host + handler, response.code,
75
                                          response.msg, response.info())
76
        return self.parse_response(response)
77
78
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.
79
class LaunchpadService(object):
0.4.27 by Martin Pool
doc
80
    """A service to talk to Launchpad via XMLRPC.
3193.5.2 by Tim Penhey
Updated the tests to handle unknown launchpad instances.
81
6622.1.33 by Jelmer Vernooij
Fix more tests (all?)
82
    See http://wiki.bazaar.canonical.com/Specs/LaunchpadRpc for the methods we
83
    can call.
0.4.27 by Martin Pool
doc
84
    """
0.4.6 by Martin Pool
Put the rest of the parameters into the registration request.
85
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
86
    LAUNCHPAD_DOMAINS = {
87
        'production': 'launchpad.net',
88
        'staging': 'staging.launchpad.net',
5615.2.1 by Jelmer Vernooij
Support the 'qastaging' instance of Launchpad.
89
        'qastaging': 'qastaging.launchpad.net',
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
90
        'demo': 'demo.launchpad.net',
91
        'dev': 'launchpad.dev',
92
        }
93
3211.1.1 by Ian Clatworthy
Extends the launchpad plugin's implementation of lp spec urls (Tim Penhey)
94
    # 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.
95
    # '/RPC2'
3955.3.2 by Jonathan Lange
Tighten up the code a little, changing the dev service to use https,
96
    LAUNCHPAD_INSTANCE = {}
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
97
    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,
98
        LAUNCHPAD_INSTANCE[instance] = 'https://xmlrpc.%s/bazaar/' % domain
99
4634.165.3 by Vincent Ladeuil
Delete all references to edge.launchpad.net in code and associated tests.
100
    # We use production as the default because edge has been deprecated circa
101
    # 2010-11 (see bug https://bugs.launchpad.net/bzr/+bug/583667)
5243.1.1 by Martin
Use the production server in the launchpad plugin rather than edge
102
    DEFAULT_INSTANCE = 'production'
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
103
    DEFAULT_SERVICE_URL = LAUNCHPAD_INSTANCE[DEFAULT_INSTANCE]
0.4.13 by Martin Pool
Update xmlrpc api to pass product name as a parameter.
104
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.
105
    transport = None
106
    registrant_email = None
107
    registrant_password = None
108
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
109
3193.5.1 by Tim Penhey
Mostly working, just need to update the tests for lp://dev
110
    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.
111
        """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
112
        self._lp_instance = lp_instance
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
113
        if transport is None:
114
            uri_type = urllib.splittype(self.service_url)[0]
4776.2.6 by Vincent Ladeuil
Fixed as per review comments.
115
            transport = XMLRPCTransport(uri_type)
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
116
            transport.user_agent = 'bzr/%s (xmlrpclib/%s)' \
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
117
                    % (_breezy_version, xmlrpclib.__version__)
0.4.29 by Martin Pool
(register-branch) override xmlrpc user-agent; move Transport construction
118
        self.transport = transport
119
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.
120
    @property
121
    def service_url(self):
122
        """Return the http or https url for the xmlrpc server.
123
124
        This does not include the username/password credentials.
125
        """
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
126
        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.
127
        if key in os.environ:
128
            return os.environ[key]
3193.5.1 by Tim Penhey
Mostly working, just need to update the tests for lp://dev
129
        elif self._lp_instance is not None:
3193.5.2 by Tim Penhey
Updated the tests to handle unknown launchpad instances.
130
            try:
131
                return self.LAUNCHPAD_INSTANCE[self._lp_instance]
132
            except KeyError:
133
                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.
134
        else:
135
            return self.DEFAULT_SERVICE_URL
136
4505.6.2 by Jonathan Lange
Extract a method that gets a service from a URL.
137
    @classmethod
138
    def for_url(cls, url, **kwargs):
139
        """Return the Launchpad service corresponding to the given URL."""
140
        result = urlsplit(url)
141
        lp_instance = result[1]
142
        if lp_instance == '':
143
            lp_instance = None
144
        elif lp_instance not in cls.LAUNCHPAD_INSTANCE:
145
            raise errors.InvalidURL(path=url)
146
        return cls(lp_instance=lp_instance, **kwargs)
147
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
148
    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.
149
        """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.
150
        url = self.service_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.
151
        return xmlrpclib.ServerProxy(url, transport=self.transport)
152
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
153
    def send_request(self, method_name, method_params):
154
        proxy = self.get_proxy()
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
155
        method = getattr(proxy, method_name)
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
156
        try:
157
            result = method(*method_params)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
158
        except xmlrpclib.ProtocolError as e:
1668.1.9 by Martin Pool
(launchpad plugin) Better reporting of errors from xmlrpc
159
            if e.errcode == 301:
160
                # TODO: This can give a ProtocolError representing a 301 error, whose
161
                # e.headers['location'] tells where to go and e.errcode==301; should
162
                # probably log something and retry on the new url.
163
                raise NotImplementedError("should resend request to %s, but this isn't implemented"
164
                        % e.headers.get('Location', 'NO-LOCATION-PRESENT'))
165
            else:
166
                # we don't want to print the original message because its
167
                # str representation includes the plaintext password.
168
                # TODO: print more headers to help in tracking down failures
169
                raise errors.BzrError("xmlrpc protocol error connecting to %s: %s %s"
170
                        % (self.service_url, e.errcode, e.errmsg))
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
171
        except socket.gaierror as e:
4505.4.1 by Jonathan Lange
Trap gaierror and reraise appropriate ConnectionError.
172
            raise errors.ConnectionError(
173
                "Could not resolve '%s'" % self.domain,
174
                orig_error=e)
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
175
        return result
176
3955.3.1 by Jonathan Lange
Start doing URL stuff, extracting the domain bit out of LaunchpadService,
177
    @property
178
    def domain(self):
179
        if self._lp_instance is None:
180
            instance = self.DEFAULT_INSTANCE
181
        else:
182
            instance = self._lp_instance
183
        return self.LAUNCHPAD_DOMAINS[instance]
184
4505.6.5 by Jonathan Lange
Factor out some code that guesses a branch's URL.
185
    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,
186
        scheme, hostinfo, path = urlsplit(branch_url)[:3]
3955.3.8 by Jonathan Lange
Support lp URL shortcuts.
187
        if _request_factory is None:
188
            _request_factory = ResolveLaunchpadPathRequest
189
        if scheme == 'lp':
190
            resolve = _request_factory(path)
3955.3.9 by Jonathan Lange
Catch errors.
191
            try:
192
                result = resolve.submit(self)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
193
            except xmlrpclib.Fault as fault:
3955.3.9 by Jonathan Lange
Catch errors.
194
                raise errors.InvalidURL(branch_url, str(fault))
3955.3.8 by Jonathan Lange
Support lp URL shortcuts.
195
            branch_url = result['urls'][0]
196
            path = urlsplit(branch_url)[2]
197
        else:
198
            domains = (
199
                'bazaar.%s' % domain
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
200
                for domain in self.LAUNCHPAD_DOMAINS.values())
3955.3.5 by Jonathan Lange
Add an untested plugin, make the error handling a little nicer.
201
            if hostinfo not in domains:
202
                raise NotLaunchpadBranch(branch_url)
4505.6.5 by Jonathan Lange
Factor out some code that guesses a branch's URL.
203
        return path.lstrip('/')
204
205
    def get_web_url_from_branch_url(self, branch_url, _request_factory=None):
206
        """Get the Launchpad web URL for the given branch URL.
207
208
        :raise errors.InvalidURL: if 'branch_url' cannot be identified as a
209
            Launchpad branch URL.
210
        :return: The URL of the branch on Launchpad.
211
        """
212
        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.
213
        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,
214
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
215
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.
216
class BaseRequest(object):
217
    """Base request for talking to a XMLRPC server."""
218
219
    # Set this to the XMLRPC method name.
220
    _methodname = None
221
222
    def _request_params(self):
223
        """Return the arguments to pass to the method"""
224
        raise NotImplementedError(self._request_params)
225
226
    def submit(self, service):
0.4.21 by Martin Pool
Refactor BaseRequest.submit so details of submission are in the LaunchpadService
227
        """Submit request to Launchpad XMLRPC server.
228
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
229
        :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.
230
        """
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
231
        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.
232
233
1668.1.12 by Martin Pool
(launchpad plugin) Improved --dry-run that uses a dummy xmlrpc service.
234
class DryRunLaunchpadService(LaunchpadService):
6622.7.1 by Colin Watson
Remove `bzr register-branch`, since it has not worked for a long time.
235
    """Service that just absorbs requests without sending to server."""
236
237
    def send_request(self, method_name, method_params):
238
        pass
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
239
240
2898.4.3 by James Henstridge
Make launchpad_transport_indirect() use XMLRPC to resolve the lp: URL.
241
class ResolveLaunchpadPathRequest(BaseRequest):
242
    """Request to resolve the path component of an lp: URL."""
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
243
2898.4.3 by James Henstridge
Make launchpad_transport_indirect() use XMLRPC to resolve the lp: URL.
244
    _methodname = 'resolve_lp_path'
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
245
246
    def __init__(self, path):
3246.4.1 by Daniel Watkins
Replaced problematic assertion with exception call.
247
        if not path:
248
            raise errors.InvalidURL(path=path,
4416.7.1 by Neil Martinsen-Burrell
Fix 238764 refer to projects rather than products in launchpad plugin
249
                                    extra="You must specify a project.")
2898.4.2 by James Henstridge
Add ResolveLaunchpadURLRequest() class to handle lp: URL resolution.
250
        self.path = path
251
252
    def _request_params(self):
253
        """Return xmlrpc request parameters"""
254
        return (self.path,)