cef5559d44363796011493557231c94f386dbfcc
[lunaix-os.git] / lunaix-os / scripts / build-tools / lcfg2 / config.py
1 import ast, os
2
3 from lib.utils import ConfigAST
4 from .common import NodeProperty, NodeDependency
5 from .nodes import GroupNode, TermNode
6
7
8 class ConfigEnvironment:
9     def __init__(self):
10         self.__node_table = {}
11         self.__exec = None
12         self.__globals = {}
13         self.__custom_fn = {
14             "env": lambda x: os.environ.get(x)
15         }
16     
17     def check_dependency(self, node) -> bool:
18         dep = NodeProperty.Dependency[node]
19         
20         if not isinstance(dep, NodeDependency):
21             return node.enabled()
22         
23         value_map = {}
24         for name in dep._names:
25             if name not in self.__node_table:
26                 raise node.config_error(f"config: '{name}' does not exists")
27             
28             n = self.__node_table[name]
29             value_map[name] = self.check_dependency(n)
30
31         return node.enabled() and dep.evaluate(value_map)
32     
33     def register_node(self, cfg_node):
34         name = cfg_node._name
35         if name in self.__node_table:
36             raise cfg_node.config_error(f"redefinition of '{name}'")
37         
38         self.__node_table[name] = cfg_node
39     
40     def get_node(self, name):
41         return self.__node_table.get(name)
42     
43     def relocate_children(self):
44         for node in self.__node_table.values():
45             parent = NodeProperty.Parent[node]
46             if not parent:
47                 continue
48
49             if not isinstance(parent, str):
50                 continue
51             
52             if parent not in self.__node_table:
53                 raise Exception(node, "unknow parent: %s"%(parent))
54             
55             parent_node = self.__node_table[parent]
56             if not isinstance(parent_node, GroupNode):
57                 raise Exception(node, "not a valid parent: %s"%(parent))
58             
59             parent_node.add_child(node)
60
61     def set_exec_context(self, astns):
62         filtered = []
63         for x in astns:
64             if isinstance(x, ConfigAST.EnterFileMarker):
65                 continue
66             if isinstance(x, ConfigAST.LeaveFileMarker):
67                 continue
68             filtered.append(x)
69
70         module = ast.Module(filtered, type_ignores=[])
71         module = ast.fix_missing_locations(module)
72
73         self.__exec = compile(module, "", mode='exec')
74
75     def __update_globals(self):
76         g = {}
77
78         exec(self.__exec, g)
79         self.__globals = {
80             **g,
81             **self.__custom_fn
82         }
83
84     def context(self):
85         return self.__globals
86         
87     def refresh(self):
88         self.__update_globals()
89
90         for name, node in self.__node_table.items():
91             node.update()
92
93         for name, node in self.__node_table.items():
94             node.sanity_check()
95             NodeProperty.Enabled[node] = self.check_dependency(node)
96
97     def reset(self):
98         self.__node_table.clear()
99
100     def nodes(self):
101         for node in self.__node_table.values():
102             yield node
103
104     def top_levels(self):
105         for node in self.__node_table.values():
106             if NodeProperty.Parent[node] is None:
107                 yield node
108
109     def terms(self):
110         for node in self.__node_table.values():
111             if isinstance(node, TermNode):
112                 yield node
113
114 import json