blob: b217737347e70667249b2ed94e5c098d8756b18e [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 Geissler6ce62a22020-11-30 19:58:47 -060012__version__ = "1.49.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
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
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":
45 self.debug = self.bbdebug
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046
47 def bbdebug(self, level, msg, *args, **kwargs):
Andrew Geissler82c905d2020-04-13 13:39:40 -050048 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)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050055
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
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080062 def verbnote(self, msg, *args, **kwargs):
63 return self.log(logging.INFO + 2, msg, *args, **kwargs)
64
Andrew Geissler5a43b432020-06-13 10:46:56 -050065Logger = logging.getLoggerClass()
66class BBLogger(Logger, BBLoggerMixin):
67 def __init__(self, name, *args, **kwargs):
68 self.setup_bblogger(name)
69 super().__init__(name, *args, **kwargs)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080070
Patrick Williamsc124f4f2015-09-15 14:41:29 -050071logging.raiseExceptions = False
72logging.setLoggerClass(BBLogger)
73
Andrew Geissler5a43b432020-06-13 10:46:56 -050074class 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
Andrew Geisslerc9f78652020-09-18 14:11:35 -050096 level = logger.getLevelName(logger.getEffectiveLevel())
Andrew Geissler5a43b432020-06-13 10:46:56 -050097 return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level)
98
99logging.LoggerAdapter = BBLoggerAdapter
100
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500101logger = logging.getLogger("BitBake")
102logger.addHandler(NullHandler())
103logger.setLevel(logging.DEBUG - 2)
104
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500105mainlogger = logging.getLogger("BitBake.Main")
106
Andrew Geissler5a43b432020-06-13 10:46:56 -0500107class 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
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500115# 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):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500124 mainlogger.plain(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125
126def debug(lvl, *args):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600127 if isinstance(lvl, str):
128 mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500129 args = (lvl,) + args
130 lvl = 1
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500131 mainlogger.debug(lvl, ''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132
133def note(*args):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500134 mainlogger.info(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500135
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800136#
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#
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500148def warn(*args):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600149 mainlogger.warning(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150
151def error(*args, **kwargs):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500152 mainlogger.error(''.join(args), extra=kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500153
154def fatal(*args, **kwargs):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500155 mainlogger.critical(''.join(args), extra=kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500156 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