#!/usr/bin/env ruby require 'fileutils' $:.unshift(File.dirname(__FILE__)+"/../lib") require "bakeqac/options/options" require 'bake/toolchain/colorizing_formatter' require 'bake/options/options' require 'common/process' require 'common/utils' module Bake ###### PREREQUISITE 1: BAKEQAC OPTIONS ###### @options = BakeqacOptions.new(ARGV) bakeOptions = Options.new([]) @options.parse_options(bakeOptions) success = false consoleOutput = "" licenseError = false ###### PREREQUISITE 2: BAKE OPTIONS ###### passedParams = [] excludeParam = false wasMinus = false ARGV.each do |x| if ["--c++11", "--c++14", "--qacnofilter", "--qacnoformat", "--qacrawformat", "--qacunittest", "--qacdoc"].include?x excludeParam = false next elsif ["--cct", "--rcf", "--acf", "--qacdata", "--qacstep", "--qacretry"].include?x excludeParam = true next elsif excludeParam excludeParam = false next end passedParams << x end passedParams << "--rebuild" unless passedParams.include?"--rebuild" passedParams << "--compile-only" if (passedParams & ["--compile-only", "--compile_only", "-f"]).empty? passedParams << "--filter-paths" unless passedParams.include?"--filter-paths" success = true ###### PREREQUISITE 3: QACLI LOCATION ###### qaExe = [@options.qac_home+"/common/bin/qacli"] if @options.qacunittest qaExe = ["ruby", File.dirname(__FILE__)+"/../spec/bin/qactester.rb"] end ###### STEP 1: CREATE ###### if (@options.qacstep.nil? or @options.qacstep.include?"admin") cmd = qaExe + ["admin", "--qaf-project-config", "--qaf-project", @options.qacdata] @options.cct.each {|c| cmd << "--cct" << c } cmd << "--rcf" << @options.rcf cmd << "--acf" << @options.acf puts "bakeqac: creating database..." FileUtils.rm_rf @options.qacdata success, consoleOutput = ProcessHelper.run(cmd, true) if success cctFilename = @options.qacdata+"/prqa/config/"+File.basename(@options.cct[0]) if File.exist?cctFilename File.open(cctFilename, 'a') do |f| f << "-coderegex='s/__attribute__\\s*\\(.*\\)//'\n" f << "-d __cdecl=\n" f << "-d _cdecl=\n" f << "-d _thiscall=\n" f << "-d __stdcall=\n" if @options.cct_append File.open(@options.cct_append, 'r') do |a| a.each_line { |line| f << line } end end end end else puts consoleOutput end end ###### STEP 2: BUILD ###### if success and (@options.qacstep.nil? or @options.qacstep.include?"analyze") FileUtils::mkdir_p @options.qacdata cmd = qaExe + ["analyze", "-P", @options.qacdata, "-b"] begin devMode = File.exist?"c:/Projekte/git/bake/bin/bake" rescue Exception devMode = false end if devMode bcmd = "ruby c:/Projekte/git/bake/bin/bake " else bcmd = (Utils::OS.windows? ? "cmd /c bake.bat " : "bake ") end bcmd += passedParams.join(" ") cmd << bcmd puts "bakeqac: building and analyzing files..." timeStart = Time.now loop do success, consoleOutput = ProcessHelper.run(cmd, false) licenseError = false consoleOutput.each_line do |line| licenseError = true if (line.include?("License Refused") && !line.include?("License Refused: C:")) end break unless (licenseError and (@options.qacretry >= (Time.now - timeStart))) puts "License refused, retry seconds left: %d" % (@options.qacretry - (Time.now - timeStart)) end puts "License refused, retry timeout over -> failure." if (@options.qacretry > 0 && licenseError) success = false # we have to parse the output, qacli returns always an error here... filterOutput = [] filter = [] endFound = false consoleOutput.each_line do |line| scan_res = line.scan(/Project path: ([a-zA-Z]{0,1})(:{0,1})(.*)/) if scan_res.length > 0 filter << (scan_res[0][0].downcase + scan_res[0][1] + scan_res[0][2].gsub(/\\/,"/").strip) elsif !endFound filterOutput << line if line.start_with?("Rebuilding ") endFound = true success = true if line.include?("Rebuilding done") # don't know why the return value is 2 in this case... end end end success = false if licenseError if @options.qacfilter if success puts filterOutput File.open("#{@options.qacdata}/filter.txt", "w+") do |f| f.puts(filter) end else puts consoleOutput # error end else puts consoleOutput # no filter end end ###### STEP 3: RESULT ###### if success and (@options.qacstep.nil? or @options.qacstep.include?"view") FileUtils::mkdir_p @options.qacdata puts "bakeqac: printing results..." filter = [] useFilter = File.exist?("#{@options.qacdata}/filter.txt") && @options.qacfilter if useFilter File.open("#{@options.qacdata}/filter.txt", "r") do |f| f.each_line { |line| filter << line.strip } end filter.delete_if { |f| (f.end_with? "/gtest") or (f.end_with? "/gmock") } end cmd = qaExe + ["view", "-P", @options.qacdata, "-m", "STDOUT"] if not @options.qacnoformat cmd += ["-f", "%?u==0%(MSG: %:trc: %)%F(%l,%c): (%r:%N)%t%?v%(\n%v%)"] end timeStart = Time.now loop do success, consoleOutput = ProcessHelper.run(cmd, false) licenseError = false consoleOutput.each_line do |line| licenseError = true if (line.include?("License Refused") && !line.include?("License Refused: C:")) end break unless (licenseError and (@options.qacretry >= (Time.now - timeStart))) puts "License refused, retry seconds left: %d" % (@options.qacretry - (Time.now - timeStart)) end puts "License refused, retry timeout over -> failure." if (@options.qacretry > 0 && licenseError) success = false if licenseError if useFilter if success # 1. filter filteredLines = [] foundFile = false consoleOutput.each_line do |line| line.strip! foundFile = false if line.empty? or line.include? " ======= Results for " scan_res = line.scan(/\/\/ ======= Results for ([a-zA-Z]{0,1})(:{0,1})(.*)/) if scan_res.length > 0 converted_line = (scan_res[0][0].downcase + scan_res[0][1] + scan_res[0][2].gsub(/\\/,"/")) filter.each do |fil| if converted_line.include?(fil+"/") and not converted_line.include?(fil+"/test/") and not converted_line.include?(fil+"/mock/") and not converted_line.include?(fil+"/.qacdata/") foundFile = true break end end end filteredLines << line if foundFile && !line.include?("QAC++ Deep Flow Static Analyser") end # 2. sort sortedLines = [] linesOfFile = {} lineNum = 0 currentMessage = [] filteredLines.each do |line| if line.include? " ======= Results for " lineNum = 0 linesOfFile.sort.each { |lineNr, s| sortedLines += s } linesOfFile = {} sortedLines << line else if (!@options.qacnoformat && line.start_with?("MSG: ")) || (@options.qacnoformat && line.include?(": Msg(")) lineScan = line.scan(/[^\(]*\((\d*)/) lineNum = lineScan[0][0].to_i if lineScan.length > 0 end if linesOfFile.has_key?lineNum currentMessage = linesOfFile[lineNum] else currentMessage = [] linesOfFile[lineNum] = currentMessage end currentMessage << line end end linesOfFile.sort.each { |lineNr, s| sortedLines += s } # 3. print numberOfMessages = 0 Dir.chdir(@options.qac_home) do sortedLines.each do |line| if (!@options.qacnoformat && line.start_with?("MSG: ")) || (@options.qacnoformat && line.include?(": Msg(")) Bake.formatter.printWarning(line) if @options.qacdoc errorNumScan = line.scan(/[^\(]*\([^\(]*\([^:]*:(\d*)/) if errorNumScan.length > 0 errorNum = errorNumScan[0][0].to_i htmlFiles = Dir.glob("components/qacpp*/doc-en_US/messages/%04d.html" % errorNum) + Dir.glob("components/mcpp*/doc-en_US/messages/%04d.html" % errorNum) htmlFiles.each do |htmlFile| puts "doc: #{File.expand_path(htmlFile)}" end end end numberOfMessages += 1 elsif line.include? " ======= Results for " Bake.formatter.printAdditionalInfo(line) else Bake.formatter.printInfo(line) end end Bake.formatter.printSuccess("\n**** Number of messages: #{numberOfMessages} ****") end else puts consoleOutput # error end else puts consoleOutput # no filter end end ###### DONE ###### exit(success ? 0 : 1) end