blob: 1a86d8fd814ceaf6ce2e673bf3d941be8186062c [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001"""
2BitBake 'Fetch' implementations
3
4Classes for obtaining upstream sources for the
5BitBake build tools.
6"""
7
8# Copyright (C) 2003, 2004 Chris Larson
9# Copyright (C) 2012 Intel Corporation
10#
Brad Bishopc342db32019-05-15 21:57:59 -040011# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -050012#
13# Based on functions from the base bb module, Copyright 2003 Holger Schurig
14
Patrick Williamsc124f4f2015-09-15 14:41:29 -050015import os, re
16import signal
Patrick Williamsc124f4f2015-09-15 14:41:29 -050017import logging
Patrick Williamsc0f7c042017-02-23 20:41:17 -060018import urllib.request, urllib.parse, urllib.error
19if 'git' not in urllib.parse.uses_netloc:
20 urllib.parse.uses_netloc.append('git')
21import operator
22import collections
23import subprocess
24import pickle
Brad Bishop6e60e8b2018-02-01 10:27:11 -050025import errno
Patrick Williamsc124f4f2015-09-15 14:41:29 -050026import bb.persist_data, bb.utils
27import bb.checksum
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028import bb.process
Brad Bishopd7bf8c12018-02-25 22:55:05 -050029import bb.event
Patrick Williamsc124f4f2015-09-15 14:41:29 -050030
31__version__ = "2"
32_checksum_cache = bb.checksum.FileChecksumCache()
33
34logger = logging.getLogger("BitBake.Fetcher")
35
Andrew Geissler82c905d2020-04-13 13:39:40 -050036CHECKSUM_LIST = [ "md5", "sha256", "sha1", "sha384", "sha512" ]
37SHOWN_CHECKSUM_LIST = ["sha256"]
38
Patrick Williamsc124f4f2015-09-15 14:41:29 -050039class BBFetchException(Exception):
40 """Class all fetch exceptions inherit from"""
41 def __init__(self, message):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050042 self.msg = message
43 Exception.__init__(self, message)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050044
45 def __str__(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050046 return self.msg
Patrick Williamsc124f4f2015-09-15 14:41:29 -050047
48class UntrustedUrl(BBFetchException):
49 """Exception raised when encountering a host not listed in BB_ALLOWED_NETWORKS"""
50 def __init__(self, url, message=''):
51 if message:
52 msg = message
53 else:
54 msg = "The URL: '%s' is not trusted and cannot be used" % url
55 self.url = url
56 BBFetchException.__init__(self, msg)
57 self.args = (url,)
58
59class MalformedUrl(BBFetchException):
60 """Exception raised when encountering an invalid url"""
61 def __init__(self, url, message=''):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050062 if message:
63 msg = message
64 else:
65 msg = "The URL: '%s' is invalid and cannot be interpreted" % url
66 self.url = url
67 BBFetchException.__init__(self, msg)
68 self.args = (url,)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050069
70class FetchError(BBFetchException):
71 """General fetcher exception when something happens incorrectly"""
72 def __init__(self, message, url = None):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050073 if url:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050074 msg = "Fetcher failure for URL: '%s'. %s" % (url, message)
Brad Bishopd7bf8c12018-02-25 22:55:05 -050075 else:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050076 msg = "Fetcher failure: %s" % message
Brad Bishopd7bf8c12018-02-25 22:55:05 -050077 self.url = url
78 BBFetchException.__init__(self, msg)
79 self.args = (message, url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050080
81class ChecksumError(FetchError):
82 """Exception when mismatched checksum encountered"""
83 def __init__(self, message, url = None, checksum = None):
84 self.checksum = checksum
85 FetchError.__init__(self, message, url)
86
87class NoChecksumError(FetchError):
88 """Exception when no checksum is specified, but BB_STRICT_CHECKSUM is set"""
89
90class UnpackError(BBFetchException):
91 """General fetcher exception when something happens incorrectly when unpacking"""
92 def __init__(self, message, url):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050093 msg = "Unpack failure for URL: '%s'. %s" % (url, message)
94 self.url = url
95 BBFetchException.__init__(self, msg)
96 self.args = (message, url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050097
98class NoMethodError(BBFetchException):
99 """Exception raised when there is no method to obtain a supplied url or set of urls"""
100 def __init__(self, url):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500101 msg = "Could not find a fetcher which supports the URL: '%s'" % url
102 self.url = url
103 BBFetchException.__init__(self, msg)
104 self.args = (url,)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500105
106class MissingParameterError(BBFetchException):
107 """Exception raised when a fetch method is missing a critical parameter in the url"""
108 def __init__(self, missing, url):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500109 msg = "URL: '%s' is missing the required parameter '%s'" % (url, missing)
110 self.url = url
111 self.missing = missing
112 BBFetchException.__init__(self, msg)
113 self.args = (missing, url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500114
115class ParameterError(BBFetchException):
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000116 """Exception raised when a url cannot be processed due to invalid parameters."""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117 def __init__(self, message, url):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500118 msg = "URL: '%s' has invalid parameters. %s" % (url, message)
119 self.url = url
120 BBFetchException.__init__(self, msg)
121 self.args = (message, url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500122
123class NetworkAccess(BBFetchException):
124 """Exception raised when network access is disabled but it is required."""
125 def __init__(self, url, cmd):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500126 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)
127 self.url = url
128 self.cmd = cmd
129 BBFetchException.__init__(self, msg)
130 self.args = (url, cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500131
132class NonLocalMethod(Exception):
133 def __init__(self):
134 Exception.__init__(self)
135
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500136class MissingChecksumEvent(bb.event.Event):
Andrew Geissler82c905d2020-04-13 13:39:40 -0500137 def __init__(self, url, **checksums):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500138 self.url = url
Andrew Geissler82c905d2020-04-13 13:39:40 -0500139 self.checksums = checksums
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500140 bb.event.Event.__init__(self)
141
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500142
143class URI(object):
144 """
145 A class representing a generic URI, with methods for
146 accessing the URI components, and stringifies to the
147 URI.
148
149 It is constructed by calling it with a URI, or setting
150 the attributes manually:
151
152 uri = URI("http://example.com/")
153
154 uri = URI()
155 uri.scheme = 'http'
156 uri.hostname = 'example.com'
157 uri.path = '/'
158
159 It has the following attributes:
160
161 * scheme (read/write)
162 * userinfo (authentication information) (read/write)
163 * username (read/write)
164 * password (read/write)
165
166 Note, password is deprecated as of RFC 3986.
167
168 * hostname (read/write)
169 * port (read/write)
170 * hostport (read only)
171 "hostname:port", if both are set, otherwise just "hostname"
172 * path (read/write)
173 * path_quoted (read/write)
174 A URI quoted version of path
175 * params (dict) (read/write)
176 * query (dict) (read/write)
177 * relative (bool) (read only)
178 True if this is a "relative URI", (e.g. file:foo.diff)
179
180 It stringifies to the URI itself.
181
182 Some notes about relative URIs: while it's specified that
183 a URI beginning with <scheme>:// should either be directly
184 followed by a hostname or a /, the old URI handling of the
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000185 fetch2 library did not conform to this. Therefore, this URI
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500186 class has some kludges to make sure that URIs are parsed in
187 a way comforming to bitbake's current usage. This URI class
188 supports the following:
189
190 file:relative/path.diff (IETF compliant)
191 git:relative/path.git (IETF compliant)
192 git:///absolute/path.git (IETF compliant)
193 file:///absolute/path.diff (IETF compliant)
194
195 file://relative/path.diff (not IETF compliant)
196
197 But it does not support the following:
198
199 file://hostname/absolute/path.diff (would be IETF compliant)
200
201 Note that the last case only applies to a list of
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000202 explicitly allowed schemes (currently only file://), that requires
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500203 its URIs to not have a network location.
204 """
205
206 _relative_schemes = ['file', 'git']
207 _netloc_forbidden = ['file']
208
209 def __init__(self, uri=None):
210 self.scheme = ''
211 self.userinfo = ''
212 self.hostname = ''
213 self.port = None
214 self._path = ''
215 self.params = {}
216 self.query = {}
217 self.relative = False
218
219 if not uri:
220 return
221
222 # We hijack the URL parameters, since the way bitbake uses
223 # them are not quite RFC compliant.
224 uri, param_str = (uri.split(";", 1) + [None])[:2]
225
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600226 urlp = urllib.parse.urlparse(uri)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500227 self.scheme = urlp.scheme
228
229 reparse = 0
230
231 # Coerce urlparse to make URI scheme use netloc
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600232 if not self.scheme in urllib.parse.uses_netloc:
233 urllib.parse.uses_params.append(self.scheme)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500234 reparse = 1
235
236 # Make urlparse happy(/ier) by converting local resources
237 # to RFC compliant URL format. E.g.:
238 # file://foo.diff -> file:foo.diff
239 if urlp.scheme in self._netloc_forbidden:
240 uri = re.sub("(?<=:)//(?!/)", "", uri, 1)
241 reparse = 1
242
243 if reparse:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600244 urlp = urllib.parse.urlparse(uri)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500245
246 # Identify if the URI is relative or not
247 if urlp.scheme in self._relative_schemes and \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800248 re.compile(r"^\w+:(?!//)").match(uri):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500249 self.relative = True
250
251 if not self.relative:
252 self.hostname = urlp.hostname or ''
253 self.port = urlp.port
254
255 self.userinfo += urlp.username or ''
256
257 if urlp.password:
258 self.userinfo += ':%s' % urlp.password
259
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600260 self.path = urllib.parse.unquote(urlp.path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500261
262 if param_str:
263 self.params = self._param_str_split(param_str, ";")
264 if urlp.query:
265 self.query = self._param_str_split(urlp.query, "&")
266
267 def __str__(self):
268 userinfo = self.userinfo
269 if userinfo:
270 userinfo += '@'
271
272 return "%s:%s%s%s%s%s%s" % (
273 self.scheme,
274 '' if self.relative else '//',
275 userinfo,
276 self.hostport,
277 self.path_quoted,
278 self._query_str(),
279 self._param_str())
280
281 def _param_str(self):
282 return (
283 ''.join([';', self._param_str_join(self.params, ";")])
284 if self.params else '')
285
286 def _query_str(self):
287 return (
288 ''.join(['?', self._param_str_join(self.query, "&")])
289 if self.query else '')
290
291 def _param_str_split(self, string, elmdelim, kvdelim="="):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600292 ret = collections.OrderedDict()
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600293 for k, v in [x.split(kvdelim, 1) for x in string.split(elmdelim) if x]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500294 ret[k] = v
295 return ret
296
297 def _param_str_join(self, dict_, elmdelim, kvdelim="="):
298 return elmdelim.join([kvdelim.join([k, v]) for k, v in dict_.items()])
299
300 @property
301 def hostport(self):
302 if not self.port:
303 return self.hostname
304 return "%s:%d" % (self.hostname, self.port)
305
306 @property
307 def path_quoted(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600308 return urllib.parse.quote(self.path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500309
310 @path_quoted.setter
311 def path_quoted(self, path):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600312 self.path = urllib.parse.unquote(path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500313
314 @property
315 def path(self):
316 return self._path
317
318 @path.setter
319 def path(self, path):
320 self._path = path
321
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500322 if not path or re.compile("^/").match(path):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500323 self.relative = False
324 else:
325 self.relative = True
326
327 @property
328 def username(self):
329 if self.userinfo:
330 return (self.userinfo.split(":", 1))[0]
331 return ''
332
333 @username.setter
334 def username(self, username):
335 password = self.password
336 self.userinfo = username
337 if password:
338 self.userinfo += ":%s" % password
339
340 @property
341 def password(self):
342 if self.userinfo and ":" in self.userinfo:
343 return (self.userinfo.split(":", 1))[1]
344 return ''
345
346 @password.setter
347 def password(self, password):
348 self.userinfo = "%s:%s" % (self.username, password)
349
350def decodeurl(url):
351 """Decodes an URL into the tokens (scheme, network location, path,
352 user, password, parameters).
353 """
354
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500355 m = re.compile('(?P<type>[^:]*)://((?P<user>[^/;]+)@)?(?P<location>[^;]+)(;(?P<parm>.*))?').match(url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500356 if not m:
357 raise MalformedUrl(url)
358
359 type = m.group('type')
360 location = m.group('location')
361 if not location:
362 raise MalformedUrl(url)
363 user = m.group('user')
364 parm = m.group('parm')
365
366 locidx = location.find('/')
367 if locidx != -1 and type.lower() != 'file':
368 host = location[:locidx]
369 path = location[locidx:]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500370 elif type.lower() == 'file':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500371 host = ""
372 path = location
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500373 else:
374 host = location
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800375 path = "/"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500376 if user:
377 m = re.compile('(?P<user>[^:]+)(:?(?P<pswd>.*))').match(user)
378 if m:
379 user = m.group('user')
380 pswd = m.group('pswd')
381 else:
382 user = ''
383 pswd = ''
384
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600385 p = collections.OrderedDict()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500386 if parm:
387 for s in parm.split(';'):
388 if s:
389 if not '=' in s:
390 raise MalformedUrl(url, "The URL: '%s' is invalid: parameter %s does not specify a value (missing '=')" % (url, s))
391 s1, s2 = s.split('=')
392 p[s1] = s2
393
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600394 return type, host, urllib.parse.unquote(path), user, pswd, p
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500395
396def encodeurl(decoded):
397 """Encodes a URL from tokens (scheme, network location, path,
398 user, password, parameters).
399 """
400
401 type, host, path, user, pswd, p = decoded
402
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403 if not type:
404 raise MissingParameterError('type', "encoded from the data %s" % str(decoded))
Andrew Geissler595f6302022-01-24 19:11:47 +0000405 url = ['%s://' % type]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500406 if user and type != "file":
Andrew Geissler595f6302022-01-24 19:11:47 +0000407 url.append("%s" % user)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500408 if pswd:
Andrew Geissler595f6302022-01-24 19:11:47 +0000409 url.append(":%s" % pswd)
410 url.append("@")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500411 if host and type != "file":
Andrew Geissler595f6302022-01-24 19:11:47 +0000412 url.append("%s" % host)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500413 if path:
414 # Standardise path to ensure comparisons work
415 while '//' in path:
416 path = path.replace("//", "/")
Andrew Geissler595f6302022-01-24 19:11:47 +0000417 url.append("%s" % urllib.parse.quote(path))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500418 if p:
419 for parm in p:
Andrew Geissler595f6302022-01-24 19:11:47 +0000420 url.append(";%s=%s" % (parm, p[parm]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500421
Andrew Geissler595f6302022-01-24 19:11:47 +0000422 return "".join(url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500423
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500424def uri_replace(ud, uri_find, uri_replace, replacements, d, mirrortarball=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500425 if not ud.url or not uri_find or not uri_replace:
426 logger.error("uri_replace: passed an undefined value, not replacing")
427 return None
428 uri_decoded = list(decodeurl(ud.url))
429 uri_find_decoded = list(decodeurl(uri_find))
430 uri_replace_decoded = list(decodeurl(uri_replace))
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600431 logger.debug2("For url %s comparing %s to %s" % (uri_decoded, uri_find_decoded, uri_replace_decoded))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500432 result_decoded = ['', '', '', '', '', {}]
Andrew Geissler595f6302022-01-24 19:11:47 +0000433 # 0 - type, 1 - host, 2 - path, 3 - user, 4- pswd, 5 - params
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500434 for loc, i in enumerate(uri_find_decoded):
435 result_decoded[loc] = uri_decoded[loc]
436 regexp = i
437 if loc == 0 and regexp and not regexp.endswith("$"):
438 # Leaving the type unanchored can mean "https" matching "file" can become "files"
439 # which is clearly undesirable.
440 regexp += "$"
441 if loc == 5:
442 # Handle URL parameters
443 if i:
444 # Any specified URL parameters must match
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800445 for k in uri_find_decoded[loc]:
446 if uri_decoded[loc][k] != uri_find_decoded[loc][k]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500447 return None
448 # Overwrite any specified replacement parameters
449 for k in uri_replace_decoded[loc]:
450 for l in replacements:
451 uri_replace_decoded[loc][k] = uri_replace_decoded[loc][k].replace(l, replacements[l])
452 result_decoded[loc][k] = uri_replace_decoded[loc][k]
Andrew Geissler595f6302022-01-24 19:11:47 +0000453 elif (loc == 3 or loc == 4) and uri_replace_decoded[loc]:
454 # User/password in the replacement is just a straight replacement
455 result_decoded[loc] = uri_replace_decoded[loc]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500456 elif (re.match(regexp, uri_decoded[loc])):
457 if not uri_replace_decoded[loc]:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500458 result_decoded[loc] = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500459 else:
460 for k in replacements:
461 uri_replace_decoded[loc] = uri_replace_decoded[loc].replace(k, replacements[k])
462 #bb.note("%s %s %s" % (regexp, uri_replace_decoded[loc], uri_decoded[loc]))
Patrick Williamsd7e96312015-09-22 08:09:05 -0500463 result_decoded[loc] = re.sub(regexp, uri_replace_decoded[loc], uri_decoded[loc], 1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500464 if loc == 2:
465 # Handle path manipulations
466 basename = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500467 if uri_decoded[0] != uri_replace_decoded[0] and mirrortarball:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500468 # If the source and destination url types differ, must be a mirrortarball mapping
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500469 basename = os.path.basename(mirrortarball)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500470 # Kill parameters, they make no sense for mirror tarballs
471 uri_decoded[5] = {}
Andrew Geisslerc5535c92023-01-27 16:10:19 -0600472 uri_find_decoded[5] = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500473 elif ud.localpath and ud.method.supports_checksum(ud):
Andrew Geissler595f6302022-01-24 19:11:47 +0000474 basename = os.path.basename(ud.localpath)
475 if basename:
476 uri_basename = os.path.basename(uri_decoded[loc])
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000477 # Prefix with a slash as a sentinel in case
478 # result_decoded[loc] does not contain one.
479 path = "/" + result_decoded[loc]
480 if uri_basename and basename != uri_basename and path.endswith("/" + uri_basename):
481 result_decoded[loc] = path[1:-len(uri_basename)] + basename
482 elif not path.endswith("/" + basename):
483 result_decoded[loc] = os.path.join(path[1:], basename)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500484 else:
485 return None
486 result = encodeurl(result_decoded)
487 if result == ud.url:
488 return None
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600489 logger.debug2("For url %s returning %s" % (ud.url, result))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500490 return result
491
492methods = []
493urldata_cache = {}
494saved_headrevs = {}
495
496def fetcher_init(d):
497 """
498 Called to initialize the fetchers once the configuration data is known.
499 Calls before this must not hit the cache.
500 """
Andrew Geissler82c905d2020-04-13 13:39:40 -0500501
502 revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
503 try:
504 # fetcher_init is called multiple times, so make sure we only save the
505 # revs the first time it is called.
506 if not bb.fetch2.saved_headrevs:
507 bb.fetch2.saved_headrevs = dict(revs)
508 except:
509 pass
510
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500511 # When to drop SCM head revisions controlled by user policy
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500512 srcrev_policy = d.getVar('BB_SRCREV_POLICY') or "clear"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500513 if srcrev_policy == "cache":
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600514 logger.debug("Keeping SRCREV cache due to cache policy of: %s", srcrev_policy)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500515 elif srcrev_policy == "clear":
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600516 logger.debug("Clearing SRCREV cache due to cache policy of: %s", srcrev_policy)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500517 revs.clear()
518 else:
519 raise FetchError("Invalid SRCREV cache policy of: %s" % srcrev_policy)
520
Andrew Geisslerc5535c92023-01-27 16:10:19 -0600521 _checksum_cache.init_cache(d.getVar("BB_CACHEDIR"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500522
523 for m in methods:
524 if hasattr(m, "init"):
525 m.init(d)
526
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500527def fetcher_parse_save():
528 _checksum_cache.save_extras()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500529
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500530def fetcher_parse_done():
531 _checksum_cache.save_merge()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500532
Brad Bishop19323692019-04-05 15:28:33 -0400533def fetcher_compare_revisions(d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500534 """
Andrew Geissler82c905d2020-04-13 13:39:40 -0500535 Compare the revisions in the persistent cache with the saved values from
536 when bitbake was started and return true if they have changed.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500537 """
538
Andrew Geissler82c905d2020-04-13 13:39:40 -0500539 headrevs = dict(bb.persist_data.persist('BB_URI_HEADREVS', d))
540 return headrevs != bb.fetch2.saved_headrevs
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500541
542def mirror_from_string(data):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500543 mirrors = (data or "").replace('\\n',' ').split()
544 # Split into pairs
545 if len(mirrors) % 2 != 0:
546 bb.warn('Invalid mirror data %s, should have paired members.' % data)
547 return list(zip(*[iter(mirrors)]*2))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500548
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500549def verify_checksum(ud, d, precomputed={}, localpath=None, fatal_nochecksum=True):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500550 """
551 verify the MD5 and SHA256 checksum for downloaded src
552
553 Raises a FetchError if one or both of the SRC_URI checksums do not match
554 the downloaded file, or if BB_STRICT_CHECKSUM is set and there are no
555 checksums specified.
556
557 Returns a dict of checksums that can be stored in a done stamp file and
558 passed in as precomputed parameter in a later call to avoid re-computing
559 the checksums from the file. This allows verifying the checksums of the
560 file against those in the recipe each time, rather than only after
561 downloading. See https://bugzilla.yoctoproject.org/show_bug.cgi?id=5571.
562 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500563 if ud.ignore_checksums or not ud.method.supports_checksum(ud):
564 return {}
565
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500566 if localpath is None:
567 localpath = ud.localpath
568
Andrew Geissler82c905d2020-04-13 13:39:40 -0500569 def compute_checksum_info(checksum_id):
570 checksum_name = getattr(ud, "%s_name" % checksum_id)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500571
Andrew Geissler82c905d2020-04-13 13:39:40 -0500572 if checksum_id in precomputed:
573 checksum_data = precomputed[checksum_id]
574 else:
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500575 checksum_data = getattr(bb.utils, "%s_file" % checksum_id)(localpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500576
Andrew Geissler82c905d2020-04-13 13:39:40 -0500577 checksum_expected = getattr(ud, "%s_expected" % checksum_id)
578
Andrew Geissler09036742021-06-25 14:25:14 -0500579 if checksum_expected == '':
580 checksum_expected = None
581
Andrew Geissler82c905d2020-04-13 13:39:40 -0500582 return {
583 "id": checksum_id,
584 "name": checksum_name,
585 "data": checksum_data,
586 "expected": checksum_expected
587 }
588
589 checksum_infos = []
590 for checksum_id in CHECKSUM_LIST:
591 checksum_infos.append(compute_checksum_info(checksum_id))
592
593 checksum_dict = {ci["id"] : ci["data"] for ci in checksum_infos}
594 checksum_event = {"%ssum" % ci["id"] : ci["data"] for ci in checksum_infos}
595
596 for ci in checksum_infos:
597 if ci["id"] in SHOWN_CHECKSUM_LIST:
598 checksum_lines = ["SRC_URI[%s] = \"%s\"" % (ci["name"], ci["data"])]
599
600 # If no checksum has been provided
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500601 if fatal_nochecksum and ud.method.recommends_checksum(ud) and all(ci["expected"] is None for ci in checksum_infos):
Andrew Geissler82c905d2020-04-13 13:39:40 -0500602 messages = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500603 strict = d.getVar("BB_STRICT_CHECKSUM") or "0"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500604
Andrew Geissler82c905d2020-04-13 13:39:40 -0500605 # If strict checking enabled and neither sum defined, raise error
606 if strict == "1":
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500607 raise NoChecksumError("\n".join(checksum_lines))
Andrew Geissler82c905d2020-04-13 13:39:40 -0500608
609 bb.event.fire(MissingChecksumEvent(ud.url, **checksum_event), d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500610
611 if strict == "ignore":
Andrew Geissler82c905d2020-04-13 13:39:40 -0500612 return checksum_dict
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500613
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500614 # Log missing sums so user can more easily add them
Andrew Geissler82c905d2020-04-13 13:39:40 -0500615 messages.append("Missing checksum for '%s', consider adding at " \
616 "least one to the recipe:" % ud.localpath)
617 messages.extend(checksum_lines)
618 logger.warning("\n".join(messages))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500619
620 # We want to alert the user if a checksum is defined in the recipe but
621 # it does not match.
Andrew Geissler82c905d2020-04-13 13:39:40 -0500622 messages = []
623 messages.append("Checksum mismatch!")
624 bad_checksum = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500625
Andrew Geissler82c905d2020-04-13 13:39:40 -0500626 for ci in checksum_infos:
627 if ci["expected"] and ci["expected"] != ci["data"]:
Andrew Geissler09036742021-06-25 14:25:14 -0500628 messages.append("File: '%s' has %s checksum '%s' when '%s' was " \
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500629 "expected" % (localpath, ci["id"], ci["data"], ci["expected"]))
Andrew Geissler82c905d2020-04-13 13:39:40 -0500630 bad_checksum = ci["data"]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500631
Andrew Geissler82c905d2020-04-13 13:39:40 -0500632 if bad_checksum:
633 messages.append("If this change is expected (e.g. you have upgraded " \
634 "to a new version without updating the checksums) " \
635 "then you can use these lines within the recipe:")
636 messages.extend(checksum_lines)
637 messages.append("Otherwise you should retry the download and/or " \
638 "check with upstream to determine if the file has " \
639 "become corrupted or otherwise unexpectedly modified.")
640 raise ChecksumError("\n".join(messages), ud.url, bad_checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500641
Andrew Geissler82c905d2020-04-13 13:39:40 -0500642 return checksum_dict
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500643
644def verify_donestamp(ud, d, origud=None):
645 """
646 Check whether the done stamp file has the right checksums (if the fetch
647 method supports them). If it doesn't, delete the done stamp and force
648 a re-download.
649
650 Returns True, if the donestamp exists and is valid, False otherwise. When
651 returning False, any existing done stamps are removed.
652 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500653 if not ud.needdonestamp or (origud and not origud.needdonestamp):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500654 return True
655
Brad Bishop316dfdd2018-06-25 12:45:53 -0400656 if not os.path.exists(ud.localpath):
657 # local path does not exist
658 if os.path.exists(ud.donestamp):
659 # done stamp exists, but the downloaded file does not; the done stamp
660 # must be incorrect, re-trigger the download
661 bb.utils.remove(ud.donestamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500662 return False
663
664 if (not ud.method.supports_checksum(ud) or
665 (origud and not origud.method.supports_checksum(origud))):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400666 # if done stamp exists and checksums not supported; assume the local
667 # file is current
668 return os.path.exists(ud.donestamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500669
670 precomputed_checksums = {}
671 # Only re-use the precomputed checksums if the donestamp is newer than the
672 # file. Do not rely on the mtime of directories, though. If ud.localpath is
673 # a directory, there will probably not be any checksums anyway.
Brad Bishop316dfdd2018-06-25 12:45:53 -0400674 if os.path.exists(ud.donestamp) and (os.path.isdir(ud.localpath) or
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500675 os.path.getmtime(ud.localpath) < os.path.getmtime(ud.donestamp)):
676 try:
677 with open(ud.donestamp, "rb") as cachefile:
678 pickled = pickle.Unpickler(cachefile)
679 precomputed_checksums.update(pickled.load())
680 except Exception as e:
681 # Avoid the warnings on the upgrade path from emtpy done stamp
682 # files to those containing the checksums.
683 if not isinstance(e, EOFError):
684 # Ignore errors, they aren't fatal
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600685 logger.warning("Couldn't load checksums from donestamp %s: %s "
686 "(msg: %s)" % (ud.donestamp, type(e).__name__,
687 str(e)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500688
689 try:
690 checksums = verify_checksum(ud, d, precomputed_checksums)
691 # If the cache file did not have the checksums, compute and store them
692 # as an upgrade path from the previous done stamp file format.
693 if checksums != precomputed_checksums:
694 with open(ud.donestamp, "wb") as cachefile:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600695 p = pickle.Pickler(cachefile, 2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500696 p.dump(checksums)
697 return True
698 except ChecksumError as e:
699 # Checksums failed to verify, trigger re-download and remove the
700 # incorrect stamp file.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600701 logger.warning("Checksum mismatch for local file %s\n"
702 "Cleaning and trying again." % ud.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500703 if os.path.exists(ud.localpath):
704 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500705 bb.utils.remove(ud.donestamp)
706 return False
707
708
709def update_stamp(ud, d):
710 """
711 donestamp is file stamp indicating the whole fetching is done
712 this function update the stamp after verifying the checksum
713 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500714 if not ud.needdonestamp:
715 return
716
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500717 if os.path.exists(ud.donestamp):
718 # Touch the done stamp file to show active use of the download
719 try:
720 os.utime(ud.donestamp, None)
721 except:
722 # Errors aren't fatal here
723 pass
724 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500725 try:
726 checksums = verify_checksum(ud, d)
727 # Store the checksums for later re-verification against the recipe
728 with open(ud.donestamp, "wb") as cachefile:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600729 p = pickle.Pickler(cachefile, 2)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500730 p.dump(checksums)
731 except ChecksumError as e:
732 # Checksums failed to verify, trigger re-download and remove the
733 # incorrect stamp file.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600734 logger.warning("Checksum mismatch for local file %s\n"
735 "Cleaning and trying again." % ud.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500736 if os.path.exists(ud.localpath):
737 rename_bad_checksum(ud, e.checksum)
738 bb.utils.remove(ud.donestamp)
739 raise
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500740
741def subprocess_setup():
742 # Python installs a SIGPIPE handler by default. This is usually not what
743 # non-Python subprocesses expect.
744 # SIGPIPE errors are known issues with gzip/bash
745 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
746
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500747def mark_recipe_nocache(d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500748 if d.getVar('BB_SRCREV_POLICY') != "cache":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500749 d.setVar('BB_DONT_CACHE', '1')
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500750
751def get_autorev(d):
752 mark_recipe_nocache(d)
753 d.setVar("__BBAUTOREV_SEEN", True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500754 return "AUTOINC"
755
756def get_srcrev(d, method_name='sortable_revision'):
757 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500758 Return the revision string, usually for use in the version string (PV) of the current package
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500759 Most packages usually only have one SCM so we just pass on the call.
760 In the multi SCM case, we build a value based on SRCREV_FORMAT which must
761 have been set.
762
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500763 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 -0500764 incremental, other code is then responsible for turning that into an increasing value (if needed)
765
766 A method_name can be supplied to retrieve an alternatively formatted revision from a fetcher, if
767 that fetcher provides a method with the given name and the same signature as sortable_revision.
768 """
769
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500770 d.setVar("__BBSRCREV_SEEN", "1")
Andrew Geissler5199d832021-09-24 16:47:35 -0500771 recursion = d.getVar("__BBINSRCREV")
772 if recursion:
773 raise FetchError("There are recursive references in fetcher variables, likely through SRC_URI")
774 d.setVar("__BBINSRCREV", True)
775
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500776 scms = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500777 fetcher = Fetch(d.getVar('SRC_URI').split(), d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500778 urldata = fetcher.ud
779 for u in urldata:
780 if urldata[u].method.supports_srcrev():
781 scms.append(u)
782
Andrew Geissler595f6302022-01-24 19:11:47 +0000783 if not scms:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500784 raise FetchError("SRCREV was used yet no valid SCM was found in SRC_URI")
785
786 if len(scms) == 1 and len(urldata[scms[0]].names) == 1:
787 autoinc, rev = getattr(urldata[scms[0]].method, method_name)(urldata[scms[0]], d, urldata[scms[0]].names[0])
788 if len(rev) > 10:
789 rev = rev[:10]
Andrew Geissler5199d832021-09-24 16:47:35 -0500790 d.delVar("__BBINSRCREV")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500791 if autoinc:
792 return "AUTOINC+" + rev
793 return rev
794
795 #
796 # Mutiple SCMs are in SRC_URI so we resort to SRCREV_FORMAT
797 #
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500798 format = d.getVar('SRCREV_FORMAT')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500799 if not format:
Brad Bishop19323692019-04-05 15:28:33 -0400800 raise FetchError("The SRCREV_FORMAT variable must be set when multiple SCMs are used.\n"\
801 "The SCMs are:\n%s" % '\n'.join(scms))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500802
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600803 name_to_rev = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500804 seenautoinc = False
805 for scm in scms:
806 ud = urldata[scm]
807 for name in ud.names:
808 autoinc, rev = getattr(ud.method, method_name)(ud, d, name)
809 seenautoinc = seenautoinc or autoinc
810 if len(rev) > 10:
811 rev = rev[:10]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600812 name_to_rev[name] = rev
813 # Replace names by revisions in the SRCREV_FORMAT string. The approach used
814 # here can handle names being prefixes of other names and names appearing
815 # as substrings in revisions (in which case the name should not be
816 # expanded). The '|' regular expression operator tries matches from left to
817 # right, so we need to sort the names with the longest ones first.
818 names_descending_len = sorted(name_to_rev, key=len, reverse=True)
819 name_to_rev_re = "|".join(re.escape(name) for name in names_descending_len)
820 format = re.sub(name_to_rev_re, lambda match: name_to_rev[match.group(0)], format)
821
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500822 if seenautoinc:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500823 format = "AUTOINC+" + format
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500824
Andrew Geissler5199d832021-09-24 16:47:35 -0500825 d.delVar("__BBINSRCREV")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500826 return format
827
828def localpath(url, d):
829 fetcher = bb.fetch2.Fetch([url], d)
830 return fetcher.localpath(url)
831
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500832# Need to export PATH as binary could be in metadata paths
833# rather than host provided
834# Also include some other variables.
835FETCH_EXPORT_VARS = ['HOME', 'PATH',
836 'HTTP_PROXY', 'http_proxy',
837 'HTTPS_PROXY', 'https_proxy',
838 'FTP_PROXY', 'ftp_proxy',
839 'FTPS_PROXY', 'ftps_proxy',
840 'NO_PROXY', 'no_proxy',
841 'ALL_PROXY', 'all_proxy',
842 'GIT_PROXY_COMMAND',
843 'GIT_SSH',
Patrick Williams03907ee2022-05-01 06:28:52 -0500844 'GIT_SSH_COMMAND',
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500845 'GIT_SSL_CAINFO',
846 'GIT_SMART_HTTP',
847 'SSH_AUTH_SOCK', 'SSH_AGENT_PID',
848 'SOCKS5_USER', 'SOCKS5_PASSWD',
849 'DBUS_SESSION_BUS_ADDRESS',
850 'P4CONFIG',
851 'SSL_CERT_FILE',
Patrick Williams864cc432023-02-09 14:54:44 -0600852 'NODE_EXTRA_CA_CERTS',
Andrew Geissler5199d832021-09-24 16:47:35 -0500853 'AWS_PROFILE',
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500854 'AWS_ACCESS_KEY_ID',
855 'AWS_SECRET_ACCESS_KEY',
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600856 'AWS_DEFAULT_REGION',
857 'GIT_CACHE_PATH',
858 'SSL_CERT_DIR']
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500859
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000860def get_fetcher_environment(d):
861 newenv = {}
862 origenv = d.getVar("BB_ORIGENV")
863 for name in bb.fetch2.FETCH_EXPORT_VARS:
864 value = d.getVar(name)
865 if not value and origenv:
866 value = origenv.getVar(name)
867 if value:
868 newenv[name] = value
869 return newenv
870
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600871def runfetchcmd(cmd, d, quiet=False, cleanup=None, log=None, workdir=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500872 """
873 Run cmd returning the command output
874 Raise an error if interrupted or cmd fails
875 Optionally echo command output to stdout
876 Optionally remove the files/directories listed in cleanup upon failure
877 """
878
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500879 exportvars = FETCH_EXPORT_VARS
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500880
881 if not cleanup:
882 cleanup = []
883
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800884 # If PATH contains WORKDIR which contains PV-PR which contains SRCPV we
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500885 # can end up in circular recursion here so give the option of breaking it
886 # in a data store copy.
887 try:
888 d.getVar("PV")
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800889 d.getVar("PR")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500890 except bb.data_smart.ExpansionError:
891 d = bb.data.createCopy(d)
892 d.setVar("PV", "fetcheravoidrecurse")
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800893 d.setVar("PR", "fetcheravoidrecurse")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500894
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600895 origenv = d.getVar("BB_ORIGENV", False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500896 for var in exportvars:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500897 val = d.getVar(var) or (origenv and origenv.getVar(var))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500898 if val:
899 cmd = 'export ' + var + '=\"%s\"; %s' % (val, cmd)
900
Brad Bishop316dfdd2018-06-25 12:45:53 -0400901 # Disable pseudo as it may affect ssh, potentially causing it to hang.
902 cmd = 'export PSEUDO_DISABLED=1; ' + cmd
903
Brad Bishop19323692019-04-05 15:28:33 -0400904 if workdir:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600905 logger.debug("Running '%s' in %s" % (cmd, workdir))
Brad Bishop19323692019-04-05 15:28:33 -0400906 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600907 logger.debug("Running %s", cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500908
909 success = False
910 error_message = ""
911
912 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600913 (output, errors) = bb.process.run(cmd, log=log, shell=True, stderr=subprocess.PIPE, cwd=workdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500914 success = True
915 except bb.process.NotFoundError as e:
Andrew Geisslereff27472021-10-29 15:35:00 -0500916 error_message = "Fetch command %s not found" % (e.command)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500917 except bb.process.ExecutionError as e:
918 if e.stdout:
919 output = "output:\n%s\n%s" % (e.stdout, e.stderr)
920 elif e.stderr:
921 output = "output:\n%s" % e.stderr
922 else:
923 output = "no output"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600924 error_message = "Fetch command %s failed with exit code %s, %s" % (e.command, e.exitcode, output)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500925 except bb.process.CmdError as e:
926 error_message = "Fetch command %s could not be run:\n%s" % (e.command, e.msg)
927 if not success:
928 for f in cleanup:
929 try:
930 bb.utils.remove(f, True)
931 except OSError:
932 pass
933
934 raise FetchError(error_message)
935
936 return output
937
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500938def check_network_access(d, info, url):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500939 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500940 log remote network access, and error if BB_NO_NETWORK is set or the given
941 URI is untrusted
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500942 """
Brad Bishop19323692019-04-05 15:28:33 -0400943 if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500944 raise NetworkAccess(url, info)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500945 elif not trusted_network(d, url):
946 raise UntrustedUrl(url, info)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500947 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600948 logger.debug("Fetcher accessed the network with the command %s" % info)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500949
950def build_mirroruris(origud, mirrors, ld):
951 uris = []
952 uds = []
953
954 replacements = {}
955 replacements["TYPE"] = origud.type
956 replacements["HOST"] = origud.host
957 replacements["PATH"] = origud.path
958 replacements["BASENAME"] = origud.path.split("/")[-1]
959 replacements["MIRRORNAME"] = origud.host.replace(':','.') + origud.path.replace('/', '.').replace('*', '.')
960
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500961 def adduri(ud, uris, uds, mirrors, tarballs):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500962 for line in mirrors:
963 try:
964 (find, replace) = line
965 except ValueError:
966 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500967
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500968 for tarball in tarballs:
969 newuri = uri_replace(ud, find, replace, replacements, ld, tarball)
970 if not newuri or newuri in uris or newuri == origud.url:
971 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500972
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500973 if not trusted_network(ld, newuri):
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600974 logger.debug("Mirror %s not in the list of trusted networks, skipping" % (newuri))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500975 continue
Patrick Williamsd7e96312015-09-22 08:09:05 -0500976
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500977 # Create a local copy of the mirrors minus the current line
978 # this will prevent us from recursively processing the same line
979 # as well as indirect recursion A -> B -> C -> A
980 localmirrors = list(mirrors)
981 localmirrors.remove(line)
982
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500983 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500984 newud = FetchData(newuri, ld)
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500985 newud.ignore_checksums = True
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500986 newud.setup_localpath(ld)
987 except bb.fetch2.BBFetchException as e:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600988 logger.debug("Mirror fetch failure for url %s (original url: %s)" % (newuri, origud.url))
989 logger.debug(str(e))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500990 try:
991 # setup_localpath of file:// urls may fail, we should still see
992 # if mirrors of the url exist
993 adduri(newud, uris, uds, localmirrors, tarballs)
994 except UnboundLocalError:
995 pass
996 continue
997 uris.append(newuri)
998 uds.append(newud)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500999
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001000 adduri(newud, uris, uds, localmirrors, tarballs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001001
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001002 adduri(origud, uris, uds, mirrors, origud.mirrortarballs or [None])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001003
1004 return uris, uds
1005
1006def rename_bad_checksum(ud, suffix):
1007 """
1008 Renames files to have suffix from parameter
1009 """
1010
1011 if ud.localpath is None:
1012 return
1013
1014 new_localpath = "%s_bad-checksum_%s" % (ud.localpath, suffix)
1015 bb.warn("Renaming %s to %s" % (ud.localpath, new_localpath))
Brad Bishop79641f22019-09-10 07:20:22 -04001016 if not bb.utils.movefile(ud.localpath, new_localpath):
1017 bb.warn("Renaming %s to %s failed, grep movefile in log.do_fetch to see why" % (ud.localpath, new_localpath))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001018
1019
1020def try_mirror_url(fetch, origud, ud, ld, check = False):
1021 # Return of None or a value means we're finished
1022 # False means try another url
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001023
1024 if ud.lockfile and ud.lockfile != origud.lockfile:
1025 lf = bb.utils.lockfile(ud.lockfile)
1026
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001027 try:
1028 if check:
1029 found = ud.method.checkstatus(fetch, ud, ld)
1030 if found:
1031 return found
1032 return False
1033
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001034 if not verify_donestamp(ud, ld, origud) or ud.method.need_update(ud, ld):
1035 ud.method.download(ud, ld)
1036 if hasattr(ud.method,"build_mirror_data"):
1037 ud.method.build_mirror_data(ud, ld)
1038
1039 if not ud.localpath or not os.path.exists(ud.localpath):
1040 return False
1041
1042 if ud.localpath == origud.localpath:
1043 return ud.localpath
1044
1045 # We may be obtaining a mirror tarball which needs further processing by the real fetcher
1046 # If that tarball is a local file:// we need to provide a symlink to it
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001047 dldir = ld.getVar("DL_DIR")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001048
1049 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 -05001050 # Create donestamp in old format to avoid triggering a re-download
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001051 if ud.donestamp:
1052 bb.utils.mkdirhier(os.path.dirname(ud.donestamp))
1053 open(ud.donestamp, 'w').close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001054 dest = os.path.join(dldir, os.path.basename(ud.localpath))
1055 if not os.path.exists(dest):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001056 # In case this is executing without any file locks held (as is
1057 # the case for file:// URLs), two tasks may end up here at the
1058 # same time, in which case we do not want the second task to
1059 # fail when the link has already been created by the first task.
1060 try:
1061 os.symlink(ud.localpath, dest)
1062 except FileExistsError:
1063 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001064 if not verify_donestamp(origud, ld) or origud.method.need_update(origud, ld):
1065 origud.method.download(origud, ld)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001066 if hasattr(origud.method, "build_mirror_data"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001067 origud.method.build_mirror_data(origud, ld)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001068 return origud.localpath
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001069 # Otherwise the result is a local file:// and we symlink to it
Andrew Geissler09209ee2020-12-13 08:44:15 -06001070 ensure_symlink(ud.localpath, origud.localpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001071 update_stamp(origud, ld)
1072 return ud.localpath
1073
1074 except bb.fetch2.NetworkAccess:
1075 raise
1076
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001077 except IOError as e:
Brad Bishop19323692019-04-05 15:28:33 -04001078 if e.errno in [errno.ESTALE]:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001079 logger.warning("Stale Error Observed %s." % ud.url)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001080 return False
1081 raise
1082
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001083 except bb.fetch2.BBFetchException as e:
1084 if isinstance(e, ChecksumError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001085 logger.warning("Mirror checksum failure for url %s (original url: %s)\nCleaning and trying again." % (ud.url, origud.url))
1086 logger.warning(str(e))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001087 if os.path.exists(ud.localpath):
1088 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001089 elif isinstance(e, NoChecksumError):
1090 raise
1091 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001092 logger.debug("Mirror fetch failure for url %s (original url: %s)" % (ud.url, origud.url))
1093 logger.debug(str(e))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001094 try:
1095 ud.method.clean(ud, ld)
1096 except UnboundLocalError:
1097 pass
1098 return False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001099 finally:
1100 if ud.lockfile and ud.lockfile != origud.lockfile:
1101 bb.utils.unlockfile(lf)
1102
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001103
Andrew Geissler09209ee2020-12-13 08:44:15 -06001104def ensure_symlink(target, link_name):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001105 if not os.path.exists(link_name):
Andrew Geissler615f2f12022-07-15 14:00:58 -05001106 dirname = os.path.dirname(link_name)
1107 bb.utils.mkdirhier(dirname)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001108 if os.path.islink(link_name):
1109 # Broken symbolic link
1110 os.unlink(link_name)
1111
1112 # In case this is executing without any file locks held (as is
1113 # the case for file:// URLs), two tasks may end up here at the
1114 # same time, in which case we do not want the second task to
1115 # fail when the link has already been created by the first task.
1116 try:
1117 os.symlink(target, link_name)
1118 except FileExistsError:
1119 pass
1120
1121
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001122def try_mirrors(fetch, d, origud, mirrors, check = False):
1123 """
1124 Try to use a mirrored version of the sources.
1125 This method will be automatically called before the fetchers go.
1126
1127 d Is a bb.data instance
1128 uri is the original uri we're trying to download
1129 mirrors is the list of mirrors we're going to try
1130 """
1131 ld = d.createCopy()
1132
1133 uris, uds = build_mirroruris(origud, mirrors, ld)
1134
1135 for index, uri in enumerate(uris):
1136 ret = try_mirror_url(fetch, origud, uds[index], ld, check)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001137 if ret:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001138 return ret
1139 return None
1140
1141def trusted_network(d, url):
1142 """
1143 Use a trusted url during download if networking is enabled and
1144 BB_ALLOWED_NETWORKS is set globally or for a specific recipe.
1145 Note: modifies SRC_URI & mirrors.
1146 """
Brad Bishop19323692019-04-05 15:28:33 -04001147 if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001148 return True
1149
1150 pkgname = d.expand(d.getVar('PN', False))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001151 trusted_hosts = None
1152 if pkgname:
1153 trusted_hosts = d.getVarFlag('BB_ALLOWED_NETWORKS', pkgname, False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001154
1155 if not trusted_hosts:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001156 trusted_hosts = d.getVar('BB_ALLOWED_NETWORKS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001157
1158 # Not enabled.
1159 if not trusted_hosts:
1160 return True
1161
1162 scheme, network, path, user, passwd, param = decodeurl(url)
1163
1164 if not network:
1165 return True
1166
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001167 network = network.split(':')[0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001168 network = network.lower()
1169
1170 for host in trusted_hosts.split(" "):
1171 host = host.lower()
1172 if host.startswith("*.") and ("." + network).endswith(host[1:]):
1173 return True
1174 if host == network:
1175 return True
1176
1177 return False
1178
1179def srcrev_internal_helper(ud, d, name):
1180 """
1181 Return:
1182 a) a source revision if specified
1183 b) latest revision if SRCREV="AUTOINC"
1184 c) None if not specified
1185 """
1186
1187 srcrev = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001188 pn = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001189 attempts = []
1190 if name != '' and pn:
Patrick Williams213cb262021-08-07 19:21:33 -05001191 attempts.append("SRCREV_%s:pn-%s" % (name, pn))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001192 if name != '':
1193 attempts.append("SRCREV_%s" % name)
1194 if pn:
Patrick Williams213cb262021-08-07 19:21:33 -05001195 attempts.append("SRCREV:pn-%s" % pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001196 attempts.append("SRCREV")
1197
1198 for a in attempts:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001199 srcrev = d.getVar(a)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001200 if srcrev and srcrev != "INVALID":
1201 break
1202
1203 if 'rev' in ud.parm and 'tag' in ud.parm:
1204 raise FetchError("Please specify a ;rev= parameter or a ;tag= parameter in the url %s but not both." % (ud.url))
1205
1206 if 'rev' in ud.parm or 'tag' in ud.parm:
1207 if 'rev' in ud.parm:
1208 parmrev = ud.parm['rev']
1209 else:
1210 parmrev = ud.parm['tag']
1211 if srcrev == "INVALID" or not srcrev:
1212 return parmrev
1213 if srcrev != parmrev:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001214 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 -05001215 return parmrev
1216
1217 if srcrev == "INVALID" or not srcrev:
1218 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)
1219 if srcrev == "AUTOINC":
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001220 d.setVar("__BBAUTOREV_ACTED_UPON", True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001221 srcrev = ud.method.latest_revision(ud, d, name)
1222
1223 return srcrev
1224
1225def get_checksum_file_list(d):
1226 """ Get a list of files checksum in SRC_URI
1227
1228 Returns the resolved local paths of all local file entries in
1229 SRC_URI as a space-separated string
1230 """
1231 fetch = Fetch([], d, cache = False, localonly = True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001232 filelist = []
1233 for u in fetch.urls:
1234 ud = fetch.ud[u]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001235 if ud and isinstance(ud.method, local.Local):
Andrew Geissler615f2f12022-07-15 14:00:58 -05001236 found = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001237 paths = ud.method.localpaths(ud, d)
1238 for f in paths:
1239 pth = ud.decodedurl
Andrew Geissler615f2f12022-07-15 14:00:58 -05001240 if os.path.exists(f):
1241 found = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001242 filelist.append(f + ":" + str(os.path.exists(f)))
Andrew Geissler615f2f12022-07-15 14:00:58 -05001243 if not found:
1244 bb.fatal(("Unable to get checksum for %s SRC_URI entry %s: file could not be found"
1245 "\nThe following paths were searched:"
1246 "\n%s") % (d.getVar('PN'), os.path.basename(f), '\n'.join(paths)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001247
1248 return " ".join(filelist)
1249
Andrew Geissler82c905d2020-04-13 13:39:40 -05001250def get_file_checksums(filelist, pn, localdirsexclude):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001251 """Get a list of the checksums for a list of local files
1252
1253 Returns the checksums for a list of local files, caching the results as
1254 it proceeds
1255
1256 """
Andrew Geissler82c905d2020-04-13 13:39:40 -05001257 return _checksum_cache.get_checksums(filelist, pn, localdirsexclude)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001258
1259
1260class FetchData(object):
1261 """
1262 A class which represents the fetcher state for a given URI.
1263 """
1264 def __init__(self, url, d, localonly = False):
1265 # localpath is the location of a downloaded result. If not set, the file is local.
1266 self.donestamp = None
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001267 self.needdonestamp = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001268 self.localfile = ""
1269 self.localpath = None
1270 self.lockfile = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001271 self.mirrortarballs = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001272 self.basename = None
1273 self.basepath = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001274 (self.type, self.host, self.path, self.user, self.pswd, self.parm) = decodeurl(d.expand(url))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001275 self.date = self.getSRCDate(d)
1276 self.url = url
1277 if not self.user and "user" in self.parm:
1278 self.user = self.parm["user"]
1279 if not self.pswd and "pswd" in self.parm:
1280 self.pswd = self.parm["pswd"]
1281 self.setup = False
1282
Andrew Geissler82c905d2020-04-13 13:39:40 -05001283 def configure_checksum(checksum_id):
1284 if "name" in self.parm:
1285 checksum_name = "%s.%ssum" % (self.parm["name"], checksum_id)
1286 else:
1287 checksum_name = "%ssum" % checksum_id
1288
1289 setattr(self, "%s_name" % checksum_id, checksum_name)
1290
1291 if checksum_name in self.parm:
1292 checksum_expected = self.parm[checksum_name]
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001293 elif self.type not in ["http", "https", "ftp", "ftps", "sftp", "s3", "az", "crate"]:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001294 checksum_expected = None
1295 else:
1296 checksum_expected = d.getVarFlag("SRC_URI", checksum_name)
1297
1298 setattr(self, "%s_expected" % checksum_id, checksum_expected)
1299
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001300 self.names = self.parm.get("name",'default').split(',')
1301
1302 self.method = None
1303 for m in methods:
1304 if m.supports(self, d):
1305 self.method = m
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001306 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001307
1308 if not self.method:
1309 raise NoMethodError(url)
1310
1311 if localonly and not isinstance(self.method, local.Local):
1312 raise NonLocalMethod()
1313
1314 if self.parm.get("proto", None) and "protocol" not in self.parm:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001315 logger.warning('Consider updating %s recipe to use "protocol" not "proto" in SRC_URI.', d.getVar('PN'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001316 self.parm["protocol"] = self.parm.get("proto", None)
1317
1318 if hasattr(self.method, "urldata_init"):
1319 self.method.urldata_init(self, d)
1320
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001321 for checksum_id in CHECKSUM_LIST:
1322 configure_checksum(checksum_id)
1323
1324 self.ignore_checksums = False
1325
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001326 if "localpath" in self.parm:
1327 # if user sets localpath for file, use it instead.
1328 self.localpath = self.parm["localpath"]
1329 self.basename = os.path.basename(self.localpath)
1330 elif self.localfile:
1331 self.localpath = self.method.localpath(self, d)
1332
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001333 dldir = d.getVar("DL_DIR")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001334
1335 if not self.needdonestamp:
1336 return
1337
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001338 # Note: .done and .lock files should always be in DL_DIR whereas localpath may not be.
1339 if self.localpath and self.localpath.startswith(dldir):
1340 basepath = self.localpath
1341 elif self.localpath:
1342 basepath = dldir + os.sep + os.path.basename(self.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001343 elif self.basepath or self.basename:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001344 basepath = dldir + os.sep + (self.basepath or self.basename)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001345 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001346 bb.fatal("Can't determine lock path for url %s" % url)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001347
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001348 self.donestamp = basepath + '.done'
1349 self.lockfile = basepath + '.lock'
1350
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001351 def setup_revisions(self, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001352 self.revisions = {}
1353 for name in self.names:
1354 self.revisions[name] = srcrev_internal_helper(self, d, name)
1355
1356 # add compatibility code for non name specified case
1357 if len(self.names) == 1:
1358 self.revision = self.revisions[self.names[0]]
1359
1360 def setup_localpath(self, d):
1361 if not self.localpath:
1362 self.localpath = self.method.localpath(self, d)
1363
1364 def getSRCDate(self, d):
1365 """
1366 Return the SRC Date for the component
1367
1368 d the bb.data module
1369 """
1370 if "srcdate" in self.parm:
1371 return self.parm['srcdate']
1372
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001373 pn = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001374
1375 if pn:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001376 return d.getVar("SRCDATE_%s" % pn) or d.getVar("SRCDATE") or d.getVar("DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001377
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001378 return d.getVar("SRCDATE") or d.getVar("DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001379
1380class FetchMethod(object):
1381 """Base class for 'fetch'ing data"""
1382
1383 def __init__(self, urls=None):
1384 self.urls = []
1385
1386 def supports(self, urldata, d):
1387 """
1388 Check to see if this fetch class supports a given url.
1389 """
1390 return 0
1391
1392 def localpath(self, urldata, d):
1393 """
1394 Return the local filename of a given url assuming a successful fetch.
1395 Can also setup variables in urldata for use in go (saving code duplication
1396 and duplicate code execution)
1397 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001398 return os.path.join(d.getVar("DL_DIR"), urldata.localfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001399
1400 def supports_checksum(self, urldata):
1401 """
1402 Is localpath something that can be represented by a checksum?
1403 """
1404
1405 # We cannot compute checksums for directories
Andrew Geissler82c905d2020-04-13 13:39:40 -05001406 if os.path.isdir(urldata.localpath):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001407 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001408 return True
1409
1410 def recommends_checksum(self, urldata):
1411 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001412 Is the backend on where checksumming is recommended (should warnings
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001413 be displayed if there is no checksum)?
1414 """
1415 return False
1416
Andrew Geissler82c905d2020-04-13 13:39:40 -05001417 def verify_donestamp(self, ud, d):
1418 """
1419 Verify the donestamp file
1420 """
1421 return verify_donestamp(ud, d)
1422
1423 def update_donestamp(self, ud, d):
1424 """
1425 Update the donestamp file
1426 """
1427 update_stamp(ud, d)
1428
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001429 def _strip_leading_slashes(self, relpath):
1430 """
1431 Remove leading slash as os.path.join can't cope
1432 """
1433 while os.path.isabs(relpath):
1434 relpath = relpath[1:]
1435 return relpath
1436
1437 def setUrls(self, urls):
1438 self.__urls = urls
1439
1440 def getUrls(self):
1441 return self.__urls
1442
1443 urls = property(getUrls, setUrls, None, "Urls property")
1444
1445 def need_update(self, ud, d):
1446 """
1447 Force a fetch, even if localpath exists?
1448 """
1449 if os.path.exists(ud.localpath):
1450 return False
1451 return True
1452
1453 def supports_srcrev(self):
1454 """
1455 The fetcher supports auto source revisions (SRCREV)
1456 """
1457 return False
1458
1459 def download(self, urldata, d):
1460 """
1461 Fetch urls
1462 Assumes localpath was called first
1463 """
Brad Bishop19323692019-04-05 15:28:33 -04001464 raise NoMethodError(urldata.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001465
1466 def unpack(self, urldata, rootdir, data):
1467 iterate = False
1468 file = urldata.localpath
1469
1470 try:
1471 unpack = bb.utils.to_boolean(urldata.parm.get('unpack'), True)
1472 except ValueError as exc:
1473 bb.fatal("Invalid value for 'unpack' parameter for %s: %s" %
1474 (file, urldata.parm.get('unpack')))
1475
1476 base, ext = os.path.splitext(file)
1477 if ext in ['.gz', '.bz2', '.Z', '.xz', '.lz']:
1478 efile = os.path.join(rootdir, os.path.basename(base))
1479 else:
1480 efile = file
1481 cmd = None
1482
1483 if unpack:
Andrew Geissler595f6302022-01-24 19:11:47 +00001484 tar_cmd = 'tar --extract --no-same-owner'
1485 if 'striplevel' in urldata.parm:
1486 tar_cmd += ' --strip-components=%s' % urldata.parm['striplevel']
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001487 if file.endswith('.tar'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001488 cmd = '%s -f %s' % (tar_cmd, file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001489 elif file.endswith('.tgz') or file.endswith('.tar.gz') or file.endswith('.tar.Z'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001490 cmd = '%s -z -f %s' % (tar_cmd, file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001491 elif file.endswith('.tbz') or file.endswith('.tbz2') or file.endswith('.tar.bz2'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001492 cmd = 'bzip2 -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001493 elif file.endswith('.gz') or file.endswith('.Z') or file.endswith('.z'):
1494 cmd = 'gzip -dc %s > %s' % (file, efile)
1495 elif file.endswith('.bz2'):
1496 cmd = 'bzip2 -dc %s > %s' % (file, efile)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001497 elif file.endswith('.txz') or file.endswith('.tar.xz'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001498 cmd = 'xz -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001499 elif file.endswith('.xz'):
1500 cmd = 'xz -dc %s > %s' % (file, efile)
1501 elif file.endswith('.tar.lz'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001502 cmd = 'lzip -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001503 elif file.endswith('.lz'):
1504 cmd = 'lzip -dc %s > %s' % (file, efile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001505 elif file.endswith('.tar.7z'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001506 cmd = '7z x -so %s | %s -f -' % (file, tar_cmd)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001507 elif file.endswith('.7z'):
1508 cmd = '7za x -y %s 1>/dev/null' % file
Andrew Geissler6ce62a22020-11-30 19:58:47 -06001509 elif file.endswith('.tzst') or file.endswith('.tar.zst'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001510 cmd = 'zstd --decompress --stdout %s | %s -f -' % (file, tar_cmd)
Andrew Geissler6ce62a22020-11-30 19:58:47 -06001511 elif file.endswith('.zst'):
1512 cmd = 'zstd --decompress --stdout %s > %s' % (file, efile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001513 elif file.endswith('.zip') or file.endswith('.jar'):
1514 try:
1515 dos = bb.utils.to_boolean(urldata.parm.get('dos'), False)
1516 except ValueError as exc:
1517 bb.fatal("Invalid value for 'dos' parameter for %s: %s" %
1518 (file, urldata.parm.get('dos')))
1519 cmd = 'unzip -q -o'
1520 if dos:
1521 cmd = '%s -a' % cmd
1522 cmd = "%s '%s'" % (cmd, file)
1523 elif file.endswith('.rpm') or file.endswith('.srpm'):
1524 if 'extract' in urldata.parm:
1525 unpack_file = urldata.parm.get('extract')
1526 cmd = 'rpm2cpio.sh %s | cpio -id %s' % (file, unpack_file)
1527 iterate = True
1528 iterate_file = unpack_file
1529 else:
1530 cmd = 'rpm2cpio.sh %s | cpio -id' % (file)
1531 elif file.endswith('.deb') or file.endswith('.ipk'):
Brad Bishopa5c52ff2018-11-23 10:55:50 +13001532 output = subprocess.check_output(['ar', '-t', file], preexec_fn=subprocess_setup)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001533 datafile = None
1534 if output:
1535 for line in output.decode().splitlines():
1536 if line.startswith('data.tar.'):
1537 datafile = line
1538 break
1539 else:
1540 raise UnpackError("Unable to unpack deb/ipk package - does not contain data.tar.* file", urldata.url)
1541 else:
1542 raise UnpackError("Unable to unpack deb/ipk package - could not list contents", urldata.url)
Andrew Geissler595f6302022-01-24 19:11:47 +00001543 cmd = 'ar x %s %s && %s -p -f %s && rm %s' % (file, datafile, tar_cmd, datafile, datafile)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001544
1545 # If 'subdir' param exists, create a dir and use it as destination for unpack cmd
1546 if 'subdir' in urldata.parm:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001547 subdir = urldata.parm.get('subdir')
1548 if os.path.isabs(subdir):
1549 if not os.path.realpath(subdir).startswith(os.path.realpath(rootdir)):
1550 raise UnpackError("subdir argument isn't a subdirectory of unpack root %s" % rootdir, urldata.url)
1551 unpackdir = subdir
1552 else:
1553 unpackdir = os.path.join(rootdir, subdir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001554 bb.utils.mkdirhier(unpackdir)
1555 else:
1556 unpackdir = rootdir
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001557
1558 if not unpack or not cmd:
1559 # If file == dest, then avoid any copies, as we already put the file into dest!
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001560 dest = os.path.join(unpackdir, os.path.basename(file))
1561 if file != dest and not (os.path.exists(dest) and os.path.samefile(file, dest)):
1562 destdir = '.'
1563 # For file:// entries all intermediate dirs in path must be created at destination
1564 if urldata.type == "file":
1565 # Trailing '/' does a copying to wrong place
1566 urlpath = urldata.path.rstrip('/')
1567 # Want files places relative to cwd so no leading '/'
1568 urlpath = urlpath.lstrip('/')
1569 if urlpath.find("/") != -1:
1570 destdir = urlpath.rsplit("/", 1)[0] + '/'
1571 bb.utils.mkdirhier("%s/%s" % (unpackdir, destdir))
Andrew Geisslerc3d88e42020-10-02 09:45:00 -05001572 cmd = 'cp -fpPRH "%s" "%s"' % (file, destdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001573
1574 if not cmd:
1575 return
1576
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001577 path = data.getVar('PATH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001578 if path:
1579 cmd = "PATH=\"%s\" %s" % (path, cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001580 bb.note("Unpacking %s to %s/" % (file, unpackdir))
1581 ret = subprocess.call(cmd, preexec_fn=subprocess_setup, shell=True, cwd=unpackdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001582
1583 if ret != 0:
1584 raise UnpackError("Unpack command %s failed with return value %s" % (cmd, ret), urldata.url)
1585
1586 if iterate is True:
1587 iterate_urldata = urldata
1588 iterate_urldata.localpath = "%s/%s" % (rootdir, iterate_file)
1589 self.unpack(urldata, rootdir, data)
1590
1591 return
1592
1593 def clean(self, urldata, d):
1594 """
1595 Clean any existing full or partial download
1596 """
1597 bb.utils.remove(urldata.localpath)
1598
1599 def try_premirror(self, urldata, d):
1600 """
1601 Should premirrors be used?
1602 """
1603 return True
1604
Andrew Geissler82c905d2020-04-13 13:39:40 -05001605 def try_mirrors(self, fetch, urldata, d, mirrors, check=False):
1606 """
1607 Try to use a mirror
1608 """
1609 return bool(try_mirrors(fetch, d, urldata, mirrors, check))
1610
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001611 def checkstatus(self, fetch, urldata, d):
1612 """
1613 Check the status of a URL
1614 Assumes localpath was called first
1615 """
Brad Bishop19323692019-04-05 15:28:33 -04001616 logger.info("URL %s could not be checked for status since no method exists.", urldata.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001617 return True
1618
1619 def latest_revision(self, ud, d, name):
1620 """
1621 Look in the cache for the latest revision, if not present ask the SCM.
1622 """
1623 if not hasattr(self, "_latest_revision"):
Brad Bishop19323692019-04-05 15:28:33 -04001624 raise ParameterError("The fetcher for this URL does not support _latest_revision", ud.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001625
1626 revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
1627 key = self.generate_revision_key(ud, d, name)
1628 try:
1629 return revs[key]
1630 except KeyError:
1631 revs[key] = rev = self._latest_revision(ud, d, name)
1632 return rev
1633
1634 def sortable_revision(self, ud, d, name):
1635 latest_rev = self._build_revision(ud, d, name)
1636 return True, str(latest_rev)
1637
1638 def generate_revision_key(self, ud, d, name):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001639 return self._revision_key(ud, d, name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001640
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001641 def latest_versionstring(self, ud, d):
1642 """
1643 Compute the latest release name like "x.y.x" in "x.y.x+gitHASH"
1644 by searching through the tags output of ls-remote, comparing
1645 versions and returning the highest match as a (version, revision) pair.
1646 """
1647 return ('', '')
1648
Andrew Geissler82c905d2020-04-13 13:39:40 -05001649 def done(self, ud, d):
1650 """
1651 Is the download done ?
1652 """
1653 if os.path.exists(ud.localpath):
1654 return True
Andrew Geissler82c905d2020-04-13 13:39:40 -05001655 return False
1656
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001657 def implicit_urldata(self, ud, d):
1658 """
1659 Get a list of FetchData objects for any implicit URLs that will also
1660 be downloaded when we fetch the given URL.
1661 """
1662 return []
1663
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001664class Fetch(object):
1665 def __init__(self, urls, d, cache = True, localonly = False, connection_cache = None):
1666 if localonly and cache:
1667 raise Exception("bb.fetch2.Fetch.__init__: cannot set cache and localonly at same time")
1668
Andrew Geissler595f6302022-01-24 19:11:47 +00001669 if not urls:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001670 urls = d.getVar("SRC_URI").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001671 self.urls = urls
1672 self.d = d
1673 self.ud = {}
1674 self.connection_cache = connection_cache
1675
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001676 fn = d.getVar('FILE')
1677 mc = d.getVar('__BBMULTICONFIG') or ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001678 key = None
1679 if cache and fn:
1680 key = mc + fn + str(id(d))
1681 if key in urldata_cache:
1682 self.ud = urldata_cache[key]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001683
1684 for url in urls:
1685 if url not in self.ud:
1686 try:
1687 self.ud[url] = FetchData(url, d, localonly)
1688 except NonLocalMethod:
1689 if localonly:
1690 self.ud[url] = None
1691 pass
1692
Andrew Geissler82c905d2020-04-13 13:39:40 -05001693 if key:
1694 urldata_cache[key] = self.ud
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001695
1696 def localpath(self, url):
1697 if url not in self.urls:
1698 self.ud[url] = FetchData(url, self.d)
1699
1700 self.ud[url].setup_localpath(self.d)
1701 return self.d.expand(self.ud[url].localpath)
1702
1703 def localpaths(self):
1704 """
1705 Return a list of the local filenames, assuming successful fetch
1706 """
1707 local = []
1708
1709 for u in self.urls:
1710 ud = self.ud[u]
1711 ud.setup_localpath(self.d)
1712 local.append(ud.localpath)
1713
1714 return local
1715
1716 def download(self, urls=None):
1717 """
1718 Fetch all urls
1719 """
1720 if not urls:
1721 urls = self.urls
1722
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001723 network = self.d.getVar("BB_NO_NETWORK")
Brad Bishop19323692019-04-05 15:28:33 -04001724 premirroronly = bb.utils.to_boolean(self.d.getVar("BB_FETCH_PREMIRRORONLY"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001725
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001726 checksum_missing_messages = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001727 for u in urls:
1728 ud = self.ud[u]
1729 ud.setup_localpath(self.d)
1730 m = ud.method
Andrew Geissler82c905d2020-04-13 13:39:40 -05001731 done = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001732
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001733 if ud.lockfile:
1734 lf = bb.utils.lockfile(ud.lockfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001735
1736 try:
1737 self.d.setVar("BB_NO_NETWORK", network)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001738 if m.verify_donestamp(ud, self.d) and not m.need_update(ud, self.d):
1739 done = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001740 elif m.try_premirror(ud, self.d):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001741 logger.debug("Trying PREMIRRORS")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001742 mirrors = mirror_from_string(self.d.getVar('PREMIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001743 done = m.try_mirrors(self, ud, self.d, mirrors)
1744 if done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001745 try:
1746 # early checksum verification so that if the checksum of the premirror
1747 # contents mismatch the fetcher can still try upstream and mirrors
Andrew Geissler82c905d2020-04-13 13:39:40 -05001748 m.update_donestamp(ud, self.d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001749 except ChecksumError as e:
1750 logger.warning("Checksum failure encountered with premirror download of %s - will attempt other sources." % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001751 logger.debug(str(e))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001752 done = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001753
1754 if premirroronly:
1755 self.d.setVar("BB_NO_NETWORK", "1")
1756
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001757 firsterr = None
Andrew Geisslereff27472021-10-29 15:35:00 -05001758 verified_stamp = False
1759 if done:
1760 verified_stamp = m.verify_donestamp(ud, self.d)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001761 if not done and (not verified_stamp or m.need_update(ud, self.d)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001762 try:
1763 if not trusted_network(self.d, ud.url):
1764 raise UntrustedUrl(ud.url)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001765 logger.debug("Trying Upstream")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001766 m.download(ud, self.d)
1767 if hasattr(m, "build_mirror_data"):
1768 m.build_mirror_data(ud, self.d)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001769 done = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001770 # early checksum verify, so that if checksum mismatched,
1771 # fetcher still have chance to fetch from mirror
Andrew Geissler82c905d2020-04-13 13:39:40 -05001772 m.update_donestamp(ud, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001773
1774 except bb.fetch2.NetworkAccess:
1775 raise
1776
1777 except BBFetchException as e:
1778 if isinstance(e, ChecksumError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001779 logger.warning("Checksum failure encountered with download of %s - will attempt other sources if available" % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001780 logger.debug(str(e))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001781 if os.path.exists(ud.localpath):
1782 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001783 elif isinstance(e, NoChecksumError):
1784 raise
1785 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001786 logger.warning('Failed to fetch URL %s, attempting MIRRORS if available' % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001787 logger.debug(str(e))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001788 firsterr = e
1789 # Remove any incomplete fetch
1790 if not verified_stamp:
1791 m.clean(ud, self.d)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001792 logger.debug("Trying MIRRORS")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001793 mirrors = mirror_from_string(self.d.getVar('MIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001794 done = m.try_mirrors(self, ud, self.d, mirrors)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001795
Andrew Geissler82c905d2020-04-13 13:39:40 -05001796 if not done or not m.done(ud, self.d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001797 if firsterr:
1798 logger.error(str(firsterr))
1799 raise FetchError("Unable to fetch URL from any source.", u)
1800
Andrew Geissler82c905d2020-04-13 13:39:40 -05001801 m.update_donestamp(ud, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001802
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001803 except IOError as e:
Brad Bishop19323692019-04-05 15:28:33 -04001804 if e.errno in [errno.ESTALE]:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001805 logger.error("Stale Error Observed %s." % u)
1806 raise ChecksumError("Stale Error Detected")
1807
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001808 except BBFetchException as e:
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001809 if isinstance(e, NoChecksumError):
1810 (message, _) = e.args
1811 checksum_missing_messages.append(message)
1812 continue
1813 elif isinstance(e, ChecksumError):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001814 logger.error("Checksum failure fetching %s" % u)
1815 raise
1816
1817 finally:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001818 if ud.lockfile:
1819 bb.utils.unlockfile(lf)
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001820 if checksum_missing_messages:
1821 logger.error("Missing SRC_URI checksum, please add those to the recipe: \n%s", "\n".join(checksum_missing_messages))
1822 raise BBFetchException("There was some missing checksums in the recipe")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001823
1824 def checkstatus(self, urls=None):
1825 """
Andrew Geisslereff27472021-10-29 15:35:00 -05001826 Check all URLs exist upstream.
1827
1828 Returns None if the URLs exist, raises FetchError if the check wasn't
1829 successful but there wasn't an error (such as file not found), and
1830 raises other exceptions in error cases.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001831 """
1832
1833 if not urls:
1834 urls = self.urls
1835
1836 for u in urls:
1837 ud = self.ud[u]
1838 ud.setup_localpath(self.d)
1839 m = ud.method
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001840 logger.debug("Testing URL %s", u)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001841 # First try checking uri, u, from PREMIRRORS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001842 mirrors = mirror_from_string(self.d.getVar('PREMIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001843 ret = m.try_mirrors(self, ud, self.d, mirrors, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001844 if not ret:
1845 # Next try checking from the original uri, u
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001846 ret = m.checkstatus(self, ud, self.d)
1847 if not ret:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001848 # Finally, try checking uri, u, from MIRRORS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001849 mirrors = mirror_from_string(self.d.getVar('MIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001850 ret = m.try_mirrors(self, ud, self.d, mirrors, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001851
1852 if not ret:
1853 raise FetchError("URL %s doesn't work" % u, u)
1854
1855 def unpack(self, root, urls=None):
1856 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001857 Unpack urls to root
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001858 """
1859
1860 if not urls:
1861 urls = self.urls
1862
1863 for u in urls:
1864 ud = self.ud[u]
1865 ud.setup_localpath(self.d)
1866
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001867 if ud.lockfile:
1868 lf = bb.utils.lockfile(ud.lockfile)
1869
1870 ud.method.unpack(ud, root, self.d)
1871
1872 if ud.lockfile:
1873 bb.utils.unlockfile(lf)
1874
1875 def clean(self, urls=None):
1876 """
1877 Clean files that the fetcher gets or places
1878 """
1879
1880 if not urls:
1881 urls = self.urls
1882
1883 for url in urls:
1884 if url not in self.ud:
Brad Bishop19323692019-04-05 15:28:33 -04001885 self.ud[url] = FetchData(url, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001886 ud = self.ud[url]
1887 ud.setup_localpath(self.d)
1888
1889 if not ud.localfile and ud.localpath is None:
1890 continue
1891
1892 if ud.lockfile:
1893 lf = bb.utils.lockfile(ud.lockfile)
1894
1895 ud.method.clean(ud, self.d)
1896 if ud.donestamp:
1897 bb.utils.remove(ud.donestamp)
1898
1899 if ud.lockfile:
1900 bb.utils.unlockfile(lf)
1901
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001902 def expanded_urldata(self, urls=None):
1903 """
1904 Get an expanded list of FetchData objects covering both the given
1905 URLS and any additional implicit URLs that are added automatically by
1906 the appropriate FetchMethod.
1907 """
1908
1909 if not urls:
1910 urls = self.urls
1911
1912 urldata = []
1913 for url in urls:
1914 ud = self.ud[url]
1915 urldata.append(ud)
1916 urldata += ud.method.implicit_urldata(ud, self.d)
1917
1918 return urldata
1919
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001920class FetchConnectionCache(object):
1921 """
1922 A class which represents an container for socket connections.
1923 """
1924 def __init__(self):
1925 self.cache = {}
1926
1927 def get_connection_name(self, host, port):
1928 return host + ':' + str(port)
1929
1930 def add_connection(self, host, port, connection):
1931 cn = self.get_connection_name(host, port)
1932
1933 if cn not in self.cache:
1934 self.cache[cn] = connection
1935
1936 def get_connection(self, host, port):
1937 connection = None
1938
1939 cn = self.get_connection_name(host, port)
1940 if cn in self.cache:
1941 connection = self.cache[cn]
1942
1943 return connection
1944
1945 def remove_connection(self, host, port):
1946 cn = self.get_connection_name(host, port)
1947 if cn in self.cache:
1948 self.cache[cn].close()
1949 del self.cache[cn]
1950
1951 def close_connections(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001952 for cn in list(self.cache.keys()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001953 self.cache[cn].close()
1954 del self.cache[cn]
1955
1956from . import cvs
1957from . import git
1958from . import gitsm
1959from . import gitannex
1960from . import local
1961from . import svn
1962from . import wget
1963from . import ssh
1964from . import sftp
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001965from . import s3
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001966from . import perforce
1967from . import bzr
1968from . import hg
1969from . import osc
1970from . import repo
1971from . import clearcase
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001972from . import npm
Andrew Geissler82c905d2020-04-13 13:39:40 -05001973from . import npmsw
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001974from . import az
Andrew Geissler595f6302022-01-24 19:11:47 +00001975from . import crate
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001976
1977methods.append(local.Local())
1978methods.append(wget.Wget())
1979methods.append(svn.Svn())
1980methods.append(git.Git())
1981methods.append(gitsm.GitSM())
1982methods.append(gitannex.GitANNEX())
1983methods.append(cvs.Cvs())
1984methods.append(ssh.SSH())
1985methods.append(sftp.SFTP())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001986methods.append(s3.S3())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001987methods.append(perforce.Perforce())
1988methods.append(bzr.Bzr())
1989methods.append(hg.Hg())
1990methods.append(osc.Osc())
1991methods.append(repo.Repo())
1992methods.append(clearcase.ClearCase())
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001993methods.append(npm.Npm())
Andrew Geissler82c905d2020-04-13 13:39:40 -05001994methods.append(npmsw.NpmShrinkWrap())
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001995methods.append(az.Az())
Andrew Geissler595f6302022-01-24 19:11:47 +00001996methods.append(crate.Crate())