diff --git a/cmd/flags.go b/cmd/flags.go index 58273a335..3d56024b3 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -1,6 +1,10 @@ package cmd import ( + "strings" + + "github.com/evcc-io/evcc/util/templates" + "github.com/samber/lo" "github.com/spf13/cobra" ) @@ -11,6 +15,10 @@ const ( flagIgnoreDatabase = "ignore-db" flagIgnoreDatabaseDescription = "Run command ignoring service database" + flagTemplate = "template" + flagTemplateDescription = "Add custom template (useful for debugging)" + flagTemplateType = "template-type" + flagDisableAuth = "disable-auth" flagDisableAuthDescription = "Disable authentication (dangerous)" @@ -54,6 +62,11 @@ const ( flagForce = "force" ) +var flagTemplateTypeDescription = "Custom template type (" + strings.Join( + lo.Map([]templates.Class{templates.Charger, templates.Meter, templates.Tariff, templates.Vehicle}, func(t templates.Class, _ int) string { + return t.String() + }), ", ") + ")" + func bind(cmd *cobra.Command, key string, flagName ...string) { name := key if len(flagName) == 1 { diff --git a/cmd/root.go b/cmd/root.go index 83e27c6df..aef0c5da2 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -69,6 +69,8 @@ func init() { rootCmd.PersistentFlags().BoolP("help", "h", false, "Help") rootCmd.PersistentFlags().Bool(flagHeaders, false, flagHeadersDescription) rootCmd.PersistentFlags().Bool(flagIgnoreDatabase, false, flagIgnoreDatabaseDescription) + rootCmd.PersistentFlags().String(flagTemplate, "", flagTemplateDescription) + rootCmd.PersistentFlags().String(flagTemplateType, "", flagTemplateTypeDescription) // config file options rootCmd.PersistentFlags().StringP("log", "l", "info", "Log level (fatal, error, warn, info, debug, trace)") diff --git a/cmd/setup.go b/cmd/setup.go index d44db535a..1a7928a65 100644 --- a/cmd/setup.go +++ b/cmd/setup.go @@ -467,14 +467,28 @@ func configureSponsorship(token string) (err error) { return sponsor.ConfigureSponsorship(token) } -func configureEnvironment(cmd *cobra.Command, conf *globalconfig.All) (err error) { +func configureEnvironment(cmd *cobra.Command, conf *globalconfig.All) error { // full http request log if cmd.Flag(flagHeaders).Changed { request.LogHeaders = true } // setup persistence - err = wrapErrorWithClass(ClassDatabase, configureDatabase(conf.Database)) + err := wrapErrorWithClass(ClassDatabase, configureDatabase(conf.Database)) + + // setup additional templates + if err == nil { + if cmd.PersistentFlags().Changed(flagTemplate) { + class, err := templates.ClassString(cmd.PersistentFlags().Lookup(flagTemplateType).Value.String()) + if err != nil { + return err + } + + if err := templates.Register(class, cmd.Flag(flagTemplate).Value.String()); err != nil { + return err + } + } + } // setup translations if err == nil { @@ -519,7 +533,7 @@ func configureEnvironment(cmd *cobra.Command, conf *globalconfig.All) (err error err = config.Init(db.Instance) } - return + return err } // configureDatabase configures session database diff --git a/util/templates/init.go b/util/templates/init.go index d34675835..9b88f6a12 100644 --- a/util/templates/init.go +++ b/util/templates/init.go @@ -5,6 +5,7 @@ import ( "embed" "fmt" "io/fs" + "os" "slices" "sync" "text/template" @@ -37,7 +38,27 @@ func init() { } } -func FromBytes(b []byte) (Template, error) { +func Register(class Class, filepath string) error { + b, err := os.ReadFile(filepath) + if err != nil { + return err + } + + tmpl, err := fromBytes(b) + if err != nil { + return fmt.Errorf("processing template '%s' failed: %w", filepath, err) + } + + if slices.ContainsFunc(templates[class], func(t Template) bool { return t.Template == tmpl.Template }) { + return fmt.Errorf("duplicate template name '%s' found in file '%s'", tmpl.Template, filepath) + } + + templates[class] = append(templates[class], tmpl) + + return nil +} + +func fromBytes(b []byte) (Template, error) { // panic if template definition contains unknown fields dec := yaml.NewDecoder(bytes.NewReader(b)) dec.KnownFields(true) @@ -79,7 +100,7 @@ func load(class Class) (res []Template) { return err } - tmpl, err := FromBytes(b) + tmpl, err := fromBytes(b) if err != nil { return fmt.Errorf("processing template '%s' failed: %w", filepath, err) }