github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/cmd/helpers.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cmd 5 6 import ( 7 "bufio" 8 "fmt" 9 "io" 10 "strings" 11 12 "github.com/juju/cmd/v3" 13 "github.com/juju/errors" 14 ) 15 16 // This file contains helper functions for generic operations commonly needed 17 // when implementing a command. 18 19 const yesNoMsg = "\nContinue [y/N]? " 20 21 var nameVerificationMsg = "\nTo continue, enter the name of the %s to be destroyed: " 22 23 type userAbortedError string 24 25 func (e userAbortedError) Error() string { 26 return string(e) 27 } 28 29 // IsUserAbortedError returns true if err is of type userAbortedError. 30 func IsUserAbortedError(err error) bool { 31 _, ok := errors.Cause(err).(userAbortedError) 32 return ok 33 } 34 35 // UserConfirmYes returns an error if we do not read a "y" or "yes" from user 36 // input. 37 func UserConfirmYes(ctx *cmd.Context) error { 38 fmt.Fprint(ctx.Stderr, yesNoMsg) 39 scanner := bufio.NewScanner(ctx.Stdin) 40 scanner.Scan() 41 err := scanner.Err() 42 if err != nil && err != io.EOF { 43 return errors.Trace(err) 44 } 45 answer := strings.ToLower(scanner.Text()) 46 if answer != "y" && answer != "yes" { 47 return errors.Trace(userAbortedError("aborted")) 48 } 49 return nil 50 } 51 52 // UserConfirmName returns an error if we do not read a "name" of the model/controller/etc from user 53 // input. 54 func UserConfirmName(verificationName string, objectType string, ctx *cmd.Context) error { 55 fmt.Fprintf(ctx.Stderr, nameVerificationMsg, objectType) 56 scanner := bufio.NewScanner(ctx.Stdin) 57 scanner.Scan() 58 err := scanner.Err() 59 if err != nil && err != io.EOF { 60 return errors.Trace(err) 61 } 62 answer := strings.ToLower(scanner.Text()) 63 if answer != verificationName { 64 return errors.Trace(userAbortedError("aborted")) 65 } 66 return nil 67 }