require "hiera/util/win32"
require "hiera/console_logger"
require "hiera/puppet_logger"
require "hiera/noop_logger"
require "hiera/fallback_logger"
require "hiera/filecache"
# Loggers are pluggable, just provide a class called
# Hiera::Foo_logger and respond to :warn and :debug
# See hiera-puppet for an example that uses the Puppet
# loging system instead of our own
require "hiera/#{logger}_logger"
@logger = Hiera::FallbackLogger.new(
Hiera.const_get("#{logger.capitalize}_logger"),
@logger = Hiera::Console_logger
warn("Failed to load #{logger} logger: #{e.class}: #{e}")
def warn(msg); @logger.warn(msg); end
def debug(msg); @logger.debug(msg); end
attr_reader :options, :config
# If the config option is a string its assumed to be a filename,
# else a hash of what would have been in the YAML config file
def initialize(options={})
config = options[:config]
# Look in codedir first, then confdir
config = File.join(Util.code_dir, 'hiera.yaml')
config = File.join(Util.config_dir, 'hiera.yaml') unless File.exist?(config)
@config = Config.load(config)
# Calls the backends to do the actual lookup.
# The _scope_ can be anything that responds to `[]`, if you have input
# data like a Puppet Scope that does not you can wrap that data in a
# class that has a `[]` method that fetches the data from your source.
# See hiera-puppet for an example of this.
# The order-override will insert as first in the hierarchy a data source
# Possible values for the _resolution_type_ parameter:
# - _:priority_ - This is the default. First found value is returned and no merge is performed
# - _:array_ - An array merge lookup assembles a value from every matching level of the hierarchy. It retrieves all
# of the (string or array) values for a given key, then flattens them into a single array of unique values.
# If _priority_ lookup can be thought of as a “default with overrides” pattern, _array_ merge lookup can be though
# of as “default with additions.”
# - _:hash_ - A hash merge lookup assembles a value from every matching level of the hierarchy. It retrieves all of
# the (hash) values for a given key, then merges the hashes into a single hash. Hash merge lookups will fail with
# an error if any of the values found in the data sources are strings or arrays. It only works when every value
# found is a hash. The actual merge behavior is determined by looking up the keys `:merge_behavior` and
# `:deep_merge_options` in the Hiera config. `:merge_behavior` can be set to `:deep`, :deeper` or `:native`
# (explained in detail below).
# - _{ deep merge options }_ - Configured values for `:merge_behavior` and `:deep_merge_options`will be completely
# ignored. Instead the _resolution_type_ will be a `:hash` merge where the `:merge_behavior` will be the value
# keyed by `:behavior` in the given hash and the `:deep_merge_options` will be the remaining top level entries of
# Valid behaviors for the _:hash_ resolution type:
# - _native_ - Performs a simple hash-merge by overwriting keys of lower lookup priority.
# - _deeper_ - In a deeper hash merge, Hiera recursively merges keys and values in each source hash. For each key,
# - only present in one source hash, it goes into the final hash.
# - a string/number/boolean and exists in two or more source hashes, the highest priority value goes into
# - an array and exists in two or more source hashes, the values from each source are merged into a single
# array and de-duplicated (but not automatically flattened, as in an array merge lookup).
# - a hash and exists in two or more source hashes, the values from each source are recursively merged, as
# though they were source hashes.
# - mismatched between two or more source hashes, we haven’t validated the behavior. It should act as
# described in the deep_merge gem documentation.
# - _deep_ - In a deep hash merge, Hiera behaves the same as for _deeper_, except that when a string/number/boolean
# exists in two or more source hashes, the lowest priority value goes into the final hash. This is considered
# largely useless and should be avoided. Use _deeper_ instead.
# The _merge_ can be given as a hash with the mandatory key `:strategy` to denote the actual strategy. This
# is useful for the `:deeper` and `:deep` strategy since they can use additional options to control the behavior.
# The options can be passed as top level keys in the `merge` parameter when it is a given as a hash. Recognized
# - 'knockout_prefix' Set to string value to signify prefix which deletes elements from existing element. Defaults is _undef_
# - 'sort_merged_arrays' Set to _true_ to sort all arrays that are merged together. Default is _false_
# - 'merge_hash_arrays' Set to _true_ to merge hashes within arrays. Default is _false_
# @param key [String] The key to lookup
# @param default [Object,nil] The value to return when there is no match for _key_
# @param scope [#[],nil] The scope to use for the lookup
# @param order_override [#[]] An override that will considered the first source of lookup
# @param resolution_type [String,Hash<Symbol,String>] Symbolic resolution type or deep merge configuration
# @return [Object] The found value or the given _default_ value
def lookup(key, default, scope, order_override=nil, resolution_type=:priority)
Backend.lookup(key, default, scope, order_override, resolution_type)