From cb1fc4d450239d092e8a941033da74e8a6f40c33 Mon Sep 17 00:00:00 2001 From: mpabi Date: Wed, 29 Apr 2026 20:03:42 +0200 Subject: [PATCH] Support directory tasks in cards --- README.md | 8 ++++---- doc/rvctl.md | 3 ++- doc/series.md | 10 ++++++---- rvctl.py | 52 ++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index b12c195..f7fccc8 100644 --- a/README.md +++ b/README.md @@ -351,10 +351,10 @@ karcie z `workspace.json`, czyli tutaj na `inf bss`: Przykładowy wynik: ```text -inf bss task1_bss ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks -inf bss task2_data ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks -inf bss task3_stack_unused ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks -inf bss task4_stack_strlen ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks +inf bss task1_bss ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks/task1_bss.s +inf bss task2_data ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks/task2_data.s +inf bss task3_stack_unused ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks/task3_stack_unused.s +inf bss task4_stack_strlen ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks/task4_stack_strlen.s ``` Przełącz się na wybrane zadanie. `rvctl` bierze login ucznia ze store tokenów, diff --git a/doc/rvctl.md b/doc/rvctl.md index 4746e7d..979590c 100644 --- a/doc/rvctl.md +++ b/doc/rvctl.md @@ -431,7 +431,8 @@ Przykład: ## `series cards tasks list SERIES CARD` -Listuje zadania z `src/tasks` pobranej karty. +Listuje zadania pobranej karty. `rvctl` rozpoznaje pliki lub katalogi `task*` +w `src/tasks`, a także katalogi `task*` bezpośrednio w korzeniu karty. Argumenty: diff --git a/doc/series.md b/doc/series.md index e97601b..29d01fe 100644 --- a/doc/series.md +++ b/doc/series.md @@ -131,6 +131,8 @@ Do codziennej pracy z domyślną kartą można używać krótszego namespace `ta ### `series cards tasks list SERIES CARD` Listuje zadania dostępne w konkretnej karcie. +`rvctl` rozpoznaje zadania zapisane jako pliki lub katalogi `task*` w +`src/tasks`, a także katalogi `task*` bezpośrednio w korzeniu karty. ```bash ./rvctl series cards tasks list inf bss @@ -145,10 +147,10 @@ Skrót dla domyślnej karty: Przykładowy wynik: ```text -inf bss task1_bss ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks -inf bss task2_data ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks -inf bss task3_stack_unused ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks -inf bss task4_stack_strlen ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks +inf bss task1_bss ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks/task1_bss.s +inf bss task2_data ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks/task2_data.s +inf bss task3_stack_unused ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks/task3_stack_unused.s +inf bss task4_stack_strlen ~/dev/workspace/rv/series/inf/lab-rv32i-strlen-bss-data-stack/src/tasks/task4_stack_strlen.s ``` ### `series cards tasks show SERIES CARD TASK` diff --git a/rvctl.py b/rvctl.py index fd13785..66d48d5 100755 --- a/rvctl.py +++ b/rvctl.py @@ -53,6 +53,12 @@ class WorkspaceConfig: git: GitConfig +@dataclass(frozen=True) +class TaskEntry: + name: str + path: Path + + SCOPE_FIELDS = [ ("a", "activitypub"), ("A", "admin"), @@ -2623,16 +2629,31 @@ def print_key_values(values: dict[str, str]) -> None: print(f"{key}\t{value}") -def task_names(card_path: Path) -> list[str]: +def task_name_from_path(path: Path) -> str: + if path.is_file(): + return path.stem + return path.name + + +def task_entries(card_path: Path) -> list[TaskEntry]: + entries: dict[str, TaskEntry] = {} task_root = card_path / "src" / "tasks" - if not task_root.is_dir(): - return [] - names = { - path.stem - for path in task_root.iterdir() - if path.is_file() and path.stem.startswith("task") - } - return sorted(names) + if task_root.is_dir(): + for path in sorted(task_root.iterdir()): + name = task_name_from_path(path) + if (path.is_file() or path.is_dir()) and name.startswith("task"): + entries[name] = TaskEntry(name=name, path=path) + + for path in sorted(card_path.iterdir()): + name = task_name_from_path(path) + if (path.is_file() or path.is_dir()) and name.startswith("task"): + entries.setdefault(name, TaskEntry(name=name, path=path)) + + return [entries[name] for name in sorted(entries)] + + +def task_names(card_path: Path) -> list[str]: + return [entry.name for entry in task_entries(card_path)] def task_branch_part(task_name: str) -> str: @@ -2733,22 +2754,23 @@ def set_branch_upstream(repo_path: Path, branch_name: str, remote_name: str, dry def print_card_tasks(config: WorkspaceConfig, series_name: str, card_name: str) -> None: card_path = resolve_workspace_card_path(config, series_name, card_name) - for task_name in task_names(card_path): - print(f"{series_name}\t{card_label_from_repo_name(card_path.name)}\t{task_name}\t{card_path / 'src' / 'tasks'}") + for entry in task_entries(card_path): + print(f"{series_name}\t{card_label_from_repo_name(card_path.name)}\t{entry.name}\t{entry.path}") def print_card_task(config: WorkspaceConfig, series_name: str, card_name: str, task_name: str) -> None: card_path = resolve_workspace_card_path(config, series_name, card_name) - matches = [name for name in task_names(card_path) if name == task_name or task_name in name] + matches = [entry for entry in task_entries(card_path) if entry.name == task_name or task_name in entry.name] if not matches: raise SystemExit(f"Missing task '{task_name}' in card: {card_path}") if len(matches) > 1: - raise SystemExit(f"Ambiguous task '{task_name}'. Matches: {', '.join(matches)}") + raise SystemExit(f"Ambiguous task '{task_name}'. Matches: {', '.join(entry.name for entry in matches)}") + task_entry = matches[0] print(f"series\t{series_name}") print(f"card\t{card_label_from_repo_name(card_path.name)}") - print(f"task\t{matches[0]}") + print(f"task\t{task_entry.name}") print(f"card_path\t{card_path}") - print(f"task_root\t{card_path / 'src' / 'tasks'}") + print(f"task_path\t{task_entry.path}") def switch_card_task(