Skip to content

Commit

Permalink
feat: config flag sets config file location (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
CallumKerson authored Mar 15, 2023
1 parent 828deda commit a8e895b
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 131 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ out/
temp/
dist/
.task/
athenaeum
/athenaeum
7 changes: 6 additions & 1 deletion Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ tasks:
compile:
desc: "Compiles for the current OS and architecture"
cmds:
- go build -ldflags "-s -w" -o . ./...
- go build -ldflags "-s -w -X main.Version={{.VERSION}} -X main.Commit={{.COMMIT}} -X main.Date={{now | date "2006-01-02T15:04:05-0700"}}" -o . ./...
vars:
COMMIT:
sh: git rev-parse HEAD
VERSION:
sh: echo "$(git describe --tags)-dev+$(git rev-parse --short HEAD)"

linux-compile:
desc: "Compiles for Linux"
Expand Down
82 changes: 82 additions & 0 deletions cmd/athenaeum/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"context"
"os"
"strings"

"github.com/spf13/cobra"

"github.com/CallumKerson/Athenaeum/internal/adapters/bolt"
"github.com/CallumKerson/Athenaeum/internal/adapters/logrus"
audiobooksService "github.com/CallumKerson/Athenaeum/internal/audiobooks/service"
mediaService "github.com/CallumKerson/Athenaeum/internal/media/service"
podcastService "github.com/CallumKerson/Athenaeum/internal/podcasts/service"
transportHttp "github.com/CallumKerson/Athenaeum/internal/transport/http"
)

const (
shortHelp = "an audiobook server that provides a podcast feed"
)

func main() {
cmd := NewRootCommand()
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
}

// Build the cobra command that handles our command line tool.
func NewRootCommand() *cobra.Command {
pathToConfig := ""
var cfg Config

// Define our command
rootCmd := &cobra.Command{
Use: "athenaeum",
Short: shortHelp,
PreRunE: func(cmd *cobra.Command, args []string) error {
return InitConfig(&cfg, pathToConfig, cmd.OutOrStderr())
},
RunE: func(cmd *cobra.Command, args []string) error {
logger := logrus.NewLogger()
setLogLevel(logger, cfg.GetLogLevel())
mediaSvc := mediaService.New(logger, cfg.GetMediaServiceOpts()...)
boltAudiobookStore, err := bolt.NewAudiobookStore(logger, true, cfg.GetBoltDBOps()...)
if err != nil {
return err
}
audiobookSvc := audiobooksService.New(mediaSvc, boltAudiobookStore, logger)
if errScan := audiobookSvc.UpdateAudiobooks(context.Background()); errScan != nil {
return errScan
}
podcastSvc := podcastService.New(audiobookSvc, logger, cfg.GetPodcastServiceOpts()...)
httpHandler := transportHttp.NewHandler(podcastSvc, audiobookSvc, logger, cfg.GetHTTPHandlerOpts()...)

return transportHttp.Serve(httpHandler, cfg.Port, logger)
},
}

// Define cobra flags, the default value has the lowest (least significant) precedence
rootCmd.PersistentFlags().StringVarP(&pathToConfig, "config", "c", pathToConfig, "path to config file")
rootCmd.SilenceUsage = true

rootCmd.Version = Version

rootCmd.AddCommand(NewVersionCommand())
return rootCmd
}

func setLogLevel(logger *logrus.Logger, level string) {
level = strings.ToLower(level)
switch level {
case "debug":
logger.SetLevelDebug()
case "warn":
logger.SetLevelWarn()
case "error":
logger.SetLevelError()
default:
logger.SetLevelInfo()
}
}
55 changes: 18 additions & 37 deletions cmd/athenaeum/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ package main

import (
"fmt"
"path/filepath"
"io"
"strings"

"github.com/spf13/viper"

"github.com/CallumKerson/loggerrific"

"github.com/CallumKerson/Athenaeum/internal/adapters/bolt"
mediaService "github.com/CallumKerson/Athenaeum/internal/media/service"
podcastService "github.com/CallumKerson/Athenaeum/internal/podcasts/service"
transportHttp "github.com/CallumKerson/Athenaeum/internal/transport/http"
)

