forked from gruntwork-io/terragrunt
-
Notifications
You must be signed in to change notification settings - Fork 2
/
extension_hook.go
134 lines (110 loc) · 4.4 KB
/
extension_hook.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package config
import (
"fmt"
"os"
"sort"
"strings"
"github.com/coveo/gotemplate/utils"
"github.com/gruntwork-io/terragrunt/options"
"github.com/gruntwork-io/terragrunt/shell"
"github.com/gruntwork-io/terragrunt/util"
)
// Hook is a definition of user command that should be executed as part of the terragrunt process
type Hook struct {
TerragruntExtensionBase `hcl:",squash"`
Command string `hcl:"command"`
Arguments []string `hcl:"arguments"`
ExpandArgs bool `hcl:"expand_args"`
OnCommands []string `hcl:"on_commands"`
IgnoreError bool `hcl:"ignore_error"`
BeforeImports bool `hcl:"before_imports"`
AfterInitState bool `hcl:"after_init_state"`
Order int `hcl:"order"`
ShellCommand bool `hcl:"shell_command"` // This indicates that the command is a shell command and output should not be redirected
}
func (hook Hook) itemType() (result string) { return HookList{}.argName() }
func (hook Hook) ignoreError() bool { return hook.IgnoreError }
func (hook Hook) help() (result string) {
if hook.Description != "" {
result += fmt.Sprintf("\n%s\n", hook.Description)
}
result += fmt.Sprintf("\nCommand: %s %s\n", hook.Command, strings.Join(hook.Arguments, " "))
if hook.OnCommands != nil {
result += fmt.Sprintf("\nApplies on the following command(s): %s\n", strings.Join(hook.OnCommands, ", "))
}
if hook.OS != nil {
result += fmt.Sprintf("\nApplied only on the following OS: %s\n", strings.Join(hook.OS, ", "))
}
attributes := []string{
fmt.Sprintf("Order = %d", hook.Order),
fmt.Sprintf("Expand arguments = %v", hook.ExpandArgs),
fmt.Sprintf("Ignore error = %v", hook.IgnoreError),
}
result += fmt.Sprintf("\n%s\n", strings.Join(attributes, ", "))
return
}
func (hook *Hook) run(args ...interface{}) (result []interface{}, err error) {
logger := hook.logger()
if len(hook.OnCommands) > 0 && !util.ListContainsElement(hook.OnCommands, hook.options().Env[options.EnvCommand]) {
// The current command is not in the list of command on which the hook should be applied
return
}
if !hook.enabled() {
logger.Debugf("Hook %s skipped, executed only on %v", hook.Name, hook.OS)
return
}
hook.Command = strings.TrimSpace(hook.Command)
if len(hook.Command) == 0 {
logger.Debugf("Hook %s skipped, no command to execute", hook.Name)
return
}
cmd := shell.NewCmd(hook.options(), hook.Command).Args(hook.Arguments...)
if hook.ShellCommand {
// We must not redirect the stderr on shell command, doing so, remove the prompt
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
}
if hook.ExpandArgs {
cmd = cmd.ExpandArgs()
}
if !utils.IsCommand(hook.Command) {
cmd.DisplayCommand = fmt.Sprintf("%s %s", hook.name(), strings.Join(hook.Arguments, " "))
}
if shouldBeApproved, approvalConfig := hook.config().ApprovalConfig.ShouldBeApproved(hook.Command); shouldBeApproved {
cmd = cmd.Expect(approvalConfig.ExpectStatements, approvalConfig.CompletedStatements)
}
err = cmd.Run()
return
}
// ----------------------- HookList -----------------------
//go:generate genny -in=extension_base_list.go -out=generated_hooks.go gen "GenericItem=Hook"
func (list HookList) argName() string { return "hooks" }
func (list HookList) sort() HookList {
sort.SliceStable(list, func(i, j int) bool { return list[i].Order < list[j].Order })
return list
}
// MergePrepend prepends elements from an imported list to the current list
func (list *HookList) MergePrepend(imported HookList) {
list.merge(imported, mergeModePrepend, "pre_hook")
}
// MergeAppend appends elements from an imported list to the current list
func (list *HookList) MergeAppend(imported HookList) {
list.merge(imported, mergeModeAppend, "post_hook")
}
// Filter returns a list of hook that match the supplied filter
func (list HookList) Filter(filter HookFilter) HookList {
result := make(HookList, 0, len(list))
for _, hook := range list.Enabled() {
if filter(hook) {
result = append(result, hook)
}
}
return result
}
// HookFilter is used to filter the hook on supplied criteria
type HookFilter func(Hook) bool
// BeforeImports is a filter function
var BeforeImports = func(hook Hook) bool { return hook.BeforeImports }
// BeforeInitState is a filter function
var BeforeInitState = func(hook Hook) bool { return !hook.AfterInitState && !hook.BeforeImports }
// AfterInitState is a filter function
var AfterInitState = func(hook Hook) bool { return hook.AfterInitState && !hook.BeforeImports }