From 67242de5775e9dc690b3f1867755c9b811d015d0 Mon Sep 17 00:00:00 2001 From: jim800121chen Date: Mon, 9 Mar 2026 18:22:05 +0800 Subject: [PATCH] feat: auto-install Python 3 via winget on Windows When Python 3 is not found during installation on Windows, the installer now automatically attempts to install it using winget (Python.Python.3.12). Falls back to manual install prompt if winget is unavailable. Co-Authored-By: Claude Opus 4.6 --- edge-ai-platform/installer/app.go | 65 ++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/edge-ai-platform/installer/app.go b/edge-ai-platform/installer/app.go index d122dc5..cb60e2a 100644 --- a/edge-ai-platform/installer/app.go +++ b/edge-ai-platform/installer/app.go @@ -365,6 +365,58 @@ func (inst *Installer) extractDir(embedDir, destDir string) error { }) } +// installPython3Windows attempts to install Python 3 via winget on Windows. +func (inst *Installer) installPython3Windows() error { + if runtime.GOOS != "windows" { + return fmt.Errorf("not windows") + } + + // Check if winget is available + if _, err := exec.LookPath("winget"); err != nil { + return fmt.Errorf("winget not found — please install Python 3 manually from https://python.org") + } + + inst.emitProgress(ProgressEvent{ + Step: "python", + Message: "Installing Python 3 via winget...", + Percent: 73, + }) + + cmd := exec.Command("winget", "install", "Python.Python.3.12", + "--accept-source-agreements", "--accept-package-agreements", "--silent") + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("winget install Python failed: %s — %w", string(out), err) + } + + // winget installs Python to %LOCALAPPDATA%\Programs\Python\Python312\ + // We need to add it to PATH for the current process + pythonDir := filepath.Join(os.Getenv("LOCALAPPDATA"), "Programs", "Python", "Python312") + scriptsDir := filepath.Join(pythonDir, "Scripts") + os.Setenv("PATH", pythonDir+";"+scriptsDir+";"+os.Getenv("PATH")) + + // Verify it works + if _, err := findPython3(); err != nil { + // Try common alternative paths + for _, ver := range []string{"Python313", "Python311", "Python310"} { + altDir := filepath.Join(os.Getenv("LOCALAPPDATA"), "Programs", "Python", ver) + if _, err := os.Stat(filepath.Join(altDir, "python.exe")); err == nil { + os.Setenv("PATH", altDir+";"+filepath.Join(altDir, "Scripts")+";"+os.Getenv("PATH")) + break + } + } + if _, err := findPython3(); err != nil { + return fmt.Errorf("Python installed but not found in PATH — please restart the installer") + } + } + + inst.emitProgress(ProgressEvent{ + Step: "python", + Message: "Python 3 installed successfully.", + Percent: 75, + }) + return nil +} + // setupPythonVenv creates a Python virtual environment and installs requirements. func (inst *Installer) setupPythonVenv(installDir string) error { venvDir := filepath.Join(installDir, "venv") @@ -372,7 +424,18 @@ func (inst *Installer) setupPythonVenv(installDir string) error { pythonPath, err := findPython3() if err != nil { - return fmt.Errorf("python3 not found on PATH: %w", err) + // On Windows, try to install Python automatically + if runtime.GOOS == "windows" { + if installErr := inst.installPython3Windows(); installErr != nil { + return fmt.Errorf("python3 not found and auto-install failed: %w", installErr) + } + pythonPath, err = findPython3() + if err != nil { + return fmt.Errorf("python3 still not found after installation: %w", err) + } + } else { + return fmt.Errorf("python3 not found on PATH: %w", err) + } } inst.emitProgress(ProgressEvent{