72 lines
2.1 KiB
Ruby
72 lines
2.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'yaml'
|
|
|
|
module Opendax
|
|
# Loads config/app.yml and deep-merges an environment overlay when present.
|
|
#
|
|
# Overlay resolution (first match wins):
|
|
# 1. OPENDAX_ENV=local|staging|production → config/app.{env}.yml
|
|
# 2. If OPENDAX_ENV unset and config/app.local.yml exists → use local overlay
|
|
#
|
|
# Never commit real secrets to config/app.yml — use app.local.yml or app.production.yml.
|
|
module ConfigLoader
|
|
BASE_PATH = 'config/app.yml'
|
|
|
|
module_function
|
|
|
|
def load
|
|
base = load_yaml_hash!(BASE_PATH, 'base config')
|
|
overlay_path = resolve_overlay_path
|
|
return base unless overlay_path && File.exist?(overlay_path)
|
|
|
|
overlay = load_yaml_hash!(overlay_path, 'overlay config')
|
|
deep_merge(base, overlay)
|
|
end
|
|
|
|
def load_yaml_hash!(path, label)
|
|
data = YAML.load_file(path)
|
|
return data if data.is_a?(Hash)
|
|
|
|
raise TypeError,
|
|
"#{label} #{path} must be a YAML mapping (Hash), got #{data.class}. " \
|
|
'Check syntax — quote values that contain colons (e.g. database passwords).'
|
|
end
|
|
|
|
def resolve_overlay_path
|
|
env = ENV['OPENDAX_ENV'].to_s.strip
|
|
if env.empty?
|
|
return 'config/app.local.yml' if File.exist?('config/app.local.yml')
|
|
|
|
return nil
|
|
end
|
|
|
|
"config/app.#{env}.yml"
|
|
end
|
|
|
|
def active_overlay
|
|
path = resolve_overlay_path
|
|
path if path && File.exist?(path)
|
|
end
|
|
|
|
def deep_merge(base, overlay)
|
|
unless base.is_a?(Hash) && overlay.is_a?(Hash)
|
|
raise TypeError,
|
|
"deep_merge expects Hash + Hash, got #{base.class} + #{overlay.class}"
|
|
end
|
|
|
|
base.merge(overlay) do |key, old_val, new_val|
|
|
if old_val.is_a?(Hash) && new_val.is_a?(Hash)
|
|
deep_merge(old_val, new_val)
|
|
elsif old_val.is_a?(Hash) && !new_val.is_a?(Hash)
|
|
raise TypeError,
|
|
"Config type mismatch at #{key}: base has Hash but overlay has " \
|
|
"#{new_val.class}. Quote scalar values in app.staging.yml (passwords with ':' need quotes)."
|
|
else
|
|
new_val
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|