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