# HG changeset patch # User Christophe de Vienne <christophe@cdevienne.info> # Date 1599824382 -7200 # Fri Sep 11 13:39:42 2020 +0200 # Node ID b9c79b6413628b85d90c2b44cf84790b7fd04bf2 # Parent 28952ee02687c9a8cc94b47b4c33f5c8bf31c56f Add configuration file handling diff --git a/database/options.go b/database/options.go --- a/database/options.go +++ b/database/options.go @@ -4,8 +4,8 @@ // Options is a jessevdk/go-flags compatible struct for db-related options type Options struct { - DSN string `long:"db-dsn" env:"DB_DSN" ini-name:"dsn" description:"DSN of the database"` - MaxConn int `long:"db-max-conn" env:"DB_MAX_CONN" ini-name:"max-conn" description:"Database max connection" default:"0"` + DSN string `long:"dsn" env:"DSN" ini-name:"dsn" description:"DSN of the database"` + MaxConn int `long:"max-conn" env:"MAX_CONN" ini-name:"max-conn" description:"Database max connection" default:"0"` } // Open a connection to the database diff --git a/generate-config.go b/generate-config.go new file mode 100644 --- /dev/null +++ b/generate-config.go @@ -0,0 +1,40 @@ +package orusapi + +import ( + "io" + "os" + + flags "github.com/orus-io/go-flags" +) + +// GenerateConfigCmd is a command that generates a configuration file +type GenerateConfigCmd struct { + Output string `short:"o" long:"output" default:"-" no-ini:"t" description:"output file"` + + parser *flags.Parser +} + +// NewGenerateConfigCmd creates a GenerateConfigCmd +func NewGenerateConfigCmd(parser *flags.Parser) *GenerateConfigCmd { + return &GenerateConfigCmd{parser: parser} +} + +// Execute write out a configuration file +func (c *GenerateConfigCmd) Execute([]string) (errResult error) { + var out io.Writer + if c.Output == "-" { + out = os.Stdout + } else { + f, err := os.OpenFile(c.Output, os.O_RDWR|os.O_CREATE, 0755) + if err != nil { + return err + } + defer func() { + errResult = f.Close() + }() + out = f + } + fp := flags.NewIniParser(c.parser) + fp.Write(out, flags.IniIncludeDefaults|flags.IniCommentDefaults|flags.IniDefault) + return nil +} diff --git a/logging.go b/logging.go --- a/logging.go +++ b/logging.go @@ -38,8 +38,8 @@ // LoggingOptions holds the logging options type LoggingOptions struct { - Level func(string) error `long:"log-level" env:"LOG_LEVEL" ini-name:"log-level" choice:"trace" choice:"debug" choice:"info" choice:"warn" choice:"error" choice:"fatal" choice:"panic" choice:"auto" default:"auto" description:"log level. 'auto' selects 'info' when stdout is a tty, 'error' otherwise."` - Format func(string) error `long:"log-format" env:"LOG_FORMAT" ini-name:"log-format" choice:"json" choice:"pretty" choice:"auto" default:"auto" description:"Logs format. 'auto' selects 'pretty' if stdout is a tty."` + Level func(string) error `long:"level" env:"LEVEL" ini-name:"log-level" choice:"trace" choice:"debug" choice:"info" choice:"warn" choice:"error" choice:"fatal" choice:"panic" choice:"auto" default:"auto" description:"log level. 'auto' selects 'info' when stdout is a tty, 'error' otherwise."` + Format func(string) error `long:"format" env:"FORMAT" ini-name:"log-format" choice:"json" choice:"pretty" choice:"auto" default:"auto" description:"Logs format. 'auto' selects 'pretty' if stdout is a tty."` Verbose func() `short:"v" long:"verbose" no-ini:"t" description:"Increase log verbosity. Can be repeated"` logFinalOutput io.Writer `no-flag:"t"` diff --git a/templates/server/cmd.gotmpl b/templates/server/cmd.gotmpl --- a/templates/server/cmd.gotmpl +++ b/templates/server/cmd.gotmpl @@ -8,15 +8,35 @@ "orus.io/orus-io/go-orus-api/database" ) +type ConfigFile struct { + ConfigFile string `long:"config" short:"c" env:"CONFIG" no-ini:"t" description:"A configuration file"` +} + var ( Logger = orusapi.DefaultLogger(os.Stdout) LoggingOptions = orusapi.MustLoggingOptions(orusapi.NewLoggingOptions(&Logger, os.Stdout)) DatabaseOptions = &database.Options{} + ConfigFileOption = &ConfigFile{} parser = flags.NewNamedParser("{{ dasherize (pascalize .Name) }}", flags.HelpFlag|flags.PassDoubleDash) + bootstrapParser = flags.NewNamedParser("{{ dasherize (pascalize .Name) }}", flags.IgnoreUnknown) ) func Run() int { + if _, err := bootstrapParser.Parse(); err != nil { + Logger.Err(err).Msg("") + return 1 + } + + if ConfigFileOption.ConfigFile != "" { + Logger.Debug().Str("configfile", ConfigFileOption.ConfigFile).Msg("parsing configuration file") + iniParser := flags.NewIniParser(parser) + if err := iniParser.ParseFile(ConfigFileOption.ConfigFile); err != nil { + Logger.Err(err).Msg("") + return 1 + } + } + if _, err := parser.Parse(); err != nil { code := 1 if fe, ok := err.(*flags.Error); ok { @@ -26,10 +46,10 @@ // so we print it on the console fmt.Println(err) } else { - log.Error().Msg(err.Error()) + Logger.Error().Msg(err.Error()) } } else { - log.Err(err).Msg("") + Logger.Err(err).Msg("") } return code } @@ -37,6 +57,34 @@ } func init() { - parser.AddGroup("Logging", "Logging options", LoggingOptions) - parser.AddGroup("Database", "Database options", DatabaseOptions) + parser.NamespaceDelimiter = "-" + parser.EnvNamespaceDelimiter = "_" + parser.EnvNamespace = "CARNET" + parser.AddGroup("Configuration", "Configuration file", ConfigFileOption) + g, err := parser.AddGroup("Logging", "Logging options", LoggingOptions) + if err != nil { + panic(err) + } + g.Namespace="log" + g.EnvNamespace="LOG" + g, err = parser.AddGroup("Database", "Database options", DatabaseOptions) + if err != nil { + panic(err) + } + g.Namespace="db" + g.EnvNamespace="DB" + + parser.AddCommand("generate-config", "Generate a configuration file", "", orusapi.NewGenerateConfigCmd(parser)) + + bootstrapParser.NamespaceDelimiter = "-" + bootstrapParser.EnvNamespaceDelimiter = "_" + bootstrapParser.EnvNamespace = "CARNET" + bootstrapParser.AddGroup("Configuration", "Configuration file", ConfigFileOption) + g, err = bootstrapParser.AddGroup("Logging", "Logging options", LoggingOptions) + if err != nil { + panic(err) + } + g.Namespace="log" + g.EnvNamespace="LOG" + }