__init__.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #
  2. # BitBake Build System Python Library
  3. #
  4. # Copyright (C) 2003 Holger Schurig
  5. # Copyright (C) 2003, 2004 Chris Larson
  6. #
  7. # Based on Gentoo's portage.py.
  8. #
  9. # SPDX-License-Identifier: GPL-2.0-only
  10. #
  11. __version__ = "2.12.0"
  12. import sys
  13. if sys.version_info < (3, 9, 0):
  14. raise RuntimeError("Sorry, python 3.9.0 or later is required for this version of bitbake")
  15. if sys.version_info < (3, 10, 0):
  16. # With python 3.8 and 3.9, we see errors of "libgcc_s.so.1 must be installed for pthread_cancel to work"
  17. # https://stackoverflow.com/questions/64797838/libgcc-s-so-1-must-be-installed-for-pthread-cancel-to-work
  18. # https://bugs.ams1.psf.io/issue42888
  19. # so ensure libgcc_s is loaded early on
  20. import ctypes
  21. libgcc_s = ctypes.CDLL('libgcc_s.so.1')
  22. class BBHandledException(Exception):
  23. """
  24. The big dilemma for generic bitbake code is what information to give the user
  25. when an exception occurs. Any exception inheriting this base exception class
  26. has already provided information to the user via some 'fired' message type such as
  27. an explicitly fired event using bb.fire, or a bb.error message. If bitbake
  28. encounters an exception derived from this class, no backtrace or other information
  29. will be given to the user, its assumed the earlier event provided the relevant information.
  30. """
  31. pass
  32. import os
  33. import logging
  34. from collections import namedtuple
  35. class NullHandler(logging.Handler):
  36. def emit(self, record):
  37. pass
  38. class BBLoggerMixin(object):
  39. def __init__(self, *args, **kwargs):
  40. # Does nothing to allow calling super() from derived classes
  41. pass
  42. def setup_bblogger(self, name):
  43. if name.split(".")[0] == "BitBake":
  44. self.debug = self._debug_helper
  45. def _debug_helper(self, *args, **kwargs):
  46. return self.bbdebug(1, *args, **kwargs)
  47. def debug2(self, *args, **kwargs):
  48. return self.bbdebug(2, *args, **kwargs)
  49. def debug3(self, *args, **kwargs):
  50. return self.bbdebug(3, *args, **kwargs)
  51. def bbdebug(self, level, msg, *args, **kwargs):
  52. loglevel = logging.DEBUG - level + 1
  53. if not bb.event.worker_pid:
  54. if self.name in bb.msg.loggerDefaultDomains and loglevel > (bb.msg.loggerDefaultDomains[self.name]):
  55. return
  56. if loglevel < bb.msg.loggerDefaultLogLevel:
  57. return
  58. if not isinstance(level, int) or not isinstance(msg, str):
  59. mainlogger.warning("Invalid arguments in bbdebug: %s" % repr((level, msg,) + args))
  60. return self.log(loglevel, msg, *args, **kwargs)
  61. def plain(self, msg, *args, **kwargs):
  62. return self.log(logging.INFO + 1, msg, *args, **kwargs)
  63. def verbose(self, msg, *args, **kwargs):
  64. return self.log(logging.INFO - 1, msg, *args, **kwargs)
  65. def verbnote(self, msg, *args, **kwargs):
  66. return self.log(logging.INFO + 2, msg, *args, **kwargs)
  67. def warnonce(self, msg, *args, **kwargs):
  68. return self.log(logging.WARNING - 1, msg, *args, **kwargs)
  69. def erroronce(self, msg, *args, **kwargs):
  70. return self.log(logging.ERROR - 1, msg, *args, **kwargs)
  71. Logger = logging.getLoggerClass()
  72. class BBLogger(Logger, BBLoggerMixin):
  73. def __init__(self, name, *args, **kwargs):
  74. self.setup_bblogger(name)
  75. super().__init__(name, *args, **kwargs)
  76. logging.raiseExceptions = False
  77. logging.setLoggerClass(BBLogger)
  78. class BBLoggerAdapter(logging.LoggerAdapter, BBLoggerMixin):
  79. def __init__(self, logger, *args, **kwargs):
  80. self.setup_bblogger(logger.name)
  81. super().__init__(logger, *args, **kwargs)
  82. logging.LoggerAdapter = BBLoggerAdapter
  83. logger = logging.getLogger("BitBake")
  84. logger.addHandler(NullHandler())
  85. logger.setLevel(logging.DEBUG - 2)
  86. mainlogger = logging.getLogger("BitBake.Main")
  87. class PrefixLoggerAdapter(logging.LoggerAdapter):
  88. def __init__(self, prefix, logger):
  89. super().__init__(logger, {})
  90. self.__msg_prefix = prefix
  91. def process(self, msg, kwargs):
  92. return "%s%s" %(self.__msg_prefix, msg), kwargs
  93. # This has to be imported after the setLoggerClass, as the import of bb.msg
  94. # can result in construction of the various loggers.
  95. import bb.msg
  96. from bb import fetch2 as fetch
  97. sys.modules['bb.fetch'] = sys.modules['bb.fetch2']
  98. # Messaging convenience functions
  99. def plain(*args):
  100. mainlogger.plain(''.join(args))
  101. def debug(lvl, *args):
  102. if isinstance(lvl, str):
  103. mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
  104. args = (lvl,) + args
  105. lvl = 1
  106. mainlogger.bbdebug(lvl, ''.join(args))
  107. def note(*args):
  108. mainlogger.info(''.join(args))
  109. #
  110. # A higher prioity note which will show on the console but isn't a warning
  111. #
  112. # Something is happening the user should be aware of but they probably did
  113. # something to make it happen
  114. #
  115. def verbnote(*args):
  116. mainlogger.verbnote(''.join(args))
  117. #
  118. # Warnings - things the user likely needs to pay attention to and fix
  119. #
  120. def warn(*args):
  121. mainlogger.warning(''.join(args))
  122. def warnonce(*args):
  123. mainlogger.warnonce(''.join(args))
  124. def error(*args, **kwargs):
  125. mainlogger.error(''.join(args), extra=kwargs)
  126. def erroronce(*args):
  127. mainlogger.erroronce(''.join(args))
  128. def fatal(*args, **kwargs):
  129. mainlogger.critical(''.join(args), extra=kwargs)
  130. raise BBHandledException()
  131. def deprecated(func, name=None, advice=""):
  132. """This is a decorator which can be used to mark functions
  133. as deprecated. It will result in a warning being emitted
  134. when the function is used."""
  135. import warnings
  136. if advice:
  137. advice = ": %s" % advice
  138. if name is None:
  139. name = func.__name__
  140. def newFunc(*args, **kwargs):
  141. warnings.warn("Call to deprecated function %s%s." % (name,
  142. advice),
  143. category=DeprecationWarning,
  144. stacklevel=2)
  145. return func(*args, **kwargs)
  146. newFunc.__name__ = func.__name__
  147. newFunc.__doc__ = func.__doc__
  148. newFunc.__dict__.update(func.__dict__)
  149. return newFunc
  150. # For compatibility
  151. def deprecate_import(current, modulename, fromlist, renames = None):
  152. """Import objects from one module into another, wrapping them with a DeprecationWarning"""
  153. module = __import__(modulename, fromlist = fromlist)
  154. for position, objname in enumerate(fromlist):
  155. obj = getattr(module, objname)
  156. newobj = deprecated(obj, "{0}.{1}".format(current, objname),
  157. "Please use {0}.{1} instead".format(modulename, objname))
  158. if renames:
  159. newname = renames[position]
  160. else:
  161. newname = objname
  162. setattr(sys.modules[current], newname, newobj)
  163. TaskData = namedtuple("TaskData", [
  164. "pn",
  165. "taskname",
  166. "fn",
  167. "deps",
  168. "provides",
  169. "taskhash",
  170. "unihash",
  171. "hashfn",
  172. "taskhash_deps",
  173. ])