-
Notifications
You must be signed in to change notification settings - Fork 699
limactl help and info flag should show available plugins #4009
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,11 +4,9 @@ | |
package main | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"runtime" | ||
"strings" | ||
|
@@ -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" | ||
) | ||
|
||
|
@@ -51,7 +51,7 @@ func main() { | |
rootCmd := newApp() | ||
if err := executeWithPluginSupport(rootCmd, os.Args[1:]); err != nil { | ||
server.StopAllExternalDrivers() | ||
handleExitError(err) | ||
usrlocalsharelima.HandleExitError(err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
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) | ||
} | ||
|
||
|
@@ -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(), | ||
|
@@ -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 { | ||
olamilekan000 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 { | ||
olamilekan000 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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. | ||
|
There was a problem hiding this comment.
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: