__init__.py 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775
  1. # ex:ts=4:sw=4:sts=4:et
  2. # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  3. """
  4. BitBake 'Fetch' implementations
  5. Classes for obtaining upstream sources for the
  6. BitBake build tools.
  7. """
  8. # Copyright (C) 2003, 2004 Chris Larson
  9. # Copyright (C) 2012 Intel Corporation
  10. #
  11. # This program is free software; you can redistribute it and/or modify
  12. # it under the terms of the GNU General Public License version 2 as
  13. # published by the Free Software Foundation.
  14. #
  15. # This program is distributed in the hope that it will be useful,
  16. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. # GNU General Public License for more details.
  19. #
  20. # You should have received a copy of the GNU General Public License along
  21. # with this program; if not, write to the Free Software Foundation, Inc.,
  22. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  23. #
  24. # Based on functions from the base bb module, Copyright 2003 Holger Schurig
  25. from __future__ import absolute_import
  26. from __future__ import print_function
  27. import os, re
  28. import signal
  29. import logging
  30. import urllib
  31. import urlparse
  32. import bb.persist_data, bb.utils
  33. import bb.checksum
  34. from bb import data
  35. import bb.process
  36. import subprocess
  37. __version__ = "2"
  38. _checksum_cache = bb.checksum.FileChecksumCache()
  39. logger = logging.getLogger("BitBake.Fetcher")
  40. try:
  41. import cPickle as pickle
  42. except ImportError:
  43. import pickle
  44. logger.info("Importing cPickle failed. "
  45. "Falling back to a very slow implementation.")
  46. class BBFetchException(Exception):
  47. """Class all fetch exceptions inherit from"""
  48. def __init__(self, message):
  49. self.msg = message
  50. Exception.__init__(self, message)
  51. def __str__(self):
  52. return self.msg
  53. class UntrustedUrl(BBFetchException):
  54. """Exception raised when encountering a host not listed in BB_ALLOWED_NETWORKS"""
  55. def __init__(self, url, message=''):
  56. if message:
  57. msg = message
  58. else:
  59. msg = "The URL: '%s' is not trusted and cannot be used" % url
  60. self.url = url
  61. BBFetchException.__init__(self, msg)
  62. self.args = (url,)
  63. class MalformedUrl(BBFetchException):
  64. """Exception raised when encountering an invalid url"""
  65. def __init__(self, url, message=''):
  66. if message:
  67. msg = message
  68. else:
  69. msg = "The URL: '%s' is invalid and cannot be interpreted" % url
  70. self.url = url
  71. BBFetchException.__init__(self, msg)
  72. self.args = (url,)
  73. class FetchError(BBFetchException):
  74. """General fetcher exception when something happens incorrectly"""
  75. def __init__(self, message, url = None):
  76. if url:
  77. msg = "Fetcher failure for URL: '%s'. %s" % (url, message)
  78. else:
  79. msg = "Fetcher failure: %s" % message
  80. self.url = url
  81. BBFetchException.__init__(self, msg)
  82. self.args = (message, url)
  83. class ChecksumError(FetchError):
  84. """Exception when mismatched checksum encountered"""
  85. def __init__(self, message, url = None, checksum = None):
  86. self.checksum = checksum
  87. FetchError.__init__(self, message, url)
  88. class NoChecksumError(FetchError):
  89. """Exception when no checksum is specified, but BB_STRICT_CHECKSUM is set"""
  90. class UnpackError(BBFetchException):
  91. """General fetcher exception when something happens incorrectly when unpacking"""
  92. def __init__(self, message, url):
  93. msg = "Unpack failure for URL: '%s'. %s" % (url, message)
  94. self.url = url
  95. BBFetchException.__init__(self, msg)
  96. self.args = (message, url)
  97. class NoMethodError(BBFetchException):
  98. """Exception raised when there is no method to obtain a supplied url or set of urls"""
  99. def __init__(self, url):
  100. msg = "Could not find a fetcher which supports the URL: '%s'" % url
  101. self.url = url
  102. BBFetchException.__init__(self, msg)
  103. self.args = (url,)
  104. class MissingParameterError(BBFetchException):
  105. """Exception raised when a fetch method is missing a critical parameter in the url"""
  106. def __init__(self, missing, url):
  107. msg = "URL: '%s' is missing the required parameter '%s'" % (url, missing)
  108. self.url = url
  109. self.missing = missing
  110. BBFetchException.__init__(self, msg)
  111. self.args = (missing, url)
  112. class ParameterError(BBFetchException):
  113. """Exception raised when a url cannot be proccessed due to invalid parameters."""
  114. def __init__(self, message, url):
  115. msg = "URL: '%s' has invalid parameters. %s" % (url, message)
  116. self.url = url
  117. BBFetchException.__init__(self, msg)
  118. self.args = (message, url)
  119. class NetworkAccess(BBFetchException):
  120. """Exception raised when network access is disabled but it is required."""
  121. def __init__(self, url, cmd):
  122. 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)
  123. self.url = url
  124. self.cmd = cmd
  125. BBFetchException.__init__(self, msg)
  126. self.args = (url, cmd)
  127. class NonLocalMethod(Exception):
  128. def __init__(self):
  129. Exception.__init__(self)
  130. class URI(object):
  131. """
  132. A class representing a generic URI, with methods for
  133. accessing the URI components, and stringifies to the
  134. URI.
  135. It is constructed by calling it with a URI, or setting
  136. the attributes manually:
  137. uri = URI("http://example.com/")
  138. uri = URI()
  139. uri.scheme = 'http'
  140. uri.hostname = 'example.com'
  141. uri.path = '/'
  142. It has the following attributes:
  143. * scheme (read/write)
  144. * userinfo (authentication information) (read/write)
  145. * username (read/write)
  146. * password (read/write)
  147. Note, password is deprecated as of RFC 3986.
  148. * hostname (read/write)
  149. * port (read/write)
  150. * hostport (read only)
  151. "hostname:port", if both are set, otherwise just "hostname"
  152. * path (read/write)
  153. * path_quoted (read/write)
  154. A URI quoted version of path
  155. * params (dict) (read/write)
  156. * query (dict) (read/write)
  157. * relative (bool) (read only)
  158. True if this is a "relative URI", (e.g. file:foo.diff)
  159. It stringifies to the URI itself.
  160. Some notes about relative URIs: while it's specified that
  161. a URI beginning with <scheme>:// should either be directly
  162. followed by a hostname or a /, the old URI handling of the
  163. fetch2 library did not comform to this. Therefore, this URI
  164. class has some kludges to make sure that URIs are parsed in
  165. a way comforming to bitbake's current usage. This URI class
  166. supports the following:
  167. file:relative/path.diff (IETF compliant)
  168. git:relative/path.git (IETF compliant)
  169. git:///absolute/path.git (IETF compliant)
  170. file:///absolute/path.diff (IETF compliant)
  171. file://relative/path.diff (not IETF compliant)
  172. But it does not support the following:
  173. file://hostname/absolute/path.diff (would be IETF compliant)
  174. Note that the last case only applies to a list of
  175. "whitelisted" schemes (currently only file://), that requires
  176. its URIs to not have a network location.
  177. """
  178. _relative_schemes = ['file', 'git']
  179. _netloc_forbidden = ['file']
  180. def __init__(self, uri=None):
  181. self.scheme = ''
  182. self.userinfo = ''
  183. self.hostname = ''
  184. self.port = None
  185. self._path = ''
  186. self.params = {}
  187. self.query = {}
  188. self.relative = False
  189. if not uri:
  190. return
  191. # We hijack the URL parameters, since the way bitbake uses
  192. # them are not quite RFC compliant.
  193. uri, param_str = (uri.split(";", 1) + [None])[:2]
  194. urlp = urlparse.urlparse(uri)
  195. self.scheme = urlp.scheme
  196. reparse = 0
  197. # Coerce urlparse to make URI scheme use netloc
  198. if not self.scheme in urlparse.uses_netloc:
  199. urlparse.uses_params.append(self.scheme)
  200. reparse = 1
  201. # Make urlparse happy(/ier) by converting local resources
  202. # to RFC compliant URL format. E.g.:
  203. # file://foo.diff -> file:foo.diff
  204. if urlp.scheme in self._netloc_forbidden:
  205. uri = re.sub("(?<=:)//(?!/)", "", uri, 1)
  206. reparse = 1
  207. if reparse:
  208. urlp = urlparse.urlparse(uri)
  209. # Identify if the URI is relative or not
  210. if urlp.scheme in self._relative_schemes and \
  211. re.compile("^\w+:(?!//)").match(uri):
  212. self.relative = True
  213. if not self.relative:
  214. self.hostname = urlp.hostname or ''
  215. self.port = urlp.port
  216. self.userinfo += urlp.username or ''
  217. if urlp.password:
  218. self.userinfo += ':%s' % urlp.password
  219. self.path = urllib.unquote(urlp.path)
  220. if param_str:
  221. self.params = self._param_str_split(param_str, ";")
  222. if urlp.query:
  223. self.query = self._param_str_split(urlp.query, "&")
  224. def __str__(self):
  225. userinfo = self.userinfo
  226. if userinfo:
  227. userinfo += '@'
  228. return "%s:%s%s%s%s%s%s" % (
  229. self.scheme,
  230. '' if self.relative else '//',
  231. userinfo,
  232. self.hostport,
  233. self.path_quoted,
  234. self._query_str(),
  235. self._param_str())
  236. def _param_str(self):
  237. return (
  238. ''.join([';', self._param_str_join(self.params, ";")])
  239. if self.params else '')
  240. def _query_str(self):
  241. return (
  242. ''.join(['?', self._param_str_join(self.query, "&")])
  243. if self.query else '')
  244. def _param_str_split(self, string, elmdelim, kvdelim="="):
  245. ret = {}
  246. for k, v in [x.split(kvdelim, 1) for x in string.split(elmdelim)]:
  247. ret[k] = v
  248. return ret
  249. def _param_str_join(self, dict_, elmdelim, kvdelim="="):
  250. return elmdelim.join([kvdelim.join([k, v]) for k, v in dict_.items()])
  251. @property
  252. def hostport(self):
  253. if not self.port:
  254. return self.hostname
  255. return "%s:%d" % (self.hostname, self.port)
  256. @property
  257. def path_quoted(self):
  258. return urllib.quote(self.path)
  259. @path_quoted.setter
  260. def path_quoted(self, path):
  261. self.path = urllib.unquote(path)
  262. @property
  263. def path(self):
  264. return self._path
  265. @path.setter
  266. def path(self, path):
  267. self._path = path
  268. if not path or re.compile("^/").match(path):
  269. self.relative = False
  270. else:
  271. self.relative = True
  272. @property
  273. def username(self):
  274. if self.userinfo:
  275. return (self.userinfo.split(":", 1))[0]
  276. return ''
  277. @username.setter
  278. def username(self, username):
  279. password = self.password
  280. self.userinfo = username
  281. if password:
  282. self.userinfo += ":%s" % password
  283. @property
  284. def password(self):
  285. if self.userinfo and ":" in self.userinfo:
  286. return (self.userinfo.split(":", 1))[1]
  287. return ''
  288. @password.setter
  289. def password(self, password):
  290. self.userinfo = "%s:%s" % (self.username, password)
  291. def decodeurl(url):
  292. """Decodes an URL into the tokens (scheme, network location, path,
  293. user, password, parameters).
  294. """
  295. m = re.compile('(?P<type>[^:]*)://((?P<user>[^/]+)@)?(?P<location>[^;]+)(;(?P<parm>.*))?').match(url)
  296. if not m:
  297. raise MalformedUrl(url)
  298. type = m.group('type')
  299. location = m.group('location')
  300. if not location:
  301. raise MalformedUrl(url)
  302. user = m.group('user')
  303. parm = m.group('parm')
  304. locidx = location.find('/')
  305. if locidx != -1 and type.lower() != 'file':
  306. host = location[:locidx]
  307. path = location[locidx:]
  308. elif type.lower() == 'file':
  309. host = ""
  310. path = location
  311. else:
  312. host = location
  313. path = ""
  314. if user:
  315. m = re.compile('(?P<user>[^:]+)(:?(?P<pswd>.*))').match(user)
  316. if m:
  317. user = m.group('user')
  318. pswd = m.group('pswd')
  319. else:
  320. user = ''
  321. pswd = ''
  322. p = {}
  323. if parm:
  324. for s in parm.split(';'):
  325. if s:
  326. if not '=' in s:
  327. raise MalformedUrl(url, "The URL: '%s' is invalid: parameter %s does not specify a value (missing '=')" % (url, s))
  328. s1, s2 = s.split('=')
  329. p[s1] = s2
  330. return type, host, urllib.unquote(path), user, pswd, p
  331. def encodeurl(decoded):
  332. """Encodes a URL from tokens (scheme, network location, path,
  333. user, password, parameters).
  334. """
  335. type, host, path, user, pswd, p = decoded
  336. if not path:
  337. raise MissingParameterError('path', "encoded from the data %s" % str(decoded))
  338. if not type:
  339. raise MissingParameterError('type', "encoded from the data %s" % str(decoded))
  340. url = '%s://' % type
  341. if user and type != "file":
  342. url += "%s" % user
  343. if pswd:
  344. url += ":%s" % pswd
  345. url += "@"
  346. if host and type != "file":
  347. url += "%s" % host
  348. # Standardise path to ensure comparisons work
  349. while '//' in path:
  350. path = path.replace("//", "/")
  351. url += "%s" % urllib.quote(path)
  352. if p:
  353. for parm in p:
  354. url += ";%s=%s" % (parm, p[parm])
  355. return url
  356. def uri_replace(ud, uri_find, uri_replace, replacements, d):
  357. if not ud.url or not uri_find or not uri_replace:
  358. logger.error("uri_replace: passed an undefined value, not replacing")
  359. return None
  360. uri_decoded = list(decodeurl(ud.url))
  361. uri_find_decoded = list(decodeurl(uri_find))
  362. uri_replace_decoded = list(decodeurl(uri_replace))
  363. logger.debug(2, "For url %s comparing %s to %s" % (uri_decoded, uri_find_decoded, uri_replace_decoded))
  364. result_decoded = ['', '', '', '', '', {}]
  365. for loc, i in enumerate(uri_find_decoded):
  366. result_decoded[loc] = uri_decoded[loc]
  367. regexp = i
  368. if loc == 0 and regexp and not regexp.endswith("$"):
  369. # Leaving the type unanchored can mean "https" matching "file" can become "files"
  370. # which is clearly undesirable.
  371. regexp += "$"
  372. if loc == 5:
  373. # Handle URL parameters
  374. if i:
  375. # Any specified URL parameters must match
  376. for k in uri_replace_decoded[loc]:
  377. if uri_decoded[loc][k] != uri_replace_decoded[loc][k]:
  378. return None
  379. # Overwrite any specified replacement parameters
  380. for k in uri_replace_decoded[loc]:
  381. for l in replacements:
  382. uri_replace_decoded[loc][k] = uri_replace_decoded[loc][k].replace(l, replacements[l])
  383. result_decoded[loc][k] = uri_replace_decoded[loc][k]
  384. elif (re.match(regexp, uri_decoded[loc])):
  385. if not uri_replace_decoded[loc]:
  386. result_decoded[loc] = ""
  387. else:
  388. for k in replacements:
  389. uri_replace_decoded[loc] = uri_replace_decoded[loc].replace(k, replacements[k])
  390. #bb.note("%s %s %s" % (regexp, uri_replace_decoded[loc], uri_decoded[loc]))
  391. result_decoded[loc] = re.sub(regexp, uri_replace_decoded[loc], uri_decoded[loc], 1)
  392. if loc == 2:
  393. # Handle path manipulations
  394. basename = None
  395. if uri_decoded[0] != uri_replace_decoded[0] and ud.mirrortarball:
  396. # If the source and destination url types differ, must be a mirrortarball mapping
  397. basename = os.path.basename(ud.mirrortarball)
  398. # Kill parameters, they make no sense for mirror tarballs
  399. uri_decoded[5] = {}
  400. elif ud.localpath and ud.method.supports_checksum(ud):
  401. basename = os.path.basename(ud.localpath)
  402. if basename and not result_decoded[loc].endswith(basename):
  403. result_decoded[loc] = os.path.join(result_decoded[loc], basename)
  404. else:
  405. return None
  406. result = encodeurl(result_decoded)
  407. if result == ud.url:
  408. return None
  409. logger.debug(2, "For url %s returning %s" % (ud.url, result))
  410. return result
  411. methods = []
  412. urldata_cache = {}
  413. saved_headrevs = {}
  414. def fetcher_init(d):
  415. """
  416. Called to initialize the fetchers once the configuration data is known.
  417. Calls before this must not hit the cache.
  418. """
  419. # When to drop SCM head revisions controlled by user policy
  420. srcrev_policy = d.getVar('BB_SRCREV_POLICY', True) or "clear"
  421. if srcrev_policy == "cache":
  422. logger.debug(1, "Keeping SRCREV cache due to cache policy of: %s", srcrev_policy)
  423. elif srcrev_policy == "clear":
  424. logger.debug(1, "Clearing SRCREV cache due to cache policy of: %s", srcrev_policy)
  425. revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
  426. try:
  427. bb.fetch2.saved_headrevs = revs.items()
  428. except:
  429. pass
  430. revs.clear()
  431. else:
  432. raise FetchError("Invalid SRCREV cache policy of: %s" % srcrev_policy)
  433. _checksum_cache.init_cache(d)
  434. for m in methods:
  435. if hasattr(m, "init"):
  436. m.init(d)
  437. def fetcher_parse_save():
  438. _checksum_cache.save_extras()
  439. def fetcher_parse_done():
  440. _checksum_cache.save_merge()
  441. def fetcher_compare_revisions():
  442. """
  443. Compare the revisions in the persistant cache with current values and
  444. return true/false on whether they've changed.
  445. """
  446. data = bb.persist_data.persist('BB_URI_HEADREVS', d).items()
  447. data2 = bb.fetch2.saved_headrevs
  448. changed = False
  449. for key in data:
  450. if key not in data2 or data2[key] != data[key]:
  451. logger.debug(1, "%s changed", key)
  452. changed = True
  453. return True
  454. else:
  455. logger.debug(2, "%s did not change", key)
  456. return False
  457. def mirror_from_string(data):
  458. return [ i.split() for i in (data or "").replace('\\n','\n').split('\n') if i ]
  459. def verify_checksum(ud, d, precomputed={}):
  460. """
  461. verify the MD5 and SHA256 checksum for downloaded src
  462. Raises a FetchError if one or both of the SRC_URI checksums do not match
  463. the downloaded file, or if BB_STRICT_CHECKSUM is set and there are no
  464. checksums specified.
  465. Returns a dict of checksums that can be stored in a done stamp file and
  466. passed in as precomputed parameter in a later call to avoid re-computing
  467. the checksums from the file. This allows verifying the checksums of the
  468. file against those in the recipe each time, rather than only after
  469. downloading. See https://bugzilla.yoctoproject.org/show_bug.cgi?id=5571.
  470. """
  471. _MD5_KEY = "md5"
  472. _SHA256_KEY = "sha256"
  473. if ud.ignore_checksums or not ud.method.supports_checksum(ud):
  474. return {}
  475. if _MD5_KEY in precomputed:
  476. md5data = precomputed[_MD5_KEY]
  477. else:
  478. md5data = bb.utils.md5_file(ud.localpath)
  479. if _SHA256_KEY in precomputed:
  480. sha256data = precomputed[_SHA256_KEY]
  481. else:
  482. sha256data = bb.utils.sha256_file(ud.localpath)
  483. if ud.method.recommends_checksum(ud) and not ud.md5_expected and not ud.sha256_expected:
  484. # If strict checking enabled and neither sum defined, raise error
  485. strict = d.getVar("BB_STRICT_CHECKSUM", True) or "0"
  486. if strict == "1":
  487. logger.error('No checksum specified for %s, please add at least one to the recipe:\n'
  488. 'SRC_URI[%s] = "%s"\nSRC_URI[%s] = "%s"' %
  489. (ud.localpath, ud.md5_name, md5data,
  490. ud.sha256_name, sha256data))
  491. raise NoChecksumError('Missing SRC_URI checksum', ud.url)
  492. # Log missing sums so user can more easily add them
  493. logger.warning('Missing md5 SRC_URI checksum for %s, consider adding to the recipe:\n'
  494. 'SRC_URI[%s] = "%s"',
  495. ud.localpath, ud.md5_name, md5data)
  496. logger.warning('Missing sha256 SRC_URI checksum for %s, consider adding to the recipe:\n'
  497. 'SRC_URI[%s] = "%s"',
  498. ud.localpath, ud.sha256_name, sha256data)
  499. # We want to alert the user if a checksum is defined in the recipe but
  500. # it does not match.
  501. msg = ""
  502. mismatch = False
  503. if ud.md5_expected and ud.md5_expected != md5data:
  504. msg = msg + "\nFile: '%s' has %s checksum %s when %s was expected" % (ud.localpath, 'md5', md5data, ud.md5_expected)
  505. mismatch = True;
  506. if ud.sha256_expected and ud.sha256_expected != sha256data:
  507. msg = msg + "\nFile: '%s' has %s checksum %s when %s was expected" % (ud.localpath, 'sha256', sha256data, ud.sha256_expected)
  508. mismatch = True;
  509. if mismatch:
  510. msg = msg + '\nIf this change is expected (e.g. you have upgraded to a new version without updating the checksums) then you can use these lines within the recipe:\nSRC_URI[%s] = "%s"\nSRC_URI[%s] = "%s"\nOtherwise you should retry the download and/or check with upstream to determine if the file has become corrupted or otherwise unexpectedly modified.\n' % (ud.md5_name, md5data, ud.sha256_name, sha256data)
  511. if len(msg):
  512. raise ChecksumError('Checksum mismatch!%s' % msg, ud.url, md5data)
  513. return {
  514. _MD5_KEY: md5data,
  515. _SHA256_KEY: sha256data
  516. }
  517. def verify_donestamp(ud, d, origud=None):
  518. """
  519. Check whether the done stamp file has the right checksums (if the fetch
  520. method supports them). If it doesn't, delete the done stamp and force
  521. a re-download.
  522. Returns True, if the donestamp exists and is valid, False otherwise. When
  523. returning False, any existing done stamps are removed.
  524. """
  525. if not ud.needdonestamp:
  526. return True
  527. if not os.path.exists(ud.donestamp):
  528. return False
  529. if (not ud.method.supports_checksum(ud) or
  530. (origud and not origud.method.supports_checksum(origud))):
  531. # done stamp exists, checksums not supported; assume the local file is
  532. # current
  533. return True
  534. if not os.path.exists(ud.localpath):
  535. # done stamp exists, but the downloaded file does not; the done stamp
  536. # must be incorrect, re-trigger the download
  537. bb.utils.remove(ud.donestamp)
  538. return False
  539. precomputed_checksums = {}
  540. # Only re-use the precomputed checksums if the donestamp is newer than the
  541. # file. Do not rely on the mtime of directories, though. If ud.localpath is
  542. # a directory, there will probably not be any checksums anyway.
  543. if (os.path.isdir(ud.localpath) or
  544. os.path.getmtime(ud.localpath) < os.path.getmtime(ud.donestamp)):
  545. try:
  546. with open(ud.donestamp, "rb") as cachefile:
  547. pickled = pickle.Unpickler(cachefile)
  548. precomputed_checksums.update(pickled.load())
  549. except Exception as e:
  550. # Avoid the warnings on the upgrade path from emtpy done stamp
  551. # files to those containing the checksums.
  552. if not isinstance(e, EOFError):
  553. # Ignore errors, they aren't fatal
  554. logger.warning("Couldn't load checksums from donestamp %s: %s "
  555. "(msg: %s)" % (ud.donestamp, type(e).__name__,
  556. str(e)))
  557. try:
  558. checksums = verify_checksum(ud, d, precomputed_checksums)
  559. # If the cache file did not have the checksums, compute and store them
  560. # as an upgrade path from the previous done stamp file format.
  561. if checksums != precomputed_checksums:
  562. with open(ud.donestamp, "wb") as cachefile:
  563. p = pickle.Pickler(cachefile, pickle.HIGHEST_PROTOCOL)
  564. p.dump(checksums)
  565. return True
  566. except ChecksumError as e:
  567. # Checksums failed to verify, trigger re-download and remove the
  568. # incorrect stamp file.
  569. logger.warning("Checksum mismatch for local file %s\n"
  570. "Cleaning and trying again." % ud.localpath)
  571. if os.path.exists(ud.localpath):
  572. rename_bad_checksum(ud, e.checksum)
  573. bb.utils.remove(ud.donestamp)
  574. return False
  575. def update_stamp(ud, d):
  576. """
  577. donestamp is file stamp indicating the whole fetching is done
  578. this function update the stamp after verifying the checksum
  579. """
  580. if not ud.needdonestamp:
  581. return
  582. if os.path.exists(ud.donestamp):
  583. # Touch the done stamp file to show active use of the download
  584. try:
  585. os.utime(ud.donestamp, None)
  586. except:
  587. # Errors aren't fatal here
  588. pass
  589. else:
  590. try:
  591. checksums = verify_checksum(ud, d)
  592. # Store the checksums for later re-verification against the recipe
  593. with open(ud.donestamp, "wb") as cachefile:
  594. p = pickle.Pickler(cachefile, pickle.HIGHEST_PROTOCOL)
  595. p.dump(checksums)
  596. except ChecksumError as e:
  597. # Checksums failed to verify, trigger re-download and remove the
  598. # incorrect stamp file.
  599. logger.warning("Checksum mismatch for local file %s\n"
  600. "Cleaning and trying again." % ud.localpath)
  601. if os.path.exists(ud.localpath):
  602. rename_bad_checksum(ud, e.checksum)
  603. bb.utils.remove(ud.donestamp)
  604. raise
  605. def subprocess_setup():
  606. # Python installs a SIGPIPE handler by default. This is usually not what
  607. # non-Python subprocesses expect.
  608. # SIGPIPE errors are known issues with gzip/bash
  609. signal.signal(signal.SIGPIPE, signal.SIG_DFL)
  610. def get_autorev(d):
  611. # only not cache src rev in autorev case
  612. if d.getVar('BB_SRCREV_POLICY', True) != "cache":
  613. d.setVar('BB_DONT_CACHE', '1')
  614. return "AUTOINC"
  615. def get_srcrev(d, method_name='sortable_revision'):
  616. """
  617. Return the revsion string, usually for use in the version string (PV) of the current package
  618. Most packages usually only have one SCM so we just pass on the call.
  619. In the multi SCM case, we build a value based on SRCREV_FORMAT which must
  620. have been set.
  621. The idea here is that we put the string "AUTOINC+" into return value if the revisions are not
  622. incremental, other code is then responsible for turning that into an increasing value (if needed)
  623. A method_name can be supplied to retrieve an alternatively formatted revision from a fetcher, if
  624. that fetcher provides a method with the given name and the same signature as sortable_revision.
  625. """
  626. scms = []
  627. fetcher = Fetch(d.getVar('SRC_URI', True).split(), d)
  628. urldata = fetcher.ud
  629. for u in urldata:
  630. if urldata[u].method.supports_srcrev():
  631. scms.append(u)
  632. if len(scms) == 0:
  633. raise FetchError("SRCREV was used yet no valid SCM was found in SRC_URI")
  634. if len(scms) == 1 and len(urldata[scms[0]].names) == 1:
  635. autoinc, rev = getattr(urldata[scms[0]].method, method_name)(urldata[scms[0]], d, urldata[scms[0]].names[0])
  636. if len(rev) > 10:
  637. rev = rev[:10]
  638. if autoinc:
  639. return "AUTOINC+" + rev
  640. return rev
  641. #
  642. # Mutiple SCMs are in SRC_URI so we resort to SRCREV_FORMAT
  643. #
  644. format = d.getVar('SRCREV_FORMAT', True)
  645. if not format:
  646. raise FetchError("The SRCREV_FORMAT variable must be set when multiple SCMs are used.")
  647. seenautoinc = False
  648. for scm in scms:
  649. ud = urldata[scm]
  650. for name in ud.names:
  651. autoinc, rev = getattr(ud.method, method_name)(ud, d, name)
  652. seenautoinc = seenautoinc or autoinc
  653. if len(rev) > 10:
  654. rev = rev[:10]
  655. format = format.replace(name, rev)
  656. if seenautoinc:
  657. format = "AUTOINC+" + format
  658. return format
  659. def localpath(url, d):
  660. fetcher = bb.fetch2.Fetch([url], d)
  661. return fetcher.localpath(url)
  662. def runfetchcmd(cmd, d, quiet=False, cleanup=None):
  663. """
  664. Run cmd returning the command output
  665. Raise an error if interrupted or cmd fails
  666. Optionally echo command output to stdout
  667. Optionally remove the files/directories listed in cleanup upon failure
  668. """
  669. # Need to export PATH as binary could be in metadata paths
  670. # rather than host provided
  671. # Also include some other variables.
  672. # FIXME: Should really include all export varaiables?
  673. exportvars = ['HOME', 'PATH',
  674. 'HTTP_PROXY', 'http_proxy',
  675. 'HTTPS_PROXY', 'https_proxy',
  676. 'FTP_PROXY', 'ftp_proxy',
  677. 'FTPS_PROXY', 'ftps_proxy',
  678. 'NO_PROXY', 'no_proxy',
  679. 'ALL_PROXY', 'all_proxy',
  680. 'GIT_PROXY_COMMAND',
  681. 'GIT_SSL_CAINFO',
  682. 'GIT_SMART_HTTP',
  683. 'SSH_AUTH_SOCK', 'SSH_AGENT_PID',
  684. 'SOCKS5_USER', 'SOCKS5_PASSWD',
  685. 'DBUS_SESSION_BUS_ADDRESS']
  686. if not cleanup:
  687. cleanup = []
  688. origenv = d.getVar("BB_ORIGENV", False)
  689. for var in exportvars:
  690. val = d.getVar(var, True) or (origenv and origenv.getVar(var, True))
  691. if val:
  692. cmd = 'export ' + var + '=\"%s\"; %s' % (val, cmd)
  693. logger.debug(1, "Running %s", cmd)
  694. success = False
  695. error_message = ""
  696. try:
  697. (output, errors) = bb.process.run(cmd, shell=True, stderr=subprocess.PIPE)
  698. success = True
  699. except bb.process.NotFoundError as e:
  700. error_message = "Fetch command %s" % (e.command)
  701. except bb.process.ExecutionError as e:
  702. if e.stdout:
  703. output = "output:\n%s\n%s" % (e.stdout, e.stderr)
  704. elif e.stderr:
  705. output = "output:\n%s" % e.stderr
  706. else:
  707. output = "no output"
  708. error_message = "Fetch command failed with exit code %s, %s" % (e.exitcode, output)
  709. except bb.process.CmdError as e:
  710. error_message = "Fetch command %s could not be run:\n%s" % (e.command, e.msg)
  711. if not success:
  712. for f in cleanup:
  713. try:
  714. bb.utils.remove(f, True)
  715. except OSError:
  716. pass
  717. raise FetchError(error_message)
  718. return output
  719. def check_network_access(d, info = "", url = None):
  720. """
  721. log remote network access, and error if BB_NO_NETWORK is set
  722. """
  723. if d.getVar("BB_NO_NETWORK", True) == "1":
  724. raise NetworkAccess(url, info)
  725. else:
  726. logger.debug(1, "Fetcher accessed the network with the command %s" % info)
  727. def build_mirroruris(origud, mirrors, ld):
  728. uris = []
  729. uds = []
  730. replacements = {}
  731. replacements["TYPE"] = origud.type
  732. replacements["HOST"] = origud.host
  733. replacements["PATH"] = origud.path
  734. replacements["BASENAME"] = origud.path.split("/")[-1]
  735. replacements["MIRRORNAME"] = origud.host.replace(':','.') + origud.path.replace('/', '.').replace('*', '.')
  736. def adduri(ud, uris, uds, mirrors):
  737. for line in mirrors:
  738. try:
  739. (find, replace) = line
  740. except ValueError:
  741. continue
  742. newuri = uri_replace(ud, find, replace, replacements, ld)
  743. if not newuri or newuri in uris or newuri == origud.url:
  744. continue
  745. if not trusted_network(ld, newuri):
  746. logger.debug(1, "Mirror %s not in the list of trusted networks, skipping" % (newuri))
  747. continue
  748. # Create a local copy of the mirrors minus the current line
  749. # this will prevent us from recursively processing the same line
  750. # as well as indirect recursion A -> B -> C -> A
  751. localmirrors = list(mirrors)
  752. localmirrors.remove(line)
  753. try:
  754. newud = FetchData(newuri, ld)
  755. newud.setup_localpath(ld)
  756. except bb.fetch2.BBFetchException as e:
  757. logger.debug(1, "Mirror fetch failure for url %s (original url: %s)" % (newuri, origud.url))
  758. logger.debug(1, str(e))
  759. try:
  760. # setup_localpath of file:// urls may fail, we should still see
  761. # if mirrors of the url exist
  762. adduri(newud, uris, uds, localmirrors)
  763. except UnboundLocalError:
  764. pass
  765. continue
  766. uris.append(newuri)
  767. uds.append(newud)
  768. adduri(newud, uris, uds, localmirrors)
  769. adduri(origud, uris, uds, mirrors)
  770. return uris, uds
  771. def rename_bad_checksum(ud, suffix):
  772. """
  773. Renames files to have suffix from parameter
  774. """
  775. if ud.localpath is None:
  776. return
  777. new_localpath = "%s_bad-checksum_%s" % (ud.localpath, suffix)
  778. bb.warn("Renaming %s to %s" % (ud.localpath, new_localpath))
  779. bb.utils.movefile(ud.localpath, new_localpath)
  780. def try_mirror_url(fetch, origud, ud, ld, check = False):
  781. # Return of None or a value means we're finished
  782. # False means try another url
  783. if ud.lockfile and ud.lockfile != origud.lockfile:
  784. lf = bb.utils.lockfile(ud.lockfile)
  785. try:
  786. if check:
  787. found = ud.method.checkstatus(fetch, ud, ld)
  788. if found:
  789. return found
  790. return False
  791. os.chdir(ld.getVar("DL_DIR", True))
  792. if not verify_donestamp(ud, ld, origud) or ud.method.need_update(ud, ld):
  793. ud.method.download(ud, ld)
  794. if hasattr(ud.method,"build_mirror_data"):
  795. ud.method.build_mirror_data(ud, ld)
  796. if not ud.localpath or not os.path.exists(ud.localpath):
  797. return False
  798. if ud.localpath == origud.localpath:
  799. return ud.localpath
  800. # We may be obtaining a mirror tarball which needs further processing by the real fetcher
  801. # If that tarball is a local file:// we need to provide a symlink to it
  802. dldir = ld.getVar("DL_DIR", True)
  803. if origud.mirrortarball and os.path.basename(ud.localpath) == os.path.basename(origud.mirrortarball) \
  804. and os.path.basename(ud.localpath) != os.path.basename(origud.localpath):
  805. # Create donestamp in old format to avoid triggering a re-download
  806. if ud.donestamp:
  807. bb.utils.mkdirhier(os.path.dirname(ud.donestamp))
  808. open(ud.donestamp, 'w').close()
  809. dest = os.path.join(dldir, os.path.basename(ud.localpath))
  810. if not os.path.exists(dest):
  811. os.symlink(ud.localpath, dest)
  812. if not verify_donestamp(origud, ld) or origud.method.need_update(origud, ld):
  813. origud.method.download(origud, ld)
  814. if hasattr(origud.method,"build_mirror_data"):
  815. origud.method.build_mirror_data(origud, ld)
  816. return origud.localpath
  817. # Otherwise the result is a local file:// and we symlink to it
  818. if not os.path.exists(origud.localpath):
  819. if os.path.islink(origud.localpath):
  820. # Broken symbolic link
  821. os.unlink(origud.localpath)
  822. os.symlink(ud.localpath, origud.localpath)
  823. update_stamp(origud, ld)
  824. return ud.localpath
  825. except bb.fetch2.NetworkAccess:
  826. raise
  827. except bb.fetch2.BBFetchException as e:
  828. if isinstance(e, ChecksumError):
  829. logger.warning("Mirror checksum failure for url %s (original url: %s)\nCleaning and trying again." % (ud.url, origud.url))
  830. logger.warning(str(e))
  831. if os.path.exists(ud.localpath):
  832. rename_bad_checksum(ud, e.checksum)
  833. elif isinstance(e, NoChecksumError):
  834. raise
  835. else:
  836. logger.debug(1, "Mirror fetch failure for url %s (original url: %s)" % (ud.url, origud.url))
  837. logger.debug(1, str(e))
  838. try:
  839. ud.method.clean(ud, ld)
  840. except UnboundLocalError:
  841. pass
  842. return False
  843. finally:
  844. if ud.lockfile and ud.lockfile != origud.lockfile:
  845. bb.utils.unlockfile(lf)
  846. def try_mirrors(fetch, d, origud, mirrors, check = False):
  847. """
  848. Try to use a mirrored version of the sources.
  849. This method will be automatically called before the fetchers go.
  850. d Is a bb.data instance
  851. uri is the original uri we're trying to download
  852. mirrors is the list of mirrors we're going to try
  853. """
  854. ld = d.createCopy()
  855. uris, uds = build_mirroruris(origud, mirrors, ld)
  856. for index, uri in enumerate(uris):
  857. ret = try_mirror_url(fetch, origud, uds[index], ld, check)
  858. if ret != False:
  859. return ret
  860. return None
  861. def trusted_network(d, url):
  862. """
  863. Use a trusted url during download if networking is enabled and
  864. BB_ALLOWED_NETWORKS is set globally or for a specific recipe.
  865. Note: modifies SRC_URI & mirrors.
  866. """
  867. if d.getVar('BB_NO_NETWORK', True) == "1":
  868. return True
  869. pkgname = d.expand(d.getVar('PN', False))
  870. trusted_hosts = d.getVarFlag('BB_ALLOWED_NETWORKS', pkgname, False)
  871. if not trusted_hosts:
  872. trusted_hosts = d.getVar('BB_ALLOWED_NETWORKS', True)
  873. # Not enabled.
  874. if not trusted_hosts:
  875. return True
  876. scheme, network, path, user, passwd, param = decodeurl(url)
  877. if not network:
  878. return True
  879. network = network.split(':')[0]
  880. network = network.lower()
  881. for host in trusted_hosts.split(" "):
  882. host = host.lower()
  883. if host.startswith("*.") and ("." + network).endswith(host[1:]):
  884. return True
  885. if host == network:
  886. return True
  887. return False
  888. def srcrev_internal_helper(ud, d, name):
  889. """
  890. Return:
  891. a) a source revision if specified
  892. b) latest revision if SRCREV="AUTOINC"
  893. c) None if not specified
  894. """
  895. srcrev = None
  896. pn = d.getVar("PN", True)
  897. attempts = []
  898. if name != '' and pn:
  899. attempts.append("SRCREV_%s_pn-%s" % (name, pn))
  900. if name != '':
  901. attempts.append("SRCREV_%s" % name)
  902. if pn:
  903. attempts.append("SRCREV_pn-%s" % pn)
  904. attempts.append("SRCREV")
  905. for a in attempts:
  906. srcrev = d.getVar(a, True)
  907. if srcrev and srcrev != "INVALID":
  908. break
  909. if 'rev' in ud.parm and 'tag' in ud.parm:
  910. raise FetchError("Please specify a ;rev= parameter or a ;tag= parameter in the url %s but not both." % (ud.url))
  911. if 'rev' in ud.parm or 'tag' in ud.parm:
  912. if 'rev' in ud.parm:
  913. parmrev = ud.parm['rev']
  914. else:
  915. parmrev = ud.parm['tag']
  916. if srcrev == "INVALID" or not srcrev:
  917. return parmrev
  918. if srcrev != parmrev:
  919. raise FetchError("Conflicting revisions (%s from SRCREV and %s from the url) found, please spcify one valid value" % (srcrev, parmrev))
  920. return parmrev
  921. if srcrev == "INVALID" or not srcrev:
  922. 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)
  923. if srcrev == "AUTOINC":
  924. srcrev = ud.method.latest_revision(ud, d, name)
  925. return srcrev
  926. def get_checksum_file_list(d):
  927. """ Get a list of files checksum in SRC_URI
  928. Returns the resolved local paths of all local file entries in
  929. SRC_URI as a space-separated string
  930. """
  931. fetch = Fetch([], d, cache = False, localonly = True)
  932. dl_dir = d.getVar('DL_DIR', True)
  933. filelist = []
  934. for u in fetch.urls:
  935. ud = fetch.ud[u]
  936. if ud and isinstance(ud.method, local.Local):
  937. paths = ud.method.localpaths(ud, d)
  938. for f in paths:
  939. pth = ud.decodedurl
  940. if '*' in pth:
  941. f = os.path.join(os.path.abspath(f), pth)
  942. if f.startswith(dl_dir):
  943. # The local fetcher's behaviour is to return a path under DL_DIR if it couldn't find the file anywhere else
  944. if os.path.exists(f):
  945. bb.warn("Getting checksum for %s SRC_URI entry %s: file not found except in DL_DIR" % (d.getVar('PN', True), os.path.basename(f)))
  946. else:
  947. bb.warn("Unable to get checksum for %s SRC_URI entry %s: file could not be found" % (d.getVar('PN', True), os.path.basename(f)))
  948. filelist.append(f + ":" + str(os.path.exists(f)))
  949. return " ".join(filelist)
  950. def get_file_checksums(filelist, pn):
  951. """Get a list of the checksums for a list of local files
  952. Returns the checksums for a list of local files, caching the results as
  953. it proceeds
  954. """
  955. return _checksum_cache.get_checksums(filelist, pn)
  956. class FetchData(object):
  957. """
  958. A class which represents the fetcher state for a given URI.
  959. """
  960. def __init__(self, url, d, localonly = False):
  961. # localpath is the location of a downloaded result. If not set, the file is local.
  962. self.donestamp = None
  963. self.needdonestamp = True
  964. self.localfile = ""
  965. self.localpath = None
  966. self.lockfile = None
  967. self.mirrortarball = None
  968. self.basename = None
  969. self.basepath = None
  970. (self.type, self.host, self.path, self.user, self.pswd, self.parm) = decodeurl(data.expand(url, d))
  971. self.date = self.getSRCDate(d)
  972. self.url = url
  973. if not self.user and "user" in self.parm:
  974. self.user = self.parm["user"]
  975. if not self.pswd and "pswd" in self.parm:
  976. self.pswd = self.parm["pswd"]
  977. self.setup = False
  978. if "name" in self.parm:
  979. self.md5_name = "%s.md5sum" % self.parm["name"]
  980. self.sha256_name = "%s.sha256sum" % self.parm["name"]
  981. else:
  982. self.md5_name = "md5sum"
  983. self.sha256_name = "sha256sum"
  984. if self.md5_name in self.parm:
  985. self.md5_expected = self.parm[self.md5_name]
  986. elif self.type not in ["http", "https", "ftp", "ftps", "sftp"]:
  987. self.md5_expected = None
  988. else:
  989. self.md5_expected = d.getVarFlag("SRC_URI", self.md5_name, True)
  990. if self.sha256_name in self.parm:
  991. self.sha256_expected = self.parm[self.sha256_name]
  992. elif self.type not in ["http", "https", "ftp", "ftps", "sftp"]:
  993. self.sha256_expected = None
  994. else:
  995. self.sha256_expected = d.getVarFlag("SRC_URI", self.sha256_name, True)
  996. self.ignore_checksums = False
  997. self.names = self.parm.get("name",'default').split(',')
  998. self.method = None
  999. for m in methods:
  1000. if m.supports(self, d):
  1001. self.method = m
  1002. break
  1003. if not self.method:
  1004. raise NoMethodError(url)
  1005. if localonly and not isinstance(self.method, local.Local):
  1006. raise NonLocalMethod()
  1007. if self.parm.get("proto", None) and "protocol" not in self.parm:
  1008. logger.warning('Consider updating %s recipe to use "protocol" not "proto" in SRC_URI.', d.getVar('PN', True))
  1009. self.parm["protocol"] = self.parm.get("proto", None)
  1010. if hasattr(self.method, "urldata_init"):
  1011. self.method.urldata_init(self, d)
  1012. if "localpath" in self.parm:
  1013. # if user sets localpath for file, use it instead.
  1014. self.localpath = self.parm["localpath"]
  1015. self.basename = os.path.basename(self.localpath)
  1016. elif self.localfile:
  1017. self.localpath = self.method.localpath(self, d)
  1018. dldir = d.getVar("DL_DIR", True)
  1019. if not self.needdonestamp:
  1020. return
  1021. # Note: .done and .lock files should always be in DL_DIR whereas localpath may not be.
  1022. if self.localpath and self.localpath.startswith(dldir):
  1023. basepath = self.localpath
  1024. elif self.localpath:
  1025. basepath = dldir + os.sep + os.path.basename(self.localpath)
  1026. elif self.basepath or self.basename:
  1027. basepath = dldir + os.sep + (self.basepath or self.basename)
  1028. else:
  1029. bb.fatal("Can't determine lock path for url %s" % url)
  1030. self.donestamp = basepath + '.done'
  1031. self.lockfile = basepath + '.lock'
  1032. def setup_revisons(self, d):
  1033. self.revisions = {}
  1034. for name in self.names:
  1035. self.revisions[name] = srcrev_internal_helper(self, d, name)
  1036. # add compatibility code for non name specified case
  1037. if len(self.names) == 1:
  1038. self.revision = self.revisions[self.names[0]]
  1039. def setup_localpath(self, d):
  1040. if not self.localpath:
  1041. self.localpath = self.method.localpath(self, d)
  1042. def getSRCDate(self, d):
  1043. """
  1044. Return the SRC Date for the component
  1045. d the bb.data module
  1046. """
  1047. if "srcdate" in self.parm:
  1048. return self.parm['srcdate']
  1049. pn = d.getVar("PN", True)
  1050. if pn:
  1051. return d.getVar("SRCDATE_%s" % pn, True) or d.getVar("SRCDATE", True) or d.getVar("DATE", True)
  1052. return d.getVar("SRCDATE", True) or d.getVar("DATE", True)
  1053. class FetchMethod(object):
  1054. """Base class for 'fetch'ing data"""
  1055. def __init__(self, urls=None):
  1056. self.urls = []
  1057. def supports(self, urldata, d):
  1058. """
  1059. Check to see if this fetch class supports a given url.
  1060. """
  1061. return 0
  1062. def localpath(self, urldata, d):
  1063. """
  1064. Return the local filename of a given url assuming a successful fetch.
  1065. Can also setup variables in urldata for use in go (saving code duplication
  1066. and duplicate code execution)
  1067. """
  1068. return os.path.join(data.getVar("DL_DIR", d, True), urldata.localfile)
  1069. def supports_checksum(self, urldata):
  1070. """
  1071. Is localpath something that can be represented by a checksum?
  1072. """
  1073. # We cannot compute checksums for directories
  1074. if os.path.isdir(urldata.localpath) == True:
  1075. return False
  1076. if urldata.localpath.find("*") != -1:
  1077. return False
  1078. return True
  1079. def recommends_checksum(self, urldata):
  1080. """
  1081. Is the backend on where checksumming is recommended (should warnings
  1082. be displayed if there is no checksum)?
  1083. """
  1084. return False
  1085. def _strip_leading_slashes(self, relpath):
  1086. """
  1087. Remove leading slash as os.path.join can't cope
  1088. """
  1089. while os.path.isabs(relpath):
  1090. relpath = relpath[1:]
  1091. return relpath
  1092. def setUrls(self, urls):
  1093. self.__urls = urls
  1094. def getUrls(self):
  1095. return self.__urls
  1096. urls = property(getUrls, setUrls, None, "Urls property")
  1097. def need_update(self, ud, d):
  1098. """
  1099. Force a fetch, even if localpath exists?
  1100. """
  1101. if os.path.exists(ud.localpath):
  1102. return False
  1103. return True
  1104. def supports_srcrev(self):
  1105. """
  1106. The fetcher supports auto source revisions (SRCREV)
  1107. """
  1108. return False
  1109. def download(self, urldata, d):
  1110. """
  1111. Fetch urls
  1112. Assumes localpath was called first
  1113. """
  1114. raise NoMethodError(url)
  1115. def unpack(self, urldata, rootdir, data):
  1116. iterate = False
  1117. file = urldata.localpath
  1118. # Localpath can't deal with 'dir/*' entries, so it converts them to '.',
  1119. # but it must be corrected back for local files copying
  1120. if urldata.basename == '*' and file.endswith('/.'):
  1121. file = '%s/%s' % (file.rstrip('/.'), urldata.path)
  1122. try:
  1123. unpack = bb.utils.to_boolean(urldata.parm.get('unpack'), True)
  1124. except ValueError as exc:
  1125. bb.fatal("Invalid value for 'unpack' parameter for %s: %s" %
  1126. (file, urldata.parm.get('unpack')))
  1127. base, ext = os.path.splitext(file)
  1128. if ext in ['.gz', '.bz2', '.Z', '.xz', '.lz']:
  1129. efile = os.path.join(rootdir, os.path.basename(base))
  1130. else:
  1131. efile = file
  1132. cmd = None
  1133. if unpack:
  1134. if file.endswith('.tar'):
  1135. cmd = 'tar x --no-same-owner -f %s' % file
  1136. elif file.endswith('.tgz') or file.endswith('.tar.gz') or file.endswith('.tar.Z'):
  1137. cmd = 'tar xz --no-same-owner -f %s' % file
  1138. elif file.endswith('.tbz') or file.endswith('.tbz2') or file.endswith('.tar.bz2'):
  1139. cmd = 'bzip2 -dc %s | tar x --no-same-owner -f -' % file
  1140. elif file.endswith('.gz') or file.endswith('.Z') or file.endswith('.z'):
  1141. cmd = 'gzip -dc %s > %s' % (file, efile)
  1142. elif file.endswith('.bz2'):
  1143. cmd = 'bzip2 -dc %s > %s' % (file, efile)
  1144. elif file.endswith('.tar.xz'):
  1145. cmd = 'xz -dc %s | tar x --no-same-owner -f -' % file
  1146. elif file.endswith('.xz'):
  1147. cmd = 'xz -dc %s > %s' % (file, efile)
  1148. elif file.endswith('.tar.lz'):
  1149. cmd = 'lzip -dc %s | tar x --no-same-owner -f -' % file
  1150. elif file.endswith('.lz'):
  1151. cmd = 'lzip -dc %s > %s' % (file, efile)
  1152. elif file.endswith('.zip') or file.endswith('.jar'):
  1153. try:
  1154. dos = bb.utils.to_boolean(urldata.parm.get('dos'), False)
  1155. except ValueError as exc:
  1156. bb.fatal("Invalid value for 'dos' parameter for %s: %s" %
  1157. (file, urldata.parm.get('dos')))
  1158. cmd = 'unzip -q -o'
  1159. if dos:
  1160. cmd = '%s -a' % cmd
  1161. cmd = "%s '%s'" % (cmd, file)
  1162. elif file.endswith('.rpm') or file.endswith('.srpm'):
  1163. if 'extract' in urldata.parm:
  1164. unpack_file = urldata.parm.get('extract')
  1165. cmd = 'rpm2cpio.sh %s | cpio -id %s' % (file, unpack_file)
  1166. iterate = True
  1167. iterate_file = unpack_file
  1168. else:
  1169. cmd = 'rpm2cpio.sh %s | cpio -id' % (file)
  1170. elif file.endswith('.deb') or file.endswith('.ipk'):
  1171. cmd = 'ar -p %s data.tar.gz | zcat | tar --no-same-owner -xpf -' % file
  1172. elif file.endswith('.tar.7z'):
  1173. cmd = '7z x -so %s | tar xf - ' % file
  1174. elif file.endswith('.7z'):
  1175. cmd = '7za x -y %s 1>/dev/null' % file
  1176. # If 'subdir' param exists, create a dir and use it as destination for unpack cmd
  1177. if 'subdir' in urldata.parm:
  1178. unpackdir = '%s/%s' % (rootdir, urldata.parm.get('subdir'))
  1179. bb.utils.mkdirhier(unpackdir)
  1180. else:
  1181. unpackdir = rootdir
  1182. if not unpack or not cmd:
  1183. # If file == dest, then avoid any copies, as we already put the file into dest!
  1184. dest = os.path.join(unpackdir, os.path.basename(file))
  1185. if file != dest and not (os.path.exists(dest) and os.path.samefile(file, dest)):
  1186. destdir = '.'
  1187. # For file:// entries all intermediate dirs in path must be created at destination
  1188. if urldata.type == "file":
  1189. # Trailing '/' does a copying to wrong place
  1190. urlpath = urldata.path.rstrip('/')
  1191. # Want files places relative to cwd so no leading '/'
  1192. urlpath = urlpath.lstrip('/')
  1193. if urlpath.find("/") != -1:
  1194. destdir = urlpath.rsplit("/", 1)[0] + '/'
  1195. bb.utils.mkdirhier("%s/%s" % (unpackdir, destdir))
  1196. cmd = 'cp -fpPR %s %s' % (file, destdir)
  1197. if not cmd:
  1198. return
  1199. # Change to unpackdir before executing command
  1200. save_cwd = os.getcwd();
  1201. os.chdir(unpackdir)
  1202. path = data.getVar('PATH', True)
  1203. if path:
  1204. cmd = "PATH=\"%s\" %s" % (path, cmd)
  1205. bb.note("Unpacking %s to %s/" % (file, os.getcwd()))
  1206. ret = subprocess.call(cmd, preexec_fn=subprocess_setup, shell=True)
  1207. os.chdir(save_cwd)
  1208. if ret != 0:
  1209. raise UnpackError("Unpack command %s failed with return value %s" % (cmd, ret), urldata.url)
  1210. if iterate is True:
  1211. iterate_urldata = urldata
  1212. iterate_urldata.localpath = "%s/%s" % (rootdir, iterate_file)
  1213. self.unpack(urldata, rootdir, data)
  1214. return
  1215. def clean(self, urldata, d):
  1216. """
  1217. Clean any existing full or partial download
  1218. """
  1219. bb.utils.remove(urldata.localpath)
  1220. def try_premirror(self, urldata, d):
  1221. """
  1222. Should premirrors be used?
  1223. """
  1224. return True
  1225. def checkstatus(self, fetch, urldata, d):
  1226. """
  1227. Check the status of a URL
  1228. Assumes localpath was called first
  1229. """
  1230. logger.info("URL %s could not be checked for status since no method exists.", url)
  1231. return True
  1232. def latest_revision(self, ud, d, name):
  1233. """
  1234. Look in the cache for the latest revision, if not present ask the SCM.
  1235. """
  1236. if not hasattr(self, "_latest_revision"):
  1237. raise ParameterError("The fetcher for this URL does not support _latest_revision", url)
  1238. revs = bb.persist_data.persist('BB_URI_HEADREVS', d)
  1239. key = self.generate_revision_key(ud, d, name)
  1240. try:
  1241. return revs[key]
  1242. except KeyError:
  1243. revs[key] = rev = self._latest_revision(ud, d, name)
  1244. return rev
  1245. def sortable_revision(self, ud, d, name):
  1246. latest_rev = self._build_revision(ud, d, name)
  1247. return True, str(latest_rev)
  1248. def generate_revision_key(self, ud, d, name):
  1249. key = self._revision_key(ud, d, name)
  1250. return "%s-%s" % (key, d.getVar("PN", True) or "")
  1251. class Fetch(object):
  1252. def __init__(self, urls, d, cache = True, localonly = False, connection_cache = None):
  1253. if localonly and cache:
  1254. raise Exception("bb.fetch2.Fetch.__init__: cannot set cache and localonly at same time")
  1255. if len(urls) == 0:
  1256. urls = d.getVar("SRC_URI", True).split()
  1257. self.urls = urls
  1258. self.d = d
  1259. self.ud = {}
  1260. self.connection_cache = connection_cache
  1261. fn = d.getVar('FILE', True)
  1262. if cache and fn and fn in urldata_cache:
  1263. self.ud = urldata_cache[fn]
  1264. for url in urls:
  1265. if url not in self.ud:
  1266. try:
  1267. self.ud[url] = FetchData(url, d, localonly)
  1268. except NonLocalMethod:
  1269. if localonly:
  1270. self.ud[url] = None
  1271. pass
  1272. if fn and cache:
  1273. urldata_cache[fn] = self.ud
  1274. def localpath(self, url):
  1275. if url not in self.urls:
  1276. self.ud[url] = FetchData(url, self.d)
  1277. self.ud[url].setup_localpath(self.d)
  1278. return self.d.expand(self.ud[url].localpath)
  1279. def localpaths(self):
  1280. """
  1281. Return a list of the local filenames, assuming successful fetch
  1282. """
  1283. local = []
  1284. for u in self.urls:
  1285. ud = self.ud[u]
  1286. ud.setup_localpath(self.d)
  1287. local.append(ud.localpath)
  1288. return local
  1289. def download(self, urls=None):
  1290. """
  1291. Fetch all urls
  1292. """
  1293. if not urls:
  1294. urls = self.urls
  1295. network = self.d.getVar("BB_NO_NETWORK", True)
  1296. premirroronly = (self.d.getVar("BB_FETCH_PREMIRRORONLY", True) == "1")
  1297. for u in urls:
  1298. ud = self.ud[u]
  1299. ud.setup_localpath(self.d)
  1300. m = ud.method
  1301. localpath = ""
  1302. if ud.lockfile:
  1303. lf = bb.utils.lockfile(ud.lockfile)
  1304. try:
  1305. self.d.setVar("BB_NO_NETWORK", network)
  1306. if verify_donestamp(ud, self.d) and not m.need_update(ud, self.d):
  1307. localpath = ud.localpath
  1308. elif m.try_premirror(ud, self.d):
  1309. logger.debug(1, "Trying PREMIRRORS")
  1310. mirrors = mirror_from_string(self.d.getVar('PREMIRRORS', True))
  1311. localpath = try_mirrors(self, self.d, ud, mirrors, False)
  1312. if premirroronly:
  1313. self.d.setVar("BB_NO_NETWORK", "1")
  1314. os.chdir(self.d.getVar("DL_DIR", True))
  1315. firsterr = None
  1316. verified_stamp = verify_donestamp(ud, self.d)
  1317. if not localpath and (not verified_stamp or m.need_update(ud, self.d)):
  1318. try:
  1319. if not trusted_network(self.d, ud.url):
  1320. raise UntrustedUrl(ud.url)
  1321. logger.debug(1, "Trying Upstream")
  1322. m.download(ud, self.d)
  1323. if hasattr(m, "build_mirror_data"):
  1324. m.build_mirror_data(ud, self.d)
  1325. localpath = ud.localpath
  1326. # early checksum verify, so that if checksum mismatched,
  1327. # fetcher still have chance to fetch from mirror
  1328. update_stamp(ud, self.d)
  1329. except bb.fetch2.NetworkAccess:
  1330. raise
  1331. except BBFetchException as e:
  1332. if isinstance(e, ChecksumError):
  1333. logger.warning("Checksum failure encountered with download of %s - will attempt other sources if available" % u)
  1334. logger.debug(1, str(e))
  1335. if os.path.exists(ud.localpath):
  1336. rename_bad_checksum(ud, e.checksum)
  1337. elif isinstance(e, NoChecksumError):
  1338. raise
  1339. else:
  1340. logger.warning('Failed to fetch URL %s, attempting MIRRORS if available' % u)
  1341. logger.debug(1, str(e))
  1342. firsterr = e
  1343. # Remove any incomplete fetch
  1344. if not verified_stamp:
  1345. m.clean(ud, self.d)
  1346. logger.debug(1, "Trying MIRRORS")
  1347. mirrors = mirror_from_string(self.d.getVar('MIRRORS', True))
  1348. localpath = try_mirrors(self, self.d, ud, mirrors)
  1349. if not localpath or ((not os.path.exists(localpath)) and localpath.find("*") == -1):
  1350. if firsterr:
  1351. logger.error(str(firsterr))
  1352. raise FetchError("Unable to fetch URL from any source.", u)
  1353. update_stamp(ud, self.d)
  1354. except BBFetchException as e:
  1355. if isinstance(e, ChecksumError):
  1356. logger.error("Checksum failure fetching %s" % u)
  1357. raise
  1358. finally:
  1359. if ud.lockfile:
  1360. bb.utils.unlockfile(lf)
  1361. def checkstatus(self, urls=None):
  1362. """
  1363. Check all urls exist upstream
  1364. """
  1365. if not urls:
  1366. urls = self.urls
  1367. for u in urls:
  1368. ud = self.ud[u]
  1369. ud.setup_localpath(self.d)
  1370. m = ud.method
  1371. logger.debug(1, "Testing URL %s", u)
  1372. # First try checking uri, u, from PREMIRRORS
  1373. mirrors = mirror_from_string(self.d.getVar('PREMIRRORS', True))
  1374. ret = try_mirrors(self, self.d, ud, mirrors, True)
  1375. if not ret:
  1376. # Next try checking from the original uri, u
  1377. try:
  1378. ret = m.checkstatus(self, ud, self.d)
  1379. except:
  1380. # Finally, try checking uri, u, from MIRRORS
  1381. mirrors = mirror_from_string(self.d.getVar('MIRRORS', True))
  1382. ret = try_mirrors(self, self.d, ud, mirrors, True)
  1383. if not ret:
  1384. raise FetchError("URL %s doesn't work" % u, u)
  1385. def unpack(self, root, urls=None):
  1386. """
  1387. Check all urls exist upstream
  1388. """
  1389. if not urls:
  1390. urls = self.urls
  1391. for u in urls:
  1392. ud = self.ud[u]
  1393. ud.setup_localpath(self.d)
  1394. if ud.lockfile:
  1395. lf = bb.utils.lockfile(ud.lockfile)
  1396. ud.method.unpack(ud, root, self.d)
  1397. if ud.lockfile:
  1398. bb.utils.unlockfile(lf)
  1399. def clean(self, urls=None):
  1400. """
  1401. Clean files that the fetcher gets or places
  1402. """
  1403. if not urls:
  1404. urls = self.urls
  1405. for url in urls:
  1406. if url not in self.ud:
  1407. self.ud[url] = FetchData(url, d)
  1408. ud = self.ud[url]
  1409. ud.setup_localpath(self.d)
  1410. if not ud.localfile and ud.localpath is None:
  1411. continue
  1412. if ud.lockfile:
  1413. lf = bb.utils.lockfile(ud.lockfile)
  1414. ud.method.clean(ud, self.d)
  1415. if ud.donestamp:
  1416. bb.utils.remove(ud.donestamp)
  1417. if ud.lockfile:
  1418. bb.utils.unlockfile(lf)
  1419. class FetchConnectionCache(object):
  1420. """
  1421. A class which represents an container for socket connections.
  1422. """
  1423. def __init__(self):
  1424. self.cache = {}
  1425. def get_connection_name(self, host, port):
  1426. return host + ':' + str(port)
  1427. def add_connection(self, host, port, connection):
  1428. cn = self.get_connection_name(host, port)
  1429. if cn not in self.cache:
  1430. self.cache[cn] = connection
  1431. def get_connection(self, host, port):
  1432. connection = None
  1433. cn = self.get_connection_name(host, port)
  1434. if cn in self.cache:
  1435. connection = self.cache[cn]
  1436. return connection
  1437. def remove_connection(self, host, port):
  1438. cn = self.get_connection_name(host, port)
  1439. if cn in self.cache:
  1440. self.cache[cn].close()
  1441. del self.cache[cn]
  1442. def close_connections(self):
  1443. for cn in self.cache.keys():
  1444. self.cache[cn].close()
  1445. del self.cache[cn]
  1446. from . import cvs
  1447. from . import git
  1448. from . import gitsm
  1449. from . import gitannex
  1450. from . import local
  1451. from . import svn
  1452. from . import wget
  1453. from . import ssh
  1454. from . import sftp
  1455. from . import perforce
  1456. from . import bzr
  1457. from . import hg
  1458. from . import osc
  1459. from . import repo
  1460. from . import clearcase
  1461. from . import npm
  1462. methods.append(local.Local())
  1463. methods.append(wget.Wget())
  1464. methods.append(svn.Svn())
  1465. methods.append(git.Git())
  1466. methods.append(gitsm.GitSM())
  1467. methods.append(gitannex.GitANNEX())
  1468. methods.append(cvs.Cvs())
  1469. methods.append(ssh.SSH())
  1470. methods.append(sftp.SFTP())
  1471. methods.append(perforce.Perforce())
  1472. methods.append(bzr.Bzr())
  1473. methods.append(hg.Hg())
  1474. methods.append(osc.Osc())
  1475. methods.append(repo.Repo())
  1476. methods.append(clearcase.ClearCase())
  1477. methods.append(npm.Npm())