class XCAnafail

A class to give this gem some scope. The designed way to use it is through the binary, though all the binary does is call the run method on this class.

Examples

> set -o pipefail
> xctool -workspace MyApp.workspace -scheme MyApp.scheme -reporter plain analyze | xcanafail | <other utilities>

Constants

ANALYZE_FILE_LINE_REGEX

Keep track of which file we are currently looking at

COMPILE_FILE_LINE_REGEX

Use this to not record warnings that occur during compilation

SEPARATOR_REGEX

Detect when a separator has happened

WARNING_COUNT_LINE_REGEX

Check to see if there have been any warnings created

Private Class Methods

run() click to toggle source

This method will start to read in from either a pipe for stdin, parse the input to detect any analysis warnings and then stream the input back out through stdout

# File lib/xcanafail.rb, line 45
def self.run

  # Read in the arguments and verify etc.
  options = OpenStruct.new
  options.output = '/dev/null'
  OptionParser.new do |opts|
    opts.banner = 'Usage: xcanafail.rb [options]'

    opts.on('-o', '--out FILE', 'An optional output file') do |o|
      options.output = o
    end

    # No argument, shows at tail.  This will print an options summary.
    opts.on_tail('-h', '--help', 'Show this message') do
      puts opts
      exit
    end
  end.parse!

  # Assume success, but this might change during the parse
  exit_code = 0

  # open the output file if we have been given one
  File.open(options.output, 'w') do |output|

    current_file = nil

    # We start at the root level
    state = ParseState::ROOT

    # We need to store up the contents of a warning block to deal with it all when we get to the end
    block_contents = nil

    ARGF.each_line { |line|
      # We should appear transparent to the end user
      puts line

      # Get each line from the pipe and see where we are
      if ANALYZE_FILE_LINE_REGEX.match(line)
        current_file = line
        next
      end

      # If we are entering a compile for a file, we just don't care
      if COMPILE_FILE_LINE_REGEX.match(line)
        current_file = nil
        next
      end

      # If we don't know which file we are in yet, don't process the rest of this line
      next if current_file.nil?

      # Or if we are going in/out of a separator block?
      if SEPARATOR_REGEX.match(line)

        if state == ParseState::ROOT
          state = ParseState::INSIDE_BLOCK
          block_contents = []
        else
          # If the last line of the block contains a warning count then we have had a valid warning
          if block_contents.count > 0
            last_line = block_contents.last
            if WARNING_COUNT_LINE_REGEX.match(last_line)
              output.print("Warning -> Error\n")
              output.print(current_file + "\n")
              output.print(block_contents.join("\n"))
              exit_code = 1
            end
          end

          #puts "Leaving warning block : " + block_contents.to_s

          block_contents = nil
          state = ParseState::ROOT
          current_file = nil
        end

        next
      end

      if state == ParseState::INSIDE_BLOCK
        block_contents << line
      end

      #puts line
    }
  end

  exit(exit_code)

end