Skip to content

Commit

Permalink
fix: stdin should be echoed to stderr by convention (#2211)
Browse files Browse the repository at this point in the history
  • Loading branch information
sweatybridge committed Apr 25, 2024
1 parent 1c01e8e commit bdb60ab
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 31 deletions.
5 changes: 1 addition & 4 deletions cmd/bootstrap.go
Expand Up @@ -30,10 +30,7 @@ var (
RunE: func(cmd *cobra.Command, args []string) error {
if !viper.IsSet("WORKDIR") {
title := fmt.Sprintf("Enter a directory to bootstrap your project (or leave blank to use %s): ", utils.Bold(utils.CurrentDirAbs))
workdir, err := utils.NewConsole().PromptText(title)
if err != nil {
return err
}
workdir := utils.NewConsole().PromptText(title)
viper.Set("WORKDIR", workdir)
}
ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt)
Expand Down
7 changes: 4 additions & 3 deletions cmd/branches.go
Expand Up @@ -177,11 +177,12 @@ func promptBranchId(ctx context.Context, ref string) error {
if len(gitBranch) > 0 {
title = fmt.Sprintf("%-2s (or leave blank to use %s): ", title, utils.Aqua(gitBranch))
}
if name, err := console.PromptText(title); err != nil {
return err
} else if len(name) > 0 {
if name := console.PromptText(title); len(name) > 0 {
gitBranch = name
}
if len(gitBranch) == 0 {
return errors.New("git branch cannot be empty")
}
for _, branch := range *resp.JSON200 {
if branch.Name == gitBranch {
branchId = branch.Id
Expand Down
11 changes: 4 additions & 7 deletions internal/projects/create/create.go
Expand Up @@ -73,14 +73,11 @@ func promptMissingParams(ctx context.Context, body *api.CreateProjectBody) error
}

func promptProjectName() (string, error) {
name, err := utils.NewConsole().PromptText("Enter your project name: ")
if err != nil {
return "", err
}
if len(name) == 0 {
return "", errors.New("project name cannot be empty")
title := "Enter your project name: "
if name := utils.NewConsole().PromptText(title); len(name) > 0 {
return name, nil
}
return name, nil
return "", errors.New("project name cannot be empty")
}

func promptOrgId(ctx context.Context) (string, error) {
Expand Down
28 changes: 11 additions & 17 deletions internal/utils/console.go
Expand Up @@ -7,23 +7,20 @@ import (
"os"
"strings"

"github.com/go-errors/errors"
"golang.org/x/term"
)

type Console struct {
IsTTY bool
stdin *bufio.Scanner
stdout io.Writer
stderr io.Writer
logger io.Writer
}

func NewConsole() Console {
return Console{
IsTTY: term.IsTerminal(int(os.Stdin.Fd())),
stdin: bufio.NewScanner(os.Stdin),
stdout: os.Stdout,
stderr: GetDebugLogger(),
logger: GetDebugLogger(),
}
}

Expand All @@ -35,13 +32,10 @@ func (c Console) PromptYesNo(label string, def bool) bool {
}
labelWithChoice := fmt.Sprintf("%s [%s] ", label, choices)
// Any error will be handled as default value
if s, err := c.PromptText(labelWithChoice); err != nil {
fmt.Fprintln(c.stdout)
if !errors.Is(err, io.EOF) {
fmt.Fprintln(c.stderr, err)
if input := c.PromptText(labelWithChoice); len(input) > 0 {
if answer := parseYesNo(input); answer != nil {
return *answer
}
} else if answer := parseYesNo(s); answer != nil {
return *answer
}
return def
}
Expand All @@ -58,19 +52,19 @@ func parseYesNo(s string) *bool {
}

// PromptText asks for input using the label.
func (c Console) PromptText(label string) (string, error) {
func (c Console) PromptText(label string) string {
fmt.Fprint(os.Stderr, label)
// Scan a single line from input or file
if !c.stdin.Scan() {
return "", errors.New(io.EOF)
fmt.Fprintln(c.logger, io.EOF)
}
if err := c.stdin.Err(); err != nil {
return "", errors.Errorf("failed to scan stdin: %w", err)
fmt.Fprintln(c.logger, err)
}
token := strings.TrimSpace(c.stdin.Text())
// Echo input from non-interactive terminal
// Echo input to stderr for non-interactive terminals
if !c.IsTTY {
fmt.Fprintln(c.stdout, token)
fmt.Fprintln(os.Stderr, token)
}
return token, nil
return token
}

0 comments on commit bdb60ab

Please sign in to comment.