6 "github.com/hashicorp/hcl2/gohcl"
7 "github.com/hashicorp/hcl2/hcl"
8 "github.com/hashicorp/hcl2/hcl/hclsyntax"
10 "github.com/hashicorp/terraform/addrs"
13 // Provider represents a "provider" block in a module or file. A provider
14 // block is a provider configuration, and there can be zero or more
15 // configurations for each actual provider.
16 type Provider struct {
20 AliasRange *hcl.Range // nil if no alias set
22 Version VersionConstraint
29 func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
30 content, config, diags := block.Body.PartialContent(providerBlockSchema)
32 provider := &Provider{
33 Name: block.Labels[0],
34 NameRange: block.LabelRanges[0],
36 DeclRange: block.DefRange,
39 if attr, exists := content.Attributes["alias"]; exists {
40 valDiags := gohcl.DecodeExpression(attr.Expr, nil, &provider.Alias)
41 diags = append(diags, valDiags...)
42 provider.AliasRange = attr.Expr.Range().Ptr()
44 if !hclsyntax.ValidIdentifier(provider.Alias) {
45 diags = append(diags, &hcl.Diagnostic{
46 Severity: hcl.DiagError,
47 Summary: "Invalid provider configuration alias",
48 Detail: fmt.Sprintf("An alias must be a valid name. %s", badIdentifierDetail),
53 if attr, exists := content.Attributes["version"]; exists {
54 var versionDiags hcl.Diagnostics
55 provider.Version, versionDiags = decodeVersionConstraint(attr)
56 diags = append(diags, versionDiags...)
59 // Reserved attribute names
60 for _, name := range []string{"count", "depends_on", "for_each", "source"} {
61 if attr, exists := content.Attributes[name]; exists {
62 diags = append(diags, &hcl.Diagnostic{
63 Severity: hcl.DiagError,
64 Summary: "Reserved argument name in provider block",
65 Detail: fmt.Sprintf("The provider argument name %q is reserved for use by Terraform in a future version.", name),
66 Subject: &attr.NameRange,
71 // Reserved block types (all of them)
72 for _, block := range content.Blocks {
73 diags = append(diags, &hcl.Diagnostic{
74 Severity: hcl.DiagError,
75 Summary: "Reserved block type name in provider block",
76 Detail: fmt.Sprintf("The block type name %q is reserved for use by Terraform in a future version.", block.Type),
77 Subject: &block.TypeRange,
81 return provider, diags
84 // Addr returns the address of the receiving provider configuration, relative
85 // to its containing module.
86 func (p *Provider) Addr() addrs.ProviderConfig {
87 return addrs.ProviderConfig{
93 func (p *Provider) moduleUniqueKey() string {
95 return fmt.Sprintf("%s.%s", p.Name, p.Alias)
100 // ProviderRequirement represents a declaration of a dependency on a particular
101 // provider version without actually configuring that provider. This is used in
102 // child modules that expect a provider to be passed in from their parent.
103 type ProviderRequirement struct {
105 Requirement VersionConstraint
108 func decodeRequiredProvidersBlock(block *hcl.Block) ([]*ProviderRequirement, hcl.Diagnostics) {
109 attrs, diags := block.Body.JustAttributes()
110 var reqs []*ProviderRequirement
111 for name, attr := range attrs {
112 req, reqDiags := decodeVersionConstraint(attr)
113 diags = append(diags, reqDiags...)
114 if !diags.HasErrors() {
115 reqs = append(reqs, &ProviderRequirement{
124 var providerBlockSchema = &hcl.BodySchema{
125 Attributes: []hcl.AttributeSchema{
133 // Attribute names reserved for future expansion.
135 {Name: "depends_on"},
139 Blocks: []hcl.BlockHeaderSchema{
140 // _All_ of these are reserved for future expansion.