const (
defaultPort = 8080
)

type Config struct {
Host string
Port int
DB DB
Media Media
Podcast Podcast
Expand All @@ -37,32 +37,13 @@ type Media struct {
}

type Podcast struct {
Root string
Copyright string
Explicit bool
Language string
Author string
Email string
}

func (c *Config) GetMediaHost() string {
return fmt.Sprintf("%s/%s", c.Host, c.Media.HostPath)
}

func (c *Config) GetMediaServiceOpts() []mediaService.Option {
return []mediaService.Option{mediaService.WithPathToMediaRoot(c.Media.Root)}
}

func (c *Config) GetBoltDBOps() []bolt.Option {
return []bolt.Option{bolt.WithDBDefaults(), bolt.WithPathToDBDirectory(c.DB.Root)}
}

func (c *Config) GetPodcastServiceOpts() []podcastService.Option {
return []podcastService.Option{podcastService.WithHost(c.Host),
podcastService.WithMediaPath(c.Media.HostPath),
podcastService.WithPodcastFeedInfo(c.Podcast.Explicit, c.Podcast.Language, c.Podcast.Author, c.Podcast.Email, c.Podcast.Copyright)}
}

func (c *Config) GetLogLevel() string {
return c.Log.Level
}
Expand All @@ -71,15 +52,15 @@ func (c *Config) GetHTTPHandlerOpts() []transportHttp.HandlerOption {
return []transportHttp.HandlerOption{transportHttp.WithMediaConfig(c.Media.Root, c.Media.HostPath), transportHttp.WithVersion(Version)}
}

func NewConfig(port int, logger loggerrific.Logger) (*Config, error) {
func InitConfig(cfg *Config, pathToConfigFile string, out io.Writer) error {
viper.SetDefault("Podcast.Copyright", "None")
viper.SetDefault("Podcast.Explicit", true)
viper.SetDefault("Podcast.Language", "EN")
viper.SetDefault("Podcast.Root", "/srv/podcasts")
viper.SetDefault("Media.HostPath", "/media")
viper.SetDefault("Media.Root", "/srv/media")
viper.SetDefault("DB.Root", "/usr/local/athenaeum")
viper.SetDefault("Host", fmt.Sprintf("http://localhost:%d", port))
viper.SetDefault("Port", defaultPort)
viper.SetDefault("Host", fmt.Sprintf("http://localhost:%d", defaultPort))
viper.SetDefault("Log.Level", "INFO")

replacer := strings.NewReplacer(".", "_")
Expand All @@ -100,21 +81,21 @@ func NewConfig(port int, logger loggerrific.Logger) (*Config, error) {

viper.AutomaticEnv()

pathToConfig := viper.GetString("Config.Path")
if pathToConfigFile == "" {
pathToConfigFile = viper.GetString("Config.Path")
}

if !filepath.IsAbs(pathToConfig) {
logger.Infoln("No valid config path found from environment variable ATHENAEUM_CONFIG_PATH,",
if pathToConfigFile == "" {
fmt.Fprintln(out, "No valid config path provided by flag or found from environment variable ATHENAEUM_CONFIG_PATH,",
"reading config from environment variables only")
} else {
viper.SetConfigFile(pathToConfig)
viper.SetConfigFile(pathToConfigFile)
err := viper.ReadInConfig()
if err != nil {
logger.WithError(err).Errorln("Cannot read config from file")
return nil, err
return fmt.Errorf("config error: %w", err)
}
}

var cfg Config
err := viper.Unmarshal(&cfg)
return &cfg, err
err := viper.Unmarshal(cfg)
return err
}
27 changes: 27 additions & 0 deletions cmd/athenaeum/config_opts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"fmt"

"github.com/CallumKerson/Athenaeum/internal/adapters/bolt"
mediaService "github.com/CallumKerson/Athenaeum/internal/media/service"
podcastService "github.com/CallumKerson/Athenaeum/internal/podcasts/service"
)

func (c *Config) GetMediaHost() string {
return fmt.Sprintf("%s/%s", c.Host, c.Media.HostPath)
}

func (c *Config) GetMediaServiceOpts() []mediaService.Option {
return []mediaService.Option{mediaService.WithPathToMediaRoot(c.Media.Root)}
}

func (c *Config) GetBoltDBOps() []bolt.Option {
return []bolt.Option{bolt.WithDBDefaults(), bolt.WithPathToDBDirectory(c.DB.Root)}
}

func (c *Config) GetPodcastServiceOpts() []podcastService.Option {
return []podcastService.Option{podcastService.WithHost(c.Host),
podcastService.WithMediaPath(c.Media.HostPath),
podcastService.WithPodcastFeedInfo(c.Podcast.Explicit, c.Podcast.Language, c.Podcast.Author, c.Podcast.Email, c.Podcast.Copyright)}
}
41 changes: 34 additions & 7 deletions cmd/athenaeum/config_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package main

import (
"bytes"
"io/fs"
"os"
"path/filepath"
"testing"

"github.com/spf13/viper"
"github.com/stretchr/testify/assert"

"github.com/CallumKerson/loggerrific/tlogger"
)

func TestConfig_FromEnvironment(t *testing.T) {
Expand All @@ -20,9 +19,10 @@ func TestConfig_FromEnvironment(t *testing.T) {
})
t.Cleanup(envVarCleanup)
viper.Reset()
var config Config

// when
config, err := NewConfig(defaultPort, tlogger.NewTLogger(t))
err := InitConfig(&config, "", &bytes.Buffer{})

// then
assert.NoError(t, err)
Expand All @@ -31,6 +31,29 @@ func TestConfig_FromEnvironment(t *testing.T) {
}

func TestConfig_FromFile(t *testing.T) {
// given
configFilePath := filepath.Join(t.TempDir(), "config.yaml")
viper.Reset()

configYAML := `---
Host: "http://localhost:8088"
Podcast:
Language: FR
`
err := os.WriteFile(configFilePath, []byte(configYAML), 0644)
assert.NoError(t, err)
var config Config

// when
err = InitConfig(&config, configFilePath, &bytes.Buffer{})

// then
assert.NoError(t, err)
assert.Equal(t, "http://localhost:8088", config.Host)
assert.Equal(t, "FR", config.Podcast.Language)
}

func TestConfig_FromFile_DefiniedInEnvironment(t *testing.T) {
// given
configFilePath := filepath.Join(t.TempDir(), "config.yaml")
envVarCleanup := envVarSetter(t, map[string]string{
Expand All @@ -46,9 +69,10 @@ Podcast:
`
err := os.WriteFile(configFilePath, []byte(configYAML), 0644)
assert.NoError(t, err)
var config Config

// when
config, err := NewConfig(defaultPort, tlogger.NewTLogger(t))
err = InitConfig(&config, "", &bytes.Buffer{})

// then
assert.NoError(t, err)
Expand All @@ -71,9 +95,10 @@ Host: "http://localhost:8083"
`
err := os.WriteFile(configFilePath, []byte(configYAML), 0644)
assert.NoError(t, err)
var config Config

// when
config, err := NewConfig(defaultPort, tlogger.NewTLogger(t))
err = InitConfig(&config, "", &bytes.Buffer{})

// then
assert.NoError(t, err)
Expand All @@ -83,9 +108,10 @@ Host: "http://localhost:8083"
func TestConfig_DefaultsOnly(t *testing.T) {
// given
viper.Reset()
var config Config

// when
config, err := NewConfig(defaultPort, tlogger.NewTLogger(t))
err := InitConfig(&config, "", &bytes.Buffer{})

// then
assert.NoError(t, err)
Expand All @@ -106,9 +132,10 @@ func TestConfig_BadFile(t *testing.T) {
})
t.Cleanup(envVarCleanup)
viper.Reset()
var config Config

// when
_, err := NewConfig(defaultPort, tlogger.NewTLogger(t))
err := InitConfig(&config, "", &bytes.Buffer{})

// then
if assert.Error(t, err) {
Expand Down
Loading

0 comments on commit a8e895b

Please sign in to comment.