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{}
13 // NewSemaphore creates a semaphore that allows up
14 // to a given limit of simultaneous acquisitions
15 func NewSemaphore(n int) Semaphore {
17 panic("semaphore with limit 0")
19 ch := make(chan struct{}, n)
23 // Acquire is used to acquire an available slot.
24 // Blocks until available.
25 func (s Semaphore) Acquire() {
29 // TryAcquire is used to do a non-blocking acquire.
30 // Returns a bool indicating success
31 func (s Semaphore) TryAcquire() bool {
40 // Release is used to return a slot. Acquire must
41 // be called as a pre-condition.
42 func (s Semaphore) Release() {
46 panic("release without an acquire")
50 // resourceProvider returns the provider name for the given type.
51 func resourceProvider(t, alias string) string {
56 idx := strings.IndexRune(t, '_')
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.
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 {
78 // deduplicate a slice of strings
79 func uniqueStrings(s []string) []string {
85 result := make([]string, 1, len(s))
87 for i := 1; i < len(s); i++ {
88 if s[i] != result[len(result)-1] {
89 result = append(result, s[i])