Introducing LunaBuild to the build flow (#36)
[lunaix-os.git] / lunaix-os / scripts / build-tools / lbuild / contract.py
1 from lib.sandbox import Sandbox
2 from lib.utils import join_path
3 from .common import BuildEnvironment
4
5 import os
6
7 class LunaBuildFile(Sandbox):
8     def __init__(self, env: BuildEnvironment, path) -> None:
9         super().__init__({
10             "_script": 
11                 path,
12             "sources": 
13                 lambda src: self.export_sources(src),
14             "headers":
15                 lambda hdr: self.export_headers(hdr),
16             "configured":
17                 lambda name: self.check_config(name),
18             "config":
19                 lambda name: self.read_config(name),
20             "use":
21                 lambda file: self.import_buildfile(file)
22         })
23         
24         self.__srcs = []
25         self.__hdrs = []
26         self.__env  = env
27
28         self.__path = path
29         self.__dir  = os.path.dirname(path)
30         
31     def resolve(self):
32         self.execute(self.__path)
33         self.__env.add_sources(self.__do_process(self.__srcs))
34         self.__env.add_headers(self.__do_process(self.__hdrs))
35
36     def __do_process(self, list):
37         resolved = []
38         for entry in list:
39             if not entry:
40                 continue
41             resolved.append(self.__resolve_value(entry))
42         return resolved
43
44     def expand_select(self, val):
45         tests = list(val.keys())
46         if len(tests) != 1:
47             raise TypeError(
48                 "select statement must have exactly one conditional")
49         
50         test = tests[0]
51         outcomes = val[test]
52         if test not in outcomes:
53             self.__raise("unbounded select")
54         return outcomes[test]
55
56     def __resolve_value(self, source):
57         resolved = source
58         while not isinstance(resolved, str):
59             if isinstance(resolved, dict):
60                 resolved = self.expand_select(resolved)
61             else:
62                 self.__raise(f"entry with unknown type: {resolved}")
63         
64         resolved = resolved.strip()
65         resolved = join_path(self.__dir, resolved)
66
67         return self.__env.to_wspath(resolved)
68     
69     def import_buildfile(self, path):
70         path = self.__resolve_value(path)
71         path = self.__env.to_wspath(path)
72         
73         if (os.path.isdir(path)):
74             path = os.path.join(path, "LBuild")
75         
76         if not os.path.exists(path):
77             self.__raise("Build file not exist: %s", path)
78
79         if os.path.abspath(path) == os.path.abspath(self.__path):
80             self.__raise("self dependency detected")
81
82         LunaBuildFile(self.__env, path).resolve()
83
84     def export_sources(self, src):
85         if not isinstance(src, list):
86             src = [src]
87         self.__srcs += src
88
89     def export_headers(self, hdr):
90         if not isinstance(hdr, list):
91             hdr = [hdr]
92         self.__hdrs += hdr
93
94     def check_config(self, name):
95         return self.__env.config_provider().has_config(name)
96     
97     def read_config(self, name):
98         return self.__env.config_provider().configured_value(name)
99     
100     def __raise(self, msg, *kargs):
101         raise Exception(msg%kargs)