lib/blocks/block.rb in bake-toolkit-2.32.0 vs lib/blocks/block.rb in bake-toolkit-2.33.0

- old
+ new

@@ -1,8 +1,10 @@ require 'bake/libElement' require 'bake/model/metamodel' require 'common/abortException' +require "multithread/job" +require "thwait" module Bake BUILD_PASSED = 0 BUILD_FAILED = 1 @@ -14,10 +16,14 @@ ALL_BLOCKS = {} ALL_COMPILE_BLOCKS = {} class Block + @@block_counter = 0 + @@delayed_result = true + @@threads = [] + attr_reader :lib_elements, :projectDir, :library, :config, :projectName, :prebuild, :output_dir, :tcs attr_accessor :visited, :inDeps, :result def startupSteps @startupSteps ||= [] @@ -71,11 +77,10 @@ @config = config @referencedConfigs = referencedConfigs @projectName = config.parent.name @configName = config.name @projectDir = config.get_project_dir - @@block_counter = 0 @result = true @tcs = tcs @lib_elements = Bake::LibElements.calcLibElements(self) @@ -97,11 +102,13 @@ return d if Bake.options.no_autodir inc = d.split("/") if (inc[0] == "..") # very simple check, but should be okay for 99.9 % of the cases if elem and Bake.options.verbose >= 2 - Bake.formatter.printInfo("path starts with \"..\"", elem) + SyncOut.mutex.synchronize do + Bake.formatter.printInfo("path starts with \"..\"", elem) + end end end res = [] @@ -136,13 +143,15 @@ res = res.map{ |r| Pathname.new(r).cleanpath.to_s }.uniq if warnIfLocal && res.length > 1 if elem and Bake.options.verbose >= 2 - Bake.formatter.printInfo("#{d} matches several paths:", elem) - puts " #{res[0]} (chosen)" - res[1..-1].each { |r| puts " #{r}" } + SyncOut.mutex.synchronize do + Bake.formatter.printInfo("#{d} matches several paths:", elem) + puts " #{res[0]} (chosen)" + res[1..-1].each { |r| puts " #{r}" } + end end end res[0] end @@ -157,10 +166,22 @@ def self.reset_block_counter @@block_counter = 0 end + def self.reset_delayed_result + @@delayed_result = true + end + + def self.delayed_result + @@delayed_result + end + + def self.threads + @@threads + end + def calcIsBuildBlock @startupSteps ||= [] return true if Metamodel::ExecutableConfig === @config if Metamodel::CustomConfig === @config @@ -205,12 +226,14 @@ @result = false ProcessHelper.killProcess(true) rescue Exception => ex1 @result = false if not Bake::IDEInterface.instance.get_abort - Bake.formatter.printError("Error: #{ex1.message}") - puts ex1.backtrace if Bake.options.debug + SyncOut.mutex.synchronize do + Bake.formatter.printError("Error: #{ex1.message}") + puts ex1.backtrace if Bake.options.debug + end end end if Bake::IDEInterface.instance.get_abort raise AbortException.new @@ -246,64 +269,130 @@ break if not depResult and Bake.options.stopOnFirstError end return depResult end + def execute_in_thread(method) + if method == :execute + @@mutex.synchronize do + if @@threads.length == Bake.options.threads + endedThread = ThreadsWait.new(@@threads).next_wait + @@threads.delete(endedThread) + end + end + thread = Thread.new() { + + exceptionOccured = false + begin + yield + exceptionOccured = true + rescue Bake::SystemCommandFailed => scf # normal compilation error + rescue SystemExit => exSys + rescue Exception => ex1 + if not Bake::IDEInterface.instance.get_abort + SyncOut.mutex.synchronize do + Bake.formatter.printError("Error: #{ex1.message}") + puts ex1.backtrace if Bake.options.debug + end + end + end + if !exceptionOccured + @result = false + @@delayed_result = false + end + } + @@mutex.synchronize do + @@threads << thread + end + else + yield + end + raise AbortException.new if Bake::IDEInterface.instance.get_abort + end + + def blockAbort?(res) + ((not res) || !@@delayed_result) and Bake.options.stopOnFirstError or Bake::IDEInterface.instance.get_abort + end + def callSteps(method) @config.writeEnvVars() Thread.current[:lastCommand] = nil preSteps.each do |step| + ThreadsWait.all_waits(Blocks::Block::threads) @result = executeStep(step, method) if @result - return false if not @result and Bake.options.stopOnFirstError + return false if blockAbort?(@result) end unless @prebuild - mainSteps.each do |step| + threadableSteps = mainSteps.select { |step| method == :execute && (Library === step || Compile === step) } + nonThreadableSteps = mainSteps.select { |step| method != :execute || !(Library === step || Compile === step) } + + execute_in_thread(method) { + threadableSteps.each do |step| + if !@prebuild || (Library === step) + Multithread::Jobs.incThread() if Library === step + begin + @result = executeStep(step, method) if @result + ensure + Multithread::Jobs.decThread() if Library === step + end + @@delayed_result &&= @result + end + break if blockAbort?(@result) + end + } if !threadableSteps.empty? + nonThreadableSteps.each do |step| if !@prebuild || (Library === step) + ThreadsWait.all_waits(Blocks::Block::threads) @result = executeStep(step, method) if @result end - return false if not @result and Bake.options.stopOnFirstError + return false if blockAbort?(@result) end postSteps.each do |step| + ThreadsWait.all_waits(Blocks::Block::threads) @result = executeStep(step, method) if @result - return false if not @result and Bake.options.stopOnFirstError + return false if blockAbort?(@result) end unless @prebuild return @result end def execute if (@inDeps) if Bake.options.verbose >= 3 - Bake.formatter.printWarning("While calculating next config, a circular dependency was found including project #{@projectName} with config #{@configName}", @config) + SyncOut.mutex.synchronize do + Bake.formatter.printWarning("While calculating next config, a circular dependency was found including project #{@projectName} with config #{@configName}", @config) + end end return true end return true if (@visited) @visited = true @inDeps = true depResult = callDeps(:execute) @inDeps = false - return false if not depResult and Bake.options.stopOnFirstError + return false if blockAbort?(depResult) Bake::IDEInterface.instance.set_build_info(@projectName, @configName) - if Bake.options.verbose >= 2 || isBuildBlock? || @prebuild - typeStr = "Building" - if @prebuild - typeStr = "Using" - elsif not isBuildBlock? - typeStr = "Applying" + SyncOut.mutex.synchronize do + if Bake.options.verbose >= 2 || isBuildBlock? || @prebuild + typeStr = "Building" + if @prebuild + typeStr = "Using" + elsif not isBuildBlock? + typeStr = "Applying" + end + Block.inc_block_counter() + Bake.formatter.printAdditionalInfo "**** #{typeStr} #{Block.block_counter} of #{@@num_projects}: #{@projectName} (#{@configName}) ****" end - Block.inc_block_counter() - Bake.formatter.printAdditionalInfo "**** #{typeStr} #{Block.block_counter} of #{@@num_projects}: #{@projectName} (#{@configName}) ****" + puts "Project path: #{@projectDir}" if Bake.options.projectPaths end - puts "Project path: #{@projectDir}" if Bake.options.projectPaths @result = callSteps(:execute) return (depResult && @result) end @@ -313,10 +402,14 @@ depResult = callDeps(:clean) return false if not depResult and Bake.options.stopOnFirstError if Bake.options.verbose >= 2 || isBuildBlock? || @prebuild + Block.inc_block_counter() + end + + if Bake.options.verbose >= 2 typeStr = "Cleaning" if @prebuild typeStr = "Checking" elsif not isBuildBlock? typeStr = "Skipping" @@ -342,9 +435,15 @@ @result = executeStep(step, :cleanStep) if @result return false if not @result and Bake.options.stopOnFirstError end unless @prebuild return (depResult && @result) + end + + def self.init_threads() + @@threads = [] + @@result = true + @@mutex = Mutex.new end def startup return true if (@visited) @visited = true \ No newline at end of file