diff --git a/cutekit/__init__.py b/cutekit/__init__.py index bb7ec34..2e34d16 100644 --- a/cutekit/__init__.py +++ b/cutekit/__init__.py @@ -95,7 +95,6 @@ def main() -> int: except RuntimeError as e: logging.exception(e) vt100.error(str(e)) - cli.usage() return 1 except KeyboardInterrupt: diff --git a/cutekit/builder.py b/cutekit/builder.py index eefb981..1ef1d46 100644 --- a/cutekit/builder.py +++ b/cutekit/builder.py @@ -389,7 +389,7 @@ def _(): class BuildArgs(model.TargetArgs): - component: str = cli.operand("component", "Component to build") + component: str = cli.operand("component", "Component to build", default="__main__") @cli.command("b", "builder/build", "Build a component or all components") @@ -409,16 +409,14 @@ class RunArgs(BuildArgs, shell.DebugArgs, shell.ProfileArgs): @cli.command("r", "builder/run", "Run a component") def runCmd(args: RunArgs): - componentSpec = args.consumeArg() or "__main__" - args.props |= {"debug": args.debug} scope = TargetScope.use(args) component = scope.registry.lookup( - componentSpec, model.Component, includeProvides=True + args.component, model.Component, includeProvides=True ) if component is None: - raise RuntimeError(f"Component {componentSpec} not found") + raise RuntimeError(f"Component {args.component} not found") product = build(scope, component)[0] diff --git a/cutekit/cli.py b/cutekit/cli.py index 5888c0a..0c4ad95 100644 --- a/cutekit/cli.py +++ b/cutekit/cli.py @@ -383,8 +383,8 @@ def arg( return Field(FieldKind.FLAG, shortName, longName, description, default) -def operand(longName: str = "", description: str = "") -> Any: - return Field(FieldKind.OPERAND, None, longName, description) +def operand(longName: str = "", description: str = "", default: Any = None) -> Any: + return Field(FieldKind.OPERAND, None, longName, description, default) def extra(longName: str = "", description: str = "") -> Any: @@ -475,8 +475,14 @@ class Schema: return arg raise ValueError(f"Unknown argument '{key}'") - def _setOperand(self, tok: OperandToken): - return + def _setOperand(self, obj: Any, value: Any): + if len(self.operands) == 0: + raise ValueError(f"Unexpected operand '{value}'") + + for operand in self.operands: + if operand.getAttr(obj) is None or operand.isList(): + operand.putValue(obj, value) + return def _instanciate(self) -> Any: if self.typ is None: @@ -484,6 +490,16 @@ class Schema: res = self.typ() for arg in self.args: arg.setDefault(res) + + for operand in self.operands: + if operand.isList(): + setattr(res, operand._fieldName, []) + else: + setattr(res, operand._fieldName, None) + + if self.extras: + self.extras.setDefault(res) + return res def parse(self, args: list[str]) -> Any: @@ -499,7 +515,7 @@ class Schema: if stack[0] == "--": if not self.extras: raise ValueError("Unexpected '--'") - self._setExtra(res, stack.pop(0)) + self.extras.putValue(res, stack[1:]) break toks = parseArg(stack.pop(0)) @@ -508,7 +524,7 @@ class Schema: arg = self._lookupArg(tok.key, tok.short) arg.putValue(res, tok.value, tok.subkey) elif isinstance(tok, OperandToken): - self._setOperand(tok) + self._setOperand(res, tok.value) else: raise ValueError(f"Unexpected token: {type(tok)}") @@ -634,10 +650,14 @@ class Command: self.callable() if self.subcommands: - if len(rest) == 0 and not self.populated: - raise ValueError("Expected subcommand") + if len(rest) > 0: + if not self.populated: + raise ValueError("Expected subcommand") + else: + self.lookupSubcommand(rest[0]).eval(rest) else: - self.lookupSubcommand(rest[0]).eval(rest) + print("Usage: " + cmd + self.usage(), end="\n\n") + return elif len(rest) > 0: raise ValueError(f"Unknown operand '{rest[0]}'") diff --git a/cutekit/plugins.py b/cutekit/plugins.py index 7c7bda4..ad3516b 100644 --- a/cutekit/plugins.py +++ b/cutekit/plugins.py @@ -56,5 +56,5 @@ class PluginsArgs: def setup(args: PluginsArgs): - if args.safemod: + if not args.safemod: loadAll() diff --git a/cutekit/shell.py b/cutekit/shell.py index 82a38e7..db6bf9b 100644 --- a/cutekit/shell.py +++ b/cutekit/shell.py @@ -467,8 +467,11 @@ def _(args: _ProfileArgs): profile(args.fullCmd(), rate=args.rate, what=args.what) -class CompresseArgs: +class CompressFormatArg: format: str = cli.arg(None, "format", "The compression format", default="zstd") + + +class CompresseArgs(CompressFormatArg): dest: Optional[str] = cli.arg(None, "dest", "The destination file or directory") path: str = cli.operand("path", "The file or directory to compress") diff --git a/tests/test_cli.py b/tests/test_cli.py index 92769e3..810b0ba 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -211,15 +211,6 @@ def test_cli_arg_dict_str(): ) -class StrOptArg: - value: str | None = cli.arg(None, "value") - - -def test_cli_arg_str_opt(): - assert_equal(extractParse(StrOptArg, []).value, None) - assert_equal(extractParse(StrOptArg, ["--value=foo"]).value, "foo") - - class FooArg: foo: str = cli.arg(None, "foo") @@ -237,3 +228,37 @@ def test_cli_arg_inheritance(): assert_equal(res.foo, "foo") assert_equal(res.bar, "bar") assert_equal(res.baz, "baz") + + +class ExtraArg: + value: str = cli.arg(None, "value") + extra: list[str] = cli.extra("extra") + + +def test_cli_extra_args(): + res = extractParse(ExtraArg, ["--value=foo", "--", "bar", "baz"]) + assert_equal(res.value, "foo") + assert_equal(res.extra, ["bar", "baz"]) + + +class StrOperandArg: + value: str = cli.operand(None, "value") + + +def test_cli_operand_args(): + res = extractParse(StrOperandArg, ["foo"]) + assert_equal(res.value, "foo") + + +class ListOperandArg: + value: list[str] = cli.operand(None, "value") + + +def test_cli_operand_list_args(): + res = extractParse(ListOperandArg, ["foo", "bar"]) + assert_equal(res.value, ["foo", "bar"]) + + +def test_cli_operand_list_args_empty(): + res = extractParse(ListOperandArg, []) + assert_equal(res.value, [])