@@ -2,6 +2,7 @@ package cmd
22
33import (
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