1eb8dc403SDave Cobbley# 2eb8dc403SDave Cobbley# BitBake Build System Python Library 3eb8dc403SDave Cobbley# 4eb8dc403SDave Cobbley# Copyright (C) 2003 Holger Schurig 5eb8dc403SDave Cobbley# Copyright (C) 2003, 2004 Chris Larson 6eb8dc403SDave Cobbley# 7eb8dc403SDave Cobbley# Based on Gentoo's portage.py. 8eb8dc403SDave Cobbley# 9c342db35SBrad Bishop# SPDX-License-Identifier: GPL-2.0-only 10eb8dc403SDave Cobbley# 11eb8dc403SDave Cobbley 12*2f814a6dSPatrick Williams__version__ = "2.9.0" 13eb8dc403SDave Cobbley 14eb8dc403SDave Cobbleyimport sys 15517393d9SAndrew Geisslerif sys.version_info < (3, 8, 0): 16517393d9SAndrew Geissler raise RuntimeError("Sorry, python 3.8.0 or later is required for this version of bitbake") 17eb8dc403SDave Cobbley 18169d7bccSPatrick Williamsif sys.version_info < (3, 10, 0): 19169d7bccSPatrick Williams # With python 3.8 and 3.9, we see errors of "libgcc_s.so.1 must be installed for pthread_cancel to work" 20169d7bccSPatrick Williams # https://stackoverflow.com/questions/64797838/libgcc-s-so-1-must-be-installed-for-pthread-cancel-to-work 21169d7bccSPatrick Williams # https://bugs.ams1.psf.io/issue42888 22169d7bccSPatrick Williams # so ensure libgcc_s is loaded early on 23169d7bccSPatrick Williams import ctypes 24169d7bccSPatrick Williams libgcc_s = ctypes.CDLL('libgcc_s.so.1') 25eb8dc403SDave Cobbley 26eb8dc403SDave Cobbleyclass BBHandledException(Exception): 27eb8dc403SDave Cobbley """ 28eb8dc403SDave Cobbley The big dilemma for generic bitbake code is what information to give the user 29eb8dc403SDave Cobbley when an exception occurs. Any exception inheriting this base exception class 30eb8dc403SDave Cobbley has already provided information to the user via some 'fired' message type such as 31eb8dc403SDave Cobbley an explicitly fired event using bb.fire, or a bb.error message. If bitbake 32eb8dc403SDave Cobbley encounters an exception derived from this class, no backtrace or other information 33eb8dc403SDave Cobbley will be given to the user, its assumed the earlier event provided the relevant information. 34eb8dc403SDave Cobbley """ 35eb8dc403SDave Cobbley pass 36eb8dc403SDave Cobbley 37eb8dc403SDave Cobbleyimport os 38eb8dc403SDave Cobbleyimport logging 39eb8dc403SDave Cobbley 40eb8dc403SDave Cobbley 41eb8dc403SDave Cobbleyclass NullHandler(logging.Handler): 42eb8dc403SDave Cobbley def emit(self, record): 43eb8dc403SDave Cobbley pass 44eb8dc403SDave Cobbley 455a43b434SAndrew Geisslerclass BBLoggerMixin(object): 465a43b434SAndrew Geissler def __init__(self, *args, **kwargs): 475a43b434SAndrew Geissler # Does nothing to allow calling super() from derived classes 485a43b434SAndrew Geissler pass 495a43b434SAndrew Geissler 505a43b434SAndrew Geissler def setup_bblogger(self, name): 51eb8dc403SDave Cobbley if name.split(".")[0] == "BitBake": 52d1e89497SAndrew Geissler self.debug = self._debug_helper 53d1e89497SAndrew Geissler 54d1e89497SAndrew Geissler def _debug_helper(self, *args, **kwargs): 55d1e89497SAndrew Geissler return self.bbdebug(1, *args, **kwargs) 56d1e89497SAndrew Geissler 57d1e89497SAndrew Geissler def debug2(self, *args, **kwargs): 58d1e89497SAndrew Geissler return self.bbdebug(2, *args, **kwargs) 59d1e89497SAndrew Geissler 60d1e89497SAndrew Geissler def debug3(self, *args, **kwargs): 61d1e89497SAndrew Geissler return self.bbdebug(3, *args, **kwargs) 62eb8dc403SDave Cobbley 63eb8dc403SDave Cobbley def bbdebug(self, level, msg, *args, **kwargs): 6482c905dcSAndrew Geissler loglevel = logging.DEBUG - level + 1 6582c905dcSAndrew Geissler if not bb.event.worker_pid: 6682c905dcSAndrew Geissler if self.name in bb.msg.loggerDefaultDomains and loglevel > (bb.msg.loggerDefaultDomains[self.name]): 6782c905dcSAndrew Geissler return 6895ac1b8dSAndrew Geissler if loglevel < bb.msg.loggerDefaultLogLevel: 6982c905dcSAndrew Geissler return 7087f5cff0SAndrew Geissler 7187f5cff0SAndrew Geissler if not isinstance(level, int) or not isinstance(msg, str): 7287f5cff0SAndrew Geissler mainlogger.warning("Invalid arguments in bbdebug: %s" % repr((level, msg,) + args)) 7387f5cff0SAndrew Geissler 7482c905dcSAndrew Geissler return self.log(loglevel, msg, *args, **kwargs) 75eb8dc403SDave Cobbley 76eb8dc403SDave Cobbley def plain(self, msg, *args, **kwargs): 77eb8dc403SDave Cobbley return self.log(logging.INFO + 1, msg, *args, **kwargs) 78eb8dc403SDave Cobbley 79eb8dc403SDave Cobbley def verbose(self, msg, *args, **kwargs): 80eb8dc403SDave Cobbley return self.log(logging.INFO - 1, msg, *args, **kwargs) 81eb8dc403SDave Cobbley 821a4b7ee2SBrad Bishop def verbnote(self, msg, *args, **kwargs): 831a4b7ee2SBrad Bishop return self.log(logging.INFO + 2, msg, *args, **kwargs) 841a4b7ee2SBrad Bishop 857e0e3c0cSAndrew Geissler def warnonce(self, msg, *args, **kwargs): 867e0e3c0cSAndrew Geissler return self.log(logging.WARNING - 1, msg, *args, **kwargs) 877e0e3c0cSAndrew Geissler 887e0e3c0cSAndrew Geissler def erroronce(self, msg, *args, **kwargs): 897e0e3c0cSAndrew Geissler return self.log(logging.ERROR - 1, msg, *args, **kwargs) 907e0e3c0cSAndrew Geissler 917e0e3c0cSAndrew Geissler 925a43b434SAndrew GeisslerLogger = logging.getLoggerClass() 935a43b434SAndrew Geisslerclass BBLogger(Logger, BBLoggerMixin): 945a43b434SAndrew Geissler def __init__(self, name, *args, **kwargs): 955a43b434SAndrew Geissler self.setup_bblogger(name) 965a43b434SAndrew Geissler super().__init__(name, *args, **kwargs) 971a4b7ee2SBrad Bishop 98eb8dc403SDave Cobbleylogging.raiseExceptions = False 99eb8dc403SDave Cobbleylogging.setLoggerClass(BBLogger) 100eb8dc403SDave Cobbley 1015a43b434SAndrew Geisslerclass BBLoggerAdapter(logging.LoggerAdapter, BBLoggerMixin): 1025a43b434SAndrew Geissler def __init__(self, logger, *args, **kwargs): 1035a43b434SAndrew Geissler self.setup_bblogger(logger.name) 1045a43b434SAndrew Geissler super().__init__(logger, *args, **kwargs) 1055a43b434SAndrew Geissler 1065a43b434SAndrew Geissler if sys.version_info < (3, 6): 1075a43b434SAndrew Geissler # These properties were added in Python 3.6. Add them in older versions 1085a43b434SAndrew Geissler # for compatibility 1095a43b434SAndrew Geissler @property 1105a43b434SAndrew Geissler def manager(self): 1115a43b434SAndrew Geissler return self.logger.manager 1125a43b434SAndrew Geissler 1135a43b434SAndrew Geissler @manager.setter 1145a43b434SAndrew Geissler def manager(self, value): 1155a43b434SAndrew Geissler self.logger.manager = value 1165a43b434SAndrew Geissler 1175a43b434SAndrew Geissler @property 1185a43b434SAndrew Geissler def name(self): 1195a43b434SAndrew Geissler return self.logger.name 1205a43b434SAndrew Geissler 1215a43b434SAndrew Geissler def __repr__(self): 1225a43b434SAndrew Geissler logger = self.logger 123c9f7865aSAndrew Geissler level = logger.getLevelName(logger.getEffectiveLevel()) 1245a43b434SAndrew Geissler return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level) 1255a43b434SAndrew Geissler 1265a43b434SAndrew Geisslerlogging.LoggerAdapter = BBLoggerAdapter 1275a43b434SAndrew Geissler 128eb8dc403SDave Cobbleylogger = logging.getLogger("BitBake") 129eb8dc403SDave Cobbleylogger.addHandler(NullHandler()) 130eb8dc403SDave Cobbleylogger.setLevel(logging.DEBUG - 2) 131eb8dc403SDave Cobbley 132eb8dc403SDave Cobbleymainlogger = logging.getLogger("BitBake.Main") 133eb8dc403SDave Cobbley 1345a43b434SAndrew Geisslerclass PrefixLoggerAdapter(logging.LoggerAdapter): 1355a43b434SAndrew Geissler def __init__(self, prefix, logger): 1365a43b434SAndrew Geissler super().__init__(logger, {}) 1375a43b434SAndrew Geissler self.__msg_prefix = prefix 1385a43b434SAndrew Geissler 1395a43b434SAndrew Geissler def process(self, msg, kwargs): 1405a43b434SAndrew Geissler return "%s%s" %(self.__msg_prefix, msg), kwargs 1415a43b434SAndrew Geissler 142eb8dc403SDave Cobbley# This has to be imported after the setLoggerClass, as the import of bb.msg 143eb8dc403SDave Cobbley# can result in construction of the various loggers. 144eb8dc403SDave Cobbleyimport bb.msg 145eb8dc403SDave Cobbley 146eb8dc403SDave Cobbleyfrom bb import fetch2 as fetch 147eb8dc403SDave Cobbleysys.modules['bb.fetch'] = sys.modules['bb.fetch2'] 148eb8dc403SDave Cobbley 149eb8dc403SDave Cobbley# Messaging convenience functions 150eb8dc403SDave Cobbleydef plain(*args): 151eb8dc403SDave Cobbley mainlogger.plain(''.join(args)) 152eb8dc403SDave Cobbley 153eb8dc403SDave Cobbleydef debug(lvl, *args): 154eb8dc403SDave Cobbley if isinstance(lvl, str): 155eb8dc403SDave Cobbley mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl) 156eb8dc403SDave Cobbley args = (lvl,) + args 157eb8dc403SDave Cobbley lvl = 1 158d1e89497SAndrew Geissler mainlogger.bbdebug(lvl, ''.join(args)) 159eb8dc403SDave Cobbley 160eb8dc403SDave Cobbleydef note(*args): 161eb8dc403SDave Cobbley mainlogger.info(''.join(args)) 162eb8dc403SDave Cobbley 1631a4b7ee2SBrad Bishop# 1641a4b7ee2SBrad Bishop# A higher prioity note which will show on the console but isn't a warning 1651a4b7ee2SBrad Bishop# 1661a4b7ee2SBrad Bishop# Something is happening the user should be aware of but they probably did 1671a4b7ee2SBrad Bishop# something to make it happen 1681a4b7ee2SBrad Bishop# 1691a4b7ee2SBrad Bishopdef verbnote(*args): 1701a4b7ee2SBrad Bishop mainlogger.verbnote(''.join(args)) 1711a4b7ee2SBrad Bishop 1721a4b7ee2SBrad Bishop# 1731a4b7ee2SBrad Bishop# Warnings - things the user likely needs to pay attention to and fix 1741a4b7ee2SBrad Bishop# 175eb8dc403SDave Cobbleydef warn(*args): 176eb8dc403SDave Cobbley mainlogger.warning(''.join(args)) 177eb8dc403SDave Cobbley 1787e0e3c0cSAndrew Geisslerdef warnonce(*args): 1797e0e3c0cSAndrew Geissler mainlogger.warnonce(''.join(args)) 1807e0e3c0cSAndrew Geissler 181eb8dc403SDave Cobbleydef error(*args, **kwargs): 182eb8dc403SDave Cobbley mainlogger.error(''.join(args), extra=kwargs) 183eb8dc403SDave Cobbley 1847e0e3c0cSAndrew Geisslerdef erroronce(*args): 1857e0e3c0cSAndrew Geissler mainlogger.erroronce(''.join(args)) 1867e0e3c0cSAndrew Geissler 187eb8dc403SDave Cobbleydef fatal(*args, **kwargs): 188eb8dc403SDave Cobbley mainlogger.critical(''.join(args), extra=kwargs) 189eb8dc403SDave Cobbley raise BBHandledException() 190eb8dc403SDave Cobbley 191eb8dc403SDave Cobbleydef deprecated(func, name=None, advice=""): 192eb8dc403SDave Cobbley """This is a decorator which can be used to mark functions 193eb8dc403SDave Cobbley as deprecated. It will result in a warning being emitted 194eb8dc403SDave Cobbley when the function is used.""" 195eb8dc403SDave Cobbley import warnings 196eb8dc403SDave Cobbley 197eb8dc403SDave Cobbley if advice: 198eb8dc403SDave Cobbley advice = ": %s" % advice 199eb8dc403SDave Cobbley if name is None: 200eb8dc403SDave Cobbley name = func.__name__ 201eb8dc403SDave Cobbley 202eb8dc403SDave Cobbley def newFunc(*args, **kwargs): 203eb8dc403SDave Cobbley warnings.warn("Call to deprecated function %s%s." % (name, 204eb8dc403SDave Cobbley advice), 205eb8dc403SDave Cobbley category=DeprecationWarning, 206eb8dc403SDave Cobbley stacklevel=2) 207eb8dc403SDave Cobbley return func(*args, **kwargs) 208eb8dc403SDave Cobbley newFunc.__name__ = func.__name__ 209eb8dc403SDave Cobbley newFunc.__doc__ = func.__doc__ 210eb8dc403SDave Cobbley newFunc.__dict__.update(func.__dict__) 211eb8dc403SDave Cobbley return newFunc 212eb8dc403SDave Cobbley 213eb8dc403SDave Cobbley# For compatibility 214eb8dc403SDave Cobbleydef deprecate_import(current, modulename, fromlist, renames = None): 215eb8dc403SDave Cobbley """Import objects from one module into another, wrapping them with a DeprecationWarning""" 216eb8dc403SDave Cobbley import sys 217eb8dc403SDave Cobbley 218eb8dc403SDave Cobbley module = __import__(modulename, fromlist = fromlist) 219eb8dc403SDave Cobbley for position, objname in enumerate(fromlist): 220eb8dc403SDave Cobbley obj = getattr(module, objname) 221eb8dc403SDave Cobbley newobj = deprecated(obj, "{0}.{1}".format(current, objname), 222eb8dc403SDave Cobbley "Please use {0}.{1} instead".format(modulename, objname)) 223eb8dc403SDave Cobbley if renames: 224eb8dc403SDave Cobbley newname = renames[position] 225eb8dc403SDave Cobbley else: 226eb8dc403SDave Cobbley newname = objname 227eb8dc403SDave Cobbley 228eb8dc403SDave Cobbley setattr(sys.modules[current], newname, newobj) 229eb8dc403SDave Cobbley 230