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())