mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-16 11:42:58 -06:00
fa2a76fa23
addrs.Module is itself internally just []string, but this better communicates our intent here and makes this integrate better with other code which is using this type for this purposes.
134 lines
4.0 KiB
Go
134 lines
4.0 KiB
Go
package configload
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
version "github.com/hashicorp/go-version"
|
|
|
|
"github.com/hashicorp/terraform/addrs"
|
|
)
|
|
|
|
// moduleRecord represents some metadata about an installed module, as part
|
|
// of a moduleManifest.
|
|
type moduleRecord struct {
|
|
// Key is a unique identifier for this particular module, based on its
|
|
// position within the static module tree.
|
|
Key string `json:"Key"`
|
|
|
|
// SourceAddr is the source address given for this module in configuration.
|
|
// This is used only to detect if the source was changed in configuration
|
|
// since the module was last installed, which means that the installer
|
|
// must re-install it.
|
|
SourceAddr string `json:"Source"`
|
|
|
|
// Version is the exact version of the module, which results from parsing
|
|
// VersionStr. nil for un-versioned modules.
|
|
Version *version.Version `json:"-"`
|
|
|
|
// VersionStr is the version specifier string. This is used only for
|
|
// serialization in snapshots and should not be accessed or updated
|
|
// by any other codepaths; use "Version" instead.
|
|
VersionStr string `json:"Version,omitempty"`
|
|
|
|
// Dir is the path to the local directory where the module is installed.
|
|
Dir string `json:"Dir"`
|
|
}
|
|
|
|
// moduleManifest is a map used to keep track of the filesystem locations
|
|
// and other metadata about installed modules.
|
|
//
|
|
// The configuration loader refers to this, while the module installer updates
|
|
// it to reflect any changes to the installed modules.
|
|
type moduleManifest map[string]moduleRecord
|
|
|
|
func manifestKey(path addrs.Module) string {
|
|
return path.String()
|
|
}
|
|
|
|
// manifestSnapshotFile is an internal struct used only to assist in our JSON
|
|
// serializtion of manifest snapshots. It should not be used for any other
|
|
// purposes.
|
|
type manifestSnapshotFile struct {
|
|
Records []moduleRecord `json:"Modules"`
|
|
}
|
|
|
|
const manifestFilename = "modules.json"
|
|
|
|
func (m *moduleMgr) manifestSnapshotPath() string {
|
|
return filepath.Join(m.Dir, manifestFilename)
|
|
}
|
|
|
|
// readModuleManifestSnapshot loads a manifest snapshot from the filesystem.
|
|
func (m *moduleMgr) readModuleManifestSnapshot() error {
|
|
src, err := m.FS.ReadFile(m.manifestSnapshotPath())
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
// We'll treat a missing file as an empty manifest
|
|
m.manifest = make(moduleManifest)
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
if len(src) == 0 {
|
|
// This should never happen, but we'll tolerate it as if it were
|
|
// a valid empty JSON object.
|
|
m.manifest = make(moduleManifest)
|
|
return nil
|
|
}
|
|
|
|
var read manifestSnapshotFile
|
|
err = json.Unmarshal(src, &read)
|
|
|
|
new := make(moduleManifest)
|
|
for _, record := range read.Records {
|
|
if record.VersionStr != "" {
|
|
record.Version, err = version.NewVersion(record.VersionStr)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid version %q for %s: %s", record.VersionStr, record.Key, err)
|
|
}
|
|
}
|
|
if _, exists := new[record.Key]; exists {
|
|
// This should never happen in any valid file, so we'll catch it
|
|
// and report it to avoid confusing/undefined behavior if the
|
|
// snapshot file was edited incorrectly outside of Terraform.
|
|
return fmt.Errorf("snapshot file contains two records for path %s", record.Key)
|
|
}
|
|
new[record.Key] = record
|
|
}
|
|
|
|
m.manifest = new
|
|
|
|
return nil
|
|
}
|
|
|
|
// writeModuleManifestSnapshot writes a snapshot of the current manifest
|
|
// to the filesystem.
|
|
//
|
|
// The caller must guarantee no concurrent modifications of the manifest for
|
|
// the duration of a call to this function, or the behavior is undefined.
|
|
func (m *moduleMgr) writeModuleManifestSnapshot() error {
|
|
var write manifestSnapshotFile
|
|
|
|
for _, record := range m.manifest {
|
|
// Make sure VersionStr is in sync with Version, since we encourage
|
|
// callers to manipulate Version and ignore VersionStr.
|
|
if record.Version != nil {
|
|
record.VersionStr = record.Version.String()
|
|
} else {
|
|
record.VersionStr = ""
|
|
}
|
|
write.Records = append(write.Records, record)
|
|
}
|
|
|
|
src, err := json.Marshal(write)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return m.FS.WriteFile(m.manifestSnapshotPath(), src, os.ModePerm)
|
|
}
|