core: path.module, path.root, path.cwd use fwd slashes on all platforms
Previously we used the native slash type for the host platform, but that leads to issues if the same configuration is applied on both Windows and non-Windows systems. Since Windows supports slashes and backslashes, we can safely return always slashes here and require that users combine the result with subsequent path parts using slashes, like: "${path.module}/foo/bar" Previously the above would lead to an error on Windows if path.module contained any backslashes. This is not really possible to unit test directly right now since we always run our tests on Unix systems and filepath.ToSlash is a no-op on Unix. However, this does include some tests for the basic behavior to verify that it's not regressed as a result of this change. This will need to be reported in the changelog as a potential breaking change, since anyone who was using Terraform _exclusively_ on Windows may have been using expressions like "${path.module}foo\\bar" which they will now need to update. This fixes #14986.
This commit is contained in:
parent
2cf63d068f
commit
cf9499cb78
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -423,7 +424,7 @@ func (d *evaluationStateData) GetPathAttr(addr addrs.PathAttr, rng tfdiags.Sourc
|
||||||
})
|
})
|
||||||
return cty.DynamicVal, diags
|
return cty.DynamicVal, diags
|
||||||
}
|
}
|
||||||
return cty.StringVal(wd), diags
|
return cty.StringVal(filepath.ToSlash(wd)), diags
|
||||||
|
|
||||||
case "module":
|
case "module":
|
||||||
moduleConfig := d.Evaluator.Config.DescendentForInstance(d.ModulePath)
|
moduleConfig := d.Evaluator.Config.DescendentForInstance(d.ModulePath)
|
||||||
|
@ -433,11 +434,11 @@ func (d *evaluationStateData) GetPathAttr(addr addrs.PathAttr, rng tfdiags.Sourc
|
||||||
panic(fmt.Sprintf("module.path read from module %s, which has no configuration", d.ModulePath))
|
panic(fmt.Sprintf("module.path read from module %s, which has no configuration", d.ModulePath))
|
||||||
}
|
}
|
||||||
sourceDir := moduleConfig.Module.SourceDir
|
sourceDir := moduleConfig.Module.SourceDir
|
||||||
return cty.StringVal(sourceDir), diags
|
return cty.StringVal(filepath.ToSlash(sourceDir)), diags
|
||||||
|
|
||||||
case "root":
|
case "root":
|
||||||
sourceDir := d.Evaluator.Config.Module.SourceDir
|
sourceDir := d.Evaluator.Config.Module.SourceDir
|
||||||
return cty.StringVal(sourceDir), diags
|
return cty.StringVal(filepath.ToSlash(sourceDir)), diags
|
||||||
|
|
||||||
default:
|
default:
|
||||||
suggestion := nameSuggestion(addr.Name, []string{"cwd", "module", "root"})
|
suggestion := nameSuggestion(addr.Name, []string{"cwd", "module", "root"})
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/addrs"
|
"github.com/hashicorp/terraform/addrs"
|
||||||
|
"github.com/hashicorp/terraform/configs"
|
||||||
"github.com/hashicorp/terraform/tfdiags"
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -34,3 +35,46 @@ func TestEvaluatorGetTerraformAttr(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEvaluatorGetPathAttr(t *testing.T) {
|
||||||
|
evaluator := &Evaluator{
|
||||||
|
Meta: &ContextMeta{
|
||||||
|
Env: "foo",
|
||||||
|
},
|
||||||
|
Config: &configs.Config{
|
||||||
|
Module: &configs.Module{
|
||||||
|
SourceDir: "bar/baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
data := &evaluationStateData{
|
||||||
|
Evaluator: evaluator,
|
||||||
|
}
|
||||||
|
scope := evaluator.Scope(data, nil)
|
||||||
|
|
||||||
|
t.Run("module", func(t *testing.T) {
|
||||||
|
want := cty.StringVal("bar/baz")
|
||||||
|
got, diags := scope.Data.GetPathAttr(addrs.PathAttr{
|
||||||
|
Name: "module",
|
||||||
|
}, tfdiags.SourceRange{})
|
||||||
|
if len(diags) != 0 {
|
||||||
|
t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
|
||||||
|
}
|
||||||
|
if !got.RawEquals(want) {
|
||||||
|
t.Errorf("wrong result %#v; want %#v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("root", func(t *testing.T) {
|
||||||
|
want := cty.StringVal("bar/baz")
|
||||||
|
got, diags := scope.Data.GetPathAttr(addrs.PathAttr{
|
||||||
|
Name: "root",
|
||||||
|
}, tfdiags.SourceRange{})
|
||||||
|
if len(diags) != 0 {
|
||||||
|
t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
|
||||||
|
}
|
||||||
|
if !got.RawEquals(want) {
|
||||||
|
t.Errorf("wrong result %#v; want %#v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue