altsrc with YAML: Flag is Never Assigned
How to use a YAML config file to set flags? I've read the docs and tried a couple of things; then waited a month and read them again but, nothing seems to work.
I'm using v2.3.0.
package cli
var Flags []cli.Flag
func init() {
Flags = []cli.Flag{
altsrc.NewStringFlag(
&cli.StringFlag{
Required: true,
Name: "foo",
}
)
}
}
package main
// In main()
app := &cli.App{
Name: "tester",
Before: altsrc.InitInputSourceWithContext(cmd.Flags,
func(context *cli.Context) (altsrc.InputSourceContext, error) {
return altsrc.NewYamlSourceFromFile(".myconfig")
}
)
}
But every time I run it I get an error because foo is required and not set.
I have also tried what sounds like a more verbose version of the above:
app := &cli.App{
Name: "sdt",
Before: func (c *cli.Context) error {
src, err := altsrc.NewYamlSourceFromFile(".myconfig")
if err != nil {
return err
}
fmt.Printf("%+v\n", src)
err = altsrc.ApplyInputSourceValues(c, src, cmd.Flags)
if err != nil {
return err
}
return nil
},
}
The config is printed and everything is there but the flag is never assigned.
I thought it may be related to #1086 but this appears to be fixed in v2.3.0. Help!
This issue or PR has been automatically marked as stale because it has not had recent activity. Please add a comment bumping this if you're still interested in it's resolution! Thanks for your help, please let us know if you need anything else.
Still interested in its resolution
This issue or PR has been bumped and is no longer marked as stale! Feel free to bump it again in the future, if it's still relevant.
This issue or PR has been automatically marked as stale because it has not had recent activity. Please add a comment bumping this if you're still interested in it's resolution! Thanks for your help, please let us know if you need anything else.
Still interested in its resolution
This issue or PR has been bumped and is no longer marked as stale! Feel free to bump it again in the future, if it's still relevant.
Here's an simple example on v2.20.2:
main.go
package main
import (
"fmt"
"os"
"github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
)
var (
logfile string
verbose int
)
func main() {
flags := []cli.Flag{
&cli.StringFlag{
Name: "config",
Usage: "yaml config file name",
},
altsrc.NewStringFlag(
&cli.StringFlag{
Name: "logfile",
Aliases: []string{"log.file"}, // match config file structure
Value: "",
Usage: "log to file",
Destination: &logfile,
},
),
altsrc.NewIntFlag(
&cli.IntFlag{
Name: "verbose",
Aliases: []string{"log.verbose"},
Value: 0,
Destination: &verbose,
},
),
}
app := &cli.App{
Flags: flags,
Before: altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("config")),
Action: func(ctx *cli.Context) error {
fmt.Printf("config file: %s, log {file: %s, verbose: %d}\n", ctx.String("config"), logfile, verbose)
return nil
},
}
fmt.Println(app.Run(os.Args))
}
example.yml
log:
verbose: 1
file: log.txt
Aliases attributes are used to specify mapping between flag and config file structure.
@Archwizard The code you have posted works
$ cat example.yml
log:
verbose: 1
file: log.txt
$ go run main.go --config example.yml
config file: example.yml, log {file: log.txt, verbose: 1}
<nil>
@sshaw Do you have a complete example to share ?
Thanks @Archwizard. The Aliases matching the log file structure are key, though a bit ugly considering they're now also command-line options.
@sshaw Do you have a complete example to share ?
@dearchap is this not a compete example?
@sshaw You need to provide Flag to app as well
app := &cli.App{
Name: "tester",
Flags: Flags,
Before: altsrc.InitInputSourceWithContext(Flags,
func(context *cli.Context) (altsrc.InputSourceContext, error) {
return altsrc.NewYamlSourceFromFile(".myconfig")
}),
}
I hope that the Aliases stuff can be mentioned in the documents...