// ReverseDeps For each input label, finds all targets which depend upon it. func ReverseDeps(graph *core.BuildGraph, labels []core.BuildLabel) { uniqueTargets := make(map[core.BuildLabel]struct{}) for _, label := range labels { for _, child := range graph.PackageOrDie(label.PackageName).AllChildren(graph.TargetOrDie(label)) { for _, target := range graph.ReverseDependencies(child) { if parent := target.Parent(graph); parent != nil { uniqueTargets[parent.Label] = struct{}{} } else { uniqueTargets[target.Label] = struct{}{} } } } } // Check for anything subincluding this guy too for _, pkg := range graph.PackageMap() { for _, label := range labels { if pkg.HasSubinclude(label) { uniqueTargets[core.BuildLabel{PackageName: pkg.Name, Name: "all"}] = struct{}{} } } } targets := make(core.BuildLabels, 0, len(uniqueTargets)) for target := range uniqueTargets { targets = append(targets, target) } sort.Sort(targets) for _, target := range targets { fmt.Printf("%s\n", target) } }
// QueryAffectedTargets walks over the build graph and identifies all targets that have a transitive // dependency on the given set of files. // Targets are filtered by given include / exclude labels and if 'tests' is true only // test targets will be returned. func QueryAffectedTargets(graph *core.BuildGraph, files, include, exclude []string, tests, transitive bool) { affectedTargets := make(chan *core.BuildTarget, 100) done := make(chan bool) filePaths := map[string]bool{} for _, file := range files { filePaths[file] = true } // Check all the targets to see if any own one of these files go func() { for _, target := range graph.AllTargets() { for _, source := range target.AllSourcePaths(graph) { if _, present := filePaths[source]; present { affectedTargets <- target break } } } done <- true }() // Check all the packages to see if any are defined by these files. // This is pretty pessimistic, we have to just assume the whole package is invalidated. // A better approach involves using plz query graph and plz_diff_graphs - see that tool // for more explanation. go func() { invalidatePackage := func(pkg *core.Package) { for _, target := range pkg.Targets { affectedTargets <- target } } for _, pkg := range graph.PackageMap() { if _, present := filePaths[pkg.Filename]; present { invalidatePackage(pkg) } else { for _, subinclude := range pkg.Subincludes { for _, source := range graph.TargetOrDie(subinclude).AllSourcePaths(graph) { if _, present := filePaths[source]; present { invalidatePackage(pkg) break } } } } } done <- true }() go handleAffectedTargets(graph, affectedTargets, done, include, exclude, tests, transitive) <-done <-done close(affectedTargets) <-done }
func filesToLabelMap(graph *core.BuildGraph) map[string]*core.BuildLabel { packageMap := make(map[string]*core.BuildLabel) for _, pkg := range graph.PackageMap() { for _, target := range pkg.Outputs { for _, output := range target.Outputs() { artifactPath := path.Join(target.OutDir(), output) packageMap[artifactPath] = &target.Label } } } return packageMap }
func makeJSONGraph(graph *core.BuildGraph, targets []core.BuildLabel) *JSONGraph { ret := JSONGraph{Packages: map[string]JSONPackage{}} if len(targets) == 0 { for name, pkg := range graph.PackageMap() { ret.Packages[name] = makeJSONPackage(graph, pkg) } } else { done := map[core.BuildLabel]struct{}{} for _, target := range targets { addJSONTarget(graph, &ret, target, done) } } return &ret }