From e2f9e6b180f28735096e8ce70dbe734723fd45c7 Mon Sep 17 00:00:00 2001 From: Huan Xu Date: Sat, 22 Apr 2023 21:43:11 -0500 Subject: [PATCH] feat: confirm `envd destroy` when path and name are both empty (#1568) * feat: fail `envd destroy` when path and name are both empty * fix: display user confirmation innstead of failing destroy * feat: additional comment for better clarity --- pkg/app/destroy.go | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/pkg/app/destroy.go b/pkg/app/destroy.go index a8c0be443..16404ab5f 100644 --- a/pkg/app/destroy.go +++ b/pkg/app/destroy.go @@ -15,9 +15,13 @@ package app import ( + "bufio" + "fmt" + "os" "path/filepath" "github.com/cockroachdb/errors" + "github.com/mattn/go-isatty" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" @@ -51,19 +55,36 @@ var CommandDestroy = &cli.Command{ Action: destroy, } +// Prompts the user to confirm an operation with [Y/n]. +// If the output is not tty, it will return false automatically. +func confirm(prompt string) bool { + isTerminal := isatty.IsTerminal(os.Stdout.Fd()) + if !isTerminal { + return false + } + + reader := bufio.NewReader(os.Stdin) + fmt.Printf("%s [Y/n] ", prompt) + response, err := reader.ReadString('\n') + if err != nil { + return false + } + + response = response[:len(response)-1] // Remove newline character + return response == "y" || response == "Y" || response == "yes" || response == "Yes" +} + func destroy(clicontext *cli.Context) error { path := clicontext.Path("path") name := clicontext.String("name") if path != "" && name != "" { return errors.New("Cannot specify --path and --name at the same time.") } - if path == "" && name == "" { - path = "." - } + var ctrName string if name != "" { ctrName = name - } else { + } else if path != "" { buildContext, err := filepath.Abs(path) if err != nil { return errors.Wrap(err, "failed to get absolute path of the build context") @@ -72,7 +93,22 @@ func destroy(clicontext *cli.Context) error { if err != nil { return errors.Wrap(err, "failed to create an env name") } + } else { + // Both path and name are empty + // Destroy the environment in the current directory only if user confirms + buildContext, err := filepath.Abs(".") + if err != nil { + return errors.Wrap(err, "failed to get absolute path of the build context") + } + ctrName, err = buildutil.CreateEnvNameFromDir(buildContext) + if err != nil { + return errors.Wrap(err, "failed to create an env name") + } + if !confirm(fmt.Sprintf("Are you sure you want to destroy container %s in the current directory?", ctrName)) { + return nil + } } + context, err := home.GetManager().ContextGetCurrent() if err != nil { return errors.Wrap(err, "failed to get the current context")