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  }