github.com/tiagovtristao/plz@v13.4.0+incompatible/src/tool/tool.go (about) 1 // Package tool implements running Please's sub-tools (via "plz tool jarcat" etc). 2 // 3 // N.B. This is not how they are invoked during the build; that runs them directly. 4 // This is only a convenience thing at the command line. 5 package tool 6 7 import ( 8 "os" 9 "path/filepath" 10 "strings" 11 "syscall" 12 13 "github.com/jessevdk/go-flags" 14 "gopkg.in/op/go-logging.v1" 15 16 "github.com/thought-machine/please/src/core" 17 "sort" 18 ) 19 20 var log = logging.MustGetLogger("tool") 21 22 // A Tool is one of Please's tools; this only exists for facilitating tab-completion for flags. 23 type Tool string 24 25 // Complete suggests completions for a partial tool name. 26 func (tool Tool) Complete(match string) []flags.Completion { 27 ret := []flags.Completion{} 28 for k := range matchingTools(core.DefaultConfiguration(), match) { 29 ret = append(ret, flags.Completion{Item: k}) 30 } 31 return ret 32 } 33 34 // Run runs one of the sub-tools. 35 func Run(config *core.Configuration, tool Tool, args []string) { 36 tools := matchingTools(config, string(tool)) 37 if len(tools) != 1 { 38 log.Fatalf("Unknown tool: %s. Must be one of [%s]", tool, strings.Join(allToolNames(config, ""), ", ")) 39 } 40 target := core.ExpandHomePath(tools[allToolNames(config, string(tool))[0]]) 41 if !core.LooksLikeABuildLabel(target) { 42 if !filepath.IsAbs(target) { 43 t, err := core.LookBuildPath(target, config) 44 if err != nil { 45 log.Fatalf("%s", err) 46 } 47 target = t 48 } 49 // Hopefully we have an absolute path now, so let's run it. 50 err := syscall.Exec(target, append([]string{target}, args...), os.Environ()) 51 log.Fatalf("Failed to exec %s: %s", target, err) // Always a failure, exec never returns. 52 } 53 // The tool is allowed to be an in-repo target. In that case it's essentially equivalent to "plz run". 54 // We have to re-exec ourselves in such a case since we don't know enough about it to run it now. 55 plz, _ := os.Executable() 56 args = append([]string{os.Args[0], "run", target, "--"}, args...) 57 err := syscall.Exec(plz, args, os.Environ()) 58 log.Fatalf("Failed to exec %s run %s: %s", plz, target, err) // Always a failure, exec never returns. 59 } 60 61 // matchingTools returns a set of matching tools for a string prefix. 62 func matchingTools(config *core.Configuration, prefix string) map[string]string { 63 knownTools := map[string]string{ 64 "gotest": config.Go.TestTool, 65 "jarcat": config.Java.JarCatTool, 66 "javacworker": config.Java.JavacWorker, 67 "junitrunner": config.Java.JUnitRunner, 68 "langserver": "build_langserver", 69 "lps": "build_langserver", 70 "maven": config.Java.PleaseMavenTool, 71 "pex": config.Python.PexTool, 72 "sandbox": "please_sandbox", 73 } 74 ret := map[string]string{} 75 for k, v := range knownTools { 76 if strings.HasPrefix(k, prefix) { 77 ret[k] = v 78 } 79 } 80 return ret 81 } 82 83 // allToolNames returns the names of all available tools. 84 func allToolNames(config *core.Configuration, prefix string) []string { 85 ret := []string{} 86 for k := range matchingTools(config, prefix) { 87 ret = append(ret, k) 88 } 89 sort.Strings(ret) 90 return ret 91 }