216 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import importlib
 | |
| import shutil
 | |
| import sys
 | |
| from types import ModuleType
 | |
| 
 | |
| import osdk.builder as builder
 | |
| import osdk.utils as utils
 | |
| import osdk.targets as targets
 | |
| import osdk.manifests as manifests
 | |
| 
 | |
| __version__ = "0.3.2"
 | |
| 
 | |
| CMDS = {}
 | |
| 
 | |
| 
 | |
| def parseOptions(args: list[str]) -> dict:
 | |
|     result = {
 | |
|         'opts': {},
 | |
|         'args': []
 | |
|     }
 | |
| 
 | |
|     for arg in args:
 | |
|         if arg.startswith("--"):
 | |
|             if "=" in arg:
 | |
|                 key, value = arg[2:].split("=", 1)
 | |
|                 result['opts'][key] = value
 | |
|             else:
 | |
|                 result['opts'][arg[2:]] = True
 | |
|         else:
 | |
|             result['args'].append(arg)
 | |
| 
 | |
|     return result
 | |
| 
 | |
| 
 | |
| def propsFromOptions(opt: dict) -> dict:
 | |
|     result = {}
 | |
|     for key in opt:
 | |
|         if key.startswith("prop:"):
 | |
|             result[key[5:]] = opt[key]
 | |
|     return result
 | |
| 
 | |
| 
 | |
| def runCmd(opts: dict, args: list[str]) -> None:
 | |
|     props = propsFromOptions(opts)
 | |
| 
 | |
|     if len(args) == 0:
 | |
|         print(f"Usage: osdk run <component>")
 | |
|         sys.exit(1)
 | |
| 
 | |
|     out = builder.buildOne(opts.get('target', 'default'), args[0], props)
 | |
| 
 | |
|     print()
 | |
|     print(f"{utils.Colors.BOLD}Running: {args[0]}{utils.Colors.RESET}")
 | |
|     utils.runCmd(out, *args[1:])
 | |
|     print()
 | |
|     print(f"{utils.Colors.GREEN}Process exited with success{utils.Colors.RESET}")
 | |
| 
 | |
| 
 | |
| def debugCmd(opts: dict, args: list[str]) -> None:
 | |
|     props = propsFromOptions(opts)
 | |
|     if len(args) == 0:
 | |
|         print(f"Usage: osdk debug <component>")
 | |
|         sys.exit(1)
 | |
| 
 | |
|     out = builder.buildOne(opts.get('target', 'default:debug'), args[0], props)
 | |
| 
 | |
|     print()
 | |
|     print(f"{utils.Colors.BOLD}Debugging: {args[0]}{utils.Colors.RESET}")
 | |
|     utils.runCmd("/usr/bin/lldb", "-o", "run",  out, *args[1:])
 | |
|     print()
 | |
|     print(f"{utils.Colors.GREEN}Process exited with success{utils.Colors.RESET}")
 | |
| 
 | |
| 
 | |
| def buildCmd(opts: dict, args: list[str]) -> None:
 | |
|     props = propsFromOptions(opts)
 | |
|     allTargets = opts.get('all-targets', False)
 | |
|     targetName = opts.get('target', 'default')
 | |
| 
 | |
|     if allTargets:
 | |
|         for target in targets.available():
 | |
|             if len(args) == 0:
 | |
|                 builder.buildAll(target, props)
 | |
|             else:
 | |
|                 for component in args:
 | |
|                     builder.buildOne(target, component, props)
 | |
|     else:
 | |
|         if len(args) == 0:
 | |
|             builder.buildAll(targetName, props)
 | |
|         else:
 | |
|             for component in args:
 | |
|                 builder.buildOne(targetName, component, props)
 | |
| 
 | |
| 
 | |
| def listCmd(opts: dict, args: list[str]) -> None:
 | |
|     props = propsFromOptions(opts)
 | |
|     targetName = opts.get('target', 'default')
 | |
|     target = targets.load(targetName, props)
 | |
|     components = manifests.loadAll(["src"], target)
 | |
| 
 | |
|     print(f"Available components for target '{targetName}':")
 | |
|     componentsNames = list(components.keys())
 | |
|     componentsNames.sort()
 | |
|     for component in componentsNames:
 | |
|         if components[component]["enabled"]:
 | |
