forked from gruntwork-io/terragrunt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcollections.go
206 lines (178 loc) · 5.14 KB
/
collections.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package util
import (
"fmt"
"regexp"
"strings"
)
func MatchesAny(regExps []string, s string) bool {
for _, item := range regExps {
if matched, _ := regexp.MatchString(item, s); matched {
return true
}
}
return false
}
// ListEquals returns true if the two lists are equal
func ListEquals[S ~[]E, E comparable](a, b S) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
// ListContainsElement returns true if the given list contains the given element
func ListContainsElement[S ~[]E, E comparable](list S, element any) bool {
for _, item := range list {
if item == element {
return true
}
}
return false
}
// ListContainsSublist returns true if an instance of the sublist can be found in the given list
func ListContainsSublist[S ~[]E, E comparable](list, sublist S) bool {
// A list cannot contain an empty sublist
if len(sublist) == 0 {
return false
}
if len(sublist) > len(list) {
return false
}
for i := 0; len(list[i:]) >= len(sublist); i++ {
if ListEquals(list[i:i+len(sublist)], sublist) {
return true
}
}
return false
}
// ListHasPrefix returns true if list starts with the given prefix list
func ListHasPrefix[S ~[]E, E comparable](list, prefix S) bool {
if len(prefix) == 0 {
return false
}
if len(prefix) > len(list) {
return false
}
return ListEquals(list[:len(prefix)], prefix)
}
// Return a copy of the given list with all instances of the given element removed
func RemoveElementFromList[S ~[]E, E comparable](list S, element E) S {
var out S
for _, item := range list {
if item != element {
out = append(out, item)
}
}
return out
}
// RemoveSublistFromList returns a copy of the given list with all instances of the given sublist removed
func RemoveSublistFromList[S ~[]E, E comparable](list, sublist S) S {
var out = list
for _, item := range sublist {
out = RemoveElementFromList(out, item)
}
return out
}
// Returns a copy of the given list with all duplicates removed (keeping the first encountereds)
func RemoveDuplicatesFromList[S ~[]E, E comparable](list S) S {
return removeDuplicatesFromList(list, false)
}
// Returns a copy of the given list with all duplicates removed (keeping the last encountereds)
func RemoveDuplicatesFromListKeepLast[S ~[]E, E comparable](list S) S {
return removeDuplicatesFromList(list, true)
}
func removeDuplicatesFromList[S ~[]E, E comparable](list S, keepLast bool) S {
out := make(S, 0, len(list))
present := make(map[E]bool)
for _, value := range list {
if _, ok := present[value]; ok {
if keepLast {
out = RemoveElementFromList(out, value)
} else {
continue
}
}
out = append(out, value)
present[value] = true
}
return out
}
// CommaSeparatedStrings returns an HCL compliant formatted list of strings (each string within double quote)
func CommaSeparatedStrings(list []string) string {
values := make([]string, 0, len(list))
for _, value := range list {
values = append(values, fmt.Sprintf(`"%s"`, value))
}
return strings.Join(values, ", ")
}
// Make a copy of the given list of strings
func CloneStringList(listToClone []string) []string {
var out []string
out = append(out, listToClone...)
return out
}
// Make a copy of the given map of strings
func CloneStringMap(mapToClone map[string]string) map[string]string {
out := map[string]string{}
for key, value := range mapToClone {
out[key] = value
}
return out
}
// A convenience method that returns the first item (0th index) in the given list or an empty string if this is an
// empty list
func FirstArg[S ~[]E, E comparable](args S) E {
if len(args) > 0 {
return args[0]
}
var empty E
return empty
}
// A convenience method that returns the second item (1st index) in the given list or an empty string if this is a
// list that has less than 2 items in it
func SecondArg[S ~[]E, E comparable](args S) E {
if len(args) > 1 {
return args[1]
}
var empty E
return empty
}
// A convenience method that returns the last item in the given list or an empty string if this is an empty list
func LastArg[S ~[]E, E comparable](args S) E {
if len(args) > 0 {
return args[len(args)-1]
}
var empty E
return empty
}
// StringListInsert will insert the given string in to the provided string list at the specified index and return the
// new list of strings. To insert the element, we append the item to the tail of the string and then prepend the
// existing items.
func StringListInsert(list []string, element string, index int) []string {
tail := append([]string{element}, list[index:]...)
return append(list[:index], tail...)
}
// SplitUrls slices s into all substrings separated by sep and returns a slice of
// the substrings between those separators.
// Taking into account that the `=` sign can also be used as a git tag, e.g. `git@github.com/test.git?ref=feature`
func SplitUrls(s, sep string) []string {
masks := map[string]string{
"?ref=": "<ref-place-holder>",
}
// mask
for src, mask := range masks {
s = strings.ReplaceAll(s, src, mask)
}
urls := strings.Split(s, sep)
// unmask
for i := range urls {
for src, mask := range masks {
urls[i] = strings.ReplaceAll(urls[i], mask, src)
}
}
return urls
}