1
0
mirror of https://github.com/go-task/task.git synced 2025-06-06 23:46:46 +02:00

Export Time Struct to Template

This commit is contained in:
Stephen Prater 2019-08-25 13:16:59 -07:00
parent cb6fe4bb59
commit a1aec8178a
11 changed files with 40 additions and 26 deletions

View File

@ -356,6 +356,11 @@ Two special variables `{{.CHECKSUM}}` and `{{.TIMESTAMP}}` are available
for interpolation within `status` commands, depending on the method assigned for interpolation within `status` commands, depending on the method assigned
to fingerprint the sources. Only `source` globs are fingerprinted. to fingerprint the sources. Only `source` globs are fingerprinted.
Note that the `{{.TIMESTAMP}}` variable is a "live" Go time struct, and can be
formatted using any of the methods that `Time` responds to.
See [the Go Time documentation](https://golang.org/pkg/time/) for more information.
You can use `--force` or `-f` if you want to force a task to run even when You can use `--force` or `-f` if you want to force a task to run even when
up-to-date. up-to-date.

View File

@ -74,7 +74,7 @@ func (c *Checksum) checksum(files ...string) (string, error) {
} }
// Value implements the Checker Interface // Value implements the Checker Interface
func (c *Checksum) Value() (string, error) { func (c *Checksum) Value() (interface{}, error) {
return c.checksum() return c.checksum()
} }

View File

@ -9,7 +9,7 @@ func (None) IsUpToDate() (bool, error) {
} }
// Value implements the Checker interface // Value implements the Checker interface
func (None) Value() (string, error) { func (None) Value() (interface{}, error) {
return "", nil return "", nil
} }

View File

