func configFileHasDependencyBlock(configPath string, terragruntOptions *options.TerragruntOptions) (bool, error) {
	configBytes, err := ioutil.ReadFile(configPath)
	if err != nil {
		return false, errors.WithStackTrace(err)
	}
	hclFile, diags := hclwrite.ParseConfig(configBytes, configPath, hcl.InitialPos)
	if diags.HasErrors() {
		return false, errors.WithStackTrace(diags)
	}
	for _, block := range hclFile.Body().Blocks() {
		if block.Type() == "dependency" || block.Type() == "dependencies" {
			return true, nil
		}
	}
	return false, nil
}
configFileHasDependencyBlock statically checks the terrragrunt config file at the given path and checks if it has any
dependency or dependencies blocks defined. Note that this does not do any decoding of the blocks, as it is only meant
to check for block presence.
package config
import (
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"reflect"
	"strings"
	"github.com/hashicorp/go-getter"
	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/hclparse"
	"github.com/hashicorp/hcl/v2/hclwrite"
	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
	"github.com/zclconf/go-cty/cty"
	"github.com/gruntwork-io/terragrunt/codegen"
	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/options"
	"github.com/gruntwork-io/terragrunt/remote"
	"github.com/gruntwork-io/terragrunt/util"
)
const DefaultTerragruntConfigPath = "terragrunt.hcl"
const DefaultTerragruntJsonConfigPath = "terragrunt.hcl.json"
type TerragruntConfig struct {
	Terraform                   *TerraformConfig
	TerraformBinary             string
	TerraformVersionConstraint  string
	TerragruntVersionConstraint string
	RemoteState                 *remote.RemoteState
	Dependencies                *ModuleDependencies
	DownloadDir                 string
	PreventDestroy              *bool
	Skip                        bool
	IamRole                     string
	IamAssumeRoleDuration       *int64
	IamAssumeRoleSessionName    string
	Inputs                      map[string]interface{}
	Locals                      map[string]interface{}
	TerragruntDependencies      []Dependency
	GenerateConfigs             map[string]codegen.GenerateConfig
	RetryableErrors             []string
	RetryMaxAttempts            *int
	RetrySleepIntervalSec       *int
	IsPartial bool
	ProcessedIncludes map[string]IncludeConfig
}
func (conf *TerragruntConfig) String() string {
	return fmt.Sprintf("TerragruntConfig{Terraform = %v, RemoteState = %v, Dependencies = %v, PreventDestroy = %v}", conf.Terraform, conf.RemoteState, conf.Dependencies, conf.PreventDestroy)
}
func (conf *TerragruntConfig) GetIAMRoleOptions() options.IAMRoleOptions {
	configIAMRoleOptions := options.IAMRoleOptions{
		RoleARN:               conf.IamRole,
		AssumeRoleSessionName: conf.IamAssumeRoleSessionName,
	}
	if conf.IamAssumeRoleDuration != nil {
		configIAMRoleOptions.AssumeRoleDuration = *conf.IamAssumeRoleDuration
	}
	return configIAMRoleOptions
}
type terragruntConfigFile struct {
	Terraform                   *TerraformConfig `hcl:"terraform,block"`
	TerraformBinary             *string          `hcl:"terraform_binary,attr"`
	TerraformVersionConstraint  *string          `hcl:"terraform_version_constraint,attr"`
	TerragruntVersionConstraint *string          `hcl:"terragrunt_version_constraint,attr"`
	Inputs                      *cty.Value       `hcl:"inputs,attr"`
	RemoteState     *remoteStateConfigFile `hcl:"remote_state,block"`
	RemoteStateAttr *cty.Value             `hcl:"remote_state,optional"`
	Dependencies             *ModuleDependencies `hcl:"dependencies,block"`
	DownloadDir              *string             `hcl:"download_dir,attr"`
	PreventDestroy           *bool               `hcl:"prevent_destroy,attr"`
	Skip                     *bool               `hcl:"skip,attr"`
	IamRole                  *string             `hcl:"iam_role,attr"`
	IamAssumeRoleDuration    *int64              `hcl:"iam_assume_role_duration,attr"`
	IamAssumeRoleSessionName *string             `hcl:"iam_assume_role_session_name,attr"`
	TerragruntDependencies   []Dependency        `hcl:"dependency,block"`
	GenerateAttrs  *cty.Value                `hcl:"generate,optional"`
	GenerateBlocks []terragruntGenerateBlock `hcl:"generate,block"`
	RetryableErrors       []string `hcl:"retryable_errors,optional"`
	RetryMaxAttempts      *int     `hcl:"retry_max_attempts,optional"`
	RetrySleepIntervalSec *int     `hcl:"retry_sleep_interval_sec,optional"`
	Locals  *terragruntLocal          `hcl:"locals,block"`
	Include []terragruntIncludeIgnore `hcl:"include,block"`
}
type terragruntLocal struct {
	Remain hcl.Body `hcl:",remain"`
}
type terragruntIncludeIgnore struct {
	Name   string   `hcl:"name,label"`
	Remain hcl.Body `hcl:",remain"`
}
type remoteStateConfigFile struct {
	Backend                       string                     `hcl:"backend,attr"`
	DisableInit                   *bool                      `hcl:"disable_init,attr"`
	DisableDependencyOptimization *bool                      `hcl:"disable_dependency_optimization,attr"`
	Generate                      *remoteStateConfigGenerate `hcl:"generate,attr"`
	Config                        cty.Value                  `hcl:"config,attr"`
}
func (remoteState *remoteStateConfigFile) String() string {
	return fmt.Sprintf("remoteStateConfigFile{Backend = %v, Config = %v}", remoteState.Backend, remoteState.Config)
}
func (remoteState *remoteStateConfigFile) toConfig() (*remote.RemoteState, error) {
	remoteStateConfig, err := parseCtyValueToMap(remoteState.Config)
	if err != nil {
		return nil, err
	}
	config := &remote.RemoteState{}
	config.Backend = remoteState.Backend
	if remoteState.Generate != nil {
		config.Generate = &remote.RemoteStateGenerate{
			Path:     remoteState.Generate.Path,
			IfExists: remoteState.Generate.IfExists,
		}
	}
	config.Config = remoteStateConfig
	if remoteState.DisableInit != nil {
		config.DisableInit = *remoteState.DisableInit
	}
	if remoteState.DisableDependencyOptimization != nil {
		config.DisableDependencyOptimization = *remoteState.DisableDependencyOptimization
	}
	config.FillDefaults()
	if err := config.Validate(); err != nil {
		return nil, err
	}
	return config, err
}
type remoteStateConfigGenerate struct {
	Path     string `cty:"path"`
	IfExists string `cty:"if_exists"`
}
type terragruntGenerateBlock struct {
	Name             string  `hcl:",label"`
	Path             string  `hcl:"path,attr" mapstructure:"path"`
	IfExists         string  `hcl:"if_exists,attr" mapstructure:"if_exists"`
	CommentPrefix    *string `hcl:"comment_prefix,attr" mapstructure:"comment_prefix"`
	Contents         string  `hcl:"contents,attr" mapstructure:"contents"`
	DisableSignature *bool   `hcl:"disable_signature,attr" mapstructure:"disable_signature"`
}
type IncludeConfig struct {
	Name          string  `hcl:"name,label"`
	Path          string  `hcl:"path,attr"`
	Expose        *bool   `hcl:"expose,attr"`
	MergeStrategy *string `hcl:"merge_strategy,attr"`
}
func (cfg *IncludeConfig) String() string {
	return fmt.Sprintf("IncludeConfig{Path = %s, Expose = %v, MergeStrategy = %v}", cfg.Path, cfg.Expose, cfg.MergeStrategy)
}
func (cfg *IncludeConfig) GetExpose() bool {
	if cfg == nil || cfg.Expose == nil {
		return false
	}
	return *cfg.Expose
}
func (cfg *IncludeConfig) GetMergeStrategy() (MergeStrategyType, error) {
	if cfg.MergeStrategy == nil {
		return ShallowMerge, nil
	}
	strategy := *cfg.MergeStrategy
	switch strategy {
	case string(NoMerge):
		return NoMerge, nil
	case string(ShallowMerge):
		return ShallowMerge, nil
	case string(DeepMerge):
		return DeepMerge, nil
	default:
		return NoMerge, errors.WithStackTrace(InvalidMergeStrategyType(strategy))
	}
}
type MergeStrategyType string
const (
	NoMerge      MergeStrategyType = "no_merge"
	ShallowMerge MergeStrategyType = "shallow"
	DeepMerge    MergeStrategyType = "deep"
)
type ModuleDependencies struct {
	Paths []string `hcl:"paths,attr" cty:"paths"`
}
func (deps *ModuleDependencies) Merge(source *ModuleDependencies) {
	if source == nil {
		return
	}
	for _, path := range source.Paths {
		if !util.ListContainsElement(deps.Paths, path) {
			deps.Paths = append(deps.Paths, path)
		}
	}
}
func (deps *ModuleDependencies) String() string {
	return fmt.Sprintf("ModuleDependencies{Paths = %v}", deps.Paths)
}
type Hook struct {
	Name       string   `hcl:"name,label" cty:"name"`
	Commands   []string `hcl:"commands,attr" cty:"commands"`
	Execute    []string `hcl:"execute,attr" cty:"execute"`
	RunOnError *bool    `hcl:"run_on_error,attr" cty:"run_on_error"`
	WorkingDir *string  `hcl:"working_dir,attr" cty:"working_dir"`
}
func (conf *Hook) String() string {
	return fmt.Sprintf("Hook{Name = %s, Commands = %v}", conf.Name, len(conf.Commands))
}
type TerraformConfig struct {
	ExtraArgs   []TerraformExtraArguments `hcl:"extra_arguments,block"`
	Source      *string                   `hcl:"source,attr"`
	BeforeHooks []Hook                    `hcl:"before_hook,block"`
	AfterHooks  []Hook                    `hcl:"after_hook,block"`
}
func (conf *TerraformConfig) String() string {
	return fmt.Sprintf("TerraformConfig{Source = %v}", conf.Source)
}
func (conf *TerraformConfig) GetBeforeHooks() []Hook {
	if conf == nil {
		return nil
	}
	return conf.BeforeHooks
}
func (conf *TerraformConfig) GetAfterHooks() []Hook {
	if conf == nil {
		return nil
	}
	return conf.AfterHooks
}
func (conf *TerraformConfig) ValidateHooks() error {
	allHooks := append(conf.GetBeforeHooks(), conf.GetAfterHooks()...)
	for _, curHook := range allHooks {
		if len(curHook.Execute) < 1 || curHook.Execute[0] == "" {
			return InvalidArgError(fmt.Sprintf("Error with hook %s. Need at least one non-empty argument in 'execute'.", curHook.Name))
		}
	}
	return nil
}
type TerraformExtraArguments struct {
	Name             string             `hcl:"name,label" cty:"name"`
	Arguments        *[]string          `hcl:"arguments,attr" cty:"arguments"`
	RequiredVarFiles *[]string          `hcl:"required_var_files,attr" cty:"required_var_files"`
	OptionalVarFiles *[]string          `hcl:"optional_var_files,attr" cty:"optional_var_files"`
	Commands         []string           `hcl:"commands,attr" cty:"commands"`
	EnvVars          *map[string]string `hcl:"env_vars,attr" cty:"env_vars"`
}
func (conf *TerraformExtraArguments) String() string {
	return fmt.Sprintf(
		"TerraformArguments{Name = %s, Arguments = %v, Commands = %v, EnvVars = %v}",
		conf.Name,
		conf.Arguments,
		conf.Commands,
		conf.EnvVars)
}
func (conf *TerraformExtraArguments) GetVarFiles(logger *logrus.Entry) []string {
	varFiles := []string{}
	if conf.RequiredVarFiles != nil {
		for _, file := range util.RemoveDuplicatesFromListKeepLast(*conf.RequiredVarFiles) {
			varFiles = append(varFiles, file)
		}
	}
	if conf.OptionalVarFiles != nil {
		for _, file := range util.RemoveDuplicatesFromListKeepLast(*conf.OptionalVarFiles) {
			if util.FileExists(file) {
				varFiles = append(varFiles, file)
			} else {
				logger.Debugf("Skipping var-file %s as it does not exist", file)
			}
		}
	}
	return varFiles
}
func GetTerraformSourceUrl(terragruntOptions *options.TerragruntOptions, terragruntConfig *TerragruntConfig) (string, error) {
	if terragruntOptions.Source != "" {
		return terragruntOptions.Source, nil
	} else if terragruntConfig.Terraform != nil && terragruntConfig.Terraform.Source != nil {
		return adjustSourceWithMap(terragruntOptions.SourceMap, *terragruntConfig.Terraform.Source, terragruntOptions.OriginalTerragruntConfigPath)
	} else {
		return "", nil
	}
}
func adjustSourceWithMap(sourceMap map[string]string, source string, modulePath string) (string, error) {
	if len(sourceMap) == 0 {
		return source, nil
	}
	moduleUrl, moduleSubdir := getter.SourceDirSubdir(source)
	if moduleUrl == "" && moduleSubdir == "" {
		return "", errors.WithStackTrace(InvalidSourceUrlWithMap{ModulePath: modulePath, ModuleSourceUrl: source})
	}
	if moduleUrl == "" {
		return source, nil
	}
	moduleUrlParsed, err := url.Parse(moduleUrl)
	if err != nil {
		return source, err
	}
	moduleUrlParsed.RawQuery = ""
	moduleUrlQuery := moduleUrlParsed.String()
	sourcePath, hasKey := sourceMap[moduleUrlQuery]
	if hasKey == false {
		return source, nil
	}
	if moduleSubdir == "" {
		moduleSubdirFromUrl, err := getModulePathFromSourceUrl(moduleUrl)
		if err != nil {
			return moduleSubdirFromUrl, err
		}
		moduleSubdir = moduleSubdirFromUrl
	}
	return util.JoinTerraformModulePath(sourcePath, moduleSubdir), nil
}
func DefaultConfigPath(workingDir string) string {
	return util.JoinPath(workingDir, DefaultTerragruntConfigPath)
}
func DefaultJsonConfigPath(workingDir string) string {
	return util.JoinPath(workingDir, DefaultTerragruntJsonConfigPath)
}
func GetDefaultConfigPath(workingDir string) string {
	if util.FileNotExists(DefaultConfigPath(workingDir)) && util.FileExists(DefaultJsonConfigPath(workingDir)) {
		return DefaultJsonConfigPath(workingDir)
	}
	return DefaultConfigPath(workingDir)
}
func FindConfigFilesInPath(rootPath string, terragruntOptions *options.TerragruntOptions) ([]string, error) {
	configFiles := []string{}
	err := filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() && info.Name() == options.TerragruntCacheDir {
			return filepath.SkipDir
		}
		isTerragruntModule, err := containsTerragruntModule(path, info, terragruntOptions)
		if err != nil {
			return err
		}
		if isTerragruntModule {
			configFiles = append(configFiles, GetDefaultConfigPath(path))
		}
		return nil
	})
	return configFiles, err
}
func containsTerragruntModule(path string, info os.FileInfo, terragruntOptions *options.TerragruntOptions) (bool, error) {
	if !info.IsDir() {
		return false, nil
	}
	if util.ContainsPath(path, options.TerragruntCacheDir) {
		return false, nil
	}
	dataDir := terragruntOptions.TerraformDataDir()
	if filepath.IsAbs(dataDir) {
		if util.HasPathPrefix(path, dataDir) {
			return false, nil
		}
	} else {
		if util.ContainsPath(path, dataDir) {
			return false, nil
		}
	}
	canonicalPath, err := util.CanonicalPath(path, "")
	if err != nil {
		return false, err
	}
	canonicalDownloadPath, err := util.CanonicalPath(terragruntOptions.DownloadDir, "")
	if err != nil {
		return false, err
	}
	if strings.Contains(canonicalPath, canonicalDownloadPath) {
		return false, err
	}
	return util.FileExists(GetDefaultConfigPath(path)), nil
}
func ReadTerragruntConfig(terragruntOptions *options.TerragruntOptions) (*TerragruntConfig, error) {
	terragruntOptions.Logger.Debugf("Reading Terragrunt config file at %s", terragruntOptions.TerragruntConfigPath)
	return ParseConfigFile(terragruntOptions.TerragruntConfigPath, terragruntOptions, nil, nil)
}
func ParseConfigFile(filename string, terragruntOptions *options.TerragruntOptions, include *IncludeConfig, dependencyOutputs *cty.Value) (*TerragruntConfig, error) {
	configString, err := util.ReadFileAsString(filename)
	if err != nil {
		return nil, err
	}
	config, err := ParseConfigString(configString, terragruntOptions, include, filename, dependencyOutputs)
	if err != nil {
		return nil, err
	}
	return config, nil
}
func ParseConfigString(
	configString string,
	terragruntOptions *options.TerragruntOptions,
	includeFromChild *IncludeConfig,
	filename string,
	dependencyOutputs *cty.Value,
) (*TerragruntConfig, error) {
	parser := hclparse.NewParser()
	file, err := parseHcl(parser, configString, filename)
	if err != nil {
		return nil, err
	}
	if err := setIAMRole(configString, terragruntOptions, includeFromChild, filename); err != nil {
		return nil, err
	}
	localsAsCty, trackInclude, err := DecodeBaseBlocks(terragruntOptions, parser, file, filename, includeFromChild, nil)
	if err != nil {
		return nil, err
	}
	contextExtensions := EvalContextExtensions{
		Locals:              localsAsCty,
		TrackInclude:        trackInclude,
		DecodedDependencies: dependencyOutputs,
	}
	if dependencyOutputs == nil {
		retrievedOutputs, err := decodeAndRetrieveOutputs(file, filename, terragruntOptions, trackInclude, contextExtensions)
		if err != nil {
			return nil, err
		}
		contextExtensions.DecodedDependencies = retrievedOutputs
	}
	terragruntConfigFile, err := decodeAsTerragruntConfigFile(file, filename, terragruntOptions, contextExtensions)
	if err != nil {
		return nil, err
	}
	if terragruntConfigFile == nil {
		return nil, errors.WithStackTrace(CouldNotResolveTerragruntConfigInFile(filename))
	}
	config, err := convertToTerragruntConfig(terragruntConfigFile, filename, terragruntOptions, contextExtensions)
	if err != nil {
		return nil, err
	}
	if trackInclude != nil {
		config, err := handleInclude(config, trackInclude, terragruntOptions, contextExtensions.DecodedDependencies)
		if err != nil {
			return nil, err
		}
		config.ProcessedIncludes = trackInclude.CurrentMap
		return config, nil
	}
	return config, nil
}
func setIAMRole(configString string, terragruntOptions *options.TerragruntOptions, includeFromChild *IncludeConfig, filename string) error {
	iamConfig, err := PartialParseConfigString(configString, terragruntOptions, includeFromChild, filename, []PartialDecodeSectionType{TerragruntFlags})
	if err != nil {
		return err
	}
	terragruntOptions.IAMRoleOptions = options.MergeIAMRoleOptions(
		iamConfig.GetIAMRoleOptions(),
		terragruntOptions.OriginalIAMRoleOptions,
	)
	return nil
}
func decodeAsTerragruntConfigFile(
	file *hcl.File,
	filename string,
	terragruntOptions *options.TerragruntOptions,
	extensions EvalContextExtensions,
) (*terragruntConfigFile, error) {
	terragruntConfig := terragruntConfigFile{}
	err := decodeHcl(file, filename, &terragruntConfig, terragruntOptions, extensions)
	if err != nil {
		return nil, err
	}
	return &terragruntConfig, nil
}
func getIndexOfHookWithName(hooks []Hook, name string) int {
	for i, hook := range hooks {
		if hook.Name == name {
			return i
		}
	}
	return -1
}
func getIndexOfExtraArgsWithName(extraArgs []TerraformExtraArguments, name string) int {
	for i, extra := range extraArgs {
		if extra.Name == name {
			return i
		}
	}
	return -1
}
func convertToTerragruntConfig(
	terragruntConfigFromFile *terragruntConfigFile,
	configPath string,
	terragruntOptions *options.TerragruntOptions,
	contextExtensions EvalContextExtensions,
) (cfg *TerragruntConfig, err error) {
	defer func() {
		if recovered := recover(); recovered != nil {
			err = errors.WithStackTrace(PanicWhileParsingConfig{RecoveredValue: recovered, ConfigFile: configPath})
		}
	}()
	terragruntConfig := &TerragruntConfig{
		IsPartial: false,
		GenerateConfigs: map[string]codegen.GenerateConfig{},
	}
	if terragruntConfigFromFile.RemoteState != nil {
		remoteState, err := terragruntConfigFromFile.RemoteState.toConfig()
		if err != nil {
			return nil, err
		}
		terragruntConfig.RemoteState = remoteState
	}
	if terragruntConfigFromFile.RemoteStateAttr != nil {
		remoteStateMap, err := parseCtyValueToMap(*terragruntConfigFromFile.RemoteStateAttr)
		if err != nil {
			return nil, err
		}
		var remoteState *remote.RemoteState
		if err := mapstructure.Decode(remoteStateMap, &remoteState); err != nil {
			return nil, err
		}
		terragruntConfig.RemoteState = remoteState
	}
	if err := terragruntConfigFromFile.Terraform.ValidateHooks(); err != nil {
		return nil, err
	}
	terragruntConfig.Terraform = terragruntConfigFromFile.Terraform
	if err := validateDependencies(terragruntOptions, terragruntConfigFromFile.Dependencies); err != nil {
		return nil, err
	}
	terragruntConfig.Dependencies = terragruntConfigFromFile.Dependencies
	terragruntConfig.TerragruntDependencies = terragruntConfigFromFile.TerragruntDependencies
	if terragruntConfigFromFile.TerraformBinary != nil {
		terragruntConfig.TerraformBinary = *terragruntConfigFromFile.TerraformBinary
	}
	if terragruntConfigFromFile.RetryableErrors != nil {
		terragruntConfig.RetryableErrors = terragruntConfigFromFile.RetryableErrors
	}
	if terragruntConfigFromFile.RetryMaxAttempts != nil {
		terragruntConfig.RetryMaxAttempts = terragruntConfigFromFile.RetryMaxAttempts
	}
	if terragruntConfigFromFile.RetrySleepIntervalSec != nil {
		terragruntConfig.RetrySleepIntervalSec = terragruntConfigFromFile.RetrySleepIntervalSec
	}
	if terragruntConfigFromFile.DownloadDir != nil {
		terragruntConfig.DownloadDir = *terragruntConfigFromFile.DownloadDir
	}
	if terragruntConfigFromFile.TerraformVersionConstraint != nil {
		terragruntConfig.TerraformVersionConstraint = *terragruntConfigFromFile.TerraformVersionConstraint
	}
	if terragruntConfigFromFile.TerragruntVersionConstraint != nil {
		terragruntConfig.TerragruntVersionConstraint = *terragruntConfigFromFile.TerragruntVersionConstraint
	}
	if terragruntConfigFromFile.PreventDestroy != nil {
		terragruntConfig.PreventDestroy = terragruntConfigFromFile.PreventDestroy
	}
	if terragruntConfigFromFile.Skip != nil {
		terragruntConfig.Skip = *terragruntConfigFromFile.Skip
	}
	if terragruntConfigFromFile.IamRole != nil {
		terragruntConfig.IamRole = *terragruntConfigFromFile.IamRole
	}
	if terragruntConfigFromFile.IamAssumeRoleDuration != nil {
		terragruntConfig.IamAssumeRoleDuration = terragruntConfigFromFile.IamAssumeRoleDuration
	}
	if terragruntConfigFromFile.IamAssumeRoleSessionName != nil {
		terragruntConfig.IamAssumeRoleSessionName = *terragruntConfigFromFile.IamAssumeRoleSessionName
	}
	generateBlocks := []terragruntGenerateBlock{}
	generateBlocks = append(generateBlocks, terragruntConfigFromFile.GenerateBlocks...)
	if terragruntConfigFromFile.GenerateAttrs != nil {
		generateMap, err := parseCtyValueToMap(*terragruntConfigFromFile.GenerateAttrs)
		if err != nil {
			return nil, err
		}
		for name, block := range generateMap {
			var generateBlock terragruntGenerateBlock
			if err := mapstructure.Decode(block, &generateBlock); err != nil {
				return nil, err
			}
			generateBlock.Name = name
			generateBlocks = append(generateBlocks, generateBlock)
		}
	}
	if err := validateGenerateBlocks(&generateBlocks); err != nil {
		return nil, err
	}
	for _, block := range generateBlocks {
		ifExists, err := codegen.GenerateConfigExistsFromString(block.IfExists)
		if err != nil {
			return nil, err
		}
		genConfig := codegen.GenerateConfig{
			Path:        block.Path,
			IfExists:    ifExists,
			IfExistsStr: block.IfExists,
			Contents:    block.Contents,
		}
		if block.CommentPrefix == nil {
			genConfig.CommentPrefix = codegen.DefaultCommentPrefix
		} else {
			genConfig.CommentPrefix = *block.CommentPrefix
		}
		if block.DisableSignature == nil {
			genConfig.DisableSignature = false
		} else {
			genConfig.DisableSignature = *block.DisableSignature
		}
		terragruntConfig.GenerateConfigs[block.Name] = genConfig
	}
	if terragruntConfigFromFile.Inputs != nil {
		inputs, err := parseCtyValueToMap(*terragruntConfigFromFile.Inputs)
		if err != nil {
			return nil, err
		}
		terragruntConfig.Inputs = inputs
	}
	if contextExtensions.Locals != nil && *contextExtensions.Locals != cty.NilVal {
		localsParsed, err := parseCtyValueToMap(*contextExtensions.Locals)
		if err != nil {
			return nil, err
		}
		terragruntConfig.Locals = localsParsed
	}
	return terragruntConfig, nil
}
func validateDependencies(terragruntOptions *options.TerragruntOptions, dependencies *ModuleDependencies) error {
	var missingDependencies []string
	if dependencies == nil {
		return nil
	}
	for _, dependencyPath := range dependencies.Paths {
		fullPath := filepath.FromSlash(dependencyPath)
		if !filepath.IsAbs(fullPath) {
			fullPath = path.Join(terragruntOptions.WorkingDir, fullPath)
		}
		if !util.IsDir(fullPath) {
			missingDependencies = append(missingDependencies, fmt.Sprintf("%s (%s)", dependencyPath, fullPath))
		}
	}
	if len(missingDependencies) > 0 {
		return DependencyDirNotFound{missingDependencies}
	}
	return nil
}
func validateGenerateBlocks(blocks *[]terragruntGenerateBlock) error {
	var blockNames = map[string]bool{}
	var duplicatedGenerateBlockNames []string
	for _, block := range *blocks {
		_, found := blockNames[block.Name]
		if found {
			duplicatedGenerateBlockNames = append(duplicatedGenerateBlockNames, block.Name)
			continue
		}
		blockNames[block.Name] = true
	}
	if len(duplicatedGenerateBlockNames) != 0 {
		return DuplicatedGenerateBlocks{duplicatedGenerateBlockNames}
	}
	return nil
}