| package earlyconfig |
| |
| import ( |
| "fmt" |
| "sort" |
| |
| version "github.com/hashicorp/go-version" |
| "github.com/hashicorp/terraform-config-inspect/tfconfig" |
| "github.com/hashicorp/terraform/addrs" |
| "github.com/hashicorp/terraform/moduledeps" |
| "github.com/hashicorp/terraform/plugin/discovery" |
| "github.com/hashicorp/terraform/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 string |
| |
| // 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 |
| } |
| |
| // ProviderDependencies returns the provider dependencies for the recieving |
| // config, including all of its descendent modules. |
| 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 { |
| inst := moduledeps.ProviderInstance(name) |
| var constraints version.Constraints |
| for _, reqStr := range reqs { |
| 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, name), |
| })) |
| continue |
| } |
| constraints = append(constraints, constraint...) |
| } |
| } |
| providers[inst] = 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 |
| } |