urfave / cli

A simple, fast, and fun package for building command line apps in Go
https://cli.urfave.org
MIT License
21.89k stars 1.69k forks source link

How to use a custom CLI flag separator #1878

Closed JonasScharpf closed 2 months ago

JonasScharpf commented 3 months ago

I'm new to Go so please bare with me.

I have an application which accepts multiple --groups flags by using StringSliceFlag which works great.

I can use it with fancy_name --groups="asdf" --groups="qwertz" and get [asdf qwertz].

As soon as the value of the args contains a , it does the right thing and splits it at the comma. fancy_name --groups="asdf,foo" --groups="qwertz" becomes [asdf foo qwertz] but I would need [asdf,foo qwertz]. This is where #1241 and #1134 becomes interesting. I already tried to set app.SliceFlagSeparator = ";" but this has no effect on the flag parsing. Changing the defaultSliceFlagSeparator in flag.go to e.g. ; solved the problem of course.

So my question in the end is how to set a slice separator for all or a specific flag

func main() {
    app := cli.NewApp()

    cli.AppHelpTemplate = flags.Template
    cli.HelpPrinterCustom = flags.HelpPrinter
    // Force the use of cli.HelpPrinterCustom.
    app.ExtraInfo = func() map[string]string { return map[string]string{} }
    app.SliceFlagSeparator = ";"
    // app.DisableSliceFlagSeparator = true

    app.Flags = flags.GetCliFlags()
    app.Action = run

    err := app.Run(os.Args)
    if err != nil {
        log.Fatal("terminated:", err)
    }
}

func GetCliFlags() []cli.Flag {
    return []cli.Flag{
        &cli.StringSliceFlag{
            Name:    "groups",
            Value:   cli.NewStringSlice("this,that,other", "foo"),
            Usage:   "Groups, can be given multiple times",
            // EnvVars: []string{"GROUPS"},
    }
}
JonasScharpf commented 3 months ago

not setting a Value for StringSliceFlag solves the issue somehow. fancy_name --groups="asdf,foo" --groups="qwertz" then returns the expected content which is [asdf,foo qwertz]

Pipello commented 3 months ago

I already tried to set app.SliceFlagSeparator = ";" but this has no effect I guess that is a bug

or a specific flag I don't see a real usage fof setting separator per flag but having a Separator string on the StringSliceFlag could solve it

dearchap commented 3 months ago

Can you try WithSeparatorSpec on the string slice flag ?

JonasScharpf commented 2 months ago

could you give me a code hint for WithSeparatorSpec on a StringSliceFlag? May I do something wrong as Go newbie, because of unknown field 'WithSeparatorSpec' in struct literal of type cli.StringSliceFlag

dearchap commented 2 months ago

https://github.com/urfave/cli/blob/v2-maint/flag_string_slice.go#L181

Are you using the latest v2 release ?

JonasScharpf commented 2 months ago

yes I do, v2.27.0

I still believe this is a syntax thing on my side

func GetCliFlags() []cli.Flag {
    return []cli.Flag{
        &cli.StringSliceFlag{
            Name:    "groups",
            Value:   cli.NewStringSlice("this,that,other", "foo"),
            Usage:   "Groups, can be given multiple times",
            WithSeparatorSpec: cli.separatorSpec{sep: ";"},
    }
}
dearchap commented 2 months ago

Ah no you need to do

func GetCliFlags() []cli.Flag {
    ssflag := &cli.StringSliceFlag{
            Name:    "groups",
            Value:   cli.NewStringSlice("this,that,other", "foo"),
            Usage:   "Groups, can be given multiple times",
    }
    ssflag.WithSeparatorSpec(cli.separatorSpec{sep: ";"})

    return []cli.Flag{
        ssflag,
    }
}
JonasScharpf commented 2 months ago

Thanks for the hint, but it does not work as separatorSpec is not exported (function starting with lower case). In the yet unreleased v3 this is even no longer available

./first.go:90:34: separatorSpec not exported by package cli
./first.go:90:48: unknown field 'sep' in struct literal of type cli.separatorSpec

I'll stay with v2, keep the setting globally and use no default value