Add tabular rvctl command overview
This commit is contained in:
@@ -1108,6 +1108,140 @@ def add_store_selection_options(parser: argparse.ArgumentParser) -> None:
|
||||
parser.add_argument("--token-name", help="Token name inside the selected user entry, for example 't1'.")
|
||||
|
||||
|
||||
def print_table(headers: list[str], rows: list[list[str]]) -> None:
|
||||
widths = [len(header) for header in headers]
|
||||
for row in rows:
|
||||
for index, value in enumerate(row):
|
||||
widths[index] = max(widths[index], len(value))
|
||||
|
||||
print(" ".join(header.ljust(widths[index]) for index, header in enumerate(headers)))
|
||||
print(" ".join("-" * width for width in widths))
|
||||
for row in rows:
|
||||
print(" ".join(value.ljust(widths[index]) for index, value in enumerate(row)))
|
||||
|
||||
|
||||
def print_config_summary(config_path: Path) -> None:
|
||||
try:
|
||||
config = load_config(config_path)
|
||||
except (OSError, json.JSONDecodeError, KeyError, TypeError, ValueError) as error:
|
||||
print("Config:")
|
||||
print_table(
|
||||
["field", "value"],
|
||||
[
|
||||
["config", str(config_path)],
|
||||
["status", f"unavailable: {error}"],
|
||||
],
|
||||
)
|
||||
return
|
||||
|
||||
print("Config:")
|
||||
print_table(
|
||||
["field", "value"],
|
||||
[
|
||||
["config", str(config.config_path)],
|
||||
["workspace", str(config.workspace_root)],
|
||||
["series", str(config.series_root)],
|
||||
["tokens", str(config.token_path)],
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def print_main_overview(config_path: Path) -> None:
|
||||
print("RVCTL - launcher workspace RV")
|
||||
print()
|
||||
print("Usage:")
|
||||
print(" ./rvctl <command> [options]")
|
||||
print(" ./rvctl tokens <command> [options]")
|
||||
print(" ./rvctl <command> --help")
|
||||
print()
|
||||
print("Commands:")
|
||||
print_table(
|
||||
["command", "arguments", "purpose"],
|
||||
[
|
||||
["show-config", "", "show resolved paths and Git defaults"],
|
||||
["list-series", "", "list series from workspace"],
|
||||
["list-cards", "[series]", "list cards in a selected series"],
|
||||
["tmux-container", "[series] [card]", "start tmux with container in pane 0"],
|
||||
["submission", "[series] [card] --class K --nick N", "prepare answer repo and student branch"],
|
||||
["tokens", "scan|read|stats|write|update", "manage tokens.json and Git remote credentials"],
|
||||
],
|
||||
)
|
||||
print()
|
||||
print("Typical flow:")
|
||||
print_table(
|
||||
["step", "command", "result"],
|
||||
[
|
||||
["1", "./rvctl tokens scan", "read credentials from remotes if present"],
|
||||
["2", "./rvctl list-series", "choose a series"],
|
||||
["3", "./rvctl list-cards inf", "choose a card"],
|
||||
["4", "./rvctl tmux-container inf <card>", "start the working container"],
|
||||
["5", "./rvctl submission inf <card> --class 4i --nick u1", "prepare answer remote and branch"],
|
||||
],
|
||||
)
|
||||
print()
|
||||
print_config_summary(config_path)
|
||||
print()
|
||||
print("Docs:")
|
||||
print(" doc/rvctl.md")
|
||||
print(" doc/tokens.md")
|
||||
print(" doc/workspace.md")
|
||||
|
||||
|
||||
def print_tokens_overview() -> None:
|
||||
print("RVCTL tokens - token store and Git remote credentials")
|
||||
print()
|
||||
print("Usage:")
|
||||
print(" ./rvctl tokens <command> [options]")
|
||||
print(" ./rvctl tokens <command> --help")
|
||||
print()
|
||||
print("Commands:")
|
||||
print_table(
|
||||
["command", "common options", "direction", "purpose"],
|
||||
[
|
||||
["scan", "[--repo PATH]", "repo -> tokens.json", "scan remotes and store credentials found in URLs"],
|
||||
["read", "[--server ENDPOINT]", "tokens.json", "show servers, users and token names"],
|
||||
["stats", "[--repo PATH]", "repo + tokens.json", "compare remote URLs with local token store"],
|
||||
["write", "--remote R [--replace]", "tokens.json -> repo", "write selected token into a remote URL"],
|
||||
["update", "--from remotes|store", "selected", "run scan or write with explicit direction"],
|
||||
],
|
||||
)
|
||||
print()
|
||||
print("Examples:")
|
||||
print_table(
|
||||
["case", "command"],
|
||||
[
|
||||
["scan current repo", "./rvctl tokens scan"],
|
||||
["scan selected card", "./rvctl tokens scan --repo ~/dev/workspace/rv/series/inf/03"],
|
||||
["compare state", "./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03"],
|
||||
["write auth to r1", "./rvctl tokens write --repo PATH --remote r1 --server URL --user u1 --token-name t1"],
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def extract_config_path(argv: list[str]) -> tuple[Path, list[str]]:
|
||||
config_path = Path(__file__).with_name("workspace.json")
|
||||
remaining: list[str] = []
|
||||
index = 0
|
||||
while index < len(argv):
|
||||
arg = argv[index]
|
||||
if arg == "--config":
|
||||
if index + 1 >= len(argv):
|
||||
remaining.append(arg)
|
||||
index += 1
|
||||
continue
|
||||
config_path = Path(argv[index + 1])
|
||||
index += 2
|
||||
continue
|
||||
if arg.startswith("--config="):
|
||||
config_path = Path(arg.split("=", 1)[1])
|
||||
index += 1
|
||||
continue
|
||||
remaining.append(arg)
|
||||
index += 1
|
||||
|
||||
return config_path, remaining
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="rvctl",
|
||||
@@ -1223,6 +1357,14 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
|
||||
|
||||
def main() -> int:
|
||||
config_path, command_args = extract_config_path(sys.argv[1:])
|
||||
if not command_args or command_args == ["help"]:
|
||||
print_main_overview(config_path)
|
||||
return 0
|
||||
if command_args in (["tokens"], ["help", "tokens"], ["tokens", "help"]):
|
||||
print_tokens_overview()
|
||||
return 0
|
||||
|
||||
parser = build_parser()
|
||||
args = parser.parse_args()
|
||||
config = load_config(args.config)
|
||||
|
||||
Reference in New Issue
Block a user