...
This commit is contained in:
178
pkg/system/builders/postgresql/postgres/goinstall.go
Normal file
178
pkg/system/builders/postgresql/postgres/goinstall.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/archiver/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultGoVersion is the default Go version to install
|
||||
DefaultGoVersion = "1.22.2"
|
||||
)
|
||||
|
||||
// GoInstaller handles Go installation checks and installation
|
||||
type GoInstaller struct {
|
||||
Version string
|
||||
}
|
||||
|
||||
// NewGoInstaller creates a new Go installer with the default version
|
||||
func NewGoInstaller() *GoInstaller {
|
||||
return &GoInstaller{
|
||||
Version: DefaultGoVersion,
|
||||
}
|
||||
}
|
||||
|
||||
// WithVersion sets the Go version to install
|
||||
func (g *GoInstaller) WithVersion(version string) *GoInstaller {
|
||||
g.Version = version
|
||||
return g
|
||||
}
|
||||
|
||||
// IsGoInstalled checks if Go is installed and available
|
||||
func (g *GoInstaller) IsGoInstalled() bool {
|
||||
// Check if go command is available
|
||||
cmd := exec.Command("go", "version")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// GetGoVersion gets the installed Go version
|
||||
func (g *GoInstaller) GetGoVersion() (string, error) {
|
||||
cmd := exec.Command("go", "version")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get Go version: %w", err)
|
||||
}
|
||||
|
||||
// Parse go version output (format: "go version go1.x.x ...")
|
||||
version := strings.TrimSpace(string(output))
|
||||
parts := strings.Split(version, " ")
|
||||
if len(parts) < 3 {
|
||||
return "", fmt.Errorf("unexpected go version output format: %s", version)
|
||||
}
|
||||
|
||||
// Return just the version number without the "go" prefix
|
||||
return strings.TrimPrefix(parts[2], "go"), nil
|
||||
}
|
||||
|
||||
// InstallGo installs Go if it's not already installed and returns the path to the Go executable
|
||||
func (g *GoInstaller) InstallGo() (string, error) {
|
||||
// First check if Go is available in PATH
|
||||
if path, err := exec.LookPath("go"); err == nil {
|
||||
// Test if it works
|
||||
cmd := exec.Command(path, "version")
|
||||
if output, err := cmd.Output(); err == nil {
|
||||
fmt.Printf("Found working Go in PATH: %s, version: %s\n", path, strings.TrimSpace(string(output)))
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
// Default Go installation location
|
||||
var installDir string = "/usr/local"
|
||||
var goExePath string = filepath.Join(installDir, "go", "bin", "go")
|
||||
|
||||
// Check if Go is already installed by checking the binary directly
|
||||
if _, err := os.Stat(goExePath); err == nil {
|
||||
version, err := g.GetGoVersion()
|
||||
if err == nil {
|
||||
fmt.Printf("Go is already installed (version %s), skipping installation\n", version)
|
||||
return goExePath, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Also check if Go is available in PATH as a fallback
|
||||
if g.IsGoInstalled() {
|
||||
path, err := exec.LookPath("go")
|
||||
if err == nil {
|
||||
version, err := g.GetGoVersion()
|
||||
if err == nil {
|
||||
fmt.Printf("Go is already installed (version %s) at %s, skipping installation\n", version, path)
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Installing Go version %s...\n", g.Version)
|
||||
|
||||
// Determine architecture and OS
|
||||
goOS := runtime.GOOS
|
||||
goArch := runtime.GOARCH
|
||||
|
||||
// Construct download URL
|
||||
downloadURL := fmt.Sprintf("https://golang.org/dl/go%s.%s-%s.tar.gz", g.Version, goOS, goArch)
|
||||
|
||||
// Create a temporary directory for download
|
||||
tempDir, err := os.MkdirTemp("", "go-install-")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temporary directory: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Download Go tarball
|
||||
tarballPath := filepath.Join(tempDir, "go.tar.gz")
|
||||
if err := downloadFile(downloadURL, tarballPath); err != nil {
|
||||
return "", fmt.Errorf("failed to download Go: %w", err)
|
||||
}
|
||||
|
||||
// Install directory - typically /usr/local for Linux/macOS
|
||||
|
||||
// Check if existing Go installation exists and remove it
|
||||
existingGoDir := filepath.Join(installDir, "go")
|
||||
if _, err := os.Stat(existingGoDir); err == nil {
|
||||
fmt.Printf("Removing existing Go installation at %s\n", existingGoDir)
|
||||
if err := os.RemoveAll(existingGoDir); err != nil {
|
||||
return "", fmt.Errorf("failed to remove existing Go installation: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Extract tarball to install directory
|
||||
fmt.Printf("Extracting Go to %s\n", installDir)
|
||||
err = extractTarGz(tarballPath, installDir)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to extract Go tarball: %w", err)
|
||||
}
|
||||
|
||||
// Verify installation
|
||||
var goExePathVerify = filepath.Join(installDir, "go", "bin", "go") // Use = instead of := to avoid variable shadowing
|
||||
|
||||
// Check if the Go binary exists
|
||||
var statErr error
|
||||
_, statErr = os.Stat(goExePathVerify)
|
||||
if statErr != nil {
|
||||
return "", fmt.Errorf("Go installation failed - go executable not found at %s", goExePathVerify)
|
||||
}
|
||||
|
||||
// Set up environment variables
|
||||
fmt.Println("Setting up Go environment variables...")
|
||||
|
||||
// Update PATH in /etc/profile
|
||||
profilePath := "/etc/profile"
|
||||
profileContent, err := os.ReadFile(profilePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read profile: %w", err)
|
||||
}
|
||||
|
||||
// Add Go bin to PATH if not already there
|
||||
goBinPath := filepath.Join(installDir, "go", "bin")
|
||||
if !strings.Contains(string(profileContent), goBinPath) {
|
||||
newContent := string(profileContent) + fmt.Sprintf("\n# Added by PostgreSQL builder\nexport PATH=$PATH:%s\n", goBinPath)
|
||||
if err := os.WriteFile(profilePath, []byte(newContent), 0644); err != nil {
|
||||
return "", fmt.Errorf("failed to update profile: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("✅ Go %s installed successfully!\n", g.Version)
|
||||
return goExePath, nil
|
||||
}
|
||||
|
||||
// Helper function to extract tarball
|
||||
func extractTarGz(src, dst string) error {
|
||||
return archiver.Unarchive(src, dst)
|
||||
}
|
Reference in New Issue
Block a user