~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Martin Pool
  • Date: 2007-07-13 04:22:17 UTC
  • mto: This revision was merged to the branch mainline in revision 2618.
  • Revision ID: mbp@sourcefrog.net-20070713042217-mnkwb9przs8x2de0
Move bencode tests from within their module into our test suite

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2011 Canonical Ltd
 
1
# Copyright (C) 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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
 
"""Directory lookup that uses Launchpad."""
18
 
 
19
 
from __future__ import absolute_import
20
 
 
21
 
from urlparse import urlsplit
22
 
import xmlrpclib
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
 
18
"""Transport indirection that uses Launchpad as a directory lookup.
 
19
 
 
20
When the transport is opened, it immediately redirects to a url
 
21
on Launchpad, which can then either serve the branch itself or redirect
 
22
again.
 
23
"""
23
24
 
24
25
from bzrlib import (
25
 
    debug,
26
26
    errors,
27
 
    trace,
28
 
    transport,
29
 
    )
30
 
from bzrlib.i18n import gettext
31
 
 
32
 
from bzrlib.plugins.launchpad.lp_registration import (
33
 
    LaunchpadService, ResolveLaunchpadPathRequest)
34
 
from bzrlib.plugins.launchpad.account import get_lp_login
35
 
 
36
 
 
37
 
# As bzrlib.transport.remote may not be loaded yet, make sure bzr+ssh
38
 
# is counted as a netloc protocol.
39
 
transport.register_urlparse_netloc_protocol('bzr+ssh')
40
 
transport.register_urlparse_netloc_protocol('lp')
41
 
 
42
 
_ubuntu_series_shortcuts = {
43
 
    'n': 'natty',
44
 
    'm': 'maverick',
45
 
    'l': 'lucid',
46
 
    'k': 'karmic',
47
 
    'j': 'jaunty',
48
 
    'h': 'hardy',
49
 
    'd': 'dapper',
50
 
    }
51
 
 
52
 
 
53
 
class LaunchpadDirectory(object):
54
 
 
55
 
    def _requires_launchpad_login(self, scheme, netloc, path, query,
56
 
                                  fragment):
57
 
        """Does the URL require a Launchpad login in order to be reached?
58
 
 
59
 
        The URL is specified by its parsed components, as returned from
60
 
        urlsplit.
61
 
        """
62
 
        return (scheme in ('bzr+ssh', 'sftp')
63
 
                and (netloc.endswith('launchpad.net')
64
 
                     or netloc.endswith('launchpad.dev')))
65
 
 
66
 
    def look_up(self, name, url):
67
 
        """See DirectoryService.look_up"""
68
 
        return self._resolve(url)
69
 
 
70
 
    def _resolve_locally(self, path, url, _request_factory):
71
 
        # This is the best I could work out about XMLRPC. If an lp: url
72
 
        # includes ~user, then it is specially validated. Otherwise, it is just
73
 
        # sent to +branch/$path.
74
 
        _, netloc, _, _, _ = urlsplit(url)
75
 
        if netloc == '':
76
 
            netloc = LaunchpadService.DEFAULT_INSTANCE
77
 
        base_url = LaunchpadService.LAUNCHPAD_DOMAINS[netloc]
78
 
        base = 'bzr+ssh://bazaar.%s/' % (base_url,)
79
 
        maybe_invalid = False
80
 
        if path.startswith('~'):
81
 
            # A ~user style path, validate it a bit.
82
 
            # If a path looks fishy, fall back to asking XMLRPC to
83
 
            # resolve it for us. That way we still get their nicer error
84
 
            # messages.
85
 
            parts = path.split('/')
86
 
            if (len(parts) < 3
87
 
                or (parts[1] in ('ubuntu', 'debian') and len(parts) < 5)):
88
 
                # This special case requires 5-parts to be valid.
89
 
                maybe_invalid = True
90
 
        else:
91
 
            base += '+branch/'
92
 
        if maybe_invalid:
93
 
            return self._resolve_via_xmlrpc(path, url, _request_factory)
94
 
        return {'urls': [base + path]}
95
 
 
96
 
    def _resolve_via_xmlrpc(self, path, url, _request_factory):
97
 
        service = LaunchpadService.for_url(url)
98
 
        resolve = _request_factory(path)
99
 
        try:
100
 
            result = resolve.submit(service)
101
 
        except xmlrpclib.Fault, fault:
102
 
            raise errors.InvalidURL(
103
 
                path=url, extra=fault.faultString)
104
 
        return result
105
 
 
106
 
    def _update_url_scheme(self, url):
107
 
        # Do ubuntu: and debianlp: expansions.
108
 
        scheme, netloc, path, query, fragment = urlsplit(url)
109
 
        if scheme in ('ubuntu', 'debianlp'):
110
 
            if scheme == 'ubuntu':
111
 
                distro = 'ubuntu'
112
 
                distro_series = _ubuntu_series_shortcuts
113
 
            elif scheme == 'debianlp':
