blob: 9f61dae14cb54e71488bd8fbebe8e6ce1d60c2a6 [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 Geissler3b8a17c2021-04-15 15:55:55 -050012__version__ = "1.50.0"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050013
14import sys
Andrew Geissler82c905d2020-04-13 13:39:40 -050015if sys.version_info < (3, 5, 0):
16 raise RuntimeError("Sorry, python 3.5.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 Geissler5a43b432020-06-13 10:46:56 -050074Logger = logging.getLoggerClass()
75class BBLogger(Logger, BBLoggerMixin):
76 def __init__(self, name, *args, **kwargs):
77 self.setup_bblogger(name)
78 super().__init__(name, *args, **kwargs)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080079
Patrick Williamsc124f4f2015-09-15 14:41:29 -050080logging.raiseExceptions = False
81logging.setLoggerClass(BBLogger)
82
Andrew Geissler5a43b432020-06-13 10:46:56 -050083class BBLoggerAdapter(logging.LoggerAdapter, BBLoggerMixin):
84 def __init__(self, logger, *args, **kwargs):
85 self.setup_bblogger(logger.name)
86 super().__init__(logger, *args, **kwargs)
87
88 if sys.version_info < (3, 6):
89 # These properties were added in Python 3.6. Add them in older versions
90 # for compatibility
91 @property
92 def manager(self):
93 return self.logger.manager
94
95 @manager.setter
96 def manager(self, value):
97 self.logger.manager = value
98
99 @property
100 def name(self):
101 return self.logger.name
102
103 def __repr__(self):
104 logger = self.logger
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500105 level = logger.getLevelName(logger.getEffectiveLevel())
Andrew Geissler5a43b432020-06-13 10:46:56 -0500106 return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level)
107
108logging.LoggerAdapter = BBLoggerAdapter
109
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500110logger = logging.getLogger("BitBake")
111logger.addHandler(NullHandler())
112logger.setLevel(logging.DEBUG - 2)
113
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500114mainlogger = logging.getLogger("BitBake.Main")
115
Andrew Geissler5a43b432020-06-13 10:46:56 -0500116class PrefixLoggerAdapter(logging.LoggerAdapter):
117 def __init__(self, prefix, logger):
118 super().__init__(logger, {})
119 self.__msg_prefix = prefix
120
121 def process(self, msg, kwargs):
122 return "%s%s" %(self.__msg_prefix, msg), kwargs
123
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500124# This has to be imported after the setLoggerClass, as the import of bb.msg
125# can result in construction of the various loggers.
126import bb.msg
127
128from bb import fetch2 as fetch
129sys.modules['bb.fetch'] = sys.modules['bb.fetch2']
130
131# Messaging convenience functions
132def plain(*args):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500133 mainlogger.plain(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500134
135def debug(lvl, *args):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600136 if isinstance(lvl, str):
137 mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500138 args = (lvl,) + args
139 lvl = 1
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600140 mainlogger.bbdebug(lvl, ''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500141
142def note(*args):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500143 mainlogger.info(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800145#
146# A higher prioity note which will show on the console but isn't a warning
147#
148# Something is happening the user should be aware of but they probably did
149# something to make it happen
150#
151def verbnote(*args):
152 mainlogger.verbnote(''.join(args))
153
154#
155# Warnings - things the user likely needs to pay attention to and fix
156#
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500157def warn(*args):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600158 mainlogger.warning(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500159
160def error(*args, **kwargs):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500161 mainlogger.error(''.join(args), extra=kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500162
163def fatal(*args, **kwargs):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500164 mainlogger.critical(''.join(args), extra=kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500165 raise BBHandledException()
166
167def deprecated(func, name=None, advice=""):
168 """This is a decorator which can be used to mark functions
169 as deprecated. It will result in a warning being emitted
170 when the function is used."""
171 import warnings
172
173 if advice:
174 advice = ": %s" % advice
175 if name is None:
176 name = func.__name__
177
178 def newFunc(*args, **kwargs):
179 warnings.warn("Call to deprecated function %s%s." % (name,
180 advice),
181 category=DeprecationWarning,
182 stacklevel=2)
183 return func(*args, **kwargs)
184 newFunc.__name__ = func.__name__
185 newFunc.__doc__ = func.__doc__
186 newFunc.__dict__.update(func.__dict__)
187 return newFunc
188
189# For compatibility
190def deprecate_import(current, modulename, fromlist, renames = None):
191 """Import objects from one module into another, wrapping them with a DeprecationWarning"""
192 import sys
193
194 module = __import__(modulename, fromlist = fromlist)
195 for position, objname in enumerate(fromlist):
196 obj = getattr(module, objname)
197 newobj = deprecated(obj, "{0}.{1}".format(current, objname),
198 "Please use {0}.{1} instead".format(modulename, objname))
199 if renames:
200 newname = renames[position]
201 else:
202 newname = objname
203
204 setattr(sys.modules[current], newname, newobj)
205