Skip to content
Open
Show file tree
Hide file tree
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
92 changes: 30 additions & 62 deletions cmd/limactl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
package main

import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
Expand All @@ -23,6 +21,8 @@ import (
"github.com/lima-vm/lima/v2/pkg/fsutil"
"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
"github.com/lima-vm/lima/v2/pkg/osutil"
"github.com/lima-vm/lima/v2/pkg/plugin"
"github.com/lima-vm/lima/v2/pkg/usrlocalsharelima"
"github.com/lima-vm/lima/v2/pkg/version"
)

Expand Down Expand Up @@ -51,7 +51,7 @@ func main() {
rootCmd := newApp()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit-picking: This whole block could be written like this:

	rootCmd := newApp()
	err := executeWithPluginSupport(rootCmd, os.Args[1:])
	server.StopAllExternalDrivers()
	usrlocalsharelima.HandleExitError(err)
	if err != nil {
		logrus.Fatal(err)
	}

if err := executeWithPluginSupport(rootCmd, os.Args[1:]); err != nil {
server.StopAllExternalDrivers()
handleExitError(err)
usrlocalsharelima.HandleExitError(err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usrlocalsharelima is kind of an unexpected place for this function. I would move it maybe to its own file in pkg/osutil/exit.go.

But this is nitpicking, unless there are other reasons to update the PR once more, this can also be fixed up later.

logrus.Fatal(err)
}

Expand Down Expand Up @@ -165,6 +165,8 @@ func newApp() *cobra.Command {
}
rootCmd.AddGroup(&cobra.Group{ID: "basic", Title: "Basic Commands:"})
rootCmd.AddGroup(&cobra.Group{ID: "advanced", Title: "Advanced Commands:"})
rootCmd.AddGroup(&cobra.Group{ID: "plugin", Title: "Available Plugins (Experimental):"})

rootCmd.AddCommand(
newCreateCommand(),
newStartCommand(),
Expand Down Expand Up @@ -201,79 +203,45 @@ func newApp() *cobra.Command {
return rootCmd
}

func handleExitError(err error) {
if err == nil {
return
}

var exitErr *exec.ExitError
if errors.As(err, &exitErr) {
os.Exit(exitErr.ExitCode()) //nolint:revive // it's intentional to call os.Exit in this function
return
}
}

// executeWithPluginSupport handles command execution with plugin support.
func executeWithPluginSupport(rootCmd *cobra.Command, args []string) error {
if len(args) > 0 {
cmd, _, err := rootCmd.Find(args)
if err != nil || cmd == rootCmd {
// Function calls os.Exit() if it found and executed the plugin
runExternalPlugin(rootCmd.Context(), args[0], args[1:])
rootCmd.SetArgs(args)

if err := rootCmd.ParseFlags(args); err == nil {
if debug, _ := rootCmd.Flags().GetBool("debug"); debug {
logrus.SetLevel(logrus.DebugLevel)
debugutil.Debug = true
}
}
Comment on lines +209 to 214
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It bothers me that this code block exists in 2 places. Can't it be called early enough that it covers both execution branches?

I think this here might be enough, and you can delete the copy in the PersistentPreRun command?


rootCmd.SetArgs(args)
addPluginCommands(rootCmd)

return rootCmd.Execute()
}

func runExternalPlugin(ctx context.Context, name string, args []string) {
if ctx == nil {
ctx = context.Background()
}

if err := updatePathEnv(); err != nil {
logrus.Warnf("failed to update PATH environment: %v", err)
// PATH update failure shouldn't prevent plugin execution
}

externalCmd := "limactl-" + name
execPath, err := exec.LookPath(externalCmd)
func addPluginCommands(rootCmd *cobra.Command) {
plugins, err := plugin.DiscoverPlugins()
if err != nil {
logrus.Warnf("Failed to discover plugins: %v", err)
return
}

cmd := exec.CommandContext(ctx, execPath, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = os.Environ()

err = cmd.Run()
handleExitError(err)
if err == nil {
os.Exit(0) //nolint:revive // it's intentional to call os.Exit in this function
}
logrus.Fatalf("external command %q failed: %v", execPath, err)
}

func updatePathEnv() error {
exe, err := os.Executable()
if err != nil {
return fmt.Errorf("failed to get executable path: %w", err)
}
for _, p := range plugins {
pluginName := p.Name
pluginCmd := &cobra.Command{
Use: pluginName,
Short: p.Description,
GroupID: "plugin",
DisableFlagParsing: true,
Run: func(cmd *cobra.Command, args []string) {
plugin.RunExternalPlugin(cmd.Context(), pluginName, args)
},
}

binDir := filepath.Dir(exe)
currentPath := os.Getenv("PATH")
newPath := binDir + string(filepath.ListSeparator) + currentPath
pluginCmd.SilenceUsage = true
pluginCmd.SilenceErrors = true

if err := os.Setenv("PATH", newPath); err != nil {
return fmt.Errorf("failed to set PATH environment: %w", err)
rootCmd.AddCommand(pluginCmd)
}

logrus.Debugf("updated PATH to prioritize %s", binDir)

return nil
}

// WrapArgsError annotates cobra args error with some context, so the error message is more user-friendly.
Expand Down
12 changes: 12 additions & 0 deletions pkg/limainfo/limainfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
"github.com/lima-vm/lima/v2/pkg/limayaml"
"github.com/lima-vm/lima/v2/pkg/plugin"
"github.com/lima-vm/lima/v2/pkg/registry"
"github.com/lima-vm/lima/v2/pkg/templatestore"
"github.com/lima-vm/lima/v2/pkg/usrlocalsharelima"
Expand All @@ -35,6 +36,7 @@ type LimaInfo struct {
HostOS string `json:"hostOS"` // since Lima v2.0.0
HostArch string `json:"hostArch"` // since Lima v2.0.0
IdentityFile string `json:"identityFile"` // since Lima v2.0.0
Plugins []plugin.Plugin `json:"plugins"` // since Lima v2.0.0
}

type DriverExt struct {
Expand Down Expand Up @@ -108,5 +110,15 @@ func New(ctx context.Context) (*LimaInfo, error) {
Location: bin,
}
}

plugins, err := plugin.DiscoverPlugins()
if err != nil {
logrus.WithError(err).Warn("Failed to discover plugins")
// Don't fail the entire info command if plugin discovery fails.
info.Plugins = []plugin.Plugin{}
} else {
info.Plugins = plugins
}

return info, nil
}
Loading
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.