Skip to content

How To Share Same Slice Destination Among Different Flags #2073

@kudla

Description

@kudla

Hi!
Please guys. Actually in v3 how to make several slice flags to share the same destination .
What I'm trying is something like this

package main

import (
	"context"
	"fmt"

	"github.com/urfave/cli/v3"
)

func main() {
	ints := []int64{}
	app := &cli.Command{
		Flags: []cli.Flag{
			&cli.IntSliceFlag{
				Name:        "a",
				Destination: &ints,
			},
			&cli.IntSliceFlag{
				Name:        "b",
				Destination: &ints,
			},
			&cli.IntSliceFlag{
				Name:        "c",
				Destination: &ints,
			},
		},
		Action: func(ctx context.Context, cmd *cli.Command) error {
			fmt.Printf("%v\n", ints)

			return nil
		},
	}

	err := app.Run(context.Background(), []string{"app", "-a", "1", "-a", "2", "-b", "3", "-c", "4", "-a", "5", "-b", "6"})

	if err != nil {
		panic(err)
	}
}

So it almost works aggregating all the values into a single slice, except it looks like one whatever the flag is being provided at first (initialized) it resets all the values had being populated with previous other flag values.

And actually the more deeper question (story) behind this.

In v3 how actually to make the set of flags to add values into a same slice of some custom type but being customized by the fine grained params for the each flag individually.

In v2 it was pretty simple by implementing Generic.Set(value string) error
in v3 it seams it really something like ValueCreators and FlagConfig should be involved for. Still I can't grasp the whole idea to achieve this.

As a simple example I can see it something like following

type BytesFlagConfig struct {
	Scale int64
}

type Amount struct {
    Value int64
    Scale int64
}

type BytesValue struct {
	destination * Amount
}


type (
	BytesSlice     = cli.SliceBase[Amount, BytesFlagConfig, BytesValue]
	BytesSliceFlag = cli.FlagBase[[]Amount, BytesFlagConfig, BytesSlice]
)

var NewBytesSlice = cli.NewSliceBase[Amount, BytesFlagConfig, BytesValue]

/*

Some lack of magic here

*/

func main() {
      data := []Amount{}

      app := &cli.Command{
          Flags: []cli.Flag{
               &BytesSliceFlag {
                      Name: "bytes",
                      Aliases: []string{"b"},
                      Config: {
                          Scale: 1,
                      },
                      Destination: &data,
               },
               &BytesSliceFlag {
                      Name: "k-bytes",
                      Aliases: []string{"k"},
                      Config: {
                          Scale: 1024,
                      },
                      Destination: &data,
               },
               &BytesSliceFlag {
                      Name: "m-bytes",
                      Aliases: []string{"M"},
                      Config: {
                          Scale: 1024 * 1024,
                      },
                      Destination: &data,
               },
          },
      }

      app.Run(context.Context. os.Args())
}

So that to be called as

my-app -b 120 -k 12 -M 100

An to have in the data destination respectively something related to [120, 12 * 1024, 100 * 1024 * 1024]
It actually matters to keep the values initial order (so that's why we need the same destination here)

Another case would be something to accumulate a set of inputs but from different encoding sources

my-app --data-hex 45af9210eca  --data-base64 c2Rmcmd0ZWZ2ZXI=

So besides the initially described problem with multi int slice flags. The question is

  • how actually to achieve such a logic.
  • Should the custom cli.Value implementation be introduced for that or could it be achieved just on the generic params manipulation level
  • Do I see it at in the right direction at all or should it be implemented in some other way
  • Maybe some very common examples on this could be shared to see as well

Thank you.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/v3relates to / is being considered for v3kind/questionsomeone asking a questionstatus/waiting-for-responseWaiting for response from original requester

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions