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 12__version__ = "2.0.0" 13 14import sys 15if sys.version_info < (3, 6, 0): 16 raise RuntimeError("Sorry, python 3.6.0 or later is required for this version of bitbake") 17 18 19class BBHandledException(Exception): 20 """ 21 The big dilemma for generic bitbake code is what information to give the user 22 when an exception occurs. Any exception inheriting this base exception class 23 has already provided information to the user via some 'fired' message type such as 24 an explicitly fired event using bb.fire, or a bb.error message. If bitbake 25 encounters an exception derived from this class, no backtrace or other information 26 will be given to the user, its assumed the earlier event provided the relevant information. 27 """ 28 pass 29 30import os 31import logging 32 33 34class NullHandler(logging.Handler): 35 def emit(self, record): 36 pass 37 38class BBLoggerMixin(object): 39 def __init__(self, *args, **kwargs): 40 # Does nothing to allow calling super() from derived classes 41 pass 42 43 def setup_bblogger(self, name): 44 if name.split(".")[0] == "BitBake": 45 self.debug = self._debug_helper 46 47 def _debug_helper(self, *args, **kwargs): 48 return self.bbdebug(1, *args, **kwargs) 49 50 def debug2(self, *args, **kwargs): 51 return self.bbdebug(2, *args, **kwargs) 52 53 def debug3(self, *args, **kwargs): 54 return self.bbdebug(3, *args, **kwargs) 55 56 def bbdebug(self, level, msg, *args, **kwargs): 57 loglevel = logging.DEBUG - level + 1 58 if not bb.event.worker_pid: 59 if self.name in bb.msg.loggerDefaultDomains and loglevel > (bb.msg.loggerDefaultDomains[self.name]): 60 return 61 if loglevel < bb.msg.loggerDefaultLogLevel: 62 return 63 return self.log(loglevel, msg, *args, **kwargs) 64 65 def plain(self, msg, *args, **kwargs): 66 return self.log(logging.INFO + 1, msg, *args, **kwargs) 67 68 def verbose(self, msg, *args, **kwargs): 69 return self.log(logging.INFO - 1, msg, *args, **kwargs) 70 71 def verbnote(self, msg, *args, **kwargs): 72 return self.log(logging.INFO + 2, msg, *args, **kwargs) 73 74 def warnonce(self, msg, *args, **kwargs): 75 return self.log(logging.WARNING - 1, msg, *args, **kwargs) 76 77 def erroronce(self, msg, *args, **kwargs): 78 return self.log(logging.ERROR - 1, msg, *args, **kwargs) 79 80 81Logger = logging.getLoggerClass() 82class BBLogger(Logger, BBLoggerMixin): 83 def __init__(self, name, *args, **kwargs): 84 self.setup_bblogger(name) 85 super().__init__(name, *args, **kwargs) 86 87logging.raiseExceptions = False 88logging.setLoggerClass(BBLogger) 89 90class BBLoggerAdapter(logging.LoggerAdapter, BBLoggerMixin): 91 def __init__(self, logger, *args, **kwargs): 92 self.setup_bblogger(logger.name) 93 super().__init__(logger, *args, **kwargs) 94 95 if sys.version_info < (3, 6): 96 # These properties were added in Python 3.6. Add them in older versions 97 # for compatibility 98 @property 99 def manager(self): 100 return self.logger.manager 101 102 @manager.setter 103 def manager(self, value): 104 self.logger.manager = value 105 106 @property 107 def name(self): 108 return self.logger.name 109 110 def __repr__(self): 111 logger = self.logger 112 level = logger.getLevelName(logger.getEffectiveLevel()) 113 return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level) 114 115logging.LoggerAdapter = BBLoggerAdapter 116 117logger = logging.getLogger("BitBake") 118logger.addHandler(NullHandler()) 119logger.setLevel(logging.DEBUG - 2) 120 121mainlogger = logging.getLogger("BitBake.Main") 122 123class PrefixLoggerAdapter(logging.LoggerAdapter): 124 def __init__(self, prefix, logger): 125 super().__init__(logger, {}) 126 self.__msg_prefix = prefix 127 128 def process(self, msg, kwargs): 129 return "%s%s" %(self.__msg_prefix, msg), kwargs 130 131# This has to be imported after the setLoggerClass, as the import of bb.msg 132# can result in construction of the various loggers. 133import bb.msg 134 135from bb import fetch2 as fetch 136sys.modules['bb.fetch'] = sys.modules['bb.fetch2'] 137 138# Messaging convenience functions 139def plain(*args): 140 mainlogger.plain(''.join(args)) 141 142def debug(lvl, *args): 143 if isinstance(lvl, str): 144 mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl) 145 args = (lvl,) + args 146 lvl = 1 147 mainlogger.bbdebug(lvl, ''.join(args)) 148 149def note(*args): 150 mainlogger.info(''.join(args)) 151 152# 153# A higher prioity note which will show on the console but isn't a warning 154# 155# Something is happening the user should be aware of but they probably did 156# something to make it happen 157# 158def verbnote(*args): 159 mainlogger.verbnote(''.join(args)) 160 161# 162# Warnings - things the user likely needs to pay attention to and fix 163# 164def warn(*args): 165 mainlogger.warning(''.join(args)) 166 167def warnonce(*args): 168 mainlogger.warnonce(''.join(args)) 169 170def error(*args, **kwargs): 171 mainlogger.error(''.join(args), extra=kwargs) 172 173def erroronce(*args): 174 mainlogger.erroronce(''.join(args)) 175 176def fatal(*args, **kwargs): 177 mainlogger.critical(''.join(args), extra=kwargs) 178 raise BBHandledException() 179 180def deprecated(func, name=None, advice=""): 181 """This is a decorator which can be used to mark functions 182 as deprecated. It will result in a warning being emitted 183 when the function is used.""" 184 import warnings 185 186 if advice: 187 advice = ": %s" % advice 188 if name is None: 189 name = func.__name__ 190 191 def newFunc(*args, **kwargs): 192 warnings.warn("Call to deprecated function %s%s." % (name, 193 advice), 194 category=DeprecationWarning, 195 stacklevel=2) 196 return func(*args, **kwargs) 197 newFunc.__name__ = func.__name__ 198 newFunc.__doc__ = func.__doc__ 199 newFunc.__dict__.update(func.__dict__) 200 return newFunc 201 202# For compatibility 203def deprecate_import(current, modulename, fromlist, renames = None): 204 """Import objects from one module into another, wrapping them with a DeprecationWarning""" 205 import sys 206 207 module = __import__(modulename, fromlist = fromlist) 208 for position, objname in enumerate(fromlist): 209 obj = getattr(module, objname) 210 newobj = deprecated(obj, "{0}.{1}".format(current, objname), 211 "Please use {0}.{1} instead".format(modulename, objname)) 212 if renames: 213 newname = renames[position] 214 else: 215 newname = objname 216 217 setattr(sys.modules[current], newname, newobj) 218 219