4
4
package main
5
5
6
6
import (
7
- "context"
8
7
"errors"
9
8
"fmt"
10
9
"os"
11
- "os/exec"
12
10
"path/filepath"
13
11
"runtime"
14
12
"strings"
@@ -23,6 +21,7 @@ import (
23
21
"github.com/lima-vm/lima/v2/pkg/fsutil"
24
22
"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
25
23
"github.com/lima-vm/lima/v2/pkg/osutil"
24
+ "github.com/lima-vm/lima/v2/pkg/plugin"
26
25
"github.com/lima-vm/lima/v2/pkg/version"
27
26
)
28
27
@@ -49,13 +48,12 @@ func main() {
49
48
}
50
49
}
51
50
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 {
55
55
logrus .Fatal (err )
56
56
}
57
-
58
- server .StopAllExternalDrivers ()
59
57
}
60
58
61
59
func newApp () * cobra.Command {
@@ -120,12 +118,6 @@ func newApp() *cobra.Command {
120
118
return fmt .Errorf ("unsupported log-format: %q" , logFormat )
121
119
}
122
120
123
- debug , _ := cmd .Flags ().GetBool ("debug" )
124
- if debug {
125
- logrus .SetLevel (logrus .DebugLevel )
126
- debugutil .Debug = true
127
- }
128
-
129
121
if osutil .IsBeingRosettaTranslated () && cmd .Parent ().Name () != "completion" && cmd .Name () != "generate-doc" && cmd .Name () != "validate" {
130
122
// running under rosetta would provide inappropriate runtime.GOARCH info, see: https://github.com/lima-vm/lima/issues/543
131
123
// allow commands that are used for packaging to run under rosetta to allow cross-architecture builds
@@ -165,6 +157,8 @@ func newApp() *cobra.Command {
165
157
}
166
158
rootCmd .AddGroup (& cobra.Group {ID : "basic" , Title : "Basic Commands:" })
167
159
rootCmd .AddGroup (& cobra.Group {ID : "advanced" , Title : "Advanced Commands:" })
160
+ rootCmd .AddGroup (& cobra.Group {ID : "plugin" , Title : "Available Plugins (Experimental):" })
161
+
168
162
rootCmd .AddCommand (
169
163
newCreateCommand (),
170
164
newStartCommand (),
@@ -201,79 +195,45 @@ func newApp() *cobra.Command {
201
195
return rootCmd
202
196
}
203
197
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.
217
198
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
223
205
}
224
206
}
225
207
226
- rootCmd .SetArgs (args )
208
+ addPluginCommands (rootCmd )
209
+
227
210
return rootCmd .Execute ()
228
211
}
229
212
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 ()
242
215
if err != nil {
216
+ logrus .Warnf ("Failed to discover plugins: %v" , err )
243
217
return
244
218
}
245
219
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
+ }
265
231
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
269
234
270
- if err := os .Setenv ("PATH" , newPath ); err != nil {
271
- return fmt .Errorf ("failed to set PATH environment: %w" , err )
235
+ rootCmd .AddCommand (pluginCmd )
272
236
}
273
-
274
- logrus .Debugf ("updated PATH to prioritize %s" , binDir )
275
-
276
- return nil
277
237
}
278
238
279
239
// WrapArgsError annotates cobra args error with some context, so the error message is more user-friendly.
0 commit comments