]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package terraform |
2 | ||
3 | import ( | |
4 | "sort" | |
5 | "strings" | |
6 | ) | |
7 | ||
8 | // Semaphore is a wrapper around a channel to provide | |
9 | // utility methods to clarify that we are treating the | |
10 | // channel as a semaphore | |
11 | type Semaphore chan struct{} | |
12 | ||
13 | // NewSemaphore creates a semaphore that allows up | |
14 | // to a given limit of simultaneous acquisitions | |
15 | func NewSemaphore(n int) Semaphore { | |
16 | if n == 0 { | |
17 | panic("semaphore with limit 0") | |
18 | } | |
19 | ch := make(chan struct{}, n) | |
20 | return Semaphore(ch) | |
21 | } | |
22 | ||
23 | // Acquire is used to acquire an available slot. | |
24 | // Blocks until available. | |
25 | func (s Semaphore) Acquire() { | |
26 | s <- struct{}{} | |
27 | } | |
28 | ||
29 | // TryAcquire is used to do a non-blocking acquire. | |
30 | // Returns a bool indicating success | |
31 | func (s Semaphore) TryAcquire() bool { | |
32 | select { | |
33 | case s <- struct{}{}: | |
34 | return true | |
35 | default: | |
36 | return false | |
37 | } | |
38 | } | |
39 | ||
40 | // Release is used to return a slot. Acquire must | |
41 | // be called as a pre-condition. | |
42 | func (s Semaphore) Release() { | |
43 | select { | |
44 | case <-s: | |
45 | default: | |
46 | panic("release without an acquire") | |
47 | } | |
48 | } | |
49 | ||
50 | // resourceProvider returns the provider name for the given type. | |
51 | func resourceProvider(t, alias string) string { | |
52 | if alias != "" { | |
53 | return alias | |
54 | } | |
55 | ||
56 | idx := strings.IndexRune(t, '_') | |
57 | if idx == -1 { | |
58 | // If no underscores, the resource name is assumed to be | |
59 | // also the provider name, e.g. if the provider exposes | |
60 | // only a single resource of each type. | |
61 | return t | |
62 | } | |
63 | ||
64 | return t[:idx] | |
65 | } | |
66 | ||
67 | // strSliceContains checks if a given string is contained in a slice | |
68 | // When anybody asks why Go needs generics, here you go. | |
69 | func strSliceContains(haystack []string, needle string) bool { | |
70 | for _, s := range haystack { | |
71 | if s == needle { | |
72 | return true | |
73 | } | |
74 | } | |
75 | return false | |
76 | } | |
77 | ||
78 | // deduplicate a slice of strings | |
79 | func uniqueStrings(s []string) []string { | |
80 | if len(s) < 2 { | |
81 | return s | |
82 | } | |
83 | ||
84 | sort.Strings(s) | |
85 | result := make([]string, 1, len(s)) | |
86 | result[0] = s[0] | |
87 | for i := 1; i < len(s); i++ { | |
88 | if s[i] != result[len(result)-1] { | |
89 | result = append(result, s[i]) | |
90 | } | |
91 | } | |
92 | return result | |
93 | } |