1
1
#a='base(octopi,a(b,c(a2)),mm)'
2
2
import argparse
3
3
import os
4
+ import subprocess
4
5
from get_remote_modules import get_remote_module
6
+ from typing import TextIO , List , Tuple , Dict , Any
7
+
8
+
9
+ def run_command (command : List [str ], ** kwargs : Dict [str , Any ]):
10
+ is_timeout = False
11
+ p = subprocess .Popen (command , shell = False , stdout = subprocess .PIPE , stderr = subprocess .PIPE , ** kwargs )
12
+ try :
13
+ stdout , stderr = p .communicate (timeout = 5 )
14
+ except subprocess .TimeoutExpired as e :
15
+ p .kill ()
16
+ stdout ,stderr = p .communicate ()
17
+ is_timeout = True
18
+ try :
19
+ stdout = stdout .decode ("utf-8" )
20
+ except UnicodeDecodeError as e :
21
+ print ("Error: can't decode stdout" )
22
+ print (e )
23
+ print (stdout )
24
+ stdout = ""
25
+
26
+ try :
27
+ stderr = stderr .decode ("utf-8" )
28
+ except UnicodeDecodeError as e :
29
+ print ("Error: can't decode stderr" )
30
+ print (stderr )
31
+ print (e )
32
+ stderr = ""
33
+
34
+ return stdout , stderr , is_timeout
5
35
6
- def handle (module , state , out ):
7
- out .write ("# " + state + "_" + module + "\n " )
8
-
9
- module_folders = [os .path .join (os .environ ['DIST_PATH' ], "modules" , module ),
10
- os .path .join (os .environ ['CUSTOM_PI_OS_PATH' ], "modules" , module )
11
- ]
12
36
13
- found_local = False
14
- found_remote = False
15
- for module_folder in module_folders :
16
- if os .path .isdir (module_folder ):
17
- found_local = True
18
- break
19
-
20
- if not found_local :
21
- # TODO: Handle update
22
- found_remote , module_folder = get_remote_module (module )
23
-
24
-
25
- if not found_local and not found_remote :
26
- print (f"Error: Module { module } does not exist and is not in remote modules list" )
27
- exit (1 )
28
-
37
+ def write_modules_scripts (module : str , state : str , module_folder : str , out : TextIO ):
38
+ out .write ("# " + state + "_" + module + "\n " )
29
39
script = os .path .join (module_folder , state + "_chroot_script" )
30
40
if os .path .isfile (script ):
31
41
out .write ("execute_chroot_script '" + module_folder + "' '" + script + "'\n " )
@@ -34,38 +44,95 @@ def handle(module, state, out):
34
44
35
45
return
36
46
37
- def parse (a , callback ) :
47
+ def parse (a : str ) -> List [ Tuple [ str , str ]] :
38
48
stack = []
49
+ return_value = []
39
50
token = ""
40
51
41
52
for char in a :
42
53
if char == "(" :
43
54
stack .append (token )
44
55
if token != "" :
45
- callback ( token , "start" )
56
+ return_value . append (( token , "start" ) )
46
57
token = ""
47
58
elif char == ")" :
48
59
parent = stack .pop ()
49
60
if token != "" :
50
- callback ( token , "start" )
51
- callback ( token , "end" )
61
+ return_value . append (( token , "start" ) )
62
+ return_value . append (( token , "end" ) )
52
63
token = ""
53
64
if parent != "" :
54
- callback ( parent , "end" )
65
+ return_value . append (( parent , "end" ) )
55
66
elif char == "," :
56
67
if token != "" :
57
- callback ( token , "start" )
58
- callback ( token , "end" )
68
+ return_value . append (( token , "start" ) )
69
+ return_value . append (( token , "end" ) )
59
70
token = ""
60
71
else :
61
72
token += char
62
73
63
74
if token != "" :
64
- callback ( token , "start" )
65
- callback ( token , "end" )
75
+ return_value . append (( token , "start" ) )
76
+ return_value . append (( token , "end" ) )
66
77
if len (stack ) > 0 :
67
78
raise Exception (str (stack ))
68
- return
79
+ return return_value
80
+
81
+ def handle_meta_modules (modules : List [Tuple [str ,str ]]) -> Tuple [List [Tuple [str ,str ]],Dict [str ,str ]]:
82
+ return_value = []
83
+ modules_to_modules_folder = {}
84
+ for module , state in modules :
85
+ module_folders = [
86
+ os .path .join (os .environ ['DIST_PATH' ], "modules" , module ),
87
+ os .path .join (os .environ ['CUSTOM_PI_OS_PATH' ], "modules" , module )
88
+ ]
89
+ # In case this is a meta module, order counts
90
+ if state == "start" :
91
+ return_value .append ((module , state ))
92
+ found_local = False
93
+ found_remote = False
94
+ for module_folder in module_folders :
95
+ if os .path .isdir (module_folder ):
96
+ found_local = True
97
+ modules_to_modules_folder [module ] = module_folder
98
+ break
99
+
100
+ if not found_local :
101
+ # TODO: Handle update
102
+ found_remote , module_folder = get_remote_module (module )
103
+ modules_to_modules_folder [module ] = module_folder
104
+
105
+
106
+ if not found_local and not found_remote :
107
+ print (f"Error: Module { module } does not exist and is not in remote modules list" )
108
+ exit (1 )
109
+
110
+ meta_module_path = os .path .join (module_folder , "meta" )
111
+ if os .path .isfile (meta_module_path ):
112
+ # Meta module detected
113
+ print (f"Running: { meta_module_path } " )
114
+ print (f"ENV: { os .environ ['BASE_BOARD' ]} " )
115
+ submodules , meta_module_errors , is_timeout = run_command (meta_module_path )
116
+ submodules = submodules .strip ()
117
+ print (f"Adding in modules: { submodules } " )
118
+ if meta_module_errors != "" or is_timeout :
119
+ print (meta_module_errors )
120
+ print (f"Got error processing meta module at: { meta_module_path } " )
121
+ exit (1 )
122
+ if submodules != "" :
123
+ print (f"Got sub modules: { submodules } " )
124
+
125
+ for sub_module in submodules .split ("," ):
126
+ sub_module = sub_module .strip ()
127
+ return_value_sub , modules_to_modules_folder_sub = handle_meta_modules ([(sub_module , state )])
128
+ return_value += return_value_sub
129
+ modules_to_modules_folder .update (modules_to_modules_folder_sub )
130
+ # In case this is a meta module, order counts
131
+ if state == "end" :
132
+ return_value .append ((module , state ))
133
+
134
+ return return_value , modules_to_modules_folder
135
+
69
136
70
137
if __name__ == "__main__" :
71
138
parser = argparse .ArgumentParser (add_help = True , description = 'Parse and run CustomPiOS chroot modules' )
@@ -80,7 +147,14 @@ def parse(a, callback):
80
147
f .write ("#!/usr/bin/env bash\n " )
81
148
f .write ("set -x\n " )
82
149
f .write ("set -e\n " )
83
- parse (args .modules .replace (" " , "" ), lambda module , state : handle (module , state , f ))
150
+ initial_execution_order = parse (args .modules .replace (" " , "" ))
151
+ f .write (f"# Defined execution order: { initial_execution_order } \n " )
152
+ modules_execution_order , modules_to_modules_folder = handle_meta_modules (initial_execution_order )
153
+ f .write (f"# With meta modules order: { modules_execution_order } \n " )
154
+
155
+ for module , state in modules_execution_order :
156
+ module_folder = modules_to_modules_folder [module ]
157
+ write_modules_scripts (module , state , module_folder , f )
84
158
85
159
os .chmod (args .output_script , 0o755 )
86
160
0 commit comments