mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-12 00:34:13 +01:00
Config: Fix fallback that loads defaults from config/defaults.yml #5325
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
@@ -10,6 +10,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
@@ -264,17 +266,52 @@ func (c *Config) OptionsYaml() string {
|
||||
return fs.Abs(c.options.OptionsYaml)
|
||||
}
|
||||
|
||||
// DefaultsYaml resolves the default options YAML file. When
|
||||
// PHOTOPRISM_DEFAULTS_YAML points to a readable file we use it; otherwise we
|
||||
// fall back to `defaults.{yml,yaml}` inside the active config directory.
|
||||
// This allows instances without `/etc/photoprism/defaults.yml` to
|
||||
// load local defaults, e.g., in containerized environments.
|
||||
func (c *Config) DefaultsYaml() string {
|
||||
if !fs.FileExistsNotEmpty(c.options.DefaultsYaml) {
|
||||
return fs.ConfigFilePath(c.ConfigPath(), "defaults", fs.ExtYml)
|
||||
// configPath resolves the config path name from the CLI context.
|
||||
func configPath(ctx *cli.Context) string {
|
||||
if dir := ctx.String("config-path"); dir != "" {
|
||||
return fs.Abs(dir)
|
||||
}
|
||||
|
||||
return fs.Abs(c.options.DefaultsYaml)
|
||||
storagePath := ctx.String("storage-path")
|
||||
|
||||
if storagePath == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
storagePath = fs.Abs(storagePath)
|
||||
|
||||
if fs.PathExists(filepath.Join(storagePath, fs.SettingsDir)) {
|
||||
return filepath.Join(storagePath, fs.SettingsDir)
|
||||
}
|
||||
|
||||
return filepath.Join(storagePath, fs.ConfigDir)
|
||||
}
|
||||
|
||||
// defaultsYaml resolves the defaults file from CLI/env overrides and falls back
|
||||
// to `defaults.{yml,yaml}` inside the active config directory when the override
|
||||
// is missing or unreadable.
|
||||
func defaultsYaml(ctx *cli.Context) string {
|
||||
fileName := ctx.String("defaults-yaml")
|
||||
|
||||
if fileName != "" && fs.FileExistsNotEmpty(fileName) {
|
||||
return fs.Abs(fileName)
|
||||
}
|
||||
|
||||
fileName = fs.ConfigFilePath(configPath(ctx), "defaults", fs.ExtYml)
|
||||
|
||||
if fs.FileExistsNotEmpty(fileName) {
|
||||
return fs.Abs(fileName)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// DefaultsYaml returns the defaults file path that was resolved during option
|
||||
// initialization (CLI/env override first, then config-path fallback). Callers
|
||||
// use this to locate the concrete defaults location without re-running the
|
||||
// resolution logic.
|
||||
func (c *Config) DefaultsYaml() string {
|
||||
return c.options.DefaultsYaml
|
||||
}
|
||||
|
||||
// HubConfigFile returns the backend API config filename, honoring either the
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
gc "github.com/patrickmn/go-cache"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
@@ -572,3 +573,31 @@ func TestConfig_SettingsYamlDefaults(t *testing.T) {
|
||||
assert.NotEqual(t, c.SettingsYaml(), name1)
|
||||
assert.NotEqual(t, c.SettingsYaml(), name3)
|
||||
}
|
||||
|
||||
func TestDefaultsYamlResolution(t *testing.T) {
|
||||
t.Run("ExplicitFlag", func(t *testing.T) {
|
||||
ctx := CliTestContext()
|
||||
file := filepath.Join(t.TempDir(), "explicit-defaults.yml")
|
||||
require.NoError(t, os.WriteFile(file, []byte("Test: true"), fs.ModeFile))
|
||||
require.NoError(t, ctx.Set("defaults-yaml", file))
|
||||
got := defaultsYaml(ctx)
|
||||
require.Equal(t, fs.Abs(file), got)
|
||||
})
|
||||
t.Run("ConfigFallback", func(t *testing.T) {
|
||||
ctx := CliTestContext()
|
||||
configDir := filepath.Join(t.TempDir(), "cfg")
|
||||
require.NoError(t, os.MkdirAll(configDir, fs.ModeDir))
|
||||
file := filepath.Join(configDir, "defaults.yml")
|
||||
require.NoError(t, os.WriteFile(file, []byte("SiteUrl: https://example.com"), fs.ModeFile))
|
||||
require.NoError(t, ctx.Set("defaults-yaml", ""))
|
||||
require.NoError(t, ctx.Set("config-path", configDir))
|
||||
got := defaultsYaml(ctx)
|
||||
require.Equal(t, fs.Abs(file), got)
|
||||
})
|
||||
t.Run("MissingReturnsEmpty", func(t *testing.T) {
|
||||
ctx := CliTestContext()
|
||||
require.NoError(t, ctx.Set("defaults-yaml", filepath.Join(t.TempDir(), "missing.yml")))
|
||||
require.NoError(t, ctx.Set("config-path", t.TempDir()))
|
||||
require.Equal(t, "", defaultsYaml(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -297,10 +297,8 @@ func NewOptions(ctx *cli.Context) *Options {
|
||||
c.BackupAlbums = true
|
||||
|
||||
// Initialize options with the values from the "defaults.yml" file, if it exists.
|
||||
if defaultsYaml := ctx.String("defaults-yaml"); defaultsYaml == "" {
|
||||
log.Tracef("config: defaults file was not specified")
|
||||
} else if c.DefaultsYaml = fs.Abs(defaultsYaml); !fs.FileExists(c.DefaultsYaml) {
|
||||
log.Tracef("config: defaults file %s does not exist", clean.Log(c.DefaultsYaml))
|
||||
if c.DefaultsYaml = defaultsYaml(ctx); !fs.FileExistsNotEmpty(c.DefaultsYaml) {
|
||||
log.Tracef("config: defaults file is empty or missing")
|
||||
} else if err := c.Load(c.DefaultsYaml); err != nil {
|
||||
log.Warnf("config: failed loading defaults from %s (%s)", clean.Log(c.DefaultsYaml), err)
|
||||
}
|
||||
|
||||
@@ -410,6 +410,7 @@ func CliTestContext() *cli.Context {
|
||||
globalSet.String("import-path", config.OriginalsPath, "doc")
|
||||
globalSet.String("cache-path", config.OriginalsPath, "doc")
|
||||
globalSet.String("temp-path", config.OriginalsPath, "doc")
|
||||
globalSet.String("defaults-yaml", config.DefaultsYaml, "doc")
|
||||
globalSet.String("cluster-uuid", config.ClusterUUID, "doc")
|
||||
globalSet.String("backup-path", config.StoragePath, "doc")
|
||||
globalSet.Int("backup-retain", config.BackupRetain, "doc")
|
||||
@@ -446,6 +447,7 @@ func CliTestContext() *cli.Context {
|
||||
LogErr(c.Set("import-path", config.ImportPath))
|
||||
LogErr(c.Set("cache-path", config.CachePath))
|
||||
LogErr(c.Set("temp-path", config.TempPath))
|
||||
LogErr(c.Set("defaults-yaml", config.DefaultsYaml))
|
||||
LogErr(c.Set("backup-path", config.BackupPath))
|
||||
LogErr(c.Set("backup-retain", strconv.Itoa(config.BackupRetain)))
|
||||
LogErr(c.Set("backup-schedule", config.BackupSchedule))
|
||||
|
||||
Reference in New Issue
Block a user