xcodebuild-rb 0.1.0
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.
- data/LICENSE +19 -0
- data/README.md +59 -0
- data/bin/rbxcb +3 -0
- data/lib/xcode_build.rb +27 -0
- data/lib/xcode_build/build_action.rb +72 -0
- data/lib/xcode_build/build_step.rb +47 -0
- data/lib/xcode_build/formatters.rb +6 -0
- data/lib/xcode_build/formatters/progress_formatter.rb +99 -0
- data/lib/xcode_build/output_translator.rb +82 -0
- data/lib/xcode_build/reporter.rb +22 -0
- data/lib/xcode_build/reporting/build_reporting.rb +61 -0
- data/lib/xcode_build/reporting/clean_reporting.rb +59 -0
- data/lib/xcode_build/tasks/build_task.rb +84 -0
- data/lib/xcode_build/translations.rb +20 -0
- data/lib/xcode_build/translations/building.rb +101 -0
- data/lib/xcode_build/translations/cleaning.rb +96 -0
- data/lib/xcode_build/utilities/colorize.rb +45 -0
- data/lib/xcodebuild.rb +1 -0
- data/spec/build_task_spec.rb +142 -0
- data/spec/output_translator_spec.rb +52 -0
- data/spec/reporting/build_reporting_spec.rb +305 -0
- data/spec/reporting/clean_reporting_spec.rb +276 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/translations/building_translations_spec.rb +167 -0
- data/spec/translations/cleaning_translations_spec.rb +144 -0
- metadata +164 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module XcodeBuild
|
4
|
+
module Reporting
|
5
|
+
module BuildReporting
|
6
|
+
def self.included(klass)
|
7
|
+
klass.instance_eval do
|
8
|
+
attr_reader :build
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_started(params)
|
13
|
+
@build = Build.new(params)
|
14
|
+
notify :build_started, @build
|
15
|
+
end
|
16
|
+
|
17
|
+
def build_step(params)
|
18
|
+
if @build.last_step
|
19
|
+
notify :build_step_finished, @build.last_step
|
20
|
+
end
|
21
|
+
|
22
|
+
@build.add_step(params)
|
23
|
+
|
24
|
+
notify :build_step_started, @build.last_step
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_error_detected(params)
|
28
|
+
@build.last_step.add_error(params)
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_succeeded
|
32
|
+
@build.success!
|
33
|
+
build_finished
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_failed
|
37
|
+
@build.failure!
|
38
|
+
build_finished
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_step_failed(params)
|
42
|
+
if step = @build.step_with_params(params)
|
43
|
+
step.failed = true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def build_finished
|
50
|
+
if @build.last_step
|
51
|
+
notify :build_step_finished, @build.last_step
|
52
|
+
end
|
53
|
+
|
54
|
+
notify :build_finished, @build
|
55
|
+
end
|
56
|
+
|
57
|
+
class Build < BuildAction
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module XcodeBuild
|
2
|
+
module Reporting
|
3
|
+
module CleanReporting
|
4
|
+
def self.included(klass)
|
5
|
+
klass.instance_eval do
|
6
|
+
attr_reader :clean
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def clean_started(params)
|
11
|
+
@clean = Clean.new(params)
|
12
|
+
notify :clean_started, @clean
|
13
|
+
end
|
14
|
+
|
15
|
+
def clean_step(params)
|
16
|
+
if clean.last_step
|
17
|
+
notify :clean_step_finished, clean.last_step
|
18
|
+
end
|
19
|
+
|
20
|
+
clean.add_step(params)
|
21
|
+
|
22
|
+
notify :clean_step_started, clean.last_step
|
23
|
+
end
|
24
|
+
|
25
|
+
def clean_error_detected(params)
|
26
|
+
clean.last_step.add_error(params)
|
27
|
+
end
|
28
|
+
|
29
|
+
def clean_succeeded
|
30
|
+
clean.success!
|
31
|
+
clean_finished
|
32
|
+
end
|
33
|
+
|
34
|
+
def clean_failed
|
35
|
+
clean.failure!
|
36
|
+
clean_finished
|
37
|
+
end
|
38
|
+
|
39
|
+
def clean_step_failed(params)
|
40
|
+
if step = clean.step_with_params(params)
|
41
|
+
step.failed = true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def clean_finished
|
48
|
+
if clean.last_step
|
49
|
+
notify :clean_step_finished, clean.last_step
|
50
|
+
end
|
51
|
+
|
52
|
+
notify :clean_finished, clean
|
53
|
+
end
|
54
|
+
|
55
|
+
class Clean < BuildAction
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'rake/tasklib'
|
2
|
+
|
3
|
+
module XcodeBuild
|
4
|
+
module Tasks
|
5
|
+
class BuildTask < ::Rake::TaskLib
|
6
|
+
attr_accessor :project_name
|
7
|
+
attr_accessor :target
|
8
|
+
attr_accessor :workspace
|
9
|
+
attr_accessor :scheme
|
10
|
+
attr_accessor :configuration
|
11
|
+
attr_accessor :arch
|
12
|
+
attr_accessor :sdk
|
13
|
+
attr_accessor :xcconfig
|
14
|
+
attr_accessor :output_to
|
15
|
+
attr_accessor :formatter
|
16
|
+
attr_accessor :invoke_from_within
|
17
|
+
attr_accessor :reporter
|
18
|
+
|
19
|
+
def initialize(namespace = :xcode, &block)
|
20
|
+
@namespace = namespace
|
21
|
+
@output_to = STDOUT
|
22
|
+
@invoke_from_within = "."
|
23
|
+
|
24
|
+
yield self if block_given?
|
25
|
+
define
|
26
|
+
end
|
27
|
+
|
28
|
+
def run(task)
|
29
|
+
Rake::Task["#{@namespace}:#{task}"].invoke
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_opts
|
33
|
+
[].tap do |opts|
|
34
|
+
opts << "-project #{project_name}" if project_name
|
35
|
+
opts << "-target #{target}" if target
|
36
|
+
opts << "-workspace #{workspace}" if workspace
|
37
|
+
opts << "-scheme #{scheme}" if scheme
|
38
|
+
opts << "-configuration #{configuration}" if configuration
|
39
|
+
opts << "-arch #{arch}" if arch
|
40
|
+
opts << "-sdk #{sdk}" if sdk
|
41
|
+
opts << "-xcconfig #{xcconfig}" if xcconfig
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def output_buffer
|
48
|
+
if reporter
|
49
|
+
XcodeBuild::OutputTranslator.new(reporter)
|
50
|
+
elsif formatter
|
51
|
+
default_reporter = XcodeBuild::Reporter.new(formatter)
|
52
|
+
XcodeBuild::OutputTranslator.new(default_reporter)
|
53
|
+
else
|
54
|
+
output_to
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def build_opts_string(*additional_opts)
|
59
|
+
(build_opts + additional_opts).join(" ")
|
60
|
+
end
|
61
|
+
|
62
|
+
def define
|
63
|
+
namespace(@namespace) do
|
64
|
+
desc "Builds the specified target(s)."
|
65
|
+
task :build do
|
66
|
+
Dir.chdir(invoke_from_within) do
|
67
|
+
XcodeBuild.run(build_opts_string, output_buffer)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "Cleans the build using the same build settings."
|
72
|
+
task :clean do
|
73
|
+
Dir.chdir(invoke_from_within) do
|
74
|
+
XcodeBuild.run(build_opts_string("clean"), output_buffer)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
desc "Builds the specified target(s) from a clean slate."
|
79
|
+
task :cleanbuild => [:clean, :build]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module XcodeBuild
|
2
|
+
module Translations
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def registered_translations
|
6
|
+
@registered_translators ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def register_translation(key, the_module)
|
10
|
+
registered_translations[key] = the_module
|
11
|
+
end
|
12
|
+
|
13
|
+
def registered_translation(key)
|
14
|
+
registered_translations[key]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require_relative "translations/building"
|
20
|
+
require_relative "translations/cleaning"
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module XcodeBuild
|
2
|
+
module Translations
|
3
|
+
module Building
|
4
|
+
def attempt_to_translate(line)
|
5
|
+
if line =~ /^\=\=\= BUILD/
|
6
|
+
notify_build_started(line)
|
7
|
+
end
|
8
|
+
|
9
|
+
return unless building?
|
10
|
+
|
11
|
+
if line =~ /^\*\* BUILD (\w+) \*\*/
|
12
|
+
notify_build_ended($1)
|
13
|
+
return
|
14
|
+
end
|
15
|
+
|
16
|
+
if @beginning_build_step
|
17
|
+
@beginning_build_step = false
|
18
|
+
notify_build_step(line) unless line.strip.empty?
|
19
|
+
return
|
20
|
+
end
|
21
|
+
|
22
|
+
if @beginning_error_report
|
23
|
+
if line =~ /^\(\d+ failure(s?)\)/
|
24
|
+
@beginning_error_report = false
|
25
|
+
else
|
26
|
+
notify_build_step_failed(line)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
case line
|
31
|
+
when /^(.*):(\d+):(\d+): error: (.*)$/
|
32
|
+
notify_build_error($1, $2, $3, $4)
|
33
|
+
when /^The following build commands failed:/
|
34
|
+
@beginning_error_report = true
|
35
|
+
when /^\n/
|
36
|
+
@beginning_build_step = true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def building?
|
41
|
+
@building
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def notify_build_started(line)
|
47
|
+
@building = true
|
48
|
+
|
49
|
+
target = line.match(/TARGET (\w+)/)[1]
|
50
|
+
project = line.match(/PROJECT (\w+)/)[1]
|
51
|
+
|
52
|
+
if line =~ /DEFAULT CONFIGURATION \((\w+)\)/
|
53
|
+
configuration = $1
|
54
|
+
default = true
|
55
|
+
else
|
56
|
+
configuration = line.match(/CONFIGURATION (\w+)/)[1]
|
57
|
+
default = false
|
58
|
+
end
|
59
|
+
|
60
|
+
notify_delegate(:build_started, required: true, args: [{
|
61
|
+
target: target,
|
62
|
+
project: project,
|
63
|
+
configuration: configuration,
|
64
|
+
default: default
|
65
|
+
}])
|
66
|
+
end
|
67
|
+
|
68
|
+
def notify_build_step(line)
|
69
|
+
notify_delegate(:build_step, args: [build_step_from_line(line)])
|
70
|
+
end
|
71
|
+
|
72
|
+
def notify_build_error(file, line, char, message)
|
73
|
+
notify_delegate(:build_error_detected, args: [{
|
74
|
+
file: file,
|
75
|
+
line: line.to_i,
|
76
|
+
char: char.to_i,
|
77
|
+
message: message
|
78
|
+
}])
|
79
|
+
end
|
80
|
+
|
81
|
+
def notify_build_ended(result)
|
82
|
+
if result =~ /SUCCEEDED/
|
83
|
+
notify_delegate(:build_succeeded, required: true)
|
84
|
+
else
|
85
|
+
notify_delegate(:build_failed, required: true)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def notify_build_step_failed(line)
|
90
|
+
notify_delegate(:build_step_failed, args: [build_step_from_line(line)])
|
91
|
+
end
|
92
|
+
|
93
|
+
def build_step_from_line(line)
|
94
|
+
parts = line.strip.split(" ")
|
95
|
+
{type: parts.shift, arguments: parts}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
register_translation :building, Building
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module XcodeBuild
|
2
|
+
module Translations
|
3
|
+
module Cleaning
|
4
|
+
def attempt_to_translate(line)
|
5
|
+
if line =~ /^\=\=\= CLEAN/
|
6
|
+
notify_clean_started(line)
|
7
|
+
end
|
8
|
+
|
9
|
+
return unless cleaning?
|
10
|
+
|
11
|
+
if line =~ /^\*\* CLEAN (\w+) \*\*/
|
12
|
+
notify_clean_ended($1)
|
13
|
+
return
|
14
|
+
end
|
15
|
+
|
16
|
+
if @beginning_clean_step
|
17
|
+
@beginning_clean_step = false
|
18
|
+
notify_clean_step(line) unless line.strip.empty?
|
19
|
+
return
|
20
|
+
end
|
21
|
+
|
22
|
+
if @beginning_error_report
|
23
|
+
if line =~ /^\(\d+ failure(s?)\)/
|
24
|
+
@beginning_error_report = false
|
25
|
+
else
|
26
|
+
notify_clean_step_failed(line)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
case line
|
31
|
+
when /^error: (.*)$/
|
32
|
+
notify_clean_error($1)
|
33
|
+
when /^The following build commands failed:/
|
34
|
+
@beginning_error_report = true
|
35
|
+
when /^\n/
|
36
|
+
@beginning_clean_step = true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def cleaning?
|
43
|
+
@cleaning
|
44
|
+
end
|
45
|
+
|
46
|
+
def notify_clean_started(line)
|
47
|
+
@cleaning = true
|
48
|
+
|
49
|
+
target = line.match(/TARGET (\w+)/)[1]
|
50
|
+
project = line.match(/PROJECT (\w+)/)[1]
|
51
|
+
|
52
|
+
if line =~ /DEFAULT CONFIGURATION \((\w+)\)/
|
53
|
+
configuration = $1
|
54
|
+
default = true
|
55
|
+
else
|
56
|
+
configuration = line.match(/CONFIGURATION (\w+)/)[1]
|
57
|
+
default = false
|
58
|
+
end
|
59
|
+
|
60
|
+
notify_delegate(:clean_started, required: true, args: [{
|
61
|
+
target: target,
|
62
|
+
project: project,
|
63
|
+
configuration: configuration,
|
64
|
+
default: default
|
65
|
+
}])
|
66
|
+
end
|
67
|
+
|
68
|
+
def notify_clean_step(line)
|
69
|
+
notify_delegate(:clean_step, args: [clean_step_from_line(line)])
|
70
|
+
end
|
71
|
+
|
72
|
+
def notify_clean_step_failed(line)
|
73
|
+
notify_delegate(:clean_step_failed, args: [clean_step_from_line(line)])
|
74
|
+
end
|
75
|
+
|
76
|
+
def notify_clean_error(message)
|
77
|
+
notify_delegate(:clean_error_detected, args: [{message: message}])
|
78
|
+
end
|
79
|
+
|
80
|
+
def notify_clean_ended(result)
|
81
|
+
if result =~ /SUCCEEDED/
|
82
|
+
notify_delegate(:clean_succeeded, required: true)
|
83
|
+
else
|
84
|
+
notify_delegate(:clean_failed, required: true)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def clean_step_from_line(line)
|
89
|
+
parts = line.strip.split(" ")
|
90
|
+
{type: parts.shift, arguments: parts}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
register_translation :cleaning, Cleaning
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module XcodeBuild
|
2
|
+
module Utilities
|
3
|
+
module Colorize # borrowed from rspec-core
|
4
|
+
def color(text, color_code)
|
5
|
+
color_enabled? ? "#{color_code}#{text}\e[0m" : text
|
6
|
+
end
|
7
|
+
|
8
|
+
def bold(text)
|
9
|
+
color(text, "\e[1m")
|
10
|
+
end
|
11
|
+
|
12
|
+
def red(text)
|
13
|
+
color(text, "\e[31m")
|
14
|
+
end
|
15
|
+
|
16
|
+
def green(text)
|
17
|
+
color(text, "\e[32m")
|
18
|
+
end
|
19
|
+
|
20
|
+
def yellow(text)
|
21
|
+
color(text, "\e[33m")
|
22
|
+
end
|
23
|
+
|
24
|
+
def blue(text)
|
25
|
+
color(text, "\e[34m")
|
26
|
+
end
|
27
|
+
|
28
|
+
def magenta(text)
|
29
|
+
color(text, "\e[35m")
|
30
|
+
end
|
31
|
+
|
32
|
+
def cyan(text)
|
33
|
+
color(text, "\e[36m")
|
34
|
+
end
|
35
|
+
|
36
|
+
def white(text)
|
37
|
+
color(text, "\e[37m")
|
38
|
+
end
|
39
|
+
|
40
|
+
def short_padding
|
41
|
+
' '
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|