utils.py 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886
  1. """
  2. BitBake Utility Functions
  3. """
  4. # Copyright (C) 2004 Michael Lauer
  5. #
  6. # SPDX-License-Identifier: GPL-2.0-only
  7. #
  8. import re, fcntl, os, string, stat, shutil, time
  9. import sys
  10. import errno
  11. import logging
  12. import bb
  13. import bb.msg
  14. import locale
  15. import multiprocessing
  16. import fcntl
  17. import importlib
  18. import importlib.machinery
  19. import importlib.util
  20. import itertools
  21. import subprocess
  22. import glob
  23. import fnmatch
  24. import traceback
  25. import errno
  26. import signal
  27. import collections
  28. import copy
  29. import ctypes
  30. import random
  31. import socket
  32. import struct
  33. import tempfile
  34. from subprocess import getstatusoutput
  35. from contextlib import contextmanager
  36. from ctypes import cdll
  37. logger = logging.getLogger("BitBake.Util")
  38. python_extensions = importlib.machinery.all_suffixes()
  39. def clean_context():
  40. return {
  41. "os": os,
  42. "bb": bb,
  43. "time": time,
  44. }
  45. def get_context():
  46. return _context
  47. def set_context(ctx):
  48. _context = ctx
  49. # Context used in better_exec, eval
  50. _context = clean_context()
  51. class VersionStringException(Exception):
  52. """Exception raised when an invalid version specification is found"""
  53. def explode_version(s):
  54. r = []
  55. alpha_regexp = re.compile(r'^([a-zA-Z]+)(.*)$')
  56. numeric_regexp = re.compile(r'^(\d+)(.*)$')
  57. while (s != ''):
  58. if s[0] in string.digits:
  59. m = numeric_regexp.match(s)
  60. r.append((0, int(m.group(1))))
  61. s = m.group(2)
  62. continue
  63. if s[0] in string.ascii_letters:
  64. m = alpha_regexp.match(s)
  65. r.append((1, m.group(1)))
  66. s = m.group(2)
  67. continue
  68. if s[0] == '~':
  69. r.append((-1, s[0]))
  70. else:
  71. r.append((2, s[0]))
  72. s = s[1:]
  73. return r
  74. def split_version(s):
  75. """Split a version string into its constituent parts (PE, PV, PR)"""
  76. s = s.strip(" <>=")
  77. e = 0
  78. if s.count(':'):
  79. e = int(s.split(":")[0])
  80. s = s.split(":")[1]
  81. r = ""
  82. if s.count('-'):
  83. r = s.rsplit("-", 1)[1]
  84. s = s.rsplit("-", 1)[0]
  85. v = s
  86. return (e, v, r)
  87. def vercmp_part(a, b):
  88. va = explode_version(a)
  89. vb = explode_version(b)
  90. while True:
  91. if va == []:
  92. (oa, ca) = (0, None)
  93. else:
  94. (oa, ca) = va.pop(0)
  95. if vb == []:
  96. (ob, cb) = (0, None)
  97. else:
  98. (ob, cb) = vb.pop(0)
  99. if (oa, ca) == (0, None) and (ob, cb) == (0, None):
  100. return 0
  101. if oa < ob:
  102. return -1
  103. elif oa > ob:
  104. return 1
  105. elif ca is None:
  106. return -1
  107. elif cb is None:
  108. return 1
  109. elif ca < cb:
  110. return -1
  111. elif ca > cb:
  112. return 1
  113. def vercmp(ta, tb):
  114. (ea, va, ra) = ta
  115. (eb, vb, rb) = tb
  116. r = int(ea or 0) - int(eb or 0)
  117. if (r == 0):
  118. r = vercmp_part(va, vb)
  119. if (r == 0):
  120. r = vercmp_part(ra, rb)
  121. return r
  122. def vercmp_string(a, b):
  123. """ Split version strings and compare them """
  124. ta = split_version(a)
  125. tb = split_version(b)
  126. return vercmp(ta, tb)
  127. def vercmp_string_op(a, b, op):
  128. """
  129. Compare two versions and check if the specified comparison operator matches the result of the comparison.
  130. This function is fairly liberal about what operators it will accept since there are a variety of styles
  131. depending on the context.
  132. """
  133. res = vercmp_string(a, b)
  134. if op in ('=', '=='):
  135. return res == 0
  136. elif op == '<=':
  137. return res <= 0
  138. elif op == '>=':
  139. return res >= 0
  140. elif op in ('>', '>>'):
  141. return res > 0
  142. elif op in ('<', '<<'):
  143. return res < 0
  144. elif op == '!=':
  145. return res != 0
  146. else:
  147. raise VersionStringException('Unsupported comparison operator "%s"' % op)
  148. def explode_deps(s):
  149. """
  150. Take an RDEPENDS style string of format:
  151. "DEPEND1 (optional version) DEPEND2 (optional version) ..."
  152. and return a list of dependencies.
  153. Version information is ignored.
  154. """
  155. r = []
  156. l = s.split()
  157. flag = False
  158. for i in l:
  159. if i[0] == '(':
  160. flag = True
  161. #j = []
  162. if not flag:
  163. r.append(i)
  164. #else:
  165. # j.append(i)
  166. if flag and i.endswith(')'):
  167. flag = False
  168. # Ignore version
  169. #r[-1] += ' ' + ' '.join(j)
  170. return r
  171. def explode_dep_versions2(s, *, sort=True):
  172. """
  173. Take an RDEPENDS style string of format:
  174. "DEPEND1 (optional version) DEPEND2 (optional version) ..."
  175. and return a dictionary of dependencies and versions.
  176. """
  177. r = collections.OrderedDict()
  178. l = s.replace(",", "").split()
  179. lastdep = None
  180. lastcmp = ""
  181. lastver = ""
  182. incmp = False
  183. inversion = False
  184. for i in l:
  185. if i[0] == '(':
  186. incmp = True
  187. i = i[1:].strip()
  188. if not i:
  189. continue
  190. if incmp:
  191. incmp = False
  192. inversion = True
  193. # This list is based on behavior and supported comparisons from deb, opkg and rpm.
  194. #
  195. # Even though =<, <<, ==, !=, =>, and >> may not be supported,
  196. # we list each possibly valid item.
  197. # The build system is responsible for validation of what it supports.
  198. if i.startswith(('<=', '=<', '<<', '==', '!=', '>=', '=>', '>>')):
  199. lastcmp = i[0:2]
  200. i = i[2:]
  201. elif i.startswith(('<', '>', '=')):
  202. lastcmp = i[0:1]
  203. i = i[1:]
  204. else:
  205. # This is an unsupported case!
  206. raise VersionStringException('Invalid version specification in "(%s" - invalid or missing operator' % i)
  207. lastcmp = (i or "")
  208. i = ""
  209. i.strip()
  210. if not i:
  211. continue
  212. if inversion:
  213. if i.endswith(')'):
  214. i = i[:-1] or ""
  215. inversion = False
  216. if lastver and i:
  217. lastver += " "
  218. if i:
  219. lastver += i
  220. if lastdep not in r:
  221. r[lastdep] = []
  222. r[lastdep].append(lastcmp + " " + lastver)
  223. continue
  224. #if not inversion:
  225. lastdep = i
  226. lastver = ""
  227. lastcmp = ""
  228. if not (i in r and r[i]):
  229. r[lastdep] = []
  230. if sort:
  231. r = collections.OrderedDict(sorted(r.items(), key=lambda x: x[0]))
  232. return r
  233. def explode_dep_versions(s):
  234. """
  235. Take an RDEPENDS style string of format:
  236. "DEPEND1 (optional version) DEPEND2 (optional version) ..."
  237. skip null value and items appeared in dependency string multiple times
  238. and return a dictionary of dependencies and versions.
  239. """
  240. r = explode_dep_versions2(s)
  241. for d in r:
  242. if not r[d]:
  243. r[d] = None
  244. continue
  245. if len(r[d]) > 1:
  246. bb.warn("explode_dep_versions(): Item %s appeared in dependency string '%s' multiple times with different values. explode_dep_versions cannot cope with this." % (d, s))
  247. r[d] = r[d][0]
  248. return r
  249. def join_deps(deps, commasep=True):
  250. """
  251. Take the result from explode_dep_versions and generate a dependency string
  252. """
  253. result = []
  254. for dep in deps:
  255. if deps[dep]:
  256. if isinstance(deps[dep], list):
  257. for v in deps[dep]:
  258. result.append(dep + " (" + v + ")")
  259. else:
  260. result.append(dep + " (" + deps[dep] + ")")
  261. else:
  262. result.append(dep)
  263. if commasep:
  264. return ", ".join(result)
  265. else:
  266. return " ".join(result)
  267. def _print_trace(body, line):
  268. """
  269. Print the Environment of a Text Body
  270. """
  271. error = []
  272. # print the environment of the method
  273. min_line = max(1, line-4)
  274. max_line = min(line + 4, len(body))
  275. for i in range(min_line, max_line + 1):
  276. if line == i:
  277. error.append(' *** %.4d:%s' % (i, body[i-1].rstrip()))
  278. else:
  279. error.append(' %.4d:%s' % (i, body[i-1].rstrip()))
  280. return error
  281. def better_compile(text, file, realfile, mode = "exec", lineno = 0):
  282. """
  283. A better compile method. This method
  284. will print the offending lines.
  285. """
  286. try:
  287. cache = bb.methodpool.compile_cache(text)
  288. if cache:
  289. return cache
  290. # We can't add to the linenumbers for compile, we can pad to the correct number of blank lines though
  291. text2 = "\n" * int(lineno) + text
  292. code = compile(text2, realfile, mode)
  293. bb.methodpool.compile_cache_add(text, code)
  294. return code
  295. except Exception as e:
  296. error = []
  297. # split the text into lines again
  298. body = text.split('\n')
  299. error.append("Error in compiling python function in %s, line %s:\n" % (realfile, e.lineno))
  300. if hasattr(e, "lineno"):
  301. error.append("The code lines resulting in this error were:")
  302. # e.lineno: line's position in reaflile
  303. # lineno: function name's "position -1" in realfile
  304. # e.lineno - lineno: line's relative position in function
  305. error.extend(_print_trace(body, e.lineno - lineno))
  306. else:
  307. error.append("The function causing this error was:")
  308. for line in body:
  309. error.append(line)
  310. error.append("%s: %s" % (e.__class__.__name__, str(e)))
  311. logger.error("\n".join(error))
  312. e = bb.BBHandledException(e)
  313. raise e
  314. def _print_exception(t, value, tb, realfile, text, context):
  315. error = []
  316. try:
  317. exception = traceback.format_exception_only(t, value)
  318. error.append('Error executing a python function in %s:\n' % realfile)
  319. # Strip 'us' from the stack (better_exec call) unless that was where the
  320. # error came from
  321. if tb.tb_next is not None:
  322. tb = tb.tb_next
  323. textarray = text.split('\n')
  324. linefailed = tb.tb_lineno
  325. tbextract = traceback.extract_tb(tb)
  326. tbformat = traceback.format_list(tbextract)
  327. error.append("The stack trace of python calls that resulted in this exception/failure was:")
  328. error.append("File: '%s', lineno: %s, function: %s" % (tbextract[0][0], tbextract[0][1], tbextract[0][2]))
  329. error.extend(_print_trace(textarray, linefailed))
  330. # See if this is a function we constructed and has calls back into other functions in
  331. # "text". If so, try and improve the context of the error by diving down the trace
  332. level = 0
  333. nexttb = tb.tb_next
  334. while nexttb is not None and (level+1) < len(tbextract):
  335. error.append("File: '%s', lineno: %s, function: %s" % (tbextract[level+1][0], tbextract[level+1][1], tbextract[level+1][2]))
  336. if tbextract[level][0] == tbextract[level+1][0] and tbextract[level+1][2] == tbextract[level][0]:
  337. # The code was possibly in the string we compiled ourselves
  338. error.extend(_print_trace(textarray, tbextract[level+1][1]))
  339. elif tbextract[level+1][0].startswith("/"):
  340. # The code looks like it might be in a file, try and load it
  341. try:
  342. with open(tbextract[level+1][0], "r") as f:
  343. text = f.readlines()
  344. error.extend(_print_trace(text, tbextract[level+1][1]))
  345. except:
  346. error.append(tbformat[level+1])
  347. else:
  348. error.append(tbformat[level+1])
  349. nexttb = tb.tb_next
  350. level = level + 1
  351. error.append("Exception: %s" % ''.join(exception))
  352. # If the exception is from spawning a task, let's be helpful and display
  353. # the output (which hopefully includes stderr).
  354. if isinstance(value, subprocess.CalledProcessError) and value.output:
  355. error.append("Subprocess output:")
  356. error.append(value.output.decode("utf-8", errors="ignore"))
  357. finally:
  358. logger.error("\n".join(error))
  359. def better_exec(code, context, text = None, realfile = "<code>", pythonexception=False):
  360. """
  361. Similiar to better_compile, better_exec will
  362. print the lines that are responsible for the
  363. error.
  364. """
  365. import bb.parse
  366. if not text:
  367. text = code
  368. if not hasattr(code, "co_filename"):
  369. code = better_compile(code, realfile, realfile)
  370. try:
  371. exec(code, get_context(), context)
  372. except (bb.BBHandledException, bb.parse.SkipRecipe, bb.data_smart.ExpansionError, bb.process.ExecutionError):
  373. # Error already shown so passthrough, no need for traceback
  374. raise
  375. except Exception as e:
  376. if pythonexception:
  377. raise
  378. (t, value, tb) = sys.exc_info()
  379. try:
  380. _print_exception(t, value, tb, realfile, text, context)
  381. except Exception as e2:
  382. logger.error("Exception handler error: %s" % str(e2))
  383. e = bb.BBHandledException(e)
  384. raise e
  385. def simple_exec(code, context):
  386. exec(code, get_context(), context)
  387. def better_eval(source, locals, extraglobals = None):
  388. ctx = get_context()
  389. if extraglobals:
  390. ctx = copy.copy(ctx)
  391. for g in extraglobals:
  392. ctx[g] = extraglobals[g]
  393. return eval(source, ctx, locals)
  394. @contextmanager
  395. def fileslocked(files, *args, **kwargs):
  396. """Context manager for locking and unlocking file locks."""
  397. locks = []
  398. if files:
  399. for lockfile in files:
  400. l = bb.utils.lockfile(lockfile, *args, **kwargs)
  401. if l is not None:
  402. locks.append(l)
  403. try:
  404. yield
  405. finally:
  406. for lock in locks:
  407. bb.utils.unlockfile(lock)
  408. def lockfile(name, shared=False, retry=True, block=False):
  409. """
  410. Use the specified file as a lock file, return when the lock has
  411. been acquired. Returns a variable to pass to unlockfile().
  412. Parameters:
  413. retry: True to re-try locking if it fails, False otherwise
  414. block: True to block until the lock succeeds, False otherwise
  415. The retry and block parameters are kind of equivalent unless you
  416. consider the possibility of sending a signal to the process to break
  417. out - at which point you want block=True rather than retry=True.
  418. """
  419. basename = os.path.basename(name)
  420. if len(basename) > 255:
  421. root, ext = os.path.splitext(basename)
  422. basename = root[:255 - len(ext)] + ext
  423. dirname = os.path.dirname(name)
  424. mkdirhier(dirname)
  425. name = os.path.join(dirname, basename)
  426. if not os.access(dirname, os.W_OK):
  427. logger.error("Unable to acquire lock '%s', directory is not writable",
  428. name)
  429. sys.exit(1)
  430. op = fcntl.LOCK_EX
  431. if shared:
  432. op = fcntl.LOCK_SH
  433. if not retry and not block:
  434. op = op | fcntl.LOCK_NB
  435. while True:
  436. # If we leave the lockfiles lying around there is no problem
  437. # but we should clean up after ourselves. This gives potential
  438. # for races though. To work around this, when we acquire the lock
  439. # we check the file we locked was still the lock file on disk.
  440. # by comparing inode numbers. If they don't match or the lockfile
  441. # no longer exists, we start again.
  442. # This implementation is unfair since the last person to request the
  443. # lock is the most likely to win it.
  444. try:
  445. lf = open(name, 'a+')
  446. fileno = lf.fileno()
  447. fcntl.flock(fileno, op)
  448. statinfo = os.fstat(fileno)
  449. if os.path.exists(lf.name):
  450. statinfo2 = os.stat(lf.name)
  451. if statinfo.st_ino == statinfo2.st_ino:
  452. return lf
  453. lf.close()
  454. except OSError as e:
  455. if e.errno == errno.EACCES or e.errno == errno.ENAMETOOLONG:
  456. logger.error("Unable to acquire lock '%s', %s",
  457. e.strerror, name)
  458. sys.exit(1)
  459. try:
  460. lf.close()
  461. except Exception:
  462. pass
  463. pass
  464. if not retry:
  465. return None
  466. def unlockfile(lf):
  467. """
  468. Unlock a file locked using lockfile()
  469. """
  470. try:
  471. # If we had a shared lock, we need to promote to exclusive before
  472. # removing the lockfile. Attempt this, ignore failures.
  473. fcntl.flock(lf.fileno(), fcntl.LOCK_EX|fcntl.LOCK_NB)
  474. os.unlink(lf.name)
  475. except (IOError, OSError):
  476. pass
  477. fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
  478. lf.close()
  479. def _hasher(method, filename):
  480. import mmap
  481. with open(filename, "rb") as f:
  482. try:
  483. with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as mm:
  484. for chunk in iter(lambda: mm.read(8192), b''):
  485. method.update(chunk)
  486. except ValueError:
  487. # You can't mmap() an empty file so silence this exception
  488. pass
  489. return method.hexdigest()
  490. def md5_file(filename):
  491. """
  492. Return the hex string representation of the MD5 checksum of filename.
  493. """
  494. import hashlib
  495. try:
  496. sig = hashlib.new('MD5', usedforsecurity=False)
  497. except TypeError:
  498. # Some configurations don't appear to support two arguments
  499. sig = hashlib.new('MD5')
  500. return _hasher(sig, filename)
  501. def sha256_file(filename):
  502. """
  503. Return the hex string representation of the 256-bit SHA checksum of
  504. filename.
  505. """
  506. import hashlib
  507. return _hasher(hashlib.sha256(), filename)
  508. def sha1_file(filename):
  509. """
  510. Return the hex string representation of the SHA1 checksum of the filename
  511. """
  512. import hashlib
  513. return _hasher(hashlib.sha1(), filename)
  514. def sha384_file(filename):
  515. """
  516. Return the hex string representation of the SHA384 checksum of the filename
  517. """
  518. import hashlib
  519. return _hasher(hashlib.sha384(), filename)
  520. def sha512_file(filename):
  521. """
  522. Return the hex string representation of the SHA512 checksum of the filename
  523. """
  524. import hashlib
  525. return _hasher(hashlib.sha512(), filename)
  526. def preserved_envvars_exported():
  527. """Variables which are taken from the environment and placed in and exported
  528. from the metadata"""
  529. return [
  530. 'BB_TASKHASH',
  531. 'HOME',
  532. 'LOGNAME',
  533. 'PATH',
  534. 'PWD',
  535. 'SHELL',
  536. 'USER',
  537. 'LC_ALL',
  538. 'BBSERVER',
  539. ]
  540. def preserved_envvars():
  541. """Variables which are taken from the environment and placed in the metadata"""
  542. v = [
  543. 'BBPATH',
  544. 'BB_PRESERVE_ENV',
  545. 'BB_ENV_PASSTHROUGH_ADDITIONS',
  546. ]
  547. return v + preserved_envvars_exported()
  548. def check_system_locale():
  549. """Make sure the required system locale are available and configured"""
  550. default_locale = locale.getlocale(locale.LC_CTYPE)
  551. try:
  552. locale.setlocale(locale.LC_CTYPE, ("en_US", "UTF-8"))
  553. except:
  554. sys.exit("Please make sure locale 'en_US.UTF-8' is available on your system")
  555. else:
  556. locale.setlocale(locale.LC_CTYPE, default_locale)
  557. if sys.getfilesystemencoding() != "utf-8":
  558. sys.exit("Please use a locale setting which supports UTF-8 (such as LANG=en_US.UTF-8).\n"
  559. "Python can't change the filesystem locale after loading so we need a UTF-8 when Python starts or things won't work.")
  560. def filter_environment(good_vars):
  561. """
  562. Create a pristine environment for bitbake. This will remove variables that
  563. are not known and may influence the build in a negative way.
  564. """
  565. removed_vars = {}
  566. for key in list(os.environ):
  567. if key in good_vars:
  568. continue
  569. removed_vars[key] = os.environ[key]
  570. del os.environ[key]
  571. # If we spawn a python process, we need to have a UTF-8 locale, else python's file
  572. # access methods will use ascii. You can't change that mode once the interpreter is
  573. # started so we have to ensure a locale is set. Ideally we'd use C.UTF-8 but not all
  574. # distros support that and we need to set something.
  575. os.environ["LC_ALL"] = "en_US.UTF-8"
  576. if removed_vars:
  577. logger.debug("Removed the following variables from the environment: %s", ", ".join(removed_vars.keys()))
  578. return removed_vars
  579. def approved_variables():
  580. """
  581. Determine and return the list of variables which are approved
  582. to remain in the environment.
  583. """
  584. if 'BB_PRESERVE_ENV' in os.environ:
  585. return os.environ.keys()
  586. approved = []
  587. if 'BB_ENV_PASSTHROUGH' in os.environ:
  588. approved = os.environ['BB_ENV_PASSTHROUGH'].split()
  589. approved.extend(['BB_ENV_PASSTHROUGH'])
  590. else:
  591. approved = preserved_envvars()
  592. if 'BB_ENV_PASSTHROUGH_ADDITIONS' in os.environ:
  593. approved.extend(os.environ['BB_ENV_PASSTHROUGH_ADDITIONS'].split())
  594. if 'BB_ENV_PASSTHROUGH_ADDITIONS' not in approved:
  595. approved.extend(['BB_ENV_PASSTHROUGH_ADDITIONS'])
  596. return approved
  597. def clean_environment():
  598. """
  599. Clean up any spurious environment variables. This will remove any
  600. variables the user hasn't chosen to preserve.
  601. """
  602. if 'BB_PRESERVE_ENV' not in os.environ:
  603. good_vars = approved_variables()
  604. return filter_environment(good_vars)
  605. return {}
  606. def empty_environment():
  607. """
  608. Remove all variables from the environment.
  609. """
  610. for s in list(os.environ.keys()):
  611. os.unsetenv(s)
  612. del os.environ[s]
  613. def build_environment(d):
  614. """
  615. Build an environment from all exported variables.
  616. """
  617. import bb.data
  618. for var in bb.data.keys(d):
  619. export = d.getVarFlag(var, "export", False)
  620. if export:
  621. os.environ[var] = d.getVar(var) or ""
  622. def _check_unsafe_delete_path(path):
  623. """
  624. Basic safeguard against recursively deleting something we shouldn't. If it returns True,
  625. the caller should raise an exception with an appropriate message.
  626. NOTE: This is NOT meant to be a security mechanism - just a guard against silly mistakes
  627. with potentially disastrous results.
  628. """
  629. extra = ''
  630. # HOME might not be /home/something, so in case we can get it, check against it
  631. homedir = os.environ.get('HOME', '')
  632. if homedir:
  633. extra = '|%s' % homedir
  634. if re.match('(/|//|/home|/home/[^/]*%s)$' % extra, os.path.abspath(path)):
  635. return True
  636. return False
  637. def remove(path, recurse=False, ionice=False):
  638. """Equivalent to rm -f or rm -rf"""
  639. if not path:
  640. return
  641. if recurse:
  642. for name in glob.glob(path):
  643. if _check_unsafe_delete_path(name):
  644. raise Exception('bb.utils.remove: called with dangerous path "%s" and recurse=True, refusing to delete!' % name)
  645. # shutil.rmtree(name) would be ideal but its too slow
  646. cmd = []
  647. if ionice:
  648. cmd = ['ionice', '-c', '3']
  649. subprocess.check_call(cmd + ['rm', '-rf'] + glob.glob(path))
  650. return
  651. for name in glob.glob(path):
  652. try:
  653. os.unlink(name)
  654. except OSError as exc:
  655. if exc.errno != errno.ENOENT:
  656. raise
  657. def prunedir(topdir, ionice=False):
  658. """ Delete everything reachable from the directory named in 'topdir'. """
  659. # CAUTION: This is dangerous!
  660. if _check_unsafe_delete_path(topdir):
  661. raise Exception('bb.utils.prunedir: called with dangerous path "%s", refusing to delete!' % topdir)
  662. remove(topdir, recurse=True, ionice=ionice)
  663. #
  664. # Could also use return re.compile("(%s)" % "|".join(map(re.escape, suffixes))).sub(lambda mo: "", var)
  665. # but thats possibly insane and suffixes is probably going to be small
  666. #
  667. def prune_suffix(var, suffixes, d):
  668. """
  669. See if var ends with any of the suffixes listed and
  670. remove it if found
  671. """
  672. for suffix in suffixes:
  673. if suffix and var.endswith(suffix):
  674. return var[:-len(suffix)]
  675. return var
  676. def mkdirhier(directory):
  677. """Create a directory like 'mkdir -p', but does not complain if
  678. directory already exists like os.makedirs
  679. """
  680. if '${' in str(directory):
  681. bb.fatal("Directory name {} contains unexpanded bitbake variable. This may cause build failures and WORKDIR polution.".format(directory))
  682. try:
  683. os.makedirs(directory)
  684. except OSError as e:
  685. if e.errno != errno.EEXIST or not os.path.isdir(directory):
  686. raise e
  687. def movefile(src, dest, newmtime = None, sstat = None):
  688. """Moves a file from src to dest, preserving all permissions and
  689. attributes; mtime will be preserved even when moving across
  690. filesystems. Returns true on success and false on failure. Move is
  691. atomic.
  692. """
  693. #print "movefile(" + src + "," + dest + "," + str(newmtime) + "," + str(sstat) + ")"
  694. try:
  695. if not sstat:
  696. sstat = os.lstat(src)
  697. except Exception as e:
  698. logger.warning("movefile: Stating source file failed...", e)
  699. return None
  700. destexists = 1
  701. try:
  702. dstat = os.lstat(dest)
  703. except:
  704. dstat = os.lstat(os.path.dirname(dest))
  705. destexists = 0
  706. if destexists:
  707. if stat.S_ISLNK(dstat[stat.ST_MODE]):
  708. try:
  709. os.unlink(dest)
  710. destexists = 0
  711. except Exception as e:
  712. pass
  713. if stat.S_ISLNK(sstat[stat.ST_MODE]):
  714. try:
  715. target = os.readlink(src)
  716. if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
  717. os.unlink(dest)
  718. os.symlink(target, dest)
  719. #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
  720. os.unlink(src)
  721. return os.lstat(dest)
  722. except Exception as e:
  723. logger.warning("movefile: failed to properly create symlink:", dest, "->", target, e)
  724. return None
  725. renamefailed = 1
  726. # os.rename needs to know the dest path ending with file name
  727. # so append the file name to a path only if it's a dir specified
  728. srcfname = os.path.basename(src)
  729. destpath = os.path.join(dest, srcfname) if os.path.isdir(dest) \
  730. else dest
  731. if sstat[stat.ST_DEV] == dstat[stat.ST_DEV]:
  732. try:
  733. bb.utils.rename(src, destpath)
  734. renamefailed = 0
  735. except Exception as e:
  736. if e.errno != errno.EXDEV:
  737. # Some random error.
  738. logger.warning("movefile: Failed to move", src, "to", dest, e)
  739. return None
  740. # Invalid cross-device-link 'bind' mounted or actually Cross-Device
  741. if renamefailed:
  742. didcopy = 0
  743. if stat.S_ISREG(sstat[stat.ST_MODE]):
  744. try: # For safety copy then move it over.
  745. shutil.copyfile(src, destpath + "#new")
  746. bb.utils.rename(destpath + "#new", destpath)
  747. didcopy = 1
  748. except Exception as e:
  749. logger.warning('movefile: copy', src, '->', dest, 'failed.', e)
  750. return None
  751. else:
  752. #we don't yet handle special, so we need to fall back to /bin/mv
  753. a = getstatusoutput("/bin/mv -f " + "'" + src + "' '" + dest + "'")
  754. if a[0] != 0:
  755. logger.warning("movefile: Failed to move special file:" + src + "' to '" + dest + "'", a)
  756. return None # failure
  757. try:
  758. if didcopy:
  759. os.lchown(destpath, sstat[stat.ST_UID], sstat[stat.ST_GID])
  760. os.chmod(destpath, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
  761. os.unlink(src)
  762. except Exception as e:
  763. logger.warning("movefile: Failed to chown/chmod/unlink", dest, e)
  764. return None
  765. if newmtime:
  766. os.utime(destpath, (newmtime, newmtime))
  767. else:
  768. os.utime(destpath, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
  769. newmtime = sstat[stat.ST_MTIME]
  770. return newmtime
  771. def copyfile(src, dest, newmtime = None, sstat = None):
  772. """
  773. Copies a file from src to dest, preserving all permissions and
  774. attributes; mtime will be preserved even when moving across
  775. filesystems. Returns true on success and false on failure.
  776. """
  777. #print "copyfile(" + src + "," + dest + "," + str(newmtime) + "," + str(sstat) + ")"
  778. try:
  779. if not sstat:
  780. sstat = os.lstat(src)
  781. except Exception as e:
  782. logger.warning("copyfile: stat of %s failed (%s)" % (src, e))
  783. return False
  784. destexists = 1
  785. try:
  786. dstat = os.lstat(dest)
  787. except:
  788. dstat = os.lstat(os.path.dirname(dest))
  789. destexists = 0
  790. if destexists:
  791. if stat.S_ISLNK(dstat[stat.ST_MODE]):
  792. try:
  793. os.unlink(dest)
  794. destexists = 0
  795. except Exception as e:
  796. pass
  797. if stat.S_ISLNK(sstat[stat.ST_MODE]):
  798. try:
  799. target = os.readlink(src)
  800. if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
  801. os.unlink(dest)
  802. os.symlink(target, dest)
  803. os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
  804. return os.lstat(dest)
  805. except Exception as e:
  806. logger.warning("copyfile: failed to create symlink %s to %s (%s)" % (dest, target, e))
  807. return False
  808. if stat.S_ISREG(sstat[stat.ST_MODE]):
  809. try:
  810. srcchown = False
  811. if not os.access(src, os.R_OK):
  812. # Make sure we can read it
  813. srcchown = True
  814. os.chmod(src, sstat[stat.ST_MODE] | stat.S_IRUSR)
  815. # For safety copy then move it over.
  816. shutil.copyfile(src, dest + "#new")
  817. bb.utils.rename(dest + "#new", dest)
  818. except Exception as e:
  819. logger.warning("copyfile: copy %s to %s failed (%s)" % (src, dest, e))
  820. return False
  821. finally:
  822. if srcchown:
  823. os.chmod(src, sstat[stat.ST_MODE])
  824. os.utime(src, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
  825. else:
  826. #we don't yet handle special, so we need to fall back to /bin/mv
  827. a = getstatusoutput("/bin/cp -f " + "'" + src + "' '" + dest + "'")
  828. if a[0] != 0:
  829. logger.warning("copyfile: failed to copy special file %s to %s (%s)" % (src, dest, a))
  830. return False # failure
  831. try:
  832. os.lchown(dest, sstat[stat.ST_UID], sstat[stat.ST_GID])
  833. os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
  834. except Exception as e:
  835. logger.warning("copyfile: failed to chown/chmod %s (%s)" % (dest, e))
  836. return False
  837. if newmtime:
  838. os.utime(dest, (newmtime, newmtime))
  839. else:
  840. os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
  841. newmtime = sstat[stat.ST_MTIME]
  842. return newmtime
  843. def break_hardlinks(src, sstat = None):
  844. """
  845. Ensures src is the only hardlink to this file. Other hardlinks,
  846. if any, are not affected (other than in their st_nlink value, of
  847. course). Returns true on success and false on failure.
  848. """
  849. try:
  850. if not sstat:
  851. sstat = os.lstat(src)
  852. except Exception as e:
  853. logger.warning("break_hardlinks: stat of %s failed (%s)" % (src, e))
  854. return False
  855. if sstat[stat.ST_NLINK] == 1:
  856. return True
  857. return copyfile(src, src, sstat=sstat)
  858. def which(path, item, direction = 0, history = False, executable=False):
  859. """
  860. Locate `item` in the list of paths `path` (colon separated string like $PATH).
  861. If `direction` is non-zero then the list is reversed.
  862. If `history` is True then the list of candidates also returned as result,history.
  863. If `executable` is True then the candidate has to be an executable file,
  864. otherwise the candidate simply has to exist.
  865. """
  866. if executable:
  867. is_candidate = lambda p: os.path.isfile(p) and os.access(p, os.X_OK)
  868. else:
  869. is_candidate = lambda p: os.path.exists(p)
  870. hist = []
  871. paths = (path or "").split(':')
  872. if direction != 0:
  873. paths.reverse()
  874. for p in paths:
  875. next = os.path.join(p, item)
  876. hist.append(next)
  877. if is_candidate(next):
  878. if not os.path.isabs(next):
  879. next = os.path.abspath(next)
  880. if history:
  881. return next, hist
  882. return next
  883. if history:
  884. return "", hist
  885. return ""
  886. @contextmanager
  887. def umask(new_mask):
  888. """
  889. Context manager to set the umask to a specific mask, and restore it afterwards.
  890. """
  891. current_mask = os.umask(new_mask)
  892. try:
  893. yield
  894. finally:
  895. os.umask(current_mask)
  896. def to_boolean(string, default=None):
  897. """
  898. Check input string and return boolean value True/False/None
  899. depending upon the checks
  900. """
  901. if not string:
  902. return default
  903. if isinstance(string, int):
  904. return string != 0
  905. normalized = string.lower()
  906. if normalized in ("y", "yes", "1", "true"):
  907. return True
  908. elif normalized in ("n", "no", "0", "false"):
  909. return False
  910. else:
  911. raise ValueError("Invalid value for to_boolean: %s" % string)
  912. def contains(variable, checkvalues, truevalue, falsevalue, d):
  913. """Check if a variable contains all the values specified.
  914. Arguments:
  915. variable -- the variable name. This will be fetched and expanded (using
  916. d.getVar(variable)) and then split into a set().
  917. checkvalues -- if this is a string it is split on whitespace into a set(),
  918. otherwise coerced directly into a set().
  919. truevalue -- the value to return if checkvalues is a subset of variable.
  920. falsevalue -- the value to return if variable is empty or if checkvalues is
  921. not a subset of variable.
  922. d -- the data store.
  923. """
  924. val = d.getVar(variable)
  925. if not val:
  926. return falsevalue
  927. val = set(val.split())
  928. if isinstance(checkvalues, str):
  929. checkvalues = set(checkvalues.split())
  930. else:
  931. checkvalues = set(checkvalues)
  932. if checkvalues.issubset(val):
  933. return truevalue
  934. return falsevalue
  935. def contains_any(variable, checkvalues, truevalue, falsevalue, d):
  936. """Check if a variable contains any values specified.
  937. Arguments:
  938. variable -- the variable name. This will be fetched and expanded (using
  939. d.getVar(variable)) and then split into a set().
  940. checkvalues -- if this is a string it is split on whitespace into a set(),
  941. otherwise coerced directly into a set().
  942. truevalue -- the value to return if checkvalues is a subset of variable.
  943. falsevalue -- the value to return if variable is empty or if checkvalues is
  944. not a subset of variable.
  945. d -- the data store.
  946. """
  947. val = d.getVar(variable)
  948. if not val:
  949. return falsevalue
  950. val = set(val.split())
  951. if isinstance(checkvalues, str):
  952. checkvalues = set(checkvalues.split())
  953. else:
  954. checkvalues = set(checkvalues)
  955. if checkvalues & val:
  956. return truevalue
  957. return falsevalue
  958. def filter(variable, checkvalues, d):
  959. """Return all words in the variable that are present in the checkvalues.
  960. Arguments:
  961. variable -- the variable name. This will be fetched and expanded (using
  962. d.getVar(variable)) and then split into a set().
  963. checkvalues -- if this is a string it is split on whitespace into a set(),
  964. otherwise coerced directly into a set().
  965. d -- the data store.
  966. """
  967. val = d.getVar(variable)
  968. if not val:
  969. return ''
  970. val = set(val.split())
  971. if isinstance(checkvalues, str):
  972. checkvalues = set(checkvalues.split())
  973. else:
  974. checkvalues = set(checkvalues)
  975. return ' '.join(sorted(checkvalues & val))
  976. def get_referenced_vars(start_expr, d):
  977. """
  978. :return: names of vars referenced in start_expr (recursively), in quasi-BFS order (variables within the same level
  979. are ordered arbitrarily)
  980. """
  981. seen = set()
  982. ret = []
  983. # The first entry in the queue is the unexpanded start expression
  984. queue = collections.deque([start_expr])
  985. # Subsequent entries will be variable names, so we need to track whether or not entry requires getVar
  986. is_first = True
  987. empty_data = bb.data.init()
  988. while queue:
  989. entry = queue.popleft()
  990. if is_first:
  991. # Entry is the start expression - no expansion needed
  992. is_first = False
  993. expression = entry
  994. else:
  995. # This is a variable name - need to get the value
  996. expression = d.getVar(entry, False)
  997. ret.append(entry)
  998. # expandWithRefs is how we actually get the referenced variables in the expression. We call it using an empty
  999. # data store because we only want the variables directly used in the expression. It returns a set, which is what
  1000. # dooms us to only ever be "quasi-BFS" rather than full BFS.
  1001. new_vars = empty_data.expandWithRefs(expression, None).references - set(seen)
  1002. queue.extend(new_vars)
  1003. seen.update(new_vars)
  1004. return ret
  1005. def cpu_count():
  1006. try:
  1007. return len(os.sched_getaffinity(0))
  1008. except OSError:
  1009. return multiprocessing.cpu_count()
  1010. def nonblockingfd(fd):
  1011. fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
  1012. def process_profilelog(fn, pout = None):
  1013. # Either call with a list of filenames and set pout or a filename and optionally pout.
  1014. if not pout:
  1015. pout = fn + '.processed'
  1016. with open(pout, 'w') as pout:
  1017. import pstats
  1018. if isinstance(fn, list):
  1019. p = pstats.Stats(*fn, stream=pout)
  1020. else:
  1021. p = pstats.Stats(fn, stream=pout)
  1022. p.sort_stats('time')
  1023. p.print_stats()
  1024. p.print_callers()
  1025. p.sort_stats('cumulative')
  1026. p.print_stats()
  1027. pout.flush()
  1028. #
  1029. # Was present to work around multiprocessing pool bugs in python < 2.7.3
  1030. #
  1031. def multiprocessingpool(*args, **kwargs):
  1032. import multiprocessing.pool
  1033. #import multiprocessing.util
  1034. #multiprocessing.util.log_to_stderr(10)
  1035. # Deal with a multiprocessing bug where signals to the processes would be delayed until the work
  1036. # completes. Putting in a timeout means the signals (like SIGINT/SIGTERM) get processed.
  1037. def wrapper(func):
  1038. def wrap(self, timeout=None):
  1039. return func(self, timeout=timeout if timeout is not None else 1e100)
  1040. return wrap
  1041. multiprocessing.pool.IMapIterator.next = wrapper(multiprocessing.pool.IMapIterator.next)
  1042. return multiprocessing.Pool(*args, **kwargs)
  1043. def exec_flat_python_func(func, *args, **kwargs):
  1044. """Execute a flat python function (defined with def funcname(args):...)"""
  1045. # Prepare a small piece of python code which calls the requested function
  1046. # To do this we need to prepare two things - a set of variables we can use to pass
  1047. # the values of arguments into the calling function, and the list of arguments for
  1048. # the function being called
  1049. context = {}
  1050. funcargs = []
  1051. # Handle unnamed arguments
  1052. aidx = 1
  1053. for arg in args:
  1054. argname = 'arg_%s' % aidx
  1055. context[argname] = arg
  1056. funcargs.append(argname)
  1057. aidx += 1
  1058. # Handle keyword arguments
  1059. context.update(kwargs)
  1060. funcargs.extend(['%s=%s' % (arg, arg) for arg in kwargs.keys()])
  1061. code = 'retval = %s(%s)' % (func, ', '.join(funcargs))
  1062. comp = bb.utils.better_compile(code, '<string>', '<string>')
  1063. bb.utils.better_exec(comp, context, code, '<string>')
  1064. return context['retval']
  1065. def edit_metadata(meta_lines, variables, varfunc, match_overrides=False):
  1066. """Edit lines from a recipe or config file and modify one or more
  1067. specified variable values set in the file using a specified callback
  1068. function. Lines are expected to have trailing newlines.
  1069. Parameters:
  1070. meta_lines: lines from the file; can be a list or an iterable
  1071. (e.g. file pointer)
  1072. variables: a list of variable names to look for. Functions
  1073. may also be specified, but must be specified with '()' at
  1074. the end of the name. Note that the function doesn't have
  1075. any intrinsic understanding of :append, :prepend, :remove,
  1076. or overrides, so these are considered as part of the name.
  1077. These values go into a regular expression, so regular
  1078. expression syntax is allowed.
  1079. varfunc: callback function called for every variable matching
  1080. one of the entries in the variables parameter. The function
  1081. should take four arguments:
  1082. varname: name of variable matched
  1083. origvalue: current value in file
  1084. op: the operator (e.g. '+=')
  1085. newlines: list of lines up to this point. You can use
  1086. this to prepend lines before this variable setting
  1087. if you wish.
  1088. and should return a four-element tuple:
  1089. newvalue: new value to substitute in, or None to drop
  1090. the variable setting entirely. (If the removal
  1091. results in two consecutive blank lines, one of the
  1092. blank lines will also be dropped).
  1093. newop: the operator to use - if you specify None here,
  1094. the original operation will be used.
  1095. indent: number of spaces to indent multi-line entries,
  1096. or -1 to indent up to the level of the assignment
  1097. and opening quote, or a string to use as the indent.
  1098. minbreak: True to allow the first element of a
  1099. multi-line value to continue on the same line as
  1100. the assignment, False to indent before the first
  1101. element.
  1102. To clarify, if you wish not to change the value, then you
  1103. would return like this: return origvalue, None, 0, True
  1104. match_overrides: True to match items with _overrides on the end,
  1105. False otherwise
  1106. Returns a tuple:
  1107. updated:
  1108. True if changes were made, False otherwise.
  1109. newlines:
  1110. Lines after processing
  1111. """
  1112. var_res = {}
  1113. if match_overrides:
  1114. override_re = r'(_[a-zA-Z0-9-_$(){}]+)?'
  1115. else:
  1116. override_re = ''
  1117. for var in variables:
  1118. if var.endswith('()'):
  1119. var_res[var] = re.compile(r'^(%s%s)[ \\t]*\([ \\t]*\)[ \\t]*{' % (var[:-2].rstrip(), override_re))
  1120. else:
  1121. var_res[var] = re.compile(r'^(%s%s)[ \\t]*[?+:.]*=[+.]*[ \\t]*(["\'])' % (var, override_re))
  1122. updated = False
  1123. varset_start = ''
  1124. varlines = []
  1125. newlines = []
  1126. in_var = None
  1127. full_value = ''
  1128. var_end = ''
  1129. def handle_var_end():
  1130. prerun_newlines = newlines[:]
  1131. op = varset_start[len(in_var):].strip()
  1132. (newvalue, newop, indent, minbreak) = varfunc(in_var, full_value, op, newlines)
  1133. changed = (prerun_newlines != newlines)
  1134. if newvalue is None:
  1135. # Drop the value
  1136. return True
  1137. elif newvalue != full_value or (newop not in [None, op]):
  1138. if newop not in [None, op]:
  1139. # Callback changed the operator
  1140. varset_new = "%s %s" % (in_var, newop)
  1141. else:
  1142. varset_new = varset_start
  1143. if isinstance(indent, int):
  1144. if indent == -1:
  1145. indentspc = ' ' * (len(varset_new) + 2)
  1146. else:
  1147. indentspc = ' ' * indent
  1148. else:
  1149. indentspc = indent
  1150. if in_var.endswith('()'):
  1151. # A function definition
  1152. if isinstance(newvalue, list):
  1153. newlines.append('%s {\n%s%s\n}\n' % (varset_new, indentspc, ('\n%s' % indentspc).join(newvalue)))
  1154. else:
  1155. if not newvalue.startswith('\n'):
  1156. newvalue = '\n' + newvalue
  1157. if not newvalue.endswith('\n'):
  1158. newvalue = newvalue + '\n'
  1159. newlines.append('%s {%s}\n' % (varset_new, newvalue))
  1160. else:
  1161. # Normal variable
  1162. if isinstance(newvalue, list):
  1163. if not newvalue:
  1164. # Empty list -> empty string
  1165. newlines.append('%s ""\n' % varset_new)
  1166. elif minbreak:
  1167. # First item on first line
  1168. if len(newvalue) == 1:
  1169. newlines.append('%s "%s"\n' % (varset_new, newvalue[0]))
  1170. else:
  1171. newlines.append('%s "%s \\\n' % (varset_new, newvalue[0]))
  1172. for item in newvalue[1:]:
  1173. newlines.append('%s%s \\\n' % (indentspc, item))
  1174. newlines.append('%s"\n' % indentspc)
  1175. else:
  1176. # No item on first line
  1177. newlines.append('%s " \\\n' % varset_new)
  1178. for item in newvalue:
  1179. newlines.append('%s%s \\\n' % (indentspc, item))
  1180. newlines.append('%s"\n' % indentspc)
  1181. else:
  1182. newlines.append('%s "%s"\n' % (varset_new, newvalue))
  1183. return True
  1184. else:
  1185. # Put the old lines back where they were
  1186. newlines.extend(varlines)
  1187. # If newlines was touched by the function, we'll need to return True
  1188. return changed
  1189. checkspc = False
  1190. for line in meta_lines:
  1191. if in_var:
  1192. value = line.rstrip()
  1193. varlines.append(line)
  1194. if in_var.endswith('()'):
  1195. full_value += '\n' + value
  1196. else:
  1197. full_value += value[:-1]
  1198. if value.endswith(var_end):
  1199. if in_var.endswith('()'):
  1200. if full_value.count('{') - full_value.count('}') >= 0:
  1201. continue
  1202. full_value = full_value[:-1]
  1203. if handle_var_end():
  1204. updated = True
  1205. checkspc = True
  1206. in_var = None
  1207. else:
  1208. skip = False
  1209. for (varname, var_re) in var_res.items():
  1210. res = var_re.match(line)
  1211. if res:
  1212. isfunc = varname.endswith('()')
  1213. if isfunc:
  1214. splitvalue = line.split('{', 1)
  1215. var_end = '}'
  1216. else:
  1217. var_end = res.groups()[-1]
  1218. splitvalue = line.split(var_end, 1)
  1219. varset_start = splitvalue[0].rstrip()
  1220. value = splitvalue[1].rstrip()
  1221. if not isfunc and value.endswith('\\'):
  1222. value = value[:-1]
  1223. full_value = value
  1224. varlines = [line]
  1225. in_var = res.group(1)
  1226. if isfunc:
  1227. in_var += '()'
  1228. if value.endswith(var_end):
  1229. full_value = full_value[:-1]
  1230. if handle_var_end():
  1231. updated = True
  1232. checkspc = True
  1233. in_var = None
  1234. skip = True
  1235. break
  1236. if not skip:
  1237. if checkspc:
  1238. checkspc = False
  1239. if newlines and newlines[-1] == '\n' and line == '\n':
  1240. # Squash blank line if there are two consecutive blanks after a removal
  1241. continue
  1242. newlines.append(line)
  1243. return (updated, newlines)
  1244. def edit_metadata_file(meta_file, variables, varfunc):
  1245. """Edit a recipe or config file and modify one or more specified
  1246. variable values set in the file using a specified callback function.
  1247. The file is only written to if the value(s) actually change.
  1248. This is basically the file version of edit_metadata(), see that
  1249. function's description for parameter/usage information.
  1250. Returns True if the file was written to, False otherwise.
  1251. """
  1252. with open(meta_file, 'r') as f:
  1253. (updated, newlines) = edit_metadata(f, variables, varfunc)
  1254. if updated:
  1255. with open(meta_file, 'w') as f:
  1256. f.writelines(newlines)
  1257. return updated
  1258. def edit_bblayers_conf(bblayers_conf, add, remove, edit_cb=None):
  1259. """Edit bblayers.conf, adding and/or removing layers
  1260. Parameters:
  1261. bblayers_conf: path to bblayers.conf file to edit
  1262. add: layer path (or list of layer paths) to add; None or empty
  1263. list to add nothing
  1264. remove: layer path (or list of layer paths) to remove; None or
  1265. empty list to remove nothing
  1266. edit_cb: optional callback function that will be called after
  1267. processing adds/removes once per existing entry.
  1268. Returns a tuple:
  1269. notadded: list of layers specified to be added but weren't
  1270. (because they were already in the list)
  1271. notremoved: list of layers that were specified to be removed
  1272. but weren't (because they weren't in the list)
  1273. """
  1274. import fnmatch
  1275. def remove_trailing_sep(pth):
  1276. if pth and pth[-1] == os.sep:
  1277. pth = pth[:-1]
  1278. return pth
  1279. approved = bb.utils.approved_variables()
  1280. def canonicalise_path(pth):
  1281. pth = remove_trailing_sep(pth)
  1282. if 'HOME' in approved and '~' in pth:
  1283. pth = os.path.expanduser(pth)
  1284. return pth
  1285. def layerlist_param(value):
  1286. if not value:
  1287. return []
  1288. elif isinstance(value, list):
  1289. return [remove_trailing_sep(x) for x in value]
  1290. else:
  1291. return [remove_trailing_sep(value)]
  1292. addlayers = layerlist_param(add)
  1293. removelayers = layerlist_param(remove)
  1294. # Need to use a list here because we can't set non-local variables from a callback in python 2.x
  1295. bblayercalls = []
  1296. removed = []
  1297. plusequals = False
  1298. orig_bblayers = []
  1299. def handle_bblayers_firstpass(varname, origvalue, op, newlines):
  1300. bblayercalls.append(op)
  1301. if op == '=':
  1302. del orig_bblayers[:]
  1303. orig_bblayers.extend([canonicalise_path(x) for x in origvalue.split()])
  1304. return (origvalue, None, 2, False)
  1305. def handle_bblayers(varname, origvalue, op, newlines):
  1306. updated = False
  1307. bblayers = [remove_trailing_sep(x) for x in origvalue.split()]
  1308. if removelayers:
  1309. for removelayer in removelayers:
  1310. for layer in bblayers:
  1311. if fnmatch.fnmatch(canonicalise_path(layer), canonicalise_path(removelayer)):
  1312. updated = True
  1313. bblayers.remove(layer)
  1314. removed.append(removelayer)
  1315. break
  1316. if addlayers and not plusequals:
  1317. for addlayer in addlayers:
  1318. if addlayer not in bblayers:
  1319. updated = True
  1320. bblayers.append(addlayer)
  1321. del addlayers[:]
  1322. if edit_cb:
  1323. newlist = []
  1324. for layer in bblayers:
  1325. res = edit_cb(layer, canonicalise_path(layer))
  1326. if res != layer:
  1327. newlist.append(res)
  1328. updated = True
  1329. else:
  1330. newlist.append(layer)
  1331. bblayers = newlist
  1332. if updated:
  1333. if op == '+=' and not bblayers:
  1334. bblayers = None
  1335. return (bblayers, None, 2, False)
  1336. else:
  1337. return (origvalue, None, 2, False)
  1338. with open(bblayers_conf, 'r') as f:
  1339. (_, newlines) = edit_metadata(f, ['BBLAYERS'], handle_bblayers_firstpass)
  1340. if not bblayercalls:
  1341. raise Exception('Unable to find BBLAYERS in %s' % bblayers_conf)
  1342. # Try to do the "smart" thing depending on how the user has laid out
  1343. # their bblayers.conf file
  1344. if bblayercalls.count('+=') > 1:
  1345. plusequals = True
  1346. removelayers_canon = [canonicalise_path(layer) for layer in removelayers]
  1347. notadded = []
  1348. for layer in addlayers:
  1349. layer_canon = canonicalise_path(layer)
  1350. if layer_canon in orig_bblayers and not layer_canon in removelayers_canon:
  1351. notadded.append(layer)
  1352. notadded_canon = [canonicalise_path(layer) for layer in notadded]
  1353. addlayers[:] = [layer for layer in addlayers if canonicalise_path(layer) not in notadded_canon]
  1354. (updated, newlines) = edit_metadata(newlines, ['BBLAYERS'], handle_bblayers)
  1355. if addlayers:
  1356. # Still need to add these
  1357. for addlayer in addlayers:
  1358. newlines.append('BBLAYERS += "%s"\n' % addlayer)
  1359. updated = True
  1360. if updated:
  1361. with open(bblayers_conf, 'w') as f:
  1362. f.writelines(newlines)
  1363. notremoved = list(set(removelayers) - set(removed))
  1364. return (notadded, notremoved)
  1365. def get_collection_res(d):
  1366. collections = (d.getVar('BBFILE_COLLECTIONS') or '').split()
  1367. collection_res = {}
  1368. for collection in collections:
  1369. collection_res[collection] = d.getVar('BBFILE_PATTERN_%s' % collection) or ''
  1370. return collection_res
  1371. def get_file_layer(filename, d, collection_res={}):
  1372. """Determine the collection (as defined by a layer's layer.conf file) containing the specified file"""
  1373. if not collection_res:
  1374. collection_res = get_collection_res(d)
  1375. def path_to_layer(path):
  1376. # Use longest path so we handle nested layers
  1377. matchlen = 0
  1378. match = None
  1379. for collection, regex in collection_res.items():
  1380. if len(regex) > matchlen and re.match(regex, path):
  1381. matchlen = len(regex)
  1382. match = collection
  1383. return match
  1384. result = None
  1385. bbfiles = (d.getVar('BBFILES_PRIORITIZED') or '').split()
  1386. bbfilesmatch = False
  1387. for bbfilesentry in bbfiles:
  1388. if fnmatch.fnmatchcase(filename, bbfilesentry):
  1389. bbfilesmatch = True
  1390. result = path_to_layer(bbfilesentry)
  1391. break
  1392. if not bbfilesmatch:
  1393. # Probably a bbclass
  1394. result = path_to_layer(filename)
  1395. return result
  1396. # Constant taken from http://linux.die.net/include/linux/prctl.h
  1397. PR_SET_PDEATHSIG = 1
  1398. class PrCtlError(Exception):
  1399. pass
  1400. def signal_on_parent_exit(signame):
  1401. """
  1402. Trigger signame to be sent when the parent process dies
  1403. """
  1404. signum = getattr(signal, signame)
  1405. # http://linux.die.net/man/2/prctl
  1406. result = cdll['libc.so.6'].prctl(PR_SET_PDEATHSIG, signum)
  1407. if result != 0:
  1408. raise PrCtlError('prctl failed with error code %s' % result)
  1409. #
  1410. # Manually call the ioprio syscall. We could depend on other libs like psutil
  1411. # however this gets us enough of what we need to bitbake for now without the
  1412. # dependency
  1413. #
  1414. _unamearch = os.uname()[4]
  1415. IOPRIO_WHO_PROCESS = 1
  1416. IOPRIO_CLASS_SHIFT = 13
  1417. def ioprio_set(who, cls, value):
  1418. NR_ioprio_set = None
  1419. if _unamearch == "x86_64":
  1420. NR_ioprio_set = 251
  1421. elif _unamearch[0] == "i" and _unamearch[2:3] == "86":
  1422. NR_ioprio_set = 289
  1423. elif _unamearch == "aarch64":
  1424. NR_ioprio_set = 30
  1425. if NR_ioprio_set:
  1426. ioprio = value | (cls << IOPRIO_CLASS_SHIFT)
  1427. rc = cdll['libc.so.6'].syscall(NR_ioprio_set, IOPRIO_WHO_PROCESS, who, ioprio)
  1428. if rc != 0:
  1429. raise ValueError("Unable to set ioprio, syscall returned %s" % rc)
  1430. else:
  1431. bb.warn("Unable to set IO Prio for arch %s" % _unamearch)
  1432. def set_process_name(name):
  1433. from ctypes import cdll, byref, create_string_buffer
  1434. # This is nice to have for debugging, not essential
  1435. try:
  1436. libc = cdll.LoadLibrary('libc.so.6')
  1437. buf = create_string_buffer(bytes(name, 'utf-8'))
  1438. libc.prctl(15, byref(buf), 0, 0, 0)
  1439. except:
  1440. pass
  1441. def enable_loopback_networking():
  1442. # From bits/ioctls.h
  1443. SIOCGIFFLAGS = 0x8913
  1444. SIOCSIFFLAGS = 0x8914
  1445. SIOCSIFADDR = 0x8916
  1446. SIOCSIFNETMASK = 0x891C
  1447. # if.h
  1448. IFF_UP = 0x1
  1449. IFF_RUNNING = 0x40
  1450. # bits/socket.h
  1451. AF_INET = 2
  1452. # char ifr_name[IFNAMSIZ=16]
  1453. ifr_name = struct.pack("@16s", b"lo")
  1454. def netdev_req(fd, req, data = b""):
  1455. # Pad and add interface name
  1456. data = ifr_name + data + (b'\x00' * (16 - len(data)))
  1457. # Return all data after interface name
  1458. return fcntl.ioctl(fd, req, data)[16:]
  1459. with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_IP) as sock:
  1460. fd = sock.fileno()
  1461. # struct sockaddr_in ifr_addr { unsigned short family; uint16_t sin_port ; uint32_t in_addr; }
  1462. req = struct.pack("@H", AF_INET) + struct.pack("=H4B", 0, 127, 0, 0, 1)
  1463. netdev_req(fd, SIOCSIFADDR, req)
  1464. # short ifr_flags
  1465. flags = struct.unpack_from('@h', netdev_req(fd, SIOCGIFFLAGS))[0]
  1466. flags |= IFF_UP | IFF_RUNNING
  1467. netdev_req(fd, SIOCSIFFLAGS, struct.pack('@h', flags))
  1468. # struct sockaddr_in ifr_netmask
  1469. req = struct.pack("@H", AF_INET) + struct.pack("=H4B", 0, 255, 0, 0, 0)
  1470. netdev_req(fd, SIOCSIFNETMASK, req)
  1471. def disable_network(uid=None, gid=None):
  1472. """
  1473. Disable networking in the current process if the kernel supports it, else
  1474. just return after logging to debug. To do this we need to create a new user
  1475. namespace, then map back to the original uid/gid.
  1476. """
  1477. libc = ctypes.CDLL('libc.so.6')
  1478. # From sched.h
  1479. # New user namespace
  1480. CLONE_NEWUSER = 0x10000000
  1481. # New network namespace
  1482. CLONE_NEWNET = 0x40000000
  1483. if uid is None:
  1484. uid = os.getuid()
  1485. if gid is None:
  1486. gid = os.getgid()
  1487. ret = libc.unshare(CLONE_NEWNET | CLONE_NEWUSER)
  1488. if ret != 0:
  1489. logger.debug("System doesn't support disabling network without admin privs")
  1490. return
  1491. with open("/proc/self/uid_map", "w") as f:
  1492. f.write("%s %s 1" % (uid, uid))
  1493. with open("/proc/self/setgroups", "w") as f:
  1494. f.write("deny")
  1495. with open("/proc/self/gid_map", "w") as f:
  1496. f.write("%s %s 1" % (gid, gid))
  1497. def export_proxies(d):
  1498. from bb.fetch2 import get_fetcher_environment
  1499. """ export common proxies variables from datastore to environment """
  1500. newenv = get_fetcher_environment(d)
  1501. for v in newenv:
  1502. os.environ[v] = newenv[v]
  1503. def load_plugins(logger, plugins, pluginpath):
  1504. def load_plugin(name):
  1505. logger.debug('Loading plugin %s' % name)
  1506. spec = importlib.machinery.PathFinder.find_spec(name, path=[pluginpath] )
  1507. if spec:
  1508. mod = importlib.util.module_from_spec(spec)
  1509. spec.loader.exec_module(mod)
  1510. return mod
  1511. logger.debug('Loading plugins from %s...' % pluginpath)
  1512. expanded = (glob.glob(os.path.join(pluginpath, '*' + ext))
  1513. for ext in python_extensions)
  1514. files = itertools.chain.from_iterable(expanded)
  1515. names = set(os.path.splitext(os.path.basename(fn))[0] for fn in files)
  1516. for name in names:
  1517. if name != '__init__':
  1518. plugin = load_plugin(name)
  1519. if hasattr(plugin, 'plugin_init'):
  1520. obj = plugin.plugin_init(plugins)
  1521. plugins.append(obj or plugin)
  1522. else:
  1523. plugins.append(plugin)
  1524. class LogCatcher(logging.Handler):
  1525. """Logging handler for collecting logged messages so you can check them later"""
  1526. def __init__(self):
  1527. self.messages = []
  1528. logging.Handler.__init__(self, logging.WARNING)
  1529. def emit(self, record):
  1530. self.messages.append(bb.build.logformatter.format(record))
  1531. def contains(self, message):
  1532. return (message in self.messages)
  1533. def is_semver(version):
  1534. """
  1535. Is the version string following the semver semantic?
  1536. https://semver.org/spec/v2.0.0.html
  1537. """
  1538. regex = re.compile(
  1539. r"""
  1540. ^
  1541. (0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)
  1542. (?:-(
  1543. (?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)
  1544. (?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*
  1545. ))?
  1546. (?:\+(
  1547. [0-9a-zA-Z-]+
  1548. (?:\.[0-9a-zA-Z-]+)*
  1549. ))?
  1550. $
  1551. """, re.VERBOSE)
  1552. if regex.match(version) is None:
  1553. return False
  1554. return True
  1555. # Wrapper around os.rename which can handle cross device problems
  1556. # e.g. from container filesystems
  1557. def rename(src, dst):
  1558. try:
  1559. os.rename(src, dst)
  1560. except OSError as err:
  1561. if err.errno == 18:
  1562. # Invalid cross-device link error
  1563. shutil.move(src, dst)
  1564. else:
  1565. raise err
  1566. @contextmanager
  1567. def environment(**envvars):
  1568. """
  1569. Context manager to selectively update the environment with the specified mapping.
  1570. """
  1571. backup = dict(os.environ)
  1572. try:
  1573. os.environ.update(envvars)
  1574. yield
  1575. finally:
  1576. for var in envvars:
  1577. if var in backup:
  1578. os.environ[var] = backup[var]
  1579. elif var in os.environ:
  1580. del os.environ[var]
  1581. def is_local_uid(uid=''):
  1582. """
  1583. Check whether uid is a local one or not.
  1584. Can't use pwd module since it gets all UIDs, not local ones only.
  1585. """
  1586. if not uid:
  1587. uid = os.getuid()
  1588. with open('/etc/passwd', 'r') as f:
  1589. for line in f:
  1590. line_split = line.split(':')
  1591. if len(line_split) < 3:
  1592. continue
  1593. if str(uid) == line_split[2]:
  1594. return True
  1595. return False
  1596. def mkstemp(suffix=None, prefix=None, dir=None, text=False):
  1597. """
  1598. Generates a unique filename, independent of time.
  1599. mkstemp() in glibc (at least) generates unique file names based on the
  1600. current system time. When combined with highly parallel builds, and
  1601. operating over NFS (e.g. shared sstate/downloads) this can result in
  1602. conflicts and race conditions.
  1603. This function adds additional entropy to the file name so that a collision
  1604. is independent of time and thus extremely unlikely.
  1605. """
  1606. entropy = "".join(random.choices("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", k=20))
  1607. if prefix:
  1608. prefix = prefix + entropy
  1609. else:
  1610. prefix = tempfile.gettempprefix() + entropy
  1611. return tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir, text=text)
  1612. def path_is_descendant(descendant, ancestor):
  1613. """
  1614. Returns True if the path `descendant` is a descendant of `ancestor`
  1615. (including being equivalent to `ancestor` itself). Otherwise returns False.
  1616. Correctly accounts for symlinks, bind mounts, etc. by using
  1617. os.path.samestat() to compare paths
  1618. May raise any exception that os.stat() raises
  1619. """
  1620. ancestor_stat = os.stat(ancestor)
  1621. # Recurse up each directory component of the descendant to see if it is
  1622. # equivalent to the ancestor
  1623. check_dir = os.path.abspath(descendant).rstrip("/")
  1624. while check_dir:
  1625. check_stat = os.stat(check_dir)
  1626. if os.path.samestat(check_stat, ancestor_stat):
  1627. return True
  1628. check_dir = os.path.dirname(check_dir).rstrip("/")
  1629. return False
  1630. # If we don't have a timeout of some kind and a process/thread exits badly (for example
  1631. # OOM killed) and held a lock, we'd just hang in the lock futex forever. It is better
  1632. # we exit at some point than hang. 5 minutes with no progress means we're probably deadlocked.
  1633. # This function can still deadlock python since it can't signal the other threads to exit
  1634. # (signals are handled in the main thread) and even os._exit() will wait on non-daemon threads
  1635. # to exit.
  1636. @contextmanager
  1637. def lock_timeout(lock):
  1638. try:
  1639. s = signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals())
  1640. held = lock.acquire(timeout=5*60)
  1641. if not held:
  1642. bb.server.process.serverlog("Couldn't get the lock for 5 mins, timed out, exiting.\n%s" % traceback.format_stack())
  1643. os._exit(1)
  1644. yield held
  1645. finally:
  1646. lock.release()
  1647. signal.pthread_sigmask(signal.SIG_SETMASK, s)
  1648. # A version of lock_timeout without the check that the lock was locked and a shorter timeout
  1649. @contextmanager
  1650. def lock_timeout_nocheck(lock):
  1651. try:
  1652. s = signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals())
  1653. l = lock.acquire(timeout=10)
  1654. yield l
  1655. finally:
  1656. if l:
  1657. lock.release()
  1658. signal.pthread_sigmask(signal.SIG_SETMASK, s)