1package initwd
2
3import (
4	"fmt"
5
6	version "github.com/hashicorp/go-version"
7	"github.com/hashicorp/terraform-config-inspect/tfconfig"
8	"github.com/hashicorp/terraform/internal/earlyconfig"
9	"github.com/hashicorp/terraform/internal/modsdir"
10	"github.com/hashicorp/terraform/internal/tfdiags"
11)
12
13// LoadConfig loads a full configuration tree that has previously had all of
14// its dependent modules installed to the given modulesDir using a
15// ModuleInstaller.
16//
17// This uses the early configuration loader and thus only reads top-level
18// metadata from the modules in the configuration. Most callers should use
19// the configs/configload package to fully load a configuration.
20func LoadConfig(rootDir, modulesDir string) (*earlyconfig.Config, tfdiags.Diagnostics) {
21	rootMod, diags := earlyconfig.LoadModule(rootDir)
22	if rootMod == nil {
23		return nil, diags
24	}
25
26	manifest, err := modsdir.ReadManifestSnapshotForDir(modulesDir)
27	if err != nil {
28		diags = diags.Append(tfdiags.Sourceless(
29			tfdiags.Error,
30			"Failed to read module manifest",
31			fmt.Sprintf("Terraform failed to read its manifest of locally-cached modules: %s.", err),
32		))
33		return nil, diags
34	}
35
36	return earlyconfig.BuildConfig(rootMod, earlyconfig.ModuleWalkerFunc(
37		func(req *earlyconfig.ModuleRequest) (*tfconfig.Module, *version.Version, tfdiags.Diagnostics) {
38			var diags tfdiags.Diagnostics
39
40			key := manifest.ModuleKey(req.Path)
41			record, exists := manifest[key]
42			if !exists {
43				diags = diags.Append(tfdiags.Sourceless(
44					tfdiags.Error,
45					"Module not installed",
46					fmt.Sprintf("Module %s is not yet installed. Run \"terraform init\" to install all modules required by this configuration.", req.Path.String()),
47				))
48				return nil, nil, diags
49			}
50
51			mod, mDiags := earlyconfig.LoadModule(record.Dir)
52			diags = diags.Append(mDiags)
53			return mod, record.Version, diags
54		},
55	))
56}
57