The logging added a line to stdout, and the genesis path parses the builder's stdout as JSON — so the first log line broke the parse with "invalid character 'c'", the c from "[clone]". A build that had worked stopped working because of a print statement. The installer's runner captures stdout alone (cmd.Output), and the contract was already stdout=result, stderr=everything else. The fix is to honour it: every builder diagnostic — the step log, the per-command echo, the module path's own lines — goes to stderr. Stdout carries only once.go's result JSON. And a unit test now fails if any fmt.Print to stdout appears in the two builder command files, except the three that belong there: the result, --version, and --help. A guard, because this was invisible until a 20-minute run hit it, and the same class of mistake should fail in milliseconds next time. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
45 lines
1.3 KiB
Go
45 lines
1.3 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// **The genesis path writes its result to stdout and nothing else there.** The installer captures
|
|
// stdout alone and parses it as JSON; one stray log line makes that fail with "invalid character"
|
|
// — exactly what a builder fmt.Printf caused, breaking a build that had worked. This keeps
|
|
// diagnostics on stderr so a future print cannot repeat it silently.
|
|
func TestBuilderDiagnosticsStayOffStdout(t *testing.T) {
|
|
allowed := map[string]bool{
|
|
"string(body)": true, // once.go: the result JSON, which IS stdout
|
|
"version)": true, // --version
|
|
`"stopping")`: true, // the loop.s shutdown line
|
|
"usage)": true, // --help text, for a human
|
|
}
|
|
for _, file := range []string{"once.go", "main.go"} {
|
|
src, err := os.ReadFile(file)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for i, raw := range strings.Split(string(src), "\n") {
|
|
line := strings.TrimSpace(raw)
|
|
if !strings.HasPrefix(line, "fmt.Printf(") &&
|
|
!strings.HasPrefix(line, "fmt.Println(") &&
|
|
!strings.HasPrefix(line, "fmt.Print(") {
|
|
continue
|
|
}
|
|
ok := false
|
|
for token := range allowed {
|
|
if strings.Contains(line, token) {
|
|
ok = true
|
|
}
|
|
}
|
|
if !ok {
|
|
t.Errorf("%s:%d writes a diagnostic to stdout, which the installer parses as JSON:\n %s",
|
|
file, i+1, line)
|
|
}
|
|
}
|
|
}
|
|
}
|