From dd3d5cfc0014e5f7ce529602cac09a1de41bdc3d Mon Sep 17 00:00:00 2001 From: Slack Coder Date: Mon, 21 Oct 2024 08:59:36 -0500 Subject: Support multiple config files Read files from /etc/mirror/conf.d. --- cmd/mirror/main.go | 22 +++++++++++--- contrib/slackbuild/mirror.SlackBuild | 1 + contrib/slackbuild/rc.mirror | 2 +- internal/service/config.go | 59 ++++++++++++++++++++++++++++-------- internal/service/service.go | 2 +- 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/cmd/mirror/main.go b/cmd/mirror/main.go index e823039..e8a00ac 100644 --- a/cmd/mirror/main.go +++ b/cmd/mirror/main.go @@ -13,14 +13,16 @@ import ( var Version string type Flags struct { - Config string - Version bool + Config string + ConfigDir string + Version bool } func ParseFlags() *Flags { var flags Flags - flag.StringVar(&flags.Config, "config", "/etc/mirror/mirror.toml", "configuration file") + flag.StringVar(&flags.Config, "config", "/etc/mirror/mirror.toml", "configuration file which takes precedence") + flag.StringVar(&flags.ConfigDir, "config-dir", "/etc/mirror/conf.d", "configuration directory") flag.BoolVar(&flags.Version, "version", false, "print version") flag.Parse() @@ -39,13 +41,23 @@ func main() { if flags.Version { fmt.Println(Version) + os.Exit(0) } - cfg, err := service.ReadConfig(flags.Config) + var cfg service.Config + + c, err := service.ReadConfigDir(flags.ConfigDir) + exitOnError(err) + + cfg.Append(c) + + c, err = service.ReadConfig(flags.Config) exitOnError(err) - srv, err := service.NewService(cfg) + cfg.Append(c) + + srv, err := service.NewService(&cfg) exitOnError(err) err = srv.Run() diff --git a/contrib/slackbuild/mirror.SlackBuild b/contrib/slackbuild/mirror.SlackBuild index 9dadca2..fb1b92e 100644 --- a/contrib/slackbuild/mirror.SlackBuild +++ b/contrib/slackbuild/mirror.SlackBuild @@ -64,6 +64,7 @@ mkdir -p "$PKG/etc/rc.d" cat "$CWD/rc.mirror" > "$PKG/etc/rc.d/rc.mirror.new" mkdir -p $PKG/etc/mirror cat "$CWD/mirror.toml" > "$PKG/etc/mirror/mirror.toml.new" +mkdir -p $PKG/etc/mirror/conf.d mkdir -p "$PKG/var/log/mirror" cd "$PKG" diff --git a/contrib/slackbuild/rc.mirror b/contrib/slackbuild/rc.mirror index df3c72f..362a3f1 100644 --- a/contrib/slackbuild/rc.mirror +++ b/contrib/slackbuild/rc.mirror @@ -20,7 +20,7 @@ start() { --user=mirror \ --pidfiles=/run/mirror \ --output=/var/log/mirror/mirror.log \ - -- mirror -config /etc/mirror/mirror.toml + -- mirror } stop() { diff --git a/internal/service/config.go b/internal/service/config.go index 27368b3..bfe271e 100644 --- a/internal/service/config.go +++ b/internal/service/config.go @@ -3,6 +3,8 @@ package service import ( "fmt" "os" + "path" + "path/filepath" "time" "git.server.ky/slackcoder/mirror/internal" @@ -13,6 +15,10 @@ type Duration struct { time.Duration } +func DurationRef(v time.Duration) *Duration { + return &Duration{v} +} + func (s Duration) MarshalText() ([]byte, error) { return []byte(s.Duration.String()), nil } @@ -29,8 +35,8 @@ func (s *Duration) UnmarshalText(text []byte) error { // Global parameters type GlobalConfig struct { - MaxInterval Duration `toml:"max-interval"` - MinInterval Duration `toml:"min-interval"` + MaxInterval *Duration `toml:"max-interval"` + MinInterval *Duration `toml:"min-interval"` } type Config struct { @@ -44,18 +50,17 @@ func (c *Config) String() string { var DefaultConfig = Config{ GlobalConfig: GlobalConfig{ - MaxInterval: Duration{24 * time.Hour}, - MinInterval: Duration{time.Hour}, + MaxInterval: DurationRef(24 * time.Hour), + MinInterval: DurationRef(time.Hour), }, } +// Read the given configuration file. func ReadConfig(fp string) (*Config, error) { var config Config f, err := os.Open(fp) - if os.IsNotExist(err) { - return nil, nil - } else if err != nil { + if err != nil { return nil, err } defer f.Close() @@ -68,14 +73,42 @@ func ReadConfig(fp string) (*Config, error) { return &config, nil } -func (c *Config) Merge(src *Config) { - if c.MaxInterval.Duration == 0 && src.MaxInterval.Duration != 0 { +// Read all configuration in the given directory. +func ReadConfigDir(fp string) (*Config, error) { + var cfg Config + + confDPath := path.Join(path.Join(fp, "conf.d")) + confDDir, err := os.ReadDir(confDPath) + if os.IsNotExist(err) { + // No directory is an empty one. + return &Config{}, nil + } else if err != nil { + return nil, err + } + + for _, entry := range confDDir { + if filepath.Ext(entry.Name()) != ".toml" { + continue + } + + entryCfg, err := ReadConfig(filepath.Join(confDPath, entry.Name())) + if err != nil { + return nil, err + } + + cfg.Append(entryCfg) + } + + return &cfg, nil +} + +// Apply the given configuration parameters. +func (c *Config) Append(src *Config) { + if src.MaxInterval != nil { c.MaxInterval = src.MaxInterval } - if c.MinInterval.Duration == 0 && src.MinInterval.Duration != 0 { + if src.MinInterval != nil { c.MinInterval = src.MinInterval } - if len(c.Mirrors) == 0 { - c.Mirrors = src.Mirrors - } + c.Mirrors = append(c.Mirrors, src.Mirrors...) } diff --git a/internal/service/service.go b/internal/service/service.go index 637a1cf..21df14b 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -32,7 +32,7 @@ type Service struct { func NewService(cfg *Config) (*Service, error) { // Apply defaults - cfg.Merge(&DefaultConfig) + cfg.Append(&DefaultConfig) for _, cmd := range requiredCommands { if err := internal.RequireCommand(cmd); err != nil { -- cgit v1.2.3