~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/plugins/launchpad/lp_registration.py

  • Committer: Ian Clatworthy
  • Date: 2007-12-07 04:21:59 UTC
  • mto: This revision was merged to the branch mainline in revision 3092.
  • Revision ID: ian.clatworthy@internode.on.net-20071207042159-n9rmhanqid1l7olh
Better PDF for Qiock Start Card (Ian Clatworthy)

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
 
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
 
18
from getpass import getpass
18
19
import os
19
 
import socket
20
20
from urlparse import urlsplit, urlunsplit
21
21
import urllib
22
22
import xmlrpclib
23
23
 
24
 
from bzrlib.lazy_import import lazy_import
25
 
lazy_import(globals(), """
26
 
from bzrlib import urlutils
27
 
""")
28
 
 
29
24
from bzrlib import (
30
25
    config,
31
26
    errors,
37
32
export BZR_LP_XMLRPC_URL=http://xmlrpc.staging.launchpad.net/bazaar/
38
33
'''
39
34
 
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
 
 
48
 
class NotLaunchpadBranch(errors.BzrError):
49
 
 
50
 
    _fmt = "%(url)s is not registered on Launchpad."
51
 
 
52
 
    def __init__(self, url):
53
 
        errors.BzrError.__init__(self, url=url)
54
 
 
55
 
 
56
35
class LaunchpadService(object):
57
36
    """A service to talk to Launchpad via XMLRPC.
58
 
 
 
37
    
59
38
    See http://bazaar-vcs.org/Specs/LaunchpadRpc for the methods we can call.
60
39
    """
61
40
 
62
 
    LAUNCHPAD_DOMAINS = {
63
 
        'production': 'launchpad.net',
64
 
        'edge': 'edge.launchpad.net',
65
 
        'staging': 'staging.launchpad.net',
66
 
        'demo': 'demo.launchpad.net',
67
 
        'dev': 'launchpad.dev',
68
 
        }
69
 
 
70
 
    # NB: these should always end in a slash to avoid xmlrpclib appending
 
41
    # NB: this should always end in a slash to avoid xmlrpclib appending
71
42
    # '/RPC2'
72
 
    LAUNCHPAD_INSTANCE = {}
73
 
    for instance, domain in LAUNCHPAD_DOMAINS.iteritems():
74
 
        LAUNCHPAD_INSTANCE[instance] = 'https://xmlrpc.%s/bazaar/' % domain
75
 
 
76
 
    # We use edge as the default because:
77
 
    # Beta users get redirected to it
78
 
    # All users can use it
79
 
    # There is a bug in the launchpad side where redirection causes an OOPS.
80
 
    DEFAULT_INSTANCE = 'edge'
81
 
    DEFAULT_SERVICE_URL = LAUNCHPAD_INSTANCE[DEFAULT_INSTANCE]
 
43
    DEFAULT_SERVICE_URL = 'https://xmlrpc.launchpad.net/bazaar/'
82
44
 
83
45
    transport = None
84
46
    registrant_email = None
85
47
    registrant_password = None
86
48
 
87
49
 
88
 
    def __init__(self, transport=None, lp_instance=None):
 
50
    def __init__(self, transport=None):
89
51
        """Construct a new service talking to the launchpad rpc server"""
90
 
        self._lp_instance = lp_instance
91
52
        if transport is None:
92
53
            uri_type = urllib.splittype(self.service_url)[0]
93
54
            if uri_type == 'https':
108
69
        key = 'BZR_LP_XMLRPC_URL'
109
70
        if key in os.environ:
110
71
            return os.environ[key]
111
 
        elif self._lp_instance is not None:
112
 
            try:
113
 
                return self.LAUNCHPAD_INSTANCE[self._lp_instance]
114
 
            except KeyError:
115
 
                raise InvalidLaunchpadInstance(self._lp_instance)
116
72
        else:
117
73
            return self.DEFAULT_SERVICE_URL
118
74
 
123
79
            # TODO: if there's no registrant email perhaps we should
124
80
            # just connect anonymously?
125
81
            scheme, hostinfo, path = urlsplit(self.service_url)[:3]
126
 
            if '@' in hostinfo:
127
 
                raise AssertionError(hostinfo)
128
 
            if self.registrant_email is None:
129
 
                raise AssertionError()
130
 
            if self.registrant_password is None:
131
 
                raise AssertionError()
 
82
            assert '@' not in hostinfo
 
83
            assert self.registrant_email is not None
 
84
            assert self.registrant_password is not None
132
85
            # TODO: perhaps fully quote the password to make it very slightly
133
86
            # obscured
134
87
            # TODO: can we perhaps add extra Authorization headers
161
114
 
162
115
    def send_request(self, method_name, method_params, authenticated):
163
116
        proxy = self.get_proxy(authenticated)
 
117
        assert method_name
164
118
        method = getattr(proxy, method_name)
165
119
        try:
166
120
            result = method(*method_params)
177
131
                # TODO: print more headers to help in tracking down failures
178
132
                raise errors.BzrError("xmlrpc protocol error connecting to %s: %s %s"
179
133
                        % (self.service_url, e.errcode, e.errmsg))
180
 
        except socket.gaierror, e:
181
 
            raise errors.ConnectionError(
182
 
                "Could not resolve '%s'" % self.domain,
183
 
                orig_error=e)
184
134
        return result
185
135
 
186
 
    @property
187
 
    def domain(self):
188
 
        if self._lp_instance is None:
189
 
            instance = self.DEFAULT_INSTANCE
190
 
        else:
191
 
            instance = self._lp_instance
192
 
        return self.LAUNCHPAD_DOMAINS[instance]
193
 
 
194
 
    def get_web_url_from_branch_url(self, branch_url, _request_factory=None):
195
 
        """Get the Launchpad web URL for the given branch URL.
196
 
 
197
 
        :raise errors.InvalidURL: if 'branch_url' cannot be identified as a
198
 
            Launchpad branch URL.
199
 
        :return: The URL of the branch on Launchpad.
200
 
        """
201
 
        scheme, hostinfo, path = urlsplit(branch_url)[:3]
202
 
        if _request_factory is None:
203
 
            _request_factory = ResolveLaunchpadPathRequest
204
 
        if scheme == 'lp':
205
 
            resolve = _request_factory(path)
206
 
            try:
207
 
                result = resolve.submit(self)
208
 
            except xmlrpclib.Fault, fault:
209
 
                raise errors.InvalidURL(branch_url, str(fault))
210
 
            branch_url = result['urls'][0]
211
 
            path = urlsplit(branch_url)[2]
212
 
        else:
213
 
            domains = (
214
 
                'bazaar.%s' % domain
215
 
                for domain in self.LAUNCHPAD_DOMAINS.itervalues())
216
 
            if hostinfo not in domains:
217
 
                raise NotLaunchpadBranch(branch_url)
218
 
        return urlutils.join('https://code.%s' % self.domain, path)
219
 
 
220
136
 
221
137
class BaseRequest(object):
222
138
    """Base request for talking to a XMLRPC server."""
241
157
 
242
158
class DryRunLaunchpadService(LaunchpadService):
243
159
    """Service that just absorbs requests without sending to server.
244
 
 
 
160
    
245
161
    The dummy service does not need authentication.
246
162
    """
247
163
 
264
180
                 author_email='',
265
181
                 product_name='',
266
182
                 ):
267
 
        if not branch_url:
268
 
            raise errors.InvalidURL(branch_url, "You need to specify a non-empty branch URL.")
 
183
        assert branch_url
269
184
        self.branch_url = branch_url
270
185
        if branch_name:
271
186
            self.branch_name = branch_name
299
214
    _methodname = 'link_branch_to_bug'
300
215
 
301
216
    def __init__(self, branch_url, bug_id):
 
217
        assert branch_url
302
218
        self.bug_id = bug_id
303
219
        self.branch_url = branch_url
304
220
 
316
232
    _authenticated = False
317
233
 
318
234
    def __init__(self, path):
319
 
        if not path:
320
 
            raise errors.InvalidURL(path=path,
321
 
                                    extra="You must specify a project.")
 
235
        assert path
322
236
        self.path = path
323
237
 
324
238
    def _request_params(self):