...
This commit is contained in:
172
pkg/system/builders/postgresql/gosp/gosp.go
Normal file
172
pkg/system/builders/postgresql/gosp/gosp.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package gosp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/postgres"
|
||||
)
|
||||
|
||||
// Constants for Go stored procedure
|
||||
const (
|
||||
DefaultGoSharedLibDir = "go_sp"
|
||||
)
|
||||
|
||||
// GoSPBuilder represents a Go stored procedure builder
|
||||
type GoSPBuilder struct {
|
||||
GoSharedLibDir string
|
||||
InstallPrefix string
|
||||
GoPath string // Path to Go executable
|
||||
}
|
||||
|
||||
// NewGoSPBuilder creates a new Go stored procedure builder
|
||||
func NewGoSPBuilder(installPrefix string) *GoSPBuilder {
|
||||
return &GoSPBuilder{
|
||||
GoSharedLibDir: DefaultGoSharedLibDir,
|
||||
InstallPrefix: installPrefix,
|
||||
}
|
||||
}
|
||||
|
||||
// WithGoSharedLibDir sets the Go shared library directory
|
||||
func (b *GoSPBuilder) WithGoSharedLibDir(dir string) *GoSPBuilder {
|
||||
b.GoSharedLibDir = dir
|
||||
return b
|
||||
}
|
||||
|
||||
// WithGoPath sets the path to the Go executable
|
||||
func (b *GoSPBuilder) WithGoPath(path string) *GoSPBuilder {
|
||||
b.GoPath = path
|
||||
return b
|
||||
}
|
||||
|
||||
// run executes a command with the given arguments and environment variables
|
||||
func (b *GoSPBuilder) run(cmd string, args ...string) error {
|
||||
fmt.Println("Running:", cmd, args)
|
||||
c := exec.Command(cmd, args...)
|
||||
// Set environment variables
|
||||
c.Env = append(os.Environ(),
|
||||
"GOROOT=/usr/local/go",
|
||||
"GOPATH=/root/go",
|
||||
"PATH=/usr/local/go/bin:" + os.Getenv("PATH"))
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
return c.Run()
|
||||
}
|
||||
|
||||
// Build builds a Go stored procedure
|
||||
func (b *GoSPBuilder) Build() error {
|
||||
fmt.Println("Building Go stored procedure...")
|
||||
|
||||
// Use the explicitly provided Go path if available
|
||||
var goExePath string
|
||||
if b.GoPath != "" {
|
||||
goExePath = b.GoPath
|
||||
fmt.Printf("Using explicitly provided Go executable: %s\n", goExePath)
|
||||
} else {
|
||||
// Fallback to ensuring Go is installed via the installer
|
||||
goInstaller := postgres.NewGoInstaller()
|
||||
var err error
|
||||
goExePath, err = goInstaller.InstallGo()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to ensure Go is installed: %w", err)
|
||||
}
|
||||
fmt.Printf("Using detected Go executable from: %s\n", goExePath)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(b.GoSharedLibDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create directory: %w", err)
|
||||
}
|
||||
|
||||
libPath := filepath.Join(b.GoSharedLibDir, "gosp.go")
|
||||
libSrc := `
|
||||
package main
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
//export helloworld
|
||||
func helloworld() {
|
||||
fmt.Println("Hello from Go stored procedure!")
|
||||
}
|
||||
|
||||
func main() {}
|
||||
`
|
||||
if err := os.WriteFile(libPath, []byte(libSrc), 0644); err != nil {
|
||||
return fmt.Errorf("failed to write to file: %w", err)
|
||||
}
|
||||
|
||||
// Use the full path to Go rather than relying on PATH
|
||||
fmt.Println("Running Go build with full path:", goExePath)
|
||||
|
||||
// Show debug information
|
||||
fmt.Println("Environment variables that will be set:")
|
||||
fmt.Println(" GOROOT=/usr/local/go")
|
||||
fmt.Println(" GOPATH=/root/go")
|
||||
fmt.Println(" PATH=/usr/local/go/bin:" + os.Getenv("PATH"))
|
||||
|
||||
// Verify that the Go executable exists before using it
|
||||
if _, err := os.Stat(goExePath); err != nil {
|
||||
return fmt.Errorf("Go executable not found at %s: %w", goExePath, err)
|
||||
}
|
||||
|
||||
// Create the output directory if it doesn't exist
|
||||
outputDir := filepath.Join(b.InstallPrefix, "lib")
|
||||
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create output directory %s: %w", outputDir, err)
|
||||
}
|
||||
|
||||
// Prepare output path
|
||||
outputPath := filepath.Join(outputDir, "libgosp.so")
|
||||
|
||||
// Instead of relying on environment variables, create a wrapper shell script
|
||||
// that sets all required environment variables and then calls the Go executable
|
||||
tempDir, err := os.MkdirTemp("", "go-build-")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create temp directory: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir) // Clean up when done
|
||||
|
||||
goRoot := filepath.Dir(filepath.Dir(goExePath)) // /usr/local/go
|
||||
wrapperScript := filepath.Join(tempDir, "go-wrapper.sh")
|
||||
wrapperContent := fmt.Sprintf(`#!/bin/sh
|
||||
# Go wrapper script created by GoSPBuilder
|
||||
export GOROOT=%s
|
||||
export GOPATH=/root/go
|
||||
export PATH=%s:$PATH
|
||||
|
||||
echo "=== Go environment variables ==="
|
||||
echo "GOROOT=$GOROOT"
|
||||
echo "GOPATH=$GOPATH"
|
||||
echo "PATH=$PATH"
|
||||
|
||||
echo "=== Running Go command ==="
|
||||
echo "%s $@"
|
||||
exec %s "$@"
|
||||
`,
|
||||
goRoot,
|
||||
filepath.Dir(goExePath),
|
||||
goExePath,
|
||||
goExePath)
|
||||
|
||||
// Write the wrapper script
|
||||
if err := os.WriteFile(wrapperScript, []byte(wrapperContent), 0755); err != nil {
|
||||
return fmt.Errorf("failed to write wrapper script: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Created wrapper script at %s\n", wrapperScript)
|
||||
|
||||
// Use the wrapper script to build the Go shared library
|
||||
cmd := exec.Command(wrapperScript, "build", "-buildmode=c-shared", "-o", outputPath, libPath)
|
||||
cmd.Dir = filepath.Dir(libPath) // Set working directory to where the source file is
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
fmt.Printf("Executing Go build via wrapper script\n")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("failed to build Go stored procedure: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("✅ Go stored procedure built successfully!")
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user