blob: 893ec6f6bda20f8b6743443df9a68cae8d249e6a [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] = {}
472 elif ud.localpath and ud.method.supports_checksum(ud):
Andrew Geissler595f6302022-01-24 19:11:47 +0000473 basename = os.path.basename(ud.localpath)
474 if basename:
475 uri_basename = os.path.basename(uri_decoded[loc])
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000476 # Prefix with a slash as a sentinel in case
477 # result_decoded[loc] does not contain one.
478 path = "/" + result_decoded[loc]
479 if uri_basename and basename != uri_basename and path.endswith("/" + uri_basename):
480 result_decoded[loc] = path[1:-len(uri_basename)] + basename
481 elif not path.endswith("/" + basename):
482 result_decoded[loc] = os.path.join(path[1:], basename)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500483 else:
484 return None
485 result = encodeurl(result_decoded)
486 if result == ud.url:
487 return None
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600488 logger.debug2("For url %s returning %s" % (ud.url, result))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500489 return result
490
491methods = []
492urldata_cache = {}
493saved_headrevs = {}
494
495def fetcher_init(d):
496 """
497 Called to initialize the fetchers once the configuration data is known.
498 Calls before this must not hit the cache.
499 """
Andrew Geissler82c905d2020-04-13 13:39:40 -0500500
501 revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
502 try:
503 # fetcher_init is called multiple times, so make sure we only save the
504 # revs the first time it is called.
505 if not bb.fetch2.saved_headrevs:
506 bb.fetch2.saved_headrevs = dict(revs)
507 except:
508 pass
509
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500510 # When to drop SCM head revisions controlled by user policy
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500511 srcrev_policy = d.getVar('BB_SRCREV_POLICY') or "clear"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500512 if srcrev_policy == "cache":
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600513 logger.debug("Keeping SRCREV cache due to cache policy of: %s", srcrev_policy)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500514 elif srcrev_policy == "clear":
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600515 logger.debug("Clearing SRCREV cache due to cache policy of: %s", srcrev_policy)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500516 revs.clear()
517 else:
518 raise FetchError("Invalid SRCREV cache policy of: %s" % srcrev_policy)
519
520 _checksum_cache.init_cache(d)
521
522 for m in methods:
523 if hasattr(m, "init"):
524 m.init(d)
525
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500526def fetcher_parse_save():
527 _checksum_cache.save_extras()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500528
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500529def fetcher_parse_done():
530 _checksum_cache.save_merge()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500531
Brad Bishop19323692019-04-05 15:28:33 -0400532def fetcher_compare_revisions(d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500533 """
Andrew Geissler82c905d2020-04-13 13:39:40 -0500534 Compare the revisions in the persistent cache with the saved values from
535 when bitbake was started and return true if they have changed.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500536 """
537
Andrew Geissler82c905d2020-04-13 13:39:40 -0500538 headrevs = dict(bb.persist_data.persist('BB_URI_HEADREVS', d))
539 return headrevs != bb.fetch2.saved_headrevs
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500540
541def mirror_from_string(data):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500542 mirrors = (data or "").replace('\\n',' ').split()
543 # Split into pairs
544 if len(mirrors) % 2 != 0:
545 bb.warn('Invalid mirror data %s, should have paired members.' % data)
546 return list(zip(*[iter(mirrors)]*2))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500547
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500548def verify_checksum(ud, d, precomputed={}, localpath=None, fatal_nochecksum=True):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500549 """
550 verify the MD5 and SHA256 checksum for downloaded src
551
552 Raises a FetchError if one or both of the SRC_URI checksums do not match
553 the downloaded file, or if BB_STRICT_CHECKSUM is set and there are no
554 checksums specified.
555
556 Returns a dict of checksums that can be stored in a done stamp file and
557 passed in as precomputed parameter in a later call to avoid re-computing
558 the checksums from the file. This allows verifying the checksums of the
559 file against those in the recipe each time, rather than only after
560 downloading. See https://bugzilla.yoctoproject.org/show_bug.cgi?id=5571.
561 """
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":
607 messages.append("No checksum specified for '%s', please add at " \
608 "least one to the recipe:" % ud.localpath)
609 messages.extend(checksum_lines)
610 logger.error("\n".join(messages))
611 raise NoChecksumError("Missing SRC_URI checksum", ud.url)
612
613 bb.event.fire(MissingChecksumEvent(ud.url, **checksum_event), d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500614
615 if strict == "ignore":
Andrew Geissler82c905d2020-04-13 13:39:40 -0500616 return checksum_dict
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500617
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500618 # Log missing sums so user can more easily add them
Andrew Geissler82c905d2020-04-13 13:39:40 -0500619 messages.append("Missing checksum for '%s', consider adding at " \
620 "least one to the recipe:" % ud.localpath)
621 messages.extend(checksum_lines)
622 logger.warning("\n".join(messages))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500623
624 # We want to alert the user if a checksum is defined in the recipe but
625 # it does not match.
Andrew Geissler82c905d2020-04-13 13:39:40 -0500626 messages = []
627 messages.append("Checksum mismatch!")
628 bad_checksum = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500629
Andrew Geissler82c905d2020-04-13 13:39:40 -0500630 for ci in checksum_infos:
631 if ci["expected"] and ci["expected"] != ci["data"]:
Andrew Geissler09036742021-06-25 14:25:14 -0500632 messages.append("File: '%s' has %s checksum '%s' when '%s' was " \
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500633 "expected" % (localpath, ci["id"], ci["data"], ci["expected"]))
Andrew Geissler82c905d2020-04-13 13:39:40 -0500634 bad_checksum = ci["data"]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500635
Andrew Geissler82c905d2020-04-13 13:39:40 -0500636 if bad_checksum:
637 messages.append("If this change is expected (e.g. you have upgraded " \
638 "to a new version without updating the checksums) " \
639 "then you can use these lines within the recipe:")
640 messages.extend(checksum_lines)
641 messages.append("Otherwise you should retry the download and/or " \
642 "check with upstream to determine if the file has " \
643 "become corrupted or otherwise unexpectedly modified.")
644 raise ChecksumError("\n".join(messages), ud.url, bad_checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500645
Andrew Geissler82c905d2020-04-13 13:39:40 -0500646 return checksum_dict
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500647
648def verify_donestamp(ud, d, origud=None):
649 """
650 Check whether the done stamp file has the right checksums (if the fetch
651 method supports them). If it doesn't, delete the done stamp and force
652 a re-download.
653
654 Returns True, if the donestamp exists and is valid, False otherwise. When
655 returning False, any existing done stamps are removed.
656 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500657 if not ud.needdonestamp or (origud and not origud.needdonestamp):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500658 return True
659
Brad Bishop316dfdd2018-06-25 12:45:53 -0400660 if not os.path.exists(ud.localpath):
661 # local path does not exist
662 if os.path.exists(ud.donestamp):
663 # done stamp exists, but the downloaded file does not; the done stamp
664 # must be incorrect, re-trigger the download
665 bb.utils.remove(ud.donestamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500666 return False
667
668 if (not ud.method.supports_checksum(ud) or
669 (origud and not origud.method.supports_checksum(origud))):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400670 # if done stamp exists and checksums not supported; assume the local
671 # file is current
672 return os.path.exists(ud.donestamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500673
674 precomputed_checksums = {}
675 # Only re-use the precomputed checksums if the donestamp is newer than the
676 # file. Do not rely on the mtime of directories, though. If ud.localpath is
677 # a directory, there will probably not be any checksums anyway.
Brad Bishop316dfdd2018-06-25 12:45:53 -0400678 if os.path.exists(ud.donestamp) and (os.path.isdir(ud.localpath) or
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500679 os.path.getmtime(ud.localpath) < os.path.getmtime(ud.donestamp)):
680 try:
681 with open(ud.donestamp, "rb") as cachefile:
682 pickled = pickle.Unpickler(cachefile)
683 precomputed_checksums.update(pickled.load())
684 except Exception as e:
685 # Avoid the warnings on the upgrade path from emtpy done stamp
686 # files to those containing the checksums.
687 if not isinstance(e, EOFError):
688 # Ignore errors, they aren't fatal
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600689 logger.warning("Couldn't load checksums from donestamp %s: %s "
690 "(msg: %s)" % (ud.donestamp, type(e).__name__,
691 str(e)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500692
693 try:
694 checksums = verify_checksum(ud, d, precomputed_checksums)
695 # If the cache file did not have the checksums, compute and store them
696 # as an upgrade path from the previous done stamp file format.
697 if checksums != precomputed_checksums:
698 with open(ud.donestamp, "wb") as cachefile:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600699 p = pickle.Pickler(cachefile, 2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500700 p.dump(checksums)
701 return True
702 except ChecksumError as e:
703 # Checksums failed to verify, trigger re-download and remove the
704 # incorrect stamp file.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600705 logger.warning("Checksum mismatch for local file %s\n"
706 "Cleaning and trying again." % ud.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500707 if os.path.exists(ud.localpath):
708 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500709 bb.utils.remove(ud.donestamp)
710 return False
711
712
713def update_stamp(ud, d):
714 """
715 donestamp is file stamp indicating the whole fetching is done
716 this function update the stamp after verifying the checksum
717 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500718 if not ud.needdonestamp:
719 return
720
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500721 if os.path.exists(ud.donestamp):
722 # Touch the done stamp file to show active use of the download
723 try:
724 os.utime(ud.donestamp, None)
725 except:
726 # Errors aren't fatal here
727 pass
728 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500729 try:
730 checksums = verify_checksum(ud, d)
731 # Store the checksums for later re-verification against the recipe
732 with open(ud.donestamp, "wb") as cachefile:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600733 p = pickle.Pickler(cachefile, 2)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500734 p.dump(checksums)
735 except ChecksumError as e:
736 # Checksums failed to verify, trigger re-download and remove the
737 # incorrect stamp file.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600738 logger.warning("Checksum mismatch for local file %s\n"
739 "Cleaning and trying again." % ud.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500740 if os.path.exists(ud.localpath):
741 rename_bad_checksum(ud, e.checksum)
742 bb.utils.remove(ud.donestamp)
743 raise
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500744
745def subprocess_setup():
746 # Python installs a SIGPIPE handler by default. This is usually not what
747 # non-Python subprocesses expect.
748 # SIGPIPE errors are known issues with gzip/bash
749 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
750
751def get_autorev(d):
752 # only not cache src rev in autorev case
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500753 if d.getVar('BB_SRCREV_POLICY') != "cache":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500754 d.setVar('BB_DONT_CACHE', '1')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500755 return "AUTOINC"
756
757def get_srcrev(d, method_name='sortable_revision'):
758 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500759 Return the revision string, usually for use in the version string (PV) of the current package
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500760 Most packages usually only have one SCM so we just pass on the call.
761 In the multi SCM case, we build a value based on SRCREV_FORMAT which must
762 have been set.
763
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500764 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 -0500765 incremental, other code is then responsible for turning that into an increasing value (if needed)
766
767 A method_name can be supplied to retrieve an alternatively formatted revision from a fetcher, if
768 that fetcher provides a method with the given name and the same signature as sortable_revision.
769 """
770
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000771 d.setVar("__BBSEENSRCREV", "1")
Andrew Geissler5199d832021-09-24 16:47:35 -0500772 recursion = d.getVar("__BBINSRCREV")
773 if recursion:
774 raise FetchError("There are recursive references in fetcher variables, likely through SRC_URI")
775 d.setVar("__BBINSRCREV", True)
776
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500777 scms = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500778 fetcher = Fetch(d.getVar('SRC_URI').split(), d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500779 urldata = fetcher.ud
780 for u in urldata:
781 if urldata[u].method.supports_srcrev():
782 scms.append(u)
783
Andrew Geissler595f6302022-01-24 19:11:47 +0000784 if not scms:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500785 raise FetchError("SRCREV was used yet no valid SCM was found in SRC_URI")
786
787 if len(scms) == 1 and len(urldata[scms[0]].names) == 1:
788 autoinc, rev = getattr(urldata[scms[0]].method, method_name)(urldata[scms[0]], d, urldata[scms[0]].names[0])
789 if len(rev) > 10:
790 rev = rev[:10]
Andrew Geissler5199d832021-09-24 16:47:35 -0500791 d.delVar("__BBINSRCREV")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500792 if autoinc:
793 return "AUTOINC+" + rev
794 return rev
795
796 #
797 # Mutiple SCMs are in SRC_URI so we resort to SRCREV_FORMAT
798 #
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500799 format = d.getVar('SRCREV_FORMAT')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500800 if not format:
Brad Bishop19323692019-04-05 15:28:33 -0400801 raise FetchError("The SRCREV_FORMAT variable must be set when multiple SCMs are used.\n"\
802 "The SCMs are:\n%s" % '\n'.join(scms))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500803
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600804 name_to_rev = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500805 seenautoinc = False
806 for scm in scms:
807 ud = urldata[scm]
808 for name in ud.names:
809 autoinc, rev = getattr(ud.method, method_name)(ud, d, name)
810 seenautoinc = seenautoinc or autoinc
811 if len(rev) > 10:
812 rev = rev[:10]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600813 name_to_rev[name] = rev
814 # Replace names by revisions in the SRCREV_FORMAT string. The approach used
815 # here can handle names being prefixes of other names and names appearing
816 # as substrings in revisions (in which case the name should not be
817 # expanded). The '|' regular expression operator tries matches from left to
818 # right, so we need to sort the names with the longest ones first.
819 names_descending_len = sorted(name_to_rev, key=len, reverse=True)
820 name_to_rev_re = "|".join(re.escape(name) for name in names_descending_len)
821 format = re.sub(name_to_rev_re, lambda match: name_to_rev[match.group(0)], format)
822
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500823 if seenautoinc:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500824 format = "AUTOINC+" + format
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500825
Andrew Geissler5199d832021-09-24 16:47:35 -0500826 d.delVar("__BBINSRCREV")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500827 return format
828
829def localpath(url, d):
830 fetcher = bb.fetch2.Fetch([url], d)
831 return fetcher.localpath(url)
832
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500833# Need to export PATH as binary could be in metadata paths
834# rather than host provided
835# Also include some other variables.
836FETCH_EXPORT_VARS = ['HOME', 'PATH',
837 'HTTP_PROXY', 'http_proxy',
838 'HTTPS_PROXY', 'https_proxy',
839 'FTP_PROXY', 'ftp_proxy',
840 'FTPS_PROXY', 'ftps_proxy',
841 'NO_PROXY', 'no_proxy',
842 'ALL_PROXY', 'all_proxy',
843 'GIT_PROXY_COMMAND',
844 'GIT_SSH',
Patrick Williams03907ee2022-05-01 06:28:52 -0500845 'GIT_SSH_COMMAND',
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500846 'GIT_SSL_CAINFO',
847 'GIT_SMART_HTTP',
848 'SSH_AUTH_SOCK', 'SSH_AGENT_PID',
849 'SOCKS5_USER', 'SOCKS5_PASSWD',
850 'DBUS_SESSION_BUS_ADDRESS',
851 'P4CONFIG',
852 'SSL_CERT_FILE',
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',
856 'AWS_DEFAULT_REGION']
857
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000858def get_fetcher_environment(d):
859 newenv = {}
860 origenv = d.getVar("BB_ORIGENV")
861 for name in bb.fetch2.FETCH_EXPORT_VARS:
862 value = d.getVar(name)
863 if not value and origenv:
864 value = origenv.getVar(name)
865 if value:
866 newenv[name] = value
867 return newenv
868
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600869def runfetchcmd(cmd, d, quiet=False, cleanup=None, log=None, workdir=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500870 """
871 Run cmd returning the command output
872 Raise an error if interrupted or cmd fails
873 Optionally echo command output to stdout
874 Optionally remove the files/directories listed in cleanup upon failure
875 """
876
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500877 exportvars = FETCH_EXPORT_VARS
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500878
879 if not cleanup:
880 cleanup = []
881
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800882 # If PATH contains WORKDIR which contains PV-PR which contains SRCPV we
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500883 # can end up in circular recursion here so give the option of breaking it
884 # in a data store copy.
885 try:
886 d.getVar("PV")
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800887 d.getVar("PR")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500888 except bb.data_smart.ExpansionError:
889 d = bb.data.createCopy(d)
890 d.setVar("PV", "fetcheravoidrecurse")
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800891 d.setVar("PR", "fetcheravoidrecurse")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500892
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600893 origenv = d.getVar("BB_ORIGENV", False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500894 for var in exportvars:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500895 val = d.getVar(var) or (origenv and origenv.getVar(var))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500896 if val:
897 cmd = 'export ' + var + '=\"%s\"; %s' % (val, cmd)
898
Brad Bishop316dfdd2018-06-25 12:45:53 -0400899 # Disable pseudo as it may affect ssh, potentially causing it to hang.
900 cmd = 'export PSEUDO_DISABLED=1; ' + cmd
901
Brad Bishop19323692019-04-05 15:28:33 -0400902 if workdir:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600903 logger.debug("Running '%s' in %s" % (cmd, workdir))
Brad Bishop19323692019-04-05 15:28:33 -0400904 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600905 logger.debug("Running %s", cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500906
907 success = False
908 error_message = ""
909
910 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600911 (output, errors) = bb.process.run(cmd, log=log, shell=True, stderr=subprocess.PIPE, cwd=workdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500912 success = True
913 except bb.process.NotFoundError as e:
Andrew Geisslereff27472021-10-29 15:35:00 -0500914 error_message = "Fetch command %s not found" % (e.command)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500915 except bb.process.ExecutionError as e:
916 if e.stdout:
917 output = "output:\n%s\n%s" % (e.stdout, e.stderr)
918 elif e.stderr:
919 output = "output:\n%s" % e.stderr
920 else:
921 output = "no output"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600922 error_message = "Fetch command %s failed with exit code %s, %s" % (e.command, e.exitcode, output)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500923 except bb.process.CmdError as e:
924 error_message = "Fetch command %s could not be run:\n%s" % (e.command, e.msg)
925 if not success:
926 for f in cleanup:
927 try:
928 bb.utils.remove(f, True)
929 except OSError:
930 pass
931
932 raise FetchError(error_message)
933
934 return output
935
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500936def check_network_access(d, info, url):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500937 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500938 log remote network access, and error if BB_NO_NETWORK is set or the given
939 URI is untrusted
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500940 """
Brad Bishop19323692019-04-05 15:28:33 -0400941 if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500942 raise NetworkAccess(url, info)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500943 elif not trusted_network(d, url):
944 raise UntrustedUrl(url, info)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500945 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600946 logger.debug("Fetcher accessed the network with the command %s" % info)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500947
948def build_mirroruris(origud, mirrors, ld):
949 uris = []
950 uds = []
951
952 replacements = {}
953 replacements["TYPE"] = origud.type
954 replacements["HOST"] = origud.host
955 replacements["PATH"] = origud.path
956 replacements["BASENAME"] = origud.path.split("/")[-1]
957 replacements["MIRRORNAME"] = origud.host.replace(':','.') + origud.path.replace('/', '.').replace('*', '.')
958
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500959 def adduri(ud, uris, uds, mirrors, tarballs):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500960 for line in mirrors:
961 try:
962 (find, replace) = line
963 except ValueError:
964 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500965
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500966 for tarball in tarballs:
967 newuri = uri_replace(ud, find, replace, replacements, ld, tarball)
968 if not newuri or newuri in uris or newuri == origud.url:
969 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500970
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500971 if not trusted_network(ld, newuri):
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600972 logger.debug("Mirror %s not in the list of trusted networks, skipping" % (newuri))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500973 continue
Patrick Williamsd7e96312015-09-22 08:09:05 -0500974
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500975 # Create a local copy of the mirrors minus the current line
976 # this will prevent us from recursively processing the same line
977 # as well as indirect recursion A -> B -> C -> A
978 localmirrors = list(mirrors)
979 localmirrors.remove(line)
980
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500981 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500982 newud = FetchData(newuri, ld)
Andrew Geissler87f5cff2022-09-30 13:13:31 -0500983 newud.ignore_checksums = True
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500984 newud.setup_localpath(ld)
985 except bb.fetch2.BBFetchException as e:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600986 logger.debug("Mirror fetch failure for url %s (original url: %s)" % (newuri, origud.url))
987 logger.debug(str(e))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500988 try:
989 # setup_localpath of file:// urls may fail, we should still see
990 # if mirrors of the url exist
991 adduri(newud, uris, uds, localmirrors, tarballs)
992 except UnboundLocalError:
993 pass
994 continue
995 uris.append(newuri)
996 uds.append(newud)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500997
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500998 adduri(newud, uris, uds, localmirrors, tarballs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500999
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001000 adduri(origud, uris, uds, mirrors, origud.mirrortarballs or [None])
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001001
1002 return uris, uds
1003
1004def rename_bad_checksum(ud, suffix):
1005 """
1006 Renames files to have suffix from parameter
1007 """
1008
1009 if ud.localpath is None:
1010 return
1011
1012 new_localpath = "%s_bad-checksum_%s" % (ud.localpath, suffix)
1013 bb.warn("Renaming %s to %s" % (ud.localpath, new_localpath))
Brad Bishop79641f22019-09-10 07:20:22 -04001014 if not bb.utils.movefile(ud.localpath, new_localpath):
1015 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 -05001016
1017
1018def try_mirror_url(fetch, origud, ud, ld, check = False):
1019 # Return of None or a value means we're finished
1020 # False means try another url
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001021
1022 if ud.lockfile and ud.lockfile != origud.lockfile:
1023 lf = bb.utils.lockfile(ud.lockfile)
1024
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001025 try:
1026 if check:
1027 found = ud.method.checkstatus(fetch, ud, ld)
1028 if found:
1029 return found
1030 return False
1031
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001032 if not verify_donestamp(ud, ld, origud) or ud.method.need_update(ud, ld):
1033 ud.method.download(ud, ld)
1034 if hasattr(ud.method,"build_mirror_data"):
1035 ud.method.build_mirror_data(ud, ld)
1036
1037 if not ud.localpath or not os.path.exists(ud.localpath):
1038 return False
1039
1040 if ud.localpath == origud.localpath:
1041 return ud.localpath
1042
1043 # We may be obtaining a mirror tarball which needs further processing by the real fetcher
1044 # If that tarball is a local file:// we need to provide a symlink to it
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001045 dldir = ld.getVar("DL_DIR")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001046
1047 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 -05001048 # Create donestamp in old format to avoid triggering a re-download
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001049 if ud.donestamp:
1050 bb.utils.mkdirhier(os.path.dirname(ud.donestamp))
1051 open(ud.donestamp, 'w').close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001052 dest = os.path.join(dldir, os.path.basename(ud.localpath))
1053 if not os.path.exists(dest):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001054 # In case this is executing without any file locks held (as is
1055 # the case for file:// URLs), two tasks may end up here at the
1056 # same time, in which case we do not want the second task to
1057 # fail when the link has already been created by the first task.
1058 try:
1059 os.symlink(ud.localpath, dest)
1060 except FileExistsError:
1061 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001062 if not verify_donestamp(origud, ld) or origud.method.need_update(origud, ld):
1063 origud.method.download(origud, ld)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001064 if hasattr(origud.method, "build_mirror_data"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001065 origud.method.build_mirror_data(origud, ld)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001066 return origud.localpath
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001067 # Otherwise the result is a local file:// and we symlink to it
Andrew Geissler09209ee2020-12-13 08:44:15 -06001068 ensure_symlink(ud.localpath, origud.localpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001069 update_stamp(origud, ld)
1070 return ud.localpath
1071
1072 except bb.fetch2.NetworkAccess:
1073 raise
1074
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001075 except IOError as e:
Brad Bishop19323692019-04-05 15:28:33 -04001076 if e.errno in [errno.ESTALE]:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001077 logger.warning("Stale Error Observed %s." % ud.url)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001078 return False
1079 raise
1080
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001081 except bb.fetch2.BBFetchException as e:
1082 if isinstance(e, ChecksumError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001083 logger.warning("Mirror checksum failure for url %s (original url: %s)\nCleaning and trying again." % (ud.url, origud.url))
1084 logger.warning(str(e))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001085 if os.path.exists(ud.localpath):
1086 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001087 elif isinstance(e, NoChecksumError):
1088 raise
1089 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001090 logger.debug("Mirror fetch failure for url %s (original url: %s)" % (ud.url, origud.url))
1091 logger.debug(str(e))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001092 try:
1093 ud.method.clean(ud, ld)
1094 except UnboundLocalError:
1095 pass
1096 return False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001097 finally:
1098 if ud.lockfile and ud.lockfile != origud.lockfile:
1099 bb.utils.unlockfile(lf)
1100
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001101
Andrew Geissler09209ee2020-12-13 08:44:15 -06001102def ensure_symlink(target, link_name):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001103 if not os.path.exists(link_name):
Andrew Geissler615f2f12022-07-15 14:00:58 -05001104 dirname = os.path.dirname(link_name)
1105 bb.utils.mkdirhier(dirname)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001106 if os.path.islink(link_name):
1107 # Broken symbolic link
1108 os.unlink(link_name)
1109
1110 # In case this is executing without any file locks held (as is
1111 # the case for file:// URLs), two tasks may end up here at the
1112 # same time, in which case we do not want the second task to
1113 # fail when the link has already been created by the first task.
1114 try:
1115 os.symlink(target, link_name)
1116 except FileExistsError:
1117 pass
1118
1119
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001120def try_mirrors(fetch, d, origud, mirrors, check = False):
1121 """
1122 Try to use a mirrored version of the sources.
1123 This method will be automatically called before the fetchers go.
1124
1125 d Is a bb.data instance
1126 uri is the original uri we're trying to download
1127 mirrors is the list of mirrors we're going to try
1128 """
1129 ld = d.createCopy()
1130
1131 uris, uds = build_mirroruris(origud, mirrors, ld)
1132
1133 for index, uri in enumerate(uris):
1134 ret = try_mirror_url(fetch, origud, uds[index], ld, check)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001135 if ret:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001136 return ret
1137 return None
1138
1139def trusted_network(d, url):
1140 """
1141 Use a trusted url during download if networking is enabled and
1142 BB_ALLOWED_NETWORKS is set globally or for a specific recipe.
1143 Note: modifies SRC_URI & mirrors.
1144 """
Brad Bishop19323692019-04-05 15:28:33 -04001145 if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001146 return True
1147
1148 pkgname = d.expand(d.getVar('PN', False))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001149 trusted_hosts = None
1150 if pkgname:
1151 trusted_hosts = d.getVarFlag('BB_ALLOWED_NETWORKS', pkgname, False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001152
1153 if not trusted_hosts:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001154 trusted_hosts = d.getVar('BB_ALLOWED_NETWORKS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001155
1156 # Not enabled.
1157 if not trusted_hosts:
1158 return True
1159
1160 scheme, network, path, user, passwd, param = decodeurl(url)
1161
1162 if not network:
1163 return True
1164
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001165 network = network.split(':')[0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001166 network = network.lower()
1167
1168 for host in trusted_hosts.split(" "):
1169 host = host.lower()
1170 if host.startswith("*.") and ("." + network).endswith(host[1:]):
1171 return True
1172 if host == network:
1173 return True
1174
1175 return False
1176
1177def srcrev_internal_helper(ud, d, name):
1178 """
1179 Return:
1180 a) a source revision if specified
1181 b) latest revision if SRCREV="AUTOINC"
1182 c) None if not specified
1183 """
1184
1185 srcrev = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001186 pn = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001187 attempts = []
1188 if name != '' and pn:
Patrick Williams213cb262021-08-07 19:21:33 -05001189 attempts.append("SRCREV_%s:pn-%s" % (name, pn))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001190 if name != '':
1191 attempts.append("SRCREV_%s" % name)
1192 if pn:
Patrick Williams213cb262021-08-07 19:21:33 -05001193 attempts.append("SRCREV:pn-%s" % pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001194 attempts.append("SRCREV")
1195
1196 for a in attempts:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001197 srcrev = d.getVar(a)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001198 if srcrev and srcrev != "INVALID":
1199 break
1200
1201 if 'rev' in ud.parm and 'tag' in ud.parm:
1202 raise FetchError("Please specify a ;rev= parameter or a ;tag= parameter in the url %s but not both." % (ud.url))
1203
1204 if 'rev' in ud.parm or 'tag' in ud.parm:
1205 if 'rev' in ud.parm:
1206 parmrev = ud.parm['rev']
1207 else:
1208 parmrev = ud.parm['tag']
1209 if srcrev == "INVALID" or not srcrev:
1210 return parmrev
1211 if srcrev != parmrev:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001212 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 -05001213 return parmrev
1214
1215 if srcrev == "INVALID" or not srcrev:
1216 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)
1217 if srcrev == "AUTOINC":
1218 srcrev = ud.method.latest_revision(ud, d, name)
1219
1220 return srcrev
1221
1222def get_checksum_file_list(d):
1223 """ Get a list of files checksum in SRC_URI
1224
1225 Returns the resolved local paths of all local file entries in
1226 SRC_URI as a space-separated string
1227 """
1228 fetch = Fetch([], d, cache = False, localonly = True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001229 filelist = []
1230 for u in fetch.urls:
1231 ud = fetch.ud[u]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001232 if ud and isinstance(ud.method, local.Local):
Andrew Geissler615f2f12022-07-15 14:00:58 -05001233 found = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001234 paths = ud.method.localpaths(ud, d)
1235 for f in paths:
1236 pth = ud.decodedurl
Andrew Geissler615f2f12022-07-15 14:00:58 -05001237 if os.path.exists(f):
1238 found = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001239 filelist.append(f + ":" + str(os.path.exists(f)))
Andrew Geissler615f2f12022-07-15 14:00:58 -05001240 if not found:
1241 bb.fatal(("Unable to get checksum for %s SRC_URI entry %s: file could not be found"
1242 "\nThe following paths were searched:"
1243 "\n%s") % (d.getVar('PN'), os.path.basename(f), '\n'.join(paths)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001244
1245 return " ".join(filelist)
1246
Andrew Geissler82c905d2020-04-13 13:39:40 -05001247def get_file_checksums(filelist, pn, localdirsexclude):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001248 """Get a list of the checksums for a list of local files
1249
1250 Returns the checksums for a list of local files, caching the results as
1251 it proceeds
1252
1253 """
Andrew Geissler82c905d2020-04-13 13:39:40 -05001254 return _checksum_cache.get_checksums(filelist, pn, localdirsexclude)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001255
1256
1257class FetchData(object):
1258 """
1259 A class which represents the fetcher state for a given URI.
1260 """
1261 def __init__(self, url, d, localonly = False):
1262 # localpath is the location of a downloaded result. If not set, the file is local.
1263 self.donestamp = None
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001264 self.needdonestamp = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001265 self.localfile = ""
1266 self.localpath = None
1267 self.lockfile = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001268 self.mirrortarballs = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001269 self.basename = None
1270 self.basepath = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001271 (self.type, self.host, self.path, self.user, self.pswd, self.parm) = decodeurl(d.expand(url))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001272 self.date = self.getSRCDate(d)
1273 self.url = url
1274 if not self.user and "user" in self.parm:
1275 self.user = self.parm["user"]
1276 if not self.pswd and "pswd" in self.parm:
1277 self.pswd = self.parm["pswd"]
1278 self.setup = False
1279
Andrew Geissler82c905d2020-04-13 13:39:40 -05001280 def configure_checksum(checksum_id):
1281 if "name" in self.parm:
1282 checksum_name = "%s.%ssum" % (self.parm["name"], checksum_id)
1283 else:
1284 checksum_name = "%ssum" % checksum_id
1285
1286 setattr(self, "%s_name" % checksum_id, checksum_name)
1287
1288 if checksum_name in self.parm:
1289 checksum_expected = self.parm[checksum_name]
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001290 elif self.type not in ["http", "https", "ftp", "ftps", "sftp", "s3", "az"]:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001291 checksum_expected = None
1292 else:
1293 checksum_expected = d.getVarFlag("SRC_URI", checksum_name)
1294
1295 setattr(self, "%s_expected" % checksum_id, checksum_expected)
1296
1297 for checksum_id in CHECKSUM_LIST:
1298 configure_checksum(checksum_id)
1299
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001300 self.ignore_checksums = False
1301
1302 self.names = self.parm.get("name",'default').split(',')
1303
1304 self.method = None
1305 for m in methods:
1306 if m.supports(self, d):
1307 self.method = m
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001308 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001309
1310 if not self.method:
1311 raise NoMethodError(url)
1312
1313 if localonly and not isinstance(self.method, local.Local):
1314 raise NonLocalMethod()
1315
1316 if self.parm.get("proto", None) and "protocol" not in self.parm:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001317 logger.warning('Consider updating %s recipe to use "protocol" not "proto" in SRC_URI.', d.getVar('PN'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001318 self.parm["protocol"] = self.parm.get("proto", None)
1319
1320 if hasattr(self.method, "urldata_init"):
1321 self.method.urldata_init(self, d)
1322
1323 if "localpath" in self.parm:
1324 # if user sets localpath for file, use it instead.
1325 self.localpath = self.parm["localpath"]
1326 self.basename = os.path.basename(self.localpath)
1327 elif self.localfile:
1328 self.localpath = self.method.localpath(self, d)
1329
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001330 dldir = d.getVar("DL_DIR")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001331
1332 if not self.needdonestamp:
1333 return
1334
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001335 # Note: .done and .lock files should always be in DL_DIR whereas localpath may not be.
1336 if self.localpath and self.localpath.startswith(dldir):
1337 basepath = self.localpath
1338 elif self.localpath:
1339 basepath = dldir + os.sep + os.path.basename(self.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001340 elif self.basepath or self.basename:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001341 basepath = dldir + os.sep + (self.basepath or self.basename)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001342 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001343 bb.fatal("Can't determine lock path for url %s" % url)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001344
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001345 self.donestamp = basepath + '.done'
1346 self.lockfile = basepath + '.lock'
1347
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001348 def setup_revisions(self, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001349 self.revisions = {}
1350 for name in self.names:
1351 self.revisions[name] = srcrev_internal_helper(self, d, name)
1352
1353 # add compatibility code for non name specified case
1354 if len(self.names) == 1:
1355 self.revision = self.revisions[self.names[0]]
1356
1357 def setup_localpath(self, d):
1358 if not self.localpath:
1359 self.localpath = self.method.localpath(self, d)
1360
1361 def getSRCDate(self, d):
1362 """
1363 Return the SRC Date for the component
1364
1365 d the bb.data module
1366 """
1367 if "srcdate" in self.parm:
1368 return self.parm['srcdate']
1369
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001370 pn = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001371
1372 if pn:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001373 return d.getVar("SRCDATE_%s" % pn) or d.getVar("SRCDATE") or d.getVar("DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001374
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001375 return d.getVar("SRCDATE") or d.getVar("DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001376
1377class FetchMethod(object):
1378 """Base class for 'fetch'ing data"""
1379
1380 def __init__(self, urls=None):
1381 self.urls = []
1382
1383 def supports(self, urldata, d):
1384 """
1385 Check to see if this fetch class supports a given url.
1386 """
1387 return 0
1388
1389 def localpath(self, urldata, d):
1390 """
1391 Return the local filename of a given url assuming a successful fetch.
1392 Can also setup variables in urldata for use in go (saving code duplication
1393 and duplicate code execution)
1394 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001395 return os.path.join(d.getVar("DL_DIR"), urldata.localfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001396
1397 def supports_checksum(self, urldata):
1398 """
1399 Is localpath something that can be represented by a checksum?
1400 """
1401
1402 # We cannot compute checksums for directories
Andrew Geissler82c905d2020-04-13 13:39:40 -05001403 if os.path.isdir(urldata.localpath):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001404 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001405 return True
1406
1407 def recommends_checksum(self, urldata):
1408 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001409 Is the backend on where checksumming is recommended (should warnings
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001410 be displayed if there is no checksum)?
1411 """
1412 return False
1413
Andrew Geissler82c905d2020-04-13 13:39:40 -05001414 def verify_donestamp(self, ud, d):
1415 """
1416 Verify the donestamp file
1417 """
1418 return verify_donestamp(ud, d)
1419
1420 def update_donestamp(self, ud, d):
1421 """
1422 Update the donestamp file
1423 """
1424 update_stamp(ud, d)
1425
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001426 def _strip_leading_slashes(self, relpath):
1427 """
1428 Remove leading slash as os.path.join can't cope
1429 """
1430 while os.path.isabs(relpath):
1431 relpath = relpath[1:]
1432 return relpath
1433
1434 def setUrls(self, urls):
1435 self.__urls = urls
1436
1437 def getUrls(self):
1438 return self.__urls
1439
1440 urls = property(getUrls, setUrls, None, "Urls property")
1441
1442 def need_update(self, ud, d):
1443 """
1444 Force a fetch, even if localpath exists?
1445 """
1446 if os.path.exists(ud.localpath):
1447 return False
1448 return True
1449
1450 def supports_srcrev(self):
1451 """
1452 The fetcher supports auto source revisions (SRCREV)
1453 """
1454 return False
1455
1456 def download(self, urldata, d):
1457 """
1458 Fetch urls
1459 Assumes localpath was called first
1460 """
Brad Bishop19323692019-04-05 15:28:33 -04001461 raise NoMethodError(urldata.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001462
1463 def unpack(self, urldata, rootdir, data):
1464 iterate = False
1465 file = urldata.localpath
1466
1467 try:
1468 unpack = bb.utils.to_boolean(urldata.parm.get('unpack'), True)
1469 except ValueError as exc:
1470 bb.fatal("Invalid value for 'unpack' parameter for %s: %s" %
1471 (file, urldata.parm.get('unpack')))
1472
1473 base, ext = os.path.splitext(file)
1474 if ext in ['.gz', '.bz2', '.Z', '.xz', '.lz']:
1475 efile = os.path.join(rootdir, os.path.basename(base))
1476 else:
1477 efile = file
1478 cmd = None
1479
1480 if unpack:
Andrew Geissler595f6302022-01-24 19:11:47 +00001481 tar_cmd = 'tar --extract --no-same-owner'
1482 if 'striplevel' in urldata.parm:
1483 tar_cmd += ' --strip-components=%s' % urldata.parm['striplevel']
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001484 if file.endswith('.tar'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001485 cmd = '%s -f %s' % (tar_cmd, file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001486 elif file.endswith('.tgz') or file.endswith('.tar.gz') or file.endswith('.tar.Z'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001487 cmd = '%s -z -f %s' % (tar_cmd, file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001488 elif file.endswith('.tbz') or file.endswith('.tbz2') or file.endswith('.tar.bz2'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001489 cmd = 'bzip2 -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001490 elif file.endswith('.gz') or file.endswith('.Z') or file.endswith('.z'):
1491 cmd = 'gzip -dc %s > %s' % (file, efile)
1492 elif file.endswith('.bz2'):
1493 cmd = 'bzip2 -dc %s > %s' % (file, efile)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001494 elif file.endswith('.txz') or file.endswith('.tar.xz'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001495 cmd = 'xz -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001496 elif file.endswith('.xz'):
1497 cmd = 'xz -dc %s > %s' % (file, efile)
1498 elif file.endswith('.tar.lz'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001499 cmd = 'lzip -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001500 elif file.endswith('.lz'):
1501 cmd = 'lzip -dc %s > %s' % (file, efile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001502 elif file.endswith('.tar.7z'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001503 cmd = '7z x -so %s | %s -f -' % (file, tar_cmd)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001504 elif file.endswith('.7z'):
1505 cmd = '7za x -y %s 1>/dev/null' % file
Andrew Geissler6ce62a22020-11-30 19:58:47 -06001506 elif file.endswith('.tzst') or file.endswith('.tar.zst'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001507 cmd = 'zstd --decompress --stdout %s | %s -f -' % (file, tar_cmd)
Andrew Geissler6ce62a22020-11-30 19:58:47 -06001508 elif file.endswith('.zst'):
1509 cmd = 'zstd --decompress --stdout %s > %s' % (file, efile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001510 elif file.endswith('.zip') or file.endswith('.jar'):
1511 try:
1512 dos = bb.utils.to_boolean(urldata.parm.get('dos'), False)
1513 except ValueError as exc:
1514 bb.fatal("Invalid value for 'dos' parameter for %s: %s" %
1515 (file, urldata.parm.get('dos')))
1516 cmd = 'unzip -q -o'
1517 if dos:
1518 cmd = '%s -a' % cmd
1519 cmd = "%s '%s'" % (cmd, file)
1520 elif file.endswith('.rpm') or file.endswith('.srpm'):
1521 if 'extract' in urldata.parm:
1522 unpack_file = urldata.parm.get('extract')
1523 cmd = 'rpm2cpio.sh %s | cpio -id %s' % (file, unpack_file)
1524 iterate = True
1525 iterate_file = unpack_file
1526 else:
1527 cmd = 'rpm2cpio.sh %s | cpio -id' % (file)
1528 elif file.endswith('.deb') or file.endswith('.ipk'):
Brad Bishopa5c52ff2018-11-23 10:55:50 +13001529 output = subprocess.check_output(['ar', '-t', file], preexec_fn=subprocess_setup)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001530 datafile = None
1531 if output:
1532 for line in output.decode().splitlines():
1533 if line.startswith('data.tar.'):
1534 datafile = line
1535 break
1536 else:
1537 raise UnpackError("Unable to unpack deb/ipk package - does not contain data.tar.* file", urldata.url)
1538 else:
1539 raise UnpackError("Unable to unpack deb/ipk package - could not list contents", urldata.url)
Andrew Geissler595f6302022-01-24 19:11:47 +00001540 cmd = 'ar x %s %s && %s -p -f %s && rm %s' % (file, datafile, tar_cmd, datafile, datafile)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001541
1542 # If 'subdir' param exists, create a dir and use it as destination for unpack cmd
1543 if 'subdir' in urldata.parm:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001544 subdir = urldata.parm.get('subdir')
1545 if os.path.isabs(subdir):
1546 if not os.path.realpath(subdir).startswith(os.path.realpath(rootdir)):
1547 raise UnpackError("subdir argument isn't a subdirectory of unpack root %s" % rootdir, urldata.url)
1548 unpackdir = subdir
1549 else:
1550 unpackdir = os.path.join(rootdir, subdir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001551 bb.utils.mkdirhier(unpackdir)
1552 else:
1553 unpackdir = rootdir
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001554
1555 if not unpack or not cmd:
1556 # If file == dest, then avoid any copies, as we already put the file into dest!
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001557 dest = os.path.join(unpackdir, os.path.basename(file))
1558 if file != dest and not (os.path.exists(dest) and os.path.samefile(file, dest)):
1559 destdir = '.'
1560 # For file:// entries all intermediate dirs in path must be created at destination
1561 if urldata.type == "file":
1562 # Trailing '/' does a copying to wrong place
1563 urlpath = urldata.path.rstrip('/')
1564 # Want files places relative to cwd so no leading '/'
1565 urlpath = urlpath.lstrip('/')
1566 if urlpath.find("/") != -1:
1567 destdir = urlpath.rsplit("/", 1)[0] + '/'
1568 bb.utils.mkdirhier("%s/%s" % (unpackdir, destdir))
Andrew Geisslerc3d88e42020-10-02 09:45:00 -05001569 cmd = 'cp -fpPRH "%s" "%s"' % (file, destdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001570
1571 if not cmd:
1572 return
1573
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001574 path = data.getVar('PATH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001575 if path:
1576 cmd = "PATH=\"%s\" %s" % (path, cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001577 bb.note("Unpacking %s to %s/" % (file, unpackdir))
1578 ret = subprocess.call(cmd, preexec_fn=subprocess_setup, shell=True, cwd=unpackdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001579
1580 if ret != 0:
1581 raise UnpackError("Unpack command %s failed with return value %s" % (cmd, ret), urldata.url)
1582
1583 if iterate is True:
1584 iterate_urldata = urldata
1585 iterate_urldata.localpath = "%s/%s" % (rootdir, iterate_file)
1586 self.unpack(urldata, rootdir, data)
1587
1588 return
1589
1590 def clean(self, urldata, d):
1591 """
1592 Clean any existing full or partial download
1593 """
1594 bb.utils.remove(urldata.localpath)
1595
1596 def try_premirror(self, urldata, d):
1597 """
1598 Should premirrors be used?
1599 """
1600 return True
1601
Andrew Geissler82c905d2020-04-13 13:39:40 -05001602 def try_mirrors(self, fetch, urldata, d, mirrors, check=False):
1603 """
1604 Try to use a mirror
1605 """
1606 return bool(try_mirrors(fetch, d, urldata, mirrors, check))
1607
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001608 def checkstatus(self, fetch, urldata, d):
1609 """
1610 Check the status of a URL
1611 Assumes localpath was called first
1612 """
Brad Bishop19323692019-04-05 15:28:33 -04001613 logger.info("URL %s could not be checked for status since no method exists.", urldata.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001614 return True
1615
1616 def latest_revision(self, ud, d, name):
1617 """
1618 Look in the cache for the latest revision, if not present ask the SCM.
1619 """
1620 if not hasattr(self, "_latest_revision"):
Brad Bishop19323692019-04-05 15:28:33 -04001621 raise ParameterError("The fetcher for this URL does not support _latest_revision", ud.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001622
1623 revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
1624 key = self.generate_revision_key(ud, d, name)
1625 try:
1626 return revs[key]
1627 except KeyError:
1628 revs[key] = rev = self._latest_revision(ud, d, name)
1629 return rev
1630
1631 def sortable_revision(self, ud, d, name):
1632 latest_rev = self._build_revision(ud, d, name)
1633 return True, str(latest_rev)
1634
1635 def generate_revision_key(self, ud, d, name):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001636 return self._revision_key(ud, d, name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001637
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001638 def latest_versionstring(self, ud, d):
1639 """
1640 Compute the latest release name like "x.y.x" in "x.y.x+gitHASH"
1641 by searching through the tags output of ls-remote, comparing
1642 versions and returning the highest match as a (version, revision) pair.
1643 """
1644 return ('', '')
1645
Andrew Geissler82c905d2020-04-13 13:39:40 -05001646 def done(self, ud, d):
1647 """
1648 Is the download done ?
1649 """
1650 if os.path.exists(ud.localpath):
1651 return True
Andrew Geissler82c905d2020-04-13 13:39:40 -05001652 return False
1653
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001654 def implicit_urldata(self, ud, d):
1655 """
1656 Get a list of FetchData objects for any implicit URLs that will also
1657 be downloaded when we fetch the given URL.
1658 """
1659 return []
1660
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001661class Fetch(object):
1662 def __init__(self, urls, d, cache = True, localonly = False, connection_cache = None):
1663 if localonly and cache:
1664 raise Exception("bb.fetch2.Fetch.__init__: cannot set cache and localonly at same time")
1665
Andrew Geissler595f6302022-01-24 19:11:47 +00001666 if not urls:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001667 urls = d.getVar("SRC_URI").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001668 self.urls = urls
1669 self.d = d
1670 self.ud = {}
1671 self.connection_cache = connection_cache
1672
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001673 fn = d.getVar('FILE')
1674 mc = d.getVar('__BBMULTICONFIG') or ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001675 key = None
1676 if cache and fn:
1677 key = mc + fn + str(id(d))
1678 if key in urldata_cache:
1679 self.ud = urldata_cache[key]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001680
1681 for url in urls:
1682 if url not in self.ud:
1683 try:
1684 self.ud[url] = FetchData(url, d, localonly)
1685 except NonLocalMethod:
1686 if localonly:
1687 self.ud[url] = None
1688 pass
1689
Andrew Geissler82c905d2020-04-13 13:39:40 -05001690 if key:
1691 urldata_cache[key] = self.ud
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001692
1693 def localpath(self, url):
1694 if url not in self.urls:
1695 self.ud[url] = FetchData(url, self.d)
1696
1697 self.ud[url].setup_localpath(self.d)
1698 return self.d.expand(self.ud[url].localpath)
1699
1700 def localpaths(self):
1701 """
1702 Return a list of the local filenames, assuming successful fetch
1703 """
1704 local = []
1705
1706 for u in self.urls:
1707 ud = self.ud[u]
1708 ud.setup_localpath(self.d)
1709 local.append(ud.localpath)
1710
1711 return local
1712
1713 def download(self, urls=None):
1714 """
1715 Fetch all urls
1716 """
1717 if not urls:
1718 urls = self.urls
1719
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001720 network = self.d.getVar("BB_NO_NETWORK")
Brad Bishop19323692019-04-05 15:28:33 -04001721 premirroronly = bb.utils.to_boolean(self.d.getVar("BB_FETCH_PREMIRRORONLY"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001722
1723 for u in urls:
1724 ud = self.ud[u]
1725 ud.setup_localpath(self.d)
1726 m = ud.method
Andrew Geissler82c905d2020-04-13 13:39:40 -05001727 done = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001728
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001729 if ud.lockfile:
1730 lf = bb.utils.lockfile(ud.lockfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001731
1732 try:
1733 self.d.setVar("BB_NO_NETWORK", network)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001734
Andrew Geissler82c905d2020-04-13 13:39:40 -05001735 if m.verify_donestamp(ud, self.d) and not m.need_update(ud, self.d):
1736 done = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001737 elif m.try_premirror(ud, self.d):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001738 logger.debug("Trying PREMIRRORS")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001739 mirrors = mirror_from_string(self.d.getVar('PREMIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001740 done = m.try_mirrors(self, ud, self.d, mirrors)
1741 if done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001742 try:
1743 # early checksum verification so that if the checksum of the premirror
1744 # contents mismatch the fetcher can still try upstream and mirrors
Andrew Geissler82c905d2020-04-13 13:39:40 -05001745 m.update_donestamp(ud, self.d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001746 except ChecksumError as e:
1747 logger.warning("Checksum failure encountered with premirror download of %s - will attempt other sources." % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001748 logger.debug(str(e))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001749 done = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001750
1751 if premirroronly:
1752 self.d.setVar("BB_NO_NETWORK", "1")
1753
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001754 firsterr = None
Andrew Geisslereff27472021-10-29 15:35:00 -05001755 verified_stamp = False
1756 if done:
1757 verified_stamp = m.verify_donestamp(ud, self.d)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001758 if not done and (not verified_stamp or m.need_update(ud, self.d)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001759 try:
1760 if not trusted_network(self.d, ud.url):
1761 raise UntrustedUrl(ud.url)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001762 logger.debug("Trying Upstream")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001763 m.download(ud, self.d)
1764 if hasattr(m, "build_mirror_data"):
1765 m.build_mirror_data(ud, self.d)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001766 done = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001767 # early checksum verify, so that if checksum mismatched,
1768 # fetcher still have chance to fetch from mirror
Andrew Geissler82c905d2020-04-13 13:39:40 -05001769 m.update_donestamp(ud, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001770
1771 except bb.fetch2.NetworkAccess:
1772 raise
1773
1774 except BBFetchException as e:
1775 if isinstance(e, ChecksumError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001776 logger.warning("Checksum failure encountered with download of %s - will attempt other sources if available" % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001777 logger.debug(str(e))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001778 if os.path.exists(ud.localpath):
1779 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001780 elif isinstance(e, NoChecksumError):
1781 raise
1782 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001783 logger.warning('Failed to fetch URL %s, attempting MIRRORS if available' % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001784 logger.debug(str(e))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001785 firsterr = e
1786 # Remove any incomplete fetch
1787 if not verified_stamp:
1788 m.clean(ud, self.d)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001789 logger.debug("Trying MIRRORS")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001790 mirrors = mirror_from_string(self.d.getVar('MIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001791 done = m.try_mirrors(self, ud, self.d, mirrors)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001792
Andrew Geissler82c905d2020-04-13 13:39:40 -05001793 if not done or not m.done(ud, self.d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001794 if firsterr:
1795 logger.error(str(firsterr))
1796 raise FetchError("Unable to fetch URL from any source.", u)
1797
Andrew Geissler82c905d2020-04-13 13:39:40 -05001798 m.update_donestamp(ud, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001799
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001800 except IOError as e:
Brad Bishop19323692019-04-05 15:28:33 -04001801 if e.errno in [errno.ESTALE]:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001802 logger.error("Stale Error Observed %s." % u)
1803 raise ChecksumError("Stale Error Detected")
1804
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001805 except BBFetchException as e:
1806 if isinstance(e, ChecksumError):
1807 logger.error("Checksum failure fetching %s" % u)
1808 raise
1809
1810 finally:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001811 if ud.lockfile:
1812 bb.utils.unlockfile(lf)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001813
1814 def checkstatus(self, urls=None):
1815 """
Andrew Geisslereff27472021-10-29 15:35:00 -05001816 Check all URLs exist upstream.
1817
1818 Returns None if the URLs exist, raises FetchError if the check wasn't
1819 successful but there wasn't an error (such as file not found), and
1820 raises other exceptions in error cases.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001821 """
1822
1823 if not urls:
1824 urls = self.urls
1825
1826 for u in urls:
1827 ud = self.ud[u]
1828 ud.setup_localpath(self.d)
1829 m = ud.method
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001830 logger.debug("Testing URL %s", u)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001831 # First try checking uri, u, from PREMIRRORS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001832 mirrors = mirror_from_string(self.d.getVar('PREMIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001833 ret = m.try_mirrors(self, ud, self.d, mirrors, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001834 if not ret:
1835 # Next try checking from the original uri, u
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001836 ret = m.checkstatus(self, ud, self.d)
1837 if not ret:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001838 # Finally, try checking uri, u, from MIRRORS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001839 mirrors = mirror_from_string(self.d.getVar('MIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001840 ret = m.try_mirrors(self, ud, self.d, mirrors, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001841
1842 if not ret:
1843 raise FetchError("URL %s doesn't work" % u, u)
1844
1845 def unpack(self, root, urls=None):
1846 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001847 Unpack urls to root
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001848 """
1849
1850 if not urls:
1851 urls = self.urls
1852
1853 for u in urls:
1854 ud = self.ud[u]
1855 ud.setup_localpath(self.d)
1856
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001857 if ud.lockfile:
1858 lf = bb.utils.lockfile(ud.lockfile)
1859
1860 ud.method.unpack(ud, root, self.d)
1861
1862 if ud.lockfile:
1863 bb.utils.unlockfile(lf)
1864
1865 def clean(self, urls=None):
1866 """
1867 Clean files that the fetcher gets or places
1868 """
1869
1870 if not urls:
1871 urls = self.urls
1872
1873 for url in urls:
1874 if url not in self.ud:
Brad Bishop19323692019-04-05 15:28:33 -04001875 self.ud[url] = FetchData(url, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001876 ud = self.ud[url]
1877 ud.setup_localpath(self.d)
1878
1879 if not ud.localfile and ud.localpath is None:
1880 continue
1881
1882 if ud.lockfile:
1883 lf = bb.utils.lockfile(ud.lockfile)
1884
1885 ud.method.clean(ud, self.d)
1886 if ud.donestamp:
1887 bb.utils.remove(ud.donestamp)
1888
1889 if ud.lockfile:
1890 bb.utils.unlockfile(lf)
1891
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001892 def expanded_urldata(self, urls=None):
1893 """
1894 Get an expanded list of FetchData objects covering both the given
1895 URLS and any additional implicit URLs that are added automatically by
1896 the appropriate FetchMethod.
1897 """
1898
1899 if not urls:
1900 urls = self.urls
1901
1902 urldata = []
1903 for url in urls:
1904 ud = self.ud[url]
1905 urldata.append(ud)
1906 urldata += ud.method.implicit_urldata(ud, self.d)
1907
1908 return urldata
1909
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001910class FetchConnectionCache(object):
1911 """
1912 A class which represents an container for socket connections.
1913 """
1914 def __init__(self):
1915 self.cache = {}
1916
1917 def get_connection_name(self, host, port):
1918 return host + ':' + str(port)
1919
1920 def add_connection(self, host, port, connection):
1921 cn = self.get_connection_name(host, port)
1922
1923 if cn not in self.cache:
1924 self.cache[cn] = connection
1925
1926 def get_connection(self, host, port):
1927 connection = None
1928
1929 cn = self.get_connection_name(host, port)
1930 if cn in self.cache:
1931 connection = self.cache[cn]
1932
1933 return connection
1934
1935 def remove_connection(self, host, port):
1936 cn = self.get_connection_name(host, port)
1937 if cn in self.cache:
1938 self.cache[cn].close()
1939 del self.cache[cn]
1940
1941 def close_connections(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001942 for cn in list(self.cache.keys()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001943 self.cache[cn].close()
1944 del self.cache[cn]
1945
1946from . import cvs
1947from . import git
1948from . import gitsm
1949from . import gitannex
1950from . import local
1951from . import svn
1952from . import wget
1953from . import ssh
1954from . import sftp
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001955from . import s3
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001956from . import perforce
1957from . import bzr
1958from . import hg
1959from . import osc
1960from . import repo
1961from . import clearcase
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001962from . import npm
Andrew Geissler82c905d2020-04-13 13:39:40 -05001963from . import npmsw
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001964from . import az
Andrew Geissler595f6302022-01-24 19:11:47 +00001965from . import crate
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001966
1967methods.append(local.Local())
1968methods.append(wget.Wget())
1969methods.append(svn.Svn())
1970methods.append(git.Git())
1971methods.append(gitsm.GitSM())
1972methods.append(gitannex.GitANNEX())
1973methods.append(cvs.Cvs())
1974methods.append(ssh.SSH())
1975methods.append(sftp.SFTP())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001976methods.append(s3.S3())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001977methods.append(perforce.Perforce())
1978methods.append(bzr.Bzr())
1979methods.append(hg.Hg())
1980methods.append(osc.Osc())
1981methods.append(repo.Repo())
1982methods.append(clearcase.ClearCase())
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001983methods.append(npm.Npm())
Andrew Geissler82c905d2020-04-13 13:39:40 -05001984methods.append(npmsw.NpmShrinkWrap())
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001985methods.append(az.Az())
Andrew Geissler595f6302022-01-24 19:11:47 +00001986methods.append(crate.Crate())