2929#
3030
3131import argparse
32+ import glob
3233import io
3334import json
3435import os
3536import platform
37+ import re
3638import shlex
3739import shutil
3840import signal
@@ -117,6 +119,7 @@ def main():
117119 parser .add_argument ('--plex' , default = '' , type = str , help = 'Platform Load Excludes' )
118120 parser .add_argument ('--enable' , default = '' , type = str , help = 'Platform Load Enable Override' )
119121 parser .add_argument ('--disable' , default = '' , type = str , help = 'Platform Load Disable Override' )
122+ parser .add_argument ('--remote' , default = '' , type = str , help = 'Remote Platform Load Git Repo' )
120123 parser .add_argument ('--enable-plugin' , default = '' , type = str , help = 'Plugin Enable' )
121124 parser .add_argument ('--disable-plugin' , default = '' , type = str , help = 'Plugin Disable' )
122125 parser .add_argument ('--fastboot' , default = '' , type = str , help = 'Update the selected platform using fastboot' )
@@ -225,7 +228,11 @@ def main():
225228 #
226229 # Create Workspace
227230 #
228- os .makedirs (workspace , exist_ok = True )
231+ os .makedirs (workspace , exist_ok = True ) #
232+ app_folder = os .path .join (workspace , 'app' )
233+ if not os .path .exists (app_folder ):
234+ os .makedirs (app_folder )
235+
229236
230237 if os .path .exists (workspace ):
231238 os .environ ['FLUTTER_WORKSPACE' ] = workspace
@@ -238,6 +245,27 @@ def main():
238245 get_flutter_engine_runtime (True , get_flutter_arch ())
239246 return
240247
248+
249+
250+ #
251+ # Load Remote Platforms
252+ #
253+
254+ # First, clear linked platforms
255+ configs_dir = os .path .join (os .getcwd (), 'configs' )
256+ if os .path .exists (configs_dir ):
257+ for filename in sorted (glob .glob (os .path .join (configs_dir , 'remote_*.json' ))):
258+ print (f'Unlinking remote config file: { filename } ' )
259+ os .unlink (filename )
260+ # Setup remote platform
261+ app_folder = os .path .join (workspace , 'app' )
262+ if args .remote :
263+ # comma-separated list of git repos
264+ print (f"Loading Remote Platforms from: { args .remote } " )
265+ remote_repos = args .remote .split (',' )
266+ for repo in remote_repos :
267+ load_remote_platform (repo , app_folder )
268+
241269 #
242270 # Limit compiler threads
243271 #
@@ -332,7 +360,6 @@ def main():
332360 print ("Invalid platform configuration" )
333361 exit (1 )
334362
335- app_folder = os .path .join (workspace , 'app' )
336363 flutter_sdk_folder = os .path .join (workspace , 'flutter' )
337364
338365 vscode_folder = os .path .join (workspace , '.vscode' )
@@ -378,7 +405,7 @@ def main():
378405 return
379406
380407 #
381- # App folder setup
408+ # Get Repos
382409 #
383410 is_exist = os .path .exists (app_folder )
384411 if not is_exist :
@@ -867,14 +894,11 @@ def validate_custom_device_config(config):
867894 return True
868895
869896
870- def get_repo (base_folder , uri , branch , rev ):
897+ def get_repo (base_folder , uri , ref , branch = None ):
871898 """ Clone Git Repo """
872899 if not uri :
873900 print ("repo entry needs a 'uri' key. Skipping" )
874901 return
875- if not branch :
876- print ("repo entry needs a 'branch' key. Skipping" )
877- return
878902
879903 # get repo folder name
880904 repo_name = uri .rsplit ('/' , 1 )[- 1 ]
@@ -897,8 +921,14 @@ def get_repo(base_folder, uri, branch, rev):
897921 subprocess .check_call (cmd , cwd = git_folder )
898922
899923 # print_banner(f'git pull: {repo_name}')
900- cmd = ['git' , 'pull' , 'origin' , branch ]
901- subprocess .check_call (cmd , cwd = git_folder )
924+ cmd = ['git' , 'pull' , '--ff-only' ]
925+ if branch :
926+ print (f'Using branch: { branch } ' )
927+ cmd .extend (['origin' , branch ])
928+ try :
929+ subprocess .check_call (cmd , cwd = git_folder )
930+ except subprocess .CalledProcessError as e :
931+ print (f"WARNING: git pull failed, continuing anyway" )
902932 else :
903933 # print_banner(f'Checking if folder exists: {git_folder}')
904934 if os .path .exists (git_folder ):
@@ -907,19 +937,21 @@ def get_repo(base_folder, uri, branch, rev):
907937 except subprocess .CalledProcessError :
908938 pass
909939
910- # print_banner(f'git clone {uri} -b {branch} {repo_name}')
911- cmd = ['git' , 'clone' , uri , '-b' , branch , repo_name ]
940+ cmd = ['git' , 'clone' , uri , repo_name ]
941+ if branch :
942+ print (f'Using branch: { branch } ' )
943+ cmd .extend (['-b' , branch ])
912944 subprocess .check_call (cmd , cwd = base_folder )
913945
914- if rev :
915- # print_banner (f'git checkout {rev }')
916- cmd = ['git' , 'checkout' , rev ]
946+ if ref :
947+ print (f'git checkout { ref } ' )
948+ cmd = ['git' , 'checkout' , ref ]
917949 subprocess .check_call (cmd , cwd = git_folder )
918- else :
919- # print_banner (f'git checkout {branch}')
950+ elif branch :
951+ print (f'git checkout { branch } ' )
920952 cmd = ['git' , 'checkout' , branch ]
921953 subprocess .check_call (cmd , cwd = git_folder )
922-
954+
923955 # get lfs
924956 git_lfs_file = os .path .join (base_folder , repo_name , '.gitattributes' )
925957 # print_banner(f'Checking if folder exists: {git_lfs_file}')
@@ -939,6 +971,62 @@ def get_repo(base_folder, uri, branch, rev):
939971 print_banner (f'Fetched: { repo_name } ' )
940972
941973
974+ # Load Remote Platforms
975+ #
976+ # For reach --remote=<git repo> specified on command line
977+ # clone the repo into app/<repo name>
978+ # and link the files in app/<repo name>/configs/... to configs/...
979+ # (but make sure not to overwrite existing files, throw error if so)
980+ def load_remote_platform (remote , app_folder ):
981+ """ Load Remote Platforms from GIT repo """
982+ if not remote :
983+ return
984+
985+ print_banner (f'Loading Remote Platforms from: { remote } ' )
986+
987+ remote_parts = remote .split ('#' )
988+ print (f'remote_parts: { remote_parts } ' )
989+ # get repo folder name
990+ repo_name = remote_parts [0 ].rsplit ('/' , 1 )
991+ print (f'repo_name parts: { repo_name } ' )
992+ repo_name = repo_name [- 1 ]
993+ print (f'repo_name before split: { repo_name } ' )
994+ repo_name = repo_name .split ("." )[0 ]
995+ print (f'repo_name: { repo_name } ' )
996+ # get git ref from remote_uri
997+ git_uri = remote_parts [0 ]
998+ git_ref = remote_parts [1 ] if len (remote_parts ) == 2 else None
999+
1000+ # get branch from ref (if starts with 'heads/)
1001+ git_branch = None
1002+ if git_ref and git_ref .startswith ('heads/' ):
1003+ git_branch = git_ref .split ('heads/' , 1 )[1 ]
1004+ git_ref = None
1005+
1006+ get_repo (base_folder = app_folder , uri = git_uri , ref = git_ref , branch = git_branch )
1007+ git_folder = str (os .path .join (app_folder , repo_name ))
1008+
1009+ # link files in app/<repo name>/configs/... to configs/...
1010+ remote_config_folder = os .path .join (git_folder , 'configs' )
1011+ if os .path .exists (remote_config_folder ):
1012+ import glob
1013+ for filename in sorted (glob .glob (os .path .join (remote_config_folder , '*.json' ))):
1014+
1015+ filepath = os .path .join (os .getcwd (), filename )
1016+ _ , tail = os .path .split (filename )
1017+
1018+ # link file as 'configs/remote_<file>'
1019+ dest_filepath = os .path .join (os .getcwd (), 'configs' , f'remote_{ tail } ' )
1020+
1021+ if os .path .exists (dest_filepath ):
1022+ print (f'Config file already exists! skipping: { dest_filepath } ' )
1023+ else :
1024+ print (f'Linking config file: { dest_filepath } ' )
1025+ os .symlink (filepath , dest_filepath )
1026+ else :
1027+ print (f'No configs folder found in remote platform repo: { remote_config_folder } ' )
1028+
1029+
9421030def get_workspace_repos (base_folder , config ):
9431031 """ Clone GIT repos referenced in config repos dict to base_folder """
9441032 import concurrent .futures
@@ -952,7 +1040,7 @@ def get_workspace_repos(base_folder, config):
9521040 futures = []
9531041 for repo in repos :
9541042 futures .append (executor .submit (get_repo , base_folder = base_folder , uri = repo .get (
955- 'uri' ), branch = repo .get ('branch ' ), rev = repo .get ('rev ' )))
1043+ 'uri' ), ref = repo .get ('rev ' ), branch = repo .get ('branch ' )))
9561044 validate_sudo_user ()
9571045
9581046 for _ in concurrent .futures .as_completed (futures ):
@@ -987,7 +1075,7 @@ def get_platform_src(src, base_folder: str):
9871075 futures = []
9881076 for repo in src :
9891077 futures .append (executor .submit (get_repo , base_folder = base_folder , uri = repo .get (
990- 'uri' ), branch = repo .get ('branch ' ), rev = repo .get ('rev ' )))
1078+ 'uri' ), ref = repo .get ('rev ' ), branch = repo .get ('branch ' )))
9911079 validate_sudo_user ()
9921080
9931081 for future in concurrent .futures .as_completed (futures ):
@@ -2089,34 +2177,63 @@ def handle_dotenv(dotenv_files):
20892177 print (f'Loaded: { dotenv_path } ' )
20902178
20912179
2092- def handle_env (env_variables , local_env , build_type = None ):
2180+ def handle_env (env_variables , env = None , build_type = None ):
20932181 if not env_variables :
20942182 return
2183+
2184+ if env is None :
2185+ env = os .environ
20952186
2187+ # If k starts with +, append to existing variable
20962188 for k , v in env_variables .items ():
2097- if local_env :
2098- if 'PATH_PREPEND' in k :
2099- local_env ['PATH' ] = os .path .normpath (os .path .expandvars (v )) + os .pathsep + local_env ['PATH' ]
2100- continue
2101- if 'PATH_APPEND' in k :
2102- local_env ['PATH' ] = local_env ['PATH' ] + os .pathsep + os .path .normpath (os .path .expandvars (v ))
2103- continue
2189+ print (f'Processing env var: { k } = { v } ' )
2190+
2191+ # Append to existing variable if the key starts with +
2192+ # (then remove the + from the key)
2193+ append = False
2194+ if k .startswith ('+' ):
2195+ append = True
2196+ k = k [1 :]
2197+
2198+ # TODO: obsolete? remove in the future
2199+ if 'PATH_PREPEND' in k :
2200+ env ['PATH' ] = os .path .normpath (os .path .expandvars (v )) + os .pathsep + env ['PATH' ]
2201+ continue
2202+ if 'PATH_APPEND' in k :
2203+ env ['PATH' ] = env ['PATH' ] + os .pathsep + os .path .normpath (os .path .expandvars (v ))
2204+ continue
21042205
2105- handle_build_type (local_env , build_type )
2206+ handle_build_type (env , build_type )
21062207
2107- local_env [k ] = os .path .normpath (os .path .expandvars (v ))
2108- else :
2109- if 'PATH_PREPEND' in k :
2110- os .environ ['PATH' ] = os .path .normpath (os .path .expandvars (v )) + os .pathsep + os .environ ['PATH' ]
2111- continue
2112- if 'PATH_APPEND' in k :
2113- os .environ ['PATH' ] = os .environ ['PATH' ] + os .pathsep + os .path .normpath (os .path .expandvars (v ))
2208+ v = os .path .expandvars (v )
2209+ if append :
2210+ # If append empty string, skip
2211+ if k == '' :
21142212 continue
21152213
2116- handle_build_type (os .environ , build_type )
2214+ # if a separator is specified in the key like `(;)SOMETHING_SOMETHING`, extract it
2215+
2216+ # Separator extraction logic:
2217+ # sep = between '(' and ')'
2218+ # default separator is " "
2219+ sep = " "
2220+ if k .startswith ('(' ) and ')' in k :
2221+ sep = k .split ('(' )[1 ].split (')' )[0 ]
2222+ k = k .split (')' )[1 ]
2223+
2224+ # Append to existing value
2225+ old_value = env .get (k , '' )
2226+ if old_value != '' :
2227+ v = old_value + sep + v
2228+ # skip append if there's no old value
2229+
2230+ env [k ] = v
2231+
2232+ # NOTE: no idea why this is here but it works, DO NOT REMOVE IT (it's been here for 6 months)
2233+ if not env is os .environ :
2234+ os .environ [k ] = v
21172235
2118- os .environ [k ] = os .path .normpath (os .path .expandvars (v ))
2119- # print(f'global: {k} = {os.environ[k]}')
2236+ print (f'Final env var: { k } = { os .environ [k ]} ' )
21202237
21212238
21222239def handle_build_type (env , build_type = None ):
0 commit comments