github.com/tiagovtristao/plz@v13.4.0+incompatible/src/query/roots.go (about)

     1  package query
     2  
     3  import (
     4  	"github.com/thought-machine/please/src/core"
     5  	"fmt"
     6  	"sort"
     7  )
     8  
     9  // Roots returns build labels with no dependents from the given list.
    10  // i.e. if `labels` contains `A` and `B` such that `A` depends-on `B` (possibly through some indirect path)
    11  // only `B` will be output.
    12  // This does not perform an ordering of the labels, but theoretically you could call this method repeatedly with a
    13  // shrinking set of labels.
    14  func Roots(graph *core.BuildGraph, labels core.BuildLabels) {
    15  	// allSeenTargets is every single reverse dependency of the passed in labels.
    16  	allSeenTargets := map[*core.BuildTarget]struct{}{}
    17  	for _, label := range labels {
    18  		target := graph.TargetOrDie(label)
    19  		// Minor efficiency, if we've seen this target already there's no point iterating it
    20  		// As any of its reverse dependencies will also have already been found.
    21  		_, ok := allSeenTargets[target]
    22  		if ok {
    23  			continue
    24  		}
    25  
    26  		targets := map[*core.BuildTarget]struct{}{}
    27  		uniqueReverseDependencies(graph, target, targets)
    28  		// We need to remove the current target from the returned list as it is a false positive at this point.
    29  		delete(targets, target)
    30  		for parent := range targets {
    31  			allSeenTargets[parent] = struct{}{}
    32  		}
    33  	}
    34  	for parent := range allSeenTargets {
    35  		// See if any of the reverse deps were passed in
    36  		i := indexOf(labels, parent.Label)
    37  		if i != -1 {
    38  			// If so, we know it must not be a root, so remove it from the set
    39  			labels[i] = labels[len(labels)-1]
    40  			labels[len(labels)-1] = core.BuildLabel{}
    41  			labels = labels[:len(labels)-1]
    42  		}
    43  	}
    44  	sort.Sort(labels)
    45  	for _, l := range labels {
    46  		fmt.Printf("%s\n", l)
    47  	}
    48  }
    49  
    50  func indexOf(labels []core.BuildLabel, label core.BuildLabel) int {
    51  	for i, l := range labels {
    52  		if l == label {
    53  			return i
    54  		}
    55  	}
    56  	return -1
    57  }
    58  
    59  func uniqueReverseDependencies(graph *core.BuildGraph, target *core.BuildTarget, targets map[*core.BuildTarget]struct{}) {
    60  	_, ok := targets[target]
    61  	if ok {
    62  		return
    63  	}
    64  	targets[target] = struct{}{}
    65  	// ReverseDependencies are the smaller order collection, so more efficient to iterate.
    66  	for _, child := range graph.ReverseDependencies(target) {
    67  		uniqueReverseDependencies(graph, child, targets)
    68  	}
    69  }