From 59d2733b88ece48398bd4e2cb9c8cd1cb82fb91d Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Thu, 7 Jan 2021 11:17:38 -0300 Subject: [PATCH] Make dynamic variables run on the right directory It was always running in the main Taskfile dir, even when the variable was declared in an included taskfile in another directory or when task had a custom dir. Closes #384 --- CHANGELOG.md | 4 ++++ internal/compiler/compiler.go | 2 +- internal/compiler/v2/compiler_v2.go | 22 +++++++++++++++---- internal/compiler/v3/compiler_v3.go | 14 +++++++++--- task_test.go | 19 ++++++++++++---- testdata/dir/dynamic_var/.gitignore | 1 + testdata/dir/dynamic_var/Taskfile.yml | 11 ++++++++++ testdata/dir/dynamic_var/subdirectory/dir.txt | 1 + testdata/generates/Taskfile.yml | 2 +- variables.go | 2 +- 10 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 testdata/dir/dynamic_var/.gitignore create mode 100644 testdata/dir/dynamic_var/Taskfile.yml create mode 100644 testdata/dir/dynamic_var/subdirectory/dir.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index d1c6d636..d1e7b0c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +- Fix a bug where dynamic variables (those declared with `sh:`) were not + running in the task directory when the task has a custom dir or it was + in an included taskfile + ([#384](https://github.com/go-task/task/issues/384)). - The watch feature (via the `--watch` flag) got a few different bug fixes and should be more stable now ([#423](https://github.com/go-task/task/pull/423), [#365](https://github.com/go-task/task/issues/365)). diff --git a/internal/compiler/compiler.go b/internal/compiler/compiler.go index 1e0fabfa..16c13886 100644 --- a/internal/compiler/compiler.go +++ b/internal/compiler/compiler.go @@ -8,6 +8,6 @@ import ( // E.g. variable merger, template processing, etc. type Compiler interface { GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfile.Vars, error) - HandleDynamicVar(v taskfile.Var) (string, error) + HandleDynamicVar(v taskfile.Var, dir string) (string, error) ResetCache() } diff --git a/internal/compiler/v2/compiler_v2.go b/internal/compiler/v2/compiler_v2.go index 5c1d6e46..d9319547 100644 --- a/internal/compiler/v2/compiler_v2.go +++ b/internal/compiler/v2/compiler_v2.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "path/filepath" "strings" "sync" @@ -37,8 +38,20 @@ type CompilerV2 struct { // 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()} + // NOTE(@andreynering): We're manually joining these paths here because + // this is the raw task, not the compiled one. + dir := t.Dir + if !filepath.IsAbs(dir) { + dir = filepath.Join(c.Dir, dir) + } + + vr := varResolver{ + c: c, + dir: dir, + 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) @@ -49,6 +62,7 @@ func (c *CompilerV2) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi type varResolver struct { c *CompilerV2 + dir string vars *taskfile.Vars err error } @@ -63,7 +77,7 @@ func (vr *varResolver) merge(vars *taskfile.Vars) { Static: tr.Replace(v.Static), Sh: tr.Replace(v.Sh), } - static, err := vr.c.HandleDynamicVar(v) + static, err := vr.c.HandleDynamicVar(v, vr.dir) if err != nil { vr.err = err return err @@ -74,7 +88,7 @@ func (vr *varResolver) merge(vars *taskfile.Vars) { vr.err = tr.Err() } -func (c *CompilerV2) HandleDynamicVar(v taskfile.Var) (string, error) { +func (c *CompilerV2) HandleDynamicVar(v taskfile.Var, dir string) (string, error) { if v.Static != "" || v.Sh == "" { return v.Static, nil } @@ -92,7 +106,7 @@ func (c *CompilerV2) HandleDynamicVar(v taskfile.Var) (string, error) { var stdout bytes.Buffer opts := &execext.RunCommandOptions{ Command: v.Sh, - Dir: c.Dir, + Dir: dir, Stdout: &stdout, Stderr: c.Logger.Stderr, } diff --git a/internal/compiler/v3/compiler_v3.go b/internal/compiler/v3/compiler_v3.go index 0cc9ba78..1c0e2d5b 100644 --- a/internal/compiler/v3/compiler_v3.go +++ b/internal/compiler/v3/compiler_v3.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "path/filepath" "strings" "sync" @@ -31,6 +32,13 @@ func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi result := compiler.GetEnviron() result.Set("TASK", taskfile.Var{Static: t.Task}) + // NOTE(@andreynering): We're manually joining these paths here because + // this is the raw task, not the compiled one. + dir := t.Dir + if !filepath.IsAbs(dir) { + dir = filepath.Join(c.Dir, dir) + } + rangeFunc := func(k string, v taskfile.Var) error { tr := templater.Templater{Vars: result, RemoveNoValue: true} v = taskfile.Var{ @@ -40,7 +48,7 @@ func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi if err := tr.Err(); err != nil { return err } - static, err := c.HandleDynamicVar(v) + static, err := c.HandleDynamicVar(v, dir) if err != nil { return err } @@ -61,7 +69,7 @@ func (c *CompilerV3) GetVariables(t *taskfile.Task, call taskfile.Call) (*taskfi return result, nil } -func (c *CompilerV3) HandleDynamicVar(v taskfile.Var) (string, error) { +func (c *CompilerV3) HandleDynamicVar(v taskfile.Var, dir string) (string, error) { if v.Static != "" || v.Sh == "" { return v.Static, nil } @@ -79,7 +87,7 @@ func (c *CompilerV3) HandleDynamicVar(v taskfile.Var) (string, error) { var stdout bytes.Buffer opts := &execext.RunCommandOptions{ Command: v.Sh, - Dir: c.Dir, + Dir: dir, Stdout: &stdout, Stderr: c.Logger.Stderr, } diff --git a/task_test.go b/task_test.go index f86d2741..9613f814 100644 --- a/task_test.go +++ b/task_test.go @@ -303,16 +303,15 @@ func TestPrecondition(t *testing.T) { } func TestGenerates(t *testing.T) { + const dir = "testdata/generates" + const ( srcTask = "sub/src.txt" relTask = "rel.txt" - absTask = "abs.txt" + absTask = "sub/abs.txt" fileWithSpaces = "my text file.txt" ) - // This test does not work with a relative dir. - dir, err := filepath.Abs("testdata/generates") - assert.NoError(t, err) var srcFile = filepath.Join(dir, srcTask) for _, task := range []string{srcTask, relTask, absTask, fileWithSpaces} { @@ -800,6 +799,18 @@ func TestWhenDirAttributeItCreatesMissingAndRunsInThatDir(t *testing.T) { _ = os.RemoveAll(toBeCreated) } +func TestDynamicVariablesShouldRunOnTheTaskDir(t *testing.T) { + tt := fileContentTest{ + Dir: "testdata/dir/dynamic_var", + Target: "default", + TrimSpace: false, + Files: map[string]string{ + "subdirectory/dir.txt": "subdirectory\n", + }, + } + tt.Run(t) +} + func TestDisplaysErrorOnUnsupportedVersion(t *testing.T) { e := task.Executor{ Dir: "testdata/version/v1", diff --git a/testdata/dir/dynamic_var/.gitignore b/testdata/dir/dynamic_var/.gitignore new file mode 100644 index 00000000..5e4f4543 --- /dev/null +++ b/testdata/dir/dynamic_var/.gitignore @@ -0,0 +1 @@ +subdirectory/dir.txt diff --git a/testdata/dir/dynamic_var/Taskfile.yml b/testdata/dir/dynamic_var/Taskfile.yml new file mode 100644 index 00000000..9a2d8cd6 --- /dev/null +++ b/testdata/dir/dynamic_var/Taskfile.yml @@ -0,0 +1,11 @@ +version: '3' + +tasks: + default: + cmds: + - echo '{{.FOLDER}}' > dir.txt + dir: subdirectory + vars: + FOLDER: + sh: basename $(pwd) + silent: true diff --git a/testdata/dir/dynamic_var/subdirectory/dir.txt b/testdata/dir/dynamic_var/subdirectory/dir.txt new file mode 100644 index 00000000..bcba6aa2 --- /dev/null +++ b/testdata/dir/dynamic_var/subdirectory/dir.txt @@ -0,0 +1 @@ +subdirectory diff --git a/testdata/generates/Taskfile.yml b/testdata/generates/Taskfile.yml index 4dc6e9ec..e2f4a87b 100644 --- a/testdata/generates/Taskfile.yml +++ b/testdata/generates/Taskfile.yml @@ -4,7 +4,7 @@ vars: BUILD_DIR: $pwd tasks: - abs.txt: + sub/abs.txt: desc: generates dest file based on absolute paths deps: - sub/src.txt diff --git a/variables.go b/variables.go index 649bac4a..a6929cfd 100644 --- a/variables.go +++ b/variables.go @@ -60,7 +60,7 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) { new.Env.Merge(r.ReplaceVars(e.Taskfile.Env)) new.Env.Merge(r.ReplaceVars(origTask.Env)) err = new.Env.Range(func(k string, v taskfile.Var) error { - static, err := e.Compiler.HandleDynamicVar(v) + static, err := e.Compiler.HandleDynamicVar(v, new.Dir) if err != nil { return err }