blob: 6b470aa195ebd992e9c42f4cd1154e017fb4492c [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 Geissler78b72792022-06-14 06:47:25 -050012__version__ = "2.0.1"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050013
14import sys
Andrew Geisslerd159c7f2021-09-02 21:05:58 -050015if sys.version_info < (3, 6, 0):
16 raise RuntimeError("Sorry, python 3.6.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
63 return self.log(loglevel, msg, *args, **kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050064
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
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080071 def verbnote(self, msg, *args, **kwargs):
72 return self.log(logging.INFO + 2, msg, *args, **kwargs)
73
Andrew Geissler7e0e3c02022-02-25 20:34:39 +000074 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
Andrew Geissler5a43b432020-06-13 10:46:56 -050081Logger = logging.getLoggerClass()
82class BBLogger(Logger, BBLoggerMixin):
83 def __init__(self, name, *args, **kwargs):
84 self.setup_bblogger(name)
85 super().__init__(name, *args, **kwargs)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080086
Patrick Williamsc124f4f2015-09-15 14:41:29 -050087logging.raiseExceptions = False
88logging.setLoggerClass(BBLogger)
89
Andrew Geissler5a43b432020-06-13 10:46:56 -050090class 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
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500112 level = logger.getLevelName(logger.getEffectiveLevel())
Andrew Geissler5a43b432020-06-13 10:46:56 -0500113 return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level)
114
115logging.LoggerAdapter = BBLoggerAdapter
116
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117logger = logging.getLogger("BitBake")
118logger.addHandler(NullHandler())
119logger.setLevel(logging.DEBUG - 2)
120
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500121mainlogger = logging.getLogger("BitBake.Main")
122
Andrew Geissler5a43b432020-06-13 10:46:56 -0500123class 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
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500131# 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):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500140 mainlogger.plain(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500141
142def debug(lvl, *args):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600143 if isinstance(lvl, str):
144 mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500145 args = (lvl,) + args
146 lvl = 1
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600147 mainlogger.bbdebug(lvl, ''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500148
149def note(*args):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500150 mainlogger.info(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500151
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800152#
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#
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500164def warn(*args):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600165 mainlogger.warning(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500166
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000167def warnonce(*args):
168 mainlogger.warnonce(''.join(args))
169
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500170def error(*args, **kwargs):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500171 mainlogger.error(''.join(args), extra=kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500172
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000173def erroronce(*args):
174 mainlogger.erroronce(''.join(args))
175
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500176def fatal(*args, **kwargs):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500177 mainlogger.critical(''.join(args), extra=kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500178 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