1
0
mirror of https://github.com/go-task/task.git synced 2025-01-12 04:34:11 +02:00
task/internal/compiler/v2/compiler_v2.go

132 lines
3.0 KiB
Go
Raw Normal View History

package v2
import (
"bytes"
2018-09-01 16:02:23 +02:00
"context"
"fmt"
"strings"
"sync"
"github.com/go-task/task/v3/internal/compiler"
"github.com/go-task/task/v3/internal/execext"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/templater"
"github.com/go-task/task/v3/taskfile"
)
var _ compiler.Compiler = &CompilerV2{}
type CompilerV2 struct {
Dir string
Taskvars *taskfile.Vars
TaskfileVars *taskfile.Vars
Expansions int
Logger *logger.Logger
dynamicCache map[string]string
muDynamicCache sync.Mutex
}
func (c *CompilerV2) GetTaskfileVariables() (*taskfile.Vars, error) {
return &taskfile.Vars{}, nil
}
// FastGetVariables is a no-op on v2
func (c *CompilerV2) FastGetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
return c.GetVariables(t, call)
}
// GetVariables returns fully resolved variables following the priority order:
// 1. Task variables
// 2. Call variables
// 3. Taskfile variables
// 4. Taskvars file variables
// 5. Environment variables
func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) {
vr := varResolver{
c: c,
vars: compiler.GetEnviron(),
}
vr.vars.Set("TASK", taskfile.Var{Static: t.Task})
for _, vars := range []*taskfile.Vars{c.Taskvars, c.TaskfileVars, call.Vars, t.Vars} {
for i := 0; i < c.Expansions; i++ {
vr.merge(vars)
}
}
return vr.vars, vr.err
}
type varResolver struct {
c *CompilerV2
vars *taskfile.Vars
err error
}
func (vr *varResolver) merge(vars *taskfile.Vars) {
if vr.err != nil {
return
}
tr := templater.Templater{Vars: vr.vars}
_ = vars.Range(func(k string, v taskfile.Var) error {
v = taskfile.Var{
Static: tr.Replace(v.Static),
Sh: tr.Replace(v.Sh),
}
static, err := vr.c.HandleDynamicVar(v, "")
if err != nil {
vr.err = err
return err
}
vr.vars.Set(k, taskfile.Var{Static: static})
return nil
})
vr.err = tr.Err()
}
func (c *CompilerV2) HandleDynamicVar(v taskfile.Var, _ string) (string, error) {
if v.Static != "" || v.Sh == "" {
return v.Static, nil
}
c.muDynamicCache.Lock()
defer c.muDynamicCache.Unlock()
if c.dynamicCache == nil {
c.dynamicCache = make(map[string]string, 30)
}
if result, ok := c.dynamicCache[v.Sh]; ok {
return result, nil
}
var stdout bytes.Buffer
opts := &execext.RunCommandOptions{
Command: v.Sh,
Stdout: &stdout,
Stderr: c.Logger.Stderr,
}
2018-09-01 16:02:23 +02:00
if err := execext.RunCommand(context.Background(), opts); err != nil {
2021-07-11 00:33:36 +02:00
return "", fmt.Errorf(`task: Command "%s" failed: %s`, opts.Command, err)
}
// Trim a single trailing newline from the result to make most command
// output easier to use in shell commands.
result := strings.TrimSuffix(stdout.String(), "\n")
c.dynamicCache[v.Sh] = result
2019-05-26 23:36:39 +02:00
c.Logger.VerboseErrf(logger.Magenta, `task: dynamic variable: '%s' result: '%s'`, v.Sh, result)
return result, nil
}
// ResetCache clear the dymanic variables cache
func (c *CompilerV2) ResetCache() {
c.muDynamicCache.Lock()
defer c.muDynamicCache.Unlock()
c.dynamicCache = nil
}