diff options
author | Olof Johansson <olof.johansson@axis.com> | 2013-01-29 08:50:07 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2013-02-17 22:32:04 +0000 |
commit | 7feca4e11e33661076385cdf18f00ea90b1604c1 (patch) | |
tree | 6abf2fe89d47c2fa81def23a3658c785ad38950f | |
parent | 46bd4fd9f0f3e2f30ccff63dd1ba93a43ac3e19c (diff) | |
download | poky-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__.py | 194 |
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 | |||
30 | import os, re | 30 | import os, re |
31 | import logging | 31 | import logging |
32 | import urllib | 32 | import urllib |
33 | from urlparse import urlparse | ||
33 | import operator | 34 | import operator |
34 | import bb.persist_data, bb.utils | 35 | import bb.persist_data, bb.utils |
35 | import bb.checksum | 36 | import 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 | |||
125 | class 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 | |||
123 | def decodeurl(url): | 317 | def 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). |