blob: 56be5a831e201c9fd0e8a1188a89f02c89721d91 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
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#
Brad Bishopc342db32019-05-15 21:57:59 -04009# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010#
Patrick Williamsc124f4f2015-09-15 14:41:29 -050011
Andrew Geissler6aa7eec2023-03-03 12:41:14 -060012__version__ = "2.3.1"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050013
14import sys
Andrew Geissler517393d2023-01-13 08:55:19 -060015if sys.version_info < (3, 8, 0):
16 raise RuntimeError("Sorry, python 3.8.0 or later is required for this version of bitbake")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050017
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
Andrew Geisslerd1e89492021-02-12 15:35:20 -060024 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
Patrick Williamsc124f4f2015-09-15 14:41:29 -050026 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
Andrew Geissler5a43b432020-06-13 10:46:56 -050038class 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):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050044 if name.split(".")[0] == "BitBake":
Andrew Geisslerd1e89492021-02-12 15:35:20 -060045 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)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050055
56 def bbdebug(self, level, msg, *args, **kwargs):
Andrew Geissler82c905d2020-04-13 13:39:40 -050057 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
Andrew Geissler95ac1b82021-03-31 14:34:31 -050061 if loglevel < bb.msg.loggerDefaultLogLevel:
Andrew Geissler82c905d2020-04-13 13:39:40 -050062 return
Andrew Geissler87f5cff2022-09-30 13:13:31 -050063
64 if not isinstance(level, int) or not isinstance(msg, str):
65 mainlogger.warning("Invalid arguments in bbdebug: %s" % repr((level, msg,) + args))
66
Andrew Geissler82c905d2020-04-13 13:39:40 -050067 return self.log(loglevel, msg, *args, **kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050068
69 def plain(self, msg, *args, **kwargs):
70 return self.log(logging.INFO + 1, msg, *args, **kwargs)
71
72 def verbose(self, msg, *args, **kwargs):
73 return self.log(logging.INFO - 1, msg, *args, **kwargs)
74
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080075 def verbnote(self, msg, *args, **kwargs):
76 return self.log(logging.INFO + 2, msg, *args, **kwargs)
77
Andrew Geissler7e0e3c02022-02-25 20:34:39 +000078 def warnonce(self, msg, *args, **kwargs):
79 return self.log(logging.WARNING - 1, msg, *args, **kwargs)
80
81 def erroronce(self, msg, *args, **kwargs):
82 return self.log(logging.ERROR - 1, msg, *args, **kwargs)
83
84
Andrew Geissler5a43b432020-06-13 10:46:56 -050085Logger = logging.getLoggerClass()
86class BBLogger(Logger, BBLoggerMixin):
87 def __init__(self, name, *args, **kwargs):
88 self.setup_bblogger(name)
89 super().__init__(name, *args, **kwargs)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080090
Patrick Williamsc124f4f2015-09-15 14:41:29 -050091logging.raiseExceptions = False
92logging.setLoggerClass(BBLogger)
93
Andrew Geissler5a43b432020-06-13 10:46:56 -050094class BBLoggerAdapter(logging.LoggerAdapter, BBLoggerMixin):
95 def __init__(self, logger, *args, **kwargs):
96 self.setup_bblogger(logger.name)
97 super().__init__(logger, *args, **kwargs)
98
99 if sys.version_info < (3, 6):
100 # These properties were added in Python 3.6. Add them in older versions
101 # for compatibility
102 @property
103 def manager(self):
104 return self.logger.manager
105
106 @manager.setter
107 def manager(self, value):
108 self.logger.manager = value
109
110 @property
111 def name(self):
112 return self.logger.name
113
114 def __repr__(self):
115 logger = self.logger
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500116 level = logger.getLevelName(logger.getEffectiveLevel())
Andrew Geissler5a43b432020-06-13 10:46:56 -0500117 return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level)
118
119logging.LoggerAdapter = BBLoggerAdapter
120
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500121logger = logging.getLogger("BitBake")
122logger.addHandler(NullHandler())
123logger.setLevel(logging.DEBUG - 2)
124
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500125mainlogger = logging.getLogger("BitBake.Main")
126
Andrew Geissler5a43b432020-06-13 10:46:56 -0500127class PrefixLoggerAdapter(logging.LoggerAdapter):
128 def __init__(self, prefix, logger):
129 super().__init__(logger, {})
130 self.__msg_prefix = prefix
131
132 def process(self, msg, kwargs):
133 return "%s%s" %(self.__msg_prefix, msg), kwargs
134
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500135# This has to be imported after the setLoggerClass, as the import of bb.msg
136# can result in construction of the various loggers.
137import bb.msg
138
139from bb import fetch2 as fetch
140sys.modules['bb.fetch'] = sys.modules['bb.fetch2']
141
142# Messaging convenience functions
143def plain(*args):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500144 mainlogger.plain(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500145
146def debug(lvl, *args):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600147 if isinstance(lvl, str):
148 mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500149 args = (lvl,) + args
150 lvl = 1
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600151 mainlogger.bbdebug(lvl, ''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500152
153def note(*args):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500154 mainlogger.info(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500155
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800156#
157# A higher prioity note which will show on the console but isn't a warning
158#
159# Something is happening the user should be aware of but they probably did
160# something to make it happen
161#
162def verbnote(*args):
163 mainlogger.verbnote(''.join(args))
164
165#
166# Warnings - things the user likely needs to pay attention to and fix
167#
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500168def warn(*args):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600169 mainlogger.warning(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500170
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000171def warnonce(*args):
172 mainlogger.warnonce(''.join(args))
173
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500174def error(*args, **kwargs):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500175 mainlogger.error(''.join(args), extra=kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500176
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000177def erroronce(*args):
178 mainlogger.erroronce(''.join(args))
179
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500180def fatal(*args, **kwargs):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500181 mainlogger.critical(''.join(args), extra=kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500182 raise BBHandledException()
183
184def deprecated(func, name=None, advice=""):
185 """This is a decorator which can be used to mark functions
186 as deprecated. It will result in a warning being emitted
187 when the function is used."""
188 import warnings
189
190 if advice:
191 advice = ": %s" % advice
192 if name is None:
193 name = func.__name__
194
195 def newFunc(*args, **kwargs):
196 warnings.warn("Call to deprecated function %s%s." % (name,
197 advice),
198 category=DeprecationWarning,
199 stacklevel=2)
200 return func(*args, **kwargs)
201 newFunc.__name__ = func.__name__
202 newFunc.__doc__ = func.__doc__
203 newFunc.__dict__.update(func.__dict__)
204 return newFunc
205
206# For compatibility
207def deprecate_import(current, modulename, fromlist, renames = None):
208 """Import objects from one module into another, wrapping them with a DeprecationWarning"""
209 import sys
210
211 module = __import__(modulename, fromlist = fromlist)
212 for position, objname in enumerate(fromlist):
213 obj = getattr(module, objname)
214 newobj = deprecated(obj, "{0}.{1}".format(current, objname),
215 "Please use {0}.{1} instead".format(modulename, objname))
216 if renames:
217 newname = renames[position]
218 else:
219 newname = objname
220
221 setattr(sys.modules[current], newname, newobj)
222