feat: migrate to golang
This commit is contained in:
121
internal/corecfg/hooks_exec.go
Normal file
121
internal/corecfg/hooks_exec.go
Normal file
@ -0,0 +1,121 @@
|
||||
package corecfg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// executeHooks runs every core_config_generated.* script found in the hooks
|
||||
// directory, in sorted order. Direct port of _execute_hooks.
|
||||
func (m *Manager) executeHooks(configFilePath string) {
|
||||
hooksDir := filepath.Join(m.Storage.ConfigDir, "hooks")
|
||||
if _, err := os.Stat(hooksDir); os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(hooksDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var hookFiles []string
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(entry.Name(), "core_config_generated.") {
|
||||
hookFiles = append(hookFiles, filepath.Join(hooksDir, entry.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
if len(hookFiles) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("🔧 Found %d hook(s) to execute\n", len(hookFiles))
|
||||
sort.Strings(hookFiles)
|
||||
|
||||
for _, hookFile := range hookFiles {
|
||||
executeHook(hookFile, configFilePath)
|
||||
}
|
||||
}
|
||||
|
||||
// executeHook runs a single hook script with the generated config file path
|
||||
// as its argument. Direct port of _execute_hook, adapted for the fact that
|
||||
// the Go binary has no bundled interpreter of its own (unlike Python's
|
||||
// sys.executable) — .py hooks are run via a system "python3"/"python"
|
||||
// found on PATH.
|
||||
func executeHook(hookPath, configFilePath string) bool {
|
||||
if _, err := os.Stat(hookPath); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
|
||||
var cmdArgs []string
|
||||
switch strings.ToLower(filepath.Ext(hookPath)) {
|
||||
case ".py":
|
||||
python := "python3"
|
||||
if runtime.GOOS == "windows" {
|
||||
python = "python"
|
||||
}
|
||||
if _, err := exec.LookPath(python); err != nil {
|
||||
alt := "python"
|
||||
if runtime.GOOS == "windows" {
|
||||
alt = "python3"
|
||||
}
|
||||
if _, err := exec.LookPath(alt); err == nil {
|
||||
python = alt
|
||||
}
|
||||
}
|
||||
cmdArgs = []string{python, hookPath, configFilePath}
|
||||
case ".js":
|
||||
cmdArgs = []string{"node", hookPath, configFilePath}
|
||||
case ".nu":
|
||||
cmdArgs = []string{"nu", hookPath, configFilePath}
|
||||
default:
|
||||
if runtime.GOOS != "windows" {
|
||||
os.Chmod(hookPath, 0o755)
|
||||
}
|
||||
cmdArgs = []string{hookPath, configFilePath}
|
||||
}
|
||||
|
||||
fmt.Printf("🔧 Executing hook: %s\n", hookPath)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, cmdArgs[0], cmdArgs[1:]...)
|
||||
cmd.Dir = filepath.Dir(hookPath)
|
||||
cmd.Env = append(os.Environ(), "PYTHONIOENCODING=utf-8")
|
||||
|
||||
var stdout, stderr strings.Builder
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
err := cmd.Run()
|
||||
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
fmt.Printf("⏰ Hook timed out: %s\n", filepath.Base(hookPath))
|
||||
return false
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
fmt.Printf("✅ Hook executed successfully: %s\n", filepath.Base(hookPath))
|
||||
if out := strings.TrimSpace(stdout.String()); out != "" {
|
||||
fmt.Printf(" Output: %s\n", out)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fmt.Printf("❌ Hook failed: %s\n", filepath.Base(hookPath))
|
||||
if errOut := strings.TrimSpace(stderr.String()); errOut != "" {
|
||||
fmt.Printf(" Error: %s\n", errOut)
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user