|
4 | 4 | package main
|
5 | 5 |
|
6 | 6 | import (
|
| 7 | + "context" |
7 | 8 | "errors"
|
8 | 9 | "fmt"
|
9 | 10 | "os"
|
| 11 | + "os/exec" |
10 | 12 | "path/filepath"
|
11 | 13 | "runtime"
|
12 | 14 | "strings"
|
@@ -40,7 +42,8 @@ func main() {
|
40 | 42 | }
|
41 | 43 | }
|
42 | 44 | }
|
43 |
| - if err := newApp().Execute(); err != nil { |
| 45 | + rootCmd := newApp() |
| 46 | + if err := executeWithPluginSupport(rootCmd, os.Args[1:]); err != nil { |
44 | 47 | handleExitCoder(err)
|
45 | 48 | logrus.Fatal(err)
|
46 | 49 | }
|
@@ -215,6 +218,67 @@ func handleExitCoder(err error) {
|
215 | 218 | }
|
216 | 219 | }
|
217 | 220 |
|
| 221 | +// executeWithPluginSupport handles command execution with plugin support. |
| 222 | +func executeWithPluginSupport(rootCmd *cobra.Command, args []string) error { |
| 223 | + if len(args) > 0 { |
| 224 | + cmd, _, err := rootCmd.Find(args) |
| 225 | + if err != nil || cmd == rootCmd { |
| 226 | + if err := runExternalPlugin(rootCmd.Context(), args[0], args[1:]); err == nil { |
| 227 | + return nil |
| 228 | + } |
| 229 | + } |
| 230 | + } |
| 231 | + |
| 232 | + rootCmd.SetArgs(args) |
| 233 | + return rootCmd.Execute() |
| 234 | +} |
| 235 | + |
| 236 | +func runExternalPlugin(ctx context.Context, name string, args []string) error { |
| 237 | + if ctx == nil { |
| 238 | + ctx = context.Background() |
| 239 | + } |
| 240 | + |
| 241 | + externalCmd := "limactl-" + name |
| 242 | + execPath, err := exec.LookPath(externalCmd) |
| 243 | + if err != nil { |
| 244 | + return err |
| 245 | + } |
| 246 | + |
| 247 | + if err := updatePathEnv(); err != nil { |
| 248 | + logrus.Warnf("failed to update PATH environment: %v", err) |
| 249 | + // PATH update failure shouldn't prevent plugin execution |
| 250 | + } |
| 251 | + |
| 252 | + logrus.Debugf("found external command: %s", execPath) |
| 253 | + |
| 254 | + cmd := exec.CommandContext(ctx, execPath, args...) |
| 255 | + cmd.Stdin = os.Stdin |
| 256 | + cmd.Stdout = os.Stdout |
| 257 | + cmd.Stderr = os.Stderr |
| 258 | + cmd.Env = os.Environ() |
| 259 | + |
| 260 | + return cmd.Run() |
| 261 | +} |
| 262 | + |
| 263 | +func updatePathEnv() error { |
| 264 | + exe, err := os.Executable() |
| 265 | + if err != nil { |
| 266 | + return fmt.Errorf("failed to get executable path: %w", err) |
| 267 | + } |
| 268 | + |
| 269 | + binDir := filepath.Dir(exe) |
| 270 | + currentPath := os.Getenv("PATH") |
| 271 | + newPath := binDir + string(filepath.ListSeparator) + currentPath |
| 272 | + |
| 273 | + if err := os.Setenv("PATH", newPath); err != nil { |
| 274 | + return fmt.Errorf("failed to set PATH environment: %w", err) |
| 275 | + } |
| 276 | + |
| 277 | + logrus.Debugf("updated PATH to prioritize %s", binDir) |
| 278 | + |
| 279 | + return nil |
| 280 | +} |
| 281 | + |
218 | 282 | // WrapArgsError annotates cobra args error with some context, so the error message is more user-friendly.
|
219 | 283 | func WrapArgsError(argFn cobra.PositionalArgs) cobra.PositionalArgs {
|
220 | 284 | return func(cmd *cobra.Command, args []string) error {
|
|
0 commit comments