github.com/knieriem/gointernal@v0.2.0-pre2/cmd/go/base/base.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package base defines shared basic pieces of the go command, 6 // in particular logging and the Command structure. 7 package base 8 9 import ( 10 "context" 11 "flag" 12 "fmt" 13 "log" 14 "os" 15 "strings" 16 "sync" 17 ) 18 19 // A Command is an implementation of a go command 20 // like go build or go fix. 21 type Command struct { 22 // Run runs the command. 23 // The args are the arguments after the command name. 24 Run func(ctx context.Context, cmd *Command, args []string) 25 26 // UsageLine is the one-line usage message. 27 // The words between "go" and the first flag or argument in the line are taken to be the command name. 28 UsageLine string 29 30 // Short is the short description shown in the 'go help' output. 31 Short string 32 33 // Long is the long message shown in the 'go help <this-command>' output. 34 Long string 35 36 // Flag is a set of flags specific to this command. 37 Flag flag.FlagSet 38 39 // CustomFlags indicates that the command will do its own 40 // flag parsing. 41 CustomFlags bool 42 43 // Commands lists the available commands and help topics. 44 // The order here is the order in which they are printed by 'go help'. 45 // Note that subcommands are in general best avoided. 46 Commands []*Command 47 } 48 49 // Prog must be initialized in package main 50 var Prog *Command 51 52 // hasFlag reports whether a command or any of its subcommands contain the given 53 // flag. 54 func hasFlag(c *Command, name string) bool { 55 if f := c.Flag.Lookup(name); f != nil { 56 return true 57 } 58 for _, sub := range c.Commands { 59 if hasFlag(sub, name) { 60 return true 61 } 62 } 63 return false 64 } 65 66 // LongName returns the command's long name: all the words in the usage line between "go" and a flag or argument, 67 func (c *Command) LongName() string { 68 name := c.UsageLine 69 if i := strings.Index(name, " -- "); i >= 0 { 70 name = name[:i] 71 } 72 if i := strings.Index(name, " ["); i >= 0 { 73 name = name[:i] 74 } 75 if name == Prog.UsageLine { 76 return "" 77 } 78 return strings.TrimPrefix(name, Prog.UsageLine+" ") 79 } 80 81 // Name returns the command's short name: the last word in the usage line before a flag or argument. 82 func (c *Command) Name() string { 83 name := c.LongName() 84 if i := strings.LastIndex(name, " "); i >= 0 { 85 name = name[i+1:] 86 } 87 return name 88 } 89 90 func (c *Command) Usage() { 91 fmt.Fprintf(os.Stderr, "usage: %s\n", strings.Replace(c.UsageLine, " -- ", " ", -1)) 92 fmt.Fprintf(os.Stderr, "Run '%s help %s' for details.\n", Prog.UsageLine, c.LongName()) 93 SetExitStatus(2) 94 Exit() 95 } 96 97 // Runnable reports whether the command can be run; otherwise 98 // it is a documentation pseudo-command such as importpath. 99 func (c *Command) Runnable() bool { 100 return c.Run != nil 101 } 102 103 var atExitFuncs []func() 104 105 func AtExit(f func()) { 106 atExitFuncs = append(atExitFuncs, f) 107 } 108 109 func Exit() { 110 for _, f := range atExitFuncs { 111 f() 112 } 113 os.Exit(exitStatus) 114 } 115 116 func Fatalf(format string, args ...interface{}) { 117 Errorf(format, args...) 118 Exit() 119 } 120 121 func Errorf(format string, args ...interface{}) { 122 log.Printf(format, args...) 123 SetExitStatus(1) 124 } 125 126 func ExitIfErrors() { 127 if exitStatus != 0 { 128 Exit() 129 } 130 } 131 132 var exitStatus = 0 133 var exitMu sync.Mutex 134 135 func SetExitStatus(n int) { 136 exitMu.Lock() 137 if exitStatus < n { 138 exitStatus = n 139 } 140 exitMu.Unlock() 141 } 142 143 func GetExitStatus() int { 144 return exitStatus 145 } 146 147 // Usage is the usage-reporting function, filled in by package main 148 // but here for reference by other packages. 149 var Usage func()