blob: d37174185a22386521db202e2b93c65374e4e1fa [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):
116 """Exception raised when a url cannot be proccessed due to invalid parameters."""
117 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
185 fetch2 library did not comform to this. Therefore, this URI
186 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
202 "whitelisted" schemes (currently only file://), that requires
203 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])
476 if uri_basename and basename != uri_basename and result_decoded[loc].endswith(uri_basename):
477 result_decoded[loc] = result_decoded[loc].replace(uri_basename, basename)
478 elif not result_decoded[loc].endswith(basename):
479 result_decoded[loc] = os.path.join(result_decoded[loc], basename)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500480 else:
481 return None
482 result = encodeurl(result_decoded)
483 if result == ud.url:
484 return None
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600485 logger.debug2("For url %s returning %s" % (ud.url, result))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500486 return result
487
488methods = []
489urldata_cache = {}
490saved_headrevs = {}
491
492def fetcher_init(d):
493 """
494 Called to initialize the fetchers once the configuration data is known.
495 Calls before this must not hit the cache.
496 """
Andrew Geissler82c905d2020-04-13 13:39:40 -0500497
498 revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
499 try:
500 # fetcher_init is called multiple times, so make sure we only save the
501 # revs the first time it is called.
502 if not bb.fetch2.saved_headrevs:
503 bb.fetch2.saved_headrevs = dict(revs)
504 except:
505 pass
506
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500507 # When to drop SCM head revisions controlled by user policy
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500508 srcrev_policy = d.getVar('BB_SRCREV_POLICY') or "clear"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500509 if srcrev_policy == "cache":
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600510 logger.debug("Keeping SRCREV cache due to cache policy of: %s", srcrev_policy)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500511 elif srcrev_policy == "clear":
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600512 logger.debug("Clearing SRCREV cache due to cache policy of: %s", srcrev_policy)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500513 revs.clear()
514 else:
515 raise FetchError("Invalid SRCREV cache policy of: %s" % srcrev_policy)
516
517 _checksum_cache.init_cache(d)
518
519 for m in methods:
520 if hasattr(m, "init"):
521 m.init(d)
522
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500523def fetcher_parse_save():
524 _checksum_cache.save_extras()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500525
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500526def fetcher_parse_done():
527 _checksum_cache.save_merge()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500528
Brad Bishop19323692019-04-05 15:28:33 -0400529def fetcher_compare_revisions(d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500530 """
Andrew Geissler82c905d2020-04-13 13:39:40 -0500531 Compare the revisions in the persistent cache with the saved values from
532 when bitbake was started and return true if they have changed.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500533 """
534
Andrew Geissler82c905d2020-04-13 13:39:40 -0500535 headrevs = dict(bb.persist_data.persist('BB_URI_HEADREVS', d))
536 return headrevs != bb.fetch2.saved_headrevs
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500537
538def mirror_from_string(data):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500539 mirrors = (data or "").replace('\\n',' ').split()
540 # Split into pairs
541 if len(mirrors) % 2 != 0:
542 bb.warn('Invalid mirror data %s, should have paired members.' % data)
543 return list(zip(*[iter(mirrors)]*2))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500544
545def verify_checksum(ud, d, precomputed={}):
546 """
547 verify the MD5 and SHA256 checksum for downloaded src
548
549 Raises a FetchError if one or both of the SRC_URI checksums do not match
550 the downloaded file, or if BB_STRICT_CHECKSUM is set and there are no
551 checksums specified.
552
553 Returns a dict of checksums that can be stored in a done stamp file and
554 passed in as precomputed parameter in a later call to avoid re-computing
555 the checksums from the file. This allows verifying the checksums of the
556 file against those in the recipe each time, rather than only after
557 downloading. See https://bugzilla.yoctoproject.org/show_bug.cgi?id=5571.
558 """
559
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500560 if ud.ignore_checksums or not ud.method.supports_checksum(ud):
561 return {}
562
Andrew Geissler82c905d2020-04-13 13:39:40 -0500563 def compute_checksum_info(checksum_id):
564 checksum_name = getattr(ud, "%s_name" % checksum_id)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500565
Andrew Geissler82c905d2020-04-13 13:39:40 -0500566 if checksum_id in precomputed:
567 checksum_data = precomputed[checksum_id]
568 else:
569 checksum_data = getattr(bb.utils, "%s_file" % checksum_id)(ud.localpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500570
Andrew Geissler82c905d2020-04-13 13:39:40 -0500571 checksum_expected = getattr(ud, "%s_expected" % checksum_id)
572
Andrew Geissler09036742021-06-25 14:25:14 -0500573 if checksum_expected == '':
574 checksum_expected = None
575
Andrew Geissler82c905d2020-04-13 13:39:40 -0500576 return {
577 "id": checksum_id,
578 "name": checksum_name,
579 "data": checksum_data,
580 "expected": checksum_expected
581 }
582
583 checksum_infos = []
584 for checksum_id in CHECKSUM_LIST:
585 checksum_infos.append(compute_checksum_info(checksum_id))
586
587 checksum_dict = {ci["id"] : ci["data"] for ci in checksum_infos}
588 checksum_event = {"%ssum" % ci["id"] : ci["data"] for ci in checksum_infos}
589
590 for ci in checksum_infos:
591 if ci["id"] in SHOWN_CHECKSUM_LIST:
592 checksum_lines = ["SRC_URI[%s] = \"%s\"" % (ci["name"], ci["data"])]
593
594 # If no checksum has been provided
595 if ud.method.recommends_checksum(ud) and all(ci["expected"] is None for ci in checksum_infos):
596 messages = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500597 strict = d.getVar("BB_STRICT_CHECKSUM") or "0"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500598
Andrew Geissler82c905d2020-04-13 13:39:40 -0500599 # If strict checking enabled and neither sum defined, raise error
600 if strict == "1":
601 messages.append("No checksum specified for '%s', please add at " \
602 "least one to the recipe:" % ud.localpath)
603 messages.extend(checksum_lines)
604 logger.error("\n".join(messages))
605 raise NoChecksumError("Missing SRC_URI checksum", ud.url)
606
607 bb.event.fire(MissingChecksumEvent(ud.url, **checksum_event), d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500608
609 if strict == "ignore":
Andrew Geissler82c905d2020-04-13 13:39:40 -0500610 return checksum_dict
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500611
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500612 # Log missing sums so user can more easily add them
Andrew Geissler82c905d2020-04-13 13:39:40 -0500613 messages.append("Missing checksum for '%s', consider adding at " \
614 "least one to the recipe:" % ud.localpath)
615 messages.extend(checksum_lines)
616 logger.warning("\n".join(messages))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500617
618 # We want to alert the user if a checksum is defined in the recipe but
619 # it does not match.
Andrew Geissler82c905d2020-04-13 13:39:40 -0500620 messages = []
621 messages.append("Checksum mismatch!")
622 bad_checksum = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500623
Andrew Geissler82c905d2020-04-13 13:39:40 -0500624 for ci in checksum_infos:
625 if ci["expected"] and ci["expected"] != ci["data"]:
Andrew Geissler09036742021-06-25 14:25:14 -0500626 messages.append("File: '%s' has %s checksum '%s' when '%s' was " \
Andrew Geissler82c905d2020-04-13 13:39:40 -0500627 "expected" % (ud.localpath, ci["id"], ci["data"], ci["expected"]))
628 bad_checksum = ci["data"]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500629
Andrew Geissler82c905d2020-04-13 13:39:40 -0500630 if bad_checksum:
631 messages.append("If this change is expected (e.g. you have upgraded " \
632 "to a new version without updating the checksums) " \
633 "then you can use these lines within the recipe:")
634 messages.extend(checksum_lines)
635 messages.append("Otherwise you should retry the download and/or " \
636 "check with upstream to determine if the file has " \
637 "become corrupted or otherwise unexpectedly modified.")
638 raise ChecksumError("\n".join(messages), ud.url, bad_checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500639
Andrew Geissler82c905d2020-04-13 13:39:40 -0500640 return checksum_dict
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500641
642def verify_donestamp(ud, d, origud=None):
643 """
644 Check whether the done stamp file has the right checksums (if the fetch
645 method supports them). If it doesn't, delete the done stamp and force
646 a re-download.
647
648 Returns True, if the donestamp exists and is valid, False otherwise. When
649 returning False, any existing done stamps are removed.
650 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500651 if not ud.needdonestamp or (origud and not origud.needdonestamp):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500652 return True
653
Brad Bishop316dfdd2018-06-25 12:45:53 -0400654 if not os.path.exists(ud.localpath):
655 # local path does not exist
656 if os.path.exists(ud.donestamp):
657 # done stamp exists, but the downloaded file does not; the done stamp
658 # must be incorrect, re-trigger the download
659 bb.utils.remove(ud.donestamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500660 return False
661
662 if (not ud.method.supports_checksum(ud) or
663 (origud and not origud.method.supports_checksum(origud))):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400664 # if done stamp exists and checksums not supported; assume the local
665 # file is current
666 return os.path.exists(ud.donestamp)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500667
668 precomputed_checksums = {}
669 # Only re-use the precomputed checksums if the donestamp is newer than the
670 # file. Do not rely on the mtime of directories, though. If ud.localpath is
671 # a directory, there will probably not be any checksums anyway.
Brad Bishop316dfdd2018-06-25 12:45:53 -0400672 if os.path.exists(ud.donestamp) and (os.path.isdir(ud.localpath) or
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500673 os.path.getmtime(ud.localpath) < os.path.getmtime(ud.donestamp)):
674 try:
675 with open(ud.donestamp, "rb") as cachefile:
676 pickled = pickle.Unpickler(cachefile)
677 precomputed_checksums.update(pickled.load())
678 except Exception as e:
679 # Avoid the warnings on the upgrade path from emtpy done stamp
680 # files to those containing the checksums.
681 if not isinstance(e, EOFError):
682 # Ignore errors, they aren't fatal
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600683 logger.warning("Couldn't load checksums from donestamp %s: %s "
684 "(msg: %s)" % (ud.donestamp, type(e).__name__,
685 str(e)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500686
687 try:
688 checksums = verify_checksum(ud, d, precomputed_checksums)
689 # If the cache file did not have the checksums, compute and store them
690 # as an upgrade path from the previous done stamp file format.
691 if checksums != precomputed_checksums:
692 with open(ud.donestamp, "wb") as cachefile:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600693 p = pickle.Pickler(cachefile, 2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500694 p.dump(checksums)
695 return True
696 except ChecksumError as e:
697 # Checksums failed to verify, trigger re-download and remove the
698 # incorrect stamp file.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600699 logger.warning("Checksum mismatch for local file %s\n"
700 "Cleaning and trying again." % ud.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500701 if os.path.exists(ud.localpath):
702 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500703 bb.utils.remove(ud.donestamp)
704 return False
705
706
707def update_stamp(ud, d):
708 """
709 donestamp is file stamp indicating the whole fetching is done
710 this function update the stamp after verifying the checksum
711 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500712 if not ud.needdonestamp:
713 return
714
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500715 if os.path.exists(ud.donestamp):
716 # Touch the done stamp file to show active use of the download
717 try:
718 os.utime(ud.donestamp, None)
719 except:
720 # Errors aren't fatal here
721 pass
722 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500723 try:
724 checksums = verify_checksum(ud, d)
725 # Store the checksums for later re-verification against the recipe
726 with open(ud.donestamp, "wb") as cachefile:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600727 p = pickle.Pickler(cachefile, 2)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500728 p.dump(checksums)
729 except ChecksumError as e:
730 # Checksums failed to verify, trigger re-download and remove the
731 # incorrect stamp file.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600732 logger.warning("Checksum mismatch for local file %s\n"
733 "Cleaning and trying again." % ud.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500734 if os.path.exists(ud.localpath):
735 rename_bad_checksum(ud, e.checksum)
736 bb.utils.remove(ud.donestamp)
737 raise
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500738
739def subprocess_setup():
740 # Python installs a SIGPIPE handler by default. This is usually not what
741 # non-Python subprocesses expect.
742 # SIGPIPE errors are known issues with gzip/bash
743 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
744
745def get_autorev(d):
746 # only not cache src rev in autorev case
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500747 if d.getVar('BB_SRCREV_POLICY') != "cache":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500748 d.setVar('BB_DONT_CACHE', '1')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500749 return "AUTOINC"
750
751def get_srcrev(d, method_name='sortable_revision'):
752 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500753 Return the revision string, usually for use in the version string (PV) of the current package
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500754 Most packages usually only have one SCM so we just pass on the call.
755 In the multi SCM case, we build a value based on SRCREV_FORMAT which must
756 have been set.
757
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500758 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 -0500759 incremental, other code is then responsible for turning that into an increasing value (if needed)
760
761 A method_name can be supplied to retrieve an alternatively formatted revision from a fetcher, if
762 that fetcher provides a method with the given name and the same signature as sortable_revision.
763 """
764
Andrew Geissler5199d832021-09-24 16:47:35 -0500765 recursion = d.getVar("__BBINSRCREV")
766 if recursion:
767 raise FetchError("There are recursive references in fetcher variables, likely through SRC_URI")
768 d.setVar("__BBINSRCREV", True)
769
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500770 scms = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500771 fetcher = Fetch(d.getVar('SRC_URI').split(), d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500772 urldata = fetcher.ud
773 for u in urldata:
774 if urldata[u].method.supports_srcrev():
775 scms.append(u)
776
Andrew Geissler595f6302022-01-24 19:11:47 +0000777 if not scms:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500778 raise FetchError("SRCREV was used yet no valid SCM was found in SRC_URI")
779
780 if len(scms) == 1 and len(urldata[scms[0]].names) == 1:
781 autoinc, rev = getattr(urldata[scms[0]].method, method_name)(urldata[scms[0]], d, urldata[scms[0]].names[0])
782 if len(rev) > 10:
783 rev = rev[:10]
Andrew Geissler5199d832021-09-24 16:47:35 -0500784 d.delVar("__BBINSRCREV")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500785 if autoinc:
786 return "AUTOINC+" + rev
787 return rev
788
789 #
790 # Mutiple SCMs are in SRC_URI so we resort to SRCREV_FORMAT
791 #
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500792 format = d.getVar('SRCREV_FORMAT')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500793 if not format:
Brad Bishop19323692019-04-05 15:28:33 -0400794 raise FetchError("The SRCREV_FORMAT variable must be set when multiple SCMs are used.\n"\
795 "The SCMs are:\n%s" % '\n'.join(scms))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500796
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600797 name_to_rev = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500798 seenautoinc = False
799 for scm in scms:
800 ud = urldata[scm]
801 for name in ud.names:
802 autoinc, rev = getattr(ud.method, method_name)(ud, d, name)
803 seenautoinc = seenautoinc or autoinc
804 if len(rev) > 10:
805 rev = rev[:10]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600806 name_to_rev[name] = rev
807 # Replace names by revisions in the SRCREV_FORMAT string. The approach used
808 # here can handle names being prefixes of other names and names appearing
809 # as substrings in revisions (in which case the name should not be
810 # expanded). The '|' regular expression operator tries matches from left to
811 # right, so we need to sort the names with the longest ones first.
812 names_descending_len = sorted(name_to_rev, key=len, reverse=True)
813 name_to_rev_re = "|".join(re.escape(name) for name in names_descending_len)
814 format = re.sub(name_to_rev_re, lambda match: name_to_rev[match.group(0)], format)
815
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500816 if seenautoinc:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500817 format = "AUTOINC+" + format
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500818
Andrew Geissler5199d832021-09-24 16:47:35 -0500819 d.delVar("__BBINSRCREV")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500820 return format
821
822def localpath(url, d):
823 fetcher = bb.fetch2.Fetch([url], d)
824 return fetcher.localpath(url)
825
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500826# Need to export PATH as binary could be in metadata paths
827# rather than host provided
828# Also include some other variables.
829FETCH_EXPORT_VARS = ['HOME', 'PATH',
830 'HTTP_PROXY', 'http_proxy',
831 'HTTPS_PROXY', 'https_proxy',
832 'FTP_PROXY', 'ftp_proxy',
833 'FTPS_PROXY', 'ftps_proxy',
834 'NO_PROXY', 'no_proxy',
835 'ALL_PROXY', 'all_proxy',
836 'GIT_PROXY_COMMAND',
837 'GIT_SSH',
838 'GIT_SSL_CAINFO',
839 'GIT_SMART_HTTP',
840 'SSH_AUTH_SOCK', 'SSH_AGENT_PID',
841 'SOCKS5_USER', 'SOCKS5_PASSWD',
842 'DBUS_SESSION_BUS_ADDRESS',
843 'P4CONFIG',
844 'SSL_CERT_FILE',
Andrew Geissler5199d832021-09-24 16:47:35 -0500845 'AWS_PROFILE',
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500846 'AWS_ACCESS_KEY_ID',
847 'AWS_SECRET_ACCESS_KEY',
848 'AWS_DEFAULT_REGION']
849
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600850def runfetchcmd(cmd, d, quiet=False, cleanup=None, log=None, workdir=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500851 """
852 Run cmd returning the command output
853 Raise an error if interrupted or cmd fails
854 Optionally echo command output to stdout
855 Optionally remove the files/directories listed in cleanup upon failure
856 """
857
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500858 exportvars = FETCH_EXPORT_VARS
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500859
860 if not cleanup:
861 cleanup = []
862
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800863 # If PATH contains WORKDIR which contains PV-PR which contains SRCPV we
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500864 # can end up in circular recursion here so give the option of breaking it
865 # in a data store copy.
866 try:
867 d.getVar("PV")
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800868 d.getVar("PR")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500869 except bb.data_smart.ExpansionError:
870 d = bb.data.createCopy(d)
871 d.setVar("PV", "fetcheravoidrecurse")
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800872 d.setVar("PR", "fetcheravoidrecurse")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500873
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600874 origenv = d.getVar("BB_ORIGENV", False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500875 for var in exportvars:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500876 val = d.getVar(var) or (origenv and origenv.getVar(var))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500877 if val:
878 cmd = 'export ' + var + '=\"%s\"; %s' % (val, cmd)
879
Brad Bishop316dfdd2018-06-25 12:45:53 -0400880 # Disable pseudo as it may affect ssh, potentially causing it to hang.
881 cmd = 'export PSEUDO_DISABLED=1; ' + cmd
882
Brad Bishop19323692019-04-05 15:28:33 -0400883 if workdir:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600884 logger.debug("Running '%s' in %s" % (cmd, workdir))
Brad Bishop19323692019-04-05 15:28:33 -0400885 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600886 logger.debug("Running %s", cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500887
888 success = False
889 error_message = ""
890
891 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600892 (output, errors) = bb.process.run(cmd, log=log, shell=True, stderr=subprocess.PIPE, cwd=workdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500893 success = True
894 except bb.process.NotFoundError as e:
Andrew Geisslereff27472021-10-29 15:35:00 -0500895 error_message = "Fetch command %s not found" % (e.command)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500896 except bb.process.ExecutionError as e:
897 if e.stdout:
898 output = "output:\n%s\n%s" % (e.stdout, e.stderr)
899 elif e.stderr:
900 output = "output:\n%s" % e.stderr
901 else:
902 output = "no output"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600903 error_message = "Fetch command %s failed with exit code %s, %s" % (e.command, e.exitcode, output)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500904 except bb.process.CmdError as e:
905 error_message = "Fetch command %s could not be run:\n%s" % (e.command, e.msg)
906 if not success:
907 for f in cleanup:
908 try:
909 bb.utils.remove(f, True)
910 except OSError:
911 pass
912
913 raise FetchError(error_message)
914
915 return output
916
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500917def check_network_access(d, info, url):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500918 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500919 log remote network access, and error if BB_NO_NETWORK is set or the given
920 URI is untrusted
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500921 """
Brad Bishop19323692019-04-05 15:28:33 -0400922 if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500923 raise NetworkAccess(url, info)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500924 elif not trusted_network(d, url):
925 raise UntrustedUrl(url, info)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500926 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600927 logger.debug("Fetcher accessed the network with the command %s" % info)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500928
929def build_mirroruris(origud, mirrors, ld):
930 uris = []
931 uds = []
932
933 replacements = {}
934 replacements["TYPE"] = origud.type
935 replacements["HOST"] = origud.host
936 replacements["PATH"] = origud.path
937 replacements["BASENAME"] = origud.path.split("/")[-1]
938 replacements["MIRRORNAME"] = origud.host.replace(':','.') + origud.path.replace('/', '.').replace('*', '.')
939
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500940 def adduri(ud, uris, uds, mirrors, tarballs):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500941 for line in mirrors:
942 try:
943 (find, replace) = line
944 except ValueError:
945 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500946
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500947 for tarball in tarballs:
948 newuri = uri_replace(ud, find, replace, replacements, ld, tarball)
949 if not newuri or newuri in uris or newuri == origud.url:
950 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500951
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500952 if not trusted_network(ld, newuri):
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600953 logger.debug("Mirror %s not in the list of trusted networks, skipping" % (newuri))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500954 continue
Patrick Williamsd7e96312015-09-22 08:09:05 -0500955
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500956 # Create a local copy of the mirrors minus the current line
957 # this will prevent us from recursively processing the same line
958 # as well as indirect recursion A -> B -> C -> A
959 localmirrors = list(mirrors)
960 localmirrors.remove(line)
961
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500962 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500963 newud = FetchData(newuri, ld)
964 newud.setup_localpath(ld)
965 except bb.fetch2.BBFetchException as e:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600966 logger.debug("Mirror fetch failure for url %s (original url: %s)" % (newuri, origud.url))
967 logger.debug(str(e))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500968 try:
969 # setup_localpath of file:// urls may fail, we should still see
970 # if mirrors of the url exist
971 adduri(newud, uris, uds, localmirrors, tarballs)
972 except UnboundLocalError:
973 pass
974 continue
975 uris.append(newuri)
976 uds.append(newud)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500977
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500978 adduri(newud, uris, uds, localmirrors, tarballs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500979
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500980 adduri(origud, uris, uds, mirrors, origud.mirrortarballs or [None])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500981
982 return uris, uds
983
984def rename_bad_checksum(ud, suffix):
985 """
986 Renames files to have suffix from parameter
987 """
988
989 if ud.localpath is None:
990 return
991
992 new_localpath = "%s_bad-checksum_%s" % (ud.localpath, suffix)
993 bb.warn("Renaming %s to %s" % (ud.localpath, new_localpath))
Brad Bishop79641f22019-09-10 07:20:22 -0400994 if not bb.utils.movefile(ud.localpath, new_localpath):
995 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 -0500996
997
998def try_mirror_url(fetch, origud, ud, ld, check = False):
999 # Return of None or a value means we're finished
1000 # False means try another url
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001001
1002 if ud.lockfile and ud.lockfile != origud.lockfile:
1003 lf = bb.utils.lockfile(ud.lockfile)
1004
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001005 try:
1006 if check:
1007 found = ud.method.checkstatus(fetch, ud, ld)
1008 if found:
1009 return found
1010 return False
1011
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001012 if not verify_donestamp(ud, ld, origud) or ud.method.need_update(ud, ld):
1013 ud.method.download(ud, ld)
1014 if hasattr(ud.method,"build_mirror_data"):
1015 ud.method.build_mirror_data(ud, ld)
1016
1017 if not ud.localpath or not os.path.exists(ud.localpath):
1018 return False
1019
1020 if ud.localpath == origud.localpath:
1021 return ud.localpath
1022
1023 # We may be obtaining a mirror tarball which needs further processing by the real fetcher
1024 # If that tarball is a local file:// we need to provide a symlink to it
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001025 dldir = ld.getVar("DL_DIR")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001026
1027 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 -05001028 # Create donestamp in old format to avoid triggering a re-download
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001029 if ud.donestamp:
1030 bb.utils.mkdirhier(os.path.dirname(ud.donestamp))
1031 open(ud.donestamp, 'w').close()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001032 dest = os.path.join(dldir, os.path.basename(ud.localpath))
1033 if not os.path.exists(dest):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001034 # In case this is executing without any file locks held (as is
1035 # the case for file:// URLs), two tasks may end up here at the
1036 # same time, in which case we do not want the second task to
1037 # fail when the link has already been created by the first task.
1038 try:
1039 os.symlink(ud.localpath, dest)
1040 except FileExistsError:
1041 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001042 if not verify_donestamp(origud, ld) or origud.method.need_update(origud, ld):
1043 origud.method.download(origud, ld)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001044 if hasattr(origud.method, "build_mirror_data"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001045 origud.method.build_mirror_data(origud, ld)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001046 return origud.localpath
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001047 # Otherwise the result is a local file:// and we symlink to it
Andrew Geissler09209ee2020-12-13 08:44:15 -06001048 ensure_symlink(ud.localpath, origud.localpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001049 update_stamp(origud, ld)
1050 return ud.localpath
1051
1052 except bb.fetch2.NetworkAccess:
1053 raise
1054
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001055 except IOError as e:
Brad Bishop19323692019-04-05 15:28:33 -04001056 if e.errno in [errno.ESTALE]:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001057 logger.warning("Stale Error Observed %s." % ud.url)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001058 return False
1059 raise
1060
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001061 except bb.fetch2.BBFetchException as e:
1062 if isinstance(e, ChecksumError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001063 logger.warning("Mirror checksum failure for url %s (original url: %s)\nCleaning and trying again." % (ud.url, origud.url))
1064 logger.warning(str(e))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001065 if os.path.exists(ud.localpath):
1066 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001067 elif isinstance(e, NoChecksumError):
1068 raise
1069 else:
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001070 logger.debug("Mirror fetch failure for url %s (original url: %s)" % (ud.url, origud.url))
1071 logger.debug(str(e))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001072 try:
1073 ud.method.clean(ud, ld)
1074 except UnboundLocalError:
1075 pass
1076 return False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001077 finally:
1078 if ud.lockfile and ud.lockfile != origud.lockfile:
1079 bb.utils.unlockfile(lf)
1080
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001081
Andrew Geissler09209ee2020-12-13 08:44:15 -06001082def ensure_symlink(target, link_name):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001083 if not os.path.exists(link_name):
1084 if os.path.islink(link_name):
1085 # Broken symbolic link
1086 os.unlink(link_name)
1087
1088 # In case this is executing without any file locks held (as is
1089 # the case for file:// URLs), two tasks may end up here at the
1090 # same time, in which case we do not want the second task to
1091 # fail when the link has already been created by the first task.
1092 try:
1093 os.symlink(target, link_name)
1094 except FileExistsError:
1095 pass
1096
1097
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001098def try_mirrors(fetch, d, origud, mirrors, check = False):
1099 """
1100 Try to use a mirrored version of the sources.
1101 This method will be automatically called before the fetchers go.
1102
1103 d Is a bb.data instance
1104 uri is the original uri we're trying to download
1105 mirrors is the list of mirrors we're going to try
1106 """
1107 ld = d.createCopy()
1108
1109 uris, uds = build_mirroruris(origud, mirrors, ld)
1110
1111 for index, uri in enumerate(uris):
1112 ret = try_mirror_url(fetch, origud, uds[index], ld, check)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001113 if ret:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001114 return ret
1115 return None
1116
1117def trusted_network(d, url):
1118 """
1119 Use a trusted url during download if networking is enabled and
1120 BB_ALLOWED_NETWORKS is set globally or for a specific recipe.
1121 Note: modifies SRC_URI & mirrors.
1122 """
Brad Bishop19323692019-04-05 15:28:33 -04001123 if bb.utils.to_boolean(d.getVar("BB_NO_NETWORK")):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001124 return True
1125
1126 pkgname = d.expand(d.getVar('PN', False))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001127 trusted_hosts = None
1128 if pkgname:
1129 trusted_hosts = d.getVarFlag('BB_ALLOWED_NETWORKS', pkgname, False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001130
1131 if not trusted_hosts:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001132 trusted_hosts = d.getVar('BB_ALLOWED_NETWORKS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001133
1134 # Not enabled.
1135 if not trusted_hosts:
1136 return True
1137
1138 scheme, network, path, user, passwd, param = decodeurl(url)
1139
1140 if not network:
1141 return True
1142
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001143 network = network.split(':')[0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001144 network = network.lower()
1145
1146 for host in trusted_hosts.split(" "):
1147 host = host.lower()
1148 if host.startswith("*.") and ("." + network).endswith(host[1:]):
1149 return True
1150 if host == network:
1151 return True
1152
1153 return False
1154
1155def srcrev_internal_helper(ud, d, name):
1156 """
1157 Return:
1158 a) a source revision if specified
1159 b) latest revision if SRCREV="AUTOINC"
1160 c) None if not specified
1161 """
1162
1163 srcrev = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001164 pn = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001165 attempts = []
1166 if name != '' and pn:
Patrick Williams213cb262021-08-07 19:21:33 -05001167 attempts.append("SRCREV_%s:pn-%s" % (name, pn))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001168 if name != '':
1169 attempts.append("SRCREV_%s" % name)
1170 if pn:
Patrick Williams213cb262021-08-07 19:21:33 -05001171 attempts.append("SRCREV:pn-%s" % pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001172 attempts.append("SRCREV")
1173
1174 for a in attempts:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001175 srcrev = d.getVar(a)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001176 if srcrev and srcrev != "INVALID":
1177 break
1178
1179 if 'rev' in ud.parm and 'tag' in ud.parm:
1180 raise FetchError("Please specify a ;rev= parameter or a ;tag= parameter in the url %s but not both." % (ud.url))
1181
1182 if 'rev' in ud.parm or 'tag' in ud.parm:
1183 if 'rev' in ud.parm:
1184 parmrev = ud.parm['rev']
1185 else:
1186 parmrev = ud.parm['tag']
1187 if srcrev == "INVALID" or not srcrev:
1188 return parmrev
1189 if srcrev != parmrev:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001190 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 -05001191 return parmrev
1192
1193 if srcrev == "INVALID" or not srcrev:
1194 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)
1195 if srcrev == "AUTOINC":
1196 srcrev = ud.method.latest_revision(ud, d, name)
1197
1198 return srcrev
1199
1200def get_checksum_file_list(d):
1201 """ Get a list of files checksum in SRC_URI
1202
1203 Returns the resolved local paths of all local file entries in
1204 SRC_URI as a space-separated string
1205 """
1206 fetch = Fetch([], d, cache = False, localonly = True)
1207
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001208 dl_dir = d.getVar('DL_DIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001209 filelist = []
1210 for u in fetch.urls:
1211 ud = fetch.ud[u]
1212
1213 if ud and isinstance(ud.method, local.Local):
1214 paths = ud.method.localpaths(ud, d)
1215 for f in paths:
1216 pth = ud.decodedurl
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001217 if f.startswith(dl_dir):
1218 # The local fetcher's behaviour is to return a path under DL_DIR if it couldn't find the file anywhere else
1219 if os.path.exists(f):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001220 bb.warn("Getting checksum for %s SRC_URI entry %s: file not found except in DL_DIR" % (d.getVar('PN'), os.path.basename(f)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001221 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001222 bb.warn("Unable to get checksum for %s SRC_URI entry %s: file could not be found" % (d.getVar('PN'), os.path.basename(f)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001223 filelist.append(f + ":" + str(os.path.exists(f)))
1224
1225 return " ".join(filelist)
1226
Andrew Geissler82c905d2020-04-13 13:39:40 -05001227def get_file_checksums(filelist, pn, localdirsexclude):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001228 """Get a list of the checksums for a list of local files
1229
1230 Returns the checksums for a list of local files, caching the results as
1231 it proceeds
1232
1233 """
Andrew Geissler82c905d2020-04-13 13:39:40 -05001234 return _checksum_cache.get_checksums(filelist, pn, localdirsexclude)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001235
1236
1237class FetchData(object):
1238 """
1239 A class which represents the fetcher state for a given URI.
1240 """
1241 def __init__(self, url, d, localonly = False):
1242 # localpath is the location of a downloaded result. If not set, the file is local.
1243 self.donestamp = None
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001244 self.needdonestamp = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001245 self.localfile = ""
1246 self.localpath = None
1247 self.lockfile = None
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001248 self.mirrortarballs = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001249 self.basename = None
1250 self.basepath = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001251 (self.type, self.host, self.path, self.user, self.pswd, self.parm) = decodeurl(d.expand(url))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001252 self.date = self.getSRCDate(d)
1253 self.url = url
1254 if not self.user and "user" in self.parm:
1255 self.user = self.parm["user"]
1256 if not self.pswd and "pswd" in self.parm:
1257 self.pswd = self.parm["pswd"]
1258 self.setup = False
1259
Andrew Geissler82c905d2020-04-13 13:39:40 -05001260 def configure_checksum(checksum_id):
1261 if "name" in self.parm:
1262 checksum_name = "%s.%ssum" % (self.parm["name"], checksum_id)
1263 else:
1264 checksum_name = "%ssum" % checksum_id
1265
1266 setattr(self, "%s_name" % checksum_id, checksum_name)
1267
1268 if checksum_name in self.parm:
1269 checksum_expected = self.parm[checksum_name]
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001270 elif self.type not in ["http", "https", "ftp", "ftps", "sftp", "s3", "az"]:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001271 checksum_expected = None
1272 else:
1273 checksum_expected = d.getVarFlag("SRC_URI", checksum_name)
1274
1275 setattr(self, "%s_expected" % checksum_id, checksum_expected)
1276
1277 for checksum_id in CHECKSUM_LIST:
1278 configure_checksum(checksum_id)
1279
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001280 self.ignore_checksums = False
1281
1282 self.names = self.parm.get("name",'default').split(',')
1283
1284 self.method = None
1285 for m in methods:
1286 if m.supports(self, d):
1287 self.method = m
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001288 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001289
1290 if not self.method:
1291 raise NoMethodError(url)
1292
1293 if localonly and not isinstance(self.method, local.Local):
1294 raise NonLocalMethod()
1295
1296 if self.parm.get("proto", None) and "protocol" not in self.parm:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001297 logger.warning('Consider updating %s recipe to use "protocol" not "proto" in SRC_URI.', d.getVar('PN'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001298 self.parm["protocol"] = self.parm.get("proto", None)
1299
1300 if hasattr(self.method, "urldata_init"):
1301 self.method.urldata_init(self, d)
1302
1303 if "localpath" in self.parm:
1304 # if user sets localpath for file, use it instead.
1305 self.localpath = self.parm["localpath"]
1306 self.basename = os.path.basename(self.localpath)
1307 elif self.localfile:
1308 self.localpath = self.method.localpath(self, d)
1309
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001310 dldir = d.getVar("DL_DIR")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001311
1312 if not self.needdonestamp:
1313 return
1314
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001315 # Note: .done and .lock files should always be in DL_DIR whereas localpath may not be.
1316 if self.localpath and self.localpath.startswith(dldir):
1317 basepath = self.localpath
1318 elif self.localpath:
1319 basepath = dldir + os.sep + os.path.basename(self.localpath)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001320 elif self.basepath or self.basename:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001321 basepath = dldir + os.sep + (self.basepath or self.basename)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001322 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001323 bb.fatal("Can't determine lock path for url %s" % url)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001324
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001325 self.donestamp = basepath + '.done'
1326 self.lockfile = basepath + '.lock'
1327
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001328 def setup_revisions(self, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001329 self.revisions = {}
1330 for name in self.names:
1331 self.revisions[name] = srcrev_internal_helper(self, d, name)
1332
1333 # add compatibility code for non name specified case
1334 if len(self.names) == 1:
1335 self.revision = self.revisions[self.names[0]]
1336
1337 def setup_localpath(self, d):
1338 if not self.localpath:
1339 self.localpath = self.method.localpath(self, d)
1340
1341 def getSRCDate(self, d):
1342 """
1343 Return the SRC Date for the component
1344
1345 d the bb.data module
1346 """
1347 if "srcdate" in self.parm:
1348 return self.parm['srcdate']
1349
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001350 pn = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001351
1352 if pn:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001353 return d.getVar("SRCDATE_%s" % pn) or d.getVar("SRCDATE") or d.getVar("DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001354
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001355 return d.getVar("SRCDATE") or d.getVar("DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001356
1357class FetchMethod(object):
1358 """Base class for 'fetch'ing data"""
1359
1360 def __init__(self, urls=None):
1361 self.urls = []
1362
1363 def supports(self, urldata, d):
1364 """
1365 Check to see if this fetch class supports a given url.
1366 """
1367 return 0
1368
1369 def localpath(self, urldata, d):
1370 """
1371 Return the local filename of a given url assuming a successful fetch.
1372 Can also setup variables in urldata for use in go (saving code duplication
1373 and duplicate code execution)
1374 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001375 return os.path.join(d.getVar("DL_DIR"), urldata.localfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001376
1377 def supports_checksum(self, urldata):
1378 """
1379 Is localpath something that can be represented by a checksum?
1380 """
1381
1382 # We cannot compute checksums for directories
Andrew Geissler82c905d2020-04-13 13:39:40 -05001383 if os.path.isdir(urldata.localpath):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001384 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001385 return True
1386
1387 def recommends_checksum(self, urldata):
1388 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001389 Is the backend on where checksumming is recommended (should warnings
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001390 be displayed if there is no checksum)?
1391 """
1392 return False
1393
Andrew Geissler82c905d2020-04-13 13:39:40 -05001394 def verify_donestamp(self, ud, d):
1395 """
1396 Verify the donestamp file
1397 """
1398 return verify_donestamp(ud, d)
1399
1400 def update_donestamp(self, ud, d):
1401 """
1402 Update the donestamp file
1403 """
1404 update_stamp(ud, d)
1405
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001406 def _strip_leading_slashes(self, relpath):
1407 """
1408 Remove leading slash as os.path.join can't cope
1409 """
1410 while os.path.isabs(relpath):
1411 relpath = relpath[1:]
1412 return relpath
1413
1414 def setUrls(self, urls):
1415 self.__urls = urls
1416
1417 def getUrls(self):
1418 return self.__urls
1419
1420 urls = property(getUrls, setUrls, None, "Urls property")
1421
1422 def need_update(self, ud, d):
1423 """
1424 Force a fetch, even if localpath exists?
1425 """
1426 if os.path.exists(ud.localpath):
1427 return False
1428 return True
1429
1430 def supports_srcrev(self):
1431 """
1432 The fetcher supports auto source revisions (SRCREV)
1433 """
1434 return False
1435
1436 def download(self, urldata, d):
1437 """
1438 Fetch urls
1439 Assumes localpath was called first
1440 """
Brad Bishop19323692019-04-05 15:28:33 -04001441 raise NoMethodError(urldata.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001442
1443 def unpack(self, urldata, rootdir, data):
1444 iterate = False
1445 file = urldata.localpath
1446
1447 try:
1448 unpack = bb.utils.to_boolean(urldata.parm.get('unpack'), True)
1449 except ValueError as exc:
1450 bb.fatal("Invalid value for 'unpack' parameter for %s: %s" %
1451 (file, urldata.parm.get('unpack')))
1452
1453 base, ext = os.path.splitext(file)
1454 if ext in ['.gz', '.bz2', '.Z', '.xz', '.lz']:
1455 efile = os.path.join(rootdir, os.path.basename(base))
1456 else:
1457 efile = file
1458 cmd = None
1459
1460 if unpack:
Andrew Geissler595f6302022-01-24 19:11:47 +00001461 tar_cmd = 'tar --extract --no-same-owner'
1462 if 'striplevel' in urldata.parm:
1463 tar_cmd += ' --strip-components=%s' % urldata.parm['striplevel']
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001464 if file.endswith('.tar'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001465 cmd = '%s -f %s' % (tar_cmd, file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001466 elif file.endswith('.tgz') or file.endswith('.tar.gz') or file.endswith('.tar.Z'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001467 cmd = '%s -z -f %s' % (tar_cmd, file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001468 elif file.endswith('.tbz') or file.endswith('.tbz2') or file.endswith('.tar.bz2'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001469 cmd = 'bzip2 -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001470 elif file.endswith('.gz') or file.endswith('.Z') or file.endswith('.z'):
1471 cmd = 'gzip -dc %s > %s' % (file, efile)
1472 elif file.endswith('.bz2'):
1473 cmd = 'bzip2 -dc %s > %s' % (file, efile)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001474 elif file.endswith('.txz') or file.endswith('.tar.xz'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001475 cmd = 'xz -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001476 elif file.endswith('.xz'):
1477 cmd = 'xz -dc %s > %s' % (file, efile)
1478 elif file.endswith('.tar.lz'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001479 cmd = 'lzip -dc %s | %s -f -' % (file, tar_cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001480 elif file.endswith('.lz'):
1481 cmd = 'lzip -dc %s > %s' % (file, efile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001482 elif file.endswith('.tar.7z'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001483 cmd = '7z x -so %s | %s -f -' % (file, tar_cmd)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001484 elif file.endswith('.7z'):
1485 cmd = '7za x -y %s 1>/dev/null' % file
Andrew Geissler6ce62a22020-11-30 19:58:47 -06001486 elif file.endswith('.tzst') or file.endswith('.tar.zst'):
Andrew Geissler595f6302022-01-24 19:11:47 +00001487 cmd = 'zstd --decompress --stdout %s | %s -f -' % (file, tar_cmd)
Andrew Geissler6ce62a22020-11-30 19:58:47 -06001488 elif file.endswith('.zst'):
1489 cmd = 'zstd --decompress --stdout %s > %s' % (file, efile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001490 elif file.endswith('.zip') or file.endswith('.jar'):
1491 try:
1492 dos = bb.utils.to_boolean(urldata.parm.get('dos'), False)
1493 except ValueError as exc:
1494 bb.fatal("Invalid value for 'dos' parameter for %s: %s" %
1495 (file, urldata.parm.get('dos')))
1496 cmd = 'unzip -q -o'
1497 if dos:
1498 cmd = '%s -a' % cmd
1499 cmd = "%s '%s'" % (cmd, file)
1500 elif file.endswith('.rpm') or file.endswith('.srpm'):
1501 if 'extract' in urldata.parm:
1502 unpack_file = urldata.parm.get('extract')
1503 cmd = 'rpm2cpio.sh %s | cpio -id %s' % (file, unpack_file)
1504 iterate = True
1505 iterate_file = unpack_file
1506 else:
1507 cmd = 'rpm2cpio.sh %s | cpio -id' % (file)
1508 elif file.endswith('.deb') or file.endswith('.ipk'):
Brad Bishopa5c52ff2018-11-23 10:55:50 +13001509 output = subprocess.check_output(['ar', '-t', file], preexec_fn=subprocess_setup)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001510 datafile = None
1511 if output:
1512 for line in output.decode().splitlines():
1513 if line.startswith('data.tar.'):
1514 datafile = line
1515 break
1516 else:
1517 raise UnpackError("Unable to unpack deb/ipk package - does not contain data.tar.* file", urldata.url)
1518 else:
1519 raise UnpackError("Unable to unpack deb/ipk package - could not list contents", urldata.url)
Andrew Geissler595f6302022-01-24 19:11:47 +00001520 cmd = 'ar x %s %s && %s -p -f %s && rm %s' % (file, datafile, tar_cmd, datafile, datafile)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001521
1522 # If 'subdir' param exists, create a dir and use it as destination for unpack cmd
1523 if 'subdir' in urldata.parm:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001524 subdir = urldata.parm.get('subdir')
1525 if os.path.isabs(subdir):
1526 if not os.path.realpath(subdir).startswith(os.path.realpath(rootdir)):
1527 raise UnpackError("subdir argument isn't a subdirectory of unpack root %s" % rootdir, urldata.url)
1528 unpackdir = subdir
1529 else:
1530 unpackdir = os.path.join(rootdir, subdir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001531 bb.utils.mkdirhier(unpackdir)
1532 else:
1533 unpackdir = rootdir
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001534
1535 if not unpack or not cmd:
1536 # If file == dest, then avoid any copies, as we already put the file into dest!
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001537 dest = os.path.join(unpackdir, os.path.basename(file))
1538 if file != dest and not (os.path.exists(dest) and os.path.samefile(file, dest)):
1539 destdir = '.'
1540 # For file:// entries all intermediate dirs in path must be created at destination
1541 if urldata.type == "file":
1542 # Trailing '/' does a copying to wrong place
1543 urlpath = urldata.path.rstrip('/')
1544 # Want files places relative to cwd so no leading '/'
1545 urlpath = urlpath.lstrip('/')
1546 if urlpath.find("/") != -1:
1547 destdir = urlpath.rsplit("/", 1)[0] + '/'
1548 bb.utils.mkdirhier("%s/%s" % (unpackdir, destdir))
Andrew Geisslerc3d88e42020-10-02 09:45:00 -05001549 cmd = 'cp -fpPRH "%s" "%s"' % (file, destdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001550
1551 if not cmd:
1552 return
1553
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001554 path = data.getVar('PATH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001555 if path:
1556 cmd = "PATH=\"%s\" %s" % (path, cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001557 bb.note("Unpacking %s to %s/" % (file, unpackdir))
1558 ret = subprocess.call(cmd, preexec_fn=subprocess_setup, shell=True, cwd=unpackdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001559
1560 if ret != 0:
1561 raise UnpackError("Unpack command %s failed with return value %s" % (cmd, ret), urldata.url)
1562
1563 if iterate is True:
1564 iterate_urldata = urldata
1565 iterate_urldata.localpath = "%s/%s" % (rootdir, iterate_file)
1566 self.unpack(urldata, rootdir, data)
1567
1568 return
1569
1570 def clean(self, urldata, d):
1571 """
1572 Clean any existing full or partial download
1573 """
1574 bb.utils.remove(urldata.localpath)
1575
1576 def try_premirror(self, urldata, d):
1577 """
1578 Should premirrors be used?
1579 """
1580 return True
1581
Andrew Geissler82c905d2020-04-13 13:39:40 -05001582 def try_mirrors(self, fetch, urldata, d, mirrors, check=False):
1583 """
1584 Try to use a mirror
1585 """
1586 return bool(try_mirrors(fetch, d, urldata, mirrors, check))
1587
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001588 def checkstatus(self, fetch, urldata, d):
1589 """
1590 Check the status of a URL
1591 Assumes localpath was called first
1592 """
Brad Bishop19323692019-04-05 15:28:33 -04001593 logger.info("URL %s could not be checked for status since no method exists.", urldata.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001594 return True
1595
1596 def latest_revision(self, ud, d, name):
1597 """
1598 Look in the cache for the latest revision, if not present ask the SCM.
1599 """
1600 if not hasattr(self, "_latest_revision"):
Brad Bishop19323692019-04-05 15:28:33 -04001601 raise ParameterError("The fetcher for this URL does not support _latest_revision", ud.url)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001602
1603 revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
1604 key = self.generate_revision_key(ud, d, name)
1605 try:
1606 return revs[key]
1607 except KeyError:
1608 revs[key] = rev = self._latest_revision(ud, d, name)
1609 return rev
1610
1611 def sortable_revision(self, ud, d, name):
1612 latest_rev = self._build_revision(ud, d, name)
1613 return True, str(latest_rev)
1614
1615 def generate_revision_key(self, ud, d, name):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001616 return self._revision_key(ud, d, name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001617
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001618 def latest_versionstring(self, ud, d):
1619 """
1620 Compute the latest release name like "x.y.x" in "x.y.x+gitHASH"
1621 by searching through the tags output of ls-remote, comparing
1622 versions and returning the highest match as a (version, revision) pair.
1623 """
1624 return ('', '')
1625
Andrew Geissler82c905d2020-04-13 13:39:40 -05001626 def done(self, ud, d):
1627 """
1628 Is the download done ?
1629 """
1630 if os.path.exists(ud.localpath):
1631 return True
Andrew Geissler82c905d2020-04-13 13:39:40 -05001632 return False
1633
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001634 def implicit_urldata(self, ud, d):
1635 """
1636 Get a list of FetchData objects for any implicit URLs that will also
1637 be downloaded when we fetch the given URL.
1638 """
1639 return []
1640
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001641class Fetch(object):
1642 def __init__(self, urls, d, cache = True, localonly = False, connection_cache = None):
1643 if localonly and cache:
1644 raise Exception("bb.fetch2.Fetch.__init__: cannot set cache and localonly at same time")
1645
Andrew Geissler595f6302022-01-24 19:11:47 +00001646 if not urls:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001647 urls = d.getVar("SRC_URI").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001648 self.urls = urls
1649 self.d = d
1650 self.ud = {}
1651 self.connection_cache = connection_cache
1652
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001653 fn = d.getVar('FILE')
1654 mc = d.getVar('__BBMULTICONFIG') or ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001655 key = None
1656 if cache and fn:
1657 key = mc + fn + str(id(d))
1658 if key in urldata_cache:
1659 self.ud = urldata_cache[key]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001660
1661 for url in urls:
1662 if url not in self.ud:
1663 try:
1664 self.ud[url] = FetchData(url, d, localonly)
1665 except NonLocalMethod:
1666 if localonly:
1667 self.ud[url] = None
1668 pass
1669
Andrew Geissler82c905d2020-04-13 13:39:40 -05001670 if key:
1671 urldata_cache[key] = self.ud
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001672
1673 def localpath(self, url):
1674 if url not in self.urls:
1675 self.ud[url] = FetchData(url, self.d)
1676
1677 self.ud[url].setup_localpath(self.d)
1678 return self.d.expand(self.ud[url].localpath)
1679
1680 def localpaths(self):
1681 """
1682 Return a list of the local filenames, assuming successful fetch
1683 """
1684 local = []
1685
1686 for u in self.urls:
1687 ud = self.ud[u]
1688 ud.setup_localpath(self.d)
1689 local.append(ud.localpath)
1690
1691 return local
1692
1693 def download(self, urls=None):
1694 """
1695 Fetch all urls
1696 """
1697 if not urls:
1698 urls = self.urls
1699
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001700 network = self.d.getVar("BB_NO_NETWORK")
Brad Bishop19323692019-04-05 15:28:33 -04001701 premirroronly = bb.utils.to_boolean(self.d.getVar("BB_FETCH_PREMIRRORONLY"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001702
1703 for u in urls:
1704 ud = self.ud[u]
1705 ud.setup_localpath(self.d)
1706 m = ud.method
Andrew Geissler82c905d2020-04-13 13:39:40 -05001707 done = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001708
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001709 if ud.lockfile:
1710 lf = bb.utils.lockfile(ud.lockfile)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001711
1712 try:
1713 self.d.setVar("BB_NO_NETWORK", network)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001714
Andrew Geissler82c905d2020-04-13 13:39:40 -05001715 if m.verify_donestamp(ud, self.d) and not m.need_update(ud, self.d):
1716 done = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001717 elif m.try_premirror(ud, self.d):
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001718 logger.debug("Trying PREMIRRORS")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001719 mirrors = mirror_from_string(self.d.getVar('PREMIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001720 done = m.try_mirrors(self, ud, self.d, mirrors)
1721 if done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001722 try:
1723 # early checksum verification so that if the checksum of the premirror
1724 # contents mismatch the fetcher can still try upstream and mirrors
Andrew Geissler82c905d2020-04-13 13:39:40 -05001725 m.update_donestamp(ud, self.d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001726 except ChecksumError as e:
1727 logger.warning("Checksum failure encountered with premirror download of %s - will attempt other sources." % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001728 logger.debug(str(e))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001729 done = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001730
1731 if premirroronly:
1732 self.d.setVar("BB_NO_NETWORK", "1")
1733
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001734 firsterr = None
Andrew Geisslereff27472021-10-29 15:35:00 -05001735 verified_stamp = False
1736 if done:
1737 verified_stamp = m.verify_donestamp(ud, self.d)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001738 if not done and (not verified_stamp or m.need_update(ud, self.d)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001739 try:
1740 if not trusted_network(self.d, ud.url):
1741 raise UntrustedUrl(ud.url)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001742 logger.debug("Trying Upstream")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001743 m.download(ud, self.d)
1744 if hasattr(m, "build_mirror_data"):
1745 m.build_mirror_data(ud, self.d)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001746 done = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001747 # early checksum verify, so that if checksum mismatched,
1748 # fetcher still have chance to fetch from mirror
Andrew Geissler82c905d2020-04-13 13:39:40 -05001749 m.update_donestamp(ud, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001750
1751 except bb.fetch2.NetworkAccess:
1752 raise
1753
1754 except BBFetchException as e:
1755 if isinstance(e, ChecksumError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001756 logger.warning("Checksum failure encountered with download of %s - will attempt other sources if available" % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001757 logger.debug(str(e))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001758 if os.path.exists(ud.localpath):
1759 rename_bad_checksum(ud, e.checksum)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001760 elif isinstance(e, NoChecksumError):
1761 raise
1762 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001763 logger.warning('Failed to fetch URL %s, attempting MIRRORS if available' % u)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001764 logger.debug(str(e))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001765 firsterr = e
1766 # Remove any incomplete fetch
1767 if not verified_stamp:
1768 m.clean(ud, self.d)
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001769 logger.debug("Trying MIRRORS")
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001770 mirrors = mirror_from_string(self.d.getVar('MIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001771 done = m.try_mirrors(self, ud, self.d, mirrors)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001772
Andrew Geissler82c905d2020-04-13 13:39:40 -05001773 if not done or not m.done(ud, self.d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001774 if firsterr:
1775 logger.error(str(firsterr))
1776 raise FetchError("Unable to fetch URL from any source.", u)
1777
Andrew Geissler82c905d2020-04-13 13:39:40 -05001778 m.update_donestamp(ud, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001779
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001780 except IOError as e:
Brad Bishop19323692019-04-05 15:28:33 -04001781 if e.errno in [errno.ESTALE]:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001782 logger.error("Stale Error Observed %s." % u)
1783 raise ChecksumError("Stale Error Detected")
1784
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001785 except BBFetchException as e:
1786 if isinstance(e, ChecksumError):
1787 logger.error("Checksum failure fetching %s" % u)
1788 raise
1789
1790 finally:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001791 if ud.lockfile:
1792 bb.utils.unlockfile(lf)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001793
1794 def checkstatus(self, urls=None):
1795 """
Andrew Geisslereff27472021-10-29 15:35:00 -05001796 Check all URLs exist upstream.
1797
1798 Returns None if the URLs exist, raises FetchError if the check wasn't
1799 successful but there wasn't an error (such as file not found), and
1800 raises other exceptions in error cases.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001801 """
1802
1803 if not urls:
1804 urls = self.urls
1805
1806 for u in urls:
1807 ud = self.ud[u]
1808 ud.setup_localpath(self.d)
1809 m = ud.method
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001810 logger.debug("Testing URL %s", u)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001811 # First try checking uri, u, from PREMIRRORS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001812 mirrors = mirror_from_string(self.d.getVar('PREMIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001813 ret = m.try_mirrors(self, ud, self.d, mirrors, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001814 if not ret:
1815 # Next try checking from the original uri, u
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001816 ret = m.checkstatus(self, ud, self.d)
1817 if not ret:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001818 # Finally, try checking uri, u, from MIRRORS
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001819 mirrors = mirror_from_string(self.d.getVar('MIRRORS'))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001820 ret = m.try_mirrors(self, ud, self.d, mirrors, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001821
1822 if not ret:
1823 raise FetchError("URL %s doesn't work" % u, u)
1824
1825 def unpack(self, root, urls=None):
1826 """
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001827 Unpack urls to root
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001828 """
1829
1830 if not urls:
1831 urls = self.urls
1832
1833 for u in urls:
1834 ud = self.ud[u]
1835 ud.setup_localpath(self.d)
1836
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001837 if ud.lockfile:
1838 lf = bb.utils.lockfile(ud.lockfile)
1839
1840 ud.method.unpack(ud, root, self.d)
1841
1842 if ud.lockfile:
1843 bb.utils.unlockfile(lf)
1844
1845 def clean(self, urls=None):
1846 """
1847 Clean files that the fetcher gets or places
1848 """
1849
1850 if not urls:
1851 urls = self.urls
1852
1853 for url in urls:
1854 if url not in self.ud:
Brad Bishop19323692019-04-05 15:28:33 -04001855 self.ud[url] = FetchData(url, self.d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001856 ud = self.ud[url]
1857 ud.setup_localpath(self.d)
1858
1859 if not ud.localfile and ud.localpath is None:
1860 continue
1861
1862 if ud.lockfile:
1863 lf = bb.utils.lockfile(ud.lockfile)
1864
1865 ud.method.clean(ud, self.d)
1866 if ud.donestamp:
1867 bb.utils.remove(ud.donestamp)
1868
1869 if ud.lockfile:
1870 bb.utils.unlockfile(lf)
1871
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001872 def expanded_urldata(self, urls=None):
1873 """
1874 Get an expanded list of FetchData objects covering both the given
1875 URLS and any additional implicit URLs that are added automatically by
1876 the appropriate FetchMethod.
1877 """
1878
1879 if not urls:
1880 urls = self.urls
1881
1882 urldata = []
1883 for url in urls:
1884 ud = self.ud[url]
1885 urldata.append(ud)
1886 urldata += ud.method.implicit_urldata(ud, self.d)
1887
1888 return urldata
1889
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001890class FetchConnectionCache(object):
1891 """
1892 A class which represents an container for socket connections.
1893 """
1894 def __init__(self):
1895 self.cache = {}
1896
1897 def get_connection_name(self, host, port):
1898 return host + ':' + str(port)
1899
1900 def add_connection(self, host, port, connection):
1901 cn = self.get_connection_name(host, port)
1902
1903 if cn not in self.cache:
1904 self.cache[cn] = connection
1905
1906 def get_connection(self, host, port):
1907 connection = None
1908
1909 cn = self.get_connection_name(host, port)
1910 if cn in self.cache:
1911 connection = self.cache[cn]
1912
1913 return connection
1914
1915 def remove_connection(self, host, port):
1916 cn = self.get_connection_name(host, port)
1917 if cn in self.cache:
1918 self.cache[cn].close()
1919 del self.cache[cn]
1920
1921 def close_connections(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001922 for cn in list(self.cache.keys()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001923 self.cache[cn].close()
1924 del self.cache[cn]
1925
1926from . import cvs
1927from . import git
1928from . import gitsm
1929from . import gitannex
1930from . import local
1931from . import svn
1932from . import wget
1933from . import ssh
1934from . import sftp
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001935from . import s3
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001936from . import perforce
1937from . import bzr
1938from . import hg
1939from . import osc
1940from . import repo
1941from . import clearcase
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001942from . import npm
Andrew Geissler82c905d2020-04-13 13:39:40 -05001943from . import npmsw
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001944from . import az
Andrew Geissler595f6302022-01-24 19:11:47 +00001945from . import crate
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001946
1947methods.append(local.Local())
1948methods.append(wget.Wget())
1949methods.append(svn.Svn())
1950methods.append(git.Git())
1951methods.append(gitsm.GitSM())
1952methods.append(gitannex.GitANNEX())
1953methods.append(cvs.Cvs())
1954methods.append(ssh.SSH())
1955methods.append(sftp.SFTP())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001956methods.append(s3.S3())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001957methods.append(perforce.Perforce())
1958methods.append(bzr.Bzr())
1959methods.append(hg.Hg())
1960methods.append(osc.Osc())
1961methods.append(repo.Repo())
1962methods.append(clearcase.ClearCase())
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001963methods.append(npm.Npm())
Andrew Geissler82c905d2020-04-13 13:39:40 -05001964methods.append(npmsw.NpmShrinkWrap())
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001965methods.append(az.Az())
Andrew Geissler595f6302022-01-24 19:11:47 +00001966methods.append(crate.Crate())