blob: 4bc47c8ab9325b48243e65cb166a488a8583e40a [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3#
4# BitBake Build System Python Library
5#
6# Copyright (C) 2003 Holger Schurig
7# Copyright (C) 2003, 2004 Chris Larson
8#
9# Based on Gentoo's portage.py.
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License version 2 as
13# published by the Free Software Foundation.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License along
21# with this program; if not, write to the Free Software Foundation, Inc.,
22# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080024__version__ = "1.40.0"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050025
26import sys
Patrick Williamsc0f7c042017-02-23 20:41:17 -060027if sys.version_info < (3, 4, 0):
28 raise RuntimeError("Sorry, python 3.4.0 or later is required for this version of bitbake")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029
30
31class BBHandledException(Exception):
32 """
33 The big dilemma for generic bitbake code is what information to give the user
34 when an exception occurs. Any exception inheriting this base exception class
35 has already provided information to the user via some 'fired' message type such as
36 an explicitly fired event using bb.fire, or a bb.error message. If bitbake
37 encounters an exception derived from this class, no backtrace or other information
38 will be given to the user, its assumed the earlier event provided the relevant information.
39 """
40 pass
41
42import os
43import logging
44
45
46class NullHandler(logging.Handler):
47 def emit(self, record):
48 pass
49
50Logger = logging.getLoggerClass()
51class BBLogger(Logger):
52 def __init__(self, name):
53 if name.split(".")[0] == "BitBake":
54 self.debug = self.bbdebug
55 Logger.__init__(self, name)
56
57 def bbdebug(self, level, msg, *args, **kwargs):
58 return self.log(logging.DEBUG - level + 1, msg, *args, **kwargs)
59
60 def plain(self, msg, *args, **kwargs):
61 return self.log(logging.INFO + 1, msg, *args, **kwargs)
62
63 def verbose(self, msg, *args, **kwargs):
64 return self.log(logging.INFO - 1, msg, *args, **kwargs)
65
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080066 def verbnote(self, msg, *args, **kwargs):
67 return self.log(logging.INFO + 2, msg, *args, **kwargs)
68
69
Patrick Williamsc124f4f2015-09-15 14:41:29 -050070logging.raiseExceptions = False
71logging.setLoggerClass(BBLogger)
72
73logger = logging.getLogger("BitBake")
74logger.addHandler(NullHandler())
75logger.setLevel(logging.DEBUG - 2)
76
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050077mainlogger = logging.getLogger("BitBake.Main")
78
Patrick Williamsc124f4f2015-09-15 14:41:29 -050079# This has to be imported after the setLoggerClass, as the import of bb.msg
80# can result in construction of the various loggers.
81import bb.msg
82
83from bb import fetch2 as fetch
84sys.modules['bb.fetch'] = sys.modules['bb.fetch2']
85
86# Messaging convenience functions
87def plain(*args):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050088 mainlogger.plain(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050089
90def debug(lvl, *args):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060091 if isinstance(lvl, str):
92 mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050093 args = (lvl,) + args
94 lvl = 1
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050095 mainlogger.debug(lvl, ''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050096
97def note(*args):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050098 mainlogger.info(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050099
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800100#
101# A higher prioity note which will show on the console but isn't a warning
102#
103# Something is happening the user should be aware of but they probably did
104# something to make it happen
105#
106def verbnote(*args):
107 mainlogger.verbnote(''.join(args))
108
109#
110# Warnings - things the user likely needs to pay attention to and fix
111#
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500112def warn(*args):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600113 mainlogger.warning(''.join(args))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500114
115def error(*args, **kwargs):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500116 mainlogger.error(''.join(args), extra=kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117
118def fatal(*args, **kwargs):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500119 mainlogger.critical(''.join(args), extra=kwargs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500120 raise BBHandledException()
121
122def deprecated(func, name=None, advice=""):
123 """This is a decorator which can be used to mark functions
124 as deprecated. It will result in a warning being emitted
125 when the function is used."""
126 import warnings
127
128 if advice:
129 advice = ": %s" % advice
130 if name is None:
131 name = func.__name__
132
133 def newFunc(*args, **kwargs):
134 warnings.warn("Call to deprecated function %s%s." % (name,
135 advice),
136 category=DeprecationWarning,
137 stacklevel=2)
138 return func(*args, **kwargs)
139 newFunc.__name__ = func.__name__
140 newFunc.__doc__ = func.__doc__
141 newFunc.__dict__.update(func.__dict__)
142 return newFunc
143
144# For compatibility
145def deprecate_import(current, modulename, fromlist, renames = None):
146 """Import objects from one module into another, wrapping them with a DeprecationWarning"""
147 import sys
148
149 module = __import__(modulename, fromlist = fromlist)
150 for position, objname in enumerate(fromlist):
151 obj = getattr(module, objname)
152 newobj = deprecated(obj, "{0}.{1}".format(current, objname),
153 "Please use {0}.{1} instead".format(modulename, objname))
154 if renames:
155 newname = renames[position]
156 else:
157 newname = objname
158
159 setattr(sys.modules[current], newname, newobj)
160