Skip to content

Commit 6bc9696

Browse files
janduboisolamilekan000
authored andcommitted
limactl help and info flag should show available plugins
Signed-off-by: olalekan odukoya <[email protected]>
2 parents ee7b66a + b385171 commit 6bc9696

File tree

10 files changed

+421
-99
lines changed

10 files changed

+421
-99
lines changed

.github/workflows/codeql.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
3333

3434
- name: Initialize CodeQL
35-
uses: github/codeql-action/init@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3.30.2
35+
uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
3636
with:
3737
languages: ${{ matrix.language }}
3838
build-mode: ${{ matrix.build-mode }}
@@ -48,6 +48,6 @@ jobs:
4848
exit 1
4949
5050
- name: Perform CodeQL Analysis
51-
uses: github/codeql-action/analyze@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3.30.2
51+
uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
5252
with:
5353
category: "/language:${{matrix.language}}"

.github/workflows/scorecard.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,6 @@ jobs:
6060
# Upload the results to GitHub's code scanning dashboard (optional).
6161
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
6262
- name: "Upload to code-scanning"
63-
uses: github/codeql-action/upload-sarif@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3.30.2
63+
uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
6464
with:
6565
sarif_file: results.sarif

cmd/limactl/main.go

Lines changed: 32 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44
package main
55

66
import (
7-
"context"
87
"errors"
98
"fmt"
109
"os"
11-
"os/exec"
1210
"path/filepath"
1311
"runtime"
1412
"strings"
@@ -23,6 +21,7 @@ import (
2321
"github.com/lima-vm/lima/v2/pkg/fsutil"
2422
"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
2523
"github.com/lima-vm/lima/v2/pkg/osutil"
24+
"github.com/lima-vm/lima/v2/pkg/plugin"
2625
"github.com/lima-vm/lima/v2/pkg/version"
2726
)
2827

@@ -49,13 +48,12 @@ func main() {
4948
}
5049
}
5150
rootCmd := newApp()
52-
if err := executeWithPluginSupport(rootCmd, os.Args[1:]); err != nil {
53-
server.StopAllExternalDrivers()
54-
handleExitError(err)
51+
err := executeWithPluginSupport(rootCmd, os.Args[1:])
52+
server.StopAllExternalDrivers()
53+
osutil.HandleExitError(err)
54+
if err != nil {
5555
logrus.Fatal(err)
5656
}
57-
58-
server.StopAllExternalDrivers()
5957
}
6058

