mirror of
https://github.com/go-task/task.git
synced 2025-01-12 04:34:11 +02:00
132 lines
3.0 KiB
Go
132 lines
3.0 KiB
Go
package v2
|
|
|
|
import (
|
|
"bytes"
|
|
"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,
|
|
}
|
|
if err := execext.RunCommand(context.Background(), opts); err != nil {
|
|
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
|
|
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
|
|
}
|