package terraform import ( "sort" ) // Semaphore is a wrapper around a channel to provide // utility methods to clarify that we are treating the // channel as a semaphore type Semaphore chan struct{} // NewSemaphore creates a semaphore that allows up // to a given limit of simultaneous acquisitions func NewSemaphore(n int) Semaphore { if n == 0 { panic("semaphore with limit 0") } ch := make(chan struct{}, n) return Semaphore(ch) } // Acquire is used to acquire an available slot. // Blocks until available. func (s Semaphore) Acquire() { s <- struct{}{} } // TryAcquire is used to do a non-blocking acquire. // Returns a bool indicating success func (s Semaphore) TryAcquire() bool { select { case s <- struct{}{}: return true default: return false } } // Release is used to return a slot. Acquire must // be called as a pre-condition. func (s Semaphore) Release() { select { case <-s: default: panic("release without an acquire") } } // strSliceContains checks if a given string is contained in a slice // When anybody asks why Go needs generics, here you go. func strSliceContains(haystack []string, needle string) bool { for _, s := range haystack { if s == needle { return true } } return false } // deduplicate a slice of strings func uniqueStrings(s []string) []string { if len(s) < 2 { return s } sort.Strings(s) result := make([]string, 1, len(s)) result[0] = s[0] for i := 1; i < len(s); i++ { if s[i] != result[len(result)-1] { result = append(result, s[i]) } } return result }