Add default series and card commands

This commit is contained in:
mpabi
2026-05-01 23:00:32 +02:00
parent 40cfa61f4c
commit 0505b829a1
4 changed files with 215 additions and 10 deletions
+10 -2
View File
@@ -325,6 +325,7 @@ inf 3 0
Po wybraniu serii `inf` wylistuj karty:
```bash
./rvctl series use inf
./rvctl series cards list inf
```
@@ -335,12 +336,19 @@ bss lab-rv32i-strlen-bss-data-stack source rv32i-c / bss-data-stack
```
Przykładowa karta `bss` odpowiada repo `lab-rv32i-strlen-bss-data-stack`.
Pobierz do workspace:
Ustaw ją jako domyślną i pobierz do workspace:
```bash
./rvctl card use bss
./rvctl series cards fetch inf bss
```
Jeżeli chcesz jedną komendą ustawić serię i kartę, użyj:
```bash
./rvctl card use inf bss
```
Karty trafiają do `series` w workspace:
```text
@@ -370,7 +378,7 @@ answer_url http://77.90.8.171:3001/c2025-1a-inf/lab-rv32i-strlen-bss-data-st
```
Następnie wylistuj zadania w karcie. Skrót `tasks` działa na domyślnej serii i
karcie z `workspace.json`, czyli tutaj na `inf bss`:
karcie ustawionej w `workspace.json`, czyli tutaj na `inf bss`:
```bash
./rvctl tasks list
+59
View File
@@ -211,8 +211,11 @@ Komendy:
- `list-series`
- `list-cards [series]`
- `series list`
- `series use SERIES`
- `series show SERIES`
- `series fetch SERIES [--dry-run]`
- `card use CARD`
- `card use SERIES CARD`
- `series cards list SERIES`
- `series cards show SERIES CARD`
- `series cards fetch SERIES CARD`
@@ -313,6 +316,30 @@ Przykład:
./rvctl series list
```
## `series use SERIES`
Ustawia `defaults.series` w `workspace.json`.
Argumenty:
- `SERIES`
Id serii, na przykład `inf`.
Przykład:
```bash
./rvctl series use inf
```
Typowy wynik:
```text
old_series<TAB>...
series<TAB>inf
status<TAB>updated|unchanged
config<TAB>...
```
## `series show SERIES`
Pokazuje szczegóły jednej serii.
@@ -373,6 +400,38 @@ Przykład:
./rvctl series cards list inf
```
## `card use CARD`
Ustawia `defaults.card` w `workspace.json` dla aktualnie domyślnej serii.
Argumenty:
- `CARD`
Pełna nazwa repo albo unikalny fragment, na przykład `bss`.
Przykład:
```bash
./rvctl card use bss
```
## `card use SERIES CARD`
Ustawia jednocześnie `defaults.series` i `defaults.card` w `workspace.json`.
Argumenty:
- `SERIES`
Id serii, na przykład `inf`.
- `CARD`
Pełna nazwa repo albo unikalny fragment, na przykład `bss`.
Przykład:
```bash
./rvctl card use inf bss
```
## `series cards show SERIES CARD`
Pokazuje szczegóły jednej karty.
+36
View File
@@ -23,7 +23,9 @@ używa starego fallbacku przez `original_series_root`.
```bash
./rvctl tokens compare
./rvctl series list
./rvctl series use inf
./rvctl series cards list inf
./rvctl card use bss
./rvctl series cards fetch inf bss
./rvctl tasks list
./rvctl tasks switch 1
@@ -62,6 +64,15 @@ Pokazuje informacje o serii.
./rvctl series show inf
```
### `series use SERIES`
Ustawia domyślną serię w `workspace.json`. Po tej komendzie skróty kart i
zadań mogą korzystać z tej serii bez podawania jej za każdym razem.
```bash
./rvctl series use inf
```
## Karty
### `series cards list SERIES`
@@ -81,6 +92,31 @@ bss lab-rv32i-strlen-bss-data-stack source rv32i-c / bss-data-stack
Pierwsza kolumna jest krótką nazwą karty. Pełna nazwa repo zostaje w drugiej
kolumnie.
### `card use CARD`
Ustawia domyślną kartę w aktualnie domyślnej serii. Dla serii `inf`:
```bash
./rvctl card use bss
```
Komenda zapisuje `defaults.card` w `workspace.json`.
### `card use SERIES CARD`
Ustawia jednocześnie domyślną serię i domyślną kartę:
```bash
./rvctl card use inf bss
```
To jest odpowiednik:
```bash
./rvctl series use inf
./rvctl card use bss
```
### `series cards fetch SERIES CARD`
Pobiera albo aktualizuje jedną kartę w workspace. `CARD` może być krótką nazwą
+110 -8
View File
@@ -185,6 +185,40 @@ def load_config(config_path: Path) -> WorkspaceConfig:
)
def write_workspace_config(config: WorkspaceConfig, raw_config: dict) -> None:
config.config_path.parent.mkdir(parents=True, exist_ok=True)
temp_path = config.config_path.with_suffix(config.config_path.suffix + ".tmp")
temp_path.write_text(json.dumps(raw_config, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
temp_path.replace(config.config_path)
def update_config_defaults(config: WorkspaceConfig, updates: dict[str, str]) -> dict[str, str]:
raw_config = json.loads(config.config_path.read_text(encoding="utf-8"))
defaults = raw_config.get("defaults")
if not isinstance(defaults, dict):
defaults = {}
raw_config["defaults"] = defaults
result: dict[str, str] = {}
changed = False
for key, value in updates.items():
old_value = str(defaults.get(key, ""))
if old_value != value:
defaults[key] = value
changed = True
config.defaults[key] = value
result[f"old_{key}"] = old_value
result[key] = value
if changed:
write_workspace_config(config, raw_config)
result["status"] = "updated"
else:
result["status"] = "unchanged"
result["config"] = str(config.config_path)
return result
def workspace_info_root(config: WorkspaceConfig) -> Path:
return config.workspace_info_path.parent
@@ -3100,10 +3134,57 @@ def print_card_details(config: WorkspaceConfig, series_name: str, card_name: str
print(f"tasks\t{' '.join(task_names(target_path))}")
def available_series_hint(config: WorkspaceConfig) -> str:
names = sorted(
set(workspace_series_manifests(config))
| {path.name for path in source_series_directories(config)}
| {path.name for path in series_directories(config)}
)
return ", ".join(names)
def use_series_default(config: WorkspaceConfig, series_name: str) -> dict[str, str]:
series_id = slug_value(series_name, "series")
if not series_exists(config, series_id):
hint = available_series_hint(config)
suffix = f" Available: {hint}" if hint else ""
raise SystemExit(f"Missing series '{series_name}'.{suffix}")
return update_config_defaults(config, {"series": series_id})
def use_card_default(config: WorkspaceConfig, selector: list[str]) -> dict[str, str]:
if len(selector) == 1:
series_name = config.defaults.get("series")
if not series_name:
raise SystemExit("Missing default series. Use: ./rvctl series use inf")
card_name = selector[0]
updates_series = False
elif len(selector) == 2:
series_name = slug_value(selector[0], "series")
card_name = selector[1]
updates_series = True
else:
raise SystemExit("Use: ./rvctl card use <card> or ./rvctl card use <series> <card>")
if not series_exists(config, series_name):
hint = available_series_hint(config)
suffix = f" Available: {hint}" if hint else ""
raise SystemExit(f"Missing series '{series_name}'.{suffix}")
card_info = resolve_card_info(config, series_name, card_name)
updates = {"card": card_info.card_id}
if updates_series:
updates = {"series": series_name, "card": card_info.card_id}
return update_config_defaults(config, updates)
def run_series(config: WorkspaceConfig, args: argparse.Namespace) -> None:
if args.series_command == "list":
print_series(config)
return
if args.series_command == "use":
print_key_values(use_series_default(config, args.series))
return
if args.series_command == "show":
print_series_details(config, args.series)
return
@@ -3143,6 +3224,13 @@ def run_series(config: WorkspaceConfig, args: argparse.Namespace) -> None:
raise SystemExit(f"Unsupported series cards tasks command: {args.tasks_command}")
def run_card(config: WorkspaceConfig, args: argparse.Namespace) -> None:
if args.card_command == "use":
print_key_values(use_card_default(config, args.selector))
return
raise SystemExit(f"Unsupported card command: {args.card_command}")
def resolve_task_command_selector(
config: WorkspaceConfig,
values: list[str],
@@ -3736,7 +3824,8 @@ def print_main_overview(config_path: Path) -> None:
[
["show-config", "", "show resolved paths and Git defaults"],
["workspace", "show|sync", "show or update meta/workspace-info"],
["series", "list|cards|fetch|tasks", "work with series, cards and tasks"],
["series", "list|use|cards|fetch|tasks", "work with series, cards and tasks"],
["card", "use [series] card", "set the default card, optionally with the default series"],
["tasks", "list|show|switch", "shortcut for tasks in the default card"],
["env", "list|sync|build", "manage rv32i/host container environment"],
["debug", "rv32i|host [selector]", "open nvim + gdb in the selected container profile"],
@@ -3757,12 +3846,14 @@ def print_main_overview(config_path: Path) -> None:
["1", "./rvctl tokens compare", "compare repo remotes with tokens.json"],
["2", "./rvctl workspace sync", "clone or update workspace-info"],
["3", "./rvctl series list", "choose a series"],
["4", "./rvctl series cards list inf", "choose a card"],
["5", "./rvctl series cards fetch inf bss", "fetch card and prepare r1a"],
["6", "./rvctl tasks list", "list tasks from the default card"],
["7", "./rvctl tasks switch 4", "switch to the answer branch for task 4"],
["8", "./rvctl debug rv32i 4", "debug task 4 in RV32I/Hazard3"],
["9", "./rvctl debug host 4", "debug task 4 natively in a host container"],
["4", "./rvctl series use inf", "set the default series"],
["5", "./rvctl series cards list inf", "choose a card"],
["6", "./rvctl card use bss", "set the default card"],
["7", "./rvctl series cards fetch inf bss", "fetch card and prepare r1a"],
["8", "./rvctl tasks list", "list tasks from the default card"],
["9", "./rvctl tasks switch 4", "switch to the answer branch for task 4"],
["10", "./rvctl debug rv32i 4", "debug task 4 in RV32I/Hazard3"],
["11", "./rvctl debug host 4", "debug task 4 natively in a host container"],
],
)
print()
@@ -3914,6 +4005,11 @@ def build_parser() -> argparse.ArgumentParser:
tasks_short_switch_parser.add_argument("--branch", help="Override the branch name.")
tasks_short_switch_parser.add_argument("--dry-run", action="store_true", help="Print plan without switching branches.")
card_parser = subparsers.add_parser("card", help="Manage the default card selector.")
card_subparsers = card_parser.add_subparsers(dest="card_command", required=True)
card_use_parser = card_subparsers.add_parser("use", help="Set the default card, optionally with the default series.")
card_use_parser.add_argument("selector", nargs="+", help="Use '<card>' or '<series> <card>', for example 'bss' or 'inf bss'.")
tmux_parser = subparsers.add_parser(
"tmux-container",
help="Create a tmux session with pane 0 running the container shell for a selected card.",
@@ -3959,6 +4055,9 @@ def build_parser() -> argparse.ArgumentParser:
series_subparsers.add_parser("list", help="List available series.")
series_use_parser = series_subparsers.add_parser("use", help="Set the default series.")
series_use_parser.add_argument("series", help="Series id, for example 'inf'.")
series_show_parser = series_subparsers.add_parser("show", help="Show one series.")
series_show_parser.add_argument("series", help="Series id, for example 'inf'.")
@@ -4138,7 +4237,7 @@ def main() -> int:
parser = build_parser()
args = parser.parse_args()
config = load_config(args.config)
if args.command in {"list-series", "list-cards", "series", "tasks", "tmux-container", "submission", "debug", "run", "shell"}:
if args.command in {"list-series", "list-cards", "series", "card", "tasks", "tmux-container", "submission", "debug", "run", "shell"}:
ensure_workspace_info(config)
if args.command == "show-config":
@@ -4168,6 +4267,9 @@ def main() -> int:
if args.command == "tasks":
run_tasks(config, args)
return 0
if args.command == "card":
run_card(config, args)
return 0
if args.command == "tmux-container":
run_tmux_container(config, args)
return 0