From c387969d9086d565c27fbb663ec083e71917e76d Mon Sep 17 00:00:00 2001 From: mvandervoord Date: Mon, 14 Oct 2024 17:52:40 -0400 Subject: [PATCH 1/6] * Refactor loginator for background processing * Refactor batchinator for better handling of exceptions * Refactor test build to directly drive builds in parallel again (not rake invoked) --- lib/ceedling/build_batchinator.rb | 58 +++++++++++--------- lib/ceedling/loginator.rb | 89 +++++++++++++++++++++++-------- lib/ceedling/objects.yml | 1 + lib/ceedling/rakefile.rb | 3 ++ lib/ceedling/test_invoker.rb | 11 ++-- plugins/gcov/lib/gcov.rb | 21 ++------ 6 files changed, 117 insertions(+), 66 deletions(-) diff --git a/lib/ceedling/build_batchinator.rb b/lib/ceedling/build_batchinator.rb index db6f0ab8..a5729ff7 100644 --- a/lib/ceedling/build_batchinator.rb +++ b/lib/ceedling/build_batchinator.rb @@ -52,39 +52,47 @@ def exec(workload:, things:, &block) threads = (1..workers).collect do thread = Thread.new do - begin - # Run tasks until there are no more enqueued - loop do - # pop(true) is non-blocking and raises ThreadError when queue is empty - yield @queue.pop(true) - end - - # First, handle thread exceptions (should always be due to empty queue) - rescue ThreadError => e - # Typical case: do nothing and allow thread to wind down + Thread.handle_interrupt(Exception => :never) do + begin + Thread.handle_interrupt(Exception => :immediate) do + # Run tasks until there are no more enqueued + loop do + # pop(true) is non-blocking and raises ThreadError when queue is empty + yield @queue.pop(true) + end + end + # First, handle thread exceptions (should always be due to empty queue) + rescue ThreadError => e + # Typical case: do nothing and allow thread to wind down + + # ThreadError outside scope of expected empty queue condition + unless e.message.strip.casecmp("queue empty") + @loginator.log(e.message, Verbosity::ERRORS) + + # Shutdown all worker threads + shutdown_threads(threads) #TODO IT SEEMS LIKE threads MIGHT NOT BE VALID YET + + raise(e) # Raise exception again + end + + # Second, catch every other kind of exception so we can intervene with thread cleanup. + # Generally speaking, catching Exception is a no-no, but we must in this case. + # Raise the exception again so that: + # 1. Calling code knows something bad happened and handles appropriately + # 2. Ruby runtime can handle most serious problems + rescue Exception => e + @loginator.log(e.message, Verbosity::ERRORS) - # ThreadError outside scope of expected empty queue condition - unless e.message.strip.casecmp("queue empty") # Shutdown all worker threads - shutdown_threads(threads) + shutdown_threads(threads) #TODO IT SEEMS LIKE threads MIGHT NOT BE VALID YET - raise(e) # Raise exception again + raise(e) # Raise exception again after intervening end - - # Second, catch every other kind of exception so we can intervene with thread cleanup. - # Generally speaking, catching Exception is a no-no, but we must in this case. - # Raise the exception again so that: - # 1. Calling code knows something bad happened and handles appropriately - # 2. Ruby runtime can handle most serious problems - rescue Exception => e - # Shutdown all worker threads - shutdown_threads(threads) - - raise(e) # Raise exception again after intervening end end # Hand thread to Enumerable collect() routine + thread.abort_on_exception = true thread end diff --git a/lib/ceedling/loginator.rb b/lib/ceedling/loginator.rb index 92fbc4f7..18726acb 100644 --- a/lib/ceedling/loginator.rb +++ b/lib/ceedling/loginator.rb @@ -43,8 +43,68 @@ def setup() @project_logging = false @log_filepath = nil + + @queue = Queue.new + @worker = Thread.new do + # Run tasks until there are no more enqueued + @done = false + while !@done do + Thread.handle_interrupt(Exception => :never) do + begin + Thread.handle_interrupt(Exception => :immediate) do + # pop(false) is blocking and should just hang here and wait for next message + item = @queue.pop(false) + if (item.nil?) + @done = true + next + end + + # pick out the details + message = item[:message] + label = item[:label] + verbosity = item[:verbosity] + stream = item[:stream] + + # Write to log as though Verbosity::DEBUG (no filtering at all) but without fun characters + if @project_logging + file_msg = message.dup() # Copy for safe inline modifications + + # Add labels + file_msg = format( file_msg, verbosity, label, false ) + + # Note: In practice, file-based logging only works with trailing newlines (i.e. `log()` calls) + # `out()` calls will be a little ugly in the log file, but these are typically only + # used for console logging anyhow. + logfile( sanitize( file_msg, false ), extract_stream_name( stream ) ) + end + + # Only output to console when message reaches current verbosity level + if !stream.nil? && (@verbosinator.should_output?( verbosity )) + # Add labels and fun characters + console_msg = format( message, verbosity, label, @decorators ) + + # Write to output stream after optionally removing any problematic characters + stream.print( sanitize( console_msg, @decorators ) ) + end + end + rescue ThreadError + @done = true + rescue Exception => e + puts e.inspect + end + end + end + end end + def wrapup + begin + @queue.close + @worker.join + rescue + #If we failed at this point, just give up on it + end + end def set_logfile( log_filepath ) if !log_filepath.empty? @@ -89,27 +149,14 @@ def log(message="\n", verbosity=Verbosity::NORMAL, label=LogLabels::AUTO, stream # Message contatenated with "\n" (unless it aready ends with a newline) message += "\n" unless message.end_with?( "\n" ) - # Write to log as though Verbosity::DEBUG (no filtering at all) but without fun characters - if @project_logging - file_msg = message.dup() # Copy for safe inline modifications - - # Add labels - file_msg = format( file_msg, verbosity, label, false ) - - # Note: In practice, file-based logging only works with trailing newlines (i.e. `log()` calls) - # `out()` calls will be a little ugly in the log file, but these are typically only - # used for console logging anyhow. - logfile( sanitize( file_msg, false ), extract_stream_name( stream ) ) - end - - # Only output to console when message reaches current verbosity level - return if !(@verbosinator.should_output?( verbosity )) - - # Add labels and fun characters - console_msg = format( message, verbosity, label, @decorators ) - - # Write to output stream after optionally removing any problematic characters - stream.print( sanitize( console_msg, @decorators ) ) + # Add item to the queue + item = { + :message => message, + :verbosity => verbosity, + :label => label, + :stream => stream + } + @queue << item end diff --git a/lib/ceedling/objects.yml b/lib/ceedling/objects.yml index 60682990..aba75aa0 100644 --- a/lib/ceedling/objects.yml +++ b/lib/ceedling/objects.yml @@ -308,6 +308,7 @@ test_invoker: - generator - test_context_extractor - file_path_utils + - file_finder - file_wrapper - verbosinator diff --git a/lib/ceedling/rakefile.rb b/lib/ceedling/rakefile.rb index 5950530b..0b820979 100644 --- a/lib/ceedling/rakefile.rb +++ b/lib/ceedling/rakefile.rb @@ -124,9 +124,11 @@ def test_failures_handler() ops_done = SystemWrapper.time_stopwatch_s() log_runtime( 'operations', start_time, ops_done, CEEDLING_APPCFG.build_tasks? ) boom_handler( @ceedling[:loginator], ex ) + @ceedling[:loginator].wrapup exit(1) end + @ceedling[:loginator].wrapup exit(0) else msg = "Ceedling could not complete operations because of errors" @@ -136,6 +138,7 @@ def test_failures_handler() rescue => ex boom_handler( @ceedling[:loginator], ex) ensure + @ceedling[:loginator].wrapup exit(1) end end diff --git a/lib/ceedling/test_invoker.rb b/lib/ceedling/test_invoker.rb index 0004296a..5cd28503 100644 --- a/lib/ceedling/test_invoker.rb +++ b/lib/ceedling/test_invoker.rb @@ -25,6 +25,7 @@ class TestInvoker :test_context_extractor, :file_path_utils, :file_wrapper, + :file_finder, :verbosinator def setup @@ -348,16 +349,18 @@ def setup_and_invoke(tests:, context:TEST_SYM, options:{}) details[:no_link_objects] = test_no_link_objects details[:results_pass] = test_pass details[:results_fail] = test_fail + details[:tool] = TOOLS_TEST_COMPILER #TODO: VERIFY THIS GETS REPLACED WHEN IN GCOV OR BULLSEYE MODE end end end # Build All Test objects @batchinator.build_step("Building Objects") do - # FYI: Temporarily removed direct object generation to allow rake invoke() to execute custom compilations (plugins, special cases) - # @test_invoker_helper.generate_objects_now(object_list, options) @testables.each do |_, details| - @task_invoker.invoke_test_objects(test: details[:name], objects:details[:objects]) + details[:objects].each do |obj| + src = @file_finder.find_build_input_file(filepath: obj, context: TEST_SYM) + compile_test_component(tool: details[:tool], context: TEST_SYM, test: details[:name], source: src, object: obj, msg: details[:msg]) + end end end @@ -432,7 +435,7 @@ def lookup_sources(test:) end def compile_test_component(tool:, context:TEST_SYM, test:, source:, object:, msg:nil) - testable = @testables[test] + testable = @testables[test.to_sym] filepath = testable[:filepath] defines = testable[:compile_defines] diff --git a/plugins/gcov/lib/gcov.rb b/plugins/gcov/lib/gcov.rb index aeaeaf7d..ff9607e2 100755 --- a/plugins/gcov/lib/gcov.rb +++ b/plugins/gcov/lib/gcov.rb @@ -60,28 +60,17 @@ def automatic_reporting_enabled? return (@project_config[:gcov_report_task] == false) end - def generate_coverage_object_file(test, source, object) - # Non-coverage compiler - tool = TOOLS_TEST_COMPILER - msg = nil + def pre_compile_execute(arg_hash) + source = arg_hash[:source] # Handle assembly file that comes through if File.extname(source) == EXTENSION_ASSEMBLY - tool = TOOLS_TEST_ASSEMBLER + arg_hash[:tool] = TOOLS_TEST_ASSEMBLER # If a source file (not unity, mocks, etc.) is to be compiled use code coverage compiler elsif @configurator.collection_all_source.include?(source) - tool = TOOLS_GCOV_COMPILER - msg = "Compiling #{File.basename(source)} with coverage..." + arg_hash[:tool] = TOOLS_GCOV_COMPILER + arg_hash[:msg] = "Compiling #{File.basename(source)} with coverage..." end - - @test_invoker.compile_test_component( - tool: tool, - context: GCOV_SYM, - test: test, - source: source, - object: object, - msg: msg - ) end # `Plugin` build step hook From 80601ce66ad001479442985d2b204dfa35fc4e7c Mon Sep 17 00:00:00 2001 From: mvandervoord Date: Fri, 18 Oct 2024 21:07:08 -0400 Subject: [PATCH 2/6] refactor gcov to run using new flow (and tweak flow to support it) --- lib/ceedling/build_batchinator.rb | 7 ++++--- lib/ceedling/generator.rb | 5 +++-- lib/ceedling/loginator.rb | 4 ++++ lib/ceedling/plugin_manager.rb | 2 +- lib/ceedling/test_invoker.rb | 10 +++++----- plugins/gcov/lib/gcov.rb | 23 ++++++++++++++--------- 6 files changed, 31 insertions(+), 20 deletions(-) diff --git a/lib/ceedling/build_batchinator.rb b/lib/ceedling/build_batchinator.rb index a5729ff7..27d61661 100644 --- a/lib/ceedling/build_batchinator.rb +++ b/lib/ceedling/build_batchinator.rb @@ -61,7 +61,8 @@ def exec(workload:, things:, &block) yield @queue.pop(true) end end - # First, handle thread exceptions (should always be due to empty queue) + + # First, handle thread exceptions (should always be due to empty queue) rescue ThreadError => e # Typical case: do nothing and allow thread to wind down @@ -70,7 +71,7 @@ def exec(workload:, things:, &block) @loginator.log(e.message, Verbosity::ERRORS) # Shutdown all worker threads - shutdown_threads(threads) #TODO IT SEEMS LIKE threads MIGHT NOT BE VALID YET + shutdown_threads(threads) raise(e) # Raise exception again end @@ -84,7 +85,7 @@ def exec(workload:, things:, &block) @loginator.log(e.message, Verbosity::ERRORS) # Shutdown all worker threads - shutdown_threads(threads) #TODO IT SEEMS LIKE threads MIGHT NOT BE VALID YET + shutdown_threads(threads) raise(e) # Raise exception again after intervening end diff --git a/lib/ceedling/generator.rb b/lib/ceedling/generator.rb index 6bfcecf3..a51e3e55 100644 --- a/lib/ceedling/generator.rb +++ b/lib/ceedling/generator.rb @@ -139,12 +139,13 @@ def generate_object_file_c( :flags => flags, :defines => defines, :list => list, - :dependencies => dependencies + :dependencies => dependencies, + :msg => String(msg) } @plugin_manager.pre_compile_execute(arg_hash) - msg = String(msg) + msg = arg_hash[:msg] msg = @reportinator.generate_module_progress( operation: "Compiling", module_name: module_name, diff --git a/lib/ceedling/loginator.rb b/lib/ceedling/loginator.rb index 18726acb..5b635d32 100644 --- a/lib/ceedling/loginator.rb +++ b/lib/ceedling/loginator.rb @@ -309,3 +309,7 @@ def logfile(string, stream='') end end + +END { + @ceedling[:loginator].wrapup +} \ No newline at end of file diff --git a/lib/ceedling/plugin_manager.rb b/lib/ceedling/plugin_manager.rb index 85a402c9..afba6409 100644 --- a/lib/ceedling/plugin_manager.rb +++ b/lib/ceedling/plugin_manager.rb @@ -39,7 +39,7 @@ def load_programmatic_plugins(plugins, system_objects) # Add plugins to hash of all system objects system_objects[hash[:plugin].downcase().to_sym()] = object - rescue + rescue @loginator.log( "Exception raised while trying to load plugin: #{hash[:plugin]}", Verbosity::ERRORS ) raise # Raise again for backtrace, etc. end diff --git a/lib/ceedling/test_invoker.rb b/lib/ceedling/test_invoker.rb index 5cd28503..e3be7dea 100644 --- a/lib/ceedling/test_invoker.rb +++ b/lib/ceedling/test_invoker.rb @@ -238,7 +238,7 @@ def setup_and_invoke(tests:, context:TEST_SYM, options:{}) testable = mock[:testable] arg_hash = { - context: TEST_SYM, + context: context, mock: mock[:name], test: testable[:name], input_filepath: details[:input], @@ -287,7 +287,7 @@ def setup_and_invoke(tests:, context:TEST_SYM, options:{}) @batchinator.build_step("Test Runners") do @batchinator.exec(workload: :compile, things: @testables) do |_, details| arg_hash = { - context: TEST_SYM, + context: context, mock_list: details[:mock_list], includes_list: @test_context_extractor.lookup_header_includes_list( details[:filepath] ), test_filepath: details[:filepath], @@ -349,7 +349,7 @@ def setup_and_invoke(tests:, context:TEST_SYM, options:{}) details[:no_link_objects] = test_no_link_objects details[:results_pass] = test_pass details[:results_fail] = test_fail - details[:tool] = TOOLS_TEST_COMPILER #TODO: VERIFY THIS GETS REPLACED WHEN IN GCOV OR BULLSEYE MODE + details[:tool] = TOOLS_TEST_COMPILER end end end @@ -358,8 +358,8 @@ def setup_and_invoke(tests:, context:TEST_SYM, options:{}) @batchinator.build_step("Building Objects") do @testables.each do |_, details| details[:objects].each do |obj| - src = @file_finder.find_build_input_file(filepath: obj, context: TEST_SYM) - compile_test_component(tool: details[:tool], context: TEST_SYM, test: details[:name], source: src, object: obj, msg: details[:msg]) + src = @file_finder.find_build_input_file(filepath: obj, context: context) + compile_test_component(tool: details[:tool], context: context, test: details[:name], source: src, object: obj, msg: details[:msg]) end end end diff --git a/plugins/gcov/lib/gcov.rb b/plugins/gcov/lib/gcov.rb index ff9607e2..55de600a 100755 --- a/plugins/gcov/lib/gcov.rb +++ b/plugins/gcov/lib/gcov.rb @@ -61,15 +61,20 @@ def automatic_reporting_enabled? end def pre_compile_execute(arg_hash) - source = arg_hash[:source] - - # Handle assembly file that comes through - if File.extname(source) == EXTENSION_ASSEMBLY - arg_hash[:tool] = TOOLS_TEST_ASSEMBLER - # If a source file (not unity, mocks, etc.) is to be compiled use code coverage compiler - elsif @configurator.collection_all_source.include?(source) - arg_hash[:tool] = TOOLS_GCOV_COMPILER - arg_hash[:msg] = "Compiling #{File.basename(source)} with coverage..." + if arg_hash[:context] == GCOV_SYM + source = arg_hash[:source] + + # If a source file (not unity, mocks, etc.) is to be compiled use code coverage compiler + if (File.extname(source) != EXTENSION_ASSEMBLY) && @configurator.collection_all_source.include?(source) + arg_hash[:tool] = TOOLS_GCOV_COMPILER + arg_hash[:msg] = "Compiling #{File.basename(source)} with coverage..." + end + end + end + + def pre_link_execute(arg_hash) + if arg_hash[:context] == GCOV_SYM + arg_hash[:tool] = TOOLS_GCOV_LINKER end end From 538c0ef45b74a023b36aef8b6c7da23a56d5b3a0 Mon Sep 17 00:00:00 2001 From: mvandervoord Date: Fri, 18 Oct 2024 21:27:08 -0400 Subject: [PATCH 3/6] remove a rule that is no longer required. --- plugins/gcov/gcov.rake | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/plugins/gcov/gcov.rake b/plugins/gcov/gcov.rake index d8efc3df..06e855cc 100755 --- a/plugins/gcov/gcov.rake +++ b/plugins/gcov/gcov.rake @@ -20,17 +20,6 @@ CLEAN.include(File.join(GCOV_DEPENDENCIES_PATH, '*')) CLOBBER.include(File.join(GCOV_BUILD_PATH, '**/*')) -rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\' + EXTENSION_OBJECT}$/ => [ - proc do |task_name| - _, object = (task_name.split('+')) - @ceedling[:file_finder].find_build_input_file(filepath: object, context: GCOV_SYM) - end - ]) do |target| - test, object = (target.name.split('+')) - - @ceedling[GCOV_SYM].generate_coverage_object_file(test.to_sym, target.source, object) - end - task directories: [GCOV_BUILD_OUTPUT_PATH, GCOV_RESULTS_PATH, GCOV_DEPENDENCIES_PATH, GCOV_ARTIFACTS_PATH] namespace GCOV_SYM do From b2e8535f0b71089c57ca52641adcb578b0679b69 Mon Sep 17 00:00:00 2001 From: mvandervoord Date: Fri, 18 Oct 2024 22:02:13 -0400 Subject: [PATCH 4/6] promote loginator so we know where to find it from anywhere. --- lib/ceedling/loginator.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ceedling/loginator.rb b/lib/ceedling/loginator.rb index 5b635d32..8588160d 100644 --- a/lib/ceedling/loginator.rb +++ b/lib/ceedling/loginator.rb @@ -17,6 +17,7 @@ class Loginator constructor :verbosinator, :file_wrapper, :system_wrapper def setup() + $loginator = self @decorators = false # Friendly robustification for certain testing scenarios @@ -311,5 +312,5 @@ def logfile(string, stream='') end END { - @ceedling[:loginator].wrapup + $loginator.wrapup unless $loginator.nil? } \ No newline at end of file From cb01ae02e46f1304d3647765b84809cae0bc1df5 Mon Sep 17 00:00:00 2001 From: mvandervoord Date: Sat, 19 Oct 2024 18:27:34 -0400 Subject: [PATCH 5/6] - remove orphaned function. - at gcov options to project.yml files --- assets/project_as_gem.yml | 2 ++ assets/project_with_guts.yml | 2 ++ lib/ceedling/test_invoker_helper.rb | 23 ----------------------- 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/assets/project_as_gem.yml b/assets/project_as_gem.yml index 22d60584..98b4d47c 100644 --- a/assets/project_as_gem.yml +++ b/assets/project_as_gem.yml @@ -232,6 +232,8 @@ # You will need to have gcov and gcovr both installed to make it work. # For more information on these options, see docs in plugins/gcov :gcov: + :summaries: TRUE # Enable simple coverage summaries to console after tests + :report_task: FALSE # Disabled dedicated report generation task (this enables automatic report generation) :utilities: - gcovr # Use gcovr to create the specified reports (default). #- ReportGenerator # Use ReportGenerator to create the specified reports. diff --git a/assets/project_with_guts.yml b/assets/project_with_guts.yml index 931d9b0a..19309b8f 100644 --- a/assets/project_with_guts.yml +++ b/assets/project_with_guts.yml @@ -232,6 +232,8 @@ # You will need to have gcov and gcovr both installed to make it work. # For more information on these options, see docs in plugins/gcov :gcov: + :summaries: TRUE # Enable simple coverage summaries to console after tests + :report_task: FALSE # Disabled dedicated report generation task (this enables automatic report generation) :utilities: - gcovr # Use gcovr to create the specified reports (default). #- ReportGenerator # Use ReportGenerator to create the specified reports. diff --git a/lib/ceedling/test_invoker_helper.rb b/lib/ceedling/test_invoker_helper.rb index 498a89d2..928ec074 100644 --- a/lib/ceedling/test_invoker_helper.rb +++ b/lib/ceedling/test_invoker_helper.rb @@ -254,29 +254,6 @@ def clean_test_results(path, tests) end end - def generate_objects_now(object_list, context, options) - @batchinator.exec(workload: :compile, things: object_list) do |object| - src = @file_finder.find_build_input_file(filepath: object, context: TEST_SYM) - if (File.basename(src) =~ /#{EXTENSION_SOURCE}$/) - @generator.generate_object_file( - options[:test_compiler], - OPERATION_COMPILE_SYM, - context, - src, - object, - @file_path_utils.form_test_build_list_filepath( object ), - @file_path_utils.form_test_dependencies_filepath( object )) - elsif (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) - @generator.generate_object_file( - options[:test_assembler], - OPERATION_ASSEMBLE_SYM, - context, - src, - object ) - end - end - end - # Convert libraries configuration form YAML configuration # into a string that can be given to the compiler. def convert_libraries_to_arguments() From 37fc98abee3eff6efa5c80434ddab919c53af5f5 Mon Sep 17 00:00:00 2001 From: mvandervoord Date: Wed, 23 Oct 2024 15:40:09 -0400 Subject: [PATCH 6/6] - Protect against relative path failures, like C: to D: - Add Ruby 3.3 testing - Report recently added exceptions as exceptions to logging decorator. --- .github/workflows/main.yml | 15 ++------------- lib/ceedling/build_batchinator.rb | 4 ++-- lib/ceedling/file_path_collection_utils.rb | 21 +++++++++++---------- lib/ceedling/plugin_manager.rb | 2 +- plugins/dependencies/lib/dependencies.rb | 6 +++++- 5 files changed, 21 insertions(+), 27 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6faf9bb1..baa12598 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['3.0', '3.1', '3.2'] + ruby: ['3.0', '3.1', '3.2', '3.3'] steps: # Use a cache for our tools to speed up testing - uses: actions/cache@v4 @@ -131,7 +131,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['3.0', '3.1', '3.2'] + ruby: ['3.0', '3.1', '3.2', '3.3'] steps: # Use a cache for our tools to speed up testing - uses: actions/cache@v4 @@ -288,14 +288,3 @@ jobs: asset_name: ceedling-${{ env.ceedling_build }}.gem asset_content_type: test/x-gemfile - # - name: Upload Pre-Release Gem - # uses: softprops/action-gh-release@v2 - # with: - # # repo_token: "${{ secrets.GITHUB_TOKEN }}" - # body: | - # [Release Notes](${{ github.workspace }}/docs/ReleaseNotes.md) - # name: ${{ env.full_ver }} - # prerelease: true - # files: | - # *.gem - diff --git a/lib/ceedling/build_batchinator.rb b/lib/ceedling/build_batchinator.rb index 27d61661..3b65dffa 100644 --- a/lib/ceedling/build_batchinator.rb +++ b/lib/ceedling/build_batchinator.rb @@ -68,7 +68,7 @@ def exec(workload:, things:, &block) # ThreadError outside scope of expected empty queue condition unless e.message.strip.casecmp("queue empty") - @loginator.log(e.message, Verbosity::ERRORS) + @loginator.log(e.message, Verbosity::ERRORS, LogLabels::EXCEPTION ) # Shutdown all worker threads shutdown_threads(threads) @@ -82,7 +82,7 @@ def exec(workload:, things:, &block) # 1. Calling code knows something bad happened and handles appropriately # 2. Ruby runtime can handle most serious problems rescue Exception => e - @loginator.log(e.message, Verbosity::ERRORS) + @loginator.log(e.message, Verbosity::ERRORS, LogLabels::EXCEPTION ) # Shutdown all worker threads shutdown_threads(threads) diff --git a/lib/ceedling/file_path_collection_utils.rb b/lib/ceedling/file_path_collection_utils.rb index ce71878c..65fbeb25 100644 --- a/lib/ceedling/file_path_collection_utils.rb +++ b/lib/ceedling/file_path_collection_utils.rb @@ -21,7 +21,6 @@ def setup() @working_dir_path = Pathname.new( Dir.pwd() ) end - # Build up a directory path list from one or more strings or arrays of (+:/-:) simple paths & globs def collect_paths(paths) plus = Set.new # All real, expanded directory paths to add @@ -78,11 +77,7 @@ def collect_paths(paths) # Use Set subtraction operator to remove any excluded paths paths = (plus - minus).to_a - - paths.map! do |path| - # Reform path from full absolute to nice, neat relative path instead - (Pathname.new( path ).relative_path_from( @working_dir_path )).to_s() - end + paths.map! {|path| shortest_path_from_working(path) } return paths end @@ -124,13 +119,19 @@ def revise_filelist(list, revisions) # Use Set subtraction operator to remove any excluded paths paths = (plus - minus).to_a + paths.map! {|path| shortest_path_from_working(path) } - paths.map! do |path| + return FileList.new( paths ) + end + + def shortest_path_from_working(path) + begin # Reform path from full absolute to nice, neat relative path instead - (Pathname.new( path ).relative_path_from( @working_dir_path )).to_s() + (Pathname.new( path ).relative_path_from( @working_dir_path )).to_s + rescue + # If we can't form a relative path between these paths, use the absolute + path end - - return FileList.new( paths ) end end diff --git a/lib/ceedling/plugin_manager.rb b/lib/ceedling/plugin_manager.rb index afba6409..ca6c5085 100644 --- a/lib/ceedling/plugin_manager.rb +++ b/lib/ceedling/plugin_manager.rb @@ -40,7 +40,7 @@ def load_programmatic_plugins(plugins, system_objects) # Add plugins to hash of all system objects system_objects[hash[:plugin].downcase().to_sym()] = object rescue - @loginator.log( "Exception raised while trying to load plugin: #{hash[:plugin]}", Verbosity::ERRORS ) + @loginator.log( "Exception raised while trying to load plugin: #{hash[:plugin]}", Verbosity::ERRORS, LogLabels::EXCEPTION ) raise # Raise again for backtrace, etc. end end diff --git a/plugins/dependencies/lib/dependencies.rb b/plugins/dependencies/lib/dependencies.rb index f0690d26..790ecec4 100644 --- a/plugins/dependencies/lib/dependencies.rb +++ b/plugins/dependencies/lib/dependencies.rb @@ -396,7 +396,11 @@ def build_lib(blob) name = blob[:name] || "" source_path = Pathname.new get_source_path(blob) build_path = Pathname.new get_build_path(blob) - relative_build_path = build_path.relative_path_from(source_path) + relative_build_path = begin + build_path.relative_path_from(source_path) + rescue + build_path + end # Verify there is an artifact that we're building that makes sense libs = []