mirror of
https://github.com/docker/compose.git
synced 2025-05-31 20:00:12 +02:00
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 {
|
if options.Force {
|
||||||
fmt.Fprintln(s.stdout(), msg)
|
fmt.Fprintln(s.stdout(), msg)
|
||||||
} else {
|
} else {
|
||||||
confirm, err := prompt.User{}.Confirm(msg, false)
|
confirm, err := prompt.NewPrompt(s.stdin(), s.stdout()).Confirm(msg, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -17,42 +17,58 @@
|
|||||||
package prompt
|
package prompt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/AlecAivazis/survey/v2"
|
"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
|
//go:generate mockgen -destination=./prompt_mock.go -self_package "github.com/docker/compose/v2/pkg/prompt" -package=prompt . UI
|
||||||
|
|
||||||
// UI - prompt user input
|
// UI - prompt user input
|
||||||
type UI interface {
|
type UI interface {
|
||||||
Select(message string, options []string) (int, error)
|
|
||||||
Input(message string, defaultValue string) (string, error)
|
|
||||||
Confirm(message string, defaultValue bool) (bool, error)
|
Confirm(message string, defaultValue bool) (bool, error)
|
||||||
Password(message string) (string, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// User - aggregates prompt methods
|
func NewPrompt(stdin *streams.In, stdout *streams.Out) UI {
|
||||||
type User struct{}
|
if stdin.IsTerminal() {
|
||||||
|
return User{stdin: streamsFileReader{stdin}, stdout: streamsFileWriter{stdout}}
|
||||||
// Select - displays a list
|
|
||||||
func (u User) Select(message string, options []string) (int, error) {
|
|
||||||
qs := &survey.Select{
|
|
||||||
Message: message,
|
|
||||||
Options: options,
|
|
||||||
}
|
}
|
||||||
var selected int
|
return Pipe{stdin: stdin, stdout: stdout}
|
||||||
err := survey.AskOne(qs, &selected, nil)
|
|
||||||
return selected, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input text with default value
|
// User - in a terminal
|
||||||
func (u User) Input(message string, defaultValue string) (string, error) {
|
type User struct {
|
||||||
qs := &survey.Input{
|
stdout streamsFileWriter
|
||||||
Message: message,
|
stdin streamsFileReader
|
||||||
Default: defaultValue,
|
}
|
||||||
}
|
|
||||||
var s string
|
// adapt streams.Out to terminal.FileWriter
|
||||||
err := survey.AskOne(qs, &s, nil)
|
type streamsFileWriter struct {
|
||||||
return s, err
|
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
|
// Confirm asks for yes or no input
|
||||||
@ -62,17 +78,24 @@ func (u User) Confirm(message string, defaultValue bool) (bool, error) {
|
|||||||
Default: defaultValue,
|
Default: defaultValue,
|
||||||
}
|
}
|
||||||
var b bool
|
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
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Password implements a text input with masked characters.
|
// Pipe - aggregates prompt methods
|
||||||
func (u User) Password(message string) (string, error) {
|
type Pipe struct {
|
||||||
qs := &survey.Password{
|
stdout io.Writer
|
||||||
Message: message,
|
stdin io.Reader
|
||||||
}
|
}
|
||||||
var p string
|
|
||||||
err := survey.AskOne(qs, &p, nil)
|
// Confirm asks for yes or no input
|
||||||
return p, err
|
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
|
// StringToBool converts a string to a boolean ignoring errors
|
||||||
func StringToBool(s string) bool {
|
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
|
return b
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user