github.com/sercand/please@v13.4.0+incompatible/src/query/somepath.go (about)

     1  package query
     2  
     3  import "fmt"
     4  
     5  import "github.com/thought-machine/please/src/core"
     6  
     7  // SomePath finds and returns a path between two targets.
     8  // Useful for a "why on earth do I depend on this thing" type query.
     9  func SomePath(graph *core.BuildGraph, label1 core.BuildLabel, label2 core.BuildLabel) {
    10  	// Awkwardly either target can be :all. This is an extremely useful idiom though so despite
    11  	// trickiness is worth supporting.
    12  	// Of course this calculation is also quadratic but it's not very obvious how to avoid that.
    13  	if label1.IsAllTargets() {
    14  		for _, target := range graph.PackageOrDie(label1).AllTargets() {
    15  			if querySomePath1(graph, target, label2, false) {
    16  				return
    17  			}
    18  		}
    19  		fmt.Printf("Couldn't find any dependency path between %s and %s\n", label1, label2)
    20  	} else {
    21  		querySomePath1(graph, graph.TargetOrDie(label1), label2, true)
    22  	}
    23  }
    24  
    25  func querySomePath1(graph *core.BuildGraph, target1 *core.BuildTarget, label2 core.BuildLabel, print bool) bool {
    26  	// Now we do the same for label2.
    27  	if label2.IsAllTargets() {
    28  		for _, target2 := range graph.PackageOrDie(label2).AllTargets() {
    29  			if querySomePath2(graph, target1, target2, false) {
    30  				return true
    31  			}
    32  		}
    33  		return false
    34  	}
    35  	return querySomePath2(graph, target1, graph.TargetOrDie(label2), print)
    36  }
    37  
    38  func querySomePath2(graph *core.BuildGraph, target1, target2 *core.BuildTarget, print bool) bool {
    39  	if !printSomePath(graph, target1, target2) && !printSomePath(graph, target2, target1) {
    40  		if print {
    41  			fmt.Printf("Couldn't find any dependency path between %s and %s\n", target1.Label, target2.Label)
    42  		}
    43  		return false
    44  	}
    45  	return true
    46  }
    47  
    48  // This is just a simple DFS through the graph.
    49  func printSomePath(graph *core.BuildGraph, target1, target2 *core.BuildTarget) bool {
    50  	if target1 == target2 {
    51  		fmt.Printf("Found path:\n  %s\n", target1.Label)
    52  		return true
    53  	}
    54  	for _, target := range graph.ReverseDependencies(target2) {
    55  		if printSomePath(graph, target1, target) {
    56  			if target2.Parent(graph) != target {
    57  				fmt.Printf("  %s\n", target2.Label)
    58  			}
    59  			return true
    60  		}
    61  	}
    62  	return false
    63  }