#!/usr/bin/env python3 import argparse import json import os import platform import shutil import subprocess import sys from script_common import resolve_command def run_capture(cmd): try: proc = subprocess.run(cmd, capture_output=True, text=True, check=False) out = (proc.stdout or "").strip() err = (proc.stderr or "").strip() text = out if out else err return proc.returncode == 0, text except Exception as ex: return False, str(ex) def probe_tool(tool): mapping = { "dotnet": ["dotnet", "--version"], "node": ["node", "--version"], "npm": ["npm", "--version"], "python": ["python", "--version"], "cargo": ["cargo", "--version"], "tauri": ["tauri", "--version"], "git": ["git", "--version"], "docker": ["docker", "--version"], } cmd = mapping.get(tool, [tool, "--version"]) resolved = resolve_command(cmd[0]) if shutil.which(resolved) is None and not os.path.exists(resolved): return {"tool": tool, "available": False, "version": None, "details": f"{cmd[0]} not found in PATH"} cmd = [resolved, *cmd[1:]] ok, text = run_capture(cmd) return {"tool": tool, "available": ok, "version": text if ok else None, "details": None if ok else text} def install_plan(tool): is_windows = platform.system().lower().startswith("win") if is_windows: plans = { "dotnet": [("winget", ["install", "Microsoft.DotNet.SDK.10"])], "node": [("winget", ["install", "OpenJS.NodeJS.LTS"])], "npm": [("winget", ["install", "OpenJS.NodeJS.LTS"])], "python": [("winget", ["install", "Python.Python.3.12"])], "cargo": [("winget", ["install", "Rustlang.Rustup"])], "tauri": [("npm", ["install", "-g", "@tauri-apps/cli"])], "git": [("winget", ["install", "Git.Git"])], "docker": [("winget", ["install", "Docker.DockerDesktop"])], } else: plans = { "dotnet": [("sh", ["-c", "echo install dotnet sdk with your package manager"])], "node": [("sh", ["-c", "echo install nodejs with your package manager"])], "npm": [("sh", ["-c", "echo install npm with your package manager"])], "python": [("sh", ["-c", "echo install python3 with your package manager"])], "cargo": [("sh", ["-c", "curl https://sh.rustup.rs -sSf | sh"])], "tauri": [("npm", ["install", "-g", "@tauri-apps/cli"])], "git": [("sh", ["-c", "echo install git with your package manager"])], "docker": [("sh", ["-c", "echo install docker with your package manager"])], } cmds = plans.get(tool, []) return { "tool": tool, "supported": len(cmds) > 0, "summary": f"Install plan for {tool} on {platform.system()}", "commands": [{"command": c, "args": a} for c, a in cmds], } def run_install(tool): plan = install_plan(tool) if not plan["supported"]: return 2 for cmd in plan["commands"]: proc = subprocess.run([cmd["command"], *cmd["args"]], check=False) if proc.returncode != 0: return proc.returncode return 0 def main(): parser = argparse.ArgumentParser(description="SDT diagnostics and install planner") sub = parser.add_subparsers(dest="cmd", required=True) p_probe = sub.add_parser("probe") p_probe.add_argument("--tool", required=True) p_probe.add_argument("--json", action="store_true") p_plan = sub.add_parser("install-plan") p_plan.add_argument("--tool", required=True) p_plan.add_argument("--json", action="store_true") p_run = sub.add_parser("install-run") p_run.add_argument("--tool", required=True) args = parser.parse_args() if args.cmd == "probe": result = probe_tool(args.tool.lower()) if args.json: print(json.dumps(result)) else: print(result) return 0 if result["available"] else 1 if args.cmd == "install-plan": result = install_plan(args.tool.lower()) if args.json: print(json.dumps(result)) else: print(result) return 0 if result["supported"] else 2 if args.cmd == "install-run": return run_install(args.tool.lower()) return 1 if __name__ == "__main__": sys.exit(main())