Skip to content

Commit b45abbd

Browse files
committed
Config: Fix fallback that loads defaults from config/defaults.yml photoprism#5325
Signed-off-by: Michael Mayer <[email protected]>
1 parent 2e85caa commit b45abbd

File tree

4 files changed

+79
-13
lines changed

4 files changed

+79
-13
lines changed

internal/config/config_storage.go

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"strings"
1111
"sync"
1212

13+
"github.com/urfave/cli/v2"
14+
1315
"github.com/photoprism/photoprism/pkg/clean"
1416
"github.com/photoprism/photoprism/pkg/fs"
1517
"github.com/photoprism/photoprism/pkg/rnd"
@@ -264,17 +266,52 @@ func (c *Config) OptionsYaml() string {
264266
return fs.Abs(c.options.OptionsYaml)
265267
}
266268

267-
// DefaultsYaml resolves the default options YAML file. When
268-
// PHOTOPRISM_DEFAULTS_YAML points to a readable file we use it; otherwise we
269-
// fall back to `defaults.{yml,yaml}` inside the active config directory.
270-
// This allows instances without `/etc/photoprism/defaults.yml` to
271-
// load local defaults, e.g., in containerized environments.
272-
func (c *Config) DefaultsYaml() string {
273-
if !fs.FileExistsNotEmpty(c.options.DefaultsYaml) {
274-
return fs.ConfigFilePath(c.ConfigPath(), "defaults", fs.ExtYml)
269+
// configPath resolves the config path name from the CLI context.
270+
func configPath(ctx *cli.Context) string {
271+
if dir := ctx.String("config-path"); dir != "" {
272+
return fs.Abs(dir)
273+
}
274+
275+
storagePath := ctx.String("storage-path")
276+
277+
if storagePath == "" {
278+
return ""
275279
}
276280

277-
return fs.Abs(c.options.DefaultsYaml)
281+
storagePath = fs.Abs(storagePath)
282+
283+
if fs.PathExists(filepath.Join(storagePath, fs.SettingsDir)) {
284+
return filepath.Join(storagePath, fs.SettingsDir)
285+
}
286+
287+
return filepath.Join(storagePath, fs.ConfigDir)
288+
}
289+
290+
// defaultsYaml resolves the defaults file from CLI/env overrides and falls back
291+
// to `defaults.{yml,yaml}` inside the active config directory when the override
292+
// is missing or unreadable.
293+
func defaultsYaml(ctx *cli.Context) string {
294+
fileName := ctx.String("defaults-yaml")
295+
296+
if fileName != "" && fs.FileExistsNotEmpty(fileName) {
297+
return fs.Abs(fileName)
298+
}
299+
300+
fileName = fs.ConfigFilePath(configPath(ctx), "defaults", fs.ExtYml)
301+
302+
if fs.FileExistsNotEmpty(fileName) {
303+
return fs.Abs(fileName)
304+
}
305+
306+
return ""
307+
}
308+
309+
// DefaultsYaml returns the defaults file path that was resolved during option
310+
// initialization (CLI/env override first, then config-path fallback). Callers
311+
// use this to locate the concrete defaults location without re-running the
312+
// resolution logic.
313+
func (c *Config) DefaultsYaml() string {
314+
return c.options.DefaultsYaml
278315
}
279316

280317
// HubConfigFile returns the backend API config filename, honoring either the

internal/config/config_storage_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
gc "github.com/patrickmn/go-cache"
1111
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
1213

1314
"github.com/photoprism/photoprism/pkg/fs"
1415
"github.com/photoprism/photoprism/pkg/rnd"
@@ -572,3 +573,31 @@ func TestConfig_SettingsYamlDefaults(t *testing.T) {
572573
assert.NotEqual(t, c.SettingsYaml(), name1)
573574
assert.NotEqual(t, c.SettingsYaml(), name3)
574575
}
576+
577+
func TestDefaultsYamlResolution(t *testing.T) {
578+
t.Run("ExplicitFlag", func(t *testing.T) {
579+
ctx := CliTestContext()
580+
file := filepath.Join(t.TempDir(), "explicit-defaults.yml")
581+
require.NoError(t, os.WriteFile(file, []byte("Test: true"), fs.ModeFile))
582+
require.NoError(t, ctx.Set("defaults-yaml", file))
583+
got := defaultsYaml(ctx)
584+
require.Equal(t, fs.Abs(file), got)
585+
})
586+
t.Run("ConfigFallback", func(t *testing.T) {
587+
ctx := CliTestContext()
588+
configDir := filepath.Join(t.TempDir(), "cfg")
589+
require.NoError(t, os.MkdirAll(configDir, fs.ModeDir))
590+
file := filepath.Join(configDir, "defaults.yml")
591+
require.NoError(t, os.WriteFile(file, []byte("SiteUrl: https://example.com"), fs.ModeFile))
592+
require.NoError(t, ctx.Set("defaults-yaml", ""))
593+
require.NoError(t, ctx.Set("config-path", configDir))
594+
got := defaultsYaml(ctx)
595+
require.Equal(t, fs.Abs(file), got)
596+
})
597+
t.Run("MissingReturnsEmpty", func(t *testing.T) {
598+
ctx := CliTestContext()
599+
require.NoError(t, ctx.Set("defaults-yaml", filepath.Join(t.TempDir(), "missing.yml")))
600+
require.NoError(t, ctx.Set("config-path", t.TempDir()))
601+
require.Equal(t, "", defaultsYaml(ctx))
602+
})
603+
}

internal/config/options.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,10 +297,8 @@ func NewOptions(ctx *cli.Context) *Options {
297297
c.BackupAlbums = true
298298

299299
// Initialize options with the values from the "defaults.yml" file, if it exists.
300-
if defaultsYaml := ctx.String("defaults-yaml"); defaultsYaml == "" {
301-
log.Tracef("config: defaults file was not specified")
302-
} else if c.DefaultsYaml = fs.Abs(defaultsYaml); !fs.FileExists(c.DefaultsYaml) {
303-
log.Tracef("config: defaults file %s does not exist", clean.Log(c.DefaultsYaml))
300+
if c.DefaultsYaml = defaultsYaml(ctx); !fs.FileExistsNotEmpty(c.DefaultsYaml) {
301+
log.Tracef("config: defaults file is empty or missing")
304302
} else if err := c.Load(c.DefaultsYaml); err != nil {
305303
log.Warnf("config: failed loading defaults from %s (%s)", clean.Log(c.DefaultsYaml), err)
306304
}

internal/config/test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ func CliTestContext() *cli.Context {
410410
globalSet.String("import-path", config.OriginalsPath, "doc")
411411
globalSet.String("cache-path", config.OriginalsPath, "doc")
412412
globalSet.String("temp-path", config.OriginalsPath, "doc")
413+
globalSet.String("defaults-yaml", config.DefaultsYaml, "doc")
413414
globalSet.String("cluster-uuid", config.ClusterUUID, "doc")
414415
globalSet.String("backup-path", config.StoragePath, "doc")
415416
globalSet.Int("backup-retain", config.BackupRetain, "doc")
@@ -446,6 +447,7 @@ func CliTestContext() *cli.Context {
446447
LogErr(c.Set("import-path", config.ImportPath))
447448
LogErr(c.Set("cache-path", config.CachePath))
448449
LogErr(c.Set("temp-path", config.TempPath))
450+
LogErr(c.Set("defaults-yaml", config.DefaultsYaml))
449451
LogErr(c.Set("backup-path", config.BackupPath))
450452
LogErr(c.Set("backup-retain", strconv.Itoa(config.BackupRetain)))
451453
LogErr(c.Set("backup-schedule", config.BackupSchedule))

0 commit comments

Comments
 (0)