blob: cf65727a205b0c919245f83756b1b5469ad07188 [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 """
563
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500564 if ud.ignore_checksums or not ud.method.supports_checksum(ud):
565 return {}
566
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500567 if localpath is None:
568 localpath = ud.localpath
569
Andrew Geissler82c905d2020-04-13 13:39:40 -0500570 def compute_checksum_info(checksum_id):
571 checksum_name = getattr(ud, "%s_name" % checksum_id)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500572
Andrew Geissler82c905d2020-04-13 13:39:40 -0500573 if checksum_id in precomputed:
574 checksum_data = precomputed[checksum_id]
575 else:
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500576 checksum_data = getattr(bb.utils, "%s_file" % checksum_id)(localpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500577
Andrew Geissler82c905d2020-04-13 13:39:40 -0500578 checksum_expected = getattr(ud, "%s_expected" % checksum_id)
579
Andrew Geissler09036742021-06-25 14:25:14 -0500580 if checksum_expected == '':
581 checksum_expected = None
582
Andrew Geissler82c905d2020-04-13 13:39:40 -0500583 return {
584 "id": checksum_id,
585 "name": checksum_name,
586 "data": checksum_data,
587 "expected": checksum_expected
588 }
589
590 checksum_infos = []
591 for checksum_id in CHECKSUM_LIST:
592 checksum_infos.append(compute_checksum_info(checksum_id))
593
594 checksum_dict = {ci["id"] : ci["data"] for ci in checksum_infos}
595 checksum_event = {"%ssum" % ci["id"] : ci["data"] for ci in checksum_infos}
596
597 for ci in checksum_infos:
598 if ci["id"] in SHOWN_CHECKSUM_LIST:
599 checksum_lines = ["SRC_URI[%s] = \"%s\"" % (ci["name"], ci["data"])]
600
601 # If no checksum has been provided
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500602 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 -0500603 messages = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500604 strict = d.getVar("BB_STRICT_CHECKSUM") or "0"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500605
Andrew Geissler82c905d2020-04-13 13:39:40 -0500606 # If strict checking enabled and neither sum defined, raise error
607 if strict == "1":
608 messages.append("No checksum specified for '%s', please add at " \
609 "least one to the recipe:" % ud.localpath)
610 messages.extend(checksum_lines)
611 logger.error("\n".join(messages))
612 raise NoChecksumError("Missing SRC_URI checksum", ud.url)
613
614 bb.event.fire(MissingChecksumEvent(ud.url, **checksum_event), d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500615
616 if strict == "ignore":
Andrew Geissler82c905d2020-04-13 13:39:40 -0500617 return checksum_dict
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500618
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500619 # Log missing sums so user can more easily add them
Andrew Geissler82c905d2020-04-13 13:39:40 -0500620 messages.append("Missing checksum for '%s', consider adding at " \
621 "least one to the recipe:" % ud.localpath)
622 messages.extend(checksum_lines)
623 logger.warning("\n".join(messages))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500624
625 # We want to alert the user if a checksum is defined in the recipe but
626 # it does not match.
Andrew Geissler82c905d2020-04-13 13:39:40 -0500627 messages = []
628 messages.append("Checksum mismatch!")
629 bad_checksum = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500630
Andrew Geissler82c905d2020-04-13 13:39:40 -0500631 for ci in checksum_infos:
632 if ci["expected"] and ci["expected"] != ci["data"]:
Andrew Geissler09036742021-06-25 14:25:14 -0500633 messages.append("File: '%s' has %s checksum '%s' when '%s' was " \
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500634 "expected" % (localpath, ci["id"], ci["data"], ci["expected"]))
Andrew Geissler82c905d2020-04-13 13:39:40 -0500635 bad_checksum = ci["data"]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500636
Andrew Geissler82c905d2020-04-13 13:39:40 -0500637 if bad_checksum:
638 messages.append("If this change is expected (e.g. you have upgraded " \
639 "to a new version without updating the checksums) " \
640 "then you can use these lines within the recipe:")
641 messages.extend(checksum_lines)
642 messages.append("Otherwise you should retry the download and/or " \
643 "check with upstream to determine if the file has " \
644 "become corrupted or otherwise unexpectedly modified.")
645 raise ChecksumError("\n".join(messages), ud.url, bad_checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500646
Andrew Geissler82c905d2020-04-13 13:39:40 -0500647 return checksum_dict
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500648
649def verify_donestamp(ud, d, origud=None):
650 """
651 Check whether the done stamp file has the right checksums (if the fetch
652 method supports them). If it doesn't, delete the done stamp and force
653 a re-download.
654
655 Returns True, if the donestamp exists and is valid, False otherwise. When
656 returning False, any existing done stamps are removed.
657 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500658 if not ud.needdonestamp or (origud and not origud.needdonestamp):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500659 return True
660
Brad Bishop316dfdd2018-06-25 12:45:53 -0400661 if not os.path.exists(ud.localpath):
662 # local path does not exist
663 if os.path.exists(ud.donestamp):
664 # done stamp exists, but the downloaded file does not; the done stamp
665 # must be incorrect, re-trigger the download
666 bb.utils.remove(ud.donestamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500667 return False
668
669 if (not ud.method.supports_checksum(ud) or
670 (origud and not origud.method.supports_checksum(origud))):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400671 # if done stamp exists and checksums not supported; assume the local
672 # file is current
673 return os.path.exists(ud.donestamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500674
675 precomputed_checksums = {}
676 # Only re-use the precomputed checksums if the donestamp is newer than the
677 # file. Do not rely on the mtime of directories, though. If ud.localpath is
678 # a directory, there will probably not be any checksums anyway.
Brad Bishop316dfdd2018-06-25 12:45:53 -0400679 if os.path.exists(ud.donestamp) and (os.path.isdir(ud.localpath) or
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500680 os.path.getmtime(ud.localpath) < os.path.getmtime(ud.donestamp)):
681 try:
682 with open(ud.donestamp, "rb") as cachefile:
683 pickled = pickle.Unpickler(cachefile)
684 precomputed_checksums.update(pickled.load())
685 except Exception as e:
686 # Avoid the warnings on the upgrade path from emtpy done stamp
687 # files to those containing the checksums.
688 if not isinstance(e, EOFError):
689 # Ignore errors, they aren't fatal
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600690 logger.warning("Couldn't load checksums from donestamp %s: %s "
691 "(msg: %s)" % (ud.donestamp, type(e).__name__,
692 str(e)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500693
694 try:
695 checksums = verify_checksum(ud, d, precomputed_checksums)
696 # If the cache file did not have the checksums, compute and store them
697 # as an upgrade path from the previous done stamp file format.
698 if checksums != precomputed_checksums:
699 with open(ud.donestamp, "wb") as cachefile:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600700 p = pickle.Pickler(cachefile, 2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500701 p.dump(checksums)
702 return True
703 except ChecksumError as e:
704 # Checksums failed to verify, trigger re-download and remove the
705 # incorrect stamp file.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600706 logger.warning("Checksum mismatch for local file %s\n"
707 "Cleaning and trying again." % ud.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500708 if os.path.exists(ud.localpath):
709 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500710 bb.utils.remove(ud.donestamp)
711 return False
712
713
714def update_stamp(ud, d):
715 """
716 donestamp is file stamp indicating the whole fetching is done
717 this function update the stamp after verifying the checksum
718 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500719 if not ud.needdonestamp:
720 return
721
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500722 if os.path.exists(ud.donestamp):
723 # Touch the done stamp file to show active use of the download
724 try:
725 os.utime(ud.donestamp, None)
726 except:
727 # Errors aren't fatal here
728 pass
729 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500730 try:
731 checksums = verify_checksum(ud, d)
732 # Store the checksums for later re-verification against the recipe
733 with open(ud.donestamp, "wb") as cachefile:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600734 p = pickle.Pickler(cachefile, 2)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500735 p.dump(checksums)
736 except ChecksumError as e:
737 # Checksums failed to verify, trigger re-download and remove the
738 # incorrect stamp file.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600739 logger.warning("Checksum mismatch for local file %s\n"
740 "Cleaning and trying again." % ud.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500741 if os.path.exists(ud.localpath):
742 rename_bad_checksum(ud, e.checksum)
743 bb.utils.remove(ud.donestamp)
744 raise
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500745
746def subprocess_setup():
747 # Python installs a SIGPIPE handler by default. This is usually not what
748 # non-Python subprocesses expect.
749 # SIGPIPE errors are known issues with gzip/bash
750 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
751
752def get_autorev(d):
753 # only not cache src rev in autorev case
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500754 if d.getVar('BB_SRCREV_POLICY') != "cache":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500755 d.setVar('BB_DONT_CACHE', '1')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500756 return "AUTOINC"
757
758def get_srcrev(d, method_name='sortable_revision'):
759 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500760 Return the revision string, usually for use in the version string (PV) of the current package
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500761 Most packages usually only have one SCM so we just pass on the call.
762 In the multi SCM case, we build a value based on SRCREV_FORMAT which must
763 have been set.
764
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500765 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 -0500766 incremental, other code is then responsible for turning that into an increasing value (if needed)
767
768 A method_name can be supplied to retrieve an alternatively formatted revision from a fetcher, if
769 that fetcher provides a method with the given name and the same signature as sortable_revision.
770 """
771
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000772 d.setVar("__BBSEENSRCREV", "1")
Andrew Geissler5199d832021-09-24 16:47:35 -0500773 recursion = d.getVar("__BBINSRCREV")
774 if recursion:
775 raise FetchError("There are recursive references in fetcher variables, likely through SRC_URI")
776 d.setVar("__BBINSRCREV", True)
777
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500778 scms = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500779 fetcher = Fetch(d.getVar('SRC_URI').split(), d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500780 urldata = fetcher.ud
781 for u in urldata:
782 if urldata[u].method.supports_srcrev():
783 scms.append(u)
784
Andrew Geissler595f6302022-01-24 19:11:47 +0000785 if not scms:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500786 raise FetchError("SRCREV was used yet no valid SCM was found in SRC_URI")
787
788 if len(scms) == 1 and len(urldata[scms[0]].names) == 1:
789 autoinc, rev = getattr(urldata[scms[0]].method, method_name)(urldata[scms[0]], d, urldata[scms[0]].names[0])
790 if len(rev) > 10:
791 rev = rev[:10]
Andrew Geissler5199d832021-09-24 16:47:35 -0500792 d.delVar("__BBINSRCREV")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500793 if autoinc:
794 return "AUTOINC+" + rev
795 return rev
796
797 #
798 # Mutiple SCMs are in SRC_URI so we resort to SRCREV_FORMAT
799 #
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500800 format = d.getVar('SRCREV_FORMAT')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500801 if not format:
Brad Bishop19323692019-04-05 15:28:33 -0400802 raise FetchError("The SRCREV_FORMAT variable must be set when multiple SCMs are used.\n"\
803 "The SCMs are:\n%s" % '\n'.join(scms))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500804
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600805 name_to_rev = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500806 seenautoinc = False
807 for scm in scms:
808 ud = urldata[scm]
809 for name in ud.names:
810 autoinc, rev = getattr(ud.method, method_name)(ud, d, name)
811 seenautoinc = seenautoinc or autoinc
812 if len(rev) > 10:
813 rev = rev[:10]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600814 name_to_rev[name] = rev
815 # Replace names by revisions in the SRCREV_FORMAT string. The approach used
816 # here can handle names being prefixes of other names and names appearing
817 # as substrings in revisions (in which case the name should not be
818 # expanded). The '|' regular expression operator tries matches from left to
819 # right, so we need to sort the names with the longest ones first.
820 names_descending_len = sorted(name_to_rev, key=len, reverse=True)
821 name_to_rev_re = "|".join(re.escape(name) for name in names_descending_len)
822 format = re.sub(name_to_rev_re, lambda match: name_to_rev[match.group(0)], format)
823
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500824 if seenautoinc:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500825 format = "AUTOINC+" + format
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500826
Andrew Geissler5199d832021-09-24 16:47:35 -0500827 d.delVar("__BBINSRCREV")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500828 return format
829
830def localpath(url, d):
831 fetcher = bb.fetch2.Fetch([url], d)
832 return fetcher.localpath(url)
833
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500834# Need to export PATH as binary could be in metadata paths
835# rather than host provided
836# Also include some other variables.
837FETCH_EXPORT_VARS = ['HOME', 'PATH',
838 'HTTP_PROXY', 'http_proxy',
839 'HTTPS_PROXY', 'https_proxy',
840 'FTP_PROXY', 'ftp_proxy',
841 'FTPS_PROXY', 'ftps_proxy',
842 'NO_PROXY', 'no_proxy',
843 'ALL_PROXY', 'all_proxy',
844 'GIT_PROXY_COMMAND',
845 'GIT_SSH',
Patrick Williams03907ee2022-05-01 06:28:52 -0500846 'GIT_SSH_COMMAND',
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500847 'GIT_SSL_CAINFO',
848 'GIT_SMART_HTTP',
849 'SSH_AUTH_SOCK', 'SSH_AGENT_PID',
850 'SOCKS5_USER', 'SOCKS5_PASSWD',
851 'DBUS_SESSION_BUS_ADDRESS',
852 'P4CONFIG',
853 'SSL_CERT_FILE',
Patrick Williams864cc432023-02-09 14:54:44 -0600854 'NODE_EXTRA_CA_CERTS',
Andrew Geissler5199d832021-09-24 16:47:35 -0500855 'AWS_PROFILE',
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500856 'AWS_ACCESS_KEY_ID',
857 'AWS_SECRET_ACCESS_KEY',
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600858 'AWS_DEFAULT_REGION',
859 'GIT_CACHE_PATH',
860 'SSL_CERT_DIR']
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500861
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000862def get_fetcher_environment(d):
863 newenv = {}
864 origenv = d.getVar("BB_ORIGENV")
865 for name in bb.fetch2.FETCH_EXPORT_VARS:
866 value = d.getVar(name)
867 if not value and origenv:
868 value = origenv.getVar(name)
869 if value:
870 newenv[name] = value
871 return newenv
872
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600873def runfetchcmd(cmd, d, quiet=False, cleanup=None, log=None, workdir=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500874 """
875 Run cmd returning the command output
876 Raise an error if interrupted or cmd fails
877 Optionally echo command output to stdout
878 Optionally remove the files/directories listed in cleanup upon failure
879 """
880
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500881 exportvars = FETCH_EXPORT_VARS
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500882
883 if not cleanup:
884 cleanup = []
885
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800886 # If PATH contains WORKDIR which contains PV-PR which contains SRCPV we
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500887 # can end up in circular recursion here so give the option of breaking it
888 # in a data store copy.
889 try:
890 d.getVar("PV")
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800891 d.getVar("PR")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500892 except bb.data_smart.ExpansionError:
893 d = bb.data.createCopy(d)
894 d.setVar("PV", "fetcheravoidrecurse")
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800895 d.setVar("PR", "fetcheravoidrecurse")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500896
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600897 origenv = d.getVar("BB_ORIGENV", False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500898 for var in exportvars:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500899 val = d.getVar(var) or (origenv and origenv.getVar(var))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500900 if val:
901 cmd = 'export ' + var + '=\"%s\"; %s' % (val, cmd)
902
Brad Bishop316dfdd2018-06-25 12:45:53 -0400903 # Disable pseudo as it may affect ssh, potentially causing it to hang.
904 cmd = 'export PSEUDO_DISABLED=1; ' + cmd
905
Brad Bishop19323692019-04-05 15:28:33 -0400906 if workdir:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600907 logger.debug("Running '%s' in %s" % (cmd, workdir))
Brad Bishop19323692019-04-05 15:28:33 -0400908 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600909 logger.debug("Running %s", cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500910
911 success = False
912 error_message = ""
913
914 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600915 (output, errors) = bb.process.run(cmd, log=log, shell=True, stderr=subprocess.PIPE, cwd=workdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500916 success = True
917 except bb.process.NotFoundError as e:
Andrew Geisslereff27472021-10-29 15:35:00 -0500918 error_message = "Fetch command %s not found" % (e.command)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500919 except bb.process.ExecutionError as e:
920 if e.stdout:
921 output = "output:\n%s\n%s" % (e.stdout, e.stderr)
922 elif e.stderr:
923 output = "output:\n%s" % e.stderr
924 else:
925 output = "no output"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600926 error_message = "Fetch command %s failed with exit code %s, %s" % (e.command, e.exitcode, output)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500927 except bb.process.CmdError as e:
928 error_message = "Fetch command %s could not be run:\n%s" % (e.command, e.msg)
929 if not success:
930 for f in cleanup:
931 try:
932 bb.utils.remove(f, True)
933 except OSError:
934 pass
935
936 raise FetchError(error_message)
937
938 return output
939
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500940def check_network_access(d, info, url):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500941 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500942 log remote network access, and error if BB_NO_NETWORK is set or the given
943 URI is untrusted
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500944 """
Brad Bishop19323692019-04-05 15:28:33 -0400945 if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500946 raise NetworkAccess(url, info)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500947 elif not trusted_network(d, url):
948 raise UntrustedUrl(url, info)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500949 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600950 logger.debug("Fetcher accessed the network with the command %s" % info)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500951
952def build_mirroruris(origud, mirrors, ld):
953 uris = []
954 uds = []
955
956 replacements = {}
957 replacements["TYPE"] = origud.type
958 replacements["HOST"] = origud.host
959 replacements["PATH"] = origud.path
960 replacements["BASENAME"] = origud.path.split("/")[-1]
961 replacements["MIRRORNAME"] = origud.host.replace(':','.') + origud.path.replace('/', '.').replace('*', '.')
962
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500963 def adduri(ud, uris, uds, mirrors, tarballs):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500964 for line in mirrors:
965 try:
966 (find, replace) = line
967 except ValueError:
968 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500969
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500970 for tarball in tarballs:
971 newuri = uri_replace(ud, find, replace, replacements, ld, tarball)
972 if not newuri or newuri in uris or newuri == origud.url:
973 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500974
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500975 if not trusted_network(ld, newuri):
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600976 logger.debug("Mirror %s not in the list of trusted networks, skipping" % (newuri))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500977 continue
Patrick Williamsd7e96312015-09-22 08:09:05 -0500978
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500979 # Create a local copy of the mirrors minus the current line
980 # this will prevent us from recursively processing the same line
981 # as well as indirect recursion A -> B -> C -> A
982 localmirrors = list(mirrors)
983 localmirrors.remove(line)
984
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500985 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500986 newud = FetchData(newuri, ld)
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500987 newud.ignore_checksums = True
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500988 newud.setup_localpath(ld)
989 except bb.fetch2.BBFetchException as e:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600990 logger.debug("Mirror fetch failure for url %s (original url: %s)" % (newuri, origud.url))
991 logger.debug(str(e))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500992 try:
993 # setup_localpath of file:// urls may fail, we should still see
994 # if mirrors of the url exist
995 adduri(newud, uris, uds, localmirrors, tarballs)
996 except UnboundLocalError:
997 pass
998 continue
999 uris.append(newuri)
1000 uds.append(newud)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001001
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001002 adduri(newud, uris, uds, localmirrors, tarballs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001003
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001004 adduri(origud, uris, uds, mirrors, origud.mirrortarballs or [None])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001005
1006 return uris, uds
1007
1008def rename_bad_checksum(ud, suffix):
1009 """
1010 Renames files to have suffix from parameter
1011 """
1012
1013 if ud.localpath is None:
1014 return
1015
1016 new_localpath = "%s_bad-checksum_%s" % (ud.localpath, suffix)
1017 bb.warn("Renaming %s to %s" % (ud.localpath, new_localpath))
Brad Bishop79641f22019-09-10 07:20:22 -04001018 if not bb.utils.movefile(ud.localpath, new_localpath):
1019 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 -05001020
1021
1022def try_mirror_url(fetch, origud, ud, ld, check = False):
1023 # Return of None or a value means we're finished
1024 # False means try another url
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001025
1026 if ud.lockfile and ud.lockfile != origud.lockfile:
1027 lf = bb.utils.lockfile(ud.lockfile)
1028
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001029 try:
1030 if check:
1031 found = ud.method.checkstatus(fetch, ud, ld)
1032 if found:
1033 return found
1034 return False
1035
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001036 if not verify_donestamp(ud, ld, origud) or ud.method.need_update(ud, ld):
1037 ud.method.download(ud, ld)
1038 if hasattr(ud.method,"build_mirror_data"):
1039 ud.method.build_mirror_data(ud, ld)
1040
1041 if not ud.localpath or not os.path.exists(ud.localpath):
1042 return False
1043
1044 if ud.localpath == origud.localpath:
1045 return ud.localpath
1046
1047 # We may be obtaining a mirror tarball which needs further processing by the real fetcher
1048 # If that tarball is a local file:// we need to provide a symlink to it
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001049 dldir = ld.getVar("DL_DIR")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001050
1051 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 -05001052 # Create donestamp in old format to avoid triggering a re-download
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001053 if ud.donestamp:
1054 bb.utils.mkdirhier(os.path.dirname(ud.donestamp))
1055 open(ud.donestamp, 'w').close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001056 dest = os.path.join(dldir, os.path.basename(ud.localpath))
1057 if not os.path.exists(dest):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001058 # In case this is executing without any file locks held (as is
1059 # the case for file:// URLs), two tasks may end up here at the
1060 # same time, in which case we do not want the second task to
1061 # fail when the link has already been created by the first task.
1062 try:
1063 os.symlink(ud.localpath, dest)
1064 except FileExistsError:
1065 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001066 if not verify_donestamp(origud, ld) or origud.method.need_update(origud, ld):
1067 origud.method.download(origud, ld)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001068 if hasattr(origud.method, "build_mirror_data"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001069 origud.method.build_mirror_data(origud, ld)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001070 return origud.localpath
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001071 # Otherwise the result is a local file:// and we symlink to it
Andrew Geissler09209ee2020-12-13 08:44:15 -06001072 ensure_symlink(ud.localpath, origud.localpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001073 update_stamp(origud, ld)
1074 return ud.localpath
1075
1076 except bb.fetch2.NetworkAccess:
1077 raise
1078
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001079 except IOError as e:
Brad Bishop19323692019-04-05 15:28:33 -04001080 if e.errno in [errno.ESTALE]:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001081 logger.warning("Stale Error Observed %s." % ud.url)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001082 return False
1083 raise
1084
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001085 except bb.fetch2.BBFetchException as e:
1086 if isinstance(e, ChecksumError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001087 logger.warning("Mirror checksum failure for url %s (original url: %s)\nCleaning and trying again." % (ud.url, origud.url))
1088 logger.warning(str(e))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001089 if os.path.exists(ud.localpath):
1090 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001091 elif isinstance(e, NoChecksumError):
1092 raise
1093 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001094 logger.debug("Mirror fetch failure for url %s (original url: %s)" % (ud.url, origud.url))
1095 logger.debug(str(e))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001096 try:
1097 ud.method.clean(ud, ld)
1098 except UnboundLocalError:
1099 pass
1100 return False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001101 finally:
1102 if ud.lockfile and ud.lockfile != origud.lockfile:
1103 bb.utils.unlockfile(lf)
1104
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001105
Andrew Geissler09209ee2020-12-13 08:44:15 -06001106def ensure_symlink(target, link_name):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001107 if not os.path.exists(link_name):
Andrew Geissler615f2f12022-07-15 14:00:58 -05001108 dirname = os.path.dirname(link_name)
1109 bb.utils.mkdirhier(dirname)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001110 if os.path.islink(link_name):
1111 # Broken symbolic link
1112 os.unlink(link_name)
1113
1114 # In case this is executing without any file locks held (as is
1115 # the case for file:// URLs), two tasks may end up here at the
1116 # same time, in which case we do not want the second task to
1117 # fail when the link has already been created by the first task.
1118 try:
1119 os.symlink(target, link_name)
1120 except FileExistsError:
1121 pass
1122
1123
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001124def try_mirrors(fetch, d, origud, mirrors, check = False):
1125 """
1126 Try to use a mirrored version of the sources.
1127 This method will be automatically called before the fetchers go.
1128
1129 d Is a bb.data instance
1130 uri is the original uri we're trying to download
1131 mirrors is the list of mirrors we're going to try
1132 """
1133 ld = d.createCopy()
1134
1135 uris, uds = build_mirroruris(origud, mirrors, ld)
1136
1137 for index, uri in enumerate(uris):
1138 ret = try_mirror_url(fetch, origud, uds[index], ld, check)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001139 if ret:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001140 return ret
1141 return None
1142
1143def trusted_network(d, url):
1144 """
1145 Use a trusted url during download if networking is enabled and
1146 BB_ALLOWED_NETWORKS is set globally or for a specific recipe.
1147 Note: modifies SRC_URI & mirrors.
1148 """
Brad Bishop19323692019-04-05 15:28:33 -04001149 if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001150 return True
1151
1152 pkgname = d.expand(d.getVar('PN', False))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001153 trusted_hosts = None
1154 if pkgname:
1155 trusted_hosts = d.getVarFlag('BB_ALLOWED_NETWORKS', pkgname, False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001156
1157 if not trusted_hosts:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001158 trusted_hosts = d.getVar('BB_ALLOWED_NETWORKS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001159
1160 # Not enabled.
1161 if not trusted_hosts:
1162 return True
1163
1164 scheme, network, path, user, passwd, param = decodeurl(url)
1165
1166 if not network:
1167 return True
1168
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001169 network = network.split(':')[0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001170 network = network.lower()
1171
1172 for host in trusted_hosts.split(" "):
1173 host = host.lower()
1174 if host.startswith("*.") and ("." + network).endswith(host[1:]):
1175 return True
1176 if host == network:
1177 return True
1178
1179 return False
1180
1181def srcrev_internal_helper(ud, d, name):
1182 """
1183 Return:
1184 a) a source revision if specified
1185 b) latest revision if SRCREV="AUTOINC"
1186 c) None if not specified
1187 """
1188
1189 srcrev = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001190 pn = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001191 attempts = []
1192 if name != '' and pn:
Patrick Williams213cb262021-08-07 19:21:33 -05001193 attempts.append("SRCREV_%s:pn-%s" % (name, pn))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001194 if name != '':
1195 attempts.append("SRCREV_%s" % name)
1196 if pn:
Patrick Williams213cb262021-08-07 19:21:33 -05001197 attempts.append("SRCREV:pn-%s" % pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001198 attempts.append("SRCREV")
1199
1200 for a in attempts:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001201 srcrev = d.getVar(a)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001202 if srcrev and srcrev != "INVALID":
1203 break
1204
1205 if 'rev' in ud.parm and 'tag' in ud.parm:
1206 raise FetchError("Please specify a ;rev= parameter or a ;tag= parameter in the url %s but not both." % (ud.url))
1207
1208 if 'rev' in ud.parm or 'tag' in ud.parm:
1209 if 'rev' in ud.parm:
1210 parmrev = ud.parm['rev']
1211 else:
1212 parmrev = ud.parm['tag']
1213 if srcrev == "INVALID" or not srcrev:
1214 return parmrev
1215 if srcrev != parmrev:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001216 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 -05001217 return parmrev
1218
1219 if srcrev == "INVALID" or not srcrev:
1220 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)
1221 if srcrev == "AUTOINC":
1222 srcrev = ud.method.latest_revision(ud, d, name)
1223
1224 return srcrev
1225
1226def get_checksum_file_list(d):
1227 """ Get a list of files checksum in SRC_URI
1228
1229 Returns the resolved local paths of all local file entries in
1230 SRC_URI as a space-separated string
1231 """
1232 fetch = Fetch([], d, cache = False, localonly = True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001233 filelist = []
1234 for u in fetch.urls:
1235 ud = fetch.ud[u]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001236 if ud and isinstance(ud.method, local.Local):
Andrew Geissler615f2f12022-07-15 14:00:58 -05001237 found = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001238 paths = ud.method.localpaths(ud, d)
1239 for f in paths:
1240 pth = ud.decodedurl
Andrew Geissler615f2f12022-07-15 14:00:58 -05001241 if os.path.exists(f):
1242 found = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001243 filelist.append(f + ":" + str(os.path.exists(f)))
Andrew Geissler615f2f12022-07-15 14:00:58 -05001244 if not found:
1245 bb.fatal(("Unable to get checksum for %s SRC_URI entry %s: file could not be found"
1246 "\nThe following paths were searched:"
1247 "\n%s") % (d.getVar('PN'), os.path.basename(f), '\n'.join(paths)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001248
1249 return " ".join(filelist)
1250
Andrew Geissler82c905d2020-04-13 13:39:40 -05001251def get_file_checksums(filelist, pn, localdirsexclude):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001252 """Get a list of the checksums for a list of local files
1253
1254 Returns the checksums for a list of local files, caching the results as
1255 it proceeds
1256
1257 """
Andrew Geissler82c905d2020-04-13 13:39:40 -05001258 return _checksum_cache.get_checksums(filelist, pn, localdirsexclude)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001259
1260
1261class FetchData(object):
1262 """
1263 A class which represents the fetcher state for a given URI.
1264 """
1265 def __init__(self, url, d, localonly = False):
1266 # localpath is the location of a downloaded result. If not set, the file is local.
1267 self.donestamp = None
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001268 self.needdonestamp = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001269 self.localfile = ""
1270 self.localpath = None
1271 self.lockfile = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001272 self.mirrortarballs = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001273 self.basename = None
1274 self.basepath = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001275 (self.type, self.host, self.path, self.user, self.pswd, self.parm) = decodeurl(d.expand(url))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001276 self.date = self.getSRCDate(d)
1277 self.url = url
1278 if not self.user and "user" in self.parm:
1279 self.user = self.parm["user"]
1280 if not self.pswd and "pswd" in self.parm:
1281 self.pswd = self.parm["pswd"]
1282 self.setup = False
1283
Andrew Geissler82c905d2020-04-13 13:39:40 -05001284 def configure_checksum(checksum_id):
1285 if "name" in self.parm:
1286 checksum_name = "%s.%ssum" % (self.parm["name"], checksum_id)
1287 else:
1288 checksum_name = "%ssum" % checksum_id
1289
1290 setattr(self, "%s_name" % checksum_id, checksum_name)
1291
1292 if checksum_name in self.parm:
1293 checksum_expected = self.parm[checksum_name]
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001294 elif self.type not in ["http", "https", "ftp", "ftps", "sftp", "s3", "az"]:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001295 checksum_expected = None
1296 else:
1297 checksum_expected = d.getVarFlag("SRC_URI", checksum_name)
1298
1299 setattr(self, "%s_expected" % checksum_id, checksum_expected)
1300
1301 for checksum_id in CHECKSUM_LIST:
1302 configure_checksum(checksum_id)
1303
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001304 self.ignore_checksums = False
1305
1306 self.names = self.parm.get("name",'default').split(',')
1307
1308 self.method = None
1309 for m in methods:
1310 if m.supports(self, d):
1311 self.method = m
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001312 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001313
1314 if not self.method:
1315 raise NoMethodError(url)
1316
1317 if localonly and not isinstance(self.method, local.Local):
1318 raise NonLocalMethod()
1319
1320 if self.parm.get("proto", None) and "protocol" not in self.parm:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001321 logger.warning('Consider updating %s recipe to use "protocol" not "proto" in SRC_URI.', d.getVar('PN'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001322 self.parm["protocol"] = self.parm.get("proto", None)
1323
1324 if hasattr(self.method, "urldata_init"):
1325 self.method.urldata_init(self, d)
1326
1327 if "localpath" in self.parm:
1328 # if user sets localpath for file, use it instead.
1329 self.localpath = self.parm["localpath"]
1330 self.basename = os.path.basename(self.localpath)
1331 elif self.localfile:
1332 self.localpath = self.method.localpath(self, d)
1333
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001334 dldir = d.getVar("DL_DIR")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001335
1336 if not self.needdonestamp:
1337 return
1338
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001339 # Note: .done and .lock files should always be in DL_DIR whereas localpath may not be.
1340 if self.localpath and self.localpath.startswith(dldir):
1341 basepath = self.localpath
1342 elif self.localpath:
1343 basepath = dldir + os.sep + os.path.basename(self.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001344 elif self.basepath or self.basename:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001345 basepath = dldir + os.sep + (self.basepath or self.basename)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001346 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001347 bb.fatal("Can't determine lock path for url %s" % url)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001348
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001349 self.donestamp = basepath + '.done'
1350 self.lockfile = basepath + '.lock'
1351
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001352 def setup_revisions(self, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001353 self.revisions = {}
1354 for name in self.names:
1355 self.revisions[name] = srcrev_internal_helper(self, d, name)
1356
1357 # add compatibility code for non name specified case
1358 if len(self.names) == 1:
1359 self.revision = self.revisions[self.names[0]]
1360
1361 def setup_localpath(self, d):
1362 if not self.localpath:
1363 self.localpath = self.method.localpath(self, d)
1364
1365 def getSRCDate(self, d):
1366 """
1367 Return the SRC Date for the component
1368
1369 d the bb.data module
1370 """
1371 if "srcdate" in self.parm:
1372 return self.parm['srcdate']
1373
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001374 pn = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001375
1376 if pn:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001377 return d.getVar("SRCDATE_%s" % pn) or d.getVar("SRCDATE") or d.getVar("DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001378
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001379 return d.getVar("SRCDATE") or d.getVar("DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001380
1381class FetchMethod(object):
1382 """Base class for 'fetch'ing data"""
1383
1384 def __init__(self, urls=None):
1385 self.urls = []
1386
1387 def supports(self, urldata, d):
1388 """
1389 Check to see if this fetch class supports a given url.
1390 """
1391 return 0
1392
1393 def localpath(self, urldata, d):
1394 """
1395 Return the local filename of a given url assuming a successful fetch.
1396 Can also setup variables in urldata for use in go (saving code duplication
1397 and duplicate code execution)
1398 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001399 return os.path.join(d.getVar("DL_DIR"), urldata.localfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001400
1401 def supports_checksum(self, urldata):
1402 """
1403 Is localpath something that can be represented by a checksum?
1404 """
1405
1406 # We cannot compute checksums for directories
Andrew Geissler82c905d2020-04-13 13:39:40 -05001407 if os.path.isdir(urldata.localpath):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001408 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001409 return True
1410
1411 def recommends_checksum(self, urldata):
1412 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001413 Is the backend on where checksumming is recommended (should warnings
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001414 be displayed if there is no checksum)?
1415 """
1416 return False
1417
Andrew Geissler82c905d2020-04-13 13:39:40 -05001418 def verify_donestamp(self, ud, d):
1419 """
1420 Verify the donestamp file
1421 """
1422 return verify_donestamp(ud, d)
1423
1424 def update_donestamp(self, ud, d):
1425 """
1426 Update the donestamp file
1427 """
1428 update_stamp(ud, d)
1429
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001430 def _strip_leading_slashes(self, relpath):
1431 """
1432 Remove leading slash as os.path.join can't cope
1433 """
1434 while os.path.isabs(relpath):
1435 relpath = relpath[1:]
1436 return relpath
1437
1438 def setUrls(self, urls):
1439 self.__urls = urls
1440
1441 def getUrls(self):
1442 return self.__urls
1443
1444 urls = property(getUrls, setUrls, None, "Urls property")
1445
1446 def need_update(self, ud, d):
1447 """
1448 Force a fetch, even if localpath exists?
1449 """
1450 if os.path.exists(ud.localpath):
1451 return False
1452 return True
1453
1454 def supports_srcrev(self):
1455 """
1456 The fetcher supports auto source revisions (SRCREV)
1457 """
1458 return False
1459
1460 def download(self, urldata, d):
1461 """
1462 Fetch urls
1463 Assumes localpath was called first
1464 """
Brad Bishop19323692019-04-05 15:28:33 -04001465 raise NoMethodError(urldata.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001466
1467 def unpack(self, urldata, rootdir, data):
1468 iterate = False
1469 file = urldata.localpath
1470
1471 try:
1472 unpack = bb.utils.to_boolean(urldata.parm.get('unpack'), True)
1473 except ValueError as exc:
1474 bb.fatal("Invalid value for 'unpack' parameter for %s: %s" %
1475 (file, urldata.parm.get('unpack')))
1476
1477 base, ext = os.path.splitext(file)
1478 if ext in ['.gz', '.bz2', '.Z', '.xz', '.lz']:
1479 efile = os.path.join(rootdir, os.path.basename(base))
1480 else:
1481 efile = file
1482 cmd = None
1483
1484 if unpack:
Andrew Geissler595f6302022-01-24 19:11:47 +00001485 tar_cmd = 'tar --extract --no-same-owner'
1486 if 'striplevel' in urldata.parm:
1487 tar_cmd += ' --strip-components=%s' % urldata.parm['striplevel']
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001488 if file.endswith('.tar'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001489 cmd = '%s -f %s' % (tar_cmd, file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001490 elif file.endswith('.tgz') or file.endswith('.tar.gz') or file.endswith('.tar.Z'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001491 cmd = '%s -z -f %s' % (tar_cmd, file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001492 elif file.endswith('.tbz') or file.endswith('.tbz2') or file.endswith('.tar.bz2'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001493 cmd = 'bzip2 -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001494 elif file.endswith('.gz') or file.endswith('.Z') or file.endswith('.z'):
1495 cmd = 'gzip -dc %s > %s' % (file, efile)
1496 elif file.endswith('.bz2'):
1497 cmd = 'bzip2 -dc %s > %s' % (file, efile)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001498 elif file.endswith('.txz') or file.endswith('.tar.xz'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001499 cmd = 'xz -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001500 elif file.endswith('.xz'):
1501 cmd = 'xz -dc %s > %s' % (file, efile)
1502 elif file.endswith('.tar.lz'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001503 cmd = 'lzip -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001504 elif file.endswith('.lz'):
1505 cmd = 'lzip -dc %s > %s' % (file, efile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001506 elif file.endswith('.tar.7z'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001507 cmd = '7z x -so %s | %s -f -' % (file, tar_cmd)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001508 elif file.endswith('.7z'):
1509 cmd = '7za x -y %s 1>/dev/null' % file
Andrew Geissler6ce62a22020-11-30 19:58:47 -06001510 elif file.endswith('.tzst') or file.endswith('.tar.zst'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001511 cmd = 'zstd --decompress --stdout %s | %s -f -' % (file, tar_cmd)
Andrew Geissler6ce62a22020-11-30 19:58:47 -06001512 elif file.endswith('.zst'):
1513 cmd = 'zstd --decompress --stdout %s > %s' % (file, efile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001514 elif file.endswith('.zip') or file.endswith('.jar'):
1515 try:
1516 dos = bb.utils.to_boolean(urldata.parm.get('dos'), False)
1517 except ValueError as exc:
1518 bb.fatal("Invalid value for 'dos' parameter for %s: %s" %
1519 (file, urldata.parm.get('dos')))
1520 cmd = 'unzip -q -o'
1521 if dos:
1522 cmd = '%s -a' % cmd
1523 cmd = "%s '%s'" % (cmd, file)
1524 elif file.endswith('.rpm') or file.endswith('.srpm'):
1525 if 'extract' in urldata.parm:
1526 unpack_file = urldata.parm.get('extract')
1527 cmd = 'rpm2cpio.sh %s | cpio -id %s' % (file, unpack_file)
1528 iterate = True
1529 iterate_file = unpack_file
1530 else:
1531 cmd = 'rpm2cpio.sh %s | cpio -id' % (file)
1532 elif file.endswith('.deb') or file.endswith('.ipk'):
Brad Bishopa5c52ff2018-11-23 10:55:50 +13001533 output = subprocess.check_output(['ar', '-t', file], preexec_fn=subprocess_setup)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001534 datafile = None
1535 if output:
1536 for line in output.decode().splitlines():
1537 if line.startswith('data.tar.'):
1538 datafile = line
1539 break
1540 else:
1541 raise UnpackError("Unable to unpack deb/ipk package - does not contain data.tar.* file", urldata.url)
1542 else:
1543 raise UnpackError("Unable to unpack deb/ipk package - could not list contents", urldata.url)
Andrew Geissler595f6302022-01-24 19:11:47 +00001544 cmd = 'ar x %s %s && %s -p -f %s && rm %s' % (file, datafile, tar_cmd, datafile, datafile)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001545
1546 # If 'subdir' param exists, create a dir and use it as destination for unpack cmd
1547 if 'subdir' in urldata.parm:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001548 subdir = urldata.parm.get('subdir')
1549 if os.path.isabs(subdir):
1550 if not os.path.realpath(subdir).startswith(os.path.realpath(rootdir)):
1551 raise UnpackError("subdir argument isn't a subdirectory of unpack root %s" % rootdir, urldata.url)
1552 unpackdir = subdir
1553 else:
1554 unpackdir = os.path.join(rootdir, subdir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001555 bb.utils.mkdirhier(unpackdir)
1556 else:
1557 unpackdir = rootdir
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001558
1559 if not unpack or not cmd:
1560 # If file == dest, then avoid any copies, as we already put the file into dest!
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001561 dest = os.path.join(unpackdir, os.path.basename(file))
1562 if file != dest and not (os.path.exists(dest) and os.path.samefile(file, dest)):
1563 destdir = '.'
1564 # For file:// entries all intermediate dirs in path must be created at destination
1565 if urldata.type == "file":
1566 # Trailing '/' does a copying to wrong place
1567 urlpath = urldata.path.rstrip('/')
1568 # Want files places relative to cwd so no leading '/'
1569 urlpath = urlpath.lstrip('/')
1570 if urlpath.find("/") != -1:
1571 destdir = urlpath.rsplit("/", 1)[0] + '/'
1572 bb.utils.mkdirhier("%s/%s" % (unpackdir, destdir))
Andrew Geisslerc3d88e42020-10-02 09:45:00 -05001573 cmd = 'cp -fpPRH "%s" "%s"' % (file, destdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001574
1575 if not cmd:
1576 return
1577
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001578 path = data.getVar('PATH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001579 if path:
1580 cmd = "PATH=\"%s\" %s" % (path, cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001581 bb.note("Unpacking %s to %s/" % (file, unpackdir))
1582 ret = subprocess.call(cmd, preexec_fn=subprocess_setup, shell=True, cwd=unpackdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001583
1584 if ret != 0:
1585 raise UnpackError("Unpack command %s failed with return value %s" % (cmd, ret), urldata.url)
1586
1587 if iterate is True:
1588 iterate_urldata = urldata
1589 iterate_urldata.localpath = "%s/%s" % (rootdir, iterate_file)
1590 self.unpack(urldata, rootdir, data)
1591
1592 return
1593
1594 def clean(self, urldata, d):
1595 """
1596 Clean any existing full or partial download
1597 """
1598 bb.utils.remove(urldata.localpath)
1599
1600 def try_premirror(self, urldata, d):
1601 """
1602 Should premirrors be used?
1603 """
1604 return True
1605
Andrew Geissler82c905d2020-04-13 13:39:40 -05001606 def try_mirrors(self, fetch, urldata, d, mirrors, check=False):
1607 """
1608 Try to use a mirror
1609 """
1610 return bool(try_mirrors(fetch, d, urldata, mirrors, check))
1611
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001612 def checkstatus(self, fetch, urldata, d):
1613 """
1614 Check the status of a URL
1615 Assumes localpath was called first
1616 """
Brad Bishop19323692019-04-05 15:28:33 -04001617 logger.info("URL %s could not be checked for status since no method exists.", urldata.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001618 return True
1619
1620 def latest_revision(self, ud, d, name):
1621 """
1622 Look in the cache for the latest revision, if not present ask the SCM.
1623 """
1624 if not hasattr(self, "_latest_revision"):
Brad Bishop19323692019-04-05 15:28:33 -04001625 raise ParameterError("The fetcher for this URL does not support _latest_revision", ud.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001626
1627 revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
1628 key = self.generate_revision_key(ud, d, name)
1629 try:
1630 return revs[key]
1631 except KeyError:
1632 revs[key] = rev = self._latest_revision(ud, d, name)
1633 return rev
1634
1635 def sortable_revision(self, ud, d, name):
1636 latest_rev = self._build_revision(ud, d, name)
1637 return True, str(latest_rev)
1638
1639 def generate_revision_key(self, ud, d, name):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001640 return self._revision_key(ud, d, name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001641
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001642 def latest_versionstring(self, ud, d):
1643 """
1644 Compute the latest release name like "x.y.x" in "x.y.x+gitHASH"
1645 by searching through the tags output of ls-remote, comparing
1646 versions and returning the highest match as a (version, revision) pair.
1647 """
1648 return ('', '')
1649
Andrew Geissler82c905d2020-04-13 13:39:40 -05001650 def done(self, ud, d):
1651 """
1652 Is the download done ?
1653 """
1654 if os.path.exists(ud.localpath):
1655 return True
Andrew Geissler82c905d2020-04-13 13:39:40 -05001656 return False
1657
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001658 def implicit_urldata(self, ud, d):
1659 """
1660 Get a list of FetchData objects for any implicit URLs that will also
1661 be downloaded when we fetch the given URL.
1662 """
1663 return []
1664
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001665class Fetch(object):
1666 def __init__(self, urls, d, cache = True, localonly = False, connection_cache = None):
1667 if localonly and cache:
1668 raise Exception("bb.fetch2.Fetch.__init__: cannot set cache and localonly at same time")
1669
Andrew Geissler595f6302022-01-24 19:11:47 +00001670 if not urls:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001671 urls = d.getVar("SRC_URI").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001672 self.urls = urls
1673 self.d = d
1674 self.ud = {}
1675 self.connection_cache = connection_cache
1676
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001677 fn = d.getVar('FILE')
1678 mc = d.getVar('__BBMULTICONFIG') or ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001679 key = None
1680 if cache and fn:
1681 key = mc + fn + str(id(d))
1682 if key in urldata_cache:
1683 self.ud = urldata_cache[key]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001684
1685 for url in urls:
1686 if url not in self.ud:
1687 try:
1688 self.ud[url] = FetchData(url, d, localonly)
1689 except NonLocalMethod:
1690 if localonly:
1691 self.ud[url] = None
1692 pass
1693
Andrew Geissler82c905d2020-04-13 13:39:40 -05001694 if key:
1695 urldata_cache[key] = self.ud
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001696
1697 def localpath(self, url):
1698 if url not in self.urls:
1699 self.ud[url] = FetchData(url, self.d)
1700
1701 self.ud[url].setup_localpath(self.d)
1702 return self.d.expand(self.ud[url].localpath)
1703
1704 def localpaths(self):
1705 """
1706 Return a list of the local filenames, assuming successful fetch
1707 """
1708 local = []
1709
1710 for u in self.urls:
1711 ud = self.ud[u]
1712 ud.setup_localpath(self.d)
1713 local.append(ud.localpath)
1714
1715 return local
1716
1717 def download(self, urls=None):
1718 """
1719 Fetch all urls
1720 """
1721 if not urls:
1722 urls = self.urls
1723
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001724 network = self.d.getVar("BB_NO_NETWORK")
Brad Bishop19323692019-04-05 15:28:33 -04001725 premirroronly = bb.utils.to_boolean(self.d.getVar("BB_FETCH_PREMIRRORONLY"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001726
1727 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)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001738
Andrew Geissler82c905d2020-04-13 13:39:40 -05001739 if m.verify_donestamp(ud, self.d) and not m.need_update(ud, self.d):
1740 done = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001741 elif m.try_premirror(ud, self.d):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001742 logger.debug("Trying PREMIRRORS")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001743 mirrors = mirror_from_string(self.d.getVar('PREMIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001744 done = m.try_mirrors(self, ud, self.d, mirrors)
1745 if done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001746 try:
1747 # early checksum verification so that if the checksum of the premirror
1748 # contents mismatch the fetcher can still try upstream and mirrors
Andrew Geissler82c905d2020-04-13 13:39:40 -05001749 m.update_donestamp(ud, self.d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001750 except ChecksumError as e:
1751 logger.warning("Checksum failure encountered with premirror download of %s - will attempt other sources." % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001752 logger.debug(str(e))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001753 done = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001754
1755 if premirroronly:
1756 self.d.setVar("BB_NO_NETWORK", "1")
1757
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001758 firsterr = None
Andrew Geisslereff27472021-10-29 15:35:00 -05001759 verified_stamp = False
1760 if done:
1761 verified_stamp = m.verify_donestamp(ud, self.d)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001762 if not done and (not verified_stamp or m.need_update(ud, self.d)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001763 try:
1764 if not trusted_network(self.d, ud.url):
1765 raise UntrustedUrl(ud.url)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001766 logger.debug("Trying Upstream")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001767 m.download(ud, self.d)
1768 if hasattr(m, "build_mirror_data"):
1769 m.build_mirror_data(ud, self.d)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001770 done = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001771 # early checksum verify, so that if checksum mismatched,
1772 # fetcher still have chance to fetch from mirror
Andrew Geissler82c905d2020-04-13 13:39:40 -05001773 m.update_donestamp(ud, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001774
1775 except bb.fetch2.NetworkAccess:
1776 raise
1777
1778 except BBFetchException as e:
1779 if isinstance(e, ChecksumError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001780 logger.warning("Checksum failure encountered with download of %s - will attempt other sources if available" % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001781 logger.debug(str(e))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001782 if os.path.exists(ud.localpath):
1783 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001784 elif isinstance(e, NoChecksumError):
1785 raise
1786 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001787 logger.warning('Failed to fetch URL %s, attempting MIRRORS if available' % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001788 logger.debug(str(e))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001789 firsterr = e
1790 # Remove any incomplete fetch
1791 if not verified_stamp:
1792 m.clean(ud, self.d)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001793 logger.debug("Trying MIRRORS")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001794 mirrors = mirror_from_string(self.d.getVar('MIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001795 done = m.try_mirrors(self, ud, self.d, mirrors)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001796
Andrew Geissler82c905d2020-04-13 13:39:40 -05001797 if not done or not m.done(ud, self.d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001798 if firsterr:
1799 logger.error(str(firsterr))
1800 raise FetchError("Unable to fetch URL from any source.", u)
1801
Andrew Geissler82c905d2020-04-13 13:39:40 -05001802 m.update_donestamp(ud, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001803
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001804 except IOError as e:
Brad Bishop19323692019-04-05 15:28:33 -04001805 if e.errno in [errno.ESTALE]:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001806 logger.error("Stale Error Observed %s." % u)
1807 raise ChecksumError("Stale Error Detected")
1808
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001809 except BBFetchException as e:
1810 if isinstance(e, ChecksumError):
1811 logger.error("Checksum failure fetching %s" % u)
1812 raise
1813
1814 finally:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001815 if ud.lockfile:
1816 bb.utils.unlockfile(lf)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001817
1818 def checkstatus(self, urls=None):
1819 """
Andrew Geisslereff27472021-10-29 15:35:00 -05001820 Check all URLs exist upstream.
1821
1822 Returns None if the URLs exist, raises FetchError if the check wasn't
1823 successful but there wasn't an error (such as file not found), and
1824 raises other exceptions in error cases.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001825 """
1826
1827 if not urls:
1828 urls = self.urls
1829
1830 for u in urls:
1831 ud = self.ud[u]
1832 ud.setup_localpath(self.d)
1833 m = ud.method
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001834 logger.debug("Testing URL %s", u)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001835 # First try checking uri, u, from PREMIRRORS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001836 mirrors = mirror_from_string(self.d.getVar('PREMIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001837 ret = m.try_mirrors(self, ud, self.d, mirrors, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001838 if not ret:
1839 # Next try checking from the original uri, u
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001840 ret = m.checkstatus(self, ud, self.d)
1841 if not ret:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001842 # Finally, try checking uri, u, from MIRRORS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001843 mirrors = mirror_from_string(self.d.getVar('MIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001844 ret = m.try_mirrors(self, ud, self.d, mirrors, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001845
1846 if not ret:
1847 raise FetchError("URL %s doesn't work" % u, u)
1848
1849 def unpack(self, root, urls=None):
1850 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001851 Unpack urls to root
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001852 """
1853
1854 if not urls:
1855 urls = self.urls
1856
1857 for u in urls:
1858 ud = self.ud[u]
1859 ud.setup_localpath(self.d)
1860
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001861 if ud.lockfile:
1862 lf = bb.utils.lockfile(ud.lockfile)
1863
1864 ud.method.unpack(ud, root, self.d)
1865
1866 if ud.lockfile:
1867 bb.utils.unlockfile(lf)
1868
1869 def clean(self, urls=None):
1870 """
1871 Clean files that the fetcher gets or places
1872 """
1873
1874 if not urls:
1875 urls = self.urls
1876
1877 for url in urls:
1878 if url not in self.ud:
Brad Bishop19323692019-04-05 15:28:33 -04001879 self.ud[url] = FetchData(url, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001880 ud = self.ud[url]
1881 ud.setup_localpath(self.d)
1882
1883 if not ud.localfile and ud.localpath is None:
1884 continue
1885
1886 if ud.lockfile:
1887 lf = bb.utils.lockfile(ud.lockfile)
1888
1889 ud.method.clean(ud, self.d)
1890 if ud.donestamp:
1891 bb.utils.remove(ud.donestamp)
1892
1893 if ud.lockfile:
1894 bb.utils.unlockfile(lf)
1895
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001896 def expanded_urldata(self, urls=None):
1897 """
1898 Get an expanded list of FetchData objects covering both the given
1899 URLS and any additional implicit URLs that are added automatically by
1900 the appropriate FetchMethod.
1901 """
1902
1903 if not urls:
1904 urls = self.urls
1905
1906 urldata = []
1907 for url in urls:
1908 ud = self.ud[url]
1909 urldata.append(ud)
1910 urldata += ud.method.implicit_urldata(ud, self.d)
1911
1912 return urldata
1913
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001914class FetchConnectionCache(object):
1915 """
1916 A class which represents an container for socket connections.
1917 """
1918 def __init__(self):
1919 self.cache = {}
1920
1921 def get_connection_name(self, host, port):
1922 return host + ':' + str(port)
1923
1924 def add_connection(self, host, port, connection):
1925 cn = self.get_connection_name(host, port)
1926
1927 if cn not in self.cache:
1928 self.cache[cn] = connection
1929
1930 def get_connection(self, host, port):
1931 connection = None
1932
1933 cn = self.get_connection_name(host, port)
1934 if cn in self.cache:
1935 connection = self.cache[cn]
1936
1937 return connection
1938
1939 def remove_connection(self, host, port):
1940 cn = self.get_connection_name(host, port)
1941 if cn in self.cache:
1942 self.cache[cn].close()
1943 del self.cache[cn]
1944
1945 def close_connections(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001946 for cn in list(self.cache.keys()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001947 self.cache[cn].close()
1948 del self.cache[cn]
1949
1950from . import cvs
1951from . import git
1952from . import gitsm
1953from . import gitannex
1954from . import local
1955from . import svn
1956from . import wget
1957from . import ssh
1958from . import sftp
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001959from . import s3
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001960from . import perforce
1961from . import bzr
1962from . import hg
1963from . import osc
1964from . import repo
1965from . import clearcase
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001966from . import npm
Andrew Geissler82c905d2020-04-13 13:39:40 -05001967from . import npmsw
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001968from . import az
Andrew Geissler595f6302022-01-24 19:11:47 +00001969from . import crate
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001970
1971methods.append(local.Local())
1972methods.append(wget.Wget())
1973methods.append(svn.Svn())
1974methods.append(git.Git())
1975methods.append(gitsm.GitSM())
1976methods.append(gitannex.GitANNEX())
1977methods.append(cvs.Cvs())
1978methods.append(ssh.SSH())
1979methods.append(sftp.SFTP())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001980methods.append(s3.S3())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001981methods.append(perforce.Perforce())
1982methods.append(bzr.Bzr())
1983methods.append(hg.Hg())
1984methods.append(osc.Osc())
1985methods.append(repo.Repo())
1986methods.append(clearcase.ClearCase())
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001987methods.append(npm.Npm())
Andrew Geissler82c905d2020-04-13 13:39:40 -05001988methods.append(npmsw.NpmShrinkWrap())
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001989methods.append(az.Az())
Andrew Geissler595f6302022-01-24 19:11:47 +00001990methods.append(crate.Crate())