|             print("  " + component)
 | |
|     print("")
 | |
| 
 | |
| 
 | |
| def cleanCmd(opts: dict, args: list[str]) -> None:
 | |
|     shutil.rmtree(".osdk/build", ignore_errors=True)
 | |
| 
 | |
| 
 | |
| def nukeCmd(opts: dict, args: list[str]) -> None:
 | |
|     shutil.rmtree(".osdk", ignore_errors=True)
 | |
| 
 | |
| 
 | |
| def helpCmd(opts: dict, args: list[str]) -> None:
 | |
|     print(f"Usage: osdk <command> [options...] [<args...>]")
 | |
|     print("")
 | |
| 
 | |
|     print("Description:")
 | |
|     print("   Operating System Development Kit.")
 | |
|     print("")
 | |
| 
 | |
|     print("Commands:")
 | |
|     for cmd in CMDS:
 | |
|         print("  " + cmd + " - " + CMDS[cmd]["desc"])
 | |
|     print("")
 | |
| 
 | |
|     print("Targets:")
 | |
|     availableTargets = targets.available()
 | |
|     if len(availableTargets) == 0:
 | |
|         print("   No targets available")
 | |
|     else:
 | |
|         for targetName in targets.available():
 | |
|             print("  " + targetName)
 | |
|     print("")
 | |
| 
 | |
|     print("Variants:")
 | |
|     for var in targets.VARIANTS:
 | |
|         print("  " + var)
 | |
|     print("")
 | |
| 
 | |
| 
 | |
| def versionCmd(opts: dict, args: list[str]) -> None:
 | |
|     print("OSDK v" + __version__)
 | |
| 
 | |
| 
 | |
| CMDS = {
 | |
|     "run": {
 | |
|         "func": runCmd,
 | |
|         "desc": "Run a component on the host",
 | |
|     },
 | |
|     "debug": {
 | |
|         "func": debugCmd,
 | |
|         "desc": "Run a component on the host in debug mode",
 | |
|     },
 | |
|     "build": {
 | |
|         "func": buildCmd,
 | |
|         "desc": "Build one or more components",
 | |
|     },
 | |
|     "list": {
 | |
|         "func": listCmd,
 | |
|         "desc": "List available components",
 | |
|     },
 | |
|     "clean": {
 | |
|         "func": cleanCmd,
 | |
|         "desc": "Clean the build directory",
 | |
|     },
 | |
|     "nuke": {
 | |
|         "func": nukeCmd,
 | |
|         "desc": "Clean the build directory and cache",
 | |
|     },
 | |
|     "help": {
 | |
|         "func": helpCmd,
 | |
|         "desc": "Show this help message",
 | |
|     },
 | |
|     "version": {
 | |
|         "func": versionCmd,
 | |
|         "desc": "Show current version",
 | |
|     },
 | |
| }
 | |
| 
 | |
| 
 | |
| def loadPlugin(path: str) -> ModuleType:
 | |
|     """Load a plugin from a path"""
 | |
|     spec = importlib.util.spec_from_file_location("plugin", path)
 | |
|     module = importlib.util.module_from_spec(spec)
 | |
|     spec.loader.exec_module(module)
 | |
|     return module
 | |
| 
 | |
| 
 | |
| for files in utils.tryListDir("meta/plugins"):
 | |
|     if files.endswith(".py"):
 | |
|         plugin = loadPlugin(f"meta/plugins/{files}")
 | |
|         CMDS[plugin.__plugin__["name"]] = plugin.__plugin__
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     argv = sys.argv
 | |
|     try:
 | |
|         if len(argv) < 2:
 | |
|             helpCmd({}, [])
 | |
|         else:
 | |
|             o = parseOptions(argv[2:])
 | |
|             if not argv[1] in CMDS:
 | |
|                 print(f"Unknown command: {argv[1]}")
 | |
|                 print("")
 | |
|                 print(f"Use '{argv[0]} help' for a list of commands")
 | |
|                 return 1
 | |
|             CMDS[argv[1]]["func"](o['opts'], o['args'])
 | |
|             return 0
 | |
|     except utils.CliException as e:
 | |
|         print()
 | |
|         print(f"{utils.Colors.RED}{e.msg}{utils.Colors.RESET}")
 | |
|         return 1
 |