Skip to content

incus: Fix alias arguments handling #1463

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

Merged
merged 1 commit into from
Dec 5, 2024
Merged
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
26 changes: 16 additions & 10 deletions cmd/incus/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,7 @@ func aliases() []string {
return aliases
}

func main() {
// Process aliases
err := execIfAliases()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}

func createApp() (*cobra.Command, *cmdGlobal) {
// Setup the parser
app := &cobra.Command{}
app.Use = "incus"
Expand Down Expand Up @@ -306,8 +299,14 @@ Custom commands can be defined through aliases, use "incus alias" to control tho
app.Flags().BoolVar(&globalCmd.flagHelpAll, "all", false, i18n.G("Show less common commands"))
help.Flags().BoolVar(&globalCmd.flagHelpAll, "all", false, i18n.G("Show less common commands"))

// Deal with --all flag and --sub-commands flag
err = app.ParseFlags(os.Args[1:])
return app, &globalCmd
}

func main() {
app, globalCmd := createApp()

// Deal with --all and --sub-commands flags as well as process aliases.
err := app.ParseFlags(os.Args[1:])
if err == nil {
if globalCmd.flagHelpAll {
// Show all commands
Expand All @@ -325,6 +324,13 @@ Custom commands can be defined through aliases, use "incus alias" to control tho
}
}

// Process aliases
err = execIfAliases(app)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}

// Run the main command and handle errors
err = app.Execute()
if err != nil {
Expand Down
43 changes: 26 additions & 17 deletions cmd/incus/main_aliases.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"

"github.com/kballard/go-shellquote"
"github.com/spf13/cobra"

"github.com/lxc/incus/v6/internal/i18n"
config "github.com/lxc/incus/v6/shared/cliconfig"
Expand Down Expand Up @@ -76,26 +77,36 @@ func findAlias(aliases map[string]string, origArgs []string) ([]string, []string
return aliasKey, aliasValue, foundAlias
}

func expandAlias(conf *config.Config, args []string) ([]string, bool, error) {
var completion = false
var completionFrament string
var newArgs []string
var origArgs []string
func expandAlias(conf *config.Config, args []string, app *cobra.Command) ([]string, bool, error) {
fset := app.Flags()

for _, arg := range args[1:] {
if !strings.HasPrefix(arg, "-") {
break
}
nargs := fset.NArg()
firstArgIndex := 1
firstPosArgIndex := 0
if fset.Arg(0) == "__complete" {
nargs--
firstArgIndex++
firstPosArgIndex++
}

newArgs = append(newArgs, arg)
if nargs == 0 {
return nil, false, nil
}

origArgs = append([]string{args[0]}, args[len(newArgs)+1:]...)
lastFlagIndex := slices.Index(args, fset.Arg(firstPosArgIndex))

// newArgs contains all the flags before the first positional argument
newArgs := args[firstArgIndex:lastFlagIndex]

// origArgs contains everything except the flags in newArgs
origArgs := slices.Concat(args[:firstArgIndex], args[lastFlagIndex:])

// strip out completion subcommand and fragment from end
completion := false
completionFragment := ""
if len(origArgs) >= 3 && origArgs[1] == "__complete" {
completion = true
completionFrament = origArgs[len(origArgs)-1]
completionFragment = origArgs[len(origArgs)-1]
origArgs = append(origArgs[:1], origArgs[2:len(origArgs)-1]...)
}

Expand Down Expand Up @@ -189,7 +200,7 @@ func expandAlias(conf *config.Config, args []string) ([]string, bool, error) {
// add back in completion if it was stripped before
if completion {
newArgs = append([]string{newArgs[0], "__complete"}, newArgs[1:]...)
newArgs = append(newArgs, completionFrament)
newArgs = append(newArgs, completionFragment)
}

// Add the rest of the arguments only if @ARGS@ wasn't used.
Expand All @@ -200,9 +211,7 @@ func expandAlias(conf *config.Config, args []string) ([]string, bool, error) {
return newArgs, true, nil
}

func execIfAliases() error {
args := os.Args

func execIfAliases(app *cobra.Command) error {
// Avoid loops
if os.Getenv("INCUS_ALIASES") == "1" {
return nil
Expand All @@ -214,7 +223,7 @@ func execIfAliases() error {
}

// Expand the aliases
newArgs, expanded, err := expandAlias(conf, args)
newArgs, expanded, err := expandAlias(conf, os.Args, app)
if err != nil {
return err
} else if !expanded {
Expand Down
12 changes: 11 additions & 1 deletion cmd/incus/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,22 @@ func TestExpandAliases(t *testing.T) {
input: []string{"incus", "snapshots", "with", "recursion", "c1", "2"},
expected: []string{"incus", "query", "/1.0/instances/c1/snapshots?recursion=2"},
},
{
input: []string{"incus", "--project", "default", "fizz", "c1", "buzz"},
expected: []string{"incus", "--project", "default", "exec", "c1", "--", "echo", "buzz"},
},
{
input: []string{"incus", "--project=default", "fizz", "c1", "buzz"},
expected: []string{"incus", "--project=default", "exec", "c1", "--", "echo", "buzz"},
},
}

conf := &config.Config{Aliases: aliases}

for _, tc := range testcases {
result, expanded, err := expandAlias(conf, tc.input)
app, _ := createApp()
_ = app.ParseFlags(tc.input[1:])
result, expanded, err := expandAlias(conf, tc.input, app)
if tc.expectErr {
assert.Error(t, err)
continue
Expand Down
Loading