require 'ostruct'
require 'pathname'
class Cartage
# The Cartage configuration structure. The supported Cartage-wide
# configuration fields are:
#
# +target+:: The target where the final Cartage package will be created. Sets
# Cartage#target. Equivalent to --target.
# +name+:: The name of the package to create. Sets Cartage#name. Equivalent
# to --name.
# +root_path+:: The root path of the application. Sets Cartage#root_path.
# Equivalent to --root-path.
# +timestamp+:: The timestamp for the final package. Sets Cartage#timestamp.
# Equivalent to --timestamp.
# +bundle_cache+:: The bundle cache. Sets Cartage#bundle_cache. Equivalent to
# --bundle-cache.
# +without+:: Groups to exclude from bundle installation. Sets
# Cartage#without_groups. Equivalent to --without.
# This value should be provided as an array.
# +plugins+:: A dictionary for plug-in configuration groups. See below for
# more information.
#
# Cartage configuration is not typically partitioned by an environment label,
# but can be. See the examples below for details.
#
# == Plug-Ins
#
# Plug-ins also keep configuration in the Cartage configuration structure,
# but as dictionary (hash) structures under the +plugins+ field. Each plug-in
# has its own key based on its name, so that the Manifest plug-in (if it had
# storable configuration values) would keep its configuration in a +manifest+
# key. See the examples below for details.
#
# == Loading Configuration
#
# When --config-file is specified, the configuration file will be
# loaded and parsed. If a filename is given, that file will be loaded. If a
# filename is not given, Cartage will look for the configuration in the
# following locations:
#
# * config/cartage.yml
# * ./cartage.yml
# * $HOME/.config/cartage.yml
# * $HOME/.cartage.yml
# * /etc/cartage.yml
#
# The contents of the configuration file are evaluated through ERB and then
# parsed from YAML and converted to nested OpenStruct objects. The basic
# environment example below would look like:
#
# #
# >
#
# == Examples
#
# Basic Cartage configuration:
#
# ---
# without:
# - test
# - development
# - assets
#
# With an environment set:
#
# ---
# development:
# without:
# - test
# - development
# - assets
#
# With the Manifest plug-in (note: the Manifest plug-in does *not* have
# configurable options; this is for example purposes only).
#
# ---
# without:
# - test
# - development
# - assets
# manifest:
# format: json
#
# With the Manifest plug-in and an environment:
#
# ---
# development:
# without:
# - test
# - development
# - assets
# manifest:
# format: json
class Config < OpenStruct
#:stopdoc:
DEFAULT_CONFIG_FILES = %w(
config/cartage.yml
./cartage.yml
~/.config/cartage.yml
~/.cartage.yml
/etc/cartage.yml
)
#:startdoc:
class << self
# Load a Cartage configuration file.
def load(filename)
config_file = resolve_config_file(filename)
config = YAML.load(ERB.new(config_file.read, nil, '%<>-').result)
new(ostructify(config))
end
private
def resolve_config_file(filename)
return unless filename
files = if filename == :default
DEFAULT_CONFIG_FILES
else
[ filename ]
end
file = files.find { |f| Pathname(f).expand_path.exist? }
if file
Pathname(file).expand_path
else
message = if filename
"Configuration file #{filename} does not exist."
else
"No default configuration file found."
end
raise ArgumentError, message
end
end
def ostructify(hash)
hash = hash.dup
hash.keys.each do |k|
hash[k.to_sym] = ostructify_recursively(hash.delete(k))
end
OpenStruct.new(hash)
end
def ostructify_recursively(object)
case object
when ::Array
object.map! { |i| ostructify_recursively(i) }
when ::OpenStruct
object = ostructify(object.to_h)
when ::Hash
object = ostructify(object)
end
object
end
end
# Convert the entire Config structure to a hash recursively.
def to_h
hashify(self)
end
# Override the default #to_yaml implementation.
def to_yaml
to_h.to_yaml
end
private
def hashify(ostruct)
{}.tap { |hash|
ostruct.each_pair do |k, v|
hash[k.to_s] = hashify_recursively(v)
end
}
end
def hashify_recursively(object)
case object
when ::Array
object.map! { |i| hashify_recursively(i) }
when ::OpenStruct, ::Hash
object = hashify(object)
end
object
end
end
end