github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/configs/configload/loader.go (about)

     1  package configload
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/terraform-plugin-sdk/internal/configs"
     7  	"github.com/hashicorp/terraform-plugin-sdk/internal/registry"
     8  	"github.com/hashicorp/terraform-svchost/disco"
     9  	"github.com/spf13/afero"
    10  )
    11  
    12  // A Loader instance is the main entry-point for loading configurations via
    13  // this package.
    14  //
    15  // It extends the general config-loading functionality in the parent package
    16  // "configs" to support installation of modules from remote sources and
    17  // loading full configurations using modules that were previously installed.
    18  type Loader struct {
    19  	// parser is used to read configuration
    20  	parser *configs.Parser
    21  
    22  	// modules is used to install and locate descendent modules that are
    23  	// referenced (directly or indirectly) from the root module.
    24  	modules moduleMgr
    25  }
    26  
    27  // Config is used with NewLoader to specify configuration arguments for the
    28  // loader.
    29  type Config struct {
    30  	// ModulesDir is a path to a directory where descendent modules are
    31  	// (or should be) installed. (This is usually the
    32  	// .terraform/modules directory, in the common case where this package
    33  	// is being loaded from the main Terraform CLI package.)
    34  	ModulesDir string
    35  
    36  	// Services is the service discovery client to use when locating remote
    37  	// module registry endpoints. If this is nil then registry sources are
    38  	// not supported, which should be true only in specialized circumstances
    39  	// such as in tests.
    40  	Services *disco.Disco
    41  }
    42  
    43  // NewLoader creates and returns a loader that reads configuration from the
    44  // real OS filesystem.
    45  //
    46  // The loader has some internal state about the modules that are currently
    47  // installed, which is read from disk as part of this function. If that
    48  // manifest cannot be read then an error will be returned.
    49  func NewLoader(config *Config) (*Loader, error) {
    50  	fs := afero.NewOsFs()
    51  	parser := configs.NewParser(fs)
    52  	reg := registry.NewClient(config.Services, nil)
    53  
    54  	ret := &Loader{
    55  		parser: parser,
    56  		modules: moduleMgr{
    57  			FS:         afero.Afero{Fs: fs},
    58  			CanInstall: true,
    59  			Dir:        config.ModulesDir,
    60  			Services:   config.Services,
    61  			Registry:   reg,
    62  		},
    63  	}
    64  
    65  	err := ret.modules.readModuleManifestSnapshot()
    66  	if err != nil {
    67  		return nil, fmt.Errorf("failed to read module manifest: %s", err)
    68  	}
    69  
    70  	return ret, nil
    71  }
    72  
    73  // ModulesDir returns the path to the directory where the loader will look for
    74  // the local cache of remote module packages.
    75  func (l *Loader) ModulesDir() string {
    76  	return l.modules.Dir
    77  }
    78  
    79  // RefreshModules updates the in-memory cache of the module manifest from the
    80  // module manifest file on disk. This is not necessary in normal use because
    81  // module installation and configuration loading are separate steps, but it
    82  // can be useful in tests where module installation is done as a part of
    83  // configuration loading by a helper function.
    84  //
    85  // Call this function after any module installation where an existing loader
    86  // is already alive and may be used again later.
    87  //
    88  // An error is returned if the manifest file cannot be read.
    89  func (l *Loader) RefreshModules() error {
    90  	if l == nil {
    91  		// Nothing to do, then.
    92  		return nil
    93  	}
    94  	return l.modules.readModuleManifestSnapshot()
    95  }
    96  
    97  // Sources returns the source code cache for the underlying parser of this
    98  // loader. This is a shorthand for l.Parser().Sources().
    99  func (l *Loader) Sources() map[string][]byte {
   100  	return l.parser.Sources()
   101  }