/
debug.go
157 lines (131 loc) · 3.39 KB
/
debug.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package cmd
import (
"fmt"
"log"
"net/http"
"os"
"runtime"
"strings"
"sync"
"time"
"github.com/exercism/cli/config"
"github.com/exercism/cli/paths"
"github.com/urfave/cli"
)
type pingResult struct {
URL string
Service string
Status string
Latency time.Duration
}
// Debug provides information about the user's environment and configuration.
func Debug(ctx *cli.Context) error {
defer fmt.Printf("\nIf you are having trouble and need to file a GitHub issue (https://github.com/exercism/exercism.io/issues) please include this information (except your API key. Keep that private).\n")
client := &http.Client{Timeout: 20 * time.Second}
fmt.Printf("\n**** Debug Information ****\n")
fmt.Printf("Exercism CLI Version: %s\n", ctx.App.Version)
u, err := NewUpgrader(client)
if err != nil {
log.Println("unable to fetch latest release: " + err.Error())
} else {
rel := u.release
needed, err := u.IsUpgradeNeeded(ctx.App.Version)
if err != nil {
log.Printf("unable to check semver: %s\n", err)
} else if needed {
defer fmt.Printf("\nA newer version of the CLI (%s) can be downloaded here: %s\n", rel.TagName, rel.Location)
}
fmt.Printf("Exercism CLI Latest Release: %s\n", rel.Version())
}
fmt.Printf("OS/Architecture: %s/%s\n", runtime.GOOS, runtime.GOARCH)
fmt.Printf("Build OS/Architecture %s/%s\n", BuildOS, BuildARCH)
if BuildARM != "" {
fmt.Printf("Build ARMv%s\n", BuildARM)
}
fmt.Printf("Home Dir: %s\n", paths.Home)
c, err := config.New(ctx.GlobalString("config"))
if err != nil {
log.Fatal(err)
}
if err := printConfigFileData(ctx, c); err != nil {
log.Fatal(err)
}
fmt.Println("Testing API endpoints reachability")
endpoints := map[string]string{
"API": c.API,
"XAPI": c.XAPI,
"GitHub API": "https://api.github.com/",
}
var wg sync.WaitGroup
results := make(chan pingResult)
defer close(results)
wg.Add(len(endpoints))
for service, url := range endpoints {
go func(service, url string) {
now := time.Now()
res, err := client.Get(url)
delta := time.Since(now)
if err != nil {
results <- pingResult{
URL: url,
Service: service,
Status: err.Error(),
Latency: delta,
}
return
}
defer res.Body.Close()
results <- pingResult{
URL: url,
Service: service,
Status: "connected",
Latency: delta,
}
}(service, url)
}
go func() {
for r := range results {
fmt.Printf(
"\t* %s: %s [%s] %s\n",
r.Service,
r.URL,
r.Status,
r.Latency,
)
wg.Done()
}
}()
wg.Wait()
return nil
}
func printConfigFileData(ctx *cli.Context, cfg *config.Config) error {
configured := true
if _, err := os.Stat(cfg.File); err != nil {
if os.IsNotExist(err) {
configured = false
} else {
return err
}
}
apiKey := "Please set your API key to access all of the CLI features"
configFile := fmt.Sprintf("%s (not configured)", cfg.File)
if configured {
configFile = cfg.File
if cfg.APIKey != "" {
if ctx.Bool("full-api-key") {
apiKey = cfg.APIKey
} else {
apiKey = redactAPIKey(cfg.APIKey)
}
}
}
fmt.Printf("Config File: %s\n", configFile)
fmt.Printf("API Key: %s\n", apiKey)
fmt.Printf("Exercises Directory: %s\n", cfg.Dir)
return nil
}
func redactAPIKey(apiKey string) string {
str := apiKey[4 : len(apiKey)-3]
redaction := strings.Repeat("*", len(str))
return string(apiKey[:4]) + redaction + string(apiKey[len(apiKey)-3:])
}