summaryrefslogtreecommitdiff
path: root/tests/vendor/ceedling/lib/tool_executor.rb
diff options
context:
space:
mode:
Diffstat (limited to 'tests/vendor/ceedling/lib/tool_executor.rb')
-rw-r--r--tests/vendor/ceedling/lib/tool_executor.rb212
1 files changed, 212 insertions, 0 deletions
diff --git a/tests/vendor/ceedling/lib/tool_executor.rb b/tests/vendor/ceedling/lib/tool_executor.rb
new file mode 100644
index 000000000..f4bccc42b
--- /dev/null
+++ b/tests/vendor/ceedling/lib/tool_executor.rb
@@ -0,0 +1,212 @@
+require 'constants'
+
+class ShellExecutionException < RuntimeError
+ attr_reader :shell_result
+ def initialize(shell_result)
+ @shell_result = shell_result
+ end
+end
+
+class ToolExecutor
+
+ constructor :configurator, :tool_executor_helper, :streaminator, :system_wrapper
+
+ def setup
+ @tool_name = ''
+ @executable = ''
+ end
+
+ # build up a command line from yaml provided config
+ def build_command_line(tool_config, *args)
+ @tool_name = tool_config[:name]
+ @executable = tool_config[:executable]
+
+ command = {}
+
+ # basic premise is to iterate top to bottom through arguments using '$' as
+ # a string replacement indicator to expand globals or inline yaml arrays
+ # into command line arguments via substitution strings
+ command[:line] = [
+ @tool_executor_helper.osify_path_separators( expandify_element(@executable, *args) ),
+ build_arguments(tool_config[:arguments], *args),
+ ].join(' ').strip
+
+ command[:options] = {
+ :stderr_redirect => @tool_executor_helper.stderr_redirection(tool_config, @configurator.project_logging),
+ :background_exec => tool_config[:background_exec]
+ }
+
+ return command
+ end
+
+
+ # shell out, execute command, and return response
+ def exec(command, options={}, args=[])
+ options[:boom] = true if (options[:boom].nil?)
+ options[:stderr_redirect] = StdErrRedirect::NONE if (options[:stderr_redirect].nil?)
+ options[:background_exec] = BackgroundExec::NONE if (options[:background_exec].nil?)
+
+ # build command line
+ command_line = [
+ @tool_executor_helper.background_exec_cmdline_prepend( options ),
+ command.strip,
+ args,
+ @tool_executor_helper.stderr_redirect_cmdline_append( options ),
+ @tool_executor_helper.background_exec_cmdline_append( options ),
+ ].flatten.compact.join(' ')
+
+ shell_result = {}
+
+ # depending on background exec option, we shell out differently
+ if (options[:background_exec] != BackgroundExec::NONE)
+ shell_result = @system_wrapper.shell_system( command_line )
+ else
+ shell_result = @system_wrapper.shell_backticks( command_line )
+ end
+
+ @tool_executor_helper.print_happy_results( command_line, shell_result, options[:boom] )
+ @tool_executor_helper.print_error_results( command_line, shell_result, options[:boom] )
+
+ # go boom if exit code isn't 0 (but in some cases we don't want a non-0 exit code to raise)
+ raise ShellExecutionException.new(shell_result) if ((shell_result[:exit_code] != 0) and options[:boom])
+
+ return shell_result
+ end
+
+
+ private #############################
+
+
+ def build_arguments(config, *args)
+ build_string = ''
+
+ return nil if (config.nil?)
+
+ # iterate through each argument
+
+ # the yaml blob array needs to be flattened so that yaml substitution
+ # is handled correctly, since it creates a nested array when an anchor is
+ # dereferenced
+ config.flatten.each do |element|
+ argument = ''
+
+ case(element)
+ # if we find a simple string then look for string replacement operators
+ # and expand with the parameters in this method's argument list
+ when String then argument = expandify_element(element, *args)
+ # if we find a hash, then we grab the key as a substitution string and expand the
+ # hash's value(s) within that substitution string
+ when Hash then argument = dehashify_argument_elements(element)
+ end
+
+ build_string.concat("#{argument} ") if (argument.length > 0)
+ end
+
+ build_string.strip!
+ return build_string if (build_string.length > 0)
+ return nil
+ end
+
+
+ # handle simple text string argument & argument array string replacement operators
+ def expandify_element(element, *args)
+ match = //
+ to_process = nil
+ args_index = 0
+
+ # handle ${#} input replacement
+ if (element =~ TOOL_EXECUTOR_ARGUMENT_REPLACEMENT_PATTERN)
+ args_index = ($2.to_i - 1)
+
+ if (args.nil? or args[args_index].nil?)
+ @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' expected valid argument data to accompany replacement operator #{$1}.", Verbosity::ERRORS)
+ raise
+ end
+
+ match = /#{Regexp.escape($1)}/
+ to_process = args[args_index]
+ end
+
+ # simple string argument: replace escaped '\$' and strip
+ element.sub!(/\\\$/, '$')
+ element.strip!
+
+ # handle inline ruby execution
+ if (element =~ RUBY_EVAL_REPLACEMENT_PATTERN)
+ element.replace(eval($1))
+ end
+
+ build_string = ''
+
+ # handle array or anything else passed into method to be expanded in place of replacement operators
+ case (to_process)
+ when Array then to_process.each {|value| build_string.concat( "#{element.sub(match, value.to_s)} " ) } if (to_process.size > 0)
+ else build_string.concat( element.sub(match, to_process.to_s) )
+ end
+
+ # handle inline ruby string substitution
+ if (build_string =~ RUBY_STRING_REPLACEMENT_PATTERN)
+ build_string.replace(@system_wrapper.module_eval(build_string))
+ end
+
+ return build_string.strip
+ end
+
+
+ # handle argument hash: keys are substitution strings, values are data to be expanded within substitution strings
+ def dehashify_argument_elements(hash)
+ build_string = ''
+ elements = []
+
+ # grab the substitution string (hash key)
+ substitution = hash.keys[0].to_s
+ # grab the string(s) to squirt into the substitution string (hash value)
+ expand = hash[hash.keys[0]]
+
+ if (expand.nil?)
+ @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' could not expand nil elements for substitution string '#{substitution}'.", Verbosity::ERRORS)
+ raise
+ end
+
+ # array-ify expansion input if only a single string
+ expansion = ((expand.class == String) ? [expand] : expand)
+
+ expansion.each do |item|
+ # code eval substitution
+ if (item =~ RUBY_EVAL_REPLACEMENT_PATTERN)
+ elements << eval($1)
+ # string eval substitution
+ elsif (item =~ RUBY_STRING_REPLACEMENT_PATTERN)
+ elements << @system_wrapper.module_eval(item)
+ # global constants
+ elsif (@system_wrapper.constants_include?(item))
+ const = Object.const_get(item)
+ if (const.nil?)
+ @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' found constant '#{item}' to be nil.", Verbosity::ERRORS)
+ raise
+ else
+ elements << const
+ end
+ elsif (item.class == Array)
+ elements << item
+ elsif (item.class == String)
+ @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' cannot expand nonexistent value '#{item}' for substitution string '#{substitution}'.", Verbosity::ERRORS)
+ raise
+ else
+ @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' cannot expand value having type '#{item.class}' for substitution string '#{substitution}'.", Verbosity::ERRORS)
+ raise
+ end
+ end
+
+ # expand elements (whether string or array) into substitution string & replace escaped '\$'
+ elements.flatten!
+ elements.each do |element|
+ build_string.concat( substitution.sub(/([^\\]*)\$/, "\\1#{element}") ) # don't replace escaped '\$' but allow us to replace just a lonesome '$'
+ build_string.gsub!(/\\\$/, '$')
+ build_string.concat(' ')
+ end
+
+ return build_string.strip
+ end
+
+end