From f95970836309d5370792ebf707698e57b2cbe19a Mon Sep 17 00:00:00 2001 From: mpabi Date: Wed, 29 Apr 2026 20:47:21 +0200 Subject: [PATCH] Auto sync workspace manifest on first use --- README.md | 12 +++++++----- doc/rvctl.md | 7 ++++++- doc/series.md | 10 ++++++---- doc/workspace.md | 5 +++++ rvctl.py | 42 +++++++++++++++++++++++++++++++++++------- 5 files changed, 59 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 92ed877..cff8902 100644 --- a/README.md +++ b/README.md @@ -296,10 +296,13 @@ Po konfiguracji tokenów najpierw sprawdź stan store: ./rvctl tokens compare ``` -Następnie pobierz albo zaktualizuj publiczny manifest wspólnego workspace: +Następnie wylistuj dostępne serie. Jeżeli manifestu `workspace-info` jeszcze +nie ma, `rvctl` pobierze go automatycznie do `meta/workspace-info`. Jeżeli +katalog `series` w workspace jeszcze nie istnieje, `rvctl` utworzy go +automatycznie: ```bash -./rvctl workspace sync +./rvctl series list ``` Manifest trafia do: @@ -308,11 +311,10 @@ Manifest trafia do: ~/dev/workspace/rv/meta/workspace-info ``` -Następnie wylistuj dostępne serie. Jeżeli katalog `series` w workspace jeszcze -nie istnieje, `rvctl` utworzy go automatycznie: +Jeżeli chcesz jawnie odświeżyć istniejący manifest, użyj: ```bash -./rvctl series list +./rvctl workspace sync ``` Przykładowy wynik: diff --git a/doc/rvctl.md b/doc/rvctl.md index 7daa783..011af9d 100644 --- a/doc/rvctl.md +++ b/doc/rvctl.md @@ -285,9 +285,14 @@ Klonuje albo aktualizuje repo `edu-workspace/workspace-info` do katalogu ./rvctl workspace sync --dry-run ``` +Jeżeli lokalnej kopii manifestu jeszcze nie ma, komendy zależne od manifestu +same wykonują bootstrap przez `git clone`. Istniejącego manifestu nie +aktualizują automatycznie; do tego służy jawne `workspace sync`. + ## `series list` -Listuje serie dostępne w `workspace-info` i workspace. Komenda tworzy +Listuje serie dostępne w `workspace-info` i workspace. Jeżeli `workspace-info` +jeszcze nie istnieje lokalnie, komenda pobiera je automatycznie. Komenda tworzy `series_root`, jeżeli katalog jeszcze nie istnieje. Format wyjścia: diff --git a/doc/series.md b/doc/series.md index a1b92b1..9eceec2 100644 --- a/doc/series.md +++ b/doc/series.md @@ -14,13 +14,14 @@ Komendy kart pracy dzielimy na trzy poziomy: `rvctl` tworzy `series_root`, jeżeli katalog jeszcze nie istnieje. Lista serii i kart pochodzi docelowo z publicznego manifestu `~/dev/workspace/rv/meta/workspace-info/workspace.json`. Jeżeli manifestu nie -ma, narzędzie używa starego fallbacku przez `original_series_root`. +ma, komendy zależne od serii automatycznie klonują repo +`edu-workspace/workspace-info`. Jeżeli klonowanie nie jest możliwe, narzędzie +używa starego fallbacku przez `original_series_root`. ## Szybki przepływ ```bash ./rvctl tokens compare -./rvctl workspace sync ./rvctl series list ./rvctl series cards list inf ./rvctl series cards fetch inf bss @@ -35,8 +36,9 @@ Dla karty `bss` właściwym repo jest `lab-rv32i-strlen-bss-data-stack`. ### `series list` Listuje dostępne serie z manifestu `workspace-info` oraz liczbę kart już -pobranych do lokalnego workspace. Jeżeli `~/dev/workspace/rv/series` nie -istnieje, komenda tworzy ten katalog. +pobranych do lokalnego workspace. Jeżeli manifestu jeszcze nie ma, komenda +pobiera go automatycznie. Jeżeli `~/dev/workspace/rv/series` nie istnieje, +komenda tworzy ten katalog. ```bash ./rvctl series list diff --git a/doc/workspace.md b/doc/workspace.md index 03648df..fd2acae 100644 --- a/doc/workspace.md +++ b/doc/workspace.md @@ -46,3 +46,8 @@ Aktualizacja manifestu: ```bash ./rvctl workspace sync ``` + +Komendy zależne od manifestu, na przykład `series list`, `series cards list`, +`series cards fetch` i `tasks list`, automatycznie klonują `workspace-info`, +jeżeli lokalnej kopii jeszcze nie ma. Nie wykonują automatycznego `pull` na +istniejącym repo; do odświeżania służy jawne `workspace sync`. diff --git a/rvctl.py b/rvctl.py index d402b1b..9938468 100755 --- a/rvctl.py +++ b/rvctl.py @@ -3325,6 +3325,38 @@ def workspace_info_status(config: WorkspaceConfig) -> str: return "missing" +def sync_workspace_info(config: WorkspaceConfig, pull_existing: bool = True) -> str: + info_root = workspace_info_root(config) + info_root.parent.mkdir(parents=True, exist_ok=True) + if (info_root / ".git").is_dir(): + if pull_existing: + subprocess.run(["git", "-C", str(info_root), "pull", "--ff-only"], check=True) + config.workspace_info = json.loads(config.workspace_info_path.read_text(encoding="utf-8")) + return "pulled" + if config.workspace_info_path.is_file(): + config.workspace_info = json.loads(config.workspace_info_path.read_text(encoding="utf-8")) + return "existing" + raise SystemExit(f"Workspace info repo exists but manifest is missing: {config.workspace_info_path}") + if info_root.exists(): + raise SystemExit(f"Workspace info path exists but is not a git repo: {info_root}") + + print(f"workspace-info missing; cloning {config.workspace_info_url}", file=sys.stderr) + subprocess.run(["git", "clone", config.workspace_info_url, str(info_root)], check=True) + if not config.workspace_info_path.is_file(): + raise SystemExit(f"Workspace info clone does not contain manifest: {config.workspace_info_path}") + config.workspace_info = json.loads(config.workspace_info_path.read_text(encoding="utf-8")) + return "cloned" + + +def ensure_workspace_info(config: WorkspaceConfig) -> None: + if config.workspace_info: + return + if config.workspace_info_path.is_file(): + config.workspace_info = json.loads(config.workspace_info_path.read_text(encoding="utf-8")) + return + sync_workspace_info(config, pull_existing=False) + + def run_workspace(config: WorkspaceConfig, args: argparse.Namespace) -> None: if args.workspace_command == "show": print(f"workspace_info_path\t{config.workspace_info_path}") @@ -3343,13 +3375,7 @@ def run_workspace(config: WorkspaceConfig, args: argparse.Namespace) -> None: print(f"status\t{workspace_info_status(config)}") print(f"command\t{'pull' if (info_root / '.git').is_dir() else 'clone'}") return - info_root.parent.mkdir(parents=True, exist_ok=True) - if (info_root / ".git").is_dir(): - subprocess.run(["git", "-C", str(info_root), "pull", "--ff-only"], check=True) - elif info_root.exists(): - raise SystemExit(f"Workspace info path exists but is not a git repo: {info_root}") - else: - subprocess.run(["git", "clone", config.workspace_info_url, str(info_root)], check=True) + sync_workspace_info(config, pull_existing=True) print(f"workspace_info_path\t{config.workspace_info_path}") print(f"status\tready") return @@ -3810,6 +3836,8 @@ 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"}: + ensure_workspace_info(config) if args.command == "show-config": print_config(config)