Skip to content

Commit 6d3bc32

Browse files
committed
Allow interrupting reading strings from stdin
1 parent d1047f1 commit 6d3bc32

File tree

1 file changed

+39
-7
lines changed

1 file changed

+39
-7
lines changed

internal/tiger/cmd/auth.go

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"bufio"
5+
"context"
56
"fmt"
67
"os"
78
"strings"
@@ -103,7 +104,7 @@ Examples:
103104
}
104105
} else if creds.publicKey == "" || creds.secretKey == "" || creds.projectID == "" {
105106
// If some credentials were provided, prompt for missing ones
106-
creds, err = promptForCredentials(cfg.ConsoleURL, creds)
107+
creds, err = promptForCredentials(cmd.Context(), cfg.ConsoleURL, creds)
107108
if err != nil {
108109
return fmt.Errorf("failed to get credentials: %w", err)
109110
}
@@ -209,7 +210,7 @@ func flagOrEnvVar(flagVal, envVarName string) string {
209210
}
210211

211212
// promptForCredentials prompts the user to enter any missing credentials
212-
func promptForCredentials(consoleURL string, creds credentials) (credentials, error) {
213+
func promptForCredentials(ctx context.Context, consoleURL string, creds credentials) (credentials, error) {
213214
// Check if we're in a terminal for interactive input
214215
if !util.IsTerminal(os.Stdin) {
215216
return credentials{}, fmt.Errorf("TTY not detected - credentials required. Use flags (--public-key, --secret-key, --project-id) or environment variables (TIGER_PUBLIC_KEY, TIGER_SECRET_KEY, TIGER_PROJECT_ID)")
@@ -222,17 +223,20 @@ func promptForCredentials(consoleURL string, creds credentials) (credentials, er
222223
// Prompt for public key if missing
223224
if creds.publicKey == "" {
224225
fmt.Print("Enter your public key: ")
225-
publicKey, err := reader.ReadString('\n')
226+
publicKey, err := readString(ctx, func() (string, error) { return reader.ReadString('\n') })
226227
if err != nil {
227228
return credentials{}, err
228229
}
229-
creds.publicKey = strings.TrimSpace(publicKey)
230+
creds.publicKey = publicKey
230231
}
231232

232233
// Prompt for secret key if missing
233234
if creds.secretKey == "" {
234235
fmt.Print("Enter your secret key: ")
235-
bytePassword, err := term.ReadPassword(int(os.Stdin.Fd()))
236+
bytePassword, err := readString(ctx, func() (string, error) {
237+
val, err := term.ReadPassword(int(os.Stdin.Fd()))
238+
return string(val), err
239+
})
236240
if err != nil {
237241
return credentials{}, err
238242
}
@@ -243,12 +247,40 @@ func promptForCredentials(consoleURL string, creds credentials) (credentials, er
243247
// Prompt for project ID if missing
244248
if creds.projectID == "" {
245249
fmt.Print("Enter your project ID: ")
246-
projectID, err := reader.ReadString('\n')
250+
projectID, err := readString(ctx, func() (string, error) { return reader.ReadString('\n') })
247251
if err != nil {
248252
return credentials{}, err
249253
}
250-
creds.projectID = strings.TrimSpace(projectID)
254+
creds.projectID = projectID
251255
}
252256

253257
return creds, nil
254258
}
259+
260+
func readString(ctx context.Context, readFn func() (string, error)) (string, error) {
261+
valCh := make(chan string)
262+
errCh := make(chan error)
263+
defer func() { close(valCh); close(errCh) }()
264+
go func() {
265+
val, err := readFn()
266+
if err != nil {
267+
errCh <- err
268+
return
269+
}
270+
select {
271+
case <-ctx.Done(): // don't return an empty value if the context is already canceled
272+
return
273+
default:
274+
}
275+
valCh <- val
276+
}()
277+
278+
select {
279+
case <-ctx.Done():
280+
return "", ctx.Err()
281+
case err := <-errCh:
282+
return "", err
283+
case val := <-valCh:
284+
return val, nil
285+
}
286+
}

0 commit comments

Comments
 (0)