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

     1  package query
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path"
     7  	"strings"
     8  
     9  	"github.com/thought-machine/please/src/core"
    10  	"github.com/thought-machine/please/src/utils"
    11  )
    12  
    13  // CompletionLabels produces a set of labels that complete a given input.
    14  // The second return value is a set of labels to parse for (since the original set generally won't turn out to exist).
    15  // The last return value is true if one or more of the inputs are a "hidden" target
    16  // (i.e. name begins with an underscore).
    17  func CompletionLabels(config *core.Configuration, args []string, repoRoot string) ([]core.BuildLabel, []core.BuildLabel, bool) {
    18  	if len(args) == 0 {
    19  		queryCompletionPackages(config, ".", repoRoot)
    20  	} else if !strings.Contains(args[0], ":") {
    21  		// Haven't picked a package yet so no parsing is necessary.
    22  		if strings.HasPrefix(args[0], "//") {
    23  			queryCompletionPackages(config, args[0][2:], repoRoot)
    24  		} else {
    25  			queryCompletionPackages(config, args[0], repoRoot)
    26  		}
    27  	}
    28  	hidden := false
    29  	for _, arg := range args {
    30  		hidden = hidden || strings.Contains(arg, ":_")
    31  	}
    32  	// Bash completion sometimes produces \: instead of just : (see issue #18).
    33  	// We silently fix that here since we've not yet worked out how to fix Bash itself :(
    34  	args[0] = strings.Replace(args[0], "\\:", ":", -1)
    35  	if strings.HasSuffix(args[0], ":") {
    36  		// Have to special-case this because it won't be a valid label.
    37  		labels := core.ParseBuildLabels([]string{args[0] + "all"})
    38  		return []core.BuildLabel{{PackageName: labels[0].PackageName, Name: ""}}, labels, hidden
    39  	}
    40  	labels := core.ParseBuildLabels([]string{args[0]})
    41  	return labels, []core.BuildLabel{{PackageName: labels[0].PackageName, Name: "all"}}, hidden
    42  }
    43  
    44  func queryCompletionPackages(config *core.Configuration, query, repoRoot string) {
    45  	packages := GetAllPackages(config, query, repoRoot)
    46  	// If there's only one package, we know it has to be that, but we don't present
    47  	// only one option otherwise bash completion will assume it's that.
    48  	if len(packages) == 1 {
    49  		fmt.Printf("/%s:\n", packages[0])
    50  		fmt.Printf("/%s:all\n", packages[0])
    51  	} else {
    52  		for _, pkg := range packages {
    53  			fmt.Printf("/%s\n", pkg)
    54  		}
    55  	}
    56  	os.Exit(0) // Don't need to run a full-blown parse, get out now.
    57  }
    58  
    59  // GetAllPackages returns a string slice of all the package labels, such as "//src/core/query"
    60  func GetAllPackages(config *core.Configuration, query, repoRoot string) []string {
    61  	root := path.Join(repoRoot, query)
    62  	origRoot := root
    63  	if !core.PathExists(root) {
    64  		root = path.Dir(root)
    65  	}
    66  	packages := []string{}
    67  	for pkg := range utils.FindAllSubpackages(config, root, origRoot) {
    68  		if strings.HasPrefix(pkg, origRoot) {
    69  			packages = append(packages, pkg[len(repoRoot):])
    70  		}
    71  	}
    72  
    73  	return packages
    74  }
    75  
    76  // Completions queries a set of possible completions for some build labels.
    77  // If 'binary' is true it will complete only targets that are runnable binaries (but not tests).
    78  // If 'test' is true it will similarly complete only targets that are tests.
    79  // If 'hidden' is true then hidden targets (i.e. those with names beginning with an underscore)
    80  // will be included as well.
    81  func Completions(graph *core.BuildGraph, labels []core.BuildLabel, binary, test, hidden bool) {
    82  	for _, label := range labels {
    83  		count := 0
    84  		for _, target := range graph.PackageOrDie(label).AllTargets() {
    85  			if !strings.HasPrefix(target.Label.Name, label.Name) {
    86  				continue
    87  			}
    88  			if (binary && (!target.IsBinary || target.IsTest)) || (test && !target.IsTest) {
    89  				continue
    90  			}
    91  			if hidden || !strings.HasPrefix(target.Label.Name, "_") {
    92  				fmt.Printf("%s\n", target.Label)
    93  				count++
    94  			}
    95  		}
    96  		if !binary && ((label.Name != "" && strings.HasPrefix("all", label.Name)) || (label.Name == "" && count > 1)) {
    97  			fmt.Printf("//%s:all\n", label.PackageName)
    98  		}
    99  	}
   100  }