mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Remove earlyconfig
This commit is contained in:
parent
8df065a2fe
commit
60ea68edc7
@ -1,210 +0,0 @@
|
|||||||
package earlyconfig
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
version "github.com/hashicorp/go-version"
|
|
||||||
"github.com/hashicorp/terraform-config-inspect/tfconfig"
|
|
||||||
"github.com/hashicorp/terraform/internal/addrs"
|
|
||||||
"github.com/hashicorp/terraform/internal/getproviders"
|
|
||||||
"github.com/hashicorp/terraform/internal/moduledeps"
|
|
||||||
"github.com/hashicorp/terraform/internal/plugin/discovery"
|
|
||||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Config is a node in the tree of modules within a configuration.
|
|
||||||
//
|
|
||||||
// The module tree is constructed by following ModuleCall instances recursively
|
|
||||||
// through the root module transitively into descendent modules.
|
|
||||||
type Config struct {
|
|
||||||
// RootModule points to the Config for the root module within the same
|
|
||||||
// module tree as this module. If this module _is_ the root module then
|
|
||||||
// this is self-referential.
|
|
||||||
Root *Config
|
|
||||||
|
|
||||||
// ParentModule points to the Config for the module that directly calls
|
|
||||||
// this module. If this is the root module then this field is nil.
|
|
||||||
Parent *Config
|
|
||||||
|
|
||||||
// Path is a sequence of module logical names that traverse from the root
|
|
||||||
// module to this config. Path is empty for the root module.
|
|
||||||
//
|
|
||||||
// This should only be used to display paths to the end-user in rare cases
|
|
||||||
// where we are talking about the static module tree, before module calls
|
|
||||||
// have been resolved. In most cases, an addrs.ModuleInstance describing
|
|
||||||
// a node in the dynamic module tree is better, since it will then include
|
|
||||||
// any keys resulting from evaluating "count" and "for_each" arguments.
|
|
||||||
Path addrs.Module
|
|
||||||
|
|
||||||
// ChildModules points to the Config for each of the direct child modules
|
|
||||||
// called from this module. The keys in this map match the keys in
|
|
||||||
// Module.ModuleCalls.
|
|
||||||
Children map[string]*Config
|
|
||||||
|
|
||||||
// Module points to the object describing the configuration for the
|
|
||||||
// various elements (variables, resources, etc) defined by this module.
|
|
||||||
Module *tfconfig.Module
|
|
||||||
|
|
||||||
// CallPos is the source position for the header of the module block that
|
|
||||||
// requested this module.
|
|
||||||
//
|
|
||||||
// This field is meaningless for the root module, where its contents are undefined.
|
|
||||||
CallPos tfconfig.SourcePos
|
|
||||||
|
|
||||||
// SourceAddr is the source address that the referenced module was requested
|
|
||||||
// from, as specified in configuration.
|
|
||||||
//
|
|
||||||
// This field is meaningless for the root module, where its contents are undefined.
|
|
||||||
SourceAddr addrs.ModuleSource
|
|
||||||
|
|
||||||
// Version is the specific version that was selected for this module,
|
|
||||||
// based on version constraints given in configuration.
|
|
||||||
//
|
|
||||||
// This field is nil if the module was loaded from a non-registry source,
|
|
||||||
// since versions are not supported for other sources.
|
|
||||||
//
|
|
||||||
// This field is meaningless for the root module, where it will always
|
|
||||||
// be nil.
|
|
||||||
Version *version.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProviderRequirements searches the full tree of modules under the receiver
|
|
||||||
// for both explicit and implicit dependencies on providers.
|
|
||||||
//
|
|
||||||
// The result is a full manifest of all of the providers that must be available
|
|
||||||
// in order to work with the receiving configuration.
|
|
||||||
//
|
|
||||||
// If the returned diagnostics includes errors then the resulting Requirements
|
|
||||||
// may be incomplete.
|
|
||||||
func (c *Config) ProviderRequirements() (getproviders.Requirements, tfdiags.Diagnostics) {
|
|
||||||
reqs := make(getproviders.Requirements)
|
|
||||||
diags := c.addProviderRequirements(reqs)
|
|
||||||
return reqs, diags
|
|
||||||
}
|
|
||||||
|
|
||||||
// addProviderRequirements is the main part of the ProviderRequirements
|
|
||||||
// implementation, gradually mutating a shared requirements object to
|
|
||||||
// eventually return.
|
|
||||||
func (c *Config) addProviderRequirements(reqs getproviders.Requirements) tfdiags.Diagnostics {
|
|
||||||
var diags tfdiags.Diagnostics
|
|
||||||
|
|
||||||
// First we'll deal with the requirements directly in _our_ module...
|
|
||||||
for localName, providerReqs := range c.Module.RequiredProviders {
|
|
||||||
var fqn addrs.Provider
|
|
||||||
if source := providerReqs.Source; source != "" {
|
|
||||||
addr, moreDiags := addrs.ParseProviderSourceString(source)
|
|
||||||
if moreDiags.HasErrors() {
|
|
||||||
diags = diags.Append(tfdiags.Sourceless(
|
|
||||||
tfdiags.Error,
|
|
||||||
"Invalid provider source address",
|
|
||||||
fmt.Sprintf("Invalid source %q for provider %q in %s", source, localName, c.Path),
|
|
||||||
))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fqn = addr
|
|
||||||
}
|
|
||||||
if fqn.IsZero() {
|
|
||||||
fqn = addrs.ImpliedProviderForUnqualifiedType(localName)
|
|
||||||
}
|
|
||||||
if _, ok := reqs[fqn]; !ok {
|
|
||||||
// We'll at least have an unconstrained dependency then, but might
|
|
||||||
// add to this in the loop below.
|
|
||||||
reqs[fqn] = nil
|
|
||||||
}
|
|
||||||
for _, constraintsStr := range providerReqs.VersionConstraints {
|
|
||||||
if constraintsStr != "" {
|
|
||||||
constraints, err := getproviders.ParseVersionConstraints(constraintsStr)
|
|
||||||
if err != nil {
|
|
||||||
diags = diags.Append(tfdiags.Sourceless(
|
|
||||||
tfdiags.Error,
|
|
||||||
"Invalid provider version constraint",
|
|
||||||
fmt.Sprintf("Provider %q in %s has invalid version constraint %q: %s.", localName, c.Path, constraintsStr, err),
|
|
||||||
))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
reqs[fqn] = append(reqs[fqn], constraints...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...and now we'll recursively visit all of the child modules to merge
|
|
||||||
// in their requirements too.
|
|
||||||
for _, childConfig := range c.Children {
|
|
||||||
moreDiags := childConfig.addProviderRequirements(reqs)
|
|
||||||
diags = diags.Append(moreDiags)
|
|
||||||
}
|
|
||||||
|
|
||||||
return diags
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProviderDependencies is a deprecated variant of ProviderRequirements which
|
|
||||||
// uses the moduledeps models for representation. This is preserved to allow
|
|
||||||
// a gradual transition over to ProviderRequirements, but note that its
|
|
||||||
// support for fully-qualified provider addresses has some idiosyncracies.
|
|
||||||
func (c *Config) ProviderDependencies() (*moduledeps.Module, tfdiags.Diagnostics) {
|
|
||||||
var diags tfdiags.Diagnostics
|
|
||||||
|
|
||||||
var name string
|
|
||||||
if len(c.Path) > 0 {
|
|
||||||
name = c.Path[len(c.Path)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
ret := &moduledeps.Module{
|
|
||||||
Name: name,
|
|
||||||
}
|
|
||||||
|
|
||||||
providers := make(moduledeps.Providers)
|
|
||||||
for name, reqs := range c.Module.RequiredProviders {
|
|
||||||
var fqn addrs.Provider
|
|
||||||
if source := reqs.Source; source != "" {
|
|
||||||
addr, parseDiags := addrs.ParseProviderSourceString(source)
|
|
||||||
if parseDiags.HasErrors() {
|
|
||||||
diags = diags.Append(wrapDiagnostic(tfconfig.Diagnostic{
|
|
||||||
Severity: tfconfig.DiagError,
|
|
||||||
Summary: "Invalid provider source",
|
|
||||||
Detail: fmt.Sprintf("Invalid source %q for provider", name),
|
|
||||||
}))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fqn = addr
|
|
||||||
}
|
|
||||||
if fqn.IsZero() {
|
|
||||||
fqn = addrs.NewDefaultProvider(name)
|
|
||||||
}
|
|
||||||
var constraints version.Constraints
|
|
||||||
for _, reqStr := range reqs.VersionConstraints {
|
|
||||||
if reqStr != "" {
|
|
||||||
constraint, err := version.NewConstraint(reqStr)
|
|
||||||
if err != nil {
|
|
||||||
diags = diags.Append(wrapDiagnostic(tfconfig.Diagnostic{
|
|
||||||
Severity: tfconfig.DiagError,
|
|
||||||
Summary: "Invalid provider version constraint",
|
|
||||||
Detail: fmt.Sprintf("Invalid version constraint %q for provider %s.", reqStr, fqn.String()),
|
|
||||||
}))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
constraints = append(constraints, constraint...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
providers[fqn] = moduledeps.ProviderDependency{
|
|
||||||
Constraints: discovery.NewConstraints(constraints),
|
|
||||||
Reason: moduledeps.ProviderDependencyExplicit,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret.Providers = providers
|
|
||||||
|
|
||||||
childNames := make([]string, 0, len(c.Children))
|
|
||||||
for name := range c.Children {
|
|
||||||
childNames = append(childNames, name)
|
|
||||||
}
|
|
||||||
sort.Strings(childNames)
|
|
||||||
|
|
||||||
for _, name := range childNames {
|
|
||||||
child, childDiags := c.Children[name].ProviderDependencies()
|
|
||||||
ret.Children = append(ret.Children, child)
|
|
||||||
diags = diags.Append(childDiags)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, diags
|
|
||||||
}
|
|
@ -1,173 +0,0 @@
|
|||||||
package earlyconfig
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
version "github.com/hashicorp/go-version"
|
|
||||||
"github.com/hashicorp/terraform-config-inspect/tfconfig"
|
|
||||||
"github.com/hashicorp/terraform/internal/addrs"
|
|
||||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BuildConfig constructs a Config from a root module by loading all of its
|
|
||||||
// descendent modules via the given ModuleWalker.
|
|
||||||
func BuildConfig(root *tfconfig.Module, walker ModuleWalker) (*Config, tfdiags.Diagnostics) {
|
|
||||||
var diags tfdiags.Diagnostics
|
|
||||||
cfg := &Config{
|
|
||||||
Module: root,
|
|
||||||
}
|
|
||||||
cfg.Root = cfg // Root module is self-referential.
|
|
||||||
cfg.Children, diags = buildChildModules(cfg, walker)
|
|
||||||
return cfg, diags
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildChildModules(parent *Config, walker ModuleWalker) (map[string]*Config, tfdiags.Diagnostics) {
|
|
||||||
var diags tfdiags.Diagnostics
|
|
||||||
ret := map[string]*Config{}
|
|
||||||
calls := parent.Module.ModuleCalls
|
|
||||||
|
|
||||||
// We'll sort the calls by their local names so that they'll appear in a
|
|
||||||
// predictable order in any logging that's produced during the walk.
|
|
||||||
callNames := make([]string, 0, len(calls))
|
|
||||||
for k := range calls {
|
|
||||||
callNames = append(callNames, k)
|
|
||||||
}
|
|
||||||
sort.Strings(callNames)
|
|
||||||
|
|
||||||
for _, callName := range callNames {
|
|
||||||
call := calls[callName]
|
|
||||||
path := make([]string, len(parent.Path)+1)
|
|
||||||
copy(path, parent.Path)
|
|
||||||
path[len(path)-1] = call.Name
|
|
||||||
|
|
||||||
var vc version.Constraints
|
|
||||||
haveVersionArg := false
|
|
||||||
if strings.TrimSpace(call.Version) != "" {
|
|
||||||
haveVersionArg = true
|
|
||||||
|
|
||||||
var err error
|
|
||||||
vc, err = version.NewConstraint(call.Version)
|
|
||||||
if err != nil {
|
|
||||||
diags = diags.Append(wrapDiagnostic(tfconfig.Diagnostic{
|
|
||||||
Severity: tfconfig.DiagError,
|
|
||||||
Summary: "Invalid version constraint",
|
|
||||||
Detail: fmt.Sprintf("Module %q (declared at %s line %d) has invalid version constraint %q: %s.", callName, call.Pos.Filename, call.Pos.Line, call.Version, err),
|
|
||||||
}))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var sourceAddr addrs.ModuleSource
|
|
||||||
var err error
|
|
||||||
if haveVersionArg {
|
|
||||||
sourceAddr, err = addrs.ParseModuleSourceRegistry(call.Source)
|
|
||||||
} else {
|
|
||||||
sourceAddr, err = addrs.ParseModuleSource(call.Source)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
if haveVersionArg {
|
|
||||||
diags = diags.Append(wrapDiagnostic(tfconfig.Diagnostic{
|
|
||||||
Severity: tfconfig.DiagError,
|
|
||||||
Summary: "Invalid registry module source address",
|
|
||||||
Detail: fmt.Sprintf("Module %q (declared at %s line %d) has invalid source address %q: %s.\n\nTerraform assumed that you intended a module registry source address because you also set the argument \"version\", which applies only to registry modules.", callName, call.Pos.Filename, call.Pos.Line, call.Source, err),
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
diags = diags.Append(wrapDiagnostic(tfconfig.Diagnostic{
|
|
||||||
Severity: tfconfig.DiagError,
|
|
||||||
Summary: "Invalid module source address",
|
|
||||||
Detail: fmt.Sprintf("Module %q (declared at %s line %d) has invalid source address %q: %s.", callName, call.Pos.Filename, call.Pos.Line, call.Source, err),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
// If we didn't have a valid source address then we can't continue
|
|
||||||
// down the module tree with this one.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
req := ModuleRequest{
|
|
||||||
Name: call.Name,
|
|
||||||
Path: path,
|
|
||||||
SourceAddr: sourceAddr,
|
|
||||||
VersionConstraints: vc,
|
|
||||||
Parent: parent,
|
|
||||||
CallPos: call.Pos,
|
|
||||||
}
|
|
||||||
|
|
||||||
mod, ver, modDiags := walker.LoadModule(&req)
|
|
||||||
diags = append(diags, modDiags...)
|
|
||||||
if mod == nil {
|
|
||||||
// nil can be returned if the source address was invalid and so
|
|
||||||
// nothing could be loaded whatsoever. LoadModule should've
|
|
||||||
// returned at least one error diagnostic in that case.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
child := &Config{
|
|
||||||
Parent: parent,
|
|
||||||
Root: parent.Root,
|
|
||||||
Path: path,
|
|
||||||
Module: mod,
|
|
||||||
CallPos: call.Pos,
|
|
||||||
SourceAddr: sourceAddr,
|
|
||||||
Version: ver,
|
|
||||||
}
|
|
||||||
|
|
||||||
child.Children, modDiags = buildChildModules(child, walker)
|
|
||||||
diags = diags.Append(modDiags)
|
|
||||||
|
|
||||||
ret[call.Name] = child
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, diags
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModuleRequest is used as part of the ModuleWalker interface used with
|
|
||||||
// function BuildConfig.
|
|
||||||
type ModuleRequest struct {
|
|
||||||
// Name is the "logical name" of the module call within configuration.
|
|
||||||
// This is provided in case the name is used as part of a storage key
|
|
||||||
// for the module, but implementations must otherwise treat it as an
|
|
||||||
// opaque string. It is guaranteed to have already been validated as an
|
|
||||||
// HCL identifier and UTF-8 encoded.
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Path is a list of logical names that traverse from the root module to
|
|
||||||
// this module. This can be used, for example, to form a lookup key for
|
|
||||||
// each distinct module call in a configuration, allowing for multiple
|
|
||||||
// calls with the same name at different points in the tree.
|
|
||||||
Path addrs.Module
|
|
||||||
|
|
||||||
// SourceAddr is the source address string provided by the user in
|
|
||||||
// configuration.
|
|
||||||
SourceAddr addrs.ModuleSource
|
|
||||||
|
|
||||||
// VersionConstraint is the version constraint applied to the module in
|
|
||||||
// configuration.
|
|
||||||
VersionConstraints version.Constraints
|
|
||||||
|
|
||||||
// Parent is the partially-constructed module tree node that the loaded
|
|
||||||
// module will be added to. Callers may refer to any field of this
|
|
||||||
// structure except Children, which is still under construction when
|
|
||||||
// ModuleRequest objects are created and thus has undefined content.
|
|
||||||
// The main reason this is provided is so that full module paths can
|
|
||||||
// be constructed for uniqueness.
|
|
||||||
Parent *Config
|
|
||||||
|
|
||||||
// CallRange is the source position for the header of the "module" block
|
|
||||||
// in configuration that prompted this request.
|
|
||||||
CallPos tfconfig.SourcePos
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModuleWalker is an interface used with BuildConfig.
|
|
||||||
type ModuleWalker interface {
|
|
||||||
LoadModule(req *ModuleRequest) (*tfconfig.Module, *version.Version, tfdiags.Diagnostics)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModuleWalkerFunc is an implementation of ModuleWalker that directly wraps
|
|
||||||
// a callback function, for more convenient use of that interface.
|
|
||||||
type ModuleWalkerFunc func(req *ModuleRequest) (*tfconfig.Module, *version.Version, tfdiags.Diagnostics)
|
|
||||||
|
|
||||||
func (f ModuleWalkerFunc) LoadModule(req *ModuleRequest) (*tfconfig.Module, *version.Version, tfdiags.Diagnostics) {
|
|
||||||
return f(req)
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
package earlyconfig
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
version "github.com/hashicorp/go-version"
|
|
||||||
"github.com/hashicorp/terraform-config-inspect/tfconfig"
|
|
||||||
svchost "github.com/hashicorp/terraform-svchost"
|
|
||||||
"github.com/hashicorp/terraform/internal/addrs"
|
|
||||||
"github.com/hashicorp/terraform/internal/getproviders"
|
|
||||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConfigProviderRequirements(t *testing.T) {
|
|
||||||
cfg := testConfig(t, "testdata/provider-reqs")
|
|
||||||
|
|
||||||
impliedProvider := addrs.NewProvider(
|
|
||||||
addrs.DefaultProviderRegistryHost,
|
|
||||||
"hashicorp", "implied",
|
|
||||||
)
|
|
||||||
nullProvider := addrs.NewProvider(
|
|
||||||
addrs.DefaultProviderRegistryHost,
|
|
||||||
"hashicorp", "null",
|
|
||||||
)
|
|
||||||
randomProvider := addrs.NewProvider(
|
|
||||||
addrs.DefaultProviderRegistryHost,
|
|
||||||
"hashicorp", "random",
|
|
||||||
)
|
|
||||||
tlsProvider := addrs.NewProvider(
|
|
||||||
addrs.DefaultProviderRegistryHost,
|
|
||||||
"hashicorp", "tls",
|
|
||||||
)
|
|
||||||
happycloudProvider := addrs.NewProvider(
|
|
||||||
svchost.Hostname("tf.example.com"),
|
|
||||||
"awesomecorp", "happycloud",
|
|
||||||
)
|
|
||||||
|
|
||||||
got, diags := cfg.ProviderRequirements()
|
|
||||||
if diags.HasErrors() {
|
|
||||||
t.Fatalf("unexpected diagnostics: %s", diags.Err().Error())
|
|
||||||
}
|
|
||||||
want := getproviders.Requirements{
|
|
||||||
// the nullProvider constraints from the two modules are merged
|
|
||||||
nullProvider: getproviders.MustParseVersionConstraints("~> 2.0.0, 2.0.1"),
|
|
||||||
randomProvider: getproviders.MustParseVersionConstraints("~> 1.2.0"),
|
|
||||||
tlsProvider: getproviders.MustParseVersionConstraints("~> 3.0"),
|
|
||||||
impliedProvider: nil,
|
|
||||||
happycloudProvider: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
if diff := cmp.Diff(want, got); diff != "" {
|
|
||||||
t.Errorf("wrong result\n%s", diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testConfig(t *testing.T, baseDir string) *Config {
|
|
||||||
rootMod, diags := LoadModule(baseDir)
|
|
||||||
if diags.HasErrors() {
|
|
||||||
t.Fatalf("unexpected diagnostics: %s", diags.Err().Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg, diags := BuildConfig(rootMod, ModuleWalkerFunc(testModuleWalkerFunc))
|
|
||||||
if diags.HasErrors() {
|
|
||||||
t.Fatalf("unexpected diagnostics: %s", diags.Err().Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
// testModuleWalkerFunc is a simple implementation of ModuleWalkerFunc that
|
|
||||||
// only understands how to resolve relative filesystem paths, using source
|
|
||||||
// location information from the call.
|
|
||||||
func testModuleWalkerFunc(req *ModuleRequest) (*tfconfig.Module, *version.Version, tfdiags.Diagnostics) {
|
|
||||||
callFilename := req.CallPos.Filename
|
|
||||||
sourcePath := req.SourceAddr.String()
|
|
||||||
finalPath := filepath.Join(filepath.Dir(callFilename), sourcePath)
|
|
||||||
log.Printf("[TRACE] %s in %s -> %s", sourcePath, callFilename, finalPath)
|
|
||||||
|
|
||||||
newMod, diags := LoadModule(finalPath)
|
|
||||||
return newMod, version.Must(version.NewVersion("0.0.0")), diags
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
package earlyconfig
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-config-inspect/tfconfig"
|
|
||||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
||||||
)
|
|
||||||
|
|
||||||
func wrapDiagnostics(diags tfconfig.Diagnostics) tfdiags.Diagnostics {
|
|
||||||
ret := make(tfdiags.Diagnostics, len(diags))
|
|
||||||
for i, diag := range diags {
|
|
||||||
ret[i] = wrapDiagnostic(diag)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapDiagnostic(diag tfconfig.Diagnostic) tfdiags.Diagnostic {
|
|
||||||
return wrappedDiagnostic{
|
|
||||||
d: diag,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type wrappedDiagnostic struct {
|
|
||||||
d tfconfig.Diagnostic
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d wrappedDiagnostic) Severity() tfdiags.Severity {
|
|
||||||
switch d.d.Severity {
|
|
||||||
case tfconfig.DiagError:
|
|
||||||
return tfdiags.Error
|
|
||||||
case tfconfig.DiagWarning:
|
|
||||||
return tfdiags.Warning
|
|
||||||
default:
|
|
||||||
// Should never happen since there are no other severities
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d wrappedDiagnostic) Description() tfdiags.Description {
|
|
||||||
// Since the inspect library doesn't produce precise source locations,
|
|
||||||
// we include the position information as part of the error message text.
|
|
||||||
// See the comment inside method "Source" for more information.
|
|
||||||
switch {
|
|
||||||
case d.d.Pos == nil:
|
|
||||||
return tfdiags.Description{
|
|
||||||
Summary: d.d.Summary,
|
|
||||||
Detail: d.d.Detail,
|
|
||||||
}
|
|
||||||
case d.d.Detail != "":
|
|
||||||
return tfdiags.Description{
|
|
||||||
Summary: d.d.Summary,
|
|
||||||
Detail: fmt.Sprintf("On %s line %d: %s", d.d.Pos.Filename, d.d.Pos.Line, d.d.Detail),
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return tfdiags.Description{
|
|
||||||
Summary: fmt.Sprintf("%s (on %s line %d)", d.d.Summary, d.d.Pos.Filename, d.d.Pos.Line),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d wrappedDiagnostic) Source() tfdiags.Source {
|
|
||||||
// Since the inspect library is constrained by the lowest common denominator
|
|
||||||
// between legacy HCL and modern HCL, it only returns ranges at whole-line
|
|
||||||
// granularity, and that isn't sufficient to populate a tfdiags.Source
|
|
||||||
// and so we'll just omit ranges altogether and include the line number in
|
|
||||||
// the Description text.
|
|
||||||
//
|
|
||||||
// Callers that want to return nicer errors should consider reacting to
|
|
||||||
// earlyconfig errors by attempting a follow-up parse with the normal
|
|
||||||
// config loader, which can produce more precise source location
|
|
||||||
// information.
|
|
||||||
return tfdiags.Source{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d wrappedDiagnostic) FromExpr() *tfdiags.FromExpr {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d wrappedDiagnostic) ExtraInfo() interface{} {
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
// Package earlyconfig is a specialized alternative to the top-level "configs"
|
|
||||||
// package that does only shallow processing of configuration and is therefore
|
|
||||||
// able to be much more liberal than the full config loader in what it accepts.
|
|
||||||
//
|
|
||||||
// In particular, it can accept both current and legacy HCL syntax, and it
|
|
||||||
// ignores top-level blocks that it doesn't recognize. These two characteristics
|
|
||||||
// make this package ideal for dependency-checking use-cases so that we are
|
|
||||||
// more likely to be able to return an error message about an explicit
|
|
||||||
// incompatibility than to return a less-actionable message about a construct
|
|
||||||
// not being supported.
|
|
||||||
//
|
|
||||||
// However, its liberal approach also means it should be used sparingly. It
|
|
||||||
// exists primarily for "terraform init", so that it is able to detect
|
|
||||||
// incompatibilities more robustly when installing dependencies. For most
|
|
||||||
// other use-cases, use the "configs" and "configs/configload" packages.
|
|
||||||
//
|
|
||||||
// Package earlyconfig is a wrapper around the terraform-config-inspect
|
|
||||||
// codebase, adding to it just some helper functionality for Terraform's own
|
|
||||||
// use-cases.
|
|
||||||
package earlyconfig
|
|
@ -1,13 +0,0 @@
|
|||||||
package earlyconfig
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hashicorp/terraform-config-inspect/tfconfig"
|
|
||||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LoadModule loads some top-level metadata for the module in the given
|
|
||||||
// directory.
|
|
||||||
func LoadModule(dir string) (*tfconfig.Module, tfdiags.Diagnostics) {
|
|
||||||
mod, diags := tfconfig.LoadModule(dir)
|
|
||||||
return mod, wrapDiagnostics(diags)
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
terraform {
|
|
||||||
required_providers {
|
|
||||||
cloud = {
|
|
||||||
source = "tf.example.com/awesomecorp/happycloud"
|
|
||||||
}
|
|
||||||
null = {
|
|
||||||
# This should merge with the null provider constraint in the root module
|
|
||||||
version = "2.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
terraform {
|
|
||||||
required_providers {
|
|
||||||
null = "~> 2.0.0"
|
|
||||||
random = {
|
|
||||||
version = "~> 1.2.0"
|
|
||||||
}
|
|
||||||
tls = {
|
|
||||||
source = "hashicorp/tls"
|
|
||||||
version = "~> 3.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# There is no provider in required_providers called "implied", so this
|
|
||||||
# implicitly declares a dependency on "hashicorp/implied".
|
|
||||||
resource "implied_foo" "bar" {
|
|
||||||
}
|
|
||||||
|
|
||||||
module "child" {
|
|
||||||
source = "./child"
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user