Show token repo and store rows per item
This commit is contained in:
@@ -156,8 +156,8 @@ Podstawowe komendy tokenow:
|
|||||||
./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03
|
./rvctl tokens stats --repo ~/dev/workspace/rv/series/inf/03
|
||||||
```
|
```
|
||||||
|
|
||||||
`tokens scan` wypisuje tabele TSV. Remote bez `LOGIN:TOKEN@` bedzie pokazany
|
`tokens scan` wypisuje waskie tabele TSV. Dla jednego endpointu zobaczysz
|
||||||
jako `url_kind=plain` i `result=no_credentials`.
|
osobny wiersz `source=repo` oraz osobny wiersz `source=tokens.json`.
|
||||||
|
|
||||||
## Fetch i switch
|
## Fetch i switch
|
||||||
|
|
||||||
|
|||||||
+26
-20
@@ -301,19 +301,26 @@ Przelaczniki:
|
|||||||
Typowy wynik:
|
Typowy wynik:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
summary
|
context
|
||||||
repo_root<TAB>remotes<TAB>urls<TAB>scanned<TAB>auth_urls<TAB>plain_urls<TAB>unsupported_urls<TAB>found<TAB>added<TAB>servers<TAB>token_path
|
item<TAB>value
|
||||||
...<TAB>1<TAB>1<TAB>1<TAB>1<TAB>0<TAB>0<TAB>1<TAB>1<TAB>1<TAB>...
|
repo_root<TAB>...
|
||||||
|
token_path<TAB>...
|
||||||
|
|
||||||
remotes
|
scan
|
||||||
remote<TAB>endpoint<TAB>type<TAB>url_kind<TAB>user<TAB>result
|
item<TAB>value
|
||||||
r1<TAB>http://77.90.8.171:3001<TAB>gitea<TAB>auth<TAB>u1<TAB>added
|
remotes<TAB>1
|
||||||
|
urls<TAB>1
|
||||||
|
|
||||||
|
items
|
||||||
|
item<TAB>source<TAB>endpoint<TAB>remote<TAB>kind<TAB>user<TAB>token<TAB>result<TAB>status
|
||||||
|
1<TAB>repo<TAB>http://77.90.8.171:3001<TAB>r1<TAB>auth<TAB>u1<TAB>remote<TAB>existing<TAB>in_sync
|
||||||
|
1<TAB>tokens.json<TAB>http://77.90.8.171:3001<TAB><TAB>store<TAB>u1<TAB>t1<TAB>present<TAB>in_sync
|
||||||
```
|
```
|
||||||
|
|
||||||
Jesli remote istnieje, ale ma URL bez `LOGIN:TOKEN@`, wynik bedzie mial
|
Jesli remote istnieje, ale ma URL bez `LOGIN:TOKEN@`, wynik bedzie mial
|
||||||
`plain_urls=1`, `auth_urls=0`, `found=0`, `added=0`, a w tabeli `remotes`
|
w wierszu `repo` wartosci `kind=plain` i `result=no_credentials`. Jezeli
|
||||||
pojawi sie `url_kind=plain` i `result=no_credentials`. To znaczy, ze `scan`
|
ten sam endpoint istnieje w `tokens.json`, drugi wiersz tego samego `item`
|
||||||
sprawdzil remote, ale nie znalazl sekretu do zapisania.
|
pokaze `source=tokens.json`, `token=t1` i `result=present`.
|
||||||
|
|
||||||
Przyklad:
|
Przyklad:
|
||||||
|
|
||||||
@@ -370,20 +377,19 @@ Przelaczniki:
|
|||||||
Typowy wynik:
|
Typowy wynik:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
context
|
||||||
|
item<TAB>value
|
||||||
repo_root<TAB>...
|
repo_root<TAB>...
|
||||||
token_path<TAB>...
|
token_path<TAB>...
|
||||||
repo_endpoints<TAB>1
|
|
||||||
store_endpoints<TAB>1
|
|
||||||
union_endpoints<TAB>1
|
|
||||||
in_sync<TAB>0
|
|
||||||
repo_only<TAB>0
|
|
||||||
store_only<TAB>0
|
|
||||||
repo_ahead<TAB>0
|
|
||||||
store_ahead<TAB>1
|
|
||||||
diverged<TAB>0
|
|
||||||
|
|
||||||
endpoint<TAB>type<TAB>repo_remotes<TAB>repo_urls<TAB>repo_auth_urls<TAB>repo_plain_urls<TAB>repo_users<TAB>repo_tokens<TAB>store_users<TAB>store_tokens<TAB>repo_only_tokens<TAB>store_only_tokens<TAB>status
|
items
|
||||||
http://77.90.8.171:3001<TAB>gitea<TAB>origin<TAB>1<TAB>0<TAB>1<TAB>0<TAB>0<TAB>1<TAB>1<TAB>0<TAB>1<TAB>store_ahead
|
item<TAB>source<TAB>endpoint<TAB>remote<TAB>kind<TAB>user<TAB>token<TAB>result<TAB>status
|
||||||
|
1<TAB>repo<TAB>http://77.90.8.171:3001<TAB>r1<TAB>plain<TAB><TAB><TAB>no_credentials<TAB>store_ahead
|
||||||
|
1<TAB>tokens.json<TAB>http://77.90.8.171:3001<TAB><TAB>store<TAB>u1<TAB>t1<TAB>present<TAB>store_ahead
|
||||||
|
|
||||||
|
status
|
||||||
|
item<TAB>value
|
||||||
|
store_ahead<TAB>1
|
||||||
```
|
```
|
||||||
|
|
||||||
Przyklad:
|
Przyklad:
|
||||||
|
|||||||
+18
-9
@@ -84,16 +84,25 @@ Dzialanie:
|
|||||||
- skanuje remote URL-e w repo
|
- skanuje remote URL-e w repo
|
||||||
- zapisuje znalezione tokeny do `tokens.json`
|
- zapisuje znalezione tokeny do `tokens.json`
|
||||||
- zapisuje je per endpoint serwera
|
- zapisuje je per endpoint serwera
|
||||||
- wypisuje wynik jako tabele TSV: `summary` oraz `remotes`
|
- wypisuje wynik jako waskie tabele TSV: `context`, `scan` oraz `items`
|
||||||
|
|
||||||
Kolumny w tabeli `remotes`:
|
Tabela `items` porownuje dwa zrodla dla tego samego endpointu. Ten sam `item`
|
||||||
|
moze miec dwa wiersze:
|
||||||
|
|
||||||
- `remote` - nazwa remote, na przyklad `r1`
|
- `source=repo` - stan remote URL-i w repo
|
||||||
|
- `source=tokens.json` - stan lokalnego store tokenow
|
||||||
|
|
||||||
|
Kolumny w tabeli `items`:
|
||||||
|
|
||||||
|
- `item` - numer porownywanego endpointu
|
||||||
|
- `source` - `repo` albo `tokens.json`
|
||||||
- `endpoint` - serwer bez sekretu, na przyklad `http://77.90.8.171:3001`
|
- `endpoint` - serwer bez sekretu, na przyklad `http://77.90.8.171:3001`
|
||||||
- `type` - typ serwera, na przyklad `gitea`
|
- `remote` - nazwa remote, na przyklad `r1`; tylko dla `source=repo`
|
||||||
- `url_kind` - `auth`, `plain` albo `unsupported`
|
- `kind` - `auth`, `plain`, `store` albo `missing`
|
||||||
- `user` - login odczytany z URL, tylko dla `auth`
|
- `user` - login odczytany z URL albo ze store
|
||||||
- `result` - `added`, `existing`, `no_credentials` albo `ignored`
|
- `token` - `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`
|
||||||
|
|
||||||
Przyklad:
|
Przyklad:
|
||||||
|
|
||||||
@@ -133,13 +142,13 @@ Pokazuje statystyki per endpoint serwera i porownuje dwa zrodla:
|
|||||||
- endpointy znalezione w remote URL-ach repo
|
- endpointy znalezione w remote URL-ach repo
|
||||||
- endpointy zapisane w `tokens.json`
|
- endpointy zapisane w `tokens.json`
|
||||||
|
|
||||||
Wynik ma ten sam model co `tokens read`, ale w formie zbiorczej:
|
Wynik ma ten sam model porownania co `tokens scan`, ale nie zapisuje zmian:
|
||||||
|
|
||||||
- liczbe endpointow w repo
|
- liczbe endpointow w repo
|
||||||
- liczbe endpointow w store
|
- liczbe endpointow w store
|
||||||
- laczna unie endpointow
|
- laczna unie endpointow
|
||||||
- statusy zgodnosci, na przyklad `in_sync`, `store_ahead`, `repo_ahead`
|
- statusy zgodnosci, na przyklad `in_sync`, `store_ahead`, `repo_ahead`
|
||||||
- tabele endpointow z liczbami tokenow po obu stronach
|
- tabele `items`, w ktorej repo i `tokens.json` sa osobnymi wierszami tego samego itemu
|
||||||
|
|
||||||
Przyklad:
|
Przyklad:
|
||||||
|
|
||||||
|
|||||||
@@ -619,6 +619,122 @@ def compare_server_entries(repo_entry: dict | None, store_entry: dict | None) ->
|
|||||||
return "diverged", len(repo_only_pairs), len(store_only_pairs)
|
return "diverged", len(repo_only_pairs), len(store_only_pairs)
|
||||||
|
|
||||||
|
|
||||||
|
def token_name_rows(users_data: dict) -> list[tuple[str, str]]:
|
||||||
|
rows: list[tuple[str, str]] = []
|
||||||
|
for user_name in sorted(users_data):
|
||||||
|
user_entry = users_data[user_name]
|
||||||
|
if not isinstance(user_entry, dict):
|
||||||
|
continue
|
||||||
|
tokens = user_entry.get("tokens", {})
|
||||||
|
if not tokens:
|
||||||
|
rows.append((str(user_name), ""))
|
||||||
|
continue
|
||||||
|
for token_name in sorted(tokens):
|
||||||
|
rows.append((str(user_name), str(token_name)))
|
||||||
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
def repo_result_for_entry(repo_entry: dict | None) -> tuple[str, str]:
|
||||||
|
if repo_entry is None:
|
||||||
|
return "missing", "missing"
|
||||||
|
if repo_entry.get("auth_urls", 0):
|
||||||
|
return "auth", "present"
|
||||||
|
if repo_entry.get("plain_urls", 0):
|
||||||
|
return "plain", "no_credentials"
|
||||||
|
return "empty", "no_credentials"
|
||||||
|
|
||||||
|
|
||||||
|
def print_token_context(
|
||||||
|
repo_root: Path | None,
|
||||||
|
config: WorkspaceConfig,
|
||||||
|
repo_servers: dict[str, dict],
|
||||||
|
store_servers: dict[str, dict],
|
||||||
|
endpoint_count: int,
|
||||||
|
) -> None:
|
||||||
|
print("context")
|
||||||
|
print("item\tvalue")
|
||||||
|
print(f"repo_root\t{repo_root or ''}")
|
||||||
|
print(f"token_path\t{config.token_path}")
|
||||||
|
print(f"repo_endpoints\t{len(repo_servers)}")
|
||||||
|
print(f"tokens_endpoints\t{len(store_servers)}")
|
||||||
|
print(f"items\t{endpoint_count}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_status_counts(status_counts: dict[str, int]) -> None:
|
||||||
|
print("status")
|
||||||
|
print("item\tvalue")
|
||||||
|
for status_name in ["in_sync", "repo_only", "store_only", "repo_ahead", "store_ahead", "diverged"]:
|
||||||
|
print(f"{status_name}\t{status_counts[status_name]}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_token_item_rows(
|
||||||
|
endpoint_names: list[str],
|
||||||
|
repo_servers: dict[str, dict],
|
||||||
|
store_servers: dict[str, dict],
|
||||||
|
scan_rows: list[dict[str, str]] | None = None,
|
||||||
|
) -> dict[str, int]:
|
||||||
|
status_names = ["in_sync", "repo_only", "store_only", "repo_ahead", "store_ahead", "diverged"]
|
||||||
|
status_counts = {status_name: 0 for status_name in status_names}
|
||||||
|
scan_rows_by_endpoint: dict[str, list[dict[str, str]]] = {}
|
||||||
|
for row in scan_rows or []:
|
||||||
|
endpoint = row.get("endpoint", "")
|
||||||
|
if endpoint:
|
||||||
|
scan_rows_by_endpoint.setdefault(endpoint, []).append(row)
|
||||||
|
|
||||||
|
print("items")
|
||||||
|
print("item\tsource\tendpoint\tremote\tkind\tuser\ttoken\tresult\tstatus")
|
||||||
|
for index, endpoint in enumerate(endpoint_names, start=1):
|
||||||
|
item_id = str(index)
|
||||||
|
repo_entry = repo_servers.get(endpoint)
|
||||||
|
store_entry = store_servers.get(endpoint)
|
||||||
|
status_name, _, _ = compare_server_entries(repo_entry, store_entry)
|
||||||
|
if status_name in status_counts:
|
||||||
|
status_counts[status_name] += 1
|
||||||
|
|
||||||
|
repo_rows = scan_rows_by_endpoint.get(endpoint, [])
|
||||||
|
if repo_rows:
|
||||||
|
for row in repo_rows:
|
||||||
|
token_label = "remote" if row["url_kind"] == "auth" else ""
|
||||||
|
print(
|
||||||
|
f"{item_id}\trepo\t{endpoint}\t{row['remote']}\t{row['url_kind']}\t"
|
||||||
|
f"{row['user']}\t{token_label}\t{row['result']}\t{status_name}"
|
||||||
|
)
|
||||||
|
elif repo_entry is None:
|
||||||
|
print(f"{item_id}\trepo\t{endpoint}\t\tmissing\t\t\tmissing\t{status_name}")
|
||||||
|
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{endpoint}\t{remote_names}\t{repo_kind}\t"
|
||||||
|
f"{user_name}\tremote\t{repo_result}\t{status_name}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"{item_id}\trepo\t{endpoint}\t{remote_names}\t{repo_kind}\t\t\t"
|
||||||
|
f"{repo_result}\t{status_name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if store_entry is None:
|
||||||
|
print(f"{item_id}\ttokens.json\t{endpoint}\t\tmissing\t\t\tmissing\t{status_name}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
store_users = token_name_rows(store_entry.get("users", {}))
|
||||||
|
if not store_users:
|
||||||
|
print(f"{item_id}\ttokens.json\t{endpoint}\t\tstore\t\t\tempty\t{status_name}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
for user_name, token_name in store_users:
|
||||||
|
print(
|
||||||
|
f"{item_id}\ttokens.json\t{endpoint}\t\tstore\t{user_name}\t"
|
||||||
|
f"{token_name}\tpresent\t{status_name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return status_counts
|
||||||
|
|
||||||
|
|
||||||
def resolve_server_from_store(token_data: dict, endpoint: str | None) -> tuple[str, dict]:
|
def resolve_server_from_store(token_data: dict, endpoint: str | None) -> tuple[str, dict]:
|
||||||
servers = token_data.get("servers", {})
|
servers = token_data.get("servers", {})
|
||||||
if endpoint:
|
if endpoint:
|
||||||
@@ -707,27 +823,28 @@ def resolve_repo_argument(repo_arg: str | None) -> Path:
|
|||||||
|
|
||||||
|
|
||||||
def run_tokens_scan(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
def run_tokens_scan(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||||
report = sync_tokens_from_repo(config, resolve_repo_argument(args.repo))
|
repo_path = resolve_repo_argument(args.repo)
|
||||||
repo_root = report["repo_root"]
|
report = sync_tokens_from_repo(config, repo_path)
|
||||||
print("summary")
|
repo_root, repo_servers = collect_repo_server_entries(config, repo_path)
|
||||||
print(
|
token_data = load_token_store(config)
|
||||||
"repo_root\tremotes\turls\tscanned\tauth_urls\tplain_urls\t"
|
store_servers = token_data.get("servers", {})
|
||||||
"unsupported_urls\tfound\tadded\tservers\ttoken_path"
|
endpoint_names = sorted(set(repo_servers) | set(store_servers))
|
||||||
)
|
|
||||||
print(
|
print_token_context(repo_root, config, repo_servers, store_servers, len(endpoint_names))
|
||||||
f"{repo_root or ''}\t{report['remotes']}\t{report['urls']}\t"
|
|
||||||
f"{report['scanned']}\t{report['auth_urls']}\t{report['plain_urls']}\t"
|
|
||||||
f"{report['unsupported_urls']}\t{report['found']}\t{report['added']}\t"
|
|
||||||
f"{report['servers']}\t{config.token_path}"
|
|
||||||
)
|
|
||||||
print()
|
print()
|
||||||
print("remotes")
|
print("scan")
|
||||||
print("remote\tendpoint\ttype\turl_kind\tuser\tresult")
|
print("item\tvalue")
|
||||||
for row in report["remote_rows"]:
|
print(f"remotes\t{report['remotes']}")
|
||||||
print(
|
print(f"urls\t{report['urls']}")
|
||||||
f"{row['remote']}\t{row['endpoint']}\t{row['type']}\t"
|
print(f"scanned\t{report['scanned']}")
|
||||||
f"{row['url_kind']}\t{row['user']}\t{row['result']}"
|
print(f"auth_urls\t{report['auth_urls']}")
|
||||||
)
|
print(f"plain_urls\t{report['plain_urls']}")
|
||||||
|
print(f"unsupported_urls\t{report['unsupported_urls']}")
|
||||||
|
print(f"found\t{report['found']}")
|
||||||
|
print(f"added\t{report['added']}")
|
||||||
|
print(f"servers\t{report['servers']}")
|
||||||
|
print()
|
||||||
|
print_token_item_rows(endpoint_names, repo_servers, store_servers, report["remote_rows"])
|
||||||
|
|
||||||
|
|
||||||
def run_tokens_read(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
def run_tokens_read(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||||
@@ -774,57 +891,11 @@ def run_tokens_stats(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
|||||||
raise SystemExit(f"Missing server endpoint in repo/store: {args.server}")
|
raise SystemExit(f"Missing server endpoint in repo/store: {args.server}")
|
||||||
endpoint_names = [args.server]
|
endpoint_names = [args.server]
|
||||||
|
|
||||||
status_names = ["in_sync", "repo_only", "store_only", "repo_ahead", "store_ahead", "diverged"]
|
print_token_context(repo_root, config, repo_servers, store_servers, len(endpoint_names))
|
||||||
status_counts = {status_name: 0 for status_name in status_names}
|
|
||||||
|
|
||||||
print(f"repo_root\t{repo_root or ''}")
|
|
||||||
print(f"token_path\t{config.token_path}")
|
|
||||||
print(f"repo_endpoints\t{len(repo_servers)}")
|
|
||||||
print(f"store_endpoints\t{len(store_servers)}")
|
|
||||||
print(f"union_endpoints\t{len(endpoint_names)}")
|
|
||||||
|
|
||||||
table_rows: list[list[str]] = []
|
|
||||||
for endpoint in endpoint_names:
|
|
||||||
repo_entry = repo_servers.get(endpoint)
|
|
||||||
store_entry = store_servers.get(endpoint)
|
|
||||||
status_name, repo_only_count, store_only_count = compare_server_entries(repo_entry, store_entry)
|
|
||||||
if status_name in status_counts:
|
|
||||||
status_counts[status_name] += 1
|
|
||||||
|
|
||||||
sample_entry = repo_entry or store_entry or {}
|
|
||||||
repo_users = repo_entry.get("users", {}) if repo_entry else {}
|
|
||||||
store_users = store_entry.get("users", {}) if store_entry else {}
|
|
||||||
table_rows.append(
|
|
||||||
[
|
|
||||||
endpoint,
|
|
||||||
str(sample_entry.get("type", "unknown")),
|
|
||||||
",".join(sorted(repo_entry.get("remotes", set()))) if repo_entry else "",
|
|
||||||
str(repo_entry.get("urls", 0) if repo_entry else 0),
|
|
||||||
str(repo_entry.get("auth_urls", 0) if repo_entry else 0),
|
|
||||||
str(repo_entry.get("plain_urls", 0) if repo_entry else 0),
|
|
||||||
str(count_users(repo_users)),
|
|
||||||
str(count_server_tokens(repo_entry) if repo_entry else 0),
|
|
||||||
str(count_users(store_users)),
|
|
||||||
str(count_server_tokens(store_entry) if store_entry else 0),
|
|
||||||
str(repo_only_count),
|
|
||||||
str(store_only_count),
|
|
||||||
status_name,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
for status_name in status_names:
|
|
||||||
print(f"{status_name}\t{status_counts[status_name]}")
|
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print(
|
status_counts = print_token_item_rows(endpoint_names, repo_servers, store_servers)
|
||||||
"endpoint\ttype\trepo_remotes\trepo_urls\trepo_auth_urls\trepo_plain_urls\t"
|
print()
|
||||||
"repo_users\trepo_tokens\tstore_users\tstore_tokens\trepo_only_tokens\t"
|
print_status_counts(status_counts)
|
||||||
"store_only_tokens\tstatus"
|
|
||||||
)
|
|
||||||
for row in table_rows:
|
|
||||||
print(
|
|
||||||
"\t".join(row)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def run_tokens_write(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
def run_tokens_write(config: WorkspaceConfig, args: argparse.Namespace) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user