summaryrefslogtreecommitdiff
path: root/lib/loader/kconfig.py
blob: 1dbebc87bbe1cd00ced8f7ffccd7b1278615e47f (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
#!/usr/bin/env python3

import kconfiglib
from frozendict import frozendict
import json
import os
import subprocess


class KConfigAttributes:
    def __init__(self, kconfig_path, datadir):
        experiments = list()
        failed_experiments = list()
        for direntry in os.listdir(datadir):
            config_path = f"{datadir}/{direntry}/.config"
            attr_path = f"{datadir}/{direntry}/attributes.json"
            metadata_path = f"{datadir}/{direntry}/metadata"
            if os.path.exists(attr_path):
                experiments.append((config_path, attr_path))
            elif os.path.exists(config_path):
                failed_experiments.append(config_path)

        kconf = kconfiglib.Kconfig(kconfig_path)
        self.kconf = kconf

        self.kconfig_hash = self.file_hash(kconfig_path)
        self.kconfig_dir = "unknown"
        if "/" in kconfig_path:
            self.kconfig_dir = kconfig_path.split("/")[-2]

        self.symbol_names = sorted(
            map(
                lambda sym: sym.name,
                filter(
                    lambda sym: kconfiglib.TYPE_TO_STR[sym.type]
                    in ("bool", "tristate", "int", "string", "hex"),
                    kconf.syms.values(),
                ),
            )
        )

        self.choice_names = sorted(
            map(lambda choice: choice.name or choice.name_and_loc, kconf.choices)
        )

        self.choice = dict()
        self.choice_symbol_names = list()
        for choice in kconf.choices:
            self.choice[choice.name or choice.name_and_loc] = choice
            self.choice_symbol_names.extend(map(lambda sym: sym.name, choice.syms))

        self.symbol = dict()
        for symbol_name in self.symbol_names:
            self.symbol[symbol_name] = kconf.syms[symbol_name]

        if int(os.getenv("DFATOOL_KCONF_WITH_CHOICE_NODES", 1)):
            for sym_name in self.choice_symbol_names:
                self.symbol_names.remove(sym_name)
            self.param_names = self.symbol_names + self.choice_names
        else:
            self.param_names = self.symbol_names

        self.data = list()
        self.configs = list()
        self.failures = list()

        for config_path, attr_path in experiments:
            self.configs.append(config_path)
            kconf.load_config(config_path)
            with open(attr_path, "r") as f:
                attr = json.load(f)

            param = self._conf_to_param()
            self.data.append((frozendict(param), attr))

        for config_path in failed_experiments:
            kconf.load_config(config_path)
            param = self._conf_to_param()
            self.failures.append(frozendict(param))

    def _conf_to_param(self):
        param = dict()
        for sym_name in self.symbol_names:
            sym = self.kconf.syms[sym_name]
            if not sym.visibility and sym.str_value == "":
                param[sym_name] = None
            elif kconfiglib.TYPE_TO_STR[sym.type] in ("int", "hex"):
                try:
                    param[sym_name] = int(sym.str_value, base=0)
                except ValueError:
                    print(
                        f"Warning: Illegal value for {sym.__repr__()}, defaulting to None"
                    )
                    param[sym_name] = None
            else:
                param[sym_name] = sym.str_value
        for choice in self.choice_names:
            if self.choice[choice].selection is None:
                param[choice] = None
            else:
                param[choice] = self.choice[choice].selection.name
        return param

    def file_hash(self, config_file):
        status = subprocess.run(
            ["sha256sum", config_file],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            universal_newlines=True,
        )
        sha256sum = status.stdout.split()[0]
        return sha256sum