mirror of
https://github.com/hashicorp/terraform.git
synced 2026-02-19 02:39:17 -05:00
97 lines
2.9 KiB
Go
97 lines
2.9 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package moduleref
|
|
|
|
import (
|
|
"maps"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/go-version"
|
|
"github.com/hashicorp/terraform/internal/configs"
|
|
"github.com/hashicorp/terraform/internal/modsdir"
|
|
)
|
|
|
|
// Resolver is the struct responsible for finding all modules references in
|
|
// Terraform configuration for a given internal module manifest.
|
|
type Resolver struct {
|
|
manifest *Manifest
|
|
internalManifest modsdir.Manifest
|
|
}
|
|
|
|
// NewResolver creates a new Resolver, storing a copy of the internal manifest
|
|
// that is passed.
|
|
func NewResolver(internalManifest modsdir.Manifest) *Resolver {
|
|
// Since maps are pointers, create a copy of the internal manifest to
|
|
// prevent introducing side effects to the original
|
|
internalManifestCopy := maps.Clone(internalManifest)
|
|
|
|
// Remove the root module entry from the internal manifest as it is
|
|
// never directly referenced.
|
|
delete(internalManifestCopy, "")
|
|
|
|
return &Resolver{
|
|
internalManifest: internalManifestCopy,
|
|
manifest: &Manifest{
|
|
FormatVersion: FormatVersion,
|
|
Records: Records{},
|
|
},
|
|
}
|
|
}
|
|
|
|
// Resolve will attempt to find all module references for the passed configuration
|
|
// and return a new manifest encapsulating this information.
|
|
func (r *Resolver) Resolve(cfg *configs.Config) *Manifest {
|
|
// First find all the referenced modules.
|
|
r.findAndTrimReferencedEntries(cfg, nil, nil)
|
|
|
|
return r.manifest
|
|
}
|
|
|
|
// findAndTrimReferencedEntries will traverse a given Terraform configuration
|
|
// and attempt find a caller for every entry in the internal module manifest.
|
|
// If an entry is found, it will be removed from the internal manifest and
|
|
// appended to the manifest that records this new information in a nested heirarchy.
|
|
func (r *Resolver) findAndTrimReferencedEntries(cfg *configs.Config, parentRecord *Record, parentKey *string) {
|
|
var name string
|
|
var versionConstraints version.Constraints
|
|
if parentKey != nil {
|
|
for key := range cfg.Parent.Children {
|
|
if key == *parentKey {
|
|
name = key
|
|
if cfg.Parent.Module.ModuleCalls[key] != nil {
|
|
versionConstraints = cfg.Parent.Module.ModuleCalls[key].Version.Required
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
childRecord := &Record{
|
|
Key: name,
|
|
Source: cfg.SourceAddr,
|
|
VersionConstraints: versionConstraints,
|
|
}
|
|
key := strings.Join(cfg.Path, ".")
|
|
|
|
for entryKey, entry := range r.internalManifest {
|
|
if entryKey == key {
|
|
// Use resolved version from manifest
|
|
childRecord.Version = entry.Version
|
|
if parentRecord.Source != nil {
|
|
parentRecord.addChild(childRecord)
|
|
} else {
|
|
r.manifest.addModuleEntry(childRecord)
|
|
}
|
|
// "Trim" the entry from the internal manifest, saving us cycles
|
|
// as we descend into the module tree.
|
|
delete(r.internalManifest, entryKey)
|
|
break
|
|
}
|
|
}
|
|
|
|
// Traverse the child configurations
|
|
for childKey, childCfg := range cfg.Children {
|
|
r.findAndTrimReferencedEntries(childCfg, childRecord, &childKey)
|
|
}
|
|
}
|