utils.py 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
  1. # ex:ts=4:sw=4:sts=4:et
  2. # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  3. """
  4. BitBake Utility Functions
  5. """
  6. # Copyright (C) 2004 Michael Lauer
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License version 2 as
  10. # published by the Free Software Foundation.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License along
  18. # with this program; if not, write to the Free Software Foundation, Inc.,
  19. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. import re, fcntl, os, string, stat, shutil, time
  21. import sys
  22. import errno
  23. import logging
  24. import bb
  25. import bb.msg
  26. import multiprocessing
  27. import fcntl
  28. import subprocess
  29. import glob
  30. import fnmatch
  31. import traceback
  32. import errno
  33. import signal
  34. import ast
  35. from commands import getstatusoutput
  36. from contextlib import contextmanager
  37. from ctypes import cdll
  38. logger = logging.getLogger("BitBake.Util")
  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('^([a-zA-Z]+)(.*)$')
  56. numeric_regexp = re.compile('^(\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.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 < cb:
  106. return -1
  107. elif ca > cb:
  108. return 1
  109. def vercmp(ta, tb):
  110. (ea, va, ra) = ta
  111. (eb, vb, rb) = tb
  112. r = int(ea or 0) - int(eb or 0)
  113. if (r == 0):
  114. r = vercmp_part(va, vb)
  115. if (r == 0):
  116. r = vercmp_part(ra, rb)
  117. return r
  118. def vercmp_string(a, b):
  119. ta = split_version(a)
  120. tb = split_version(b)
  121. return vercmp(ta, tb)
  122. def vercmp_string_op(a, b, op):
  123. """
  124. Compare two versions and check if the specified comparison operator matches the result of the comparison.
  125. This function is fairly liberal about what operators it will accept since there are a variety of styles
  126. depending on the context.
  127. """
  128. res = vercmp_string(a, b)
  129. if op in ('=', '=='):
  130. return res == 0
  131. elif op == '<=':
  132. return res <= 0
  133. elif op == '>=':
  134. return res >= 0
  135. elif op in ('>', '>>'):
  136. return res > 0
  137. elif op in ('<', '<<'):
  138. return res < 0
  139. elif op == '!=':
  140. return res != 0
  141. else:
  142. raise VersionStringException('Unsupported comparison operator "%s"' % op)
  143. def explode_deps(s):
  144. """
  145. Take an RDEPENDS style string of format:
  146. "DEPEND1 (optional version) DEPEND2 (optional version) ..."
  147. and return a list of dependencies.
  148. Version information is ignored.
  149. """
  150. r = []
  151. l = s.split()
  152. flag = False
  153. for i in l:
  154. if i[0] == '(':
  155. flag = True
  156. #j = []
  157. if not flag:
  158. r.append(i)
  159. #else:
  160. # j.append(i)
  161. if flag and i.endswith(')'):
  162. flag = False
  163. # Ignore version
  164. #r[-1] += ' ' + ' '.join(j)
  165. return r
  166. def explode_dep_versions2(s):
  167. """
  168. Take an RDEPENDS style string of format:
  169. "DEPEND1 (optional version) DEPEND2 (optional version) ..."
  170. and return a dictionary of dependencies and versions.
  171. """
  172. r = {}
  173. l = s.replace(",", "").split()
  174. lastdep = None
  175. lastcmp = ""
  176. lastver = ""
  177. incmp = False
  178. inversion = False
  179. for i in l:
  180. if i[0] == '(':
  181. incmp = True
  182. i = i[1:].strip()
  183. if not i:
  184. continue
  185. if incmp:
  186. incmp = False
  187. inversion = True
  188. # This list is based on behavior and supported comparisons from deb, opkg and rpm.
  189. #
  190. # Even though =<, <<, ==, !=, =>, and >> may not be supported,
  191. # we list each possibly valid item.
  192. # The build system is responsible for validation of what it supports.
  193. if i.startswith(('<=', '=<', '<<', '==', '!=', '>=', '=>', '>>')):
  194. lastcmp = i[0:2]
  195. i = i[2:]
  196. elif i.startswith(('<', '>', '=')):
  197. lastcmp = i[0:1]
  198. i = i[1:]
  199. else:
  200. # This is an unsupported case!
  201. raise VersionStringException('Invalid version specification in "(%s" - invalid or missing operator' % i)
  202. lastcmp = (i or "")
  203. i = ""
  204. i.strip()
  205. if not i:
  206. continue
  207. if inversion:
  208. if i.endswith(')'):
  209. i = i[:-1] or ""
  210. inversion = False
  211. if lastver and i:
  212. lastver += " "
  213. if i:
  214. lastver += i
  215. if lastdep not in r:
  216. r[lastdep] = []
  217. r[lastdep].append(lastcmp + " " + lastver)
  218. continue
  219. #if not inversion:
  220. lastdep = i
  221. lastver = ""
  222. lastcmp = ""
  223. if not (i in r and r[i]):
  224. r[lastdep] = []
  225. return r
  226. def explode_dep_versions(s):
  227. r = explode_dep_versions2(s)
  228. for d in r:
  229. if not r[d]:
  230. r[d] = None
  231. continue
  232. if len(r[d]) > 1:
  233. 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))
  234. r[d] = r[d][0]
  235. return r
  236. def join_deps(deps, commasep=True):
  237. """
  238. Take the result from explode_dep_versions and generate a dependency string
  239. """
  240. result = []
  241. for dep in deps:
  242. if deps[dep]:
  243. if isinstance(deps[dep], list):
  244. for v in deps[dep]:
  245. result.append(dep + " (" + v + ")")
  246. else:
  247. result.append(dep + " (" + deps[dep] + ")")
  248. else:
  249. result.append(dep)
  250. if commasep:
  251. return ", ".join(result)
  252. else:
  253. return " ".join(result)
  254. def _print_trace(body, line):
  255. """
  256. Print the Environment of a Text Body
  257. """
  258. error = []
  259. # print the environment of the method
  260. min_line = max(1, line-4)
  261. max_line = min(line + 4, len(body))
  262. for i in range(min_line, max_line + 1):
  263. if line == i:
  264. error.append(' *** %.4d:%s' % (i, body[i-1].rstrip()))
  265. else:
  266. error.append(' %.4d:%s' % (i, body[i-1].rstrip()))
  267. return error
  268. def better_compile(text, file, realfile, mode = "exec", lineno = None):
  269. """
  270. A better compile method. This method
  271. will print the offending lines.
  272. """
  273. try:
  274. cache = bb.methodpool.compile_cache(text)
  275. if cache:
  276. return cache
  277. code = compile(text, realfile, mode, ast.PyCF_ONLY_AST)
  278. if lineno is not None:
  279. ast.increment_lineno(code, lineno)
  280. code = compile(code, realfile, mode)
  281. bb.methodpool.compile_cache_add(text, code)
  282. return code
  283. except Exception as e:
  284. error = []
  285. # split the text into lines again
  286. body = text.split('\n')
  287. error.append("Error in compiling python function in %s, line %s:\n" % (realfile, lineno))
  288. if hasattr(e, "lineno"):
  289. error.append("The code lines resulting in this error were:")
  290. error.extend(_print_trace(body, e.lineno))
  291. else:
  292. error.append("The function causing this error was:")
  293. for line in body:
  294. error.append(line)
  295. error.append("%s: %s" % (e.__class__.__name__, str(e)))
  296. logger.error("\n".join(error))
  297. e = bb.BBHandledException(e)
  298. raise e
  299. def _print_exception(t, value, tb, realfile, text, context):
  300. error = []
  301. try:
  302. exception = traceback.format_exception_only(t, value)
  303. error.append('Error executing a python function in %s:\n' % realfile)
  304. # Strip 'us' from the stack (better_exec call) unless that was where the
  305. # error came from
  306. if tb.tb_next is not None:
  307. tb = tb.tb_next
  308. textarray = text.split('\n')
  309. linefailed = tb.tb_lineno
  310. tbextract = traceback.extract_tb(tb)
  311. tbformat = traceback.format_list(tbextract)
  312. error.append("The stack trace of python calls that resulted in this exception/failure was:")
  313. error.append("File: '%s', lineno: %s, function: %s" % (tbextract[0][0], tbextract[0][1], tbextract[0][2]))
  314. error.extend(_print_trace(textarray, linefailed))
  315. # See if this is a function we constructed and has calls back into other functions in
  316. # "text". If so, try and improve the context of the error by diving down the trace
  317. level = 0
  318. nexttb = tb.tb_next
  319. while nexttb is not None and (level+1) < len(tbextract):
  320. error.append("File: '%s', lineno: %s, function: %s" % (tbextract[level+1][0], tbextract[level+1][1], tbextract[level+1][2]))
  321. if tbextract[level][0] == tbextract[level+1][0] and tbextract[level+1][2] == tbextract[level][0]:
  322. # The code was possibly in the string we compiled ourselves
  323. error.extend(_print_trace(textarray, tbextract[level+1][1]))
  324. elif tbextract[level+1][0].startswith("/"):
  325. # The code looks like it might be in a file, try and load it
  326. try:
  327. with open(tbextract[level+1][0], "r") as f:
  328. text = f.readlines()
  329. error.extend(_print_trace(text, tbextract[level+1][1]))
  330. except:
  331. error.append(tbformat[level+1])
  332. elif "d" in context and tbextract[level+1][2]:
  333. # Try and find the code in the datastore based on the functionname
  334. d = context["d"]
  335. functionname = tbextract[level+1][2]
  336. text = d.getVar(functionname, True)
  337. if text:
  338. error.extend(_print_trace(text.split('\n'), tbextract[level+1][1]))
  339. else:
  340. error.append(tbformat[level+1])
  341. else:
  342. error.append(tbformat[level+1])
  343. nexttb = tb.tb_next
  344. level = level + 1
  345. error.append("Exception: %s" % ''.join(exception))
  346. finally:
  347. logger.error("\n".join(error))
  348. def better_exec(code, context, text = None, realfile = "<code>"):
  349. """
  350. Similiar to better_compile, better_exec will
  351. print the lines that are responsible for the
  352. error.
  353. """
  354. import bb.parse
  355. if not text:
  356. text = code
  357. if not hasattr(code, "co_filename"):
  358. code = better_compile(code, realfile, realfile)
  359. try:
  360. exec(code, get_context(), context)
  361. except (bb.BBHandledException, bb.parse.SkipRecipe, bb.build.FuncFailed, bb.data_smart.ExpansionError):
  362. # Error already shown so passthrough, no need for traceback
  363. raise
  364. except Exception as e:
  365. (t, value, tb) = sys.exc_info()
  366. try:
  367. _print_exception(t, value, tb, realfile, text, context)
  368. except Exception as e:
  369. logger.error("Exception handler error: %s" % str(e))
  370. e = bb.BBHandledException(e)
  371. raise e
  372. def simple_exec(code, context):
  373. exec(code, get_context(), context)
  374. def better_eval(source, locals):
  375. return eval(source, get_context(), locals)
  376. @contextmanager
  377. def fileslocked(files):
  378. """Context manager for locking and unlocking file locks."""
  379. locks = []
  380. if files:
  381. for lockfile in files:
  382. locks.append(bb.utils.lockfile(lockfile))
  383. yield
  384. for lock in locks:
  385. bb.utils.unlockfile(lock)
  386. @contextmanager
  387. def timeout(seconds):
  388. def timeout_handler(signum, frame):
  389. pass
  390. original_handler = signal.signal(signal.SIGALRM, timeout_handler)
  391. try:
  392. signal.alarm(seconds)
  393. yield
  394. finally:
  395. signal.alarm(0)
  396. signal.signal(signal.SIGALRM, original_handler)
  397. def lockfile(name, shared=False, retry=True, block=False):
  398. """
  399. Use the specified file as a lock file, return when the lock has
  400. been acquired. Returns a variable to pass to unlockfile().
  401. Parameters:
  402. retry: True to re-try locking if it fails, False otherwise
  403. block: True to block until the lock succeeds, False otherwise
  404. The retry and block parameters are kind of equivalent unless you
  405. consider the possibility of sending a signal to the process to break
  406. out - at which point you want block=True rather than retry=True.
  407. """
  408. dirname = os.path.dirname(name)
  409. mkdirhier(dirname)
  410. if not os.access(dirname, os.W_OK):
  411. logger.error("Unable to acquire lock '%s', directory is not writable",
  412. name)
  413. sys.exit(1)
  414. op = fcntl.LOCK_EX
  415. if shared:
  416. op = fcntl.LOCK_SH
  417. if not retry and not block:
  418. op = op | fcntl.LOCK_NB
  419. while True:
  420. # If we leave the lockfiles lying around there is no problem
  421. # but we should clean up after ourselves. This gives potential
  422. # for races though. To work around this, when we acquire the lock
  423. # we check the file we locked was still the lock file on disk.
  424. # by comparing inode numbers. If they don't match or the lockfile
  425. # no longer exists, we start again.
  426. # This implementation is unfair since the last person to request the
  427. # lock is the most likely to win it.
  428. try:
  429. lf = open(name, 'a+')
  430. fileno = lf.fileno()
  431. fcntl.flock(fileno, op)
  432. statinfo = os.fstat(fileno)
  433. if os.path.exists(lf.name):
  434. statinfo2 = os.stat(lf.name)
  435. if statinfo.st_ino == statinfo2.st_ino:
  436. return lf
  437. lf.close()
  438. except Exception:
  439. try:
  440. lf.close()
  441. except Exception:
  442. pass
  443. pass
  444. if not retry:
  445. return None
  446. def unlockfile(lf):
  447. """
  448. Unlock a file locked using lockfile()
  449. """
  450. try:
  451. # If we had a shared lock, we need to promote to exclusive before
  452. # removing the lockfile. Attempt this, ignore failures.
  453. fcntl.flock(lf.fileno(), fcntl.LOCK_EX|fcntl.LOCK_NB)
  454. os.unlink(lf.name)
  455. except (IOError, OSError):
  456. pass
  457. fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
  458. lf.close()
  459. def md5_file(filename):
  460. """
  461. Return the hex string representation of the MD5 checksum of filename.
  462. """
  463. try:
  464. import hashlib
  465. m = hashlib.md5()
  466. except ImportError:
  467. import md5
  468. m = md5.new()
  469. with open(filename, "rb") as f:
  470. for line in f:
  471. m.update(line)
  472. return m.hexdigest()
  473. def sha256_file(filename):
  474. """
  475. Return the hex string representation of the 256-bit SHA checksum of
  476. filename. On Python 2.4 this will return None, so callers will need to
  477. handle that by either skipping SHA checks, or running a standalone sha256sum
  478. binary.
  479. """
  480. try:
  481. import hashlib
  482. except ImportError:
  483. return None
  484. s = hashlib.sha256()
  485. with open(filename, "rb") as f:
  486. for line in f:
  487. s.update(line)
  488. return s.hexdigest()
  489. def preserved_envvars_exported():
  490. """Variables which are taken from the environment and placed in and exported
  491. from the metadata"""
  492. return [
  493. 'BB_TASKHASH',
  494. 'HOME',
  495. 'LOGNAME',
  496. 'PATH',
  497. 'PWD',
  498. 'SHELL',
  499. 'TERM',
  500. 'USER',
  501. ]
  502. def preserved_envvars():
  503. """Variables which are taken from the environment and placed in the metadata"""
  504. v = [
  505. 'BBPATH',
  506. 'BB_PRESERVE_ENV',
  507. 'BB_ENV_WHITELIST',
  508. 'BB_ENV_EXTRAWHITE',
  509. ]
  510. return v + preserved_envvars_exported()
  511. def filter_environment(good_vars):
  512. """
  513. Create a pristine environment for bitbake. This will remove variables that
  514. are not known and may influence the build in a negative way.
  515. """
  516. removed_vars = {}
  517. for key in os.environ.keys():
  518. if key in good_vars:
  519. continue
  520. removed_vars[key] = os.environ[key]
  521. os.unsetenv(key)
  522. del os.environ[key]
  523. if removed_vars:
  524. logger.debug(1, "Removed the following variables from the environment: %s", ", ".join(removed_vars.keys()))
  525. return removed_vars
  526. def approved_variables():
  527. """
  528. Determine and return the list of whitelisted variables which are approved
  529. to remain in the environment.
  530. """
  531. if 'BB_PRESERVE_ENV' in os.environ:
  532. return os.environ.keys()
  533. approved = []
  534. if 'BB_ENV_WHITELIST' in os.environ:
  535. approved = os.environ['BB_ENV_WHITELIST'].split()
  536. approved.extend(['BB_ENV_WHITELIST'])
  537. else:
  538. approved = preserved_envvars()
  539. if 'BB_ENV_EXTRAWHITE' in os.environ:
  540. approved.extend(os.environ['BB_ENV_EXTRAWHITE'].split())
  541. if 'BB_ENV_EXTRAWHITE' not in approved:
  542. approved.extend(['BB_ENV_EXTRAWHITE'])
  543. return approved
  544. def clean_environment():
  545. """
  546. Clean up any spurious environment variables. This will remove any
  547. variables the user hasn't chosen to preserve.
  548. """
  549. if 'BB_PRESERVE_ENV' not in os.environ:
  550. good_vars = approved_variables()
  551. return filter_environment(good_vars)
  552. return {}
  553. def empty_environment():
  554. """
  555. Remove all variables from the environment.
  556. """
  557. for s in os.environ.keys():
  558. os.unsetenv(s)
  559. del os.environ[s]
  560. def build_environment(d):
  561. """
  562. Build an environment from all exported variables.
  563. """
  564. import bb.data
  565. for var in bb.data.keys(d):
  566. export = d.getVarFlag(var, "export")
  567. if export:
  568. os.environ[var] = d.getVar(var, True) or ""
  569. def _check_unsafe_delete_path(path):
  570. """
  571. Basic safeguard against recursively deleting something we shouldn't. If it returns True,
  572. the caller should raise an exception with an appropriate message.
  573. NOTE: This is NOT meant to be a security mechanism - just a guard against silly mistakes
  574. with potentially disastrous results.
  575. """
  576. extra = ''
  577. # HOME might not be /home/something, so in case we can get it, check against it
  578. homedir = os.environ.get('HOME', '')
  579. if homedir:
  580. extra = '|%s' % homedir
  581. if re.match('(/|//|/home|/home/[^/]*%s)$' % extra, os.path.abspath(path)):
  582. return True
  583. return False
  584. def remove(path, recurse=False):
  585. """Equivalent to rm -f or rm -rf"""
  586. if not path:
  587. return
  588. if recurse:
  589. for name in glob.glob(path):
  590. if _check_unsafe_delete_path(path):
  591. raise Exception('bb.utils.remove: called with dangerous path "%s" and recurse=True, refusing to delete!' % path)
  592. # shutil.rmtree(name) would be ideal but its too slow
  593. subprocess.call(['rm', '-rf'] + glob.glob(path))
  594. return
  595. for name in glob.glob(path):
  596. try:
  597. os.unlink(name)
  598. except OSError as exc:
  599. if exc.errno != errno.ENOENT:
  600. raise
  601. def prunedir(topdir):
  602. # Delete everything reachable from the directory named in 'topdir'.
  603. # CAUTION: This is dangerous!
  604. if _check_unsafe_delete_path(topdir):
  605. raise Exception('bb.utils.prunedir: called with dangerous path "%s", refusing to delete!' % topdir)
  606. for root, dirs, files in os.walk(topdir, topdown = False):
  607. for name in files:
  608. os.remove(os.path.join(root, name))
  609. for name in dirs:
  610. if os.path.islink(os.path.join(root, name)):
  611. os.remove(os.path.join(root, name))
  612. else:
  613. os.rmdir(os.path.join(root, name))
  614. os.rmdir(topdir)
  615. #
  616. # Could also use return re.compile("(%s)" % "|".join(map(re.escape, suffixes))).sub(lambda mo: "", var)
  617. # but thats possibly insane and suffixes is probably going to be small
  618. #
  619. def prune_suffix(var, suffixes, d):
  620. # See if var ends with any of the suffixes listed and
  621. # remove it if found
  622. for suffix in suffixes:
  623. if var.endswith(suffix):
  624. return var.replace(suffix, "")
  625. return var
  626. def mkdirhier(directory):
  627. """Create a directory like 'mkdir -p', but does not complain if
  628. directory already exists like os.makedirs
  629. """
  630. try:
  631. os.makedirs(directory)
  632. except OSError as e:
  633. if e.errno != errno.EEXIST:
  634. raise e
  635. def movefile(src, dest, newmtime = None, sstat = None):
  636. """Moves a file from src to dest, preserving all permissions and
  637. attributes; mtime will be preserved even when moving across
  638. filesystems. Returns true on success and false on failure. Move is
  639. atomic.
  640. """
  641. #print "movefile(" + src + "," + dest + "," + str(newmtime) + "," + str(sstat) + ")"
  642. try:
  643. if not sstat:
  644. sstat = os.lstat(src)
  645. except Exception as e:
  646. print("movefile: Stating source file failed...", e)
  647. return None
  648. destexists = 1
  649. try:
  650. dstat = os.lstat(dest)
  651. except:
  652. dstat = os.lstat(os.path.dirname(dest))
  653. destexists = 0
  654. if destexists:
  655. if stat.S_ISLNK(dstat[stat.ST_MODE]):
  656. try:
  657. os.unlink(dest)
  658. destexists = 0
  659. except Exception as e:
  660. pass
  661. if stat.S_ISLNK(sstat[stat.ST_MODE]):
  662. try:
  663. target = os.readlink(src)
  664. if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
  665. os.unlink(dest)
  666. os.symlink(target, dest)
  667. #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
  668. os.unlink(src)
  669. return os.lstat(dest)
  670. except Exception as e:
  671. print("movefile: failed to properly create symlink:", dest, "->", target, e)
  672. return None
  673. renamefailed = 1
  674. if sstat[stat.ST_DEV] == dstat[stat.ST_DEV]:
  675. try:
  676. # os.rename needs to know the dest path ending with file name
  677. # so append the file name to a path only if it's a dir specified
  678. srcfname = os.path.basename(src)
  679. destpath = os.path.join(dest, srcfname) if os.path.isdir(dest) \
  680. else dest
  681. os.rename(src, destpath)
  682. renamefailed = 0
  683. except Exception as e:
  684. if e[0] != errno.EXDEV:
  685. # Some random error.
  686. print("movefile: Failed to move", src, "to", dest, e)
  687. return None
  688. # Invalid cross-device-link 'bind' mounted or actually Cross-Device
  689. if renamefailed:
  690. didcopy = 0
  691. if stat.S_ISREG(sstat[stat.ST_MODE]):
  692. try: # For safety copy then move it over.
  693. shutil.copyfile(src, dest + "#new")
  694. os.rename(dest + "#new", dest)
  695. didcopy = 1
  696. except Exception as e:
  697. print('movefile: copy', src, '->', dest, 'failed.', e)
  698. return None
  699. else:
  700. #we don't yet handle special, so we need to fall back to /bin/mv
  701. a = getstatusoutput("/bin/mv -f " + "'" + src + "' '" + dest + "'")
  702. if a[0] != 0:
  703. print("movefile: Failed to move special file:" + src + "' to '" + dest + "'", a)
  704. return None # failure
  705. try:
  706. if didcopy:
  707. os.lchown(dest, sstat[stat.ST_UID], sstat[stat.ST_GID])
  708. os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
  709. os.unlink(src)
  710. except Exception as e:
  711. print("movefile: Failed to chown/chmod/unlink", dest, e)
  712. return None
  713. if newmtime:
  714. os.utime(dest, (newmtime, newmtime))
  715. else:
  716. os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
  717. newmtime = sstat[stat.ST_MTIME]
  718. return newmtime
  719. def copyfile(src, dest, newmtime = None, sstat = None):
  720. """
  721. Copies a file from src to dest, preserving all permissions and
  722. attributes; mtime will be preserved even when moving across
  723. filesystems. Returns true on success and false on failure.
  724. """
  725. #print "copyfile(" + src + "," + dest + "," + str(newmtime) + "," + str(sstat) + ")"
  726. try:
  727. if not sstat:
  728. sstat = os.lstat(src)
  729. except Exception as e:
  730. logger.warn("copyfile: stat of %s failed (%s)" % (src, e))
  731. return False
  732. destexists = 1
  733. try:
  734. dstat = os.lstat(dest)
  735. except:
  736. dstat = os.lstat(os.path.dirname(dest))
  737. destexists = 0
  738. if destexists:
  739. if stat.S_ISLNK(dstat[stat.ST_MODE]):
  740. try:
  741. os.unlink(dest)
  742. destexists = 0
  743. except Exception as e:
  744. pass
  745. if stat.S_ISLNK(sstat[stat.ST_MODE]):
  746. try:
  747. target = os.readlink(src)
  748. if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
  749. os.unlink(dest)
  750. os.symlink(target, dest)
  751. #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
  752. return os.lstat(dest)
  753. except Exception as e:
  754. logger.warn("copyfile: failed to create symlink %s to %s (%s)" % (dest, target, e))
  755. return False
  756. if stat.S_ISREG(sstat[stat.ST_MODE]):
  757. try:
  758. srcchown = False
  759. if not os.access(src, os.R_OK):
  760. # Make sure we can read it
  761. srcchown = True
  762. os.chmod(src, sstat[stat.ST_MODE] | stat.S_IRUSR)
  763. # For safety copy then move it over.
  764. shutil.copyfile(src, dest + "#new")
  765. os.rename(dest + "#new", dest)
  766. except Exception as e:
  767. logger.warn("copyfile: copy %s to %s failed (%s)" % (src, dest, e))
  768. return False
  769. finally:
  770. if srcchown:
  771. os.chmod(src, sstat[stat.ST_MODE])
  772. os.utime(src, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
  773. else:
  774. #we don't yet handle special, so we need to fall back to /bin/mv
  775. a = getstatusoutput("/bin/cp -f " + "'" + src + "' '" + dest + "'")
  776. if a[0] != 0:
  777. logger.warn("copyfile: failed to copy special file %s to %s (%s)" % (src, dest, a))
  778. return False # failure
  779. try:
  780. os.lchown(dest, sstat[stat.ST_UID], sstat[stat.ST_GID])
  781. os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
  782. except Exception as e:
  783. logger.warn("copyfile: failed to chown/chmod %s (%s)" % (dest, e))
  784. return False
  785. if newmtime:
  786. os.utime(dest, (newmtime, newmtime))
  787. else:
  788. os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME]))
  789. newmtime = sstat[stat.ST_MTIME]
  790. return newmtime
  791. def which(path, item, direction = 0, history = False):
  792. """
  793. Locate a file in a PATH
  794. """
  795. hist = []
  796. paths = (path or "").split(':')
  797. if direction != 0:
  798. paths.reverse()
  799. for p in paths:
  800. next = os.path.join(p, item)
  801. hist.append(next)
  802. if os.path.exists(next):
  803. if not os.path.isabs(next):
  804. next = os.path.abspath(next)
  805. if history:
  806. return next, hist
  807. return next
  808. if history:
  809. return "", hist
  810. return ""
  811. def to_boolean(string, default=None):
  812. if not string:
  813. return default
  814. normalized = string.lower()
  815. if normalized in ("y", "yes", "1", "true"):
  816. return True
  817. elif normalized in ("n", "no", "0", "false"):
  818. return False
  819. else:
  820. raise ValueError("Invalid value for to_boolean: %s" % string)
  821. def contains(variable, checkvalues, truevalue, falsevalue, d):
  822. val = d.getVar(variable, True)
  823. if not val:
  824. return falsevalue
  825. val = set(val.split())
  826. if isinstance(checkvalues, basestring):
  827. checkvalues = set(checkvalues.split())
  828. else:
  829. checkvalues = set(checkvalues)
  830. if checkvalues.issubset(val):
  831. return truevalue
  832. return falsevalue
  833. def contains_any(variable, checkvalues, truevalue, falsevalue, d):
  834. val = d.getVar(variable, True)
  835. if not val:
  836. return falsevalue
  837. val = set(val.split())
  838. if isinstance(checkvalues, basestring):
  839. checkvalues = set(checkvalues.split())
  840. else:
  841. checkvalues = set(checkvalues)
  842. if checkvalues & val:
  843. return truevalue
  844. return falsevalue
  845. def cpu_count():
  846. return multiprocessing.cpu_count()
  847. def nonblockingfd(fd):
  848. fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
  849. def process_profilelog(fn, pout = None):
  850. # Either call with a list of filenames and set pout or a filename and optionally pout.
  851. if not pout:
  852. pout = fn + '.processed'
  853. pout = open(pout, 'w')
  854. import pstats
  855. if isinstance(fn, list):
  856. p = pstats.Stats(*fn, stream=pout)
  857. else:
  858. p = pstats.Stats(fn, stream=pout)
  859. p.sort_stats('time')
  860. p.print_stats()
  861. p.print_callers()
  862. p.sort_stats('cumulative')
  863. p.print_stats()
  864. pout.flush()
  865. pout.close()
  866. #
  867. # Was present to work around multiprocessing pool bugs in python < 2.7.3
  868. #
  869. def multiprocessingpool(*args, **kwargs):
  870. import multiprocessing.pool
  871. #import multiprocessing.util
  872. #multiprocessing.util.log_to_stderr(10)
  873. # Deal with a multiprocessing bug where signals to the processes would be delayed until the work
  874. # completes. Putting in a timeout means the signals (like SIGINT/SIGTERM) get processed.
  875. def wrapper(func):
  876. def wrap(self, timeout=None):
  877. return func(self, timeout=timeout if timeout is not None else 1e100)
  878. return wrap
  879. multiprocessing.pool.IMapIterator.next = wrapper(multiprocessing.pool.IMapIterator.next)
  880. return multiprocessing.Pool(*args, **kwargs)
  881. def exec_flat_python_func(func, *args, **kwargs):
  882. """Execute a flat python function (defined with def funcname(args):...)"""
  883. # Prepare a small piece of python code which calls the requested function
  884. # To do this we need to prepare two things - a set of variables we can use to pass
  885. # the values of arguments into the calling function, and the list of arguments for
  886. # the function being called
  887. context = {}
  888. funcargs = []
  889. # Handle unnamed arguments
  890. aidx = 1
  891. for arg in args:
  892. argname = 'arg_%s' % aidx
  893. context[argname] = arg
  894. funcargs.append(argname)
  895. aidx += 1
  896. # Handle keyword arguments
  897. context.update(kwargs)
  898. funcargs.extend(['%s=%s' % (arg, arg) for arg in kwargs.iterkeys()])
  899. code = 'retval = %s(%s)' % (func, ', '.join(funcargs))
  900. comp = bb.utils.better_compile(code, '<string>', '<string>')
  901. bb.utils.better_exec(comp, context, code, '<string>')
  902. return context['retval']
  903. def edit_metadata(meta_lines, variables, varfunc, match_overrides=False):
  904. """Edit lines from a recipe or config file and modify one or more
  905. specified variable values set in the file using a specified callback
  906. function. Lines are expected to have trailing newlines.
  907. Parameters:
  908. meta_lines: lines from the file; can be a list or an iterable
  909. (e.g. file pointer)
  910. variables: a list of variable names to look for. Functions
  911. may also be specified, but must be specified with '()' at
  912. the end of the name. Note that the function doesn't have
  913. any intrinsic understanding of _append, _prepend, _remove,
  914. or overrides, so these are considered as part of the name.
  915. These values go into a regular expression, so regular
  916. expression syntax is allowed.
  917. varfunc: callback function called for every variable matching
  918. one of the entries in the variables parameter. The function
  919. should take four arguments:
  920. varname: name of variable matched
  921. origvalue: current value in file
  922. op: the operator (e.g. '+=')
  923. newlines: list of lines up to this point. You can use
  924. this to prepend lines before this variable setting
  925. if you wish.
  926. and should return a three-element tuple:
  927. newvalue: new value to substitute in, or None to drop
  928. the variable setting entirely. (If the removal
  929. results in two consecutive blank lines, one of the
  930. blank lines will also be dropped).
  931. newop: the operator to use - if you specify None here,
  932. the original operation will be used.
  933. indent: number of spaces to indent multi-line entries,
  934. or -1 to indent up to the level of the assignment
  935. and opening quote, or a string to use as the indent.
  936. minbreak: True to allow the first element of a
  937. multi-line value to continue on the same line as
  938. the assignment, False to indent before the first
  939. element.
  940. match_overrides: True to match items with _overrides on the end,
  941. False otherwise
  942. Returns a tuple:
  943. updated:
  944. True if changes were made, False otherwise.
  945. newlines:
  946. Lines after processing
  947. """
  948. var_res = {}
  949. if match_overrides:
  950. override_re = '(_[a-zA-Z0-9-_$(){}]+)?'
  951. else:
  952. override_re = ''
  953. for var in variables:
  954. if var.endswith('()'):
  955. var_res[var] = re.compile('^(%s%s)[ \\t]*\([ \\t]*\)[ \\t]*{' % (var[:-2].rstrip(), override_re))
  956. else:
  957. var_res[var] = re.compile('^(%s%s)[ \\t]*[?+:.]*=[+.]*[ \\t]*(["\'])' % (var, override_re))
  958. updated = False
  959. varset_start = ''
  960. varlines = []
  961. newlines = []
  962. in_var = None
  963. full_value = ''
  964. var_end = ''
  965. def handle_var_end():
  966. prerun_newlines = newlines[:]
  967. op = varset_start[len(in_var):].strip()
  968. (newvalue, newop, indent, minbreak) = varfunc(in_var, full_value, op, newlines)
  969. changed = (prerun_newlines != newlines)
  970. if newvalue is None:
  971. # Drop the value
  972. return True
  973. elif newvalue != full_value or (newop not in [None, op]):
  974. if newop not in [None, op]:
  975. # Callback changed the operator
  976. varset_new = "%s %s" % (in_var, newop)
  977. else:
  978. varset_new = varset_start
  979. if isinstance(indent, (int, long)):
  980. if indent == -1:
  981. indentspc = ' ' * (len(varset_new) + 2)
  982. else:
  983. indentspc = ' ' * indent
  984. else:
  985. indentspc = indent
  986. if in_var.endswith('()'):
  987. # A function definition
  988. if isinstance(newvalue, list):
  989. newlines.append('%s {\n%s%s\n}\n' % (varset_new, indentspc, ('\n%s' % indentspc).join(newvalue)))
  990. else:
  991. if not newvalue.startswith('\n'):
  992. newvalue = '\n' + newvalue
  993. if not newvalue.endswith('\n'):
  994. newvalue = newvalue + '\n'
  995. newlines.append('%s {%s}\n' % (varset_new, newvalue))
  996. else:
  997. # Normal variable
  998. if isinstance(newvalue, list):
  999. if not newvalue:
  1000. # Empty list -> empty string
  1001. newlines.append('%s ""\n' % varset_new)
  1002. elif minbreak:
  1003. # First item on first line
  1004. if len(newvalue) == 1:
  1005. newlines.append('%s "%s"\n' % (varset_new, newvalue[0]))
  1006. else:
  1007. newlines.append('%s "%s \\\n' % (varset_new, newvalue[0]))
  1008. for item in newvalue[1:]:
  1009. newlines.append('%s%s \\\n' % (indentspc, item))
  1010. newlines.append('%s"\n' % indentspc)
  1011. else:
  1012. # No item on first line
  1013. newlines.append('%s " \\\n' % varset_new)
  1014. for item in newvalue:
  1015. newlines.append('%s%s \\\n' % (indentspc, item))
  1016. newlines.append('%s"\n' % indentspc)
  1017. else:
  1018. newlines.append('%s "%s"\n' % (varset_new, newvalue))
  1019. return True
  1020. else:
  1021. # Put the old lines back where they were
  1022. newlines.extend(varlines)
  1023. # If newlines was touched by the function, we'll need to return True
  1024. return changed
  1025. checkspc = False
  1026. for line in meta_lines:
  1027. if in_var:
  1028. value = line.rstrip()
  1029. varlines.append(line)
  1030. if in_var.endswith('()'):
  1031. full_value += '\n' + value
  1032. else:
  1033. full_value += value[:-1]
  1034. if value.endswith(var_end):
  1035. if in_var.endswith('()'):
  1036. if full_value.count('{') - full_value.count('}') >= 0:
  1037. continue
  1038. full_value = full_value[:-1]
  1039. if handle_var_end():
  1040. updated = True
  1041. checkspc = True
  1042. in_var = None
  1043. else:
  1044. skip = False
  1045. for (varname, var_re) in var_res.iteritems():
  1046. res = var_re.match(line)
  1047. if res:
  1048. isfunc = varname.endswith('()')
  1049. if isfunc:
  1050. splitvalue = line.split('{', 1)
  1051. var_end = '}'
  1052. else:
  1053. var_end = res.groups()[-1]
  1054. splitvalue = line.split(var_end, 1)
  1055. varset_start = splitvalue[0].rstrip()
  1056. value = splitvalue[1].rstrip()
  1057. if not isfunc and value.endswith('\\'):
  1058. value = value[:-1]
  1059. full_value = value
  1060. varlines = [line]
  1061. in_var = res.group(1)
  1062. if isfunc:
  1063. in_var += '()'
  1064. if value.endswith(var_end):
  1065. full_value = full_value[:-1]
  1066. if handle_var_end():
  1067. updated = True
  1068. checkspc = True
  1069. in_var = None
  1070. skip = True
  1071. break
  1072. if not skip:
  1073. if checkspc:
  1074. checkspc = False
  1075. if newlines and newlines[-1] == '\n' and line == '\n':
  1076. # Squash blank line if there are two consecutive blanks after a removal
  1077. continue
  1078. newlines.append(line)
  1079. return (updated, newlines)
  1080. def edit_metadata_file(meta_file, variables, varfunc):
  1081. """Edit a recipe or config file and modify one or more specified
  1082. variable values set in the file using a specified callback function.
  1083. The file is only written to if the value(s) actually change.
  1084. This is basically the file version of edit_metadata(), see that
  1085. function's description for parameter/usage information.
  1086. Returns True if the file was written to, False otherwise.
  1087. """
  1088. with open(meta_file, 'r') as f:
  1089. (updated, newlines) = edit_metadata(f, variables, varfunc)
  1090. if updated:
  1091. with open(meta_file, 'w') as f:
  1092. f.writelines(newlines)
  1093. return updated
  1094. def edit_bblayers_conf(bblayers_conf, add, remove):
  1095. """Edit bblayers.conf, adding and/or removing layers
  1096. Parameters:
  1097. bblayers_conf: path to bblayers.conf file to edit
  1098. add: layer path (or list of layer paths) to add; None or empty
  1099. list to add nothing
  1100. remove: layer path (or list of layer paths) to remove; None or
  1101. empty list to remove nothing
  1102. Returns a tuple:
  1103. notadded: list of layers specified to be added but weren't
  1104. (because they were already in the list)
  1105. notremoved: list of layers that were specified to be removed
  1106. but weren't (because they weren't in the list)
  1107. """
  1108. import fnmatch
  1109. def remove_trailing_sep(pth):
  1110. if pth and pth[-1] == os.sep:
  1111. pth = pth[:-1]
  1112. return pth
  1113. approved = bb.utils.approved_variables()
  1114. def canonicalise_path(pth):
  1115. pth = remove_trailing_sep(pth)
  1116. if 'HOME' in approved and '~' in pth:
  1117. pth = os.path.expanduser(pth)
  1118. return pth
  1119. def layerlist_param(value):
  1120. if not value:
  1121. return []
  1122. elif isinstance(value, list):
  1123. return [remove_trailing_sep(x) for x in value]
  1124. else:
  1125. return [remove_trailing_sep(value)]
  1126. addlayers = layerlist_param(add)
  1127. removelayers = layerlist_param(remove)
  1128. # Need to use a list here because we can't set non-local variables from a callback in python 2.x
  1129. bblayercalls = []
  1130. removed = []
  1131. plusequals = False
  1132. orig_bblayers = []
  1133. def handle_bblayers_firstpass(varname, origvalue, op, newlines):
  1134. bblayercalls.append(op)
  1135. if op == '=':
  1136. del orig_bblayers[:]
  1137. orig_bblayers.extend([canonicalise_path(x) for x in origvalue.split()])
  1138. return (origvalue, None, 2, False)
  1139. def handle_bblayers(varname, origvalue, op, newlines):
  1140. updated = False
  1141. bblayers = [remove_trailing_sep(x) for x in origvalue.split()]
  1142. if removelayers:
  1143. for removelayer in removelayers:
  1144. for layer in bblayers:
  1145. if fnmatch.fnmatch(canonicalise_path(layer), canonicalise_path(removelayer)):
  1146. updated = True
  1147. bblayers.remove(layer)
  1148. removed.append(removelayer)
  1149. break
  1150. if addlayers and not plusequals:
  1151. for addlayer in addlayers:
  1152. if addlayer not in bblayers:
  1153. updated = True
  1154. bblayers.append(addlayer)
  1155. del addlayers[:]
  1156. if updated:
  1157. if op == '+=' and not bblayers:
  1158. bblayers = None
  1159. return (bblayers, None, 2, False)
  1160. else:
  1161. return (origvalue, None, 2, False)
  1162. with open(bblayers_conf, 'r') as f:
  1163. (_, newlines) = edit_metadata(f, ['BBLAYERS'], handle_bblayers_firstpass)
  1164. if not bblayercalls:
  1165. raise Exception('Unable to find BBLAYERS in %s' % bblayers_conf)
  1166. # Try to do the "smart" thing depending on how the user has laid out
  1167. # their bblayers.conf file
  1168. if bblayercalls.count('+=') > 1:
  1169. plusequals = True
  1170. removelayers_canon = [canonicalise_path(layer) for layer in removelayers]
  1171. notadded = []
  1172. for layer in addlayers:
  1173. layer_canon = canonicalise_path(layer)
  1174. if layer_canon in orig_bblayers and not layer_canon in removelayers_canon:
  1175. notadded.append(layer)
  1176. notadded_canon = [canonicalise_path(layer) for layer in notadded]
  1177. addlayers[:] = [layer for layer in addlayers if canonicalise_path(layer) not in notadded_canon]
  1178. (updated, newlines) = edit_metadata(newlines, ['BBLAYERS'], handle_bblayers)
  1179. if addlayers:
  1180. # Still need to add these
  1181. for addlayer in addlayers:
  1182. newlines.append('BBLAYERS += "%s"\n' % addlayer)
  1183. updated = True
  1184. if updated:
  1185. with open(bblayers_conf, 'w') as f:
  1186. f.writelines(newlines)
  1187. notremoved = list(set(removelayers) - set(removed))
  1188. return (notadded, notremoved)
  1189. def get_file_layer(filename, d):
  1190. """Determine the collection (as defined by a layer's layer.conf file) containing the specified file"""
  1191. collections = (d.getVar('BBFILE_COLLECTIONS', True) or '').split()
  1192. collection_res = {}
  1193. for collection in collections:
  1194. collection_res[collection] = d.getVar('BBFILE_PATTERN_%s' % collection, True) or ''
  1195. def path_to_layer(path):
  1196. # Use longest path so we handle nested layers
  1197. matchlen = 0
  1198. match = None
  1199. for collection, regex in collection_res.iteritems():
  1200. if len(regex) > matchlen and re.match(regex, path):
  1201. matchlen = len(regex)
  1202. match = collection
  1203. return match
  1204. result = None
  1205. bbfiles = (d.getVar('BBFILES', True) or '').split()
  1206. bbfilesmatch = False
  1207. for bbfilesentry in bbfiles:
  1208. if fnmatch.fnmatch(filename, bbfilesentry):
  1209. bbfilesmatch = True
  1210. result = path_to_layer(bbfilesentry)
  1211. if not bbfilesmatch:
  1212. # Probably a bbclass
  1213. result = path_to_layer(filename)
  1214. return result
  1215. # Constant taken from http://linux.die.net/include/linux/prctl.h
  1216. PR_SET_PDEATHSIG = 1
  1217. class PrCtlError(Exception):
  1218. pass
  1219. def signal_on_parent_exit(signame):
  1220. """
  1221. Trigger signame to be sent when the parent process dies
  1222. """
  1223. signum = getattr(signal, signame)
  1224. # http://linux.die.net/man/2/prctl
  1225. result = cdll['libc.so.6'].prctl(PR_SET_PDEATHSIG, signum)
  1226. if result != 0:
  1227. raise PrCtlError('prctl failed with error code %s' % result)
  1228. #
  1229. # Manually call the ioprio syscall. We could depend on other libs like psutil
  1230. # however this gets us enough of what we need to bitbake for now without the
  1231. # dependency
  1232. #
  1233. _unamearch = os.uname()[4]
  1234. IOPRIO_WHO_PROCESS = 1
  1235. IOPRIO_CLASS_SHIFT = 13
  1236. def ioprio_set(who, cls, value):
  1237. NR_ioprio_set = None
  1238. if _unamearch == "x86_64":
  1239. NR_ioprio_set = 251
  1240. elif _unamearch[0] == "i" and _unamearch[2:3] == "86":
  1241. NR_ioprio_set = 289
  1242. if NR_ioprio_set:
  1243. ioprio = value | (cls << IOPRIO_CLASS_SHIFT)
  1244. rc = cdll['libc.so.6'].syscall(NR_ioprio_set, IOPRIO_WHO_PROCESS, who, ioprio)
  1245. if rc != 0:
  1246. raise ValueError("Unable to set ioprio, syscall returned %s" % rc)
  1247. else:
  1248. bb.warn("Unable to set IO Prio for arch %s" % _unamearch)