github.com/tiagovtristao/plz@v13.4.0+incompatible/src/query/affected_targets.go (about) 1 package query 2 3 import "github.com/thought-machine/please/src/core" 4 import "fmt" 5 6 // AffectedTargets walks over the build graph and identifies all targets that have a transitive 7 // dependency on the given set of files. 8 // Targets are filtered by given include / exclude labels and if 'tests' is true only 9 // test targets will be returned. 10 func AffectedTargets(state *core.BuildState, files, include, exclude []string, tests, transitive bool) { 11 affectedTargets := make(chan *core.BuildTarget, 100) 12 done := make(chan bool) 13 14 filePaths := map[string]bool{} 15 for _, file := range files { 16 filePaths[file] = true 17 } 18 19 // Check all the targets to see if any own one of these files 20 go func() { 21 for _, target := range state.Graph.AllTargets() { 22 for _, source := range target.AllSourcePaths(state.Graph) { 23 if _, present := filePaths[source]; present { 24 affectedTargets <- target 25 break 26 } 27 } 28 } 29 done <- true 30 }() 31 32 // Check all the packages to see if any are defined by these files. 33 // This is pretty pessimistic, we have to just assume the whole package is invalidated. 34 // A better approach involves using plz query graph and plz_diff_graphs - see that tool 35 // for more explanation. 36 go func() { 37 invalidatePackage := func(pkg *core.Package) { 38 for _, target := range pkg.AllTargets() { 39 affectedTargets <- target 40 } 41 } 42 for _, pkg := range state.Graph.PackageMap() { 43 if _, present := filePaths[pkg.Filename]; present { 44 invalidatePackage(pkg) 45 } else { 46 for _, subinclude := range pkg.Subincludes { 47 for _, source := range state.Graph.TargetOrDie(subinclude).AllSourcePaths(state.Graph) { 48 if _, present := filePaths[source]; present { 49 invalidatePackage(pkg) 50 break 51 } 52 } 53 } 54 } 55 } 56 done <- true 57 }() 58 59 go handleAffectedTargets(state, affectedTargets, done, include, exclude, tests, transitive) 60 61 <-done 62 <-done 63 close(affectedTargets) 64 <-done 65 } 66 67 func handleAffectedTargets(state *core.BuildState, affectedTargets <-chan *core.BuildTarget, done chan<- bool, include, exclude []string, tests, transitive bool) { 68 seenTargets := map[*core.BuildTarget]bool{} 69 70 var inner func(*core.BuildTarget) 71 inner = func(target *core.BuildTarget) { 72 if !seenTargets[target] { 73 seenTargets[target] = true 74 if transitive { 75 for _, revdep := range state.Graph.ReverseDependencies(target) { 76 inner(revdep) 77 } 78 } 79 if (!tests || target.IsTest) && state.ShouldInclude(target) { 80 fmt.Printf("%s\n", target.Label) 81 } 82 } 83 } 84 for target := range affectedTargets { 85 inner(target) 86 } 87 done <- true 88 }