summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/__init__.py
blob: c1e30697b3da03769f6f4f25232b93ff31005ed7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#
# BitBake Build System Python Library
#
# Copyright (C) 2003  Holger Schurig
# Copyright (C) 2003, 2004  Chris Larson
#
# Based on Gentoo's portage.py.
#
# SPDX-License-Identifier: GPL-2.0-only
#

__version__ = "1.51.1"

import sys
if sys.version_info < (3, 5, 0):
    raise RuntimeError("Sorry, python 3.5.0 or later is required for this version of bitbake")


class BBHandledException(Exception):
    """
    The big dilemma for generic bitbake code is what information to give the user
    when an exception occurs. Any exception inheriting this base exception class
    has already provided information to the user via some 'fired' message type such as
    an explicitly fired event using bb.fire, or a bb.error message. If bitbake
    encounters an exception derived from this class, no backtrace or other information
    will be given to the user, its assumed the earlier event provided the relevant information.
    """
    pass

import os
import logging


class NullHandler(logging.Handler):
    def emit(self, record):
        pass

class BBLoggerMixin(object):
    def __init__(self, *args, **kwargs):
        # Does nothing to allow calling super() from derived classes
        pass

    def setup_bblogger(self, name):
        if name.split(".")[0] == "BitBake":
            self.debug = self._debug_helper

    def _debug_helper(self, *args, **kwargs):
        return self.bbdebug(1, *args, **kwargs)

    def debug2(self, *args, **kwargs):
        return self.bbdebug(2, *args, **kwargs)

    def debug3(self, *args, **kwargs):
        return self.bbdebug(3, *args, **kwargs)

    def bbdebug(self, level, msg, *args, **kwargs):
        loglevel = logging.DEBUG - level + 1
        if not bb.event.worker_pid:
            if self.name in bb.msg.loggerDefaultDomains and loglevel > (bb.msg.loggerDefaultDomains[self.name]):
                return
            if loglevel < bb.msg.loggerDefaultLogLevel:
                return
        return self.log(loglevel, msg, *args, **kwargs)

    def plain(self, msg, *args, **kwargs):
        return self.log(logging.INFO + 1, msg, *args, **kwargs)

    def verbose(self, msg, *args, **kwargs):
        return self.log(logging.INFO - 1, msg, *args, **kwargs)

    def verbnote(self, msg, *args, **kwargs):
        return self.log(logging.INFO + 2, msg, *args, **kwargs)

Logger = logging.getLoggerClass()
class BBLogger(Logger, BBLoggerMixin):
    def __init__(self, name, *args, **kwargs):
        self.setup_bblogger(name)
        super().__init__(name, *args, **kwargs)

logging.raiseExceptions = False
logging.setLoggerClass(BBLogger)

class BBLoggerAdapter(logging.LoggerAdapter, BBLoggerMixin):
    def __init__(self, logger, *args, **kwargs):
        self.setup_bblogger(logger.name)
        super().__init__(logger, *args, **kwargs)

    if sys.version_info < (3, 6):
        # These properties were added in Python 3.6. Add them in older versions
        # for compatibility
        @property
        def manager(self):
            return self.logger.manager

        @manager.setter
        def manager(self, value):
            self.logger.manager = value

        @property
        def name(self):
            return self.logger.name

        def __repr__(self):
            logger = self.logger
            level = logger.getLevelName(logger.getEffectiveLevel())
            return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level)

logging.LoggerAdapter = BBLoggerAdapter

logger = logging.getLogger("BitBake")
logger.addHandler(NullHandler())
logger.setLevel(logging.DEBUG - 2)

mainlogger = logging.getLogger("BitBake.Main")

class PrefixLoggerAdapter(logging.LoggerAdapter):
    def __init__(self, prefix, logger):
        super().__init__(logger, {})
        self.__msg_prefix = prefix

    def process(self, msg, kwargs):
        return "%s%s" %(self.__msg_prefix, msg), kwargs

# This has to be imported after the setLoggerClass, as the import of bb.msg
# can result in construction of the various loggers.
import bb.msg

from bb import fetch2 as fetch
sys.modules['bb.fetch'] = sys.modules['bb.fetch2']

# Messaging convenience functions
def plain(*args):
    mainlogger.plain(''.join(args))

def debug(lvl, *args):
    if isinstance(lvl, str):
        mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
        args = (lvl,) + args
        lvl = 1
    mainlogger.bbdebug(lvl, ''.join(args))

def note(*args):
    mainlogger.info(''.join(args))

#
# A higher prioity note which will show on the console but isn't a warning
#
# Something is happening the user should be aware of but they probably did
# something to make it happen
#
def verbnote(*args):
    mainlogger.verbnote(''.join(args))

#
# Warnings - things the user likely needs to pay attention to and fix
#
def warn(*args):
    mainlogger.warning(''.join(args))

def error(*args, **kwargs):
    mainlogger.error(''.join(args), extra=kwargs)

def fatal(*args, **kwargs):
    mainlogger.critical(''.join(args), extra=kwargs)
    raise BBHandledException()

def deprecated(func, name=None, advice=""):
    """This is a decorator which can be used to mark functions
    as deprecated. It will result in a warning being emitted
    when the function is used."""
    import warnings

    if advice:
        advice = ": %s" % advice
    if name is None:
        name = func.__name__

    def newFunc(*args, **kwargs):
        warnings.warn("Call to deprecated function %s%s." % (name,
                                                             advice),
                      category=DeprecationWarning,
                      stacklevel=2)
        return func(*args, **kwargs)
    newFunc.__name__ = func.__name__
    newFunc.__doc__ = func.__doc__
    newFunc.__dict__.update(func.__dict__)
    return newFunc

# For compatibility
def deprecate_import(current, modulename, fromlist, renames = None):
    """Import objects from one module into another, wrapping them with a DeprecationWarning"""
    import sys

    module = __import__(modulename, fromlist = fromlist)
    for position, objname in enumerate(fromlist):
        obj = getattr(module, objname)
        newobj = deprecated(obj, "{0}.{1}".format(current, objname),
                            "Please use {0}.{1} instead".format(modulename, objname))
        if renames:
            newname = renames[position]
        else:
            newname = objname

        setattr(sys.modules[current], newname, newobj)