1
2
3
4
5
6
7 package base
8
9 import (
10 "context"
11 "flag"
12 "fmt"
13 exec "internal/execabs"
14 "log"
15 "os"
16 "strings"
17 "sync"
18
19 "cmd/go/internal/cfg"
20 "cmd/go/internal/str"
21 )
22
23
24
25 type Command struct {
26
27
28 Run func(ctx context.Context, cmd *Command, args []string)
29
30
31
32 UsageLine string
33
34
35 Short string
36
37
38 Long string
39
40
41 Flag flag.FlagSet
42
43
44
45 CustomFlags bool
46
47
48
49
50 Commands []*Command
51 }
52
53 var Go = &Command{
54 UsageLine: "go",
55 Long: `Go is a tool for managing Go source code.`,
56
57 }
58
59
60
61 func hasFlag(c *Command, name string) bool {
62 if f := c.Flag.Lookup(name); f != nil {
63 return true
64 }
65 for _, sub := range c.Commands {
66 if hasFlag(sub, name) {
67 return true
68 }
69 }
70 return false
71 }
72
73
74 func (c *Command) LongName() string {
75 name := c.UsageLine
76 if i := strings.Index(name, " ["); i >= 0 {
77 name = name[:i]
78 }
79 if name == "go" {
80 return ""
81 }
82 return strings.TrimPrefix(name, "go ")
83 }
84
85
86 func (c *Command) Name() string {
87 name := c.LongName()
88 if i := strings.LastIndex(name, " "); i >= 0 {
89 name = name[i+1:]
90 }
91 return name
92 }
93
94 func (c *Command) Usage() {
95 fmt.Fprintf(os.Stderr, "usage: %s\n", c.UsageLine)
96 fmt.Fprintf(os.Stderr, "Run 'go help %s' for details.\n", c.LongName())
97 SetExitStatus(2)
98 Exit()
99 }
100
101
102
103 func (c *Command) Runnable() bool {
104 return c.Run != nil
105 }
106
107 var atExitFuncs []func()
108
109 func AtExit(f func()) {
110 atExitFuncs = append(atExitFuncs, f)
111 }
112
113 func Exit() {
114 for _, f := range atExitFuncs {
115 f()
116 }
117 os.Exit(exitStatus)
118 }
119
120 func Fatalf(format string, args ...any) {
121 Errorf(format, args...)
122 Exit()
123 }
124
125 func Errorf(format string, args ...any) {
126 log.Printf(format, args...)
127 SetExitStatus(1)
128 }
129
130 func ExitIfErrors() {
131 if exitStatus != 0 {
132 Exit()
133 }
134 }
135
136 var exitStatus = 0
137 var exitMu sync.Mutex
138
139 func SetExitStatus(n int) {
140 exitMu.Lock()
141 if exitStatus < n {
142 exitStatus = n
143 }
144 exitMu.Unlock()
145 }
146
147 func GetExitStatus() int {
148 return exitStatus
149 }
150
151
152
153
154 func Run(cmdargs ...any) {
155 cmdline := str.StringList(cmdargs...)
156 if cfg.BuildN || cfg.BuildX {
157 fmt.Printf("%s\n", strings.Join(cmdline, " "))
158 if cfg.BuildN {
159 return
160 }
161 }
162
163 cmd := exec.Command(cmdline[0], cmdline[1:]...)
164 cmd.Stdout = os.Stdout
165 cmd.Stderr = os.Stderr
166 if err := cmd.Run(); err != nil {
167 Errorf("%v", err)
168 }
169 }
170
171
172 func RunStdin(cmdline []string) {
173 cmd := exec.Command(cmdline[0], cmdline[1:]...)
174 cmd.Stdin = os.Stdin
175 cmd.Stdout = os.Stdout
176 cmd.Stderr = os.Stderr
177 cmd.Env = cfg.OrigEnv
178 StartSigHandlers()
179 if err := cmd.Run(); err != nil {
180 Errorf("%v", err)
181 }
182 }
183
184
185
186 var Usage func()
187
View as plain text