blob: 72d6092deb3c9e0c37f8388366a47c58bab110e9 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3"""
4BitBake 'Fetch' implementations
5
6Classes for obtaining upstream sources for the
7BitBake build tools.
8"""
9
10# Copyright (C) 2003, 2004 Chris Larson
11# Copyright (C) 2012 Intel Corporation
12#
13# This program is free software; you can redistribute it and/or modify
14# it under the terms of the GNU General Public License version 2 as
15# published by the Free Software Foundation.
16#
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License along
23# with this program; if not, write to the Free Software Foundation, Inc.,
24# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25#
26# Based on functions from the base bb module, Copyright 2003 Holger Schurig
27
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028import os, re
29import signal
Patrick Williamsc124f4f2015-09-15 14:41:29 -050030import logging
Patrick Williamsc0f7c042017-02-23 20:41:17 -060031import urllib.request, urllib.parse, urllib.error
32if 'git' not in urllib.parse.uses_netloc:
33 urllib.parse.uses_netloc.append('git')
34import operator
35import collections
36import subprocess
37import pickle
Brad Bishop6e60e8b2018-02-01 10:27:11 -050038import errno
Patrick Williamsc124f4f2015-09-15 14:41:29 -050039import bb.persist_data, bb.utils
40import bb.checksum
Patrick Williamsc124f4f2015-09-15 14:41:29 -050041import bb.process
Brad Bishopd7bf8c12018-02-25 22:55:05 -050042import bb.event
Patrick Williamsc124f4f2015-09-15 14:41:29 -050043
44__version__ = "2"
45_checksum_cache = bb.checksum.FileChecksumCache()
46
47logger = logging.getLogger("BitBake.Fetcher")
48
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049class BBFetchException(Exception):
50 """Class all fetch exceptions inherit from"""
51 def __init__(self, message):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050052 self.msg = message
53 Exception.__init__(self, message)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050054
55 def __str__(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050056 return self.msg
Patrick Williamsc124f4f2015-09-15 14:41:29 -050057
58class UntrustedUrl(BBFetchException):
59 """Exception raised when encountering a host not listed in BB_ALLOWED_NETWORKS"""
60 def __init__(self, url, message=''):
61 if message:
62 msg = message
63 else:
64 msg = "The URL: '%s' is not trusted and cannot be used" % url
65 self.url = url
66 BBFetchException.__init__(self, msg)
67 self.args = (url,)
68
69class MalformedUrl(BBFetchException):
70 """Exception raised when encountering an invalid url"""
71 def __init__(self, url, message=''):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050072 if message:
73 msg = message
74 else:
75 msg = "The URL: '%s' is invalid and cannot be interpreted" % url
76 self.url = url
77 BBFetchException.__init__(self, msg)
78 self.args = (url,)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050079
80class FetchError(BBFetchException):
81 """General fetcher exception when something happens incorrectly"""
82 def __init__(self, message, url = None):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050083 if url:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050084 msg = "Fetcher failure for URL: '%s'. %s" % (url, message)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050085 else:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050086 msg = "Fetcher failure: %s" % message
Brad Bishopd7bf8c12018-02-25 22:55:05 -050087 self.url = url
88 BBFetchException.__init__(self, msg)
89 self.args = (message, url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050090
91class ChecksumError(FetchError):
92 """Exception when mismatched checksum encountered"""
93 def __init__(self, message, url = None, checksum = None):
94 self.checksum = checksum
95 FetchError.__init__(self, message, url)
96
97class NoChecksumError(FetchError):
98 """Exception when no checksum is specified, but BB_STRICT_CHECKSUM is set"""
99
100class UnpackError(BBFetchException):
101 """General fetcher exception when something happens incorrectly when unpacking"""
102 def __init__(self, message, url):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500103 msg = "Unpack failure for URL: '%s'. %s" % (url, message)
104 self.url = url
105 BBFetchException.__init__(self, msg)
106 self.args = (message, url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500107
108class NoMethodError(BBFetchException):
109 """Exception raised when there is no method to obtain a supplied url or set of urls"""
110 def __init__(self, url):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500111 msg = "Could not find a fetcher which supports the URL: '%s'" % url
112 self.url = url
113 BBFetchException.__init__(self, msg)
114 self.args = (url,)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500115
116class MissingParameterError(BBFetchException):
117 """Exception raised when a fetch method is missing a critical parameter in the url"""
118 def __init__(self, missing, url):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500119 msg = "URL: '%s' is missing the required parameter '%s'" % (url, missing)
120 self.url = url
121 self.missing = missing
122 BBFetchException.__init__(self, msg)
123 self.args = (missing, url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500124
125class ParameterError(BBFetchException):
126 """Exception raised when a url cannot be proccessed due to invalid parameters."""
127 def __init__(self, message, url):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500128 msg = "URL: '%s' has invalid parameters. %s" % (url, message)
129 self.url = url
130 BBFetchException.__init__(self, msg)
131 self.args = (message, url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132
133class NetworkAccess(BBFetchException):
134 """Exception raised when network access is disabled but it is required."""
135 def __init__(self, url, cmd):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500136 msg = "Network access disabled through BB_NO_NETWORK (or set indirectly due to use of BB_FETCH_PREMIRRORONLY) but access requested with command %s (for url %s)" % (cmd, url)
137 self.url = url
138 self.cmd = cmd
139 BBFetchException.__init__(self, msg)
140 self.args = (url, cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500141
142class NonLocalMethod(Exception):
143 def __init__(self):
144 Exception.__init__(self)
145
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500146class MissingChecksumEvent(bb.event.Event):
147 def __init__(self, url, md5sum, sha256sum):
148 self.url = url
149 self.checksums = {'md5sum': md5sum,
150 'sha256sum': sha256sum}
151 bb.event.Event.__init__(self)
152
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500153
154class URI(object):
155 """
156 A class representing a generic URI, with methods for
157 accessing the URI components, and stringifies to the
158 URI.
159
160 It is constructed by calling it with a URI, or setting
161 the attributes manually:
162
163 uri = URI("http://example.com/")
164
165 uri = URI()
166 uri.scheme = 'http'
167 uri.hostname = 'example.com'
168 uri.path = '/'
169
170 It has the following attributes:
171
172 * scheme (read/write)
173 * userinfo (authentication information) (read/write)
174 * username (read/write)
175 * password (read/write)
176
177 Note, password is deprecated as of RFC 3986.
178
179 * hostname (read/write)
180 * port (read/write)
181 * hostport (read only)
182 "hostname:port", if both are set, otherwise just "hostname"
183 * path (read/write)
184 * path_quoted (read/write)
185 A URI quoted version of path
186 * params (dict) (read/write)
187 * query (dict) (read/write)
188 * relative (bool) (read only)
189 True if this is a "relative URI", (e.g. file:foo.diff)
190
191 It stringifies to the URI itself.
192
193 Some notes about relative URIs: while it's specified that
194 a URI beginning with <scheme>:// should either be directly
195 followed by a hostname or a /, the old URI handling of the
196 fetch2 library did not comform to this. Therefore, this URI
197 class has some kludges to make sure that URIs are parsed in
198 a way comforming to bitbake's current usage. This URI class
199 supports the following:
200
201 file:relative/path.diff (IETF compliant)
202 git:relative/path.git (IETF compliant)
203 git:///absolute/path.git (IETF compliant)
204 file:///absolute/path.diff (IETF compliant)
205
206 file://relative/path.diff (not IETF compliant)
207
208 But it does not support the following:
209
210 file://hostname/absolute/path.diff (would be IETF compliant)
211
212 Note that the last case only applies to a list of
213 "whitelisted" schemes (currently only file://), that requires
214 its URIs to not have a network location.
215 """
216
217 _relative_schemes = ['file', 'git']
218 _netloc_forbidden = ['file']
219
220 def __init__(self, uri=None):
221 self.scheme = ''
222 self.userinfo = ''
223 self.hostname = ''
224 self.port = None
225 self._path = ''
226 self.params = {}
227 self.query = {}
228 self.relative = False
229
230 if not uri:
231 return
232
233 # We hijack the URL parameters, since the way bitbake uses
234 # them are not quite RFC compliant.
235 uri, param_str = (uri.split(";", 1) + [None])[:2]
236
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600237 urlp = urllib.parse.urlparse(uri)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500238 self.scheme = urlp.scheme
239
240 reparse = 0
241
242 # Coerce urlparse to make URI scheme use netloc
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600243 if not self.scheme in urllib.parse.uses_netloc:
244 urllib.parse.uses_params.append(self.scheme)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500245 reparse = 1
246
247 # Make urlparse happy(/ier) by converting local resources
248 # to RFC compliant URL format. E.g.:
249 # file://foo.diff -> file:foo.diff
250 if urlp.scheme in self._netloc_forbidden:
251 uri = re.sub("(?<=:)//(?!/)", "", uri, 1)
252 reparse = 1
253
254 if reparse:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600255 urlp = urllib.parse.urlparse(uri)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500256
257 # Identify if the URI is relative or not
258 if urlp.scheme in self._relative_schemes and \
259 re.compile("^\w+:(?!//)").match(uri):
260 self.relative = True
261
262 if not self.relative:
263 self.hostname = urlp.hostname or ''
264 self.port = urlp.port
265
266 self.userinfo += urlp.username or ''
267
268 if urlp.password:
269 self.userinfo += ':%s' % urlp.password
270
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600271 self.path = urllib.parse.unquote(urlp.path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500272
273 if param_str:
274 self.params = self._param_str_split(param_str, ";")
275 if urlp.query:
276 self.query = self._param_str_split(urlp.query, "&")
277
278 def __str__(self):
279 userinfo = self.userinfo
280 if userinfo:
281 userinfo += '@'
282
283 return "%s:%s%s%s%s%s%s" % (
284 self.scheme,
285 '' if self.relative else '//',
286 userinfo,
287 self.hostport,
288 self.path_quoted,
289 self._query_str(),
290 self._param_str())
291
292 def _param_str(self):
293 return (
294 ''.join([';', self._param_str_join(self.params, ";")])
295 if self.params else '')
296
297 def _query_str(self):
298 return (
299 ''.join(['?', self._param_str_join(self.query, "&")])
300 if self.query else '')
301
302 def _param_str_split(self, string, elmdelim, kvdelim="="):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600303 ret = collections.OrderedDict()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500304 for k, v in [x.split(kvdelim, 1) for x in string.split(elmdelim)]:
305 ret[k] = v
306 return ret
307
308 def _param_str_join(self, dict_, elmdelim, kvdelim="="):
309 return elmdelim.join([kvdelim.join([k, v]) for k, v in dict_.items()])
310
311 @property
312 def hostport(self):
313 if not self.port:
314 return self.hostname
315 return "%s:%d" % (self.hostname, self.port)
316
317 @property
318 def path_quoted(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600319 return urllib.parse.quote(self.path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500320
321 @path_quoted.setter
322 def path_quoted(self, path):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600323 self.path = urllib.parse.unquote(path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500324
325 @property
326 def path(self):
327 return self._path
328
329 @path.setter
330 def path(self, path):
331 self._path = path
332
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500333 if not path or re.compile("^/").match(path):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500334 self.relative = False
335 else:
336 self.relative = True
337
338 @property
339 def username(self):
340 if self.userinfo:
341 return (self.userinfo.split(":", 1))[0]
342 return ''
343
344 @username.setter
345 def username(self, username):
346 password = self.password
347 self.userinfo = username
348 if password:
349 self.userinfo += ":%s" % password
350
351 @property
352 def password(self):
353 if self.userinfo and ":" in self.userinfo:
354 return (self.userinfo.split(":", 1))[1]
355 return ''
356
357 @password.setter
358 def password(self, password):
359 self.userinfo = "%s:%s" % (self.username, password)
360
361def decodeurl(url):
362 """Decodes an URL into the tokens (scheme, network location, path,
363 user, password, parameters).
364 """
365
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500366 m = re.compile('(?P<type>[^:]*)://((?P<user>[^/;]+)@)?(?P<location>[^;]+)(;(?P<parm>.*))?').match(url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500367 if not m:
368 raise MalformedUrl(url)
369
370 type = m.group('type')
371 location = m.group('location')
372 if not location:
373 raise MalformedUrl(url)
374 user = m.group('user')
375 parm = m.group('parm')
376
377 locidx = location.find('/')
378 if locidx != -1 and type.lower() != 'file':
379 host = location[:locidx]
380 path = location[locidx:]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500381 elif type.lower() == 'file':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500382 host = ""
383 path = location
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500384 else:
385 host = location
386 path = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500387 if user:
388 m = re.compile('(?P<user>[^:]+)(:?(?P<pswd>.*))').match(user)
389 if m:
390 user = m.group('user')
391 pswd = m.group('pswd')
392 else:
393 user = ''
394 pswd = ''
395
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600396 p = collections.OrderedDict()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500397 if parm:
398 for s in parm.split(';'):
399 if s:
400 if not '=' in s:
401 raise MalformedUrl(url, "The URL: '%s' is invalid: parameter %s does not specify a value (missing '=')" % (url, s))
402 s1, s2 = s.split('=')
403 p[s1] = s2
404
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600405 return type, host, urllib.parse.unquote(path), user, pswd, p
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500406
407def encodeurl(decoded):
408 """Encodes a URL from tokens (scheme, network location, path,
409 user, password, parameters).
410 """
411
412 type, host, path, user, pswd, p = decoded
413
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500414 if not type:
415 raise MissingParameterError('type', "encoded from the data %s" % str(decoded))
416 url = '%s://' % type
417 if user and type != "file":
418 url += "%s" % user
419 if pswd:
420 url += ":%s" % pswd
421 url += "@"
422 if host and type != "file":
423 url += "%s" % host
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500424 if path:
425 # Standardise path to ensure comparisons work
426 while '//' in path:
427 path = path.replace("//", "/")
428 url += "%s" % urllib.parse.quote(path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500429 if p:
430 for parm in p:
431 url += ";%s=%s" % (parm, p[parm])
432
433 return url
434
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500435def uri_replace(ud, uri_find, uri_replace, replacements, d, mirrortarball=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500436 if not ud.url or not uri_find or not uri_replace:
437 logger.error("uri_replace: passed an undefined value, not replacing")
438 return None
439 uri_decoded = list(decodeurl(ud.url))
440 uri_find_decoded = list(decodeurl(uri_find))
441 uri_replace_decoded = list(decodeurl(uri_replace))
442 logger.debug(2, "For url %s comparing %s to %s" % (uri_decoded, uri_find_decoded, uri_replace_decoded))
443 result_decoded = ['', '', '', '', '', {}]
444 for loc, i in enumerate(uri_find_decoded):
445 result_decoded[loc] = uri_decoded[loc]
446 regexp = i
447 if loc == 0 and regexp and not regexp.endswith("$"):
448 # Leaving the type unanchored can mean "https" matching "file" can become "files"
449 # which is clearly undesirable.
450 regexp += "$"
451 if loc == 5:
452 # Handle URL parameters
453 if i:
454 # Any specified URL parameters must match
455 for k in uri_replace_decoded[loc]:
456 if uri_decoded[loc][k] != uri_replace_decoded[loc][k]:
457 return None
458 # Overwrite any specified replacement parameters
459 for k in uri_replace_decoded[loc]:
460 for l in replacements:
461 uri_replace_decoded[loc][k] = uri_replace_decoded[loc][k].replace(l, replacements[l])
462 result_decoded[loc][k] = uri_replace_decoded[loc][k]
463 elif (re.match(regexp, uri_decoded[loc])):
464 if not uri_replace_decoded[loc]:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500465 result_decoded[loc] = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500466 else:
467 for k in replacements:
468 uri_replace_decoded[loc] = uri_replace_decoded[loc].replace(k, replacements[k])
469 #bb.note("%s %s %s" % (regexp, uri_replace_decoded[loc], uri_decoded[loc]))
Patrick Williamsd7e96312015-09-22 08:09:05 -0500470 result_decoded[loc] = re.sub(regexp, uri_replace_decoded[loc], uri_decoded[loc], 1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500471 if loc == 2:
472 # Handle path manipulations
473 basename = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500474 if uri_decoded[0] != uri_replace_decoded[0] and mirrortarball:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500475 # If the source and destination url types differ, must be a mirrortarball mapping
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500476 basename = os.path.basename(mirrortarball)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500477 # Kill parameters, they make no sense for mirror tarballs
478 uri_decoded[5] = {}
479 elif ud.localpath and ud.method.supports_checksum(ud):
480 basename = os.path.basename(ud.localpath)
481 if basename and not result_decoded[loc].endswith(basename):
482 result_decoded[loc] = os.path.join(result_decoded[loc], basename)
483 else:
484 return None
485 result = encodeurl(result_decoded)
486 if result == ud.url:
487 return None
488 logger.debug(2, "For url %s returning %s" % (ud.url, result))
489 return result
490
491methods = []
492urldata_cache = {}
493saved_headrevs = {}
494
495def fetcher_init(d):
496 """
497 Called to initialize the fetchers once the configuration data is known.
498 Calls before this must not hit the cache.
499 """
500 # When to drop SCM head revisions controlled by user policy
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500501 srcrev_policy = d.getVar('BB_SRCREV_POLICY') or "clear"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500502 if srcrev_policy == "cache":
503 logger.debug(1, "Keeping SRCREV cache due to cache policy of: %s", srcrev_policy)
504 elif srcrev_policy == "clear":
505 logger.debug(1, "Clearing SRCREV cache due to cache policy of: %s", srcrev_policy)
506 revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
507 try:
508 bb.fetch2.saved_headrevs = revs.items()
509 except:
510 pass
511 revs.clear()
512 else:
513 raise FetchError("Invalid SRCREV cache policy of: %s" % srcrev_policy)
514
515 _checksum_cache.init_cache(d)
516
517 for m in methods:
518 if hasattr(m, "init"):
519 m.init(d)
520
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500521def fetcher_parse_save():
522 _checksum_cache.save_extras()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500523
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500524def fetcher_parse_done():
525 _checksum_cache.save_merge()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500526
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500527def fetcher_compare_revisions():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500528 """
529 Compare the revisions in the persistant cache with current values and
530 return true/false on whether they've changed.
531 """
532
533 data = bb.persist_data.persist('BB_URI_HEADREVS', d).items()
534 data2 = bb.fetch2.saved_headrevs
535
536 changed = False
537 for key in data:
538 if key not in data2 or data2[key] != data[key]:
539 logger.debug(1, "%s changed", key)
540 changed = True
541 return True
542 else:
543 logger.debug(2, "%s did not change", key)
544 return False
545
546def mirror_from_string(data):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500547 mirrors = (data or "").replace('\\n',' ').split()
548 # Split into pairs
549 if len(mirrors) % 2 != 0:
550 bb.warn('Invalid mirror data %s, should have paired members.' % data)
551 return list(zip(*[iter(mirrors)]*2))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500552
553def verify_checksum(ud, d, precomputed={}):
554 """
555 verify the MD5 and SHA256 checksum for downloaded src
556
557 Raises a FetchError if one or both of the SRC_URI checksums do not match
558 the downloaded file, or if BB_STRICT_CHECKSUM is set and there are no
559 checksums specified.
560
561 Returns a dict of checksums that can be stored in a done stamp file and
562 passed in as precomputed parameter in a later call to avoid re-computing
563 the checksums from the file. This allows verifying the checksums of the
564 file against those in the recipe each time, rather than only after
565 downloading. See https://bugzilla.yoctoproject.org/show_bug.cgi?id=5571.
566 """
567
568 _MD5_KEY = "md5"
569 _SHA256_KEY = "sha256"
570
571 if ud.ignore_checksums or not ud.method.supports_checksum(ud):
572 return {}
573
574 if _MD5_KEY in precomputed:
575 md5data = precomputed[_MD5_KEY]
576 else:
577 md5data = bb.utils.md5_file(ud.localpath)
578
579 if _SHA256_KEY in precomputed:
580 sha256data = precomputed[_SHA256_KEY]
581 else:
582 sha256data = bb.utils.sha256_file(ud.localpath)
583
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500584 if ud.method.recommends_checksum(ud) and not ud.md5_expected and not ud.sha256_expected:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500585 # If strict checking enabled and neither sum defined, raise error
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500586 strict = d.getVar("BB_STRICT_CHECKSUM") or "0"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500587 if strict == "1":
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500588 logger.error('No checksum specified for %s, please add at least one to the recipe:\n'
589 'SRC_URI[%s] = "%s"\nSRC_URI[%s] = "%s"' %
590 (ud.localpath, ud.md5_name, md5data,
591 ud.sha256_name, sha256data))
592 raise NoChecksumError('Missing SRC_URI checksum', ud.url)
593
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500594 bb.event.fire(MissingChecksumEvent(ud.url, md5data, sha256data), d)
595
596 if strict == "ignore":
597 return {
598 _MD5_KEY: md5data,
599 _SHA256_KEY: sha256data
600 }
601
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500602 # Log missing sums so user can more easily add them
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600603 logger.warning('Missing md5 SRC_URI checksum for %s, consider adding to the recipe:\n'
604 'SRC_URI[%s] = "%s"',
605 ud.localpath, ud.md5_name, md5data)
606 logger.warning('Missing sha256 SRC_URI checksum for %s, consider adding to the recipe:\n'
607 'SRC_URI[%s] = "%s"',
608 ud.localpath, ud.sha256_name, sha256data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500609
610 # We want to alert the user if a checksum is defined in the recipe but
611 # it does not match.
612 msg = ""
613 mismatch = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500614 if ud.md5_expected and ud.md5_expected != md5data:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500615 msg = msg + "\nFile: '%s' has %s checksum %s when %s was expected" % (ud.localpath, 'md5', md5data, ud.md5_expected)
616 mismatch = True;
617
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500618 if ud.sha256_expected and ud.sha256_expected != sha256data:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500619 msg = msg + "\nFile: '%s' has %s checksum %s when %s was expected" % (ud.localpath, 'sha256', sha256data, ud.sha256_expected)
620 mismatch = True;
621
622 if mismatch:
623 msg = msg + '\nIf this change is expected (e.g. you have upgraded to a new version without updating the checksums) then you can use these lines within the recipe:\nSRC_URI[%s] = "%s"\nSRC_URI[%s] = "%s"\nOtherwise you should retry the download and/or check with upstream to determine if the file has become corrupted or otherwise unexpectedly modified.\n' % (ud.md5_name, md5data, ud.sha256_name, sha256data)
624
625 if len(msg):
626 raise ChecksumError('Checksum mismatch!%s' % msg, ud.url, md5data)
627
628 return {
629 _MD5_KEY: md5data,
630 _SHA256_KEY: sha256data
631 }
632
633
634def verify_donestamp(ud, d, origud=None):
635 """
636 Check whether the done stamp file has the right checksums (if the fetch
637 method supports them). If it doesn't, delete the done stamp and force
638 a re-download.
639
640 Returns True, if the donestamp exists and is valid, False otherwise. When
641 returning False, any existing done stamps are removed.
642 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500643 if not ud.needdonestamp or (origud and not origud.needdonestamp):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500644 return True
645
Brad Bishop316dfdd2018-06-25 12:45:53 -0400646 if not os.path.exists(ud.localpath):
647 # local path does not exist
648 if os.path.exists(ud.donestamp):
649 # done stamp exists, but the downloaded file does not; the done stamp
650 # must be incorrect, re-trigger the download
651 bb.utils.remove(ud.donestamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500652 return False
653
654 if (not ud.method.supports_checksum(ud) or
655 (origud and not origud.method.supports_checksum(origud))):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400656 # if done stamp exists and checksums not supported; assume the local
657 # file is current
658 return os.path.exists(ud.donestamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500659
660 precomputed_checksums = {}
661 # Only re-use the precomputed checksums if the donestamp is newer than the
662 # file. Do not rely on the mtime of directories, though. If ud.localpath is
663 # a directory, there will probably not be any checksums anyway.
Brad Bishop316dfdd2018-06-25 12:45:53 -0400664 if os.path.exists(ud.donestamp) and (os.path.isdir(ud.localpath) or
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500665 os.path.getmtime(ud.localpath) < os.path.getmtime(ud.donestamp)):
666 try:
667 with open(ud.donestamp, "rb") as cachefile:
668 pickled = pickle.Unpickler(cachefile)
669 precomputed_checksums.update(pickled.load())
670 except Exception as e:
671 # Avoid the warnings on the upgrade path from emtpy done stamp
672 # files to those containing the checksums.
673 if not isinstance(e, EOFError):
674 # Ignore errors, they aren't fatal
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600675 logger.warning("Couldn't load checksums from donestamp %s: %s "
676 "(msg: %s)" % (ud.donestamp, type(e).__name__,
677 str(e)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500678
679 try:
680 checksums = verify_checksum(ud, d, precomputed_checksums)
681 # If the cache file did not have the checksums, compute and store them
682 # as an upgrade path from the previous done stamp file format.
683 if checksums != precomputed_checksums:
684 with open(ud.donestamp, "wb") as cachefile:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600685 p = pickle.Pickler(cachefile, 2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500686 p.dump(checksums)
687 return True
688 except ChecksumError as e:
689 # Checksums failed to verify, trigger re-download and remove the
690 # incorrect stamp file.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600691 logger.warning("Checksum mismatch for local file %s\n"
692 "Cleaning and trying again." % ud.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500693 if os.path.exists(ud.localpath):
694 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500695 bb.utils.remove(ud.donestamp)
696 return False
697
698
699def update_stamp(ud, d):
700 """
701 donestamp is file stamp indicating the whole fetching is done
702 this function update the stamp after verifying the checksum
703 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500704 if not ud.needdonestamp:
705 return
706
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500707 if os.path.exists(ud.donestamp):
708 # Touch the done stamp file to show active use of the download
709 try:
710 os.utime(ud.donestamp, None)
711 except:
712 # Errors aren't fatal here
713 pass
714 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500715 try:
716 checksums = verify_checksum(ud, d)
717 # Store the checksums for later re-verification against the recipe
718 with open(ud.donestamp, "wb") as cachefile:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600719 p = pickle.Pickler(cachefile, 2)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500720 p.dump(checksums)
721 except ChecksumError as e:
722 # Checksums failed to verify, trigger re-download and remove the
723 # incorrect stamp file.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600724 logger.warning("Checksum mismatch for local file %s\n"
725 "Cleaning and trying again." % ud.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500726 if os.path.exists(ud.localpath):
727 rename_bad_checksum(ud, e.checksum)
728 bb.utils.remove(ud.donestamp)
729 raise
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500730
731def subprocess_setup():
732 # Python installs a SIGPIPE handler by default. This is usually not what
733 # non-Python subprocesses expect.
734 # SIGPIPE errors are known issues with gzip/bash
735 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
736
737def get_autorev(d):
738 # only not cache src rev in autorev case
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500739 if d.getVar('BB_SRCREV_POLICY') != "cache":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500740 d.setVar('BB_DONT_CACHE', '1')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500741 return "AUTOINC"
742
743def get_srcrev(d, method_name='sortable_revision'):
744 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500745 Return the revision string, usually for use in the version string (PV) of the current package
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500746 Most packages usually only have one SCM so we just pass on the call.
747 In the multi SCM case, we build a value based on SRCREV_FORMAT which must
748 have been set.
749
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500750 The idea here is that we put the string "AUTOINC+" into return value if the revisions are not
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500751 incremental, other code is then responsible for turning that into an increasing value (if needed)
752
753 A method_name can be supplied to retrieve an alternatively formatted revision from a fetcher, if
754 that fetcher provides a method with the given name and the same signature as sortable_revision.
755 """
756
757 scms = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500758 fetcher = Fetch(d.getVar('SRC_URI').split(), d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500759 urldata = fetcher.ud
760 for u in urldata:
761 if urldata[u].method.supports_srcrev():
762 scms.append(u)
763
764 if len(scms) == 0:
765 raise FetchError("SRCREV was used yet no valid SCM was found in SRC_URI")
766
767 if len(scms) == 1 and len(urldata[scms[0]].names) == 1:
768 autoinc, rev = getattr(urldata[scms[0]].method, method_name)(urldata[scms[0]], d, urldata[scms[0]].names[0])
769 if len(rev) > 10:
770 rev = rev[:10]
771 if autoinc:
772 return "AUTOINC+" + rev
773 return rev
774
775 #
776 # Mutiple SCMs are in SRC_URI so we resort to SRCREV_FORMAT
777 #
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500778 format = d.getVar('SRCREV_FORMAT')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500779 if not format:
780 raise FetchError("The SRCREV_FORMAT variable must be set when multiple SCMs are used.")
781
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600782 name_to_rev = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500783 seenautoinc = False
784 for scm in scms:
785 ud = urldata[scm]
786 for name in ud.names:
787 autoinc, rev = getattr(ud.method, method_name)(ud, d, name)
788 seenautoinc = seenautoinc or autoinc
789 if len(rev) > 10:
790 rev = rev[:10]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600791 name_to_rev[name] = rev
792 # Replace names by revisions in the SRCREV_FORMAT string. The approach used
793 # here can handle names being prefixes of other names and names appearing
794 # as substrings in revisions (in which case the name should not be
795 # expanded). The '|' regular expression operator tries matches from left to
796 # right, so we need to sort the names with the longest ones first.
797 names_descending_len = sorted(name_to_rev, key=len, reverse=True)
798 name_to_rev_re = "|".join(re.escape(name) for name in names_descending_len)
799 format = re.sub(name_to_rev_re, lambda match: name_to_rev[match.group(0)], format)
800
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500801 if seenautoinc:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500802 format = "AUTOINC+" + format
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500803
804 return format
805
806def localpath(url, d):
807 fetcher = bb.fetch2.Fetch([url], d)
808 return fetcher.localpath(url)
809
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600810def runfetchcmd(cmd, d, quiet=False, cleanup=None, log=None, workdir=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500811 """
812 Run cmd returning the command output
813 Raise an error if interrupted or cmd fails
814 Optionally echo command output to stdout
815 Optionally remove the files/directories listed in cleanup upon failure
816 """
817
818 # Need to export PATH as binary could be in metadata paths
819 # rather than host provided
820 # Also include some other variables.
821 # FIXME: Should really include all export varaiables?
822 exportvars = ['HOME', 'PATH',
823 'HTTP_PROXY', 'http_proxy',
824 'HTTPS_PROXY', 'https_proxy',
825 'FTP_PROXY', 'ftp_proxy',
826 'FTPS_PROXY', 'ftps_proxy',
827 'NO_PROXY', 'no_proxy',
828 'ALL_PROXY', 'all_proxy',
829 'GIT_PROXY_COMMAND',
830 'GIT_SSL_CAINFO',
831 'GIT_SMART_HTTP',
832 'SSH_AUTH_SOCK', 'SSH_AGENT_PID',
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600833 'SOCKS5_USER', 'SOCKS5_PASSWD',
834 'DBUS_SESSION_BUS_ADDRESS',
835 'P4CONFIG']
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500836
837 if not cleanup:
838 cleanup = []
839
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500840 # If PATH contains WORKDIR which contains PV which contains SRCPV we
841 # can end up in circular recursion here so give the option of breaking it
842 # in a data store copy.
843 try:
844 d.getVar("PV")
845 except bb.data_smart.ExpansionError:
846 d = bb.data.createCopy(d)
847 d.setVar("PV", "fetcheravoidrecurse")
848
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600849 origenv = d.getVar("BB_ORIGENV", False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500850 for var in exportvars:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500851 val = d.getVar(var) or (origenv and origenv.getVar(var))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500852 if val:
853 cmd = 'export ' + var + '=\"%s\"; %s' % (val, cmd)
854
Brad Bishop316dfdd2018-06-25 12:45:53 -0400855 # Disable pseudo as it may affect ssh, potentially causing it to hang.
856 cmd = 'export PSEUDO_DISABLED=1; ' + cmd
857
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500858 logger.debug(1, "Running %s", cmd)
859
860 success = False
861 error_message = ""
862
863 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600864 (output, errors) = bb.process.run(cmd, log=log, shell=True, stderr=subprocess.PIPE, cwd=workdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500865 success = True
866 except bb.process.NotFoundError as e:
867 error_message = "Fetch command %s" % (e.command)
868 except bb.process.ExecutionError as e:
869 if e.stdout:
870 output = "output:\n%s\n%s" % (e.stdout, e.stderr)
871 elif e.stderr:
872 output = "output:\n%s" % e.stderr
873 else:
874 output = "no output"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600875 error_message = "Fetch command %s failed with exit code %s, %s" % (e.command, e.exitcode, output)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500876 except bb.process.CmdError as e:
877 error_message = "Fetch command %s could not be run:\n%s" % (e.command, e.msg)
878 if not success:
879 for f in cleanup:
880 try:
881 bb.utils.remove(f, True)
882 except OSError:
883 pass
884
885 raise FetchError(error_message)
886
887 return output
888
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500889def check_network_access(d, info, url):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500890 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500891 log remote network access, and error if BB_NO_NETWORK is set or the given
892 URI is untrusted
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500893 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500894 if d.getVar("BB_NO_NETWORK") == "1":
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500895 raise NetworkAccess(url, info)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500896 elif not trusted_network(d, url):
897 raise UntrustedUrl(url, info)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500898 else:
899 logger.debug(1, "Fetcher accessed the network with the command %s" % info)
900
901def build_mirroruris(origud, mirrors, ld):
902 uris = []
903 uds = []
904
905 replacements = {}
906 replacements["TYPE"] = origud.type
907 replacements["HOST"] = origud.host
908 replacements["PATH"] = origud.path
909 replacements["BASENAME"] = origud.path.split("/")[-1]
910 replacements["MIRRORNAME"] = origud.host.replace(':','.') + origud.path.replace('/', '.').replace('*', '.')
911
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500912 def adduri(ud, uris, uds, mirrors, tarballs):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500913 for line in mirrors:
914 try:
915 (find, replace) = line
916 except ValueError:
917 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500918
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500919 for tarball in tarballs:
920 newuri = uri_replace(ud, find, replace, replacements, ld, tarball)
921 if not newuri or newuri in uris or newuri == origud.url:
922 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500923
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500924 if not trusted_network(ld, newuri):
925 logger.debug(1, "Mirror %s not in the list of trusted networks, skipping" % (newuri))
926 continue
Patrick Williamsd7e96312015-09-22 08:09:05 -0500927
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500928 # Create a local copy of the mirrors minus the current line
929 # this will prevent us from recursively processing the same line
930 # as well as indirect recursion A -> B -> C -> A
931 localmirrors = list(mirrors)
932 localmirrors.remove(line)
933
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500934 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500935 newud = FetchData(newuri, ld)
936 newud.setup_localpath(ld)
937 except bb.fetch2.BBFetchException as e:
938 logger.debug(1, "Mirror fetch failure for url %s (original url: %s)" % (newuri, origud.url))
939 logger.debug(1, str(e))
940 try:
941 # setup_localpath of file:// urls may fail, we should still see
942 # if mirrors of the url exist
943 adduri(newud, uris, uds, localmirrors, tarballs)
944 except UnboundLocalError:
945 pass
946 continue
947 uris.append(newuri)
948 uds.append(newud)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500949
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500950 adduri(newud, uris, uds, localmirrors, tarballs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500951
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500952 adduri(origud, uris, uds, mirrors, origud.mirrortarballs or [None])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500953
954 return uris, uds
955
956def rename_bad_checksum(ud, suffix):
957 """
958 Renames files to have suffix from parameter
959 """
960
961 if ud.localpath is None:
962 return
963
964 new_localpath = "%s_bad-checksum_%s" % (ud.localpath, suffix)
965 bb.warn("Renaming %s to %s" % (ud.localpath, new_localpath))
966 bb.utils.movefile(ud.localpath, new_localpath)
967
968
969def try_mirror_url(fetch, origud, ud, ld, check = False):
970 # Return of None or a value means we're finished
971 # False means try another url
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500972
973 if ud.lockfile and ud.lockfile != origud.lockfile:
974 lf = bb.utils.lockfile(ud.lockfile)
975
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500976 try:
977 if check:
978 found = ud.method.checkstatus(fetch, ud, ld)
979 if found:
980 return found
981 return False
982
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500983 if not verify_donestamp(ud, ld, origud) or ud.method.need_update(ud, ld):
984 ud.method.download(ud, ld)
985 if hasattr(ud.method,"build_mirror_data"):
986 ud.method.build_mirror_data(ud, ld)
987
988 if not ud.localpath or not os.path.exists(ud.localpath):
989 return False
990
991 if ud.localpath == origud.localpath:
992 return ud.localpath
993
994 # We may be obtaining a mirror tarball which needs further processing by the real fetcher
995 # If that tarball is a local file:// we need to provide a symlink to it
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500996 dldir = ld.getVar("DL_DIR")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500997
998 if origud.mirrortarballs and os.path.basename(ud.localpath) in origud.mirrortarballs and os.path.basename(ud.localpath) != os.path.basename(origud.localpath):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500999 # Create donestamp in old format to avoid triggering a re-download
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001000 if ud.donestamp:
1001 bb.utils.mkdirhier(os.path.dirname(ud.donestamp))
1002 open(ud.donestamp, 'w').close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001003 dest = os.path.join(dldir, os.path.basename(ud.localpath))
1004 if not os.path.exists(dest):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001005 # In case this is executing without any file locks held (as is
1006 # the case for file:// URLs), two tasks may end up here at the
1007 # same time, in which case we do not want the second task to
1008 # fail when the link has already been created by the first task.
1009 try:
1010 os.symlink(ud.localpath, dest)
1011 except FileExistsError:
1012 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001013 if not verify_donestamp(origud, ld) or origud.method.need_update(origud, ld):
1014 origud.method.download(origud, ld)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001015 if hasattr(origud.method, "build_mirror_data"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001016 origud.method.build_mirror_data(origud, ld)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001017 return origud.localpath
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001018 # Otherwise the result is a local file:// and we symlink to it
1019 if not os.path.exists(origud.localpath):
1020 if os.path.islink(origud.localpath):
1021 # Broken symbolic link
1022 os.unlink(origud.localpath)
1023
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001024 # As per above, in case two tasks end up here simultaneously.
1025 try:
1026 os.symlink(ud.localpath, origud.localpath)
1027 except FileExistsError:
1028 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001029 update_stamp(origud, ld)
1030 return ud.localpath
1031
1032 except bb.fetch2.NetworkAccess:
1033 raise
1034
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001035 except IOError as e:
1036 if e.errno in [os.errno.ESTALE]:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001037 logger.warning("Stale Error Observed %s." % ud.url)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001038 return False
1039 raise
1040
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001041 except bb.fetch2.BBFetchException as e:
1042 if isinstance(e, ChecksumError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001043 logger.warning("Mirror checksum failure for url %s (original url: %s)\nCleaning and trying again." % (ud.url, origud.url))
1044 logger.warning(str(e))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001045 if os.path.exists(ud.localpath):
1046 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001047 elif isinstance(e, NoChecksumError):
1048 raise
1049 else:
1050 logger.debug(1, "Mirror fetch failure for url %s (original url: %s)" % (ud.url, origud.url))
1051 logger.debug(1, str(e))
1052 try:
1053 ud.method.clean(ud, ld)
1054 except UnboundLocalError:
1055 pass
1056 return False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001057 finally:
1058 if ud.lockfile and ud.lockfile != origud.lockfile:
1059 bb.utils.unlockfile(lf)
1060
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001061
1062def try_mirrors(fetch, d, origud, mirrors, check = False):
1063 """
1064 Try to use a mirrored version of the sources.
1065 This method will be automatically called before the fetchers go.
1066
1067 d Is a bb.data instance
1068 uri is the original uri we're trying to download
1069 mirrors is the list of mirrors we're going to try
1070 """
1071 ld = d.createCopy()
1072
1073 uris, uds = build_mirroruris(origud, mirrors, ld)
1074
1075 for index, uri in enumerate(uris):
1076 ret = try_mirror_url(fetch, origud, uds[index], ld, check)
1077 if ret != False:
1078 return ret
1079 return None
1080
1081def trusted_network(d, url):
1082 """
1083 Use a trusted url during download if networking is enabled and
1084 BB_ALLOWED_NETWORKS is set globally or for a specific recipe.
1085 Note: modifies SRC_URI & mirrors.
1086 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001087 if d.getVar('BB_NO_NETWORK') == "1":
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001088 return True
1089
1090 pkgname = d.expand(d.getVar('PN', False))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001091 trusted_hosts = d.getVarFlag('BB_ALLOWED_NETWORKS', pkgname, False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001092
1093 if not trusted_hosts:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001094 trusted_hosts = d.getVar('BB_ALLOWED_NETWORKS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001095
1096 # Not enabled.
1097 if not trusted_hosts:
1098 return True
1099
1100 scheme, network, path, user, passwd, param = decodeurl(url)
1101
1102 if not network:
1103 return True
1104
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001105 network = network.split(':')[0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001106 network = network.lower()
1107
1108 for host in trusted_hosts.split(" "):
1109 host = host.lower()
1110 if host.startswith("*.") and ("." + network).endswith(host[1:]):
1111 return True
1112 if host == network:
1113 return True
1114
1115 return False
1116
1117def srcrev_internal_helper(ud, d, name):
1118 """
1119 Return:
1120 a) a source revision if specified
1121 b) latest revision if SRCREV="AUTOINC"
1122 c) None if not specified
1123 """
1124
1125 srcrev = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001126 pn = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001127 attempts = []
1128 if name != '' and pn:
1129 attempts.append("SRCREV_%s_pn-%s" % (name, pn))
1130 if name != '':
1131 attempts.append("SRCREV_%s" % name)
1132 if pn:
1133 attempts.append("SRCREV_pn-%s" % pn)
1134 attempts.append("SRCREV")
1135
1136 for a in attempts:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001137 srcrev = d.getVar(a)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001138 if srcrev and srcrev != "INVALID":
1139 break
1140
1141 if 'rev' in ud.parm and 'tag' in ud.parm:
1142 raise FetchError("Please specify a ;rev= parameter or a ;tag= parameter in the url %s but not both." % (ud.url))
1143
1144 if 'rev' in ud.parm or 'tag' in ud.parm:
1145 if 'rev' in ud.parm:
1146 parmrev = ud.parm['rev']
1147 else:
1148 parmrev = ud.parm['tag']
1149 if srcrev == "INVALID" or not srcrev:
1150 return parmrev
1151 if srcrev != parmrev:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001152 raise FetchError("Conflicting revisions (%s from SRCREV and %s from the url) found, please specify one valid value" % (srcrev, parmrev))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001153 return parmrev
1154
1155 if srcrev == "INVALID" or not srcrev:
1156 raise FetchError("Please set a valid SRCREV for url %s (possible key names are %s, or use a ;rev=X URL parameter)" % (str(attempts), ud.url), ud.url)
1157 if srcrev == "AUTOINC":
1158 srcrev = ud.method.latest_revision(ud, d, name)
1159
1160 return srcrev
1161
1162def get_checksum_file_list(d):
1163 """ Get a list of files checksum in SRC_URI
1164
1165 Returns the resolved local paths of all local file entries in
1166 SRC_URI as a space-separated string
1167 """
1168 fetch = Fetch([], d, cache = False, localonly = True)
1169
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001170 dl_dir = d.getVar('DL_DIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001171 filelist = []
1172 for u in fetch.urls:
1173 ud = fetch.ud[u]
1174
1175 if ud and isinstance(ud.method, local.Local):
1176 paths = ud.method.localpaths(ud, d)
1177 for f in paths:
1178 pth = ud.decodedurl
1179 if '*' in pth:
1180 f = os.path.join(os.path.abspath(f), pth)
1181 if f.startswith(dl_dir):
1182 # The local fetcher's behaviour is to return a path under DL_DIR if it couldn't find the file anywhere else
1183 if os.path.exists(f):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001184 bb.warn("Getting checksum for %s SRC_URI entry %s: file not found except in DL_DIR" % (d.getVar('PN'), os.path.basename(f)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001185 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001186 bb.warn("Unable to get checksum for %s SRC_URI entry %s: file could not be found" % (d.getVar('PN'), os.path.basename(f)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001187 filelist.append(f + ":" + str(os.path.exists(f)))
1188
1189 return " ".join(filelist)
1190
1191def get_file_checksums(filelist, pn):
1192 """Get a list of the checksums for a list of local files
1193
1194 Returns the checksums for a list of local files, caching the results as
1195 it proceeds
1196
1197 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001198 return _checksum_cache.get_checksums(filelist, pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001199
1200
1201class FetchData(object):
1202 """
1203 A class which represents the fetcher state for a given URI.
1204 """
1205 def __init__(self, url, d, localonly = False):
1206 # localpath is the location of a downloaded result. If not set, the file is local.
1207 self.donestamp = None
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001208 self.needdonestamp = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001209 self.localfile = ""
1210 self.localpath = None
1211 self.lockfile = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001212 self.mirrortarballs = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001213 self.basename = None
1214 self.basepath = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001215 (self.type, self.host, self.path, self.user, self.pswd, self.parm) = decodeurl(d.expand(url))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001216 self.date = self.getSRCDate(d)
1217 self.url = url
1218 if not self.user and "user" in self.parm:
1219 self.user = self.parm["user"]
1220 if not self.pswd and "pswd" in self.parm:
1221 self.pswd = self.parm["pswd"]
1222 self.setup = False
1223
1224 if "name" in self.parm:
1225 self.md5_name = "%s.md5sum" % self.parm["name"]
1226 self.sha256_name = "%s.sha256sum" % self.parm["name"]
1227 else:
1228 self.md5_name = "md5sum"
1229 self.sha256_name = "sha256sum"
1230 if self.md5_name in self.parm:
1231 self.md5_expected = self.parm[self.md5_name]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001232 elif self.type not in ["http", "https", "ftp", "ftps", "sftp", "s3"]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001233 self.md5_expected = None
1234 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001235 self.md5_expected = d.getVarFlag("SRC_URI", self.md5_name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001236 if self.sha256_name in self.parm:
1237 self.sha256_expected = self.parm[self.sha256_name]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001238 elif self.type not in ["http", "https", "ftp", "ftps", "sftp", "s3"]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001239 self.sha256_expected = None
1240 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001241 self.sha256_expected = d.getVarFlag("SRC_URI", self.sha256_name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001242 self.ignore_checksums = False
1243
1244 self.names = self.parm.get("name",'default').split(',')
1245
1246 self.method = None
1247 for m in methods:
1248 if m.supports(self, d):
1249 self.method = m
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001250 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001251
1252 if not self.method:
1253 raise NoMethodError(url)
1254
1255 if localonly and not isinstance(self.method, local.Local):
1256 raise NonLocalMethod()
1257
1258 if self.parm.get("proto", None) and "protocol" not in self.parm:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001259 logger.warning('Consider updating %s recipe to use "protocol" not "proto" in SRC_URI.', d.getVar('PN'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001260 self.parm["protocol"] = self.parm.get("proto", None)
1261
1262 if hasattr(self.method, "urldata_init"):
1263 self.method.urldata_init(self, d)
1264
1265 if "localpath" in self.parm:
1266 # if user sets localpath for file, use it instead.
1267 self.localpath = self.parm["localpath"]
1268 self.basename = os.path.basename(self.localpath)
1269 elif self.localfile:
1270 self.localpath = self.method.localpath(self, d)
1271
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001272 dldir = d.getVar("DL_DIR")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001273
1274 if not self.needdonestamp:
1275 return
1276
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001277 # Note: .done and .lock files should always be in DL_DIR whereas localpath may not be.
1278 if self.localpath and self.localpath.startswith(dldir):
1279 basepath = self.localpath
1280 elif self.localpath:
1281 basepath = dldir + os.sep + os.path.basename(self.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001282 elif self.basepath or self.basename:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001283 basepath = dldir + os.sep + (self.basepath or self.basename)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001284 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001285 bb.fatal("Can't determine lock path for url %s" % url)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001286
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001287 self.donestamp = basepath + '.done'
1288 self.lockfile = basepath + '.lock'
1289
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001290 def setup_revisions(self, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001291 self.revisions = {}
1292 for name in self.names:
1293 self.revisions[name] = srcrev_internal_helper(self, d, name)
1294
1295 # add compatibility code for non name specified case
1296 if len(self.names) == 1:
1297 self.revision = self.revisions[self.names[0]]
1298
1299 def setup_localpath(self, d):
1300 if not self.localpath:
1301 self.localpath = self.method.localpath(self, d)
1302
1303 def getSRCDate(self, d):
1304 """
1305 Return the SRC Date for the component
1306
1307 d the bb.data module
1308 """
1309 if "srcdate" in self.parm:
1310 return self.parm['srcdate']
1311
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001312 pn = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001313
1314 if pn:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001315 return d.getVar("SRCDATE_%s" % pn) or d.getVar("SRCDATE") or d.getVar("DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001316
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001317 return d.getVar("SRCDATE") or d.getVar("DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001318
1319class FetchMethod(object):
1320 """Base class for 'fetch'ing data"""
1321
1322 def __init__(self, urls=None):
1323 self.urls = []
1324
1325 def supports(self, urldata, d):
1326 """
1327 Check to see if this fetch class supports a given url.
1328 """
1329 return 0
1330
1331 def localpath(self, urldata, d):
1332 """
1333 Return the local filename of a given url assuming a successful fetch.
1334 Can also setup variables in urldata for use in go (saving code duplication
1335 and duplicate code execution)
1336 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001337 return os.path.join(d.getVar("DL_DIR"), urldata.localfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001338
1339 def supports_checksum(self, urldata):
1340 """
1341 Is localpath something that can be represented by a checksum?
1342 """
1343
1344 # We cannot compute checksums for directories
1345 if os.path.isdir(urldata.localpath) == True:
1346 return False
1347 if urldata.localpath.find("*") != -1:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001348 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001349
1350 return True
1351
1352 def recommends_checksum(self, urldata):
1353 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001354 Is the backend on where checksumming is recommended (should warnings
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001355 be displayed if there is no checksum)?
1356 """
1357 return False
1358
1359 def _strip_leading_slashes(self, relpath):
1360 """
1361 Remove leading slash as os.path.join can't cope
1362 """
1363 while os.path.isabs(relpath):
1364 relpath = relpath[1:]
1365 return relpath
1366
1367 def setUrls(self, urls):
1368 self.__urls = urls
1369
1370 def getUrls(self):
1371 return self.__urls
1372
1373 urls = property(getUrls, setUrls, None, "Urls property")
1374
1375 def need_update(self, ud, d):
1376 """
1377 Force a fetch, even if localpath exists?
1378 """
1379 if os.path.exists(ud.localpath):
1380 return False
1381 return True
1382
1383 def supports_srcrev(self):
1384 """
1385 The fetcher supports auto source revisions (SRCREV)
1386 """
1387 return False
1388
1389 def download(self, urldata, d):
1390 """
1391 Fetch urls
1392 Assumes localpath was called first
1393 """
1394 raise NoMethodError(url)
1395
1396 def unpack(self, urldata, rootdir, data):
1397 iterate = False
1398 file = urldata.localpath
1399
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001400 # Localpath can't deal with 'dir/*' entries, so it converts them to '.',
1401 # but it must be corrected back for local files copying
1402 if urldata.basename == '*' and file.endswith('/.'):
1403 file = '%s/%s' % (file.rstrip('/.'), urldata.path)
1404
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001405 try:
1406 unpack = bb.utils.to_boolean(urldata.parm.get('unpack'), True)
1407 except ValueError as exc:
1408 bb.fatal("Invalid value for 'unpack' parameter for %s: %s" %
1409 (file, urldata.parm.get('unpack')))
1410
1411 base, ext = os.path.splitext(file)
1412 if ext in ['.gz', '.bz2', '.Z', '.xz', '.lz']:
1413 efile = os.path.join(rootdir, os.path.basename(base))
1414 else:
1415 efile = file
1416 cmd = None
1417
1418 if unpack:
1419 if file.endswith('.tar'):
1420 cmd = 'tar x --no-same-owner -f %s' % file
1421 elif file.endswith('.tgz') or file.endswith('.tar.gz') or file.endswith('.tar.Z'):
1422 cmd = 'tar xz --no-same-owner -f %s' % file
1423 elif file.endswith('.tbz') or file.endswith('.tbz2') or file.endswith('.tar.bz2'):
1424 cmd = 'bzip2 -dc %s | tar x --no-same-owner -f -' % file
1425 elif file.endswith('.gz') or file.endswith('.Z') or file.endswith('.z'):
1426 cmd = 'gzip -dc %s > %s' % (file, efile)
1427 elif file.endswith('.bz2'):
1428 cmd = 'bzip2 -dc %s > %s' % (file, efile)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001429 elif file.endswith('.txz') or file.endswith('.tar.xz'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001430 cmd = 'xz -dc %s | tar x --no-same-owner -f -' % file
1431 elif file.endswith('.xz'):
1432 cmd = 'xz -dc %s > %s' % (file, efile)
1433 elif file.endswith('.tar.lz'):
1434 cmd = 'lzip -dc %s | tar x --no-same-owner -f -' % file
1435 elif file.endswith('.lz'):
1436 cmd = 'lzip -dc %s > %s' % (file, efile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001437 elif file.endswith('.tar.7z'):
1438 cmd = '7z x -so %s | tar x --no-same-owner -f -' % file
1439 elif file.endswith('.7z'):
1440 cmd = '7za x -y %s 1>/dev/null' % file
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001441 elif file.endswith('.zip') or file.endswith('.jar'):
1442 try:
1443 dos = bb.utils.to_boolean(urldata.parm.get('dos'), False)
1444 except ValueError as exc:
1445 bb.fatal("Invalid value for 'dos' parameter for %s: %s" %
1446 (file, urldata.parm.get('dos')))
1447 cmd = 'unzip -q -o'
1448 if dos:
1449 cmd = '%s -a' % cmd
1450 cmd = "%s '%s'" % (cmd, file)
1451 elif file.endswith('.rpm') or file.endswith('.srpm'):
1452 if 'extract' in urldata.parm:
1453 unpack_file = urldata.parm.get('extract')
1454 cmd = 'rpm2cpio.sh %s | cpio -id %s' % (file, unpack_file)
1455 iterate = True
1456 iterate_file = unpack_file
1457 else:
1458 cmd = 'rpm2cpio.sh %s | cpio -id' % (file)
1459 elif file.endswith('.deb') or file.endswith('.ipk'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001460 output = subprocess.check_output('ar -t %s' % file, preexec_fn=subprocess_setup, shell=True)
1461 datafile = None
1462 if output:
1463 for line in output.decode().splitlines():
1464 if line.startswith('data.tar.'):
1465 datafile = line
1466 break
1467 else:
1468 raise UnpackError("Unable to unpack deb/ipk package - does not contain data.tar.* file", urldata.url)
1469 else:
1470 raise UnpackError("Unable to unpack deb/ipk package - could not list contents", urldata.url)
1471 cmd = 'ar x %s %s && tar --no-same-owner -xpf %s && rm %s' % (file, datafile, datafile, datafile)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001472
1473 # If 'subdir' param exists, create a dir and use it as destination for unpack cmd
1474 if 'subdir' in urldata.parm:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001475 subdir = urldata.parm.get('subdir')
1476 if os.path.isabs(subdir):
1477 if not os.path.realpath(subdir).startswith(os.path.realpath(rootdir)):
1478 raise UnpackError("subdir argument isn't a subdirectory of unpack root %s" % rootdir, urldata.url)
1479 unpackdir = subdir
1480 else:
1481 unpackdir = os.path.join(rootdir, subdir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001482 bb.utils.mkdirhier(unpackdir)
1483 else:
1484 unpackdir = rootdir
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001485
1486 if not unpack or not cmd:
1487 # If file == dest, then avoid any copies, as we already put the file into dest!
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001488 dest = os.path.join(unpackdir, os.path.basename(file))
1489 if file != dest and not (os.path.exists(dest) and os.path.samefile(file, dest)):
1490 destdir = '.'
1491 # For file:// entries all intermediate dirs in path must be created at destination
1492 if urldata.type == "file":
1493 # Trailing '/' does a copying to wrong place
1494 urlpath = urldata.path.rstrip('/')
1495 # Want files places relative to cwd so no leading '/'
1496 urlpath = urlpath.lstrip('/')
1497 if urlpath.find("/") != -1:
1498 destdir = urlpath.rsplit("/", 1)[0] + '/'
1499 bb.utils.mkdirhier("%s/%s" % (unpackdir, destdir))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001500 cmd = 'cp -fpPRH %s %s' % (file, destdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001501
1502 if not cmd:
1503 return
1504
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001505 path = data.getVar('PATH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001506 if path:
1507 cmd = "PATH=\"%s\" %s" % (path, cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001508 bb.note("Unpacking %s to %s/" % (file, unpackdir))
1509 ret = subprocess.call(cmd, preexec_fn=subprocess_setup, shell=True, cwd=unpackdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001510
1511 if ret != 0:
1512 raise UnpackError("Unpack command %s failed with return value %s" % (cmd, ret), urldata.url)
1513
1514 if iterate is True:
1515 iterate_urldata = urldata
1516 iterate_urldata.localpath = "%s/%s" % (rootdir, iterate_file)
1517 self.unpack(urldata, rootdir, data)
1518
1519 return
1520
1521 def clean(self, urldata, d):
1522 """
1523 Clean any existing full or partial download
1524 """
1525 bb.utils.remove(urldata.localpath)
1526
1527 def try_premirror(self, urldata, d):
1528 """
1529 Should premirrors be used?
1530 """
1531 return True
1532
1533 def checkstatus(self, fetch, urldata, d):
1534 """
1535 Check the status of a URL
1536 Assumes localpath was called first
1537 """
1538 logger.info("URL %s could not be checked for status since no method exists.", url)
1539 return True
1540
1541 def latest_revision(self, ud, d, name):
1542 """
1543 Look in the cache for the latest revision, if not present ask the SCM.
1544 """
1545 if not hasattr(self, "_latest_revision"):
1546 raise ParameterError("The fetcher for this URL does not support _latest_revision", url)
1547
1548 revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
1549 key = self.generate_revision_key(ud, d, name)
1550 try:
1551 return revs[key]
1552 except KeyError:
1553 revs[key] = rev = self._latest_revision(ud, d, name)
1554 return rev
1555
1556 def sortable_revision(self, ud, d, name):
1557 latest_rev = self._build_revision(ud, d, name)
1558 return True, str(latest_rev)
1559
1560 def generate_revision_key(self, ud, d, name):
1561 key = self._revision_key(ud, d, name)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001562 return "%s-%s" % (key, d.getVar("PN") or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001563
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001564 def latest_versionstring(self, ud, d):
1565 """
1566 Compute the latest release name like "x.y.x" in "x.y.x+gitHASH"
1567 by searching through the tags output of ls-remote, comparing
1568 versions and returning the highest match as a (version, revision) pair.
1569 """
1570 return ('', '')
1571
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001572class Fetch(object):
1573 def __init__(self, urls, d, cache = True, localonly = False, connection_cache = None):
1574 if localonly and cache:
1575 raise Exception("bb.fetch2.Fetch.__init__: cannot set cache and localonly at same time")
1576
1577 if len(urls) == 0:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001578 urls = d.getVar("SRC_URI").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001579 self.urls = urls
1580 self.d = d
1581 self.ud = {}
1582 self.connection_cache = connection_cache
1583
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001584 fn = d.getVar('FILE')
1585 mc = d.getVar('__BBMULTICONFIG') or ""
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001586 if cache and fn and mc + fn in urldata_cache:
1587 self.ud = urldata_cache[mc + fn]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001588
1589 for url in urls:
1590 if url not in self.ud:
1591 try:
1592 self.ud[url] = FetchData(url, d, localonly)
1593 except NonLocalMethod:
1594 if localonly:
1595 self.ud[url] = None
1596 pass
1597
1598 if fn and cache:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001599 urldata_cache[mc + fn] = self.ud
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001600
1601 def localpath(self, url):
1602 if url not in self.urls:
1603 self.ud[url] = FetchData(url, self.d)
1604
1605 self.ud[url].setup_localpath(self.d)
1606 return self.d.expand(self.ud[url].localpath)
1607
1608 def localpaths(self):
1609 """
1610 Return a list of the local filenames, assuming successful fetch
1611 """
1612 local = []
1613
1614 for u in self.urls:
1615 ud = self.ud[u]
1616 ud.setup_localpath(self.d)
1617 local.append(ud.localpath)
1618
1619 return local
1620
1621 def download(self, urls=None):
1622 """
1623 Fetch all urls
1624 """
1625 if not urls:
1626 urls = self.urls
1627
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001628 network = self.d.getVar("BB_NO_NETWORK")
1629 premirroronly = (self.d.getVar("BB_FETCH_PREMIRRORONLY") == "1")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001630
1631 for u in urls:
1632 ud = self.ud[u]
1633 ud.setup_localpath(self.d)
1634 m = ud.method
1635 localpath = ""
1636
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001637 if ud.lockfile:
1638 lf = bb.utils.lockfile(ud.lockfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001639
1640 try:
1641 self.d.setVar("BB_NO_NETWORK", network)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001642
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001643 if verify_donestamp(ud, self.d) and not m.need_update(ud, self.d):
1644 localpath = ud.localpath
1645 elif m.try_premirror(ud, self.d):
1646 logger.debug(1, "Trying PREMIRRORS")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001647 mirrors = mirror_from_string(self.d.getVar('PREMIRRORS'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001648 localpath = try_mirrors(self, self.d, ud, mirrors, False)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001649 if localpath:
1650 try:
1651 # early checksum verification so that if the checksum of the premirror
1652 # contents mismatch the fetcher can still try upstream and mirrors
1653 update_stamp(ud, self.d)
1654 except ChecksumError as e:
1655 logger.warning("Checksum failure encountered with premirror download of %s - will attempt other sources." % u)
1656 logger.debug(1, str(e))
1657 localpath = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001658
1659 if premirroronly:
1660 self.d.setVar("BB_NO_NETWORK", "1")
1661
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001662 firsterr = None
1663 verified_stamp = verify_donestamp(ud, self.d)
1664 if not localpath and (not verified_stamp or m.need_update(ud, self.d)):
1665 try:
1666 if not trusted_network(self.d, ud.url):
1667 raise UntrustedUrl(ud.url)
1668 logger.debug(1, "Trying Upstream")
1669 m.download(ud, self.d)
1670 if hasattr(m, "build_mirror_data"):
1671 m.build_mirror_data(ud, self.d)
1672 localpath = ud.localpath
1673 # early checksum verify, so that if checksum mismatched,
1674 # fetcher still have chance to fetch from mirror
1675 update_stamp(ud, self.d)
1676
1677 except bb.fetch2.NetworkAccess:
1678 raise
1679
1680 except BBFetchException as e:
1681 if isinstance(e, ChecksumError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001682 logger.warning("Checksum failure encountered with download of %s - will attempt other sources if available" % u)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001683 logger.debug(1, str(e))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001684 if os.path.exists(ud.localpath):
1685 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001686 elif isinstance(e, NoChecksumError):
1687 raise
1688 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001689 logger.warning('Failed to fetch URL %s, attempting MIRRORS if available' % u)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001690 logger.debug(1, str(e))
1691 firsterr = e
1692 # Remove any incomplete fetch
1693 if not verified_stamp:
1694 m.clean(ud, self.d)
1695 logger.debug(1, "Trying MIRRORS")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001696 mirrors = mirror_from_string(self.d.getVar('MIRRORS'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001697 localpath = try_mirrors(self, self.d, ud, mirrors)
1698
1699 if not localpath or ((not os.path.exists(localpath)) and localpath.find("*") == -1):
1700 if firsterr:
1701 logger.error(str(firsterr))
1702 raise FetchError("Unable to fetch URL from any source.", u)
1703
1704 update_stamp(ud, self.d)
1705
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001706 except IOError as e:
1707 if e.errno in [os.errno.ESTALE]:
1708 logger.error("Stale Error Observed %s." % u)
1709 raise ChecksumError("Stale Error Detected")
1710
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001711 except BBFetchException as e:
1712 if isinstance(e, ChecksumError):
1713 logger.error("Checksum failure fetching %s" % u)
1714 raise
1715
1716 finally:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001717 if ud.lockfile:
1718 bb.utils.unlockfile(lf)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001719
1720 def checkstatus(self, urls=None):
1721 """
1722 Check all urls exist upstream
1723 """
1724
1725 if not urls:
1726 urls = self.urls
1727
1728 for u in urls:
1729 ud = self.ud[u]
1730 ud.setup_localpath(self.d)
1731 m = ud.method
1732 logger.debug(1, "Testing URL %s", u)
1733 # First try checking uri, u, from PREMIRRORS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001734 mirrors = mirror_from_string(self.d.getVar('PREMIRRORS'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001735 ret = try_mirrors(self, self.d, ud, mirrors, True)
1736 if not ret:
1737 # Next try checking from the original uri, u
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001738 ret = m.checkstatus(self, ud, self.d)
1739 if not ret:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001740 # Finally, try checking uri, u, from MIRRORS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001741 mirrors = mirror_from_string(self.d.getVar('MIRRORS'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001742 ret = try_mirrors(self, self.d, ud, mirrors, True)
1743
1744 if not ret:
1745 raise FetchError("URL %s doesn't work" % u, u)
1746
1747 def unpack(self, root, urls=None):
1748 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001749 Unpack urls to root
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001750 """
1751
1752 if not urls:
1753 urls = self.urls
1754
1755 for u in urls:
1756 ud = self.ud[u]
1757 ud.setup_localpath(self.d)
1758
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001759 if ud.lockfile:
1760 lf = bb.utils.lockfile(ud.lockfile)
1761
1762 ud.method.unpack(ud, root, self.d)
1763
1764 if ud.lockfile:
1765 bb.utils.unlockfile(lf)
1766
1767 def clean(self, urls=None):
1768 """
1769 Clean files that the fetcher gets or places
1770 """
1771
1772 if not urls:
1773 urls = self.urls
1774
1775 for url in urls:
1776 if url not in self.ud:
1777 self.ud[url] = FetchData(url, d)
1778 ud = self.ud[url]
1779 ud.setup_localpath(self.d)
1780
1781 if not ud.localfile and ud.localpath is None:
1782 continue
1783
1784 if ud.lockfile:
1785 lf = bb.utils.lockfile(ud.lockfile)
1786
1787 ud.method.clean(ud, self.d)
1788 if ud.donestamp:
1789 bb.utils.remove(ud.donestamp)
1790
1791 if ud.lockfile:
1792 bb.utils.unlockfile(lf)
1793
1794class FetchConnectionCache(object):
1795 """
1796 A class which represents an container for socket connections.
1797 """
1798 def __init__(self):
1799 self.cache = {}
1800
1801 def get_connection_name(self, host, port):
1802 return host + ':' + str(port)
1803
1804 def add_connection(self, host, port, connection):
1805 cn = self.get_connection_name(host, port)
1806
1807 if cn not in self.cache:
1808 self.cache[cn] = connection
1809
1810 def get_connection(self, host, port):
1811 connection = None
1812
1813 cn = self.get_connection_name(host, port)
1814 if cn in self.cache:
1815 connection = self.cache[cn]
1816
1817 return connection
1818
1819 def remove_connection(self, host, port):
1820 cn = self.get_connection_name(host, port)
1821 if cn in self.cache:
1822 self.cache[cn].close()
1823 del self.cache[cn]
1824
1825 def close_connections(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001826 for cn in list(self.cache.keys()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001827 self.cache[cn].close()
1828 del self.cache[cn]
1829
1830from . import cvs
1831from . import git
1832from . import gitsm
1833from . import gitannex
1834from . import local
1835from . import svn
1836from . import wget
1837from . import ssh
1838from . import sftp
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001839from . import s3
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001840from . import perforce
1841from . import bzr
1842from . import hg
1843from . import osc
1844from . import repo
1845from . import clearcase
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001846from . import npm
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001847
1848methods.append(local.Local())
1849methods.append(wget.Wget())
1850methods.append(svn.Svn())
1851methods.append(git.Git())
1852methods.append(gitsm.GitSM())
1853methods.append(gitannex.GitANNEX())
1854methods.append(cvs.Cvs())
1855methods.append(ssh.SSH())
1856methods.append(sftp.SFTP())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001857methods.append(s3.S3())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001858methods.append(perforce.Perforce())
1859methods.append(bzr.Bzr())
1860methods.append(hg.Hg())
1861methods.append(osc.Osc())
1862methods.append(repo.Repo())
1863methods.append(clearcase.ClearCase())
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001864methods.append(npm.Npm())