feat: improved error messaging, and automatic doctor runs on fatal failure
This commit is contained in:
parent
6ad6876051
commit
d992074c9c
4 changed files with 39 additions and 9 deletions
|
|
@ -38,19 +38,28 @@ func runDoctor(w io.Writer) bool {
|
||||||
}
|
}
|
||||||
hasError := false
|
hasError := false
|
||||||
|
|
||||||
|
lastFail := false
|
||||||
|
|
||||||
emit := func(level, msg string) {
|
emit := func(level, msg string) {
|
||||||
var code string
|
var code string
|
||||||
switch level {
|
switch level {
|
||||||
case "ok":
|
case "ok":
|
||||||
code = "32"
|
code = "32"
|
||||||
|
lastFail = false
|
||||||
case "WARN":
|
case "WARN":
|
||||||
code = "33"
|
code = "33"
|
||||||
|
lastFail = false
|
||||||
case "FAIL":
|
case "FAIL":
|
||||||
code = "31"
|
code = "31"
|
||||||
hasError = true
|
hasError = true
|
||||||
|
lastFail = true
|
||||||
}
|
}
|
||||||
|
if lastFail && tty {
|
||||||
|
fmt.Fprintf(w, "%s \033[1m%s\033[0m\n", keyword(code, level, tty), msg)
|
||||||
|
} else {
|
||||||
fmt.Fprintf(w, "%s %s\n", keyword(code, level, tty), msg)
|
fmt.Fprintf(w, "%s %s\n", keyword(code, level, tty), msg)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tree := func(items []string) {
|
tree := func(items []string) {
|
||||||
for i, item := range items {
|
for i, item := range items {
|
||||||
|
|
@ -58,9 +67,13 @@ func runDoctor(w io.Writer) bool {
|
||||||
if i == len(items)-1 {
|
if i == len(items)-1 {
|
||||||
connector = "└── "
|
connector = "└── "
|
||||||
}
|
}
|
||||||
|
if lastFail && tty {
|
||||||
|
fmt.Fprintf(w, "\033[1m %s%s\033[0m\n", connector, item)
|
||||||
|
} else {
|
||||||
fmt.Fprintf(w, " %s%s\n", connector, item)
|
fmt.Fprintf(w, " %s%s\n", connector, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Version + platform
|
// 1. Version + platform
|
||||||
emit("ok", fmt.Sprintf("%s (%s/%s)", version, runtime.GOOS, runtime.GOARCH))
|
emit("ok", fmt.Sprintf("%s (%s/%s)", version, runtime.GOOS, runtime.GOARCH))
|
||||||
|
|
@ -117,6 +130,7 @@ func runDoctor(w io.Writer) bool {
|
||||||
}
|
}
|
||||||
if configErr != nil {
|
if configErr != nil {
|
||||||
issues = append(issues, fmt.Sprintf("Parse error: %v", configErr))
|
issues = append(issues, fmt.Sprintf("Parse error: %v", configErr))
|
||||||
|
issues = append(issues, "While broken, ONLY 'doctor', 'config edit', and 'config init' will function")
|
||||||
issues = append(issues, "Fix with 'pda config edit' or 'pda config init --new'")
|
issues = append(issues, "Fix with 'pda config edit' or 'pda config init --new'")
|
||||||
}
|
}
|
||||||
if unexpectedFiles(cfgDir, map[string]bool{
|
if unexpectedFiles(cfgDir, map[string]bool{
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ func TestDoctorCleanEnv(t *testing.T) {
|
||||||
configDir := t.TempDir()
|
configDir := t.TempDir()
|
||||||
t.Setenv("PDA_DATA", dataDir)
|
t.Setenv("PDA_DATA", dataDir)
|
||||||
t.Setenv("PDA_CONFIG", configDir)
|
t.Setenv("PDA_CONFIG", configDir)
|
||||||
|
saved := configErr
|
||||||
|
configErr = nil
|
||||||
|
t.Cleanup(func() { configErr = saved })
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
hasError := runDoctor(&buf)
|
hasError := runDoctor(&buf)
|
||||||
|
|
@ -40,6 +43,9 @@ func TestDoctorWithStores(t *testing.T) {
|
||||||
configDir := t.TempDir()
|
configDir := t.TempDir()
|
||||||
t.Setenv("PDA_DATA", dataDir)
|
t.Setenv("PDA_DATA", dataDir)
|
||||||
t.Setenv("PDA_CONFIG", configDir)
|
t.Setenv("PDA_CONFIG", configDir)
|
||||||
|
saved := configErr
|
||||||
|
configErr = nil
|
||||||
|
t.Cleanup(func() { configErr = saved })
|
||||||
|
|
||||||
content := "{\"key\":\"foo\",\"value\":\"bar\",\"encoding\":\"text\"}\n" +
|
content := "{\"key\":\"foo\",\"value\":\"bar\",\"encoding\":\"text\"}\n" +
|
||||||
"{\"key\":\"baz\",\"value\":\"qux\",\"encoding\":\"text\"}\n"
|
"{\"key\":\"baz\",\"value\":\"qux\",\"encoding\":\"text\"}\n"
|
||||||
|
|
|
||||||
21
cmd/msg.go
21
cmd/msg.go
|
|
@ -31,24 +31,33 @@ func stdoutIsTerminal() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// keyword returns a right-aligned, colored keyword (color only on TTY).
|
// keyword returns a right-aligned, colored keyword (color only on TTY).
|
||||||
|
// All keywords are bold except dim (code "2").
|
||||||
//
|
//
|
||||||
// FAIL red (stderr)
|
// FAIL bold red (stderr)
|
||||||
// hint dim (stderr)
|
// hint dim (stderr)
|
||||||
// WARN yellow (stderr)
|
// WARN bold yellow (stderr)
|
||||||
// info blue (stderr)
|
// info bold blue (stderr)
|
||||||
// ok green (stderr)
|
// ok bold green (stderr)
|
||||||
// ? cyan (stdout)
|
// ? bold cyan (stdout)
|
||||||
// > dim (stdout)
|
// > dim (stdout)
|
||||||
func keyword(code, word string, tty bool) string {
|
func keyword(code, word string, tty bool) string {
|
||||||
padded := fmt.Sprintf("%4s", word)
|
padded := fmt.Sprintf("%4s", word)
|
||||||
if tty {
|
if tty {
|
||||||
|
if code != "2" {
|
||||||
|
code = "1;" + code
|
||||||
|
}
|
||||||
return fmt.Sprintf("\033[%sm%s\033[0m", code, padded)
|
return fmt.Sprintf("\033[%sm%s\033[0m", code, padded)
|
||||||
}
|
}
|
||||||
return padded
|
return padded
|
||||||
}
|
}
|
||||||
|
|
||||||
func printError(err error) {
|
func printError(err error) {
|
||||||
fmt.Fprintf(os.Stderr, "%s %s\n", keyword("31", "FAIL", stderrIsTerminal()), err)
|
tty := stderrIsTerminal()
|
||||||
|
if tty {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s \033[1m%s\033[0m\n", keyword("31", "FAIL", true), err)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s %s\n", keyword("31", "FAIL", false), err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printHint(format string, args ...any) {
|
func printHint(format string, args ...any) {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ THE SOFTWARE.
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
@ -40,7 +41,7 @@ func Execute() {
|
||||||
if configErr != nil {
|
if configErr != nil {
|
||||||
cmd, _, _ := rootCmd.Find(os.Args[1:])
|
cmd, _, _ := rootCmd.Find(os.Args[1:])
|
||||||
if !configSafeCmd(cmd) {
|
if !configSafeCmd(cmd) {
|
||||||
infof("Running pda! doctor")
|
printError(fmt.Errorf("fatal problem: running pda! doctor automatically"))
|
||||||
runDoctor(os.Stderr)
|
runDoctor(os.Stderr)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue