Skip to content

Commit

Permalink
Restructure the setup config load order
Browse files Browse the repository at this point in the history
Change the structure to merge both the default configs and the user-defined configs separately. Then combine the two sets of merged configs.
  • Loading branch information
chuyingy authored and tbates-redarc committed Mar 4, 2024
1 parent a181177 commit 576568f
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 67 deletions.
4 changes: 2 additions & 2 deletions lib/ceedling.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ def self.register_plugin(name, prefix=nil)

# Register the plugin with Ceedling
require 'ceedling/defaults'
DEFAULT_CEEDLING_CONFIG[:plugins][:enabled] << name
DEFAULT_CEEDLING_CONFIG[:plugins][:load_paths] << gem_dir
CEEDLING_CONFIG_INTERNAL[:plugins][:enabled] << name
CEEDLING_CONFIG_INTERNAL[:plugins][:load_paths] << gem_dir
end
end

91 changes: 57 additions & 34 deletions lib/ceedling/configurator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,60 +79,61 @@ def reset_defaults(config)
# We do this because early config validation failures may need access to verbosity,
# but the accessors won't be available until after configuration is validated.
def set_verbosity(config)
# PROJECT_VERBOSITY and PROJECT_DEBUG were set at command line processing
# PROJECT_VERBOSITY and PROJECT_DEBUG were set at command line processing
# before Ceedling is even loaded.

if (!!defined?(PROJECT_DEBUG) and PROJECT_DEBUG) or (config[:project][:debug])
eval("def project_debug() return true end", binding())
else
eval("def project_debug() return false end", binding())
eval("def project_debug() return false end", binding())
end

if !!defined?(PROJECT_VERBOSITY)
eval("def project_verbosity() return #{PROJECT_VERBOSITY} end", binding())
end

# Configurator will try to create these accessors automatically but will silently
# Configurator will try to create these accessors automatically but will silently
# fail if they already exist.
end


# The default values defined in defaults.rb (eg. DEFAULT_TOOLS_TEST) are populated
# into @param config
def populate_defaults(config)
new_config = DEFAULT_CEEDLING_CONFIG.deep_clone
new_config.deep_merge!(config)
config.replace(new_config)

@configurator_builder.populate_defaults( config, DEFAULT_TOOLS_TEST )
@configurator_builder.populate_defaults( config, DEFAULT_TOOLS_TEST_PREPROCESSORS ) if (config[:project][:use_test_preprocessor])
@configurator_builder.populate_defaults( config, DEFAULT_TOOLS_TEST_ASSEMBLER ) if (config[:test_build][:use_assembly])

@configurator_builder.populate_defaults( config, DEFAULT_TOOLS_RELEASE ) if (config[:project][:release_build])
@configurator_builder.populate_defaults( config, DEFAULT_TOOLS_RELEASE_ASSEMBLER ) if (config[:project][:release_build] and config[:release_build][:use_assembly])
def merge_ceedling_config(config, default_config)
# Merge ceedling default config with default tools
default_config.replace( DEFAULT_CEEDLING_CONFIG.deep_clone )
default_config.deep_merge( DEFAULT_TOOLS_TEST.deep_clone )
default_config.deep_merge( DEFAULT_TOOLS_TEST_PREPROCESSORS.deep_clone ) if (config[:project][:use_test_preprocessor])
default_config.deep_merge( DEFAULT_TOOLS_TEST_ASSEMBLER.deep_clone ) if (config[:test_build][:use_assembly])

default_config.deep_merge( DEFAULT_TOOLS_RELEASE.deep_clone ) if (config[:project][:release_build])
default_config.deep_merge( DEFAULT_TOOLS_RELEASE_ASSEMBLER.deep_clone ) if (config[:project][:release_build] and config[:release_build][:use_assembly])

# Merge current config with ceedling internal settings
config.deep_merge( CEEDLING_CONFIG_INTERNAL.deep_clone )
end


def populate_unity_defaults(config)
unity = config[:unity] || {}
@runner_config = unity.merge(config[:test_runner] || {})
end

def populate_cmock_defaults(config)
def merge_cmock_config(config, default_config)
# cmock has its own internal defaults handling, but we need to set these specific values
# so they're present for the build environment to access;
# note: these need to end up in the hash given to initialize cmock for this to be successful
cmock = config[:cmock] || {}

# populate defaults with cmock internal settings
default_cmock = default_config[:cmock] || {}

# yes, we're duplicating the default mock_prefix in cmock, but it's because we need CMOCK_MOCK_PREFIX always available in Ceedling's environment
cmock[:mock_prefix] = 'Mock' if (cmock[:mock_prefix].nil?)
default_cmock[:mock_prefix] = 'Mock' if (default_cmock[:mock_prefix].nil?)

# just because strict ordering is the way to go
cmock[:enforce_strict_ordering] = true if (cmock[:enforce_strict_ordering].nil?)
default_cmock[:enforce_strict_ordering] = true if (default_cmock[:enforce_strict_ordering].nil?)

cmock[:mock_path] = File.join(config[:project][:build_root], TESTS_BASE_PATH, 'mocks') if (cmock[:mock_path].nil?)
default_cmock[:mock_path] = File.join(config[:project][:build_root], TESTS_BASE_PATH, 'mocks') if (default_cmock[:mock_path].nil?)

cmock[:verbosity] = @project_verbosity if (cmock[:verbosity].nil?)
default_cmock[:verbosity] = @project_verbosity if (default_cmock[:verbosity].nil?)

# populate current config with cmock config
cmock = config[:cmock] || {}

cmock[:plugins] = [] if (cmock[:plugins].nil?)
cmock[:plugins].map! { |plugin| plugin.to_sym }
Expand All @@ -142,16 +143,24 @@ def populate_cmock_defaults(config)

if (cmock[:unity_helper])
cmock[:unity_helper] = [cmock[:unity_helper]] if cmock[:unity_helper].is_a? String
cmock[:includes] = [] if (cmock[:includes].nil?)
cmock[:includes] += cmock[:unity_helper].map{|helper| File.basename(helper) }
cmock[:includes].uniq!
end

@runner_config = cmock.merge(@runner_config || config[:test_runner] || {})

@cmock_config = cmock
end


def copy_vendor_defines(config)
# NOTE: To maintain any backwards compatibility following a refactoring of :defines: handling,
# copy top-level vendor defines into the respective tool areas.
config[UNITY_SYM].store(:defines, config[:defines][UNITY_SYM])
config[CMOCK_SYM].store(:defines, config[:defines][CMOCK_SYM])
config[CEXCEPTION_SYM].store(:defines, config[:defines][CEXCEPTION_SYM])
end


def get_runner_config
return @runner_config.clone
end
Expand Down Expand Up @@ -207,7 +216,7 @@ def tools_supplement_arguments(config)
end


def find_and_merge_plugins(config)
def find_and_merge_plugins(config, default_config)
# Plugins must be loaded before generic path evaluation & magic that happen later.
# So, perform path magic here as discrete step.
config[:plugins][:load_paths].each do |path|
Expand Down Expand Up @@ -238,12 +247,12 @@ def find_and_merge_plugins(config)

# Load base configuration values (defaults) from YAML
plugin_yml_defaults.each do |defaults|
@configurator_builder.populate_defaults( config, @yaml_wrapper.load(defaults) )
default_config.deep_merge!( @yaml_wrapper.load(defaults) )
end

# Load base configuration values (defaults) as hash from Ruby
plugin_hash_defaults.each do |defaults|
@configurator_builder.populate_defaults( config, defaults )
@configurator_builder.populate_defaults( default_config, defaults )
end

# Merge plugin configuration values (like Ceedling project file)
Expand All @@ -252,7 +261,7 @@ def find_and_merge_plugins(config)

# Special handling for plugin paths
if (plugin_config.include?( :paths ))
plugin_config[:paths].update(plugin_config[:paths]) do |k,v|
plugin_config[:paths].update(plugin_config[:paths]) do |k,v|
plugin_path = plugin.match(/(.*)[\/]config[\/]\w+\.yml/)[1]
v.map {|vv| File.expand_path(vv.gsub!(/\$PLUGIN_PATH/,plugin_path)) }
end
Expand All @@ -269,6 +278,22 @@ def find_and_merge_plugins(config)
end


def populate_config_with_defaults(config, default_config)
@configurator_builder.populate_defaults( config, default_config )
end


# unity cmock initializer
def populate_runner_config(config)
unity = config[:unity] || {}
@runner_config = unity.merge(config[:test_runner])

cmock = config[:cmock] || {}
@runner_config = cmock.merge(@runner_config)
@cmock_config = cmock
end


def merge_imports(config)
if config[:import]
if config[:import].is_a? Array
Expand Down Expand Up @@ -453,7 +478,6 @@ def build_supplement(config_base, config_more)
end
end


