|
8 | 8 | package main
|
9 | 9 |
|
10 | 10 | import (
|
11 |
| - "bufio" |
12 |
| - "flag" |
13 | 11 | "fmt"
|
14 |
| - "log" |
15 | 12 | "os"
|
16 |
| - "runtime/debug" |
17 |
| - "strings" |
18 |
| - "time" |
19 |
| - |
20 |
| - "golang.org/x/telemetry/counter" |
21 | 13 | )
|
22 | 14 |
|
23 |
| -type command struct { |
24 |
| - usage string |
25 |
| - short string |
26 |
| - flags *flag.FlagSet |
27 |
| - hasArgs bool |
28 |
| - run func(args []string) error |
29 |
| -} |
30 |
| - |
31 |
| -func (c command) name() string { |
32 |
| - name, _, _ := strings.Cut(c.usage, " ") |
33 |
| - return name |
34 |
| -} |
35 |
| - |
36 |
| -var allCommands []*command |
37 |
| - |
38 |
| -func init() { |
39 |
| - allCommands = []*command{ |
40 |
| - { |
41 |
| - usage: "inc_counters", |
42 |
| - short: "increment telemetry counters", |
43 |
| - run: runIncCounters, |
44 |
| - }, |
45 |
| - { |
46 |
| - usage: "version", |
47 |
| - short: "print version information", |
48 |
| - run: runVersion, |
49 |
| - }, |
50 |
| - { |
51 |
| - usage: "help <command>", |
52 |
| - short: "show help for a command", |
53 |
| - hasArgs: true, |
54 |
| - run: runHelp, // accesses allCommands. |
55 |
| - }, |
56 |
| - } |
57 |
| - |
58 |
| - for _, cmd := range allCommands { |
59 |
| - name := cmd.name() |
60 |
| - if cmd.flags == nil { |
61 |
| - cmd.flags = flag.NewFlagSet(name, flag.ExitOnError) |
62 |
| - } |
63 |
| - cmd.flags.Usage = func() { |
64 |
| - help(name) |
65 |
| - } |
66 |
| - } |
67 |
| -} |
68 |
| - |
69 | 15 | func main() {
|
70 |
| - counter.Open() |
71 |
| - log.SetFlags(0) |
72 |
| - flag.Usage = usage |
73 |
| - flag.Parse() |
74 |
| - |
75 |
| - args := flag.Args() |
76 |
| - var cmd *command |
77 |
| - if len(args) > 0 { |
78 |
| - cmd = findCommand(args[0]) |
79 |
| - } |
80 |
| - if cmd == nil { |
81 |
| - flag.Usage() |
82 |
| - os.Exit(2) |
83 |
| - } |
84 |
| - cmd.flags.Parse(args[1:]) // will exit on error |
85 |
| - args = cmd.flags.Args() |
86 |
| - if !cmd.hasArgs && len(args) > 0 { |
87 |
| - help(cmd.name()) |
88 |
| - failf("\ncommand %q does not accept any arguments.\n", cmd.name()) |
89 |
| - } |
90 |
| - if err := cmd.run(args); err != nil { |
91 |
| - failf("%v\n", err) |
92 |
| - } |
93 |
| -} |
94 |
| - |
95 |
| -func output(msgs ...interface{}) { |
96 |
| - fmt.Fprintln(flag.CommandLine.Output(), msgs...) |
97 |
| -} |
98 |
| - |
99 |
| -func usage() { |
100 |
| - printCommand := func(cmd *command) { |
101 |
| - output(fmt.Sprintf("\t%s\t%s", cmd.name(), cmd.short)) |
102 |
| - } |
103 |
| - output("vscgo is a helper tool for the VS Code Go extension, written in Go.") |
104 |
| - output() |
105 |
| - output("Usage:") |
106 |
| - output() |
107 |
| - output("\tvscgo <command> [arguments]") |
108 |
| - output() |
109 |
| - output("The commands are:") |
110 |
| - output() |
111 |
| - for _, cmd := range allCommands { |
112 |
| - printCommand(cmd) |
113 |
| - } |
114 |
| - output() |
115 |
| - output(`Use "vscgo help <command>" for details about any command.`) |
116 |
| - output() |
117 |
| -} |
118 |
| - |
119 |
| -func failf(format string, args ...any) { |
120 |
| - fmt.Fprintf(os.Stderr, format, args...) |
121 |
| - os.Exit(1) |
122 |
| -} |
123 |
| - |
124 |
| -func findCommand(name string) *command { |
125 |
| - for _, cmd := range allCommands { |
126 |
| - if cmd.name() == name { |
127 |
| - return cmd |
128 |
| - } |
129 |
| - } |
130 |
| - return nil |
131 |
| -} |
132 |
| - |
133 |
| -func help(name string) { |
134 |
| - cmd := findCommand(name) |
135 |
| - if cmd == nil { |
136 |
| - failf("unknown command %q\n", name) |
137 |
| - } |
138 |
| - output(fmt.Sprintf("Usage: vscgo %s", cmd.usage)) |
139 |
| - output() |
140 |
| - output(fmt.Sprintf("%s is used to %s.", cmd.name(), cmd.short)) |
141 |
| - anyflags := false |
142 |
| - cmd.flags.VisitAll(func(*flag.Flag) { |
143 |
| - anyflags = true |
144 |
| - }) |
145 |
| - if anyflags { |
146 |
| - output() |
147 |
| - output("Flags:") |
148 |
| - output() |
149 |
| - cmd.flags.PrintDefaults() |
150 |
| - } |
151 |
| -} |
152 |
| - |
153 |
| -// runIncCounters increments telemetry counters read from stdin. |
154 |
| -func runIncCounters(_ []string) error { |
155 |
| - scanner := bufio.NewScanner(os.Stdin) |
156 |
| - if counterFile := os.Getenv("TELEMETRY_COUNTER_FILE"); counterFile != "" { |
157 |
| - return printCounter(counterFile, scanner) |
158 |
| - } |
159 |
| - return runIncCountersImpl(scanner, counter.Add) |
160 |
| -} |
161 |
| - |
162 |
| -func printCounter(fname string, scanner *bufio.Scanner) (rerr error) { |
163 |
| - f, err := os.OpenFile(fname, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) |
164 |
| - if err != nil { |
165 |
| - return err |
166 |
| - } |
167 |
| - defer func() { |
168 |
| - if err := f.Close(); rerr == nil { |
169 |
| - rerr = err |
170 |
| - } |
171 |
| - }() |
172 |
| - return runIncCountersImpl(scanner, func(name string, count int64) { |
173 |
| - fmt.Fprintln(f, name, count) |
174 |
| - }) |
175 |
| -} |
176 |
| - |
177 |
| -const ( |
178 |
| - incCountersBadInput = "inc_counters_bad_input" |
179 |
| -) |
180 |
| - |
181 |
| -func incCountersInputLength(n int) string { |
182 |
| - const name = "inc_counters_num_input" |
183 |
| - for i := 1; i < 8; i *= 2 { |
184 |
| - if n < i { |
185 |
| - return fmt.Sprintf("%s:<%d", name, i) |
186 |
| - } |
187 |
| - } |
188 |
| - return name + ":>=8" |
189 |
| -} |
190 |
| - |
191 |
| -func incCountersDuration(duration time.Duration) string { |
192 |
| - const name = "inc_counters_duration" |
193 |
| - switch { |
194 |
| - case duration < 10*time.Millisecond: |
195 |
| - return name + ":<10ms" |
196 |
| - case duration < 100*time.Millisecond: |
197 |
| - return name + ":<100ms" |
198 |
| - case duration < 1*time.Second: |
199 |
| - return name + ":<1s" |
200 |
| - case duration < 10*time.Second: |
201 |
| - return name + ":<10s" |
202 |
| - } |
203 |
| - return name + ":>=10s" |
204 |
| -} |
205 |
| - |
206 |
| -func runIncCountersImpl(scanner *bufio.Scanner, incCounter func(name string, count int64)) error { |
207 |
| - start := time.Now() |
208 |
| - linenum := 0 |
209 |
| - for scanner.Scan() { |
210 |
| - line := strings.TrimSpace(scanner.Text()) |
211 |
| - if line == "" { |
212 |
| - continue |
213 |
| - } |
214 |
| - var name string |
215 |
| - var count int64 |
216 |
| - if _, err := fmt.Sscanf(line, "%s %d", &name, &count); err != nil || count < 0 { |
217 |
| - incCounter(incCountersBadInput, 1) |
218 |
| - return fmt.Errorf("invalid line: %q", line) |
219 |
| - } |
220 |
| - linenum++ |
221 |
| - incCounter(name, int64(count)) |
222 |
| - } |
223 |
| - incCounter(incCountersInputLength(linenum), 1) |
224 |
| - incCounter(incCountersDuration(time.Since(start)), 1) |
225 |
| - return nil |
226 |
| -} |
227 |
| - |
228 |
| -func runVersion(_ []string) error { |
229 |
| - info, ok := debug.ReadBuildInfo() |
230 |
| - if !ok { |
231 |
| - fmt.Println("vscgo: unknown") |
232 |
| - fmt.Println("go: unknown") |
233 |
| - return nil |
234 |
| - } |
235 |
| - fmt.Println("vscgo:", info.Main.Version) |
236 |
| - fmt.Println("go:", info.GoVersion) |
237 |
| - return nil |
238 |
| -} |
239 |
| - |
240 |
| -func runHelp(args []string) error { |
241 |
| - switch len(args) { |
242 |
| - case 1: |
243 |
| - help(args[0]) |
244 |
| - default: |
245 |
| - flag.Usage() |
246 |
| - failf("too many arguments to \"help\"") |
247 |
| - } |
248 |
| - return nil |
| 16 | + fmt.Fprintln(os.Stderr, "This is a deprecated version of vscgo. Please reinstall:") |
| 17 | + fmt.Fprintln(os.Stderr, " go install github.com/golang/vscode-go/vscgo@latest") |
249 | 18 | }
|
0 commit comments