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 /bitbake | |
| 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>
Diffstat (limited to 'bitbake')
| -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). |
