runv-finger (3286B)
1 #!/usr/bin/env python3 2 """Mostra o perfil público de um membro runv.club (estilo finger).""" 3 4 from __future__ import annotations 5 6 import argparse 7 import sys 8 9 sys.tracebacklimit = 0 10 11 12 def _bootstrap() -> None: 13 from pathlib import Path 14 15 installed = Path("/usr/local/share/runv/lib") 16 candidates = [installed] 17 script = Path(__file__).resolve() 18 if script.parent.name == "bin": 19 candidates.insert(0, script.parent.parent / "lib") 20 for c in candidates: 21 if (c / "runv_community.py").is_file() and str(c) not in sys.path: 22 sys.path.insert(0, str(c)) 23 return 24 25 26 _bootstrap() 27 import runv_community as rc # noqa: E402 28 29 30 def cmd_finger(username: str) -> int: 31 user = rc.validate_username(username) 32 paths = rc.home_paths(user) 33 if not paths["home"].is_dir(): 34 rc.friendly_exit(f"usuário não encontrado: {user}") 35 36 print(f"{user} @ runv.club\n") 37 38 profile_text = rc.read_text_limited(paths["profile"]) 39 profile, warn = rc.parse_profile_json(profile_text) 40 if warn: 41 print(warn) 42 43 def field(label: str, value: str | None) -> None: 44 print(f"{label}: {value if value and value.strip() else 'não informado'}") 45 46 if profile: 47 field("Nome", profile.get("display_name", "")) 48 field("Bio", profile.get("bio", "")) 49 field("Local", profile.get("location", "")) 50 else: 51 field("Nome", None) 52 field("Bio", None) 53 field("Local", None) 54 55 if paths["public_index"].is_file(): 56 print(f"Home: /~{user}/") 57 mtime = rc.format_mtime_local(paths["public_index"]) 58 if mtime: 59 print(f"Home atualizada: {mtime}") 60 else: 61 print("Home: não informado") 62 63 project_text = rc.read_text_limited(paths["project"]) 64 plan_text = rc.read_text_limited(paths["plan"]) 65 66 print("\nProjeto:") 67 if project_text and project_text.strip(): 68 for line in project_text.strip().splitlines(): 69 print(f" {line}") 70 else: 71 print(" não informado") 72 73 print("\n.plan:") 74 if plan_text and plan_text.strip(): 75 for line in plan_text.strip().splitlines(): 76 print(f" {line}") 77 else: 78 print(" não informado") 79 80 if profile: 81 links = profile.get("links") or [] 82 print("\nLinks:") 83 if links: 84 for link in links: 85 print(f" {link}") 86 else: 87 print(" não informado") 88 interests = profile.get("interests") or [] 89 print("\nInteresses:") 90 if interests: 91 for item in interests: 92 print(f" {item}") 93 else: 94 print(" não informado") 95 96 return 0 97 98 99 def main(argv: list[str] | None = None) -> int: 100 try: 101 p = argparse.ArgumentParser( 102 prog="runv-finger", 103 description="Mostra o perfil público de outro membro.", 104 ) 105 p.add_argument("username", help="nome de utilizador Unix") 106 args = p.parse_args(argv) 107 return cmd_finger(args.username) 108 except KeyboardInterrupt: 109 print("\nInterrompido.", file=sys.stderr) 110 return 130 111 except SystemExit: 112 raise 113 except Exception as e: 114 rc.friendly_exit(f"erro: {e}") 115 116 117 if __name__ == "__main__": 118 raise SystemExit(main())