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__ = "1.47.0" 13 14import sys 15if sys.version_info < (3, 5, 0): 16 raise RuntimeError("Sorry, python 3.5.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.bbdebug 46 47 def bbdebug(self, level, msg, *args, **kwargs): 48 loglevel = logging.DEBUG - level + 1 49 if not bb.event.worker_pid: 50 if self.name in bb.msg.loggerDefaultDomains and loglevel > (bb.msg.loggerDefaultDomains[self.name]): 51 return 52 if loglevel > bb.msg.loggerDefaultLogLevel: 53 return 54 return self.log(loglevel, msg, *args, **kwargs) 55 56 def plain(self, msg, *args, **kwargs): 57 return self.log(logging.INFO + 1, msg, *args, **kwargs) 58 59 def verbose(self, msg, *args, **kwargs): 60 return self.log(logging.INFO - 1, msg, *args, **kwargs) 61 62 def verbnote(self, msg, *args, **kwargs): 63 return self.log(logging.INFO + 2, msg, *args, **kwargs) 64 65Logger = logging.getLoggerClass() 66class BBLogger(Logger, BBLoggerMixin): 67 def __init__(self, name, *args, **kwargs): 68 self.setup_bblogger(name) 69 super().__init__(name, *args, **kwargs) 70 71logging.raiseExceptions = False 72logging.setLoggerClass(BBLogger) 73 74class BBLoggerAdapter(logging.LoggerAdapter, BBLoggerMixin): 75 def __init__(self, logger, *args, **kwargs): 76 self.setup_bblogger(logger.name) 77 super().__init__(logger, *args, **kwargs) 78 79 if sys.version_info < (3, 6): 80 # These properties were added in Python 3.6. Add them in older versions 81 # for compatibility 82 @property 83 def manager(self): 84 return self.logger.manager 85 86 @manager.setter 87 def manager(self, value): 88 self.logger.manager = value 89 90 @property 91 def name(self): 92 return self.logger.name 93 94 def __repr__(self): 95 logger = self.logger 96 level = getLevelName(logger.getEffectiveLevel()) 97 return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level) 98 99logging.LoggerAdapter = BBLoggerAdapter 100 101logger = logging.getLogger("BitBake") 102logger.addHandler(NullHandler()) 103logger.setLevel(logging.DEBUG - 2) 104 105mainlogger = logging.getLogger("BitBake.Main") 106 107class PrefixLoggerAdapter(logging.LoggerAdapter): 108 def __init__(self, prefix, logger): 109 super().__init__(logger, {}) 110 self.__msg_prefix = prefix 111 112 def process(self, msg, kwargs): 113 return "%s%s" %(self.__msg_prefix, msg), kwargs 114 115# This has to be imported after the setLoggerClass, as the import of bb.msg 116# can result in construction of the various loggers. 117import bb.msg 118 119from bb import fetch2 as fetch 120sys.modules['bb.fetch'] = sys.modules['bb.fetch2'] 121 122# Messaging convenience functions 123def plain(*args): 124 mainlogger.plain(''.join(args)) 125 126def debug(lvl, *args): 127 if isinstance(lvl, str): 128 mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl) 129 args = (lvl,) + args 130 lvl = 1 131 mainlogger.debug(lvl, ''.join(args)) 132 133def note(*args): 134 mainlogger.info(''.join(args)) 135 136# 137# A higher prioity note which will show on the console but isn't a warning 138# 139# Something is happening the user should be aware of but they probably did 140# something to make it happen 141# 142def verbnote(*args): 143 mainlogger.verbnote(''.join(args)) 144 145# 146# Warnings - things the user likely needs to pay attention to and fix 147# 148def warn(*args): 149 mainlogger.warning(''.join(args)) 150 151def error(*args, **kwargs): 152 mainlogger.error(''.join(args), extra=kwargs) 153 154def fatal(*args, **kwargs): 155 mainlogger.critical(''.join(args), extra=kwargs) 156 raise BBHandledException() 157 158def deprecated(func, name=None, advice=""): 159 """This is a decorator which can be used to mark functions 160 as deprecated. It will result in a warning being emitted 161 when the function is used.""" 162 import warnings 163 164 if advice: 165 advice = ": %s" % advice 166 if name is None: 167 name = func.__name__ 168 169 def newFunc(*args, **kwargs): 170 warnings.warn("Call to deprecated function %s%s." % (name, 171 advice), 172 category=DeprecationWarning, 173 stacklevel=2) 174 return func(*args, **kwargs) 175 newFunc.__name__ = func.__name__ 176 newFunc.__doc__ = func.__doc__ 177 newFunc.__dict__.update(func.__dict__) 178 return newFunc 179 180# For compatibility 181def deprecate_import(current, modulename, fromlist, renames = None): 182 """Import objects from one module into another, wrapping them with a DeprecationWarning""" 183 import sys 184 185 module = __import__(modulename, fromlist = fromlist) 186 for position, objname in enumerate(fromlist): 187 obj = getattr(module, objname) 188 newobj = deprecated(obj, "{0}.{1}".format(current, objname), 189 "Please use {0}.{1} instead".format(modulename, objname)) 190 if renames: 191 newname = renames[position] 192 else: 193 newname = objname 194 195 setattr(sys.modules[current], newname, newobj) 196 197