Files
cheat/internal/installer/prompt.go
Christopher Allen Lane fd1465ee38 fix: avoid stdin buffering bug in installer prompts
Prompt() created a new bufio.NewReader(os.Stdin) on each call, which
buffered all piped input on the first call and left nothing for
subsequent prompts. This made cheat un-scriptable (e.g., piping answers
via printf). Fix by reading one byte at a time from os.Stdin directly.

Also adds an end-to-end integration test for the first-run experience
(regression test for #721, #771, #730) and bumps the Dockerfile to
Go 1.26.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 21:51:30 -05:00

53 lines
1017 B
Go

// Package installer implements functions that provide a first-time
// installation wizard.
package installer
import (
"fmt"
"os"
"strings"
)
// Prompt prompts the user for a answer
func Prompt(prompt string, def bool) (bool, error) {
// display the prompt
fmt.Printf("%s: ", prompt)
// read one byte at a time until newline to avoid buffering past the
// end of the current line, which would consume input intended for
// subsequent Prompt calls on the same stdin
var line []byte
buf := make([]byte, 1)
for {
n, err := os.Stdin.Read(buf)
if n > 0 {
if buf[0] == '\n' {
break
}
if buf[0] != '\r' {
line = append(line, buf[0])
}
}
if err != nil {
if len(line) > 0 {
break
}
return false, fmt.Errorf("failed to prompt: %v", err)
}
}
// normalize the answer
ans := strings.ToLower(strings.TrimSpace(string(line)))
// return the appropriate response
switch ans {
case "y":
return true, nil
case "":
return def, nil
default:
return false, nil
}
}