61
73
and (netloc.endswith('launchpad.net')
62
74
or netloc.endswith('launchpad.dev')))
64
def look_up(self, name, url):
65
"""See DirectoryService.look_up"""
66
return self._resolve(url)
68
def _resolve_locally(self, path, url, _request_factory):
69
# This is the best I could work out about XMLRPC. If an lp: url
70
# includes ~user, then it is specially validated. Otherwise, it is just
71
# sent to +branch/$path.
72
_, netloc, _, _, _ = urlsplit(url)
74
netloc = LaunchpadService.DEFAULT_INSTANCE
75
base_url = LaunchpadService.LAUNCHPAD_DOMAINS[netloc]
76
base = 'bzr+ssh://bazaar.%s/' % (base_url,)
78
if path.startswith('~'):
79
# A ~user style path, validate it a bit.
80
# If a path looks fishy, fall back to asking XMLRPC to
81
# resolve it for us. That way we still get their nicer error
83
parts = path.split('/')
85
or (parts[1] in ('ubuntu', 'debian') and len(parts) < 5)):
86
# This special case requires 5-parts to be valid.
91
return self._resolve_via_xmlrpc(path, url, _request_factory)
92
return {'urls': [base + path]}
94
def _resolve_via_xmlrpc(self, path, url, _request_factory):
95
service = LaunchpadService.for_url(url)
76
def _resolve(self, abspath,
77
_request_factory=ResolveLaunchpadPathRequest,
79
"""Resolve the base URL for this transport."""
80
path = urlsplit(abspath)[2].lstrip('/')
81
# Perform an XMLRPC request to resolve the path
96
82
resolve = _request_factory(path)
83
service = LaunchpadService()
98
85
result = resolve.submit(service)
99
86
except xmlrpclib.Fault, fault:
100
87
raise errors.InvalidURL(
101
path=url, extra=fault.faultString)
104
def _update_url_scheme(self, url):
105
# Do ubuntu: and debianlp: expansions.
106
scheme, netloc, path, query, fragment = urlsplit(url)
107
if scheme in ('ubuntu', 'debianlp'):
108
if scheme == 'ubuntu':
110
distro_series = _ubuntu_series_shortcuts
111
elif scheme == 'debianlp':
113
# No shortcuts for Debian distroseries.
116
raise AssertionError('scheme should be ubuntu: or debianlp:')
117
# Split the path. It's either going to be 'project' or
118
# 'series/project', but recognize that it may be a series we don't
120
path_parts = path.split('/')
121
if len(path_parts) == 1:
122
# It's just a project name.
123
lp_url_template = 'lp:%(distro)s/%(project)s'
124
project = path_parts[0]
126
elif len(path_parts) == 2:
127
# It's a series and project.
128
lp_url_template = 'lp:%(distro)s/%(series)s/%(project)s'
129
series, project = path_parts
131
# There are either 0 or > 2 path parts, neither of which is
132
# supported for these schemes.
133
raise errors.InvalidURL('Bad path: %s' % result.path)
134
# Expand any series shortcuts, but keep unknown series.
135
series = distro_series.get(series, series)
136
# Hack the url and let the following do the final resolution.
137
url = lp_url_template % dict(
141
scheme, netloc, path, query, fragment = urlsplit(url)
144
def _expand_user(self, path, url, lp_login):
145
if path.startswith('~/'):
147
raise errors.InvalidURL(path=url,
148
extra='Cannot resolve "~" to your username.'
149
' See "bzr help launchpad-login"')
150
path = '~' + lp_login + path[1:]
153
def _resolve(self, url,
154
_request_factory=ResolveLaunchpadPathRequest,
156
"""Resolve the base URL for this transport."""
157
url, path = self._update_url_scheme(url)
88
path=abspath, extra=fault.faultString)
90
if 'launchpad' in debug.debug_flags:
91
trace.mutter("resolve_lp_path(%r) == %r", path, result)
158
93
if _lp_login is None:
159
94
_lp_login = get_lp_login()
160
path = path.strip('/')
161
path = self._expand_user(path, url, _lp_login)
162
if _lp_login is not None:
163
result = self._resolve_locally(path, url, _request_factory)
164
if 'launchpad' in debug.debug_flags:
166
result = self._resolve_via_xmlrpc(path, url, _request_factory)
167
trace.note('resolution for %s\n local: %s\n remote: %s'
168
% (url, local_res['urls'], result['urls']))
170
result = self._resolve_via_xmlrpc(path, url, _request_factory)
172
if 'launchpad' in debug.debug_flags:
173
trace.mutter("resolve_lp_path(%r) == %r", url, result)
175
_warned_login = False
176
95
for url in result['urls']:
177
96
scheme, netloc, path, query, fragment = urlsplit(url)
178
97
if self._requires_launchpad_login(scheme, netloc, path, query,
180
99
# Only accept launchpad.net bzr+ssh URLs if we know
181
100
# the user's Launchpad login:
182
if _lp_login is not None:
184
101
if _lp_login is None:
185
if not _warned_login:
187
'You have not informed bzr of your Launchpad ID, and you must do this to\n'
188
'write to Launchpad or access private data. See "bzr help launchpad-login".')
103
url = urlunsplit((scheme, '%s@%s' % (_lp_login, netloc),
104
path, query, fragment))
191
107
# Use the URL if we can create a transport for it.
193
transport.get_transport(url)
194
110
except (errors.PathError, errors.TransportError):
199
raise errors.InvalidURL(path=url, extra='no supported schemes')
115
raise errors.InvalidURL(path=abspath,
116
extra='no supported schemes')
119
def _request_redirect(self, relpath):
120
source = urlutils.join(self.base, relpath)
121
# Split the source location into the branch location, and the
122
# extra path components.
123
pos = source.find('/.bzr/')
125
branchpath = source[:pos]
130
target = self._resolve(branchpath) + extra
131
raise errors.RedirectRequested(
135
def get(self, relpath):
136
"""See Transport.get()."""
137
self._request_redirect(relpath)
139
def mkdir(self, relpath, mode=None):
140
"""See Transport.mkdir()."""
141
self._request_redirect(relpath)
203
144
def get_test_permutations():
204
145
# Since this transport doesn't do anything once opened, it's not subjected