Autodetect config format based on extension
What type of PR is this?
- feature
What this PR does / why we need it:
- Allows use of
DetectNewSourceFromFlagFunc(flag)to support configs in more than one format for a single application, by autodetecting which format to parse with according to the config file's extension. - Allows registration of third-party
New*SourceFromFlagFunc()functions to new file extensions for support by the autodetector. - Preregisters the three built-in parsers as follows:
-
.yaml→NewYamlSourceFromFlagFunc -
.yml→NewYamlSourceFromFlagFunc -
.json→NewJSONSourceFromFlagFunc -
.toml→NewTomlSourceFromFlagFunc -
.conf→NewTomlSourceFromFlagFunc
-
Testing
- set up a new CLI project using the following (or similar) configuration:
main.go
func main() {
app := cli.NewApp()
app.Name = "dynamic-config"
app.Version = "0.1.0"
app.Description = "Showcases how to use the DetectNewSourceFromFlagFunc feature"
app.Authors = []*cli.Author{
{Name: "Hennik Hunsaker", Email: "[email protected]"},
}
app.Flags = []cli.Flag{
altsrc.NewIntFlag(&cli.IntFlag{
Name: "number",
Aliases: []string{"n"},
Usage: "the `answer` to spit out",
Value: 42,
}),
&cli.PathFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "specify the configuration `file` to use",
Value: "oa2s.conf",
TakesFile: true,
},
}
app.AddExtension(altsrc.NewDetectableSourcesAppExtension())
app.Before = altsrc.InitInputSourceWithContext(app.Flags, altsrc.DetectNewSourceFromFlagFunc("config"))
app.Action = func(c *cli.Context) error {
fmt.Printf("The answer is %d", c.Int("number"))
return nil
}
_ = app.Run(os.Args)
}
- Create the following config files to test against:
config.yaml
number: 43
config.json
{"number": 44}
config.toml
number = 45
config.conf
number = 46
config.yml
number: 47
- Try the code using a terminal or console:
go run main.go
go run main.go -- --config config.yaml
go run main.go -- --config config.json
go run main.go -- --config config.toml
go run main.go -- --config config.conf
go run main.go -- --config config.yml
- Compare the results with the following outputs:
The answer is 42
The answer is 43
The answer is 44
The answer is 45
The answer is 46
The answer is 47
Release Notes
Added support to detect the configuration file format from its extension, rather than predefine it in the code.
Should add .yml aswell for yaml
Should add .yml aswell for yaml
Done!
Now to add the new tests.
Ahh circular dependencies... Moving the InputSourceContext interface to cli is a backwards compatibility issue. I'm not sure how used it is, maybe someone else can provide some insight. @urfave/cli
I put some time into it, and I'm not sure how it could be done differently. Maybe you have other ideas if the compatibility is an issue @danhunsaker
If Go offered a way to attach objects to other objects without defining an explicit name first...
Though maybe we could add something more generic for myriad extensions to use... 🤔
@danhunsaker v2 is only in maintenance mode right now. No new features/capabilities. Can you do this PR for v3/main ?
Sure, once v3 is actually out of alpha and into a real release. I can't use/test it until then.
Also, I don't see support for InputSourceContexts (or their equivalent) on v3 in the first place, meaning I'd have to reimplement all of that as well.
v3 is the mainline branch. Alpha will be out soon. altsrc has been moved into its own repo for v3 since it is ancillary to cli and not a core.
There's nothing anywhere pointing it out, so I didn't know there was a separate repository. I'll see what I can do with that.
@danhunsaker Thanks for your patience! The transitional state of the ./altsrc ➡️ altsrc move is definitely awkward. Sorry about that! I would love to see this new feature land over there if possible. If you're interested in moving the "altsrc" concepts forward like this, we could really use the help 🙇🏼
Closing as per the comments above. v2 is in maintenance mode and we don't accept new features for it.
Thank you for the contribution, and if possible, please submit it to https://github.com/urfave/cli-altsrc