Properly handle extra and operands

This commit is contained in:
Sleepy Monax 2024-02-15 15:28:50 +01:00
parent 2268f94d1f
commit cc9f7c7b3f
6 changed files with 71 additions and 26 deletions

View file

@ -95,7 +95,6 @@ def main() -> int:
except RuntimeError as e:
logging.exception(e)
vt100.error(str(e))
cli.usage()
return 1
except KeyboardInterrupt:

View file

@ -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]

View file

@ -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]}'")

View file

@ -56,5 +56,5 @@ class PluginsArgs:
def setup(args: PluginsArgs):
if args.safemod:
if not args.safemod:
loadAll()

View file

@ -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")

View file

@ -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, [])