diff --git a/README.md b/README.md index d754c85..7bac03f 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ Podstawowe komendy tokenow: ./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03 ``` -`tokens scan` wypisuje waskie tabele TSV. Dla jednego endpointu zobaczysz +`tokens scan` wypisuje waska tabele. Dla jednego endpointu zobaczysz osobny wiersz `source=repo` oraz osobny wiersz `source=tokens.json`. ## Fetch i switch diff --git a/doc/rvctl.md b/doc/rvctl.md index c2ec6de..0afa228 100644 --- a/doc/rvctl.md +++ b/doc/rvctl.md @@ -304,9 +304,10 @@ Typowy wynik: ```text items -itemsourceremotekindusertokenresultstatusurl -1repor1authu1remoteexistingin_synchttp://77.90.8.171:3001 -1tokens.jsonstoreu1t1presentin_synchttp://77.90.8.171:3001 +item source remote kind user token_ref result status url +---- ----------- ---------- -------- ---------- ---------- ---------------- ----------- -------------------------------- +1 repo r1 auth u1 remote existing in_sync http://77.90.8.171:3001 +1 tokens.json store u1 t1 present in_sync http://77.90.8.171:3001 ``` Jesli remote istnieje, ale ma URL bez `LOGIN:TOKEN@`, wynik bedzie mial @@ -376,9 +377,10 @@ repo_root... token_path... items -itemsourceremotekindusertokenresultstatusurl -1repor1plainno_credentialsstore_aheadhttp://77.90.8.171:3001 -1tokens.jsonstoreu1t1presentstore_aheadhttp://77.90.8.171:3001 +item source remote kind user token_ref result status url +---- ----------- ---------- -------- ---------- ---------- ---------------- ----------- -------------------------------- +1 repo r1 plain no_credentials store_ahead http://77.90.8.171:3001 +1 tokens.json store u1 t1 present store_ahead http://77.90.8.171:3001 status itemvalue diff --git a/doc/tokens.md b/doc/tokens.md index d542ebd..86ae244 100644 --- a/doc/tokens.md +++ b/doc/tokens.md @@ -84,7 +84,7 @@ Dzialanie: - skanuje remote URL-e w repo - zapisuje znalezione tokeny do `tokens.json` - zapisuje je per endpoint serwera -- wypisuje domyslnie tylko waska tabele TSV `items` +- wypisuje domyslnie tylko waska tabele `items` - z `--verbose` dopisuje diagnostyczne sekcje `context` oraz `scan` Tabela `items` porownuje dwa zrodla dla tego samego endpointu. Ten sam `item` @@ -100,10 +100,10 @@ Kolumny w tabeli `items`: - `remote` - nazwa remote, na przyklad `r1`; tylko dla `source=repo` - `kind` - `auth`, `plain`, `store` albo `missing` - `user` - login odczytany z URL albo ze store -- `token` - `remote` dla tokenu w URL albo nazwa tokenu ze store, na przyklad `t1` +- `token_ref` - referencja bez sekretu: `remote` dla tokenu w URL albo nazwa tokenu ze store, na przyklad `t1` - `result` - `added`, `existing`, `present`, `no_credentials` albo `missing` - `status` - relacja repo do `tokens.json`, na przyklad `in_sync` albo `store_ahead` -- `url` - endpoint serwera bez sekretu, trzymany jako ostatnia kolumna +- `url` - endpoint serwera bez sekretu, trzymany jako ostatnia kolumna i przycinany do szerokosci tabeli Przyklad: diff --git a/rvctl.py b/rvctl.py index 7be6f94..3b96785 100644 --- a/rvctl.py +++ b/rvctl.py @@ -667,6 +667,35 @@ def print_status_counts(status_counts: dict[str, int]) -> None: print(f"{status_name}\t{status_counts[status_name]}") +TOKEN_ITEM_COLUMNS = [ + ("item", 4), + ("source", 11), + ("remote", 10), + ("kind", 8), + ("user", 10), + ("token_ref", 10), + ("result", 16), + ("status", 12), + ("url", 32), +] + + +def fit_cell(value: str, width: int) -> str: + if len(value) <= width: + return value.ljust(width) + if width <= 1: + return value[:width] + return f"{value[:width - 1]}…" + + +def print_token_item_table(rows: list[dict[str, str]]) -> None: + print("items") + print(" ".join(fit_cell(name, width) for name, width in TOKEN_ITEM_COLUMNS)) + print(" ".join("-" * width for _, width in TOKEN_ITEM_COLUMNS)) + for row in rows: + print(" ".join(fit_cell(row.get(name, ""), width) for name, width in TOKEN_ITEM_COLUMNS)) + + def print_token_item_rows( endpoint_names: list[str], repo_servers: dict[str, dict], @@ -681,8 +710,7 @@ def print_token_item_rows( if endpoint: scan_rows_by_endpoint.setdefault(endpoint, []).append(row) - print("items") - print("item\tsource\tremote\tkind\tuser\ttoken\tresult\tstatus\turl") + item_rows: list[dict[str, str]] = [] for index, endpoint in enumerate(endpoint_names, start=1): item_id = str(index) repo_entry = repo_servers.get(endpoint) @@ -695,43 +723,104 @@ def print_token_item_rows( if repo_rows: for row in repo_rows: token_label = "remote" if row["url_kind"] == "auth" else "" - print( - f"{item_id}\trepo\t{row['remote']}\t{row['url_kind']}\t" - f"{row['user']}\t{token_label}\t{row['result']}\t{status_name}\t{endpoint}" + item_rows.append( + { + "item": item_id, + "source": "repo", + "remote": row["remote"], + "kind": row["url_kind"], + "user": row["user"], + "token_ref": token_label, + "result": row["result"], + "status": status_name, + "url": endpoint, + } ) elif repo_entry is None: - print(f"{item_id}\trepo\t\tmissing\t\t\tmissing\t{status_name}\t{endpoint}") + item_rows.append( + { + "item": item_id, + "source": "repo", + "kind": "missing", + "result": "missing", + "status": status_name, + "url": endpoint, + } + ) else: repo_kind, repo_result = repo_result_for_entry(repo_entry) remote_names = ",".join(sorted(repo_entry.get("remotes", set()))) repo_users = token_name_rows(repo_entry.get("users", {})) if repo_users: for user_name, _ in repo_users: - print( - f"{item_id}\trepo\t{remote_names}\t{repo_kind}\t" - f"{user_name}\tremote\t{repo_result}\t{status_name}\t{endpoint}" + item_rows.append( + { + "item": item_id, + "source": "repo", + "remote": remote_names, + "kind": repo_kind, + "user": user_name, + "token_ref": "remote", + "result": repo_result, + "status": status_name, + "url": endpoint, + } ) else: - print( - f"{item_id}\trepo\t{remote_names}\t{repo_kind}\t\t\t" - f"{repo_result}\t{status_name}\t{endpoint}" + item_rows.append( + { + "item": item_id, + "source": "repo", + "remote": remote_names, + "kind": repo_kind, + "result": repo_result, + "status": status_name, + "url": endpoint, + } ) if store_entry is None: - print(f"{item_id}\ttokens.json\t\tmissing\t\t\tmissing\t{status_name}\t{endpoint}") + item_rows.append( + { + "item": item_id, + "source": "tokens.json", + "kind": "missing", + "result": "missing", + "status": status_name, + "url": endpoint, + } + ) continue store_users = token_name_rows(store_entry.get("users", {})) if not store_users: - print(f"{item_id}\ttokens.json\t\tstore\t\t\tempty\t{status_name}\t{endpoint}") + item_rows.append( + { + "item": item_id, + "source": "tokens.json", + "kind": "store", + "result": "empty", + "status": status_name, + "url": endpoint, + } + ) continue for user_name, token_name in store_users: - print( - f"{item_id}\ttokens.json\t\tstore\t{user_name}\t" - f"{token_name}\tpresent\t{status_name}\t{endpoint}" + item_rows.append( + { + "item": item_id, + "source": "tokens.json", + "kind": "store", + "user": user_name, + "token_ref": token_name, + "result": "present", + "status": status_name, + "url": endpoint, + } ) + print_token_item_table(item_rows) return status_counts