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 +4 -4
- data/.travis.yml +3 -0
- data/CHANGELOG.md +33 -0
- data/README.md +11 -4
- data/bin/xcpretty +3 -2
- data/features/json_compilation_database_report.feature +21 -0
- data/features/junit_report.feature +5 -0
- data/features/steps/json_steps.rb +37 -0
- data/features/steps/junit_steps.rb +6 -0
- data/features/support/env.rb +14 -0
- data/lib/xcpretty/formatters/formatter.rb +44 -34
- data/lib/xcpretty/parser.rb +101 -50
- data/lib/xcpretty/reporters/json_compilation_database.rb +58 -0
- data/lib/xcpretty/reporters/junit.rb +12 -1
- data/lib/xcpretty/version.rb +1 -1
- data/lib/xcpretty.rb +1 -0
- data/spec/fixtures/constants.rb +8 -0
- data/spec/support/matchers/colors.rb +2 -0
- data/spec/xcpretty/formatters/formatter_spec.rb +15 -4
- data/spec/xcpretty/parser_spec.rb +24 -4
- data/vendor/json_pure/COPYING +57 -0
- data/vendor/json_pure/LICENSE +340 -0
- data/vendor/json_pure/generator.rb +443 -0
- data/vendor/json_pure/parser.rb +364 -0
- metadata +25 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1a03b19be84f708774b6c76d7b89cac3231eed1
|
4
|
+
data.tar.gz: 282c28b193dd9f9e92e83e46f38e86481c3f8432
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ac22b284e55a4397cb190a9406e4fc4992ab79ebb2b1a25b1210361f5bacbebdd26e269228ccdbb2cd3856bea055314c66f52f78bf213ae2c34d0110aa21230
|
7
|
+
data.tar.gz: 63fb8efd9849d07ad752efad960bfdadab4a67e4d741600fe62a70a92f3e97b4e3b5bf725b7ad2d06ebb85612dcd155dae8eef4d77c961b5f14b494b66de4116
|
data/.travis.yml
CHANGED
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
|
-
[](http://rubygems.org/gems/xcpretty)
|
7
|
+
[](https://travis-ci.org/supermarin/xcpretty)
|
8
|
+
[](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
|
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
|

|
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"
|
17
|
-
"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
|
data/features/support/env.rb
CHANGED
@@ -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);
|
13
|
-
def format_build_target(target, project, configuration);
|
14
|
-
def format_check_dependencies;
|
15
|
-
def format_clean(project, target, configuration);
|
16
|
-
def format_clean_target(target, project, configuration);
|
17
|
-
def format_clean_remove;
|
18
|
-
def format_compile(file_name, file_path);
|
19
|
-
def
|
20
|
-
def
|
21
|
-
def
|
22
|
-
def
|
23
|
-
def
|
24
|
-
def
|
25
|
-
def
|
26
|
-
def
|
27
|
-
def
|
28
|
-
def
|
29
|
-
def
|
30
|
-
def
|
31
|
-
def
|
32
|
-
def
|
33
|
-
def
|
34
|
-
def
|
35
|
-
def
|
36
|
-
def
|
37
|
-
def
|
38
|
-
def
|
39
|
-
def
|
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);
|
44
|
-
def format_error(message);
|
45
|
-
def
|
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
|
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
|
96
|
-
"\n#{red(error_symbol + " " + message)}\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
|
|
data/lib/xcpretty/parser.rb
CHANGED
@@ -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
|
51
|
-
|
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
|
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 =~
|
293
|
-
|
315
|
+
if text =~ LINKER_UNDEFINED_SYMBOLS_MATCHER ||
|
316
|
+
text =~ LINKER_DUPLICATE_SYMBOLS_MATCHER
|
317
|
+
|
294
318
|
current_linker_failure[:message] = $1
|
295
|
-
|
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
|
-
|
326
|
+
when LINKER_UNDEFINED_SYMBOL_LOCATION_MATCHER
|
298
327
|
current_linker_failure[:reference] = text.strip
|
299
|
-
|
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
|
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
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
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
|