xcpretty 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3cdbe8277b55adfd4317be89f22241dc8d4c578c
4
- data.tar.gz: 9bfea05a3753284b4e1db7e91943db93ee26ef21
3
+ metadata.gz: d1a03b19be84f708774b6c76d7b89cac3231eed1
4
+ data.tar.gz: 282c28b193dd9f9e92e83e46f38e86481c3f8432
5
5
  SHA512:
6
- metadata.gz: a592232729d2a6b7401e7d647f372546f065a24ca3ff79c51d06a35aafac74203133628b19d665def319427bb1cc7755a0802d00c7b6c16ab882d8ff5c61f940
7
- data.tar.gz: 39521953385cccd526e2d7b96dc0319cad393dce8803a2a14cf0b15d9e0bcf7a46cc84e3393681b101ab707c61f1d8a4a5248214e1442cdc8776cbe5af5ff22b
6
+ metadata.gz: 9ac22b284e55a4397cb190a9406e4fc4992ab79ebb2b1a25b1210361f5bacbebdd26e269228ccdbb2cd3856bea055314c66f52f78bf213ae2c34d0110aa21230
7
+ data.tar.gz: 63fb8efd9849d07ad752efad960bfdadab4a67e4d741600fe62a70a92f3e97b4e3b5bf725b7ad2d06ebb85612dcd155dae8eef4d77c961b5f14b494b66de4116
data/.travis.yml CHANGED
@@ -5,6 +5,9 @@ before_install:
5
5
  - gem update --system 2.1.11
6
6
  - gem --version
7
7
 
8
+ install:
9
+ - bundle install
10
+
8
11
  rvm:
9
12
  - 2.1.0
10
13
  - 2.0.0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.5
