xcpretty 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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