33import sys
44from pathlib import Path
55import inspect
6-
6+ import shlex
77from . import utils
88
99from .action import Action , default_parent
@@ -74,9 +74,11 @@ def search(self, i):
7474 return {'return' : 0 , 'list' : result }
7575 #indices
7676
77+ mlc_run_cmd = None
7778
7879def mlc_expand_short (action , target = "script" ):
79-
80+ global mlc_run_cmd
81+ mlc_run_cmd = shlex .join (sys .argv )
8082 # Insert the positional argument into sys.argv for the main function
8183 sys .argv .insert (1 , action )
8284 sys .argv .insert (2 , target )
@@ -88,6 +90,10 @@ def mlcr():
8890 mlc_expand_short ("run" )
8991def mlcd ():
9092 mlc_expand_short ("docker" )
93+ def mlcdr ():
94+ mlc_expand_short ("docker" )
95+ def mlcrr ():
96+ mlc_expand_short ("remote-run" )
9197def mlce ():
9298 mlc_expand_short ("experiment" )
9399def mlct ():
@@ -115,7 +121,86 @@ def process_console_output(res, target, action, run_args):
115121if default_parent is None :
116122 default_parent = Action ()
117123
118- # Main CLI function
124+
125+ log_flag_aliases = {'-v' : '--verbose' , '-s' : '--silent' }
126+ log_levels = {'--verbose' : logging .DEBUG , '--silent' : logging .WARNING }
127+
128+
129+ def build_pre_parser ():
130+ pre_parser = argparse .ArgumentParser (add_help = False )
131+ pre_parser .add_argument ("action" , nargs = "?" , help = "Top-level action (run, build, help, etc.)" )
132+ pre_parser .add_argument ("target" , choices = ['run' , 'script' , 'cache' , 'repo' , 'repos' ], nargs = "?" , help = "Target (repo, script, cache, ...)" )
133+ pre_parser .add_argument ("-h" , "--help" , action = "store_true" )
134+ return pre_parser
135+
136+
137+ def build_parser (pre_args ):
138+ parser = argparse .ArgumentParser (prog = "mlc" , description = "Manage repos, scripts, and caches." , add_help = False )
139+ subparsers = parser .add_subparsers (dest = "command" , required = not pre_args .help )
140+
141+ # General commands
142+ for action in ['run' , 'pull' , 'test' , 'add' , 'show' , 'list' , 'find' , 'search' , 'rm' , 'cp' , 'mv' , 'help' ]:
143+ p = subparsers .add_parser (action , add_help = False )
144+ p .add_argument ('target' , choices = ['repo' , 'repos' , 'script' , 'cache' ])
145+ p .add_argument ('details' , nargs = '?' , help = 'Details or identifier (optional)' )
146+ p .add_argument ('extra' , nargs = argparse .REMAINDER )
147+
148+ # Script-only
149+ for action in ['docker' , 'docker-run' , 'experiment' , 'remote-run' , 'doc' , 'lint' ]:
150+ p = subparsers .add_parser (action , add_help = False )
151+ p .add_argument ('target' , choices = ['script' , 'run' ])
152+ p .add_argument ('details' , nargs = '?' , help = 'Details or identifier (optional)' )
153+ p .add_argument ('extra' , nargs = argparse .REMAINDER )
154+
155+ # Load cfg
156+ load_parser = subparsers .add_parser ("load" , add_help = False )
157+ load_parser .add_argument ("target" , choices = ["cfg" ])
158+ return parser
159+
160+
161+ def configure_logging (args ):
162+ if hasattr (args , 'extra' ) and args .extra :
163+ args .extra [:] = [log_flag_aliases .get (a , a ) for a in args .extra ]
164+ for flag , level in log_levels .items ():
165+ if flag in args .extra :
166+ logger .setLevel (level )
167+ args .extra .remove (flag )
168+
169+
170+ def build_run_args (args ):
171+ global mlc_run_cmd
172+ res = utils .convert_args_to_dictionary (getattr (args , 'extra' , []))
173+ if res ['return' ] > 0 :
174+ return res
175+
176+ run_args = res ['args_dict' ]
177+ if not mlc_run_cmd :
178+ mlc_run_cmd = shlex .join (sys .argv )
179+ run_args ['mlc_run_cmd' ] = mlc_run_cmd
180+
181+ if args .command in ['pull' , 'rm' , 'add' , 'find' ] and args .target == "repo" :
182+ run_args ['repo' ] = args .details
183+
184+ if args .command in ['docker' , 'docker-run' , 'experiment' , 'remote-run' , 'doc' , 'lint' ] and args .target == "run" :
185+ #run_args['target'] = 'script' #dont modify this as script might have target as in input
186+ args .target = "script"
187+
188+ if args .details and not utils .is_uid (args .details ) and not run_args .get ("tags" ) and args .target in ["script" , "cache" ]:
189+ run_args ['tags' ] = args .details
190+
191+ if not run_args .get ('details' ) and args .details :
192+ run_args ['details' ] = args .details
193+
194+ if args .command in ["cp" , "mv" ]:
195+ run_args ['target' ] = args .target
196+ if args .details :
197+ run_args ['src' ] = args .details
198+ if args .extra :
199+ run_args ['dest' ] = args .extra [0 ]
200+
201+ return run_args
202+
203+
119204def main ():
120205 """
121206 MLCFlow is a CLI tool for managing repos, scripts, and caches.
@@ -130,11 +215,11 @@ def main():
130215
131216 Each target has a specific set of actions to tailor automation workflows, as shown below:
132217
133- | Target | Actions |
134- |---------|-------------------------------------------------------|
135- | script | run, find/search, rm, mv, cp, add, test, docker, show |
136- | cache | find/search, rm, show |
137- | repo | pull, search, rm, list, find/search |
218+ | Target | Actions |
219+ |---------|----------------------------------------------------------- |
220+ | script | run, find/search, rm, mv, cp, add, test, docker-run , show |
221+ | cache | find/search, rm, show |
222+ | repo | pull, search, rm, list, find/search |
138223
139224 Example:
140225 mlc run script detect-os
@@ -154,18 +239,22 @@ def main():
154239 mlc run script --help
155240 mlc pull repo -h
156241 """
157-
158- # First level parser for showing help
159- pre_parser = argparse .ArgumentParser (add_help = False )
160- pre_parser .add_argument ("action" , nargs = "?" , help = "Top-level action (run, build, help, etc.)" )
161- pre_parser .add_argument ("target" , choices = ['run' , 'script' , 'cache' , 'repo' ], nargs = "?" , help = "Potential target (repo, script, cache, ...)" )
162- pre_parser .add_argument ("-h" , "--help" , action = "store_true" )
242+ pre_parser = build_pre_parser ()
163243 pre_args , remaining_args = pre_parser .parse_known_args ()
164244
165- if pre_args .help and not any ("--tags" in arg for arg in remaining_args ):
245+ parser = build_parser (pre_args )
246+ args = parser .parse_args () if remaining_args or pre_args .target else pre_args
247+
248+ if hasattr (args , 'command' ) and args .command :
249+ args .command = args .command .replace ("-" , "_" )
250+
251+ configure_logging (args )
252+ run_args = build_run_args (args ) if hasattr (args , "command" ) else {}
253+
254+ if pre_args .help and not "tags" in run_args :
166255 help_text = ""
167256 if pre_args .target == "run" :
168- if pre_args .action == "docker" :
257+ if pre_args .action . startswith ( "docker" ) :
169258 pre_args .target = "script"
170259 else :
171260 logger .error (f"Invalid action-target { pre_args .action } - { pre_args .target } combination" )
@@ -196,104 +285,26 @@ def main():
196285 if help_text != "" :
197286 print (help_text )
198287 sys .exit (0 )
199-
200- # parser for execution of the automation scripts
201- parser = argparse .ArgumentParser (prog = 'mlc' , description = 'A CLI tool for managing repos, scripts, and caches.' , add_help = False )
202-
203- # Subparsers are added to main parser, allowing for different commands (subcommands) to be defined.
204- # The chosen subcommand will be stored in the "command" attribute of the parsed arguments.
205- subparsers = parser .add_subparsers (dest = 'command' , required = True )
206-
207- # Script and Cache-specific subcommands
208- for action in ['run' , 'pull' , 'test' , 'add' , 'show' , 'list' , 'find' , 'search' , 'rm' , 'cp' , 'mv' ]:
209- action_parser = subparsers .add_parser (action , add_help = False )
210- action_parser .add_argument ('target' , choices = ['repo' , 'script' , 'cache' ], help = 'Target type (repo, script, cache).' )
211- # the argument given after target and before any extra options like --tags will be stored in "details"
212- action_parser .add_argument ('details' , nargs = '?' , help = 'Details or identifier (optional for list).' )
213- action_parser .add_argument ('extra' , nargs = argparse .REMAINDER , help = 'Extra options (e.g., -v)' )
214-
215- # Script specific subcommands
216- for action in ['docker' , 'experiment' , 'doc' , 'lint' ]:
217- action_parser = subparsers .add_parser (action , add_help = False )
218- action_parser .add_argument ('target' , choices = ['script' , 'run' ], help = 'Target type (script).' )
219- # the argument given after target and before any extra options like --tags will be stored in "details"
220- action_parser .add_argument ('details' , nargs = '?' , help = 'Details or identifier (optional for list).' )
221- action_parser .add_argument ('extra' , nargs = argparse .REMAINDER , help = 'Extra options (e.g., -v)' )
222-
223- for action in ['load' ]:
224- load_parser = subparsers .add_parser (action , add_help = False )
225- load_parser .add_argument ('target' , choices = ['cfg' ], help = 'Target type (cfg).' )
226-
227- # Parse arguments
228- args = parser .parse_args ()
229-
230- #logger.info(f"Args = {args}")
231-
232- # set log level for MLCFlow if -v/--verbose or -s/--silent is specified
233- log_flag_aliases = {
234- '-v' : '--verbose' ,
235- '-s' : '--silent'
236- }
237-
238- log_levels = {
239- '--verbose' : logging .DEBUG ,
240- '--silent' : logging .WARNING
241- }
242-
243- # Modify args.extra in place
244- args .extra [:] = [log_flag_aliases .get (arg , arg ) for arg in args .extra ]
245-
246- # Set log level based on the first matching flag
247- for flag , level in log_levels .items ():
248- if flag in args .extra :
249- logger .setLevel (level )
250- args .extra .remove (flag )
251288
252- res = utils .convert_args_to_dictionary (args .extra )
253- if res ['return' ] > 0 :
254- return res
255-
256- run_args = res ['args_dict' ]
257-
258- run_args ['mlc_run_cmd' ] = " " .join (sys .argv )
259-
260- if hasattr (args , 'repo' ) and args .repo :
261- run_args ['repo' ] = args .repo
289+ # show repos alias list repo
290+ if args .command in ("show" ):
291+ args .command = "list"
292+ if args .target == "repos" :
293+ args .target = "repo"
262294
263- if args .command in ['pull' , 'rm' , 'add' , 'find' ]:
264- if args .target == "repo" :
265- run_args ['repo' ] = args .details
266-
267- if args .command in ['docker' , 'experiment' , 'doc' , 'lint' ]:
268- if args .target == "run" :
269- run_args ['target' ] = 'script' #allowing run to be used for docker run instead of docker script
270- args .target = "script"
271-
272- if hasattr (args , 'details' ) and args .details and not utils .is_uid (args .details ) and not run_args .get ("tags" ) and args .target in ["script" , "cache" ]:
273- run_args ['tags' ] = args .details
295+ action = get_action (args .target , default_parent )
274296
275- if not run_args .get ('details' ) and args .details :
276- run_args ['details' ] = args .details
297+ if not action or not hasattr (action , args .command ):
298+ logging .error ("Error: '%s' is not supported for %s." , args .command , args .target )
299+ sys .exit (1 )
277300
278- if args .command in ["cp" , "mv" ]:
279- run_args ['target' ] = args .target
280- if hasattr (args , 'details' ) and args .details :
281- run_args ['src' ] = args .details
282- if hasattr (args , 'extra' ) and args .extra :
283- run_args ['dest' ] = args .extra [0 ]
301+ method = getattr (action , args .command )
302+ res = method (run_args )
303+ if res ['return' ] > 0 :
304+ logging .error (res .get ('error' , f"Error in { action } " ))
305+ raise Exception (f"An error occurred { res } " )
284306
285- # Get the action handler for other commands
286- action = get_action (args .target , default_parent )
287- # Dynamically call the method (e.g., run, list, show)
288- if action and hasattr (action , args .command ):
289- method = getattr (action , args .command )
290- res = method (run_args )
291- if res ['return' ] > 0 :
292- logger .error (res .get ('error' , f"Error in { action } " ))
293- raise Exception (f"""An error occurred { res } """ )
294- process_console_output (res , args .target , args .command , run_args )
295- else :
296- logger .error (f"Error: '{ args .command } ' is not supported for { args .target } ." )
307+ process_console_output (res , args .target , args .command , run_args )
297308
298309if __name__ == '__main__' :
299310 main ()
0 commit comments