@ -9,7 +9,7 @@ var (
// Checker is an interface that checks if the status is up-to-date // Checker is an interface that checks if the status is up-to-date
type Checker interface { type Checker interface {
IsUpToDate() (bool, error) IsUpToDate() (bool, error)
Value() (string, error) Value() (interface{}, error)
OnError() error OnError() error
Kind() string Kind() string
} }

View File

@ -1,7 +1,6 @@
package status package status
import ( import (
"fmt"
"os" "os"
"time" "time"
) )
@ -47,22 +46,22 @@ func (t *Timestamp) Kind() string {
} }
// Value implements the Checker Interface // Value implements the Checker Interface
func (t *Timestamp) Value() (string, error) { func (t *Timestamp) Value() (interface{}, error) {
sources, err := glob(t.Dir, t.Sources) sources, err := glob(t.Dir, t.Sources)
if err != nil { if err != nil {
return "<no value>", err return time.Now(), err
} }
sourcesMaxTime, err := getMaxTime(sources...) sourcesMaxTime, err := getMaxTime(sources...)
if err != nil { if err != nil {
return "<no value>", err return time.Now(), err
} }
if sourcesMaxTime.IsZero() { if sourcesMaxTime.IsZero() {
return "0", nil return time.Unix(0, 0), nil
} }
return fmt.Sprintf("%d", sourcesMaxTime.Unix()), nil return sourcesMaxTime, nil
} }
func getMinTime(files ...string) (time.Time, error) { func getMinTime(files ...string) (time.Time, error) {

View File

@ -13,24 +13,30 @@ var (
// Vars is a string[string] variables map. // Vars is a string[string] variables map.
type Vars map[string]Var type Vars map[string]Var
// ToStringMap converts Vars to a string map containing only the static // ToCacheMap converts Vars to a map containing only the static
// variables // variables
func (vs Vars) ToStringMap() (m map[string]string) { func (vs Vars) ToCacheMap() (m map[string](interface{})) {
m = make(map[string]string, len(vs)) m = make(map[string](interface{}), len(vs))
for k, v := range vs { for k, v := range vs {
if v.Sh != "" { if v.Sh != "" {
// Dynamic variable is not yet resolved; trigger // Dynamic variable is not yet resolved; trigger
// <no value> to be used in templates. // <no value> to be used in templates.
continue continue
} }
if v.Live != nil {
m[k] = v.Live
} else {
m[k] = v.Static m[k] = v.Static
} }
}
return return
} }
// Var represents either a static or dynamic variable. // Var represents either a static or dynamic variable.
type Var struct { type Var struct {
Static string Static string
Live interface{}
Sh string Sh string
} }

View File

@ -14,12 +14,12 @@ import (
type Templater struct { type Templater struct {
Vars taskfile.Vars Vars taskfile.Vars
strMap map[string]string cacheMap map[string](interface{})
err error err error
} }
func (r *Templater) RefreshStringMap() { func (r *Templater) RefreshCacheMap() {
r.strMap = r.Vars.ToStringMap() r.cacheMap = r.Vars.ToCacheMap()
} }
func (r *Templater) Replace(str string) string { func (r *Templater) Replace(str string) string {
@ -33,12 +33,12 @@ func (r *Templater) Replace(str string) string {
return "" return ""
} }
if r.strMap == nil { if r.cacheMap == nil {
r.strMap = r.Vars.ToStringMap() r.cacheMap = r.Vars.ToCacheMap()
} }
var b bytes.Buffer var b bytes.Buffer
if err = templ.Execute(&b, r.strMap); err != nil { if err = templ.Execute(&b, r.cacheMap); err != nil {
r.err = err r.err = err
return "" return ""
} }
@ -66,6 +66,7 @@ func (r *Templater) ReplaceVars(vars taskfile.Vars) taskfile.Vars {
for k, v := range vars { for k, v := range vars {
new[k] = taskfile.Var{ new[k] = taskfile.Var{
Static: r.Replace(v.Static), Static: r.Replace(v.Static),
Live: v.Live,
Sh: r.Replace(v.Sh), Sh: r.Replace(v.Sh),
} }
} }

View File

@ -355,7 +355,7 @@ func getEnviron(t *taskfile.Task) []string {
} }
environ := os.Environ() environ := os.Environ()
for k, v := range t.Env.ToStringMap() { for k, v := range t.Env.ToCacheMap() {
environ = append(environ, fmt.Sprintf("%s=%s", k, v)) environ = append(environ, fmt.Sprintf("%s=%s", k, v))
} }
return environ return environ

View File

@ -423,8 +423,10 @@ func TestStatusChecksum(t *testing.T) {
buff.Reset() buff.Reset()
inf, _ := os.Stat(filepath.Join(dir, "source.txt")) inf, _ := os.Stat(filepath.Join(dir, "source.txt"))
ts := fmt.Sprintf("%d", inf.ModTime().Unix()) ts := fmt.Sprintf("%d", inf.ModTime().Unix())
tf := fmt.Sprintf("%s", inf.ModTime())
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "build-with-timestamp"})) assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "build-with-timestamp"}))
assert.Contains(t, buff.String(), ts) assert.Contains(t, buff.String(), ts)
assert.Contains(t, buff.String(), tf)
} }
func TestInit(t *testing.T) { func TestInit(t *testing.T) {

View File

@ -19,4 +19,5 @@ build-with-timestamp:
sources: sources:
- ./source.txt - ./source.txt
status: status:
- echo "{{.TIMESTAMP}}" - echo '{{.TIMESTAMP.Unix }}'
- echo '{{.TIMESTAMP}}'

View File

@ -106,10 +106,10 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) {
return nil, err return nil, err
} }
vars[strings.ToUpper(checker.Kind())] = taskfile.Var{Static: value} vars[strings.ToUpper(checker.Kind())] = taskfile.Var{Live: value}
// Adding new static variables, requires us to refresh the templaters // Adding new variables, requires us to refresh the templaters
// cache of the the static values // cache of the the values manually
r.RefreshStringMap() r.RefreshCacheMap()
new.Status = r.ReplaceSlice(origTask.Status) new.Status = r.ReplaceSlice(origTask.Status)
} }