107 lines
2.1 KiB
Go
107 lines
2.1 KiB
Go
package task
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"code.icb4dc0.de/buildr/buildr/internal/sh"
|
|
"code.icb4dc0.de/buildr/buildr/modules"
|
|
)
|
|
|
|
var (
|
|
_ modules.Module = (*ScriptTask)(nil)
|
|
_ modules.Helper = (*ScriptTask)(nil)
|
|
)
|
|
|
|
type ScriptTask struct {
|
|
Env map[string]string `hcl:"environment,optional"`
|
|
Shell string `hcl:"shell,optional"`
|
|
Script string `hcl:"script,optional"`
|
|
WorkingDir string `hcl:"working_dir,optional"`
|
|
Inline []string `hcl:"inline,optional"`
|
|
ContinueOnError bool `hcl:"continue_on_error,optional"`
|
|
}
|
|
|
|
func (s ScriptTask) Type() string {
|
|
return "script"
|
|
}
|
|
|
|
func (s ScriptTask) Category() modules.Category {
|
|
return modules.CategoryTask
|
|
}
|
|
|
|
func (s ScriptTask) Execute(ctx modules.ExecutionContext) (err error) {
|
|
logger := ctx.Logger()
|
|
|
|
shell := s.Shell
|
|
if shell == "" {
|
|
shell = "/bin/sh"
|
|
}
|
|
|
|
if _, err = exec.LookPath(shell); err != nil {
|
|
return fmt.Errorf("failed to lookup shell (%s) path: %w", shell, err)
|
|
}
|
|
|
|
cmd, err := sh.PrepareCommand(ctx, shell)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if s.WorkingDir != "" {
|
|
if !filepath.IsLocal(s.WorkingDir) {
|
|
return fmt.Errorf("working_dir must be a local path: %s", s.WorkingDir)
|
|
}
|
|
|
|
cmd.SetWorkingDir(filepath.Join(ctx.WorkingDir(), s.WorkingDir))
|
|
}
|
|
|
|
var scriptSource io.ReadCloser
|
|
|
|
scriptSource, err = s.scriptReader()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() {
|
|
err = errors.Join(err, scriptSource.Close())
|
|
}()
|
|
|
|
cmd.SetStdIn(scriptSource)
|
|
|
|
cmd.AddEnv(s.Env)
|
|
|
|
logger.Info(
|
|
"Executing script",
|
|
slog.String("shell", shell),
|
|
)
|
|
|
|
if err := cmd.Run(); err != nil {
|
|
if s.ContinueOnError {
|
|
logger.Warn("Error occurred while executing script", slog.Any("error", err))
|
|
return nil
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s ScriptTask) scriptReader() (io.ReadCloser, error) {
|
|
if len(s.Inline) > 0 {
|
|
return io.NopCloser(strings.NewReader(strings.Join(s.Inline, "\n"))), nil
|
|
}
|
|
|
|
if s.Script != "" {
|
|
return os.Open(s.Script)
|
|
}
|
|
|
|
return nil, fmt.Errorf("no script source provided")
|
|
}
|