From 5be73801907bff948dc0b2ac52035d3e15880164 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 19 Jun 2026 10:40:14 +0200 Subject: [PATCH] Use actions for feature and machine commands Instead of using positional arguments and options, follow the config command, and use named actions: - info, to show the feature/machine metadata - list, to list all the available features/machines This is technically a breaking change, but luckily we haven't yet released moonforge-cli. --- src/moonforgecli/feature.py | 112 ++++++++++++++++++------------------ src/moonforgecli/machine.py | 87 ++++++++++++++-------------- 2 files changed, 102 insertions(+), 97 deletions(-) diff --git a/src/moonforgecli/feature.py b/src/moonforgecli/feature.py index ffbeef5..20667e4 100644 --- a/src/moonforgecli/feature.py +++ b/src/moonforgecli/feature.py @@ -14,62 +14,64 @@ def add_args(parser) -> None: - parser.add_argument("--list", default=False, dest="list", action="store_true", - help="list all available features") - parser.add_argument("features", nargs="*", - help="optional list of features to query") + parser.add_argument("action", choices=["info", "list"], help="action to perform") + parser.add_argument("features", nargs="*", help="optional list of features to query", default=[]) def run(options) -> int: - if options.list: - res = [term.heading(text="Available features:")] - max_name_len = 0 - for f in available_features(): - max_name_len = len(f.name) if len(f.name) > max_name_len else max_name_len - for f in available_features(): - name = term.option(f.name) - pad = " ".ljust(max_name_len - len(f.name) + 1) - res.append(f"- {name}:{pad}{f.description}") - print("\n".join(res)) - return 0 - - if len(options.features) == 0: - heading = term.heading("usage:") - command = term.command("moonforge") - option = term.option("feature") - print(f"{heading} {command} {option} FEATURE...") - return 1 - - features = [] - for feat in options.features: - try: - f = get_feature(feat) - except IndexError as err: - log.error(f"{err}") - features.append(f) - for feature in features: - res = [] - res.append(f"{term.heading('Feature:')} {term.bold(feature.name)}") - res.append("") - res.append(f" {feature.description}") - res.append("") - if feature.variables is not None: - res.append(term.heading("Variables:")) - for var in feature.variables: - res.append(f" - {term.green(var.name)}:") - res.append(f" {var.description}") - res.append(f" Default value: {var.default}") - res.append("") - if len(feature.includes) > 0: - res.append(term.heading("Includes:")) - for include in feature.includes: - res.append(f" - {term.green(include.file)} from {term.green(include.repo)}") - res.append("") - if feature.conflicts is not None and len(feature.conflicts) > 0: - res.append(term.heading("Conflicts:")) - for conflict in feature.conflicts: - res.append(f" - {term.red(conflict)}") - res.append("") - print("\n".join(res)) - + match options.action: + case "list": + if len(options.features) != 0: + heading = term.heading("usage:") + command = term.command("moonforge") + option = term.option("feature") + print(f"{heading} {command} {option} list") + return 1 + res = [term.heading(text="Available features:")] + max_name_len = 0 + for f in available_features(): + max_name_len = len(f.name) if len(f.name) > max_name_len else max_name_len + for f in available_features(): + name = term.option(f.name) + pad = " ".ljust(max_name_len - len(f.name) + 1) + res.append(f"- {name}:{pad}{f.description}") + print("\n".join(res)) + case "info": + if len(options.features) == 0: + heading = term.heading("usage:") + command = term.command("moonforge") + option = term.option("feature") + print(f"{heading} {command} {option} info FEATURE ...") + return 1 + features = [] + for feat in options.features: + try: + f = get_feature(feat) + features.append(f) + except IndexError as err: + log.error(f"{err}") + for feature in features: + res = [] + res.append(f"{term.heading('Feature:')} {term.bold(feature.name)}") + res.append("") + res.append(f" {feature.description}") + res.append("") + if feature.variables is not None: + res.append(term.heading("Variables:")) + for var in feature.variables: + res.append(f" - {term.green(var.name)}:") + res.append(f" {var.description}") + res.append(f" Default value: {var.default}") + res.append("") + if len(feature.includes) > 0: + res.append(term.heading("Includes:")) + for include in feature.includes: + res.append(f" - {term.green(include.file)} from {term.green(include.repo)}") + res.append("") + if feature.conflicts is not None and len(feature.conflicts) > 0: + res.append(term.heading("Conflicts:")) + for conflict in feature.conflicts: + res.append(f" - {term.red(conflict)}") + res.append("") + print("\n".join(res)) return 0 diff --git a/src/moonforgecli/machine.py b/src/moonforgecli/machine.py index d4bb15f..61e3f74 100644 --- a/src/moonforgecli/machine.py +++ b/src/moonforgecli/machine.py @@ -14,50 +14,53 @@ def add_args(parser) -> None: - parser.add_argument("--list", default=False, dest="list", action="store_true", - help="list all available machines") - parser.add_argument("machines", nargs="*", - help="optional list of machines to query") + parser.add_argument("action", choices=["info", "list"], help="action to perform") + parser.add_argument("machines", nargs="*", help="optional machines", default=[]) def run(options) -> int: - if options.list: - res = [term.heading(text="Available machines:")] - max_name_len = 0 - for m in available_machines(): - max_name_len = len(m.name) if len(m.name) > max_name_len else max_name_len - for m in available_machines(): - name = term.option(m.name) - pad = " ".ljust(max_name_len - len(m.name) + 1) - res.append(f"- {name}:{pad}{m.description}") - print("\n".join(res)) - return 0 - - if len(options.machines) == 0: - heading = term.heading("usage:") - command = term.command("moonforge") - option = term.option("machine") - print(f"{heading} {command} {option} MACHINE...") - return 1 - - machines = [] - for machine in options.machines: - try: - m = get_machine(machine) - except IndexError as err: - log.error(f"{err}") - machines.append(m) - for machine in machines: - res = [] - res.append(f"{term.heading('Machine:')} {term.bold(machine.name)}") - res.append("") - res.append(f" {machine.description}") - res.append("") - if len(machine.includes) > 0: - res.append(term.heading("Includes:")) - for include in machine.includes: - res.append(f" - {term.green(include.file)} from {term.green(include.repo)}") - res.append("") - print("\n".join(res)) + match options.action: + case "list": + if len(options.machines) != 0: + heading = term.heading("usage:") + command = term.command("moonforge") + option = term.option("info") + print(f"{heading} {command} {option} MACHINE ...") + return 1 + res = [term.heading(text="Available machines:")] + max_name_len = 0 + for m in available_machines(): + max_name_len = len(m.name) if len(m.name) > max_name_len else max_name_len + for m in available_machines(): + name = term.option(m.name) + pad = " ".ljust(max_name_len - len(m.name) + 1) + res.append(f"- {name}:{pad}{m.description}") + print("\n".join(res)) + case "info": + if len(options.machines) == 0: + heading = term.heading("usage:") + command = term.command("moonforge") + option = term.option("info") + print(f"{heading} {command} {option} MACHINE ...") + return 1 + machines = [] + for machine in options.machines: + try: + m = get_machine(machine) + machines.append(m) + except IndexError as err: + log.error(f"{err}") + for machine in machines: + res = [] + res.append(f"{term.heading('Machine:')} {term.bold(machine.name)}") + res.append("") + res.append(f" {machine.description}") + res.append("") + if len(machine.includes) > 0: + res.append(term.heading("Includes:")) + for include in machine.includes: + res.append(f" - {term.green(include.file)} from {term.green(include.repo)}") + res.append("") + print("\n".join(res)) return 0