aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/bb-print-layer-data
blob: afbefe937550607cb0e2d120034cb0cd53a7cdaa (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
#!/usr/bin/env python3
#
# ---------------------------------------------------------------------------------------------------------------------
# SPDX-License-Identifier: MIT
# ---------------------------------------------------------------------------------------------------------------------
#
# Given a layer or layer.conf path, print the layer metadata

import contextlib
import os
import signal
import sys
from operator import itemgetter


class Terminate(BaseException):
    pass


def sigterm_exception(signum, stackframe):
    raise Terminate()


def setup_command_import(command, relpath='../lib'):
    """Set up sys.path based on the location of a binary in the PATH """
    PATH = os.getenv('PATH').split(':')
    cmd_paths = [os.path.join(path, relpath)
                for path in PATH if os.path.exists(os.path.join(path, command))]
    if not cmd_paths:
        raise ImportError("Unable to locate bb, please ensure PATH is set correctly.")

    sys.path[0:0] = cmd_paths


@contextlib.contextmanager
def status(message, outfile=sys.stderr):
    """Show the user what we're doing, and whether we succeed"""
    outfile.write('{0}..'.format(message))
    outfile.flush()
    try:
        yield
    except KeyboardInterrupt:
        outfile.write('.interrupted\n')
        raise
    except Terminate:
        outfile.write('.terminated\n')
        raise
    except BaseException:
        outfile.write('.failed\n')
        raise
    outfile.write('.done\n')


class LayerError(Exception):
    pass


def get_layer_data(layer_path, lconf=None, data=None):
    if lconf is None:
        lconf = os.path.join(layer_path, 'conf', 'layer.conf')

    if data is None:
        ldata = bb.data.init()
        bb.parse.init_parser(ldata)
    else:
        ldata = data.createCopy()

    ldata.setVar('LAYERDIR', layer_path)
    try:
        ldata = bb.parse.handle(lconf, ldata, include=True)
    except BaseException as exc:
        raise LayerError(exc)
    ldata.expandVarref('LAYERDIR')

    collections = (ldata.getVar('BBFILE_COLLECTIONS', True) or '').split()
    if not collections:
        name = os.path.basename(layer_path)
        collections = [name]

    for name in collections:
        priority = ldata.getVar('BBFILE_PRIORITY_%s' % name, True)
        pattern = ldata.getVar('BBFILE_PATTERN_%s' % name, True)
        depends = ldata.getVar('LAYERDEPENDS_%s' % name, True)
        yield name, priority, layer_path, pattern, depends


def print_layer_data(cmdline_opts):
    if len(cmdline_opts) < 1:
        return "Usage: bb-print-layer-data LCONF|LAYERDIR [LCONF|LAYERDIR..]\n"

    setup_command_import('bitbake')
    try:
        import bb
    except ImportError as exc:
        sys.exit("Unable to import 'bb' python package: %s" % exc)

    import bb.parse
    import bb.data

    data = bb.data.init()
    bb.parse.init_parser(data)

    collections = set()

    for layer_path in cmdline_opts:
        if os.path.isdir(layer_path):
            lconf = os.path.join(layer_path, 'conf', 'layer.conf')
        else:
            lconf = layer_path
            layer_path = os.path.dirname(os.path.dirname(lconf))

        with status("Parsing {0}".format(lconf)):
            collections |= set(get_layer_data(layer_path, lconf, data))

    priority_key = lambda i: int(i[1]) if i[1] is not None else None
    for name, priority, layer_path, pattern, depends in sorted(collections, key=priority_key):
        print("{0}: {1}|{2}|{3}|{4}".format(name, priority or '', layer_path, pattern or '', depends or ''))


if __name__ == '__main__':
    signal.signal(signal.SIGTERM, sigterm_exception)
    try:
        sys.exit(print_layer_data(sys.argv[1:]) or 0)
    except KeyboardInterrupt:
        signal.signal(signal.SIGINT, signal.SIG_DFL)
        os.kill(os.getpid(), signal.SIGINT)
    except Terminate:
        signal.signal(signal.SIGTERM, signal.SIG_DFL)
        os.kill(os.getpid(), signal.SIGTERM)