def insert_rake_plugins(plugins)
plugins.each do |plugin|
@project_config_hash[:project_rakefile_component_files] << plugin
Expand All @@ -476,7 +500,7 @@ def collect_path_list( container )
paths << container[key] if (key.to_s =~ /_path(s)?$/)
end
end

return paths.flatten()
end

Expand All @@ -496,4 +520,3 @@ def eval_path_entries( container )
end

end

31 changes: 22 additions & 9 deletions lib/ceedling/defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -363,12 +363,6 @@
:include => [],
},

# unlike other top-level entries, environment's value is an array to preserve order
:environment => [
# when evaluated, this provides wider text field for rake task comments
{:rake_columns => '120'},
],

:defines => {
:use_test_definition => false,
:test => [], # A hash/sub-hashes in config file can include operations and test executable matchers as keys
Expand Down Expand Up @@ -405,18 +399,15 @@
},

:unity => {
:vendor_path => CEEDLING_VENDOR,
:defines => []
},

:cmock => {
:vendor_path => CEEDLING_VENDOR,
:includes => [],
:defines => []
},

:cexception => {
:vendor_path => CEEDLING_VENDOR,
:defines => []
},

Expand Down Expand Up @@ -446,6 +437,28 @@
:release_assembler => { :arguments => [] },
:release_dependencies_generator => { :arguments => [] },

}.freeze

