Skip to content

Commit

Permalink
limactl shell: ask whether to start the instance if not running
Browse files Browse the repository at this point in the history
Signed-off-by: Jan Dubois <jan.dubois@suse.com>
  • Loading branch information
jandubois committed Nov 3, 2024
1 parent 9c21e15 commit cabc268
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 35 deletions.
35 changes: 6 additions & 29 deletions cmd/limactl/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@ import (
"github.com/lima-vm/lima/cmd/limactl/editflags"
"github.com/lima-vm/lima/cmd/limactl/guessarg"
"github.com/lima-vm/lima/pkg/editutil"
"github.com/lima-vm/lima/pkg/instance"
"github.com/lima-vm/lima/pkg/limayaml"
networks "github.com/lima-vm/lima/pkg/networks/reconcile"
"github.com/lima-vm/lima/pkg/store"
"github.com/lima-vm/lima/pkg/store/filenames"
"github.com/lima-vm/lima/pkg/uiutil"
"github.com/lima-vm/lima/pkg/yqutil"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -132,34 +129,14 @@ func editAction(cmd *cobra.Command, args []string) error {
}
if inst != nil {
logrus.Infof("Instance %q configuration edited", inst.Name)
}

if !tty {
// use "start" to start it
return nil
}
if inst == nil {
// edited a limayaml file directly
return nil
}
startNow, err := askWhetherToStart()
if err != nil {
return err
}
if !startNow {
return nil
}
ctx := cmd.Context()
err = networks.Reconcile(ctx, inst.Name)
if err != nil {
tty, err := interactive(cmd)
if tty && err == nil {
err = askToStart(cmd, inst.Name, false)
}
return err
}
return instance.Start(ctx, inst, "", false)
}

func askWhetherToStart() (bool, error) {
message := "Do you want to start the instance now? "
return uiutil.Confirm(message, true)
// inst is nil if edited a limayaml file directly
return nil
}

func editBashComplete(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
Expand Down
28 changes: 25 additions & 3 deletions cmd/limactl/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func newShellCommand() *cobra.Command {
}

func shellAction(cmd *cobra.Command, args []string) error {
_ = os.Setenv("_LIMACTL_SHELL_IN_ACTION", "")
// simulate the behavior of double dash
newArg := []string{}
if len(args) >= 2 && args[1] == "--" {
Expand All @@ -68,15 +69,36 @@ func shellAction(cmd *cobra.Command, args []string) error {
}
}

tty, err := interactive(cmd)
if err != nil {
return err
}
inst, err := store.Inspect(instName)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
if !errors.Is(err, os.ErrNotExist) {
return err
}
if !tty {
return fmt.Errorf("instance %q does not exist, run `limactl create %s` to create a new instance", instName, instName)
}
if err := askToStart(cmd, instName, true); err != nil {
return err
}
inst, err = store.Inspect(instName)
} else if inst.Status == store.StatusStopped {
if !tty {
return fmt.Errorf("instance %q is stopped, run `limactl start %s` to start the instance", instName, instName)
}
if err := askToStart(cmd, instName, false); err != nil {
return err
}
inst, err = store.Inspect(instName)
}
if err != nil {
return err
}
if inst.Status == store.StatusStopped {
return fmt.Errorf("instance %q is stopped, run `limactl start %s` to start the instance", instName, instName)
if inst.Status != store.StatusRunning {
return fmt.Errorf("instance %q status is not %q but %q", inst.Name, store.StatusRunning, inst.Status)
}

// When workDir is explicitly set, the shell MUST have workDir as the cwd, or exit with an error.
Expand Down
53 changes: 53 additions & 0 deletions cmd/limactl/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/lima-vm/lima/pkg/templatestore"
"github.com/lima-vm/lima/pkg/uiutil"
"github.com/lima-vm/lima/pkg/yqutil"
"github.com/mattn/go-isatty"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -529,3 +530,55 @@ func startBashComplete(cmd *cobra.Command, _ []string, _ string) ([]string, cobr
compTmpl, _ := bashCompleteTemplateNames(cmd)
return append(compInst, compTmpl...), cobra.ShellCompDirectiveDefault
}

// interactive returns true if --tty is true and both STDIN and STDOUT are terminals.
func interactive(cmd *cobra.Command) (bool, error) {
flags := cmd.Flags()
tty, err := flags.GetBool("tty")
if err != nil {
return false, err
}
if !isatty.IsTerminal(os.Stdin.Fd()) && !isatty.IsCygwinTerminal(os.Stdin.Fd()) {
tty = false
}
if !isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()) {
tty = false
}
return tty, nil
}

func askToStart(cmd *cobra.Command, instName string, create bool) error {
template := "default"
templates, err := templatestore.Templates()
if err != nil {
return err
}
for _, t := range templates {
if t.Name == instName {
template = instName
break
}
}
var message string
if create {
message = fmt.Sprintf("Do you want to create and start the instance %q using the %q template now?", instName, template)
} else {
message = fmt.Sprintf("Do you want to start the instance %q now?", instName)
}
ans, err := uiutil.Confirm(message, true)
if !ans || err != nil {
return err
}

rootCmd := cmd.Root()
if create {
// The create command shows the template chooser UI, etc.
rootCmd.SetArgs([]string{"create", "template://" + template})
if err := rootCmd.Execute(); err != nil {
return err
}
}
// The start command reconciles the networks, etc.
rootCmd.SetArgs([]string{"start", instName})
return rootCmd.Execute()
}
13 changes: 10 additions & 3 deletions pkg/instance/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,17 @@ func watchHostAgentEvents(ctx context.Context, inst *store.Instance, haStdoutPat
err = xerr
return true
}
if *inst.Config.Plain {
logrus.Infof("READY. Run `ssh -F %q %s` to open the shell.", inst.SSHConfigFile, inst.Hostname)
// _LIMACTL_SHELL_IN_ACTION is set if `limactl shell` invoked `limactl start`.
// In this case we shouldn't print "Run `lima` to open the shell",
// because the user has already executed the `lima` command.
if _, limactlShellInAction := os.LookupEnv("_LIMACTL_SHELL_IN_ACTION"); limactlShellInAction {
logrus.Infof("READY.")
} else {
logrus.Infof("READY. Run `%s` to open the shell.", LimactlShellCmd(inst.Name))
if *inst.Config.Plain {
logrus.Infof("READY. Run `ssh -F %q %s` to open the shell.", inst.SSHConfigFile, inst.Hostname)
} else {
logrus.Infof("READY. Run `%s` to open the shell.", LimactlShellCmd(inst.Name))
}
}
_ = ShowMessage(inst)
err = nil
Expand Down

0 comments on commit cabc268

Please sign in to comment.