config_loader.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. package cmd
  2. import (
  3. "fmt"
  4. "github.com/urfave/cli/v2"
  5. "github.com/urfave/cli/v2/altsrc"
  6. "gopkg.in/yaml.v2"
  7. "heckel.io/ntfy/v2/util"
  8. "os"
  9. )
  10. // initConfigFileInputSourceFunc is like altsrc.InitInputSourceWithContext and altsrc.NewYamlSourceFromFlagFunc, but checks
  11. // if the config flag is exists and only loads it if it does. If the flag is set and the file exists, it fails.
  12. func initConfigFileInputSourceFunc(configFlag string, flags []cli.Flag, next cli.BeforeFunc) cli.BeforeFunc {
  13. return func(context *cli.Context) error {
  14. configFile := context.String(configFlag)
  15. if context.IsSet(configFlag) && !util.FileExists(configFile) {
  16. return fmt.Errorf("config file %s does not exist", configFile)
  17. } else if !context.IsSet(configFlag) && !util.FileExists(configFile) {
  18. return nil
  19. }
  20. inputSource, err := newYamlSourceFromFile(configFile, flags)
  21. if err != nil {
  22. return err
  23. }
  24. if err := altsrc.ApplyInputSourceValues(context, inputSource, flags); err != nil {
  25. return err
  26. }
  27. if next != nil {
  28. if err := next(context); err != nil {
  29. return err
  30. }
  31. }
  32. return nil
  33. }
  34. }
  35. // newYamlSourceFromFile creates a new Yaml InputSourceContext from a filepath.
  36. //
  37. // This function also maps aliases, so a .yml file can contain short options, or options with underscores
  38. // instead of dashes. See https://github.com/binwiederhier/ntfy/issues/255.
  39. func newYamlSourceFromFile(file string, flags []cli.Flag) (altsrc.InputSourceContext, error) {
  40. var rawConfig map[any]any
  41. b, err := os.ReadFile(file)
  42. if err != nil {
  43. return nil, err
  44. }
  45. if err := yaml.Unmarshal(b, &rawConfig); err != nil {
  46. return nil, err
  47. }
  48. for _, f := range flags {
  49. flagName := f.Names()[0]
  50. for _, flagAlias := range f.Names()[1:] {
  51. if _, ok := rawConfig[flagAlias]; ok {
  52. rawConfig[flagName] = rawConfig[flagAlias]
  53. }
  54. }
  55. }
  56. return altsrc.NewMapInputSource(file, rawConfig), nil
  57. }