helper script for personal provider account script for pi agent.

This commit is contained in:
yaroslav k 2026-07-30 02:20:17 +03:00
parent 5393e4eab5
commit 5a18e93d93

182
helpers/fill-oc-go-providers.py Executable file
View File

@ -0,0 +1,182 @@
#!/usr/bin/env python3
"""ocd-fill.py -- create ocd account stubs from oc-go account names.
Reads the oc-go provider account map (a YAML file), takes the account names,
and appends [[account]] stubs to the ocd config for any name not already
present. cookie and default_workspace are left empty for you to fill in.
Inputs
source defaults to $OC_GO_YAML or
~/.pi/agent/oc-providers/accounts/oc-go.yaml
(fallback: ~/.pi/agent/oc-providers/oc-go.yaml)
config defaults to $OCD_CONFIG or
$XDG_CONFIG_HOME/ocd/config.toml (~/.config/ocd/config.toml)
Flags
--source PATH override the oc-go YAML path
--config PATH override the ocd config path
--dry-run print the plan, do not write
-h, --help print this help
Report: added N / present N / to fill N
added new stubs written this run
present source names already in the config
to fill config entries whose cookie or default_workspace is empty or
still a placeholder
"""
from __future__ import annotations
import argparse
import os
import sys
from pathlib import Path
import yaml
try:
import tomllib # Python 3.11+
except ModuleNotFoundError: # pragma: no cover
sys.stderr.write("ocd-fill: python 3.11+ required for tomllib\n")
sys.exit(1)
HEADER = (
"# ocd config. Generated by ocd-fill; fill in cookie and\n"
"# default_workspace for each account. ${VAR} expands from env.\n"
)
def default_source() -> Path:
if env := os.environ.get("OC_GO_YAML"):
return Path(env)
home = Path.home()
primary = home / ".pi/agent/oc-providers/accounts/oc-go.yaml"
if primary.is_file():
return primary
return home / ".pi/agent/oc-providers/oc-go.yaml"
def default_config() -> Path:
if env := os.environ.get("OCD_CONFIG"):
return Path(env)
xdg = os.environ.get("XDG_CONFIG_HOME") or str(Path.home() / ".config")
return Path(xdg) / "ocd/config.toml"
def toml_basic_string(s: str) -> str:
"""Encode a TOML basic string (double-quoted, minimal escapes)."""
s = s.replace("\\", "\\\\").replace('"', '\\"')
return f'"{s}"'
def read_source_names(path: Path) -> list[str]:
with path.open(encoding="utf-8") as f:
data = yaml.safe_load(f) or {}
accs = data.get("accounts") or {}
if not isinstance(accs, dict):
sys.stderr.write(f"ocd-fill: `accounts:` is not a map in {path}\n")
sys.exit(1)
return list(accs.keys())
def read_config(path: Path) -> tuple[list[str], int]:
"""Return (existing account names, count of entries still to fill)."""
if not path.is_file():
return [], 0
try:
with path.open("rb") as f:
data = tomllib.load(f)
except tomllib.TOMLDecodeError as e:
sys.stderr.write(f"ocd-fill: config is not valid TOML: {e}\n")
sys.exit(1)
names: list[str] = []
to_fill = 0
for a in data.get("account", []):
n = a.get("name")
if n:
names.append(str(n))
cookie = str(a.get("cookie", "") or "")
ws = str(a.get("default_workspace", "") or "")
needs = (
not cookie.strip()
or not ws.strip()
or "REPLACE_ME" in cookie
or "REPLACE_ME" in ws
)
if needs:
to_fill += 1
return names, to_fill
def append_stubs(path: Path, names: list[str]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
existing = path.read_text(encoding="utf-8") if path.is_file() else ""
stub_text = "\n\n".join(stub_block(n) for n in names) + "\n"
with path.open("a", encoding="utf-8") as f:
if existing.strip():
# Keep one blank line before the first new stub.
f.write(existing.rstrip("\n") + "\n\n")
else:
f.write(HEADER + "\n")
f.write(stub_text)
def stub_block(name: str) -> str:
return (
f"[[account]]\n"
f"name = {toml_basic_string(name)}\n"
f'cookie = ""\n'
f'default_workspace = ""'
)
def main(argv: list[str]) -> int:
p = argparse.ArgumentParser(
prog="ocd-fill",
description="Create ocd account stubs from oc-go account names.",
add_help=False,
)
p.add_argument("-h", "--help", action="help", help="print this help and exit")
p.add_argument("--source", type=Path, default=default_source(),
help="oc-go YAML path")
p.add_argument("--config", type=Path, default=default_config(),
help="ocd config path to write")
p.add_argument("--dry-run", action="store_true", help="print plan, do not write")
args = p.parse_args(argv)
if not args.source.is_file():
sys.stderr.write(f"ocd-fill: source file not found: {args.source}\n")
return 1
src_names = read_source_names(args.source)
existing_names, to_fill = read_config(args.config)
existing_set = set(existing_names)
to_add = [n for n in src_names if n not in existing_set]
present = [n for n in src_names if n in existing_set]
n_added = len(to_add)
n_present = len(present)
print(f"ocd-fill: source={args.source}")
print(f"ocd-fill: config={args.config}")
if n_added == 0:
print("ocd-fill: added 0")
else:
print(f"ocd-fill: added {n_added}: {' '.join(to_add)}")
print(f"ocd-fill: present {n_present}")
print(f"ocd-fill: to fill {to_fill}")
if args.dry_run:
print("ocd-fill: dry run, no write")
return 0
if n_added == 0:
return 0
append_stubs(args.config, to_add)
print(f"ocd-fill: wrote {n_added} stub(s) to {args.config}")
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))