Skip to content

Commit 96ad267

Browse files
authored
Merge pull request #192 from mlcommons/dev
Merge Dev
2 parents 5425b74 + e34b924 commit 96ad267

File tree

9 files changed

+188
-133
lines changed

9 files changed

+188
-133
lines changed

.github/workflows/test-mlc-docker-core.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
strategy:
1717
fail-fast: false
1818
matrix:
19-
python-version: ["3.12", "3.8"]
19+
python-version: ["3.13", "3.8"]
2020
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
2121
exclude:
2222
- os: windows-latest
@@ -46,12 +46,12 @@ jobs:
4646
4747
- name: Test --docker_dt for running in detached mode
4848
run: |
49-
mlc docker run --tags=detect,os --docker_dt
49+
mlc docker-run script --tags=detect,os --docker_dt
5050
docker stop $(docker ps -aq)
5151
5252
- name: Test --docker_detached for running in detached mode
5353
run: |
54-
mlc docker run --tags=detect,os --docker_detached
54+
mlcd detect,os --docker_detached
5555
docker stop $(docker ps -aq)
5656
5757
- name: Test --docker_cache
@@ -64,4 +64,4 @@ jobs:
6464
6565
- name: Test --dockerfile_recreate
6666
run: |
67-
mlc docker run --tags=detect,os --docker_dt --docker_cache=no --docker_rebuild --dockerfile_recreate
67+
mlc docker-run script --tags=detect,os --docker_dt --docker_cache=no --docker_rebuild --dockerfile_recreate

README.md

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Each target has its own set of specific actions to tailor automation workflows a
5757

5858
| Target | Action |
5959
|--------|-----------------|
60-
| script | run, find/search, rm, mv, cp, add, test, docker, show |
60+
| script | run, find/search, rm, mv, cp, add, test, docker-run, show, experiment, doc |
6161
| cache | find/search, rm, show |
6262
| repo | pull, search, rm, list, find/search , add |
6363

@@ -115,9 +115,6 @@ classDiagram
115115
+show(args)
116116
+list(args)
117117
}
118-
class CfgAction {
119-
+load(args)
120-
}
121118
class Index {
122119
+add(meta, folder_type, path, repo)
123120
+get_index(folder_type, uid)
@@ -148,8 +145,6 @@ classDiagram
148145
Action <|-- RepoAction
149146
Action <|-- ScriptAction
150147
Action <|-- CacheAction
151-
Action <|-- ExperimentAction
152-
Action <|-- CfgAction
153148
RepoAction o-- Repo
154149
ScriptAction o-- Automation
155150
CacheAction o-- Index

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.2.0
1+
1.1.9

mlc/action.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ def access(self, options):
4242
return {'return': 1, 'error': "'action' key is required in options"}
4343
#logger.info(f"options = {options}")
4444

45+
action_name = action_name.replace("-", "_")
46+
4547
action_target = options.get('target')
4648
if not action_target:
4749
action_target = options.get('automation', 'script') # Default to script if not provided

mlc/index.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,6 @@ def _save_indices(self):
178178
try:
179179
with open(output_file, "w") as f:
180180
json.dump(index_data, f, indent=4, cls=CustomJSONEncoder)
181-
logger.debug(f"Shared index for {folder_type} saved to {output_file}.")
181+
#logger.debug(f"Shared index for {folder_type} saved to {output_file}.")
182182
except Exception as e:
183183
logger.error(f"Error saving shared index for {folder_type}: {e}")

mlc/main.py

Lines changed: 120 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import sys
44
from pathlib import Path
55
import inspect
6-
6+
import shlex
77
from . import utils
88

99
from .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

7879
def 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")
8991
def mlcd():
9092
mlc_expand_short("docker")
93+
def mlcdr():
94+
mlc_expand_short("docker")
95+
def mlcrr():
96+
mlc_expand_short("remote-run")
9197
def mlce():
9298
mlc_expand_short("experiment")
9399
def mlct():
@@ -115,7 +121,86 @@ def process_console_output(res, target, action, run_args):
115121
if 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+
119204
def 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

298309
if __name__ == '__main__':
299310
main()

0 commit comments

Comments
 (0)