buildr/modules/task/script_task.go
Peter e60726ef9e
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
feat: implement new and man for plugin modules
- use extracted shared libraries
2023-08-23 22:06:26 +02:00

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")
}