mirror of https://github.com/docker/compose.git
use a simpler prompt implementation when we lack a terminal
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
a226d014b8
commit
f1313f3a09
|
@ -61,7 +61,7 @@ func (s *composeService) Remove(ctx context.Context, projectName string, options
|
|||
if options.Force {
|
||||
fmt.Fprintln(s.stdout(), msg)
|
||||
} else {
|
||||
confirm, err := prompt.User{}.Confirm(msg, false)
|
||||
confirm, err := prompt.NewPrompt(s.stdin(), s.stdout()).Confirm(msg, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,42 +17,58 @@
|
|||
package prompt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=./prompt_mock.go -self_package "github.com/docker/compose/v2/pkg/prompt" -package=prompt . UI
|
||||
|
||||
// UI - prompt user input
|
||||
type UI interface {
|
||||
Select(message string, options []string) (int, error)
|
||||
Input(message string, defaultValue string) (string, error)
|
||||
Confirm(message string, defaultValue bool) (bool, error)
|
||||
Password(message string) (string, error)
|
||||
}
|
||||
|
||||
// User - aggregates prompt methods
|
||||
type User struct{}
|
||||
|
||||
// Select - displays a list
|
||||
func (u User) Select(message string, options []string) (int, error) {
|
||||
qs := &survey.Select{
|
||||
Message: message,
|
||||
Options: options,
|
||||
func NewPrompt(stdin *streams.In, stdout *streams.Out) UI {
|
||||
if stdin.IsTerminal() {
|
||||
return User{stdin: streamsFileReader{stdin}, stdout: streamsFileWriter{stdout}}
|
||||
}
|
||||
var selected int
|
||||
err := survey.AskOne(qs, &selected, nil)
|
||||
return selected, err
|
||||
return Pipe{stdin: stdin, stdout: stdout}
|
||||
}
|
||||
|
||||
// Input text with default value
|
||||
func (u User) Input(message string, defaultValue string) (string, error) {
|
||||
qs := &survey.Input{
|
||||
Message: message,
|
||||
Default: defaultValue,
|
||||
}
|
||||
var s string
|
||||
err := survey.AskOne(qs, &s, nil)
|
||||
return s, err
|
||||
// User - in a terminal
|
||||
type User struct {
|
||||
stdout streamsFileWriter
|
||||
stdin streamsFileReader
|
||||
}
|
||||
|
||||
// adapt streams.Out to terminal.FileWriter
|
||||
type streamsFileWriter struct {
|
||||
stream *streams.Out
|
||||
}
|
||||
|
||||
func (s streamsFileWriter) Write(p []byte) (n int, err error) {
|
||||
return s.stream.Write(p)
|
||||
}
|
||||
|
||||
func (s streamsFileWriter) Fd() uintptr {
|
||||
return s.stream.FD()
|
||||
}
|
||||
|
||||
// adapt streams.In to terminal.FileReader
|
||||
type streamsFileReader struct {
|
||||
stream *streams.In
|
||||
}
|
||||
|
||||
func (s streamsFileReader) Read(p []byte) (n int, err error) {
|
||||
return s.stream.Read(p)
|
||||
}
|
||||
|
||||
func (s streamsFileReader) Fd() uintptr {
|
||||
return s.stream.FD()
|
||||
}
|
||||
|
||||
// Confirm asks for yes or no input
|
||||
|
@ -62,17 +78,24 @@ func (u User) Confirm(message string, defaultValue bool) (bool, error) {
|
|||
Default: defaultValue,
|
||||
}
|
||||
var b bool
|
||||
err := survey.AskOne(qs, &b, nil)
|
||||
err := survey.AskOne(qs, &b, func(options *survey.AskOptions) error {
|
||||
options.Stdio.In = u.stdin
|
||||
options.Stdio.Out = u.stdout
|
||||
return nil
|
||||
})
|
||||
return b, err
|
||||
}
|
||||
|
||||
// Password implements a text input with masked characters.
|
||||
func (u User) Password(message string) (string, error) {
|
||||
qs := &survey.Password{
|
||||
Message: message,
|
||||
}
|
||||
var p string
|
||||
err := survey.AskOne(qs, &p, nil)
|
||||
return p, err
|
||||
|
||||
// Pipe - aggregates prompt methods
|
||||
type Pipe struct {
|
||||
stdout io.Writer
|
||||
stdin io.Reader
|
||||
}
|
||||
|
||||
// Confirm asks for yes or no input
|
||||
func (u Pipe) Confirm(message string, defaultValue bool) (bool, error) {
|
||||
fmt.Fprint(u.stdout, message)
|
||||
var answer string
|
||||
fmt.Scanln(&answer)
|
||||
return utils.StringToBool(answer), nil
|
||||
}
|
||||
|
|
|
@ -33,6 +33,10 @@ func StringContains(array []string, needle string) bool {
|
|||
|
||||
// StringToBool converts a string to a boolean ignoring errors
|
||||
func StringToBool(s string) bool {
|
||||
b, _ := strconv.ParseBool(strings.ToLower(strings.TrimSpace(s)))
|
||||
s = strings.ToLower(strings.TrimSpace(s))
|
||||
if s == "y" {
|
||||
return true
|
||||
}
|
||||
b, _ := strconv.ParseBool(s)
|
||||
return b
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue