Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions internal/core/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package core

import (
"errors"
"fmt"

"github.com/caarlos0/env/v10"
Expand Down Expand Up @@ -137,11 +138,23 @@ type Config struct {

var config *Config

// startupErrors collects configuration failures raised while packages
// initialise. They cannot be logged where they happen, because logging is not
// configured until the command runs, and printing them bypasses the
// configured log format. Validate reports them instead.
var startupErrors []error

// RecordStartupError stores a configuration failure for Validate to report.
// Only safe to call during package initialisation, which is single threaded.
func RecordStartupError(err error) {
if err != nil {
startupErrors = append(startupErrors, err)
}
}

func init() {
config = &Config{}
if err := env.Parse(config); err != nil {
fmt.Printf("%+v\n", err)
}
RecordStartupError(env.Parse(config))
}

func ReadConfig() *Config {
Expand All @@ -150,6 +163,10 @@ func ReadConfig() *Config {

// Validate reports settings that would otherwise fail quietly at request time.
func (c *Config) Validate() error {
if len(startupErrors) > 0 {
return fmt.Errorf("invalid configuration: %w", errors.Join(startupErrors...))
}

if c.OutputFormat.Default == "" {
return nil
}
Expand Down
56 changes: 56 additions & 0 deletions internal/core/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package core

import (
"errors"
"testing"

"github.com/stretchr/testify/require"
)

// A malformed setting used to be printed and ignored, so the service started
// with silent defaults. Validate reports it instead.
func TestValidateReportsStartupErrors(t *testing.T) {
saved := startupErrors
t.Cleanup(func() { startupErrors = saved })

startupErrors = []error{errors.New(`strconv.ParseInt: parsing "abc"`)}

config := *ReadConfig()
err := config.Validate()

require.Error(t, err)
require.Contains(t, err.Error(), "invalid configuration")
require.Contains(t, err.Error(), "abc")
}

func TestValidateAcceptsAWorkingConfiguration(t *testing.T) {
saved := startupErrors
t.Cleanup(func() { startupErrors = saved })
startupErrors = nil

config := *ReadConfig()
config.OutputFormat.Default = ""

require.NoError(t, config.Validate())
}

func TestValidateRejectsAnUnknownDefaultFormat(t *testing.T) {
saved := startupErrors
t.Cleanup(func() { startupErrors = saved })
startupErrors = nil

config := *ReadConfig()
config.OutputFormat.Default = "WEBP"

require.Error(t, config.Validate(), "the map is keyed in lower case")
}

func TestRecordStartupErrorIgnoresNil(t *testing.T) {
saved := startupErrors
t.Cleanup(func() { startupErrors = saved })
startupErrors = nil

RecordStartupError(nil)

require.Empty(t, startupErrors)
}
7 changes: 2 additions & 5 deletions internal/core/encryption.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"fmt"
"github.com/caarlos0/env/v10"
"io"
"log/slog"
"strings"
)

Expand All @@ -22,13 +21,11 @@ var salt = []byte("go-dims")

func init() {
envConfig := Signing{}
if err := env.Parse(&envConfig); err != nil {
fmt.Printf("%+v\n", err)
}
RecordStartupError(env.Parse(&envConfig))

var err error
if encryptionKey, err = deriveKey(envConfig.SigningKey); err != nil {
slog.Error("failed to derive encryption key", "error", err)
RecordStartupError(fmt.Errorf("failed to derive the encryption key: %w", err))
return
}
}
Expand Down
5 changes: 1 addition & 4 deletions internal/core/image.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package core

import (
"fmt"
"github.com/beetlebugorg/go-dims/internal/gox/imagex/colorx"
"github.com/caarlos0/env/v10"
"golang.org/x/exp/slices"
Expand Down Expand Up @@ -46,9 +45,7 @@ var defaultSourceBackend SourceBackend

func RegisterImageBackend(sourceBackend SourceBackend) {
config := Source{}
if err := env.Parse(&config); err != nil {
fmt.Printf("%+v\n", err)
}
RecordStartupError(env.Parse(&config))

allSourceBackends = append(allSourceBackends, sourceBackend)

Expand Down
5 changes: 1 addition & 4 deletions internal/source/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package source

import (
"context"
"fmt"
"github.com/beetlebugorg/go-dims/internal/core"
"github.com/caarlos0/env/v10"
"github.com/davidbyttow/govips/v2/vips"
Expand All @@ -19,9 +18,7 @@ type fileSourceBackend struct {

func init() {
envConfig := core.FileSource{}
if err := env.Parse(&envConfig); err != nil {
fmt.Printf("%+v\n", err)
}
core.RecordStartupError(env.Parse(&envConfig))

core.RegisterImageBackend(NewFileSourceBackend(envConfig.BaseDir))
}
Expand Down
5 changes: 1 addition & 4 deletions internal/source/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package source

import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
Expand Down Expand Up @@ -37,9 +36,7 @@ var s3Client = sync.OnceValues(func() (*s3.Client, error) {

func init() {
envConfig := core.S3{}
if err := env.Parse(&envConfig); err != nil {
fmt.Printf("%+v\n", err)
}
core.RecordStartupError(env.Parse(&envConfig))

core.RegisterImageBackend(NewS3SourceBackend(envConfig))
}
Expand Down
Loading