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 <noreply@anthropic.com>
This commit is contained in:
parent
3bc537df95
commit
67242de577
@ -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{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user