func runActionWithHooks(description string, terragruntOptions *options.TerragruntOptions, terragruntConfig *config.TerragruntConfig, action func() error) error {
	var allErrors *multierror.Error
	beforeHookErrors := processHooks(terragruntConfig.Terraform.GetBeforeHooks(), terragruntOptions, allErrors)
	allErrors = multierror.Append(allErrors, beforeHookErrors)
	var actionErrors error
	if beforeHookErrors == nil {
		actionErrors = action()
		allErrors = multierror.Append(allErrors, actionErrors)
	} else {
		terragruntOptions.Logger.Errorf("Errors encountered running before_hooks. Not running '%s'.", description)
	}
	postHookErrors := processHooks(terragruntConfig.Terraform.GetAfterHooks(), terragruntOptions, allErrors)
	allErrors = multierror.Append(allErrors, postHookErrors)
	return allErrors.ErrorOrNil()
}
Run the given action function surrounded by hooks. That is, run the before hooks first, then, if there were no
errors, run the action, and finally, run the after hooks. Return any errors hit from the hooks or action.
package cli
import (
	"encoding/json"
	"fmt"
	"io"
	"regexp"
	"strings"
	"time"
	"github.com/hashicorp/go-multierror"
	"github.com/mattn/go-zglob"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli"
	"github.com/gruntwork-io/terragrunt/aws_helper"
	"github.com/gruntwork-io/terragrunt/cli/tfsource"
	"github.com/gruntwork-io/terragrunt/codegen"
	"github.com/gruntwork-io/terragrunt/config"
	"github.com/gruntwork-io/terragrunt/configstack"
	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/options"
	"github.com/gruntwork-io/terragrunt/remote"
	"github.com/gruntwork-io/terragrunt/shell"
	"github.com/gruntwork-io/terragrunt/util"
)
const (
	optTerragruntConfig                      = "terragrunt-config"
	optTerragruntTFPath                      = "terragrunt-tfpath"
	optTerragruntNoAutoInit                  = "terragrunt-no-auto-init"
	optTerragruntNoAutoRetry                 = "terragrunt-no-auto-retry"
	optNonInteractive                        = "terragrunt-non-interactive"
	optWorkingDir                            = "terragrunt-working-dir"
	optDownloadDir                           = "terragrunt-download-dir"
	optTerragruntSource                      = "terragrunt-source"
	optTerragruntSourceMap                   = "terragrunt-source-map"
	optTerragruntSourceUpdate                = "terragrunt-source-update"
	optTerragruntIAMRole                     = "terragrunt-iam-role"
	optTerragruntIAMAssumeRoleDuration       = "terragrunt-iam-assume-role-duration"
	optTerragruntIAMAssumeRoleSessionName    = "terragrunt-iam-assume-role-session-name"
	optTerragruntIgnoreDependencyErrors      = "terragrunt-ignore-dependency-errors"
	optTerragruntIgnoreDependencyOrder       = "terragrunt-ignore-dependency-order"
	optTerragruntIgnoreExternalDependencies  = "terragrunt-ignore-external-dependencies"
	optTerragruntIncludeExternalDependencies = "terragrunt-include-external-dependencies"
	optTerragruntExcludeDir                  = "terragrunt-exclude-dir"
	optTerragruntIncludeDir                  = "terragrunt-include-dir"
	optTerragruntStrictInclude               = "terragrunt-strict-include"
	optTerragruntParallelism                 = "terragrunt-parallelism"
	optTerragruntCheck                       = "terragrunt-check"
	optTerragruntHCLFmt                      = "terragrunt-hclfmt-file"
	optTerragruntDebug                       = "terragrunt-debug"
	optTerragruntOverrideAttr                = "terragrunt-override-attr"
	optTerragruntLogLevel                    = "terragrunt-log-level"
	optTerragruntStrictValidate              = "terragrunt-strict-validate"
	optTerragruntJSONOut                     = "terragrunt-json-out"
)
var allTerragruntBooleanOpts = []string{
	optNonInteractive,
	optTerragruntSourceUpdate,
	optTerragruntIgnoreDependencyErrors,
	optTerragruntIgnoreDependencyOrder,
	optTerragruntIgnoreExternalDependencies,
	optTerragruntIncludeExternalDependencies,
	optTerragruntNoAutoInit,
	optTerragruntNoAutoRetry,
	optTerragruntCheck,
	optTerragruntStrictInclude,
	optTerragruntDebug,
}
var allTerragruntStringOpts = []string{
	optTerragruntConfig,
	optTerragruntTFPath,
	optWorkingDir,
	optDownloadDir,
	optTerragruntSource,
	optTerragruntSourceMap,
	optTerragruntIAMRole,
	optTerragruntIAMAssumeRoleDuration,
	optTerragruntIAMAssumeRoleSessionName,
	optTerragruntExcludeDir,
	optTerragruntIncludeDir,
	optTerragruntParallelism,
	optTerragruntHCLFmt,
	optTerragruntOverrideAttr,
	optTerragruntLogLevel,
	optTerragruntStrictValidate,
	optTerragruntJSONOut,
}
const CMD_INIT = "init"
const CMD_INIT_FROM_MODULE = "init-from-module"
const CMD_PROVIDERS = "providers"
const CMD_LOCK = "lock"
const CMD_TERRAGRUNT_INFO = "terragrunt-info"
const CMD_TERRAGRUNT_VALIDATE_INPUTS = "validate-inputs"
const CMD_TERRAGRUNT_GRAPH_DEPENDENCIES = "graph-dependencies"
const CMD_TERRAGRUNT_READ_CONFIG = "terragrunt-read-config"
const CMD_HCLFMT = "hclfmt"
const CMD_AWS_PROVIDER_PATCH = "aws-provider-patch"
const CMD_RENDER_JSON = "render-json"
const CMD_RUN_ALL = "run-all"
var runAllDisabledCommands = map[string]string{
	"import":       "terraform import should only be run against a single state representation to avoid injecting the wrong object in the wrong state representation.",
	"taint":        "terraform taint should only be run against a single state representation to avoid using the wrong state address.",
	"untaint":      "terraform untaint should only be run against a single state representation to avoid using the wrong state address.",
	"console":      "terraform console requires stdin, which is shared across all instances of run-all when multiple modules run concurrently.",
	"force-unlock": "lock IDs are unique per state representation and thus should not be run with run-all.",
}
var MULTI_MODULE_COMMANDS = []string{
	CMD_RUN_ALL,
	CMD_APPLY_ALL,
	CMD_DESTROY_ALL,
	CMD_OUTPUT_ALL,
	CMD_PLAN_ALL,
	CMD_VALIDATE_ALL,
}
const (
	CMD_SPIN_UP      = "spin-up"
	CMD_TEAR_DOWN    = "tear-down"
	CMD_PLAN_ALL     = "plan-all"
	CMD_APPLY_ALL    = "apply-all"
	CMD_DESTROY_ALL  = "destroy-all"
	CMD_OUTPUT_ALL   = "output-all"
	CMD_VALIDATE_ALL = "validate-all"
)
var deprecatedCommands = map[string]func(origOptions *options.TerragruntOptions) (*options.TerragruntOptions, string, string){
	CMD_SPIN_UP:      spinUpDeprecationHandler,
	CMD_TEAR_DOWN:    tearDownDeprecationHandler,
	CMD_APPLY_ALL:    applyAllDeprecationHandler,
	CMD_DESTROY_ALL:  destroyAllDeprecationHandler,
	CMD_PLAN_ALL:     planAllDeprecationHandler,
	CMD_VALIDATE_ALL: validateAllDeprecationHandler,
	CMD_OUTPUT_ALL:   outputAllDeprecationHandler,
}
var TERRAFORM_COMMANDS_THAT_USE_STATE = []string{
	"init",
	"apply",
	"destroy",
	"env",
	"import",
	"graph",
	"output",
	"plan",
	"push",
	"refresh",
	"show",
	"taint",
	"untaint",
	"validate",
	"force-unlock",
	"state",
}
var TERRAFORM_COMMANDS_THAT_DO_NOT_NEED_INIT = []string{
	"version",
	"terragrunt-info",
	"graph-dependencies",
}
var DEPRECATED_ARGUMENTS = map[string]string{}
type TerragruntInfoGroup struct {
	ConfigPath       string
	DownloadDir      string
	IamRole          string
	TerraformBinary  string
	TerraformCommand string
	WorkingDir       string
}
var CUSTOM_USAGE_TEXT = `DESCRIPTION:
   {{.Name}} - {{.UsageText}}
USAGE:
   {{.Usage}}
COMMANDS:
   run-all               Run a terraform command against a 'stack' by running the specified command in each subfolder. E.g., to run 'terragrunt apply' in each subfolder, use 'terragrunt run-all apply'.
   terragrunt-info       Emits limited terragrunt state on stdout and exits
   validate-inputs       Checks if the terragrunt configured inputs align with the terraform defined variables.
   graph-dependencies    Prints the terragrunt dependency graph to stdout
   hclfmt                Recursively find hcl files and rewrite them into a canonical format.
   aws-provider-patch    Overwrite settings on nested AWS providers to work around a Terraform bug (issue #13018)
   render-json           Render the final terragrunt config, with all variables, includes, and functions resolved, as json. This is useful for enforcing policies using static analysis tools like Open Policy Agent, or for debugging your terragrunt config.
   *                     Terragrunt forwards all other commands directly to Terraform
GLOBAL OPTIONS:
   terragrunt-config                            Path to the Terragrunt config file. Default is terragrunt.hcl.
   terragrunt-tfpath                            Path to the Terraform binary. Default is terraform (on PATH).
   terragrunt-no-auto-init                      Don't automatically run 'terraform init' during other terragrunt commands. You must run 'terragrunt init' manually.
   terragrunt-no-auto-retry                     Don't automatically re-run command in case of transient errors.
   terragrunt-non-interactive                   Assume "yes" for all prompts.
   terragrunt-working-dir                       The path to the Terraform templates. Default is current directory.
   terragrunt-download-dir                      The path where to download Terraform code. Default is .terragrunt-cache in the working directory.
   terragrunt-source                            Download Terraform configurations from the specified source into a temporary folder, and run Terraform in that temporary folder.
   terragrunt-source-update                     Delete the contents of the temporary folder to clear out any old, cached source code before downloading new source code into it.
   terragrunt-iam-role                          Assume the specified IAM role before executing Terraform. Can also be set via the TERRAGRUNT_IAM_ROLE environment variable.
   terragrunt-iam-assume-role-duration          Session duration for IAM Assume Role session. Can also be set via the TERRAGRUNT_IAM_ASSUME_ROLE_DURATION environment variable.
   terragrunt-iam-assume-role-session-name      Name for the IAM Assummed Role session. Can also be set via TERRAGRUNT_IAM_ASSUME_ROLE_SESSION_NAME environment variable.
   terragrunt-ignore-dependency-errors          *-all commands continue processing components even if a dependency fails.
   terragrunt-ignore-dependency-order           *-all commands will be run disregarding the dependencies
   terragrunt-ignore-external-dependencies      *-all commands will not attempt to include external dependencies
   terragrunt-include-external-dependencies     *-all commands will include external dependencies
   terragrunt-parallelism <N>                   *-all commands parallelism set to at most N modules
   terragrunt-exclude-dir                       Unix-style glob of directories to exclude when running *-all commands
   terragrunt-include-dir                       Unix-style glob of directories to include when running *-all commands
   terragrunt-check                             Enable check mode in the hclfmt command.
   terragrunt-hclfmt-file                       The path to a single hcl file that the hclfmt command should run on.
   terragrunt-override-attr                     A key=value attribute to override in a provider block as part of the aws-provider-patch command. May be specified multiple times.
   terragrunt-debug                             Write terragrunt-debug.tfvars to working folder to help root-cause issues.
   terragrunt-log-level                         Sets the logging level for Terragrunt. Supported levels: panic, fatal, error, warn (default), info, debug, trace.
   terragrunt-strict-validate                   Sets strict mode for the validate-inputs command. By default, strict mode is off. When this flag is passed, strict mode is turned on. When strict mode is turned off, the validate-inputs command will only return an error if required inputs are missing from all input sources (env vars, var files, etc). When strict mode is turned on, an error will be returned if required inputs are missing OR if unused variables are passed to Terragrunt.
   terragrunt-json-out                          The file path that terragrunt should use when rendering the terragrunt.hcl config as json. Only used in the render-json command. Defaults to terragrunt_rendered.json.
VERSION:
   {{.Version}}{{if len .Authors}}
AUTHOR(S):
   {{range .Authors}}{{.}}{{end}}
   {{end}}
`
var MODULE_REGEX = regexp.MustCompile(`module[[:blank:]]+".+"`)
const DEFAULT_TERRAFORM_VERSION_CONSTRAINT = ">= v0.12.0"
const TERRAFORM_EXTENSION_GLOB = "*.tf"
const TFVarPrefix = "TF_VAR"
var TERRAFORM_HELP_FLAGS = []string{
	"--help",
	"-help",
	"-h",
}
func CreateTerragruntCli(version string, writer io.Writer, errwriter io.Writer) *cli.App {
	cli.OsExiter = func(exitCode int) {
	}
	cli.AppHelpTemplate = CUSTOM_USAGE_TEXT
	app := cli.NewApp()
	app.Name = "terragrunt"
	app.Author = "Gruntwork <www.gruntwork.io>"
	app.Version = version
	app.Action = runApp
	app.Usage = "terragrunt <COMMAND> [GLOBAL OPTIONS]"
	app.Writer = writer
	app.ErrWriter = errwriter
	app.UsageText = `Terragrunt is a thin wrapper for Terraform that provides extra tools for working with multiple
   Terraform modules, remote state, and locking. For documentation, see https: 
	return app
}
func runApp(cliContext *cli.Context) (finalErr error) {
	defer errors.Recover(func(cause error) { finalErr = cause })
	if !cliContext.Args().Present() {
		return cli.ShowAppHelp(cliContext)
	}
	terragruntOptions, err := ParseTerragruntOptions(cliContext)
	if err != nil {
		return err
	}
	shell.PrepareConsole(terragruntOptions)
	givenCommand := cliContext.Args().First()
	newOptions, command := checkDeprecated(givenCommand, terragruntOptions)
	return runCommand(command, newOptions)
}
func checkDeprecated(command string, terragruntOptions *options.TerragruntOptions) (*options.TerragruntOptions, string) {
	deprecationHandler, deprecated := deprecatedCommands[command]
	if deprecated {
		newOptions, newCommand, newCommandFriendly := deprecationHandler(terragruntOptions)
		terragruntOptions.Logger.Warnf(
			"'%s' is deprecated. Running '%s' instead. Please update your workflows to use '%s', as '%s' may be removed in the future!\n",
			command,
			newCommandFriendly,
			newCommandFriendly,
			command,
		)
		return newOptions, newCommand
	}
	return terragruntOptions, command
}
func runCommand(command string, terragruntOptions *options.TerragruntOptions) (finalEff error) {
	if command == CMD_RUN_ALL {
		return runAll(terragruntOptions)
	}
	if command == "destroy" {
		terragruntOptions.CheckDependentModules = true
	}
	return RunTerragrunt(terragruntOptions)
}
func RunTerragrunt(terragruntOptions *options.TerragruntOptions) error {
	if shouldPrintTerraformHelp(terragruntOptions) {
		return shell.RunTerraformCommand(terragruntOptions, terragruntOptions.TerraformCliArgs...)
	}
	if shouldRunHCLFmt(terragruntOptions) {
		return runHCLFmt(terragruntOptions)
	}
	if shouldRunGraphDependencies(terragruntOptions) {
		return runGraphDependencies(terragruntOptions)
	}
	if err := checkVersionConstraints(terragruntOptions); err != nil {
		return err
	}
	terragruntConfig, err := config.ReadTerragruntConfig(terragruntOptions)
	if err != nil {
		return err
	}
	if shouldRunRenderJSON(terragruntOptions) {
		return runRenderJSON(terragruntOptions, terragruntConfig)
	}
	terragruntOptionsClone := terragruntOptions.Clone(terragruntOptions.TerragruntConfigPath)
	terragruntOptionsClone.TerraformCommand = CMD_TERRAGRUNT_READ_CONFIG
	if err := processHooks(terragruntConfig.Terraform.GetAfterHooks(), terragruntOptionsClone, nil); err != nil {
		return err
	}
	if terragruntConfig.Skip {
		terragruntOptions.Logger.Infof(
			"Skipping terragrunt module %s due to skip = true.",
			terragruntOptions.TerragruntConfigPath,
		)
		return nil
	}
	terragruntOptions.IAMRoleOptions = options.MergeIAMRoleOptions(
		terragruntConfig.GetIAMRoleOptions(),
		terragruntOptions.OriginalIAMRoleOptions,
	)
	if err := aws_helper.AssumeRoleAndUpdateEnvIfNecessary(terragruntOptions); err != nil {
		return err
	}
	_, defaultDownloadDir, err := options.DefaultWorkingAndDownloadDirs(terragruntOptions.TerragruntConfigPath)
	if err != nil {
		return err
	}
	if terragruntOptions.DownloadDir == defaultDownloadDir && terragruntConfig.DownloadDir != "" {
		terragruntOptions.DownloadDir = terragruntConfig.DownloadDir
	}
	if terragruntConfig.RetryableErrors != nil {
		terragruntOptions.RetryableErrors = terragruntConfig.RetryableErrors
	}
	if terragruntConfig.RetryMaxAttempts != nil {
		if *terragruntConfig.RetryMaxAttempts < 1 {
			return fmt.Errorf("Cannot have less than 1 max retry, but you specified %d", *terragruntConfig.RetryMaxAttempts)
		}
		terragruntOptions.RetryMaxAttempts = *terragruntConfig.RetryMaxAttempts
	}
	if terragruntConfig.RetrySleepIntervalSec != nil {
		if *terragruntConfig.RetrySleepIntervalSec < 0 {
			return fmt.Errorf("Cannot sleep for less than 0 seconds, but you specified %d", *terragruntConfig.RetrySleepIntervalSec)
		}
		terragruntOptions.RetrySleepIntervalSec = time.Duration(*terragruntConfig.RetrySleepIntervalSec) * time.Second
	}
	updatedTerragruntOptions := terragruntOptions
	sourceUrl, err := config.GetTerraformSourceUrl(terragruntOptions, terragruntConfig)
	if err != nil {
		return err
	}
	if sourceUrl != "" {
		updatedTerragruntOptions, err = downloadTerraformSource(sourceUrl, terragruntOptions, terragruntConfig)
		if err != nil {
			return err
		}
	}
	if shouldPrintTerragruntInfo(updatedTerragruntOptions) {
		group := TerragruntInfoGroup{
			ConfigPath:       updatedTerragruntOptions.TerragruntConfigPath,
			DownloadDir:      updatedTerragruntOptions.DownloadDir,
			IamRole:          updatedTerragruntOptions.IAMRoleOptions.RoleARN,
			TerraformBinary:  updatedTerragruntOptions.TerraformPath,
			TerraformCommand: updatedTerragruntOptions.TerraformCommand,
			WorkingDir:       updatedTerragruntOptions.WorkingDir,
		}
		b, err := json.MarshalIndent(group, "", "  ")
		if err != nil {
			updatedTerragruntOptions.Logger.Errorf("JSON error marshalling terragrunt-info")
			return err
		}
		fmt.Fprintf(updatedTerragruntOptions.Writer, "%s\n", b)
		return nil
	}
	for _, config := range terragruntConfig.GenerateConfigs {
		if err := codegen.WriteToFile(updatedTerragruntOptions, updatedTerragruntOptions.WorkingDir, config); err != nil {
			return err
		}
	}
	if terragruntConfig.RemoteState != nil && terragruntConfig.RemoteState.Generate != nil {
		if err := terragruntConfig.RemoteState.GenerateTerraformCode(updatedTerragruntOptions); err != nil {
			return err
		}
	} else if terragruntConfig.RemoteState != nil {
		if err := checkTerraformCodeDefinesBackend(updatedTerragruntOptions, terragruntConfig.RemoteState.Backend); err != nil {
			return err
		}
	}
	if shouldValidateTerragruntInputs(updatedTerragruntOptions) {
		return validateTerragruntInputs(updatedTerragruntOptions, terragruntConfig)
	}
	if updatedTerragruntOptions.Debug {
		err := writeTerragruntDebugFile(updatedTerragruntOptions, terragruntConfig)
		if err != nil {
			return err
		}
	}
	if err := checkFolderContainsTerraformCode(updatedTerragruntOptions); err != nil {
		return err
	}
	if terragruntOptions.CheckDependentModules {
		allowDestroy := confirmActionWithDependentModules(terragruntOptions, terragruntConfig)
		if !allowDestroy {
			return nil
		}
	}
	return runTerragruntWithConfig(terragruntOptions, updatedTerragruntOptions, terragruntConfig, false)
}
func checkVersionConstraints(terragruntOptions *options.TerragruntOptions) error {
	partialTerragruntConfig, err := config.PartialParseConfigFile(
		terragruntOptions.TerragruntConfigPath,
		terragruntOptions,
		nil,
		[]config.PartialDecodeSectionType{config.TerragruntVersionConstraints},
	)
	if err != nil {
		return err
	}
	if terragruntOptions.TerraformPath == options.TERRAFORM_DEFAULT_PATH && partialTerragruntConfig.TerraformBinary != "" {
		terragruntOptions.TerraformPath = partialTerragruntConfig.TerraformBinary
	}
	if err := PopulateTerraformVersion(terragruntOptions); err != nil {
		return err
	}
	terraformVersionConstraint := DEFAULT_TERRAFORM_VERSION_CONSTRAINT
	if partialTerragruntConfig.TerraformVersionConstraint != "" {
		terraformVersionConstraint = partialTerragruntConfig.TerraformVersionConstraint
	}
	if err := CheckTerraformVersion(terraformVersionConstraint, terragruntOptions); err != nil {
		return err
	}
	if partialTerragruntConfig.TerragruntVersionConstraint != "" {
		if err := CheckTerragruntVersion(partialTerragruntConfig.TerragruntVersionConstraint, terragruntOptions); err != nil {
			return err
		}
	}
	return nil
}
func runGraphDependencies(terragruntOptions *options.TerragruntOptions) error {
	stack, err := configstack.FindStackInSubfolders(terragruntOptions)
	if err != nil {
		return err
	}
	stack.Graph(terragruntOptions)
	return nil
}
func shouldPrintTerraformHelp(terragruntOptions *options.TerragruntOptions) bool {
	for _, tfHelpFlag := range TERRAFORM_HELP_FLAGS {
		if util.ListContainsElement(terragruntOptions.TerraformCliArgs, tfHelpFlag) {
			return true
		}
	}
	return false
}
func shouldRunGraphDependencies(terragruntOptions *options.TerragruntOptions) bool {
	return util.ListContainsElement(terragruntOptions.TerraformCliArgs, CMD_TERRAGRUNT_GRAPH_DEPENDENCIES)
}
func shouldPrintTerragruntInfo(terragruntOptions *options.TerragruntOptions) bool {
	return util.ListContainsElement(terragruntOptions.TerraformCliArgs, CMD_TERRAGRUNT_INFO)
}
func shouldValidateTerragruntInputs(terragruntOptions *options.TerragruntOptions) bool {
	return util.ListContainsElement(terragruntOptions.TerraformCliArgs, CMD_TERRAGRUNT_VALIDATE_INPUTS)
}
func shouldRunHCLFmt(terragruntOptions *options.TerragruntOptions) bool {
	return util.ListContainsElement(terragruntOptions.TerraformCliArgs, CMD_HCLFMT)
}
func shouldRunRenderJSON(terragruntOptions *options.TerragruntOptions) bool {
	return util.ListContainsElement(terragruntOptions.TerraformCliArgs, CMD_RENDER_JSON)
}
func shouldApplyAwsProviderPatch(terragruntOptions *options.TerragruntOptions) bool {
	return util.ListContainsElement(terragruntOptions.TerraformCliArgs, CMD_AWS_PROVIDER_PATCH)
}
func processHooks(hooks []config.Hook, terragruntOptions *options.TerragruntOptions, previousExecErrors *multierror.Error) error {
	if len(hooks) == 0 {
		return nil
	}
	var errorsOccured *multierror.Error
	terragruntOptions.Logger.Debugf("Detected %d Hooks", len(hooks))
	for _, curHook := range hooks {
		allPreviousErrors := multierror.Append(previousExecErrors, errorsOccured)
		if shouldRunHook(curHook, terragruntOptions, allPreviousErrors) {
			terragruntOptions.Logger.Infof("Executing hook: %s", curHook.Name)
			workingDir := ""
			if curHook.WorkingDir != nil {
				workingDir = *curHook.WorkingDir
			}
			actionToExecute := curHook.Execute[0]
			actionParams := curHook.Execute[1:]
			_, possibleError := shell.RunShellCommandWithOutput(
				terragruntOptions,
				workingDir,
				false,
				false,
				actionToExecute, actionParams...,
			)
			if possibleError != nil {
				terragruntOptions.Logger.Errorf("Error running hook %s with message: %s", curHook.Name, possibleError.Error())
				errorsOccured = multierror.Append(errorsOccured, possibleError)
			}
		}
	}
	return errorsOccured.ErrorOrNil()
}
func shouldRunHook(hook config.Hook, terragruntOptions *options.TerragruntOptions, previousExecErrors *multierror.Error) bool {
	hasErrors := previousExecErrors.ErrorOrNil() != nil
	isCommandInHook := util.ListContainsElement(hook.Commands, terragruntOptions.TerraformCommand)
	return isCommandInHook && (!hasErrors || (hook.RunOnError != nil && *hook.RunOnError))
}
func runTerragruntWithConfig(originalTerragruntOptions *options.TerragruntOptions, terragruntOptions *options.TerragruntOptions, terragruntConfig *config.TerragruntConfig, allowSourceDownload bool) error {
	if terragruntConfig.Terraform != nil && terragruntConfig.Terraform.ExtraArgs != nil && len(terragruntConfig.Terraform.ExtraArgs) > 0 {
		args := filterTerraformExtraArgs(terragruntOptions, terragruntConfig)
		terragruntOptions.InsertTerraformCliArgs(args...)
		for k, v := range filterTerraformEnvVarsFromExtraArgs(terragruntOptions, terragruntConfig) {
			terragruntOptions.Env[k] = v
		}
	}
	if err := setTerragruntInputsAsEnvVars(terragruntOptions, terragruntConfig); err != nil {
		return err
	}
	if util.FirstArg(terragruntOptions.TerraformCliArgs) == CMD_INIT {
		if err := prepareInitCommand(terragruntOptions, terragruntConfig, allowSourceDownload); err != nil {
			return err
		}
	} else {
		if err := prepareNonInitCommand(originalTerragruntOptions, terragruntOptions, terragruntConfig); err != nil {
			return err
		}
	}
	if shouldApplyAwsProviderPatch(terragruntOptions) {
		return applyAwsProviderPatch(terragruntOptions)
	}
	if err := checkProtectedModule(terragruntOptions, terragruntConfig); err != nil {
		return err
	}
	return runActionWithHooks("terraform", terragruntOptions, terragruntConfig, func() error {
		runTerraformError := runTerraformWithRetry(terragruntOptions)
		var lockFileError error
		if shouldCopyLockFile(terragruntOptions.TerraformCliArgs) {
			lockFileError = copyLockFile(terragruntOptions.WorkingDir, originalTerragruntOptions.WorkingDir, terragruntOptions.Logger)
		}
		return multierror.Append(runTerraformError, lockFileError).ErrorOrNil()
	})
}
func confirmActionWithDependentModules(terragruntOptions *options.TerragruntOptions, terragruntConfig *config.TerragruntConfig) bool {
	modules, err := configstack.FindWhereWorkingDirIsIncluded(terragruntOptions, terragruntConfig)
	if err != nil {
		terragruntOptions.Logger.Warnf("Failed to detect where module is used %v", err)
		return true
	}
	if len(modules) != 0 {
		if _, err := terragruntOptions.ErrWriter.Write([]byte("Detected dependent modules:\n")); err != nil {
			terragruntOptions.Logger.Error(err)
			return false
		}
		for _, module := range modules {
			if _, err := terragruntOptions.ErrWriter.Write([]byte(fmt.Sprintf("%s\n", module.Path))); err != nil {
				terragruntOptions.Logger.Error(err)
				return false
			}
		}
		prompt := "WARNING: Are you sure you want to continue?"
		shouldRun, err := shell.PromptUserForYesNo(prompt, terragruntOptions)
		if err != nil {
			terragruntOptions.Logger.Error(err)
			return false
		}
		return shouldRun
	}
	return true
}
func shouldCopyLockFile(args []string) bool {
	if util.FirstArg(args) == CMD_INIT {
		return true
	}
	if util.FirstArg(args) == CMD_PROVIDERS && util.SecondArg(args) == CMD_LOCK {
		return true
	}
	return false
}
func copyLockFile(sourceFolder string, destinationFolder string, logger *logrus.Entry) error {
	sourceLockFilePath := util.JoinPath(sourceFolder, util.TerraformLockFile)
	destinationLockFilePath := util.JoinPath(destinationFolder, util.TerraformLockFile)
	if util.FileExists(sourceLockFilePath) {
		logger.Debugf("Copying lock file from %s to %s", sourceLockFilePath, destinationFolder)
		return util.CopyFile(sourceLockFilePath, destinationLockFilePath)
	}
	return nil
}