CEEDLING_CONFIG_INTERNAL = {

# unlike other top-level entries, environment's value is an array to preserve order
:environment => [
# when evaluated, this provides wider text field for rake task comments
{:rake_columns => '120'},
],

:unity => {
:vendor_path => CEEDLING_VENDOR
},

:cmock => {
:vendor_path => CEEDLING_VENDOR
},

:cexception => {
:vendor_path => CEEDLING_VENDOR
},

:plugins => {
:load_paths => [],
:enabled => CEEDLING_PLUGINS,
Expand Down
22 changes: 13 additions & 9 deletions lib/ceedling/setupinator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,22 @@ def load_project_files

def do_setup(config_hash)
@config_hash = config_hash
defaults_hash = {}

# Load up all the constants and accessors our rake files, objects, & external scripts will need.
# Note: Configurator modifies the cmock section of the hash with a couple defaults to tie
# Note: Configurator modifies the cmock section of the hash with a couple defaults to tie
# projects together -- the modified hash is used to build the cmock object.
@ceedling[:configurator].set_verbosity( config_hash )
@ceedling[:configurator].populate_defaults( config_hash )
@ceedling[:configurator].populate_unity_defaults( config_hash )
@ceedling[:configurator].populate_cmock_defaults( config_hash )
@ceedling[:configurator].merge_ceedling_config( config_hash, defaults_hash )
@ceedling[:configurator].merge_cmock_config( config_hash, defaults_hash )
@ceedling[:configurator].eval_environment_variables( config_hash )
@ceedling[:configurator].find_and_merge_plugins( config_hash, defaults_hash )
@ceedling[:configurator].populate_config_with_defaults( config_hash, defaults_hash )
@ceedling[:configurator].populate_runner_config( config_hash )
@ceedling[:configurator].merge_imports( config_hash )
@ceedling[:configurator].eval_environment_variables( config_hash )
@ceedling[:configurator].eval_paths( config_hash )
@ceedling[:configurator].standardize_paths( config_hash )
@ceedling[:configurator].find_and_merge_plugins( config_hash )
@ceedling[:configurator].merge_imports( config_hash )
@ceedling[:configurator].tools_setup( config_hash )
@ceedling[:configurator].validate( config_hash )
Expand All @@ -45,13 +49,13 @@ def do_setup(config_hash)

@ceedling[:configurator].insert_rake_plugins( @ceedling[:configurator].rake_plugins )
@ceedling[:configurator].tools_supplement_arguments( config_hash )

# Merge in any environment variables that plugins specify after the main build
@ceedling[:plugin_manager].load_programmatic_plugins( @ceedling[:configurator].programmatic_plugins, @ceedling ) do |env|
@ceedling[:configurator].eval_environment_variables( env )
@ceedling[:configurator].build_supplement( config_hash, env )
end

@ceedling[:plugin_reportinator].set_system_objects( @ceedling )
@ceedling[:loginator].project_log_filepath = form_log_filepath()
@ceedling[:project_config_manager].config_hash = config_hash
Expand All @@ -68,7 +72,7 @@ def reset_defaults(config_hash)
def form_log_filepath()
# Various project files and options files can combine to create different configurations.
# Different configurations means different behaviors.
# As these variations are easy to run from the command line, a resulting log file
# As these variations are easy to run from the command line, a resulting log file
# should differentiate its context.
# We do this by concatenating config/options names into a log filename.

Expand All @@ -78,7 +82,7 @@ def form_log_filepath()
config_files << @ceedling[:project_file_loader].user_file
config_files += @ceedling[:project_config_manager].options_files
config_files.compact! # Remove empties

# Drop component file name extensions and smoosh together with underscores
log_name = config_files.map{ |file| file.ext('') }.join( '_' )

Expand Down
25 changes: 12 additions & 13 deletions spec/ceedling_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@

it 'should load the project with the specified plugins enabled' do
# create test state/variables
DEFAULT_CEEDLING_CONFIG[:plugins][:enabled].clear()
DEFAULT_CEEDLING_CONFIG[:plugins][:load_paths].clear()
CEEDLING_CONFIG_INTERNAL[:plugins][:enabled].clear()
CEEDLING_CONFIG_INTERNAL[:plugins][:load_paths].clear()
spec_double = double('spec-double')
rakefile_path = File.expand_path( File.join( File.dirname(__FILE__), '..' ).gsub( 'spec','lib' ) )
rakefile_path = File.join( rakefile_path, 'lib', 'ceedling', 'rakefile.rb' )
Expand All @@ -102,8 +102,8 @@
it 'should set the project root if the root key is provided' do
# create test state/variables
Object.send(:remove_const, :PROJECT_ROOT)
DEFAULT_CEEDLING_CONFIG[:plugins][:enabled].clear()
DEFAULT_CEEDLING_CONFIG[:plugins][:load_paths].clear()
CEEDLING_CONFIG_INTERNAL[:plugins][:enabled].clear()
CEEDLING_CONFIG_INTERNAL[:plugins][:load_paths].clear()
rakefile_path = File.expand_path( File.join( File.dirname(__FILE__), '..' ).gsub( 'spec','lib' ) )
rakefile_path = File.join( rakefile_path, 'lib', 'ceedling', 'rakefile.rb' )
# mocks/stubs/expected calls
Expand All @@ -120,8 +120,8 @@
context 'register_plugin' do
it 'should register a plugin' do
# create test state/variables
DEFAULT_CEEDLING_CONFIG[:plugins][:enabled].clear()
DEFAULT_CEEDLING_CONFIG[:plugins][:load_paths].clear()
CEEDLING_CONFIG_INTERNAL[:plugins][:enabled].clear()
CEEDLING_CONFIG_INTERNAL[:plugins][:load_paths].clear()
spec_double = double('spec-double')
# mocks/stubs/expected calls
expect(Gem::Specification).to receive(:find_by_name).with('ceedling-foo').and_return(spec_double)
Expand All @@ -130,14 +130,14 @@
# execute method
Ceedling.register_plugin('foo')
# validate results
expect(DEFAULT_CEEDLING_CONFIG[:plugins][:enabled]).to eq ["foo"]
expect(DEFAULT_CEEDLING_CONFIG[:plugins][:load_paths]).to eq(["dummy/path"])
expect(CEEDLING_CONFIG_INTERNAL[:plugins][:enabled]).to eq ["foo"]
expect(CEEDLING_CONFIG_INTERNAL[:plugins][:load_paths]).to eq(["dummy/path"])
end

it 'should register a plugin with an alternative prefix' do
# create test state/variables
DEFAULT_CEEDLING_CONFIG[:plugins][:enabled].clear()
DEFAULT_CEEDLING_CONFIG[:plugins][:load_paths].clear()
CEEDLING_CONFIG_INTERNAL[:plugins][:enabled].clear()
CEEDLING_CONFIG_INTERNAL[:plugins][:load_paths].clear()
spec_double = double('spec-double')
# mocks/stubs/expected calls
expect(Gem::Specification).to receive(:find_by_name).with('prefix-foo').and_return(spec_double)
Expand All @@ -146,9 +146,8 @@
# execute method
Ceedling.register_plugin('foo','prefix-')
# validate results
expect(DEFAULT_CEEDLING_CONFIG[:plugins][:enabled]).to eq(["foo"])
expect(DEFAULT_CEEDLING_CONFIG[:plugins][:load_paths]).to eq(["dummy/path"])
expect(CEEDLING_CONFIG_INTERNAL[:plugins][:enabled]).to eq(["foo"])
expect(CEEDLING_CONFIG_INTERNAL[:plugins][:load_paths]).to eq(["dummy/path"])
end
end
end

0 comments on commit 576568f

Please sign in to comment.