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 +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
|
-
[![
|
7
|
-
[![
|
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
|
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"
|
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
|