From a1aec8178a917c46278c9d989a1eb64c6fc9c3e8 Mon Sep 17 00:00:00 2001 From: Stephen Prater Date: Sun, 25 Aug 2019 13:16:59 -0700 Subject: [PATCH] Export Time Struct to Template --- docs/usage.md | 5 +++++ internal/status/checksum.go | 2 +- internal/status/none.go | 2 +- internal/status/status.go | 2 +- internal/status/timestamp.go | 11 +++++------ internal/taskfile/var.go | 14 ++++++++++---- internal/templater/templater.go | 15 ++++++++------- task.go | 2 +- task_test.go | 2 ++ testdata/checksum/Taskfile.yml | 3 ++- variables.go | 8 ++++---- 11 files changed, 40 insertions(+), 26 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index c4882332..02a8db7e 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -356,6 +356,11 @@ Two special variables `{{.CHECKSUM}}` and `{{.TIMESTAMP}}` are available for interpolation within `status` commands, depending on the method assigned 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 up-to-date. diff --git a/internal/status/checksum.go b/internal/status/checksum.go index bdd2aff9..9d449d65 100644 --- a/internal/status/checksum.go +++ b/internal/status/checksum.go @@ -74,7 +74,7 @@ func (c *Checksum) checksum(files ...string) (string, error) { } // Value implements the Checker Interface -func (c *Checksum) Value() (string, error) { +func (c *Checksum) Value() (interface{}, error) { return c.checksum() } diff --git a/internal/status/none.go b/internal/status/none.go index c67dc437..cca3888b 100644 --- a/internal/status/none.go +++ b/internal/status/none.go @@ -9,7 +9,7 @@ func (None) IsUpToDate() (bool, error) { } // Value implements the Checker interface -func (None) Value() (string, error) { +func (None) Value() (interface{}, error) { return "", nil } diff --git a/internal/status/status.go b/internal/status/status.go index 45388b49..2648d27c 100644 --- a/internal/status/status.go +++ b/internal/status/status.go @@ -9,7 +9,7 @@ var ( // Checker is an interface that checks if the status is up-to-date type Checker interface { IsUpToDate() (bool, error) - Value() (string, error) + Value() (interface{}, error) OnError() error Kind() string } diff --git a/internal/status/timestamp.go b/internal/status/timestamp.go index a97549fc..97881f58 100644 --- a/internal/status/timestamp.go +++ b/internal/status/timestamp.go @@ -1,7 +1,6 @@ package status import ( - "fmt" "os" "time" ) @@ -47,22 +46,22 @@ func (t *Timestamp) Kind() string { } // Value implements the Checker Interface -func (t *Timestamp) Value() (string, error) { +func (t *Timestamp) Value() (interface{}, error) { sources, err := glob(t.Dir, t.Sources) if err != nil { - return "", err + return time.Now(), err } sourcesMaxTime, err := getMaxTime(sources...) if err != nil { - return "", err + return time.Now(), err } 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) { diff --git a/internal/taskfile/var.go b/internal/taskfile/var.go index f52e0f8b..ad0f5e90 100644 --- a/internal/taskfile/var.go +++ b/internal/taskfile/var.go @@ -13,17 +13,22 @@ var ( // Vars is a string[string] variables map. 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 -func (vs Vars) ToStringMap() (m map[string]string) { - m = make(map[string]string, len(vs)) +func (vs Vars) ToCacheMap() (m map[string](interface{})) { + m = make(map[string](interface{}), len(vs)) for k, v := range vs { if v.Sh != "" { // Dynamic variable is not yet resolved; trigger // to be used in templates. continue } - m[k] = v.Static + + if v.Live != nil { + m[k] = v.Live + } else { + m[k] = v.Static + } } return } @@ -31,6 +36,7 @@ func (vs Vars) ToStringMap() (m map[string]string) { // Var represents either a static or dynamic variable. type Var struct { Static string + Live interface{} Sh string } diff --git a/internal/templater/templater.go b/internal/templater/templater.go index d601c99a..d43117e0 100644 --- a/internal/templater/templater.go +++ b/internal/templater/templater.go @@ -14,12 +14,12 @@ import ( type Templater struct { Vars taskfile.Vars - strMap map[string]string - err error + cacheMap map[string](interface{}) + err error } -func (r *Templater) RefreshStringMap() { - r.strMap = r.Vars.ToStringMap() +func (r *Templater) RefreshCacheMap() { + r.cacheMap = r.Vars.ToCacheMap() } func (r *Templater) Replace(str string) string { @@ -33,12 +33,12 @@ func (r *Templater) Replace(str string) string { return "" } - if r.strMap == nil { - r.strMap = r.Vars.ToStringMap() + if r.cacheMap == nil { + r.cacheMap = r.Vars.ToCacheMap() } 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 return "" } @@ -66,6 +66,7 @@ func (r *Templater) ReplaceVars(vars taskfile.Vars) taskfile.Vars { for k, v := range vars { new[k] = taskfile.Var{ Static: r.Replace(v.Static), + Live: v.Live, Sh: r.Replace(v.Sh), } } diff --git a/task.go b/task.go index 40b1dc98..657abbcd 100644 --- a/task.go +++ b/task.go @@ -355,7 +355,7 @@ func getEnviron(t *taskfile.Task) []string { } 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)) } return environ diff --git a/task_test.go b/task_test.go index 1e126a2b..6cb95058 100644 --- a/task_test.go +++ b/task_test.go @@ -423,8 +423,10 @@ func TestStatusChecksum(t *testing.T) { buff.Reset() inf, _ := os.Stat(filepath.Join(dir, "source.txt")) 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.Contains(t, buff.String(), ts) + assert.Contains(t, buff.String(), tf) } func TestInit(t *testing.T) { diff --git a/testdata/checksum/Taskfile.yml b/testdata/checksum/Taskfile.yml index b9d5f6e9..029264fb 100644 --- a/testdata/checksum/Taskfile.yml +++ b/testdata/checksum/Taskfile.yml @@ -19,4 +19,5 @@ build-with-timestamp: sources: - ./source.txt status: - - echo "{{.TIMESTAMP}}" + - echo '{{.TIMESTAMP.Unix }}' + - echo '{{.TIMESTAMP}}' diff --git a/variables.go b/variables.go index 57e7ae78..8307fc4d 100644 --- a/variables.go +++ b/variables.go @@ -106,10 +106,10 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) { return nil, err } - vars[strings.ToUpper(checker.Kind())] = taskfile.Var{Static: value} - // Adding new static variables, requires us to refresh the templaters - // cache of the the static values - r.RefreshStringMap() + vars[strings.ToUpper(checker.Kind())] = taskfile.Var{Live: value} + // Adding new variables, requires us to refresh the templaters + // cache of the the values manually + r.RefreshCacheMap() new.Status = r.ReplaceSlice(origTask.Status) }