zlh-agent/internal/provision/executil/embedded_exec.go

70 lines
1.8 KiB
Go

package executil
import (
"bytes"
"fmt"
"os"
"os/exec"
"path"
"strings"
"zlh-agent/scripts"
)
// RunEmbeddedScript executes an embedded script via bash by piping its contents to stdin.
// If the script is a devcontainer installer, this automatically prepends the shared common.sh
// so that tiny per-runtime installers can call install_runtime in the same shell session.
func RunEmbeddedScript(scriptPath string, extraEnv ...string) error {
normalized := normalizeEmbeddedPath(scriptPath)
payload, err := loadEmbeddedPayload(normalized)
if err != nil {
return err
}
cmd := exec.Command("bash")
cmd.Stdin = bytes.NewReader(payload)
// Inherit current env and overlay any provided vars (e.g., RUNTIME_VERSION=24).
if len(extraEnv) > 0 {
cmd.Env = append(os.Environ(), extraEnv...)
}
// Match RunScript behavior (executil.go)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func loadEmbeddedPayload(normalized string) ([]byte, error) {
// If this is a devcontainer installer, prepend the shared library.
if strings.HasPrefix(normalized, "devcontainer/") {
commonPath := "devcontainer/lib/common.sh"
common, err := scripts.FS.ReadFile(commonPath)
if err != nil {
return nil, fmt.Errorf("embedded script missing: %s: %w", commonPath, err)
}
body, err := scripts.FS.ReadFile(normalized)
if err != nil {
return nil, fmt.Errorf("embedded script missing: %s: %w", normalized, err)
}
// Ensure bash sees common first, then runtime installer.
return append(append(common, '\n'), body...), nil
}
data, err := scripts.FS.ReadFile(normalized)
if err != nil {
return nil, fmt.Errorf("embedded script missing: %s: %w", normalized, err)
}
return data, nil
}
func normalizeEmbeddedPath(p string) string {
p = strings.TrimPrefix(p, "scripts/")
p = path.Clean(p)
return strings.TrimPrefix(p, "/")
}