Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

limactl shell: ask whether to start the instance if not running #2832

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
limactl shell: ask whether to start the instance if not running
Signed-off-by: Jan Dubois <jan.dubois@suse.com>
jandubois committed Nov 3, 2024
commit cabc26878694eb372a4949f2321d39204ef2dd1b
35 changes: 6 additions & 29 deletions cmd/limactl/edit.go
Original file line number Diff line number Diff line change
@@ -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"
@@ -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) {
28 changes: 25 additions & 3 deletions cmd/limactl/shell.go
Original file line number Diff line number Diff line change
@@ -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] == "--" {
@@ -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.
53 changes: 53 additions & 0 deletions cmd/limactl/start.go
Original file line number Diff line number Diff line change
@@ -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"
)
@@ -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
@@ -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