summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlof Johansson <olof.johansson@axis.com>2013-01-29 08:50:07 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2013-02-17 22:32:04 +0000
commit7feca4e11e33661076385cdf18f00ea90b1604c1 (patch)
tree6abf2fe89d47c2fa81def23a3658c785ad38950f
parent46bd4fd9f0f3e2f30ccff63dd1ba93a43ac3e19c (diff)
downloadpoky-7feca4e11e33661076385cdf18f00ea90b1604c1.tar.gz
bitbake: fetch2: Add a class representing a generic URI
A class representing a generic URI, with methods for accessing the URI components, and stringifies to the URI. This class should be a bit more flexible than the existing {encode,decode}_url functions in that it supports more components (e.g. port) and that it does not rely on a specific order on the return values. This makes it easy to add new properties without affecting the API. (Bitbake rev: bd824da8a7eafe27310e410807319628378caeca) Signed-off-by: Olof Johansson <olof.johansson@axis.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/bb/fetch2/__init__.py194
1 files changed, 194 insertions, 0 deletions
diff --git a/bitbake/lib/bb/fetch2/__init__.py b/bitbake/lib/bb/fetch2/__init__.py
index 252e2966b4..6969e261b4 100644
--- a/bitbake/lib/bb/fetch2/__init__.py
+++ b/bitbake/lib/bb/fetch2/__init__.py
@@ -30,6 +30,7 @@ from __future__ import print_function
30import os, re 30import os, re
31import logging 31import logging
32import urllib 32import urllib
33from urlparse import urlparse
33import operator 34import operator
34import bb.persist_data, bb.utils 35import bb.persist_data, bb.utils
35import bb.checksum 36import bb.checksum
@@ -120,6 +121,199 @@ class NonLocalMethod(Exception):
120 def __init__(self): 121 def __init__(self):
121 Exception.__init__(self) 122 Exception.__init__(self)
122 123
124
125class URI(object):
126 """
127 A class representing a generic URI, with methods for
128 accessing the URI components, and stringifies to the
129 URI.
130
131 It is constructed by calling it with a URI, or setting
132 the attributes manually:
133
134 uri = URI("http://example.com/")
135
136 uri = URI()
137 uri.scheme = 'http'
138 uri.hostname = 'example.com'
139 uri.path = '/'
140
141 It has the following attributes:
142
143 * scheme (read/write)
144 * userinfo (authentication information) (read/write)
145 * username (read/write)
146 * password (read/write)
147
148 Note, password is deprecated as of RFC 3986.
149
150 * hostname (read/write)
151 * port (read/write)
152 * hostport (read only)
153 "hostname:port", if both are set, otherwise just "hostname"
154 * path (read/write)
155 * path_quoted (read/write)
156 A URI quoted version of path
157 * params (dict) (read/write)
158 * relative (bool) (read only)
159 True if this is a "relative URI", (e.g. file:foo.diff)
160
161 It stringifies to the URI itself.
162
163 Some notes about relative URIs: while it's specified that
164 a URI beginning with <scheme>:// should either be directly
165 followed by a hostname or a /, the old URI handling of the
166 fetch2 library did not comform to this. Therefore, this URI
167 class has some kludges to make sure that URIs are parsed in
168 a way comforming to bitbake's current usage. This URI class
169 supports the following:
170
171 file:relative/path.diff (IETF compliant)
172 git:relative/path.git (IETF compliant)
173 git:///absolute/path.git (IETF compliant)
174 file:///absolute/path.diff (IETF compliant)
175
176 file://relative/path.diff (not IETF compliant)
177
178 But it does not support the following:
179
180 file://hostname/absolute/path.diff (would be IETF compliant)
181
182 Note that the last case only applies to a list of
183 "whitelisted" schemes (currently only file://), that requires
184 its URIs to not have a network location.
185 """
186
187 _relative_schemes = ['file', 'git']
188 _netloc_forbidden = ['file']
189
190 def __init__(self, uri=None):
191 self.scheme = ''
192 self.userinfo = ''
193 self.hostname = ''
194 self.port = None
195 self._path = ''
196 self.params = {}
197 self.relative = False
198
199 if not uri:
200 return
201
202 urlp = urlparse(uri)
203 self.scheme = urlp.scheme
204
205 # Convert URI to be relative
206 if urlp.scheme in self._netloc_forbidden:
207 uri = re.sub("(?<=:)//(?!/)", "", uri, 1)
208 urlp = urlparse(uri)
209
210 # Identify if the URI is relative or not
211 if urlp.scheme in self._relative_schemes and \
212 re.compile("^\w+:(?!//)").match(uri):
213 self.relative = True
214
215 if not self.relative:
216 self.hostname = urlp.hostname or ''
217 self.port = urlp.port
218
219 self.userinfo += urlp.username or ''
220
221 if urlp.password:
222 self.userinfo += ':%s' % urlp.password
223
224 # Do support params even for URI schemes that Python's
225 # urlparse doesn't support params for.
226 path = ''
227 param_str = ''
228 if not urlp.params:
229 path, param_str = (list(urlp.path.split(";", 1)) + [None])[:2]
230 else:
231 path = urlp.path
232 param_str = urlp.params
233
234 self.path = urllib.unquote(path)
235
236 if param_str:
237 self.params = self._param_dict(param_str)
238
239 def __str__(self):
240 userinfo = self.userinfo
241 if userinfo:
242 userinfo += '@'
243
244 return "%s:%s%s%s%s%s" % (
245 self.scheme,
246 '' if self.relative else '//',
247 userinfo,
248 self.hostport,
249 self.path_quoted,
250 self._param_str)
251
252 @property
253 def _param_str(self):
254 ret = ''
255 for key, val in self.params.items():
256 ret += ";%s=%s" % (key, val)
257 return ret
258
259 def _param_dict(self, param_str):
260 parm = {}
261
262 for keyval in param_str.split(";"):
263 key, val = keyval.split("=", 1)
264 parm[key] = val
265
266 return parm
267
268 @property
269 def hostport(self):
270 if not self.port:
271 return self.hostname
272 return "%s:%d" % (self.hostname, self.port)
273
274 @property
275 def path_quoted(self):
276 return urllib.quote(self.path)
277
278 @path_quoted.setter
279 def path_quoted(self, path):
280 self.path = urllib.unquote(path)
281
282 @property
283 def path(self):
284 return self._path
285
286 @path.setter
287 def path(self, path):
288 self._path = path
289
290 if re.compile("^/").match(path):
291 self.relative = False
292 else:
293 self.relative = True
294
295 @property
296 def username(self):
297 if self.userinfo:
298 return (self.userinfo.split(":", 1))[0]
299 return ''
300
301 @username.setter
302 def username(self, username):
303 self.userinfo = username
304 if self.password:
305 self.userinfo += ":%s" % self.password
306
307 @property
308 def password(self):
309 if self.userinfo and ":" in self.userinfo:
310 return (self.userinfo.split(":", 1))[1]
311 return ''
312
313 @password.setter
314 def password(self, password):
315 self.userinfo = "%s:%s" % (self.username, password)
316
123def decodeurl(url): 317def decodeurl(url):
124 """Decodes an URL into the tokens (scheme, network location, path, 318 """Decodes an URL into the tokens (scheme, network location, path,
125 user, password, parameters). 319 user, password, parameters).