33import time
44import shlex
55import pathlib
6+ import re
67import subprocess
78
8- # Target will be a board, "test", "docs", "mpy-cross-mac", or "windows"
9- TARGET = sys .argv [1 ]
9+ TOP = pathlib .Path (__file__ ).parent .parent
10+
11+
12+ def _git_version ():
13+ version_str = subprocess .check_output (["git" , "--version" ], encoding = "ascii" , errors = "replace" )
14+ version_str = re .search ("([0-9]\.*)*[0-9]" , version_str ).group (0 )
15+ return tuple (int (part ) for part in version_str .split ("." ))
16+
17+
18+ clone_supports_filter = (
19+ False if "NO_USE_CLONE_FILTER" in os .environ else _git_version () >= (2 , 27 , 0 )
20+ )
21+
22+ if clone_supports_filter :
23+ filter_maybe = "--filter=blob:none"
24+ else :
25+ filter_maybe = ""
26+
27+
28+ def _all_submodules ():
29+ submodule_str = subprocess .check_output (
30+ ["git" , "submodule" , "status" ], encoding = "ascii" , errors = "replace" , cwd = TOP
31+ )
32+ return [row .split ()[1 ] for row in submodule_str .strip ().split ("\n " )]
33+
34+
35+ all_submodules = _all_submodules ()
36+
37+
38+ def matching_submodules (s ):
39+ if s .endswith ("/" ):
40+ return [m for m in all_submodules if m .startswith (s )]
41+ elif s not in all_submodules :
42+ raise ValueError (f"{ s !r} is not a submodule" )
43+ return [s ]
44+
1045
1146# Submodules needed by port builds outside of their ports directory.
1247# Should we try and detect these?
66101}
67102
68103
69- def run (title , command , check = True ):
104+ def run (title , command , cwd ):
70105 print ("::group::" + title , flush = True )
71- print (command , flush = True )
106+ print (f" { command } (in { cwd } )" , flush = True )
72107 start = time .monotonic ()
73108 try :
74- subprocess .run (shlex .split (command ), stderr = subprocess .STDOUT , check = check )
109+ subprocess .run (shlex .split (command ), stderr = subprocess .STDOUT , check = True , cwd = cwd )
75110 finally :
76111 print ("::endgroup::" , flush = True )
77112 print ("Duration:" , time .monotonic () - start , flush = True )
78113
79114
115+ def matching_submodules (where ):
116+ for m in all_submodules :
117+ if m in where :
118+ yield m
119+ for w in where :
120+ if m .startswith (f"{ w } /" ):
121+ yield m
122+ break
123+
124+
125+ def fetch (where ):
126+ if clone_supports_filter :
127+ run (
128+ "Init submodules (using filter)" ,
129+ f"git submodule update --init { filter_maybe } { ' ' .join (where )} " ,
130+ cwd = TOP ,
131+ )
132+ else :
133+ run (
134+ "Init submodules (using depth)" ,
135+ f"git submodule update --init --depth 1 { ' ' .join (where )} " ,
136+ cwd = TOP ,
137+ )
138+ for s in matching_submodules ([w for w in where if w .startswith ("frozen" )]):
139+ run (f"Ensure tags exist in { s } " , "git fetch --tags --depth 1" , cwd = TOP / s )
140+
141+
80142def set_output (name , value ):
81143 if "GITHUB_OUTPUT" in os .environ :
82144 with open (os .environ ["GITHUB_OUTPUT" ], "at" ) as f :
83145 print (f"{ name } ={ value } " , file = f )
84146 else :
85- print (f"Would set GitHub actions output { name } to ' { value } ' " )
147+ print (f"{ name } : { value !r } " )
86148
87149
88- def main ():
150+ SUBMODULES_BY_TARGET = {}
151+
152+
153+ def main (target ):
89154 submodules = []
90- submodules_tags = []
91155
92- print ("Target:" , TARGET )
156+ print ("Target:" , target )
93157
94- if TARGET == "scheduler" :
95- # submodules = ["tools/"]
158+ if target == "all" :
159+ submodules = ["." , "frozen" ] # explicitly list frozen to get tags
160+ elif target == "scheduler" :
96161 submodules = ["extmod/ulab" , "lib/" , "tools/" ]
97- elif TARGET == "tests" :
98- submodules = ["extmod/ulab" , "lib/" , "tools/" ]
99- submodules_tags = [
162+ elif target == "tests" :
163+ submodules = [
164+ "extmod/ulab" ,
165+ "lib/" ,
166+ "tools/" ,
100167 "frozen/Adafruit_CircuitPython_asyncio" ,
101168 "frozen/Adafruit_CircuitPython_Ticks" ,
102169 ]
103- elif TARGET == "docs" :
170+ elif target == "docs" :
104171 # used in .readthedocs.yml to generate RTD
105- submodules = ["extmod/ulab" ]
106- submodules_tags = ["frozen/" ]
107- elif TARGET == "mpy-cross" or TARGET == "mpy-cross-mac" :
172+ submodules = ["extmod/ulab" , "frozen" ]
173+ elif target == "mpy-cross" or target == "mpy-cross-mac" :
108174 submodules = ["tools/" ] # for huffman
109- elif TARGET == "windows" :
175+ elif target == "windows" :
110176 # This builds one board from a number of ports so fill out a bunch of submodules
111177 for port in ("atmel-samd" , "nrf" , "raspberrypi" , "stm" ):
112178 submodules .append (f"ports/{ port } " )
113179 submodules .extend (PORT_DEPS [port ])
114180 unique_submodules = set (submodules )
115181 submodules = list (unique_submodules )
116- elif TARGET == "website" :
117- submodules = ["tools/adabot/" ]
118- submodules_tags = ["frozen/" ]
119- elif TARGET == "pre-commit" :
182+ elif target == "website" :
183+ submodules = ["tools/adabot" , "frozen" ]
184+ elif target == "pre-commit" :
120185 submodules = ["extmod/ulab" ]
186+ elif target in PORT_DEPS :
187+ submodules = ["data" , "extmod" , "lib" , "tools" , "frozen" , f"ports/{ target } " ] + PORT_DEPS [
188+ target
189+ ]
121190 else :
122- p = list (pathlib .Path ("." ).glob (f"ports/*/boards/{ TARGET } /mpconfigboard.mk" ))
191+ p = list (pathlib .Path (TOP ).glob (f"ports/*/boards/{ target } /mpconfigboard.mk" ))
123192 if not p :
124- raise RuntimeError (f"Unsupported target: { TARGET } " )
193+ raise RuntimeError (f"Unsupported target: { target } " )
125194
126195 config = p [0 ]
127196 # Add the ports folder to init submodules
128197 port_folder = config .parents [2 ]
129198 port = port_folder .name
130- submodules .append (str ( port_folder ) )
199+ submodules .append (f"ports/ { port } " )
131200 submodules .append ("tools/" ) # for huffman
132201 submodules .extend (PORT_DEPS [port ])
133202 with config .open () as f :
@@ -140,24 +209,14 @@ def main():
140209 if lib_folder .count ("/" ) > 1 :
141210 lib_folder = lib_folder .split ("/" , maxsplit = 2 )
142211 lib_folder = "/" .join (lib_folder [:2 ])
143- submodules_tags .append (lib_folder )
144-
145- print ("Submodule tags[Y]:" , submodules_tags )
146- print ("Submodule tags[N]:" , submodules )
212+ submodules .append (lib_folder )
147213
148- if submodules_tags :
149- run (
150- "Init the submodules with tags" ,
151- f"git submodule update --init { ' ' .join (submodules_tags )} " ,
152- )
214+ print ("Submodules:" , " " .join (submodules ))
153215
154216 if submodules :
155- run (
156- "Init the submodules without tags" ,
157- f"git submodule update --init --depth=1 { ' ' .join (submodules )} " ,
158- )
217+ fetch (submodules )
159218
160- for submodule in submodules_tags :
219+ for submodule in submodules :
161220 if submodule .startswith ("frozen" ):
162221 set_output ("frozen_tags" , True )
163222 break
@@ -166,4 +225,11 @@ def main():
166225
167226
168227if __name__ == "__main__" :
169- main ()
228+ if len (sys .argv ) < 2 :
229+ raise SystemExit ("Usage: ci_fetch_deps dep..." )
230+
231+ run ("Sync submodule URLs" , "git submodule sync --quiet" , cwd = TOP )
232+
233+ # Target will be a board, "test", "docs", "mpy-cross-mac", or "windows"
234+ for target in sys .argv [1 :]:
235+ main (target )
0 commit comments