63
73
and (netloc.endswith('launchpad.net')
64
74
or netloc.endswith('launchpad.dev')))
66
def look_up(self, name, url):
67
"""See DirectoryService.look_up"""
68
return self._resolve(url)
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)
76
netloc = LaunchpadService.DEFAULT_INSTANCE
77
base_url = LaunchpadService.LAUNCHPAD_DOMAINS[netloc]
78
base = 'bzr+ssh://bazaar.%s/' % (base_url,)
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
85
parts = path.split('/')
87
or (parts[1] in ('ubuntu', 'debian') and len(parts) < 5)):
88
# This special case requires 5-parts to be valid.
93
return self._resolve_via_xmlrpc(path, url, _request_factory)
94
return {'urls': [base + path]}
96
def _resolve_via_xmlrpc(self, path, url, _request_factory):
97
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
98
82
resolve = _request_factory(path)
83
service = LaunchpadService()
100
85
result = resolve.submit(service)
101
86
except xmlrpclib.Fault, fault:
102
87
raise errors.InvalidURL(
103
path=url, extra=fault.faultString)
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':
112
distro_series = _ubuntu_series_shortcuts
113
elif scheme == 'debianlp':
115
# No shortcuts for Debian distroseries.
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
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]
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
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(
143
scheme, netloc, path, query, fragment = urlsplit(url)
146
def _expand_user(self, path, url, lp_login):
147
if path.startswith('~/'):
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:]
155
def _resolve(self, url,
156
_request_factory=ResolveLaunchpadPathRequest,
158
"""Resolve the base URL for this transport."""
159
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)
160
93
if _lp_login is None:
161
94
_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:
168
result = self._resolve_via_xmlrpc(path, url, _request_factory)
170
'resolution for {0}\n local: {1}\n remote: {2}').format(
171
url, local_res['urls'], result['urls']))
173
result = self._resolve_via_xmlrpc(path, url, _request_factory)
175
if 'launchpad' in debug.debug_flags:
176
trace.mutter("resolve_lp_path(%r) == %r", url, result)
178
_warned_login = False
179
95
for url in result['urls']:
180
96
scheme, netloc, path, query, fragment = urlsplit(url)
181
97
if self._requires_launchpad_login(scheme, netloc, path, query,
183
99
# Only accept launchpad.net bzr+ssh URLs if we know
184
100
# the user's Launchpad login:
185
if _lp_login is not None:
187
101
if _lp_login is None:
188
if not _warned_login:
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".')
103
url = urlunsplit((scheme, '%s@%s' % (_lp_login, netloc),
104
path, query, fragment))
194
107
# Use the URL if we can create a transport for it.
196
transport.get_transport(url)
197
110
except (errors.PathError, errors.TransportError):
202
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)
206
144
def get_test_permutations():
207
145
# Since this transport doesn't do anything once opened, it's not subjected