114
 
                distro = 'debian'
115
 
                # No shortcuts for Debian distroseries.
116
 
                distro_series = {}
117
 
            else:
118
 
                raise AssertionError('scheme should be ubuntu: or debianlp:')
119
 
            # Split the path.  It's either going to be 'project' or
120
 
            # 'series/project', but recognize that it may be a series we don't
121
 
            # know about.
122
 
            path_parts = path.split('/')
123
 
            if len(path_parts) == 1:
124
 
                # It's just a project name.
125
 
                lp_url_template = 'lp:%(distro)s/%(project)s'
126
 
                project = path_parts[0]
127
 
                series = None
128
 
            elif len(path_parts) == 2:
129
 
                # It's a series and project.
130
 
                lp_url_template = 'lp:%(distro)s/%(series)s/%(project)s'
131
 
                series, project = path_parts
132
 
            else:
133
 
                # There are either 0 or > 2 path parts, neither of which is
134
 
                # supported for these schemes.
135
 
                raise errors.InvalidURL('Bad path: %s' % url)
136
 
            # Expand any series shortcuts, but keep unknown series.
137
 
            series = distro_series.get(series, series)
138
 
            # Hack the url and let the following do the final resolution.
139
 
            url = lp_url_template % dict(
140
 
                distro=distro,
141
 
                series=series,
142
 
                project=project)
143
 
            scheme, netloc, path, query, fragment = urlsplit(url)
144
 
        return url, path
145
 
 
146
 
    def _expand_user(self, path, url, lp_login):
147
 
        if path.startswith('~/'):
148
 
            if lp_login is None:
149
 
                raise errors.InvalidURL(path=url,
150
 
                    extra='Cannot resolve "~" to your username.'
151
 
                          ' See "bzr help launchpad-login"')
152
 
            path = '~' + lp_login + path[1:]
153
 
        return path
154
 
 
155
 
    def _resolve(self, url,
156
 
                 _request_factory=ResolveLaunchpadPathRequest,
157
 
                 _lp_login=None):
158
 
        """Resolve the base URL for this transport."""
159
 
        url, path = self._update_url_scheme(url)
160
 
        if _lp_login is None:
161
 
            _lp_login = get_lp_login()
162
 
        path = path.strip('/')
163
 
        path = self._expand_user(path, url, _lp_login)
164
 
        if _lp_login is not None:
165
 
            result = self._resolve_locally(path, url, _request_factory)
166
 
            if 'launchpad' in debug.debug_flags:
167
 
                local_res = result
168
 
                result = self._resolve_via_xmlrpc(path, url, _request_factory)
169
 
                trace.note(gettext(
170
 
                    'resolution for {0}\n  local: {1}\n remote: {2}').format(
171
 
                           url, local_res['urls'], result['urls']))
172
 
        else:
173
 
            result = self._resolve_via_xmlrpc(path, url, _request_factory)
174
 
 
175
 
        if 'launchpad' in debug.debug_flags:
176
 
            trace.mutter("resolve_lp_path(%r) == %r", url, result)
177
 
 
178
 
        _warned_login = False
179
 
        for url in result['urls']:
180
 
            scheme, netloc, path, query, fragment = urlsplit(url)
181
 
            if self._requires_launchpad_login(scheme, netloc, path, query,
182
 
                                              fragment):
183
 
                # Only accept launchpad.net bzr+ssh URLs if we know
184
 
                # the user's Launchpad login:
185
 
                if _lp_login is not None:
186
 
                    break
187
 
                if _lp_login is None:
188
 
                    if not _warned_login:
189
 
                        trace.warning(
190
 
'You have not informed bzr of your Launchpad ID, and you must do this to\n'
191
 
'write to Launchpad or access private data.  See "bzr help launchpad-login".')
192
 
                        _warned_login = True
193
 
            else:
194
 
                # Use the URL if we can create a transport for it.
195
 
                try:
196
 
                    transport.get_transport(url)
197
 
                except (errors.PathError, errors.TransportError):
198
 
                    pass
199
 
                else:
200
 
                    break
201
 
        else:
202
 
            raise errors.InvalidURL(path=url, extra='no supported schemes')
203
 
        return url
 
27
    )
 
28
from bzrlib.transport import (
 
29
    get_transport,
 
30
    Transport,
 
31
    )
 
32
 
 
33
 
 
34
def launchpad_transport_indirect(base_url):
 
35
    """Uses Launchpad.net as a directory of open source software"""
 
36
    if base_url.startswith('lp:///'):
 
37
        real_url = 'http://code.launchpad.net/' + base_url[6:]
 
38
    elif base_url.startswith('lp:') and base_url[3] != '/':
 
39
        real_url = 'http://code.launchpad.net/' + base_url[3:]
 
40
    else:
 
41
        raise errors.InvalidURL(path=base_url)
 
42
    return get_transport(real_url)
204
43
 
205
44
 
206
45
def get_test_permutations():