17
17
package prompt
18
18
19
19
import (
20
+ "fmt"
21
+ "io"
22
+
20
23
"github.com/AlecAivazis/survey/v2"
24
+ "github.com/docker/cli/cli/streams"
25
+ "github.com/docker/compose/v2/pkg/utils"
21
26
)
22
27
23
28
//go:generate mockgen -destination=./prompt_mock.go -self_package "github.com/docker/compose/v2/pkg/prompt" -package=prompt . UI
24
29
25
30
// UI - prompt user input
26
31
type UI interface {
27
- Select (message string , options []string ) (int , error )
28
- Input (message string , defaultValue string ) (string , error )
29
32
Confirm (message string , defaultValue bool ) (bool , error )
30
- Password (message string ) (string , error )
31
33
}
32
34
33
- // User - aggregates prompt methods
34
- type User struct {}
35
-
36
- // Select - displays a list
37
- func (u User ) Select (message string , options []string ) (int , error ) {
38
- qs := & survey.Select {
39
- Message : message ,
40
- Options : options ,
35
+ func NewPrompt (stdin * streams.In , stdout * streams.Out ) UI {
36
+ if stdin .IsTerminal () {
37
+ return User {stdin : streamsFileReader {stdin }, stdout : streamsFileWriter {stdout }}
41
38
}
42
- var selected int
43
- err := survey .AskOne (qs , & selected , nil )
44
- return selected , err
39
+ return Pipe {stdin : stdin , stdout : stdout }
45
40
}
46
41
47
- // Input text with default value
48
- func (u User ) Input (message string , defaultValue string ) (string , error ) {
49
- qs := & survey.Input {
50
- Message : message ,
51
- Default : defaultValue ,
52
- }
53
- var s string
54
- err := survey .AskOne (qs , & s , nil )
55
- return s , err
42
+ // User - in a terminal
43
+ type User struct {
44
+ stdout streamsFileWriter
45
+ stdin streamsFileReader
46
+ }
47
+
48
+ // adapt streams.Out to terminal.FileWriter
49
+ type streamsFileWriter struct {
50
+ stream * streams.Out
51
+ }
52
+
53
+ func (s streamsFileWriter ) Write (p []byte ) (n int , err error ) {
54
+ return s .stream .Write (p )
55
+ }
56
+
57
+ func (s streamsFileWriter ) Fd () uintptr {
58
+ return s .stream .FD ()
59
+ }
60
+
61
+ // adapt streams.In to terminal.FileReader
62
+ type streamsFileReader struct {
63
+ stream * streams.In
64
+ }
65
+
66
+ func (s streamsFileReader ) Read (p []byte ) (n int , err error ) {
67
+ return s .stream .Read (p )
68
+ }
69
+
70
+ func (s streamsFileReader ) Fd () uintptr {
71
+ return s .stream .FD ()
56
72
}
57
73
58
74
// Confirm asks for yes or no input
@@ -62,17 +78,24 @@ func (u User) Confirm(message string, defaultValue bool) (bool, error) {
62
78
Default : defaultValue ,
63
79
}
64
80
var b bool
65
- err := survey .AskOne (qs , & b , nil )
81
+ err := survey .AskOne (qs , & b , func (options * survey.AskOptions ) error {
82
+ options .Stdio .In = u .stdin
83
+ options .Stdio .Out = u .stdout
84
+ return nil
85
+ })
66
86
return b , err
67
87
}
68
88
69
- // Password implements a text input with masked characters.
70
- func (u User ) Password (message string ) (string , error ) {
71
- qs := & survey.Password {
72
- Message : message ,
73
- }
74
- var p string
75
- err := survey .AskOne (qs , & p , nil )
76
- return p , err
89
+ // Pipe - aggregates prompt methods
90
+ type Pipe struct {
91
+ stdout io.Writer
92
+ stdin io.Reader
93
+ }
77
94
95
+ // Confirm asks for yes or no input
96
+ func (u Pipe ) Confirm (message string , defaultValue bool ) (bool , error ) {
97
+ fmt .Fprint (u .stdout , message )
98
+ var answer string
99
+ fmt .Scanln (& answer )
100
+ return utils .StringToBool (answer ), nil
78
101
}
0 commit comments