zlh-agent/internal/provision/executil/embedded_exec.go
2026-03-20 23:17:19 +00:00

82 lines
2.3 KiB
Go

package executil
import (
"bytes"
"fmt"
"io"
"log"
"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)
var buf bytes.Buffer
cmd.Stdout = io.MultiWriter(os.Stdout, &buf)
cmd.Stderr = io.MultiWriter(os.Stderr, &buf)
log.Printf("[provision] action=run_embedded_script path=%s", normalized)
if err := cmd.Run(); err != nil {
log.Printf("[provision] action=run_embedded_script status=failed path=%s err=%v", normalized, err)
for _, line := range tailLogLines(buf.String(), 10) {
log.Printf("[provision] path=%s output=%s", normalized, line)
}
return err
}
log.Printf("[provision] action=run_embedded_script status=ok path=%s", normalized)
return nil
}
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, "/")
}