6159
func newApp() *cobra.Command {
@@ -120,12 +118,6 @@ func newApp() *cobra.Command {
120118
return fmt.Errorf("unsupported log-format: %q", logFormat)
121119
}
122120

123-
debug, _ := cmd.Flags().GetBool("debug")
124-
if debug {
125-
logrus.SetLevel(logrus.DebugLevel)
126-
debugutil.Debug = true
127-
}
128-
129121
if osutil.IsBeingRosettaTranslated() && cmd.Parent().Name() != "completion" && cmd.Name() != "generate-doc" && cmd.Name() != "validate" {
130122
// running under rosetta would provide inappropriate runtime.GOARCH info, see: https://github.com/lima-vm/lima/issues/543
131123
// allow commands that are used for packaging to run under rosetta to allow cross-architecture builds
@@ -165,6 +157,8 @@ func newApp() *cobra.Command {
165157
}
166158
rootCmd.AddGroup(&cobra.Group{ID: "basic", Title: "Basic Commands:"})
167159
rootCmd.AddGroup(&cobra.Group{ID: "advanced", Title: "Advanced Commands:"})
160+
rootCmd.AddGroup(&cobra.Group{ID: "plugin", Title: "Available Plugins (Experimental):"})
161+
168162
rootCmd.AddCommand(
169163
newCreateCommand(),
170164
newStartCommand(),
@@ -201,79 +195,45 @@ func newApp() *cobra.Command {
201195
return rootCmd
202196
}
203197

204-
func handleExitError(err error) {
205-
if err == nil {
206-
return
207-
}
208-
209-
var exitErr *exec.ExitError
210-
if errors.As(err, &exitErr) {
211-
os.Exit(exitErr.ExitCode()) //nolint:revive // it's intentional to call os.Exit in this function
212-
return
213-
}
214-
}
215-
216-
// executeWithPluginSupport handles command execution with plugin support.
217198
func executeWithPluginSupport(rootCmd *cobra.Command, args []string) error {
218-
if len(args) > 0 {
219-
cmd, _, err := rootCmd.Find(args)
220-
if err != nil || cmd == rootCmd {
221-
// Function calls os.Exit() if it found and executed the plugin
222-
runExternalPlugin(rootCmd.Context(), args[0], args[1:])
199+
rootCmd.SetArgs(args)
200+
201+
if err := rootCmd.ParseFlags(args); err == nil {
202+
if debug, _ := rootCmd.Flags().GetBool("debug"); debug {
203+
logrus.SetLevel(logrus.DebugLevel)
204+
debugutil.Debug = true
223205
}
224206
}
225207

226-
rootCmd.SetArgs(args)
208+
addPluginCommands(rootCmd)
209+
227210
return rootCmd.Execute()
228211
}
229212

230-
func runExternalPlugin(ctx context.Context, name string, args []string) {
231-
if ctx == nil {
232-
ctx = context.Background()
233-
}
234-
235-
if err := updatePathEnv(); err != nil {
236-
logrus.Warnf("failed to update PATH environment: %v", err)
237-
// PATH update failure shouldn't prevent plugin execution
238-
}
239-
240-
externalCmd := "limactl-" + name
241-
execPath, err := exec.LookPath(externalCmd)
213+
func addPluginCommands(rootCmd *cobra.Command) {
214+
plugins, err := plugin.DiscoverPlugins()
242215
if err != nil {
216+
logrus.Warnf("Failed to discover plugins: %v", err)
243217
return
244218
}
245219

246-
cmd := exec.CommandContext(ctx, execPath, args...)
247-
cmd.Stdin = os.Stdin
248-
cmd.Stdout = os.Stdout
249-
cmd.Stderr = os.Stderr
250-
cmd.Env = os.Environ()
251-
252-
err = cmd.Run()
253-
handleExitError(err)
254-
if err == nil {
255-
os.Exit(0) //nolint:revive // it's intentional to call os.Exit in this function
256-
}
257-
logrus.Fatalf("external command %q failed: %v", execPath, err)
258-
}
259-
260-
func updatePathEnv() error {
261-
exe, err := os.Executable()
262-
if err != nil {
263-
return fmt.Errorf("failed to get executable path: %w", err)
264-
}
220+
for _, p := range plugins {
221+
pluginName := p.Name
222+
pluginCmd := &cobra.Command{
223+
Use: pluginName,
224+
Short: p.Description,
225+
GroupID: "plugin",
226+
DisableFlagParsing: true,
227+
Run: func(cmd *cobra.Command, args []string) {
228+
plugin.RunExternalPlugin(cmd.Context(), pluginName, args)
229+
},
230+
}
265231

266-
binDir := filepath.Dir(exe)
267-
currentPath := os.Getenv("PATH")
268-
newPath := binDir + string(filepath.ListSeparator) + currentPath
232+
pluginCmd.SilenceUsage = true
233+
pluginCmd.SilenceErrors = true
269234

270-
if err := os.Setenv("PATH", newPath); err != nil {
271-
return fmt.Errorf("failed to set PATH environment: %w", err)
235+
rootCmd.AddCommand(pluginCmd)
272236
}
273-
274-
logrus.Debugf("updated PATH to prioritize %s", binDir)
275-
276-
return nil
277237
}
278238

279239
// WrapArgsError annotates cobra args error with some context, so the error message is more user-friendly.

pkg/limainfo/limainfo.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
1818
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
1919
"github.com/lima-vm/lima/v2/pkg/limayaml"
20+
"github.com/lima-vm/lima/v2/pkg/plugin"
2021
"github.com/lima-vm/lima/v2/pkg/registry"
2122
"github.com/lima-vm/lima/v2/pkg/templatestore"
2223
"github.com/lima-vm/lima/v2/pkg/usrlocalsharelima"
@@ -35,6 +36,7 @@ type LimaInfo struct {
3536
HostOS string `json:"hostOS"` // since Lima v2.0.0
3637
HostArch string `json:"hostArch"` // since Lima v2.0.0
3738
IdentityFile string `json:"identityFile"` // since Lima v2.0.0
39+
Plugins []plugin.Plugin `json:"plugins"` // since Lima v2.0.0
3840
}
3941

4042
type DriverExt struct {
@@ -108,5 +110,15 @@ func New(ctx context.Context) (*LimaInfo, error) {
108110
Location: bin,
109111
}
110112
}
113+
114+
plugins, err := plugin.DiscoverPlugins()
115+
if err != nil {
116+
logrus.WithError(err).Warn("Failed to discover plugins")
117+
// Don't fail the entire info command if plugin discovery fails.
118+
info.Plugins = []plugin.Plugin{}
119+
} else {
120+
info.Plugins = plugins
121+
}
122+
111123
return info, nil
112124
}

pkg/osutil/exit.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-FileCopyrightText: Copyright The Lima Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package osutil
5+
6+
import (
7+
"errors"
8+
"os"
9+
"os/exec"
10+
)
11+
12+
func HandleExitError(err error) {
13+
if err == nil {
14+
return
15+
}
16+
17+
var exitErr *exec.ExitError
18+
if errors.As(err, &exitErr) {
19+
os.Exit(exitErr.ExitCode()) //nolint:revive // it's intentional to call os.Exit in this function
20+
return
21+
}
22+
}

0 commit comments

Comments
 (0)