runv-server

server tooling for runv.club
Log | Files | Refs | README

runv-profile (5195B)


      1 #!/usr/bin/env python3
      2 """Gerencia o perfil local público do utilizador (runv.club)."""
      3 
      4 from __future__ import annotations
      5 
      6 import argparse
      7 import os
      8 import sys
      9 from pathlib import Path
     10 
     11 sys.tracebacklimit = 0
     12 
     13 
     14 def _bootstrap() -> None:
     15     from pathlib import Path
     16 
     17     installed = Path("/usr/local/share/runv/lib")
     18     candidates = [installed]
     19     script = Path(__file__).resolve()
     20     if script.parent.name == "bin":
     21         candidates.insert(0, script.parent.parent / "lib")
     22     for c in candidates:
     23         if (c / "runv_community.py").is_file() and str(c) not in sys.path:
     24             sys.path.insert(0, str(c))
     25             return
     26 
     27 
     28 _bootstrap()
     29 import runv_community as rc  # noqa: E402
     30 
     31 PLAN_INITIAL = "Ainda estou escrevendo meu .plan.\n"
     32 PROJECT_INITIAL = "Explorando a runv.club.\n"
     33 
     34 
     35 def local_paths() -> dict[str, Path]:
     36     home = Path.home()
     37     return {
     38         "runv_dir": home / ".runv",
     39         "profile": home / ".runv" / "profile.json",
     40         "plan": home / ".plan",
     41         "project": home / ".project",
     42     }
     43 
     44 
     45 def cmd_init() -> int:
     46     paths = local_paths()
     47     created: list[str] = []
     48     existed: list[str] = []
     49 
     50     if not paths["runv_dir"].exists():
     51         paths["runv_dir"].mkdir(parents=True, exist_ok=True)
     52         os.chmod(paths["runv_dir"], 0o755)
     53         created.append(str(paths["runv_dir"]))
     54     else:
     55         os.chmod(paths["runv_dir"], 0o755)
     56         existed.append(str(paths["runv_dir"]))
     57 
     58     targets: list[tuple[Path, str]] = [
     59         (paths["profile"], rc.profile_json_default_text()),
     60         (paths["plan"], PLAN_INITIAL),
     61         (paths["project"], PROJECT_INITIAL),
     62     ]
     63     for path, content in targets:
     64         if path.exists():
     65             existed.append(str(path))
     66             continue
     67         path.parent.mkdir(parents=True, exist_ok=True)
     68         path.write_text(content, encoding="utf-8")
     69         os.chmod(path, 0o644)
     70         created.append(str(path))
     71 
     72     print("Perfil runv inicializado.\n")
     73     if created:
     74         print("criado:")
     75         for p in created:
     76             print(f"  {p}")
     77     if existed:
     78         print("\njá existia:")
     79         for p in existed:
     80             print(f"  {p}")
     81     if not created and not existed:
     82         print("(nada a fazer)")
     83     return 0
     84 
     85 
     86 def cmd_show() -> int:
     87     paths = local_paths()
     88     print("Perfil runv\n")
     89     print("Arquivo:")
     90     print(f"  {paths['profile']}\n")
     91 
     92     if not paths["profile"].is_file():
     93         print("Perfil ainda não existe.")
     94         print("Rode: runv-profile init\n")
     95     else:
     96         text = rc.read_text_limited(paths["profile"])
     97         profile, warn = rc.parse_profile_json(text)
     98         if warn:
     99             print(warn)
    100         if profile:
    101             print(f"Nome:\n  {profile.get('display_name') or '(vazio)'}\n")
    102             print(f"Bio:\n  {profile.get('bio') or '(vazio)'}\n")
    103             print(f"Local:\n  {profile.get('location') or '(vazio)'}\n")
    104             links = profile.get("links") or []
    105             print("Links:")
    106             if links:
    107                 for link in links:
    108                     print(f"  {link}")
    109             else:
    110                 print("  (vazio)")
    111             print()
    112             interests = profile.get("interests") or []
    113             print("Interesses:")
    114             if interests:
    115                 for item in interests:
    116                     print(f"  {item}")
    117             else:
    118                 print("  (vazio)")
    119             print()
    120 
    121     plan_text = rc.read_text_limited(paths["plan"])
    122     project_text = rc.read_text_limited(paths["project"])
    123     print(".project:")
    124     if project_text and project_text.strip():
    125         for line in project_text.strip().splitlines():
    126             print(f"  {line}")
    127     else:
    128         print("  (vazio)")
    129     print()
    130     print(".plan:")
    131     if plan_text and plan_text.strip():
    132         for line in plan_text.strip().splitlines():
    133             print(f"  {line}")
    134     else:
    135         print("  (vazio)")
    136     return 0
    137 
    138 
    139 def cmd_path() -> int:
    140     paths = local_paths()
    141     print(f"profile: {paths['profile']}")
    142     print(f"plan:    {paths['plan']}")
    143     print(f"project: {paths['project']}")
    144     return 0
    145 
    146 
    147 def build_parser() -> argparse.ArgumentParser:
    148     p = argparse.ArgumentParser(
    149         prog="runv-profile",
    150         description="Gerencia o perfil local público (~/.runv/profile.json, .plan, .project).",
    151     )
    152     sub = p.add_subparsers(dest="command")
    153 
    154     sub.add_parser("init", help="cria ficheiros de perfil se ainda não existirem")
    155     sub.add_parser("show", help="mostra o perfil local")
    156     sub.add_parser("path", help="mostra caminhos dos ficheiros de perfil")
    157     return p
    158 
    159 
    160 def main(argv: list[str] | None = None) -> int:
    161     try:
    162         args = build_parser().parse_args(argv)
    163         if args.command == "init":
    164             return cmd_init()
    165         if args.command == "show":
    166             return cmd_show()
    167         if args.command == "path":
    168             return cmd_path()
    169         build_parser().print_help()
    170         return 1
    171     except KeyboardInterrupt:
    172         print("\nInterrompido.", file=sys.stderr)
    173         return 130
    174     except SystemExit:
    175         raise
    176     except Exception as e:
    177         rc.friendly_exit(f"erro: {e}")
    178 
    179 
    180 if __name__ == "__main__":
    181     raise SystemExit(main())