@@ -18,35 +18,37 @@ var (
1818
1919// IO is an interface to work with input/output.
2020type IO interface {
21- Stdin () Reader
22- Stdout () Writer
23- Prompts () (Reader , Writer , error )
21+ Stdin () io.Reader
22+ Stdout () io.Writer
23+ Prompts () (io.Reader , io.Writer , error )
24+ IsStdinPiped () bool
25+ IsStdoutPiped () bool
2426}
2527
2628// UserIO is a middleware between input and output to the CLI program.
2729// It implements userIO.Prompter and can be passed to libraries.
2830type UserIO struct {
29- Input Reader
30- Output Writer
31- tty file
31+ Input * os. File
32+ Output * os. File
33+ tty * os. File
3234 ttyAvailable bool
3335}
3436
3537// NewStdUserIO creates a new UserIO middleware only from os.Stdin and os.Stdout.
3638func NewStdUserIO () UserIO {
3739 return UserIO {
38- Input : file { os .Stdin } ,
39- Output : file { os .Stdout } ,
40+ Input : os .Stdin ,
41+ Output : os .Stdout ,
4042 }
4143}
4244
4345// Stdin returns the UserIO's Input.
44- func (o UserIO ) Stdin () Reader {
46+ func (o UserIO ) Stdin () io. Reader {
4547 return o .Input
4648}
4749
4850// Stdout returns the UserIO's Output.
49- func (o UserIO ) Stdout () Writer {
51+ func (o UserIO ) Stdout () io. Writer {
5052 return o .Output
5153}
5254
@@ -55,8 +57,8 @@ func (o UserIO) Stdout() Writer {
5557// bypass stdin and stdout by connecting to /dev/tty on Unix systems when
5658// available. On systems where tty is not available and when either input
5759// or output is piped, prompting is not possible so an error is returned.
58- func (o UserIO ) Prompts () (Reader , Writer , error ) {
59- if o .Input . IsPiped () || o .Output . IsPiped () {
60+ func (o UserIO ) Prompts () (io. Reader , io. Writer , error ) {
61+ if o .IsStdoutPiped () || o .IsStdinPiped () {
6062 if o .ttyAvailable {
6163 return o .tty , o .tty , nil
6264 }
@@ -65,12 +67,30 @@ func (o UserIO) Prompts() (Reader, Writer, error) {
6567 return o .Input , o .Output , nil
6668}
6769
68- // Reader can read input for a CLI program.
69- type Reader interface {
70- io.Reader
71- // ReadPassword reads a line of input from a terminal without local echo.
72- ReadPassword () ([]byte , error )
73- IsPiped () bool
70+ func (o UserIO ) IsStdinPiped () bool {
71+ return isPiped (o .Input )
72+ }
73+
74+ func (o UserIO ) IsStdoutPiped () bool {
75+ return isPiped (o .Output )
76+ }
77+
78+ // readPassword reads one line of input from the terminal without echoing the user input.
79+ func readPassword (r io.Reader ) (string , error ) {
80+ file , ok := r .(* os.File )
81+ if ! ok {
82+ return "" , ErrCannotAsk
83+ }
84+ // this case happens among other things when input is piped and ReadPassword is called.
85+ if ! terminal .IsTerminal (int (file .Fd ())) {
86+ return "" , ErrCannotAsk
87+ }
88+
89+ password , err := terminal .ReadPassword (int (file .Fd ()))
90+ if err != nil {
91+ return "" , err
92+ }
93+ return string (password ), nil
7494}
7595
7696// Readln reads 1 line of input from a io.Reader. The newline character is not included in the response.
@@ -84,31 +104,10 @@ func Readln(r io.Reader) (string, error) {
84104 return s .Text (), nil
85105}
86106
87- // Writer can write output for a CLI program.
88- type Writer interface {
89- io.Writer
90- IsPiped () bool
91- }
92-
93- // file implements the Reader and Writer interface.
94- type file struct {
95- * os.File
96- }
97-
98- // ReadPassword reads from a terminal without echoing back the typed input.
99- func (f file ) ReadPassword () ([]byte , error ) {
100- // this case happens among other things when input is piped and ReadPassword is called.
101- if ! terminal .IsTerminal (int (f .Fd ())) {
102- return nil , ErrCannotAsk
103- }
104-
105- return terminal .ReadPassword (int (f .Fd ()))
106- }
107-
108- // IsPiped checks whether the file is a pipe.
107+ // isPiped checks whether the file is a pipe.
109108// If the file does not exist, it returns false.
110- func ( f file ) IsPiped ( ) bool {
111- stat , err := f .Stat ()
109+ func isPiped ( file * os. File ) bool {
110+ stat , err := file .Stat ()
112111 if err != nil {
113112 return false
114113 }
0 commit comments