4
+
5
+ ###### Enhancements
6
+
7
+ * Json-compilation-databse report!
8
+ | [Boris Bügling](https://github.com/neonichu)
9
+ | [#77](https://github.com/supermarin/xcpretty/pull/77)
10
+ * Parsing duplicate symbols
11
+ | [#78](https://github.com/supermarin/xcpretty/pull/78)
12
+ * Improved performance (nobody cares)
13
+
14
+ ###### Bug Fixes
15
+
16
+ * Fix closing files when used from another proccess
17
+ | [Jonas Witt](https://github.com/jonaswitt)
18
+ | [#75](http://github.com/supermarin/xcpretty/pull/75)
19
+
20
+
21
+ ## 0.1.4
22
+
23
+ ###### Enhancements
24
+
25
+ * New logo
26
+ * New output format: tap
27
+ * New output format: knock
28
+ * Updated parser to support Specta 0.2.1
29
+ | [Josh Vickery](https://github.com/vickeryj)
30
+ | [#64](https://github.com/supermarin/xcpretty/pull/64)
31
+ * Support additional file extensions
32
+ | [Boris Bügling](https://github.com/neonichu)
33
+ | [#59](https://github.com/supermarin/xcpretty/pull/59)
34
+
35
+
3
36
  ## 0.1.3
4
37
 
5
38
  ###### Enhancements
data/README.md CHANGED
@@ -3,8 +3,9 @@
3
3
  __`xcpretty` is a fast and flexible formatter for `xcodebuild`__.<br/>
4
4
  It does one thing, and it should do it well.
5
5
 
6
- [![Build Status](https://travis-ci.org/supermarin/xcpretty.png?branch=master)](https://travis-ci.org/supermarin/xcpretty)
7
- [![Code Climate](https://codeclimate.com/github/supermarin/xcpretty.png)](https://codeclimate.com/github/supermarin/xcpretty)
6
+ [![Gem version](http://img.shields.io/gem/v/xcpretty.svg)](http://rubygems.org/gems/xcpretty)
7
+ [![Build Status](https://travis-ci.org/supermarin/xcpretty.svg?branch=master)](https://travis-ci.org/supermarin/xcpretty)
8
+ [![Code Climate](http://img.shields.io/codeclimate/github/supermarin/xcpretty.svg)](https://codeclimate.com/github/supermarin/xcpretty)
8
9
 
9
10
  ## Installation
10
11
  ``` bash
@@ -22,7 +23,11 @@ __Important:__ If you're running `xcpretty` on a CI like Travis or Jenkins, you
22
23
  CI uses the status code to determine if build has failed.
23
24
 
24
25
  ``` bash
25
- $ xcodebuild [flags] | xcpretty -c; exit ${PIPESTATUS[0]}
26
+ $ set -o pipefail && xcodebuild [flags] | xcpretty -c
27
+ #
28
+ # OR
29
+ #
30
+ $ xcodebuild [flags] | xcpretty -c && exit ${PIPESTATUS[0]}
26
31
  ```
27
32
 
28
33
  ## Formats
@@ -41,11 +46,13 @@ $ xcodebuild [flags] | xcpretty -c; exit ${PIPESTATUS[0]}
41
46
 
42
47
  ## Reporters
43
48
 
44
- - `--report junit`, `-r junit`: Creates a JUnit-style XML report at `build/reports/junit.xml`, compatible with Jenkins CI.
49
+ - `--report junit`, `-r junit`: Creates a JUnit-style XML report at `build/reports/junit.xml`, compatible with Jenkins and TeamCity CI.
45
50
 
46
51
  - `--report html`, `-r html`: Creates a simple HTML report at `build/reports/tests.html`.
47
52
  ![xcpretty html](http://i.imgur.com/0Rnux3v.gif)
48
53
 
54
+ - `--report json-compilation-database`, `-r json-compilation-database`: Creates a [JSON compilation database](http://clang.llvm.org/docs/JSONCompilationDatabase.html) at `build/reports/compilation.json`. This is a format to replay single compilations independently of the build system.
55
+
49
56
  Writing a report to a custom path can be specified using `--output PATH`.
50
57
 
51
58
  ## Did you just clone xctool?
data/bin/xcpretty CHANGED
@@ -13,8 +13,9 @@ require 'optparse'
13
13
  report_options = []
14
14
  report_classes = []
15
15
  report_formats = {
16
- "junit" => XCPretty::JUnit,
17
- "html" => XCPretty::HTML
16
+ "junit" => XCPretty::JUnit,
17
+ "html" => XCPretty::HTML,
18
+ "json-compilation-database" => XCPretty::JSONCompilationDatabase,
18
19
  }
19
20
 
20
21
  printer_opts = {
@@ -0,0 +1,21 @@
1
+ Feature: Create a JSON compilation database
2
+
3
+ Scenario: Showing file compilation
4
+ Given I have a file to compile
5
+ When I pipe to xcpretty with "--report json-compilation-database" and specify a custom path
6
+ Then the JSON compilation database should contain an entry with a command
7
+ Then the JSON compilation database should contain an entry with a directory
8
+ Then the JSON compilation database should contain an entry with a file
9
+
10
+ Scenario: Handling a complete xcodebuild session
11
+ Given some big input
12
+ When I pipe to xcpretty with "--report json-compilation-database" and specify a custom path
13
+ Then the JSON compilation database should be complete
14
+
15
+ Scenario: Writing to a custom file path
16
+ When I pipe to xcpretty with "--report json-compilation-database" and specify a custom path
17
+ Then I should have a JSON compilation database in a custom path
18
+
19
+ Scenario: Writing to multiple custom file paths
20
+ When I pipe to xcpretty with two custom "json-compilation-database" report paths
21
+ Then I should have JSON compilation databases in two custom paths
@@ -8,6 +8,11 @@ Feature: Creating a JUnit test report
8
8
  When I pipe to xcpretty with "--report junit"
9
9
  Then I should see a test suite node
10
10
 
11
+ Scenario: Showing pending test output
12
+ Given I have a pending test in my suite
13
+ When I pipe to xcpretty with "--report junit"
14
+ Then I should see a pending test node in my report
15
+
11
16
  Scenario: Showing failed tests
12
17
  Given I have a failing test in my suite
13
18
  When I pipe to xcpretty with "--report junit"
@@ -0,0 +1,37 @@
1
+ Given(/^some big input$/) do
2
+ add_run_input File.open('features/fixtures/xcodebuild.log', 'r').read
3
+ end
4
+
5
+ Then(/^I should have a JSON compilation database in a custom path$/) do
6
+ step("I should have a JSON compilation database at \"#{custom_report_path}\"")
7
+ end
8
+
9
+ Then(/^I should have a JSON compilation database at "(.*?)"$/) do |path|
10
+ json = JSON.parse(File.open(path, 'r').read)
11
+ json.should_not be_nil
12
+ end
13
+
14
+ Then(/^I should have JSON compilation databases in two custom paths$/) do
15
+ step("I should have a JSON compilation database at \"#{custom_report_path}\"")
16
+ step("I should have a JSON compilation database at \"#{other_custom_report_path}\"")
17
+ end
18
+
19
+ Then(/^the JSON compilation database should contain an entry with a command$/) do
20
+ json_db.length.should == 1
21
+
22
+ json_db[0]["command"].should start_with("/Applications/Xcode.app/Contents/Developer")
23
+ json_db[0]["command"].should end_with(".o")
24
+ end
25
+
26
+ Then(/^the JSON compilation database should contain an entry with a file$/) do
27
+ json_db[0]["file"].should == "NSMutableArray+ObjectiveSugar.m"
28
+ end
29
+
30
+ Then(/^the JSON compilation database should contain an entry with a directory$/) do
31
+ json_db[0]["directory"].should == "/Users/musalj/code/OSS/ObjectiveSugar/Classes"
32
+ end
33
+
34
+ Then(/^the JSON compilation database should be complete$/) do
35
+ entries = json_db.select {|entry| entry['command'] && entry['file'] && entry['directory']}
36
+ entries.length.should == JSON_DB_FIXTURE_COMMAND_COUNT
37
+ end
@@ -11,6 +11,12 @@ Then(/^I should see a passing test node in my report$/) do
11
11
  end.should_not be_nil
12
12
  end
13
13
 
14
+ Then(/^I should see a pending test node in my report$/) do
15
+ junit_report_root.elements.to_a.detect do |node|
16
+ node.elements.to_a.detect {|child| child.name == 'skipped'}
17
+ end.should_not be_nil
18
+ end
19
+
14
20
  Then(/^I should see a test suite node$/) do
15
21
  junit_report_root.elements.to_a.first.should_not be_nil
16
22
  end
@@ -10,6 +10,12 @@ require 'rexml/document'
10
10
  require 'lib/xcpretty/formatters/formatter'
11
11
  require 'lib/xcpretty/reporters/junit'
12
12
  require 'lib/xcpretty/reporters/html'
13
+ require 'lib/xcpretty/reporters/json_compilation_database'
14
+ begin
15
+ require 'json'
16
+ rescue LoadError
17
+ require 'vendor/json_pure/parser'
18
+ end
13
19
 
14
20
  include XCPretty::ANSI
15
21
 
@@ -21,6 +27,8 @@ PASSING_TEST_NAME_MATCHER = %r{\w+\s\(\d+\.\d+\sseconds\)}
21
27
  PENDING_TEST_NAME_MATCHER = %r{\w+\s\[PENDING\]}
22
28
  FAILING_TEST_NAME_MATCHER = %r{\w+, expected:}
23
29
 
30
+ JSON_DB_FIXTURE_COMMAND_COUNT = 557
31
+
24
32
  def run_xcpretty(flags)
25
33
  input_file = Tempfile.new('xcpretty_input')
26
34
  File.open(input_file.path, 'w') do |file|
@@ -57,6 +65,10 @@ def html_test_suites
57
65
  end
58
66
  end
59
67
 
68
+ def json_db
69
+ @json ||= JSON.parse(File.open(custom_report_path, 'r').read)
70
+ end
71
+
60
72
  def junit_report
61
73
  REXML::Document.new(File.open(XCPretty::JUnit::FILEPATH, 'r').read)
62
74
  end
@@ -89,6 +101,8 @@ After do
89
101
  @custom_report_file1.unlink if @custom_report_file1
90
102
  @custom_report_file2.unlink if @custom_report_file2
91
103
  @html_report = nil
104
+ @json = nil
92
105
  FileUtils.rm_rf(XCPretty::JUnit::FILEPATH)
93
106
  FileUtils.rm_rf(XCPretty::HTML::FILEPATH)
107
+ FileUtils.rm_rf(XCPretty::JSONCompilationDatabase::FILEPATH)
94
108
  end
@@ -9,40 +9,42 @@ module XCPretty
9
9
  module FormatMethods
10
10
  EMPTY = ''.freeze
11
11
 
12
- def format_analyze(file_name, file_path); EMPTY; end
13
- def format_build_target(target, project, configuration); EMPTY; end
14
- def format_check_dependencies; EMPTY; end
15
- def format_clean(project, target, configuration); EMPTY; end
16
- def format_clean_target(target, project, configuration); EMPTY; end
17
- def format_clean_remove; EMPTY; end
18
- def format_compile(file_name, file_path); EMPTY; end
19
- def format_compile_xib(file_name, file_path); EMPTY; end
20
- def format_copy_strings_file(file_name); EMPTY; end
21
- def format_cpresource(file); EMPTY; end
22
- def format_generate_dsym(dsym); EMPTY; end
23
- def format_linking(file, build_variant, arch); EMPTY; end
24
- def format_libtool(library); EMPTY; end
25
- def format_passing_test(suite, test, time); EMPTY; end
26
- def format_pending_test(suite, test); EMPTY; end
27
- def format_failing_test(suite, test, time, file_path); EMPTY; end
28
- def format_process_pch(file); EMPTY; end
29
- def format_phase_script_execution(script_name); EMPTY; end
30
- def format_process_info_plist(file_name, file_path); EMPTY; end
31
- def format_codesign(file); EMPTY; end
32
- def format_preprocess(file); EMPTY; end
33
- def format_pbxcp(file); EMPTY; end
34
- def format_test_run_started(name); EMPTY; end
35
- def format_test_run_finished(name, time); EMPTY; end
36
- def format_test_suite_started(name); EMPTY; end
37
- def format_test_summary(message, failures_per_suite); EMPTY; end
38
- def format_touch(file_path, file_name); EMPTY; end
39
- def format_tiffutil(file); EMPTY; end
12
+ def format_analyze(file_name, file_path); EMPTY; end
13
+ def format_build_target(target, project, configuration); EMPTY; end
14
+ def format_check_dependencies; EMPTY; end
15
+ def format_clean(project, target, configuration); EMPTY; end
16
+ def format_clean_target(target, project, configuration); EMPTY; end
17
+ def format_clean_remove; EMPTY; end
18
+ def format_compile(file_name, file_path); EMPTY; end
19
+ def format_compile_command(compiler_command); EMPTY; end
20
+ def format_compile_xib(file_name, file_path); EMPTY; end
21
+ def format_copy_strings_file(file_name); EMPTY; end
22
+ def format_cpresource(file); EMPTY; end
23
+ def format_generate_dsym(dsym); EMPTY; end
24
+ def format_linking(file, build_variant, arch); EMPTY; end
25
+ def format_libtool(library); EMPTY; end
26
+ def format_passing_test(suite, test, time); EMPTY; end
27
+ def format_pending_test(suite, test); EMPTY; end
28
+ def format_failing_test(suite, test, time, file_path); EMPTY; end
29
+ def format_process_pch(file); EMPTY; end
30
+ def format_phase_script_execution(script_name); EMPTY; end
31
+ def format_process_info_plist(file_name, file_path); EMPTY; end
32
+ def format_codesign(file); EMPTY; end
33
+ def format_preprocess(file); EMPTY; end
34
+ def format_pbxcp(file); EMPTY; end
35
+ def format_test_run_started(name); EMPTY; end
36
+ def format_test_run_finished(name, time); EMPTY; end
37
+ def format_test_suite_started(name); EMPTY; end
38
+ def format_test_summary(message, failures_per_suite); EMPTY; end
39
+ def format_touch(file_path, file_name); EMPTY; end
40
+ def format_tiffutil(file); EMPTY; end
40
41
 
41
42
  # COMPILER / LINKER ERRORS
42
43
  def format_compile_error(file_name, file_path, reason,
43
- line, cursor); EMPTY; end
44
- def format_error(message); EMPTY; end
45
- def format_linker_failure(message, symbol, reference); EMPTY; end
44
+ line, cursor); EMPTY; end
45
+ def format_error(message); EMPTY; end
46
+ def format_undefined_symbols(message, symbol, reference); EMPTY; end
47
+ def format_duplicate_symbols(message, file_paths); EMPTY; end
46
48
  end
47
49
 
48
50
  class Formatter
@@ -89,11 +91,19 @@ module XCPretty
89
91
  end
90
92
 
91
93
  def format_compile_error(file, file_path, reason, line, cursor)
92
- "\n#{red(error_symbol + " ")}#{file_path}: #{red(reason)}\n\n#{line}\n#{cyan(cursor)}\n\n"
94
+ "\n#{red(error_symbol + " ")}#{file_path}: #{red(reason)}\n\n" +
95
+ "#{line}\n#{cyan(cursor)}\n\n"
93
96
  end
94
97
 
95
- def format_linker_failure(message, symbol, reference)
96
- "\n#{red(error_symbol + " " + message)}\n> Symbol: #{symbol}\n> Referenced from: #{reference}\n\n"
98
+ def format_undefined_symbols(message, symbol, reference)
99
+ "\n#{red(error_symbol + " " + message)}\n" +
100
+ "> Symbol: #{symbol}\n" +
101
+ "> Referenced from: #{reference}\n\n"
102
+ end
103
+
104
+ def format_duplicate_symbols(message, file_paths)
105
+ "\n#{red(error_symbol + " " + message)}\n" +
106
+ "> #{file_paths.map { |path| path.split('/').last }.join("\n> ")}\n"
97
107
  end
98
108
 
99
109
 
@@ -16,10 +16,6 @@ module XCPretty
16
16
  # @regex Nothing returned here for now
17
17
  CHECK_DEPENDENCIES_MATCHER = /^Check dependencies/
18
18
 
19
- # @regex Captured groups
20
- # $1 = whole error
21
- CLANG_ERROR_MATCHER = /^(clang: error:.*)$/
22
-
23
19
  # @regex Nothing returned here for now
24
20
  CLEAN_REMOVE_MATCHER = /^Clean.Remove/
25
21
 
@@ -37,20 +33,14 @@ module XCPretty
37
33
  # $1 = file
38
34
  CODESIGN_FRAMEWORK_MATCHER = /^CodeSign\s((?:\\ |[^ ])*.framework)\/Versions/
39
35
 
40
- # @regex Captured groups
41
- # $1 = whole error
42
- CODESIGN_ERROR_MATCHER = /^(Code\s?Sign error:.*)$/
43
-
44
36
  # @regex Captured groups
45
37
  # $1 file_path
46
38
  # $2 file_name (e.g. KWNull.m)
47
39
  COMPILE_MATCHER = /^CompileC\s.*\s(.*\/(.*\.(?:m|mm|c|cc|cpp|cxx)))\s.*/
48
40
 
49
41
  # @regex Captured groups
50
- # $1 = file_path
51
- # $2 = file_name
52
- # $3 = reason
53
- COMPILE_ERROR_MATCHER = /^(\/.+\/(.*):.*:.*):(?:\sfatal)?\serror:\s(.*)$/
42
+ # $1 compiler_command
43
+ COMPILE_COMMAND_MATCHER = /^\s*(.*\/usr\/bin\/clang\s.*\.o)$/
54
44
 
55
45
  # @regex Captured groups
56
46
  # $1 file_path
@@ -65,10 +55,6 @@ module XCPretty
65
55
  # $1 resource
66
56
  CPRESOURCE_MATCHER = /^CpResource\s(.*)\s\//
67
57
 
68
- # @regex Captured groups
69
- # $1 cursor (with whitespaces and tildes)
70
- CURSOR_MATCHER = /^([\s~]*\^[\s~]*)$/
71
-
72
58
  # @regex Captured groups
73
59
  #
74
60
  EXECUTED_MATCHER = /^\s*Executed/
@@ -80,11 +66,6 @@ module XCPretty
80
66
  # $4 = reason
81
67
  FAILING_TEST_MATCHER = /^\s*(.+:\d+):\serror:\s[\+\-]\[(.*)\s(.*)\]\s:(?:\s'.*'\s\[FAILED\],)?\s(.*)/
82
68
 
83
- # @regex Captured groups
84
- # $1 = whole error.
85
- # it varies a lot, not sure if it makes sense to catch everything separately
86
- FATAL_ERROR_MATCHER = /^(fatal error:.*)$/
87
-
88
69
  # @regex Captured groups
89
70
  # $1 = dsym
90
71
  GENERATE_DSYM_MATCHER = /^GenerateDSYMFile \/.*\/(.*\.dSYM)/
@@ -93,14 +74,6 @@ module XCPretty
93
74
  # $1 = library
94
75
  LIBTOOL_MATCHER = /^Libtool.*\/(.*\.a)/
95
76
 
96
- # @regex Captured groups
97
- # $1 = whole error
98
- LD_ERROR_MATCHER = /^(ld:.*not found for.*)/
99
-
100
- # @regex Captured groups
101
- # $1 reason
102
- LINKER_FAILURE_MATCHER = /^(Undefined symbols for architecture .*):$/
103
-
104
77
  # @regex Captured groups
105
78
  # $1 = target
106
79
  # $2 = build_variants (normal, profile, debug)
@@ -122,9 +95,6 @@ module XCPretty
122
95
  # $1 = script_name
123
96
  PHASE_SCRIPT_EXECUTION_MATCHER = /^PhaseScriptExecution\s(.*)\s\//
124
97
 
125
- # @regex Captured groups
126
- PODS_ERROR_MATCHER = /^error:\s(.*)/
127
-
128
98
  # @regex Captured groups
129
99
  # $1 = file
130
100
  PROCESS_PCH_MATCHER = /^ProcessPCH\s.*\s(.*.pch)/
@@ -141,10 +111,6 @@ module XCPretty
141
111
  # $1 = file
142
112
  PROCESS_INFO_PLIST_MATCHER = /^ProcessInfoPlistFile\s.*\.plist\s(.*\/+(.*\.plist))/
143
113
 
144
- # @regex Captured groups
145
- # $1 = reference
146
- SYMBOL_REFERENCED_FROM_MATCHER = /\s+"(.*)", referenced from:$/
147
-
148
114
  # @regex Captured groups
149
115
  # $1 = suite
150
116
  # $2 = time
@@ -167,11 +133,65 @@ module XCPretty
167
133
  # $1 file_path
168
134
  # $2 file_name
169
135
  TOUCH_MATCHER = /^Touch\s(.*\/([\w+\.]+))/
136
+
137
+ module Errors
138
+ # @regex Captured groups
139
+ # $1 = whole error
140
+ CLANG_ERROR_MATCHER = /^(clang: error:.*)$/
141
+
142
+ # @regex Captured groups
143
+ # $1 = whole error
144
+ CODESIGN_ERROR_MATCHER = /^(Code\s?Sign error:.*)$/
145
+
146
+ # @regex Captured groups
147
+ # $1 = file_path
148
+ # $2 = file_name
149
+ # $3 = reason
150
+ COMPILE_ERROR_MATCHER = /^(\/.+\/(.*):.*:.*):(?:\sfatal)?\serror:\s(.*)$/
151
+
152
+ # @regex Captured groups
153
+ # $1 cursor (with whitespaces and tildes)
154
+ CURSOR_MATCHER = /^([\s~]*\^[\s~]*)$/
155
+
156
+ # @regex Captured groups
157
+ # $1 = whole error.
158
+ # it varies a lot, not sure if it makes sense to catch everything separately
159
+ FATAL_ERROR_MATCHER = /^(fatal error:.*)$/
160
+
161
+ # @regex Captured groups
162
+ # $1 = whole error
163
+ LD_ERROR_MATCHER = /^(ld:.*not found for.*)/
164
+
165
+ # @regex Captured groups
166
+ # $1 file path
167
+ LINKER_DUPLICATE_SYMBOLS_LOCATION_MATCHER = /^\s+(\/.*\.o[\)]?)$/
168
+
169
+ # @regex Captured groups
170
+ # $1 reason
171
+ LINKER_DUPLICATE_SYMBOLS_MATCHER = /^(duplicate symbol .*):$/
172
+
173
+ # @regex Captured groups
174
+ # $1 symbol location
175
+ LINKER_UNDEFINED_SYMBOL_LOCATION_MATCHER = /^(.* in .*\.o)$/
176
+
177
+ # @regex Captured groups
178
+ # $1 reason
179
+ LINKER_UNDEFINED_SYMBOLS_MATCHER = /^(Undefined symbols for architecture .*):$/
180
+
181
+ # @regex Captured groups
182
+ PODS_ERROR_MATCHER = /^error:\s(.*)/
183
+
184
+ # @regex Captured groups
185
+ # $1 = reference
186
+ SYMBOL_REFERENCED_FROM_MATCHER = /\s+"(.*)", referenced from:$/
187
+ end
170
188
  end
171
189
 
172
190
  class Parser
173
191
 
174
192
  include Matchers
193
+ include Matchers::Errors
194
+
175
195
  attr_reader :formatter
176
196
 
177
197
  def initialize(formatter)
@@ -184,7 +204,8 @@ module XCPretty
184
204
  update_linker_failure_state(text)
185
205
 
186
206
  return format_compile_error if should_format_error?
187
- return format_linker_failure if should_format_linker_failure?
207
+ return format_undefined_symbols if should_format_undefined_symbols?
208
+ return format_duplicate_symbols if should_format_duplicate_symbols?
188
209
 
189
210
  case text
190
211
  when ANALYZE_MATCHER
@@ -209,6 +230,8 @@ module XCPretty
209
230
  formatter.format_error($1)
210
231
  when COMPILE_MATCHER
211
232
  formatter.format_compile($2, $1)
233
+ when COMPILE_COMMAND_MATCHER
234
+ formatter.format_compile_command($1)
212
235
  when COMPILE_XIB_MATCHER
213
236
  formatter.format_compile_xib($2, $1)
214
237
  when CPRESOURCE_MATCHER
@@ -289,14 +312,21 @@ module XCPretty
289
312
  end
290
313
 
291
314
  def update_linker_failure_state(text)
292
- if text =~ LINKER_FAILURE_MATCHER
293
- @formatting_linker_error = true
315
+ if text =~ LINKER_UNDEFINED_SYMBOLS_MATCHER ||
316
+ text =~ LINKER_DUPLICATE_SYMBOLS_MATCHER
317
+
294
318
  current_linker_failure[:message] = $1
295
- elsif text =~ SYMBOL_REFERENCED_FROM_MATCHER
319
+ @formatting_linker_failure = true
320
+ end
321
+ return unless @formatting_linker_failure
322
+
323
+ case text
324
+ when SYMBOL_REFERENCED_FROM_MATCHER
296
325
  current_linker_failure[:symbol] = $1
297
- elsif @formatting_linker_error
326
+ when LINKER_UNDEFINED_SYMBOL_LOCATION_MATCHER
298
327
  current_linker_failure[:reference] = text.strip
299
- @formatting_linker_error = false
328
+ when LINKER_DUPLICATE_SYMBOLS_LOCATION_MATCHER
329
+ current_linker_failure[:files] << $1
300
330
  end
301
331
  end
302
332
 
@@ -305,18 +335,23 @@ module XCPretty
305
335
  current_error[:reason] && current_error[:cursor] && current_error[:line]
306
336
  end
307
337
 
308
- def should_format_linker_failure?
338
+ def should_format_undefined_symbols?
309
339
  current_linker_failure[:message] &&
310
340
  current_linker_failure[:symbol] &&
311
341
  current_linker_failure[:reference]
312
342
  end
313
343
 
344
+ def should_format_duplicate_symbols?
345
+ current_linker_failure[:message] &&
346
+ current_linker_failure[:files].count > 1
347
+ end
348
+
314
349
  def current_error
315
350
  @current_error ||= {}
316
351
  end
317
352
 
318
353
  def current_linker_failure
319
- @linker_failure ||= {}
354
+ @linker_failure ||= { :files => [] }
320
355
  end
321
356
 
322
357
  def format_compile_error
@@ -329,12 +364,28 @@ module XCPretty
329
364
  error[:cursor])
330
365
  end
331
366
 
332
- def format_linker_failure
333
- failure = current_linker_failure.dup
334
- @linker_failure = {}
335
- formatter.format_linker_failure(failure[:message],
336
- failure[:symbol],
337
- failure[:reference])
367
+ def format_undefined_symbols
368
+ result = formatter.format_undefined_symbols(
369
+ current_linker_failure[:message],
370
+ current_linker_failure[:symbol],
371
+ current_linker_failure[:reference]
372
+ )
373
+ reset_linker_format_state
374
+ result
375
+ end
376
+
377
+ def format_duplicate_symbols
378
+ result = formatter.format_duplicate_symbols(
379
+ current_linker_failure[:message],
380
+ current_linker_failure[:files]
381
+ )
382
+ reset_linker_format_state
383
+ result
384
+ end
385
+
386
+ def reset_linker_format_state
387
+ @linker_failure = nil
388
+ @formatting_linker_failure = false
338
389
  end
339
390
 
340
391
  def store_failure(file, test_suite, test_case, reason)
@@ -0,0 +1,58 @@
1
+ module XCPretty
2
+ class JSONCompilationDatabase
3
+
4
+ include XCPretty::FormatMethods
5
+ FILEPATH = 'build/reports/compilation_db.json'
6
+
7
+ def load_dependencies
8
+ unless @@loaded ||= false
9
+ require 'fileutils'
10
+ require 'pathname'
11
+ unless Object.const_defined?(:JSON)
12
+ begin
13
+ require 'json'
14
+ rescue LoadError
15
+ require File.expand_path(File.join(File.dirname(__FILE__),'../../../vendor/json_pure/generator'))
16
+ end
17
+ end
18
+ @@loaded = true
19
+ end
20
+ end
21
+
22
+ def initialize(options)
23
+ load_dependencies
24
+ @filepath = options[:path] || FILEPATH
25
+ @parser = Parser.new(self)
26
+ @compilation_units = []
27
+ @current_file = nil
28
+ @current_path = nil
29
+ end
30
+
31
+ def handle(line)
32
+ @parser.parse(line)
33
+ end
34
+
35
+ def format_compile(file_name, file_path)
36
+ @current_file = file_name
37
+ @current_path = File.dirname(file_path)
38
+ end
39
+
40
+ def format_compile_command(compiler_command)
41
+ @compilation_units << { :command => compiler_command,
42
+ :file => @current_file, :directory => @current_path }
43
+ end
44
+
45
+ def finish
46
+ FileUtils.mkdir_p(File.dirname(@filepath))
47
+ write_report
48
+ end
49
+
50
+ private
51
+
52
+ def write_report
53
+ File.open(@filepath, 'w') do |f|
54
+ f.write(@compilation_units.to_json)
55
+ end
56
+ end
57
+ end
58
+ end