github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/build/model.go (about) 1 /* 2 Copyright 2020 The Skaffold Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package build 18 19 import ( 20 "context" 21 22 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" 23 ) 24 25 // node models the artifact dependency graph using a set of channels. 26 // Each build node has a wait channel which it closes once it completes building by calling markComplete. 27 // This notifies all listeners waiting for this node's build to complete. 28 // Additionally it has a reference to the channels for each of its dependencies. 29 // Calling `waitForDependencies` ensures that all required nodes' channels have already been closed and as such have finished building before the current artifact build starts. 30 type node struct { 31 imageName string 32 wait chan interface{} 33 dependencies []node 34 } 35 36 // markComplete broadcasts that this node's build is complete. 37 func (a *node) markComplete() { 38 // closing channel notifies all listeners 39 close(a.wait) 40 } 41 42 // waitForDependencies waits for all required builds to complete or returns an error if any build fails 43 func (a *node) waitForDependencies(ctx context.Context) error { 44 for _, dep := range a.dependencies { 45 // wait for required builds to complete 46 select { 47 case <-ctx.Done(): 48 return ctx.Err() 49 case <-dep.wait: 50 } 51 } 52 return nil 53 } 54 55 func createNodes(artifacts []*latest.Artifact) []node { 56 nodeMap := make(map[string]node) 57 for _, a := range artifacts { 58 nodeMap[a.ImageName] = node{ 59 imageName: a.ImageName, 60 wait: make(chan interface{}), 61 } 62 } 63 64 var nodes []node 65 for _, a := range artifacts { 66 ar := nodeMap[a.ImageName] 67 for _, d := range a.Dependencies { 68 ch, found := nodeMap[d.ImageName] 69 if !found { 70 // if a dependency is not present in `artifacts` slice then we ignore it. 71 continue 72 } 73 ar.dependencies = append(ar.dependencies, ch) 74 } 75 nodes = append(nodes, ar) 76 } 77 return nodes 78 } 79 80 // countingSemaphore uses a buffered channel of size `n` that acts like a counting semaphore, allowing up to `n` concurrent operations 81 type countingSemaphore struct { 82 sem chan bool 83 } 84 85 func newCountingSemaphore(count int) countingSemaphore { 86 return countingSemaphore{sem: make(chan bool, count)} 87 } 88 89 func (c countingSemaphore) acquire() (release func()) { 90 c.sem <- true 91 return func() { 92 <-c.sem 93 } 94 }