xcodebuild-rb 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.md +11 -0
- data/README.md +4 -2
- data/bin/rbxcb +7 -1
- data/lib/xcode_build.rb +8 -5
- data/lib/xcode_build/build_action.rb +10 -2
- data/lib/xcode_build/build_step.rb +8 -0
- data/lib/xcode_build/formatters.rb +1 -1
- data/lib/xcode_build/formatters/progress_formatter.rb +14 -10
- data/lib/xcode_build/output_translator.rb +4 -3
- data/lib/xcode_build/reporter.rb +10 -2
- data/lib/xcode_build/reporting/build_reporting.rb +43 -14
- data/lib/xcode_build/reporting/clean_reporting.rb +5 -1
- data/lib/xcode_build/tasks.rb +6 -0
- data/lib/xcode_build/tasks/build_task.rb +66 -16
- data/lib/xcode_build/translations.rb +2 -2
- data/lib/xcode_build/translations/building.rb +30 -18
- data/lib/xcode_build/translations/cleaning.rb +11 -11
- data/lib/xcodebuild.rb +1 -1
- data/spec/build_task_spec.rb +147 -39
- data/spec/output_translator_spec.rb +1 -1
- data/spec/reporting/build_reporting_spec.rb +61 -8
- data/spec/translations/building_translations_spec.rb +48 -32
- data/spec/translations/cleaning_translations_spec.rb +18 -18
- metadata +22 -19
data/CHANGES.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# xcodebuild-rb changes
|
2
|
+
|
3
|
+
## 0.2.0
|
4
|
+
* Added archive task
|
5
|
+
* Support Ruby 1.8.7
|
6
|
+
* Added after_(build|clean|archive) hooks for rake tasks
|
7
|
+
* Support capturing environment variables when a Run Script Phase with 'Show Environment Variables' is added.
|
8
|
+
* Ensure rake tasks exit with an appropriate exit code when the builds fail.
|
9
|
+
|
10
|
+
## 0.1.0
|
11
|
+
* Initial release.
|
data/README.md
CHANGED
@@ -15,7 +15,7 @@ After installing the gem, you need to create a `Rakefile` in the root of your pr
|
|
15
15
|
A simple Rakefile will look like this:
|
16
16
|
|
17
17
|
require 'rubygems'
|
18
|
-
require 'xcodebuild
|
18
|
+
require 'xcodebuild'
|
19
19
|
|
20
20
|
XcodeBuild::Tasks::BuildTask.new
|
21
21
|
|
@@ -35,6 +35,8 @@ When you run `rake xcode:build`, `xcodebuild` will be invoked without any argume
|
|
35
35
|
t.configuration = "Release"
|
36
36
|
end
|
37
37
|
|
38
|
+
_Note that in order to be able to use the `xcode:archive` task, a scheme **has** to be provided_
|
39
|
+
|
38
40
|
When you run the rake tasks provided, the default behaviour is to simply output the exact output from `xcodebuild`. However, `xcodebuild-rb` can go one better and allow you to configure custom formatters that change the way the build output is displayed. Some formatters are built-in, or you can write your own.
|
39
41
|
|
40
42
|
For instance, we could use the "progress" formatter that ships with `xcodebuild-rb`. Anybody who is used to the output of Ruby's Test::Unit library or RSpec library will be familiar with this.
|
@@ -56,4 +58,4 @@ Now when you run your build, your output will look something like this:
|
|
56
58
|
|
57
59
|
## License
|
58
60
|
|
59
|
-
This library is licensed under the [MIT license](http://en.wikipedia.org/wiki/MIT_License).
|
61
|
+
This library is licensed under the [MIT license](http://en.wikipedia.org/wiki/MIT_License).
|
data/bin/rbxcb
CHANGED
data/lib/xcode_build.rb
CHANGED
@@ -13,14 +13,17 @@ module XcodeBuild
|
|
13
13
|
rescue EOFError
|
14
14
|
end
|
15
15
|
end
|
16
|
+
|
17
|
+
$?.exitstatus
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
require 'xcode_build/build_action'
|
22
|
+
require 'xcode_build/build_step'
|
23
|
+
require 'xcode_build/output_translator'
|
24
|
+
require 'xcode_build/reporter'
|
25
|
+
require 'xcode_build/formatters'
|
26
|
+
require 'xcode_build/tasks'
|
24
27
|
|
25
28
|
# configure the default translations for general use
|
26
29
|
XcodeBuild::OutputTranslator.use_translation(:building)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'state_machine'
|
2
2
|
|
3
|
-
|
3
|
+
require "xcode_build/build_step"
|
4
4
|
|
5
5
|
module XcodeBuild
|
6
6
|
class BuildAction
|
@@ -47,11 +47,19 @@ module XcodeBuild
|
|
47
47
|
def finished?
|
48
48
|
successful? || failed?
|
49
49
|
end
|
50
|
+
|
51
|
+
def has_errors?
|
52
|
+
failed_steps.any?
|
53
|
+
end
|
50
54
|
|
51
55
|
def duration
|
52
56
|
return nil unless finished?
|
53
57
|
@finished_at - @started_at
|
54
58
|
end
|
59
|
+
|
60
|
+
def label
|
61
|
+
@label.downcase.capitalize
|
62
|
+
end
|
55
63
|
|
56
64
|
def project_name
|
57
65
|
@metadata[:project]
|
@@ -69,4 +77,4 @@ module XcodeBuild
|
|
69
77
|
@metadata[:default]
|
70
78
|
end
|
71
79
|
end
|
72
|
-
end
|
80
|
+
end
|
@@ -11,6 +11,7 @@ module XcodeBuild
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def add_error(params)
|
14
|
+
@failed = true
|
14
15
|
@errors << Error.new(params)
|
15
16
|
end
|
16
17
|
|
@@ -42,6 +43,13 @@ module XcodeBuild
|
|
42
43
|
private
|
43
44
|
|
44
45
|
class Error < OpenStruct
|
46
|
+
def error_detail
|
47
|
+
if self.file
|
48
|
+
"in #{err.file}:#{err.line.to_s}"
|
49
|
+
elsif self.command
|
50
|
+
"#{self.command} failed with exit code #{self.exit_code}"
|
51
|
+
end
|
52
|
+
end
|
45
53
|
end
|
46
54
|
end
|
47
55
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
|
2
|
+
require 'xcode_build/utilities/colorize'
|
3
3
|
|
4
4
|
module XcodeBuild
|
5
5
|
module Formatters
|
@@ -19,7 +19,7 @@ module XcodeBuild
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def clean_finished(clean)
|
22
|
-
report_finished(
|
22
|
+
report_finished(clean)
|
23
23
|
end
|
24
24
|
|
25
25
|
def build_started(build)
|
@@ -31,30 +31,34 @@ module XcodeBuild
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def build_finished(build)
|
34
|
-
report_finished(
|
34
|
+
report_finished(build)
|
35
35
|
end
|
36
36
|
|
37
|
-
def report_finished(
|
37
|
+
def report_finished(object)
|
38
38
|
puts
|
39
39
|
puts
|
40
40
|
puts "Finished in #{object.duration} seconds."
|
41
41
|
|
42
42
|
if object.successful?
|
43
|
-
puts green("#{
|
43
|
+
puts green("#{object.label} succeeded.")
|
44
44
|
else
|
45
|
-
puts red("#{
|
45
|
+
puts red("#{object.label} failed.")
|
46
46
|
puts
|
47
|
-
puts "Failed #{
|
47
|
+
puts "Failed #{object.label.downcase} steps:"
|
48
48
|
puts
|
49
49
|
error_counter = 1
|
50
50
|
object.steps_completed.each do |step|
|
51
51
|
next unless step.has_errors?
|
52
|
-
|
52
|
+
|
53
53
|
puts indent("#{error_counter}) #{step.type} #{step.arguments.join(" ")}")
|
54
54
|
|
55
55
|
step.errors.each do |err|
|
56
|
-
|
57
|
-
|
56
|
+
print indent(" #{red(err.message)}")
|
57
|
+
if err.error_detail
|
58
|
+
puts indent(cyan(err.error_detail))
|
59
|
+
else
|
60
|
+
puts
|
61
|
+
end
|
58
62
|
puts
|
59
63
|
end
|
60
64
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
|
2
|
+
require 'xcode_build/translations'
|
3
3
|
|
4
4
|
module XcodeBuild
|
5
5
|
class OutputTranslator
|
@@ -13,7 +13,7 @@ module XcodeBuild
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def <<(line)
|
16
|
-
notify_delegate(:beginning_translation_of_line, args
|
16
|
+
notify_delegate(:beginning_translation_of_line, :args => line)
|
17
17
|
translations.each { |translation| translation.attempt_to_translate(line) }
|
18
18
|
end
|
19
19
|
|
@@ -56,7 +56,8 @@ module XcodeBuild
|
|
56
56
|
private
|
57
57
|
|
58
58
|
module TranslationHelpers
|
59
|
-
def notify_delegate(message, options = {
|
59
|
+
def notify_delegate(message, options = {})
|
60
|
+
options[:args] ||= []
|
60
61
|
if @delegate.respond_to?(message)
|
61
62
|
@delegate.send(message, *options[:args])
|
62
63
|
else
|
data/lib/xcode_build/reporter.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require "xcode_build/reporting/build_reporting"
|
2
|
+
require "xcode_build/reporting/clean_reporting"
|
3
3
|
|
4
4
|
module XcodeBuild
|
5
5
|
class Reporter
|
@@ -11,6 +11,14 @@ module XcodeBuild
|
|
11
11
|
def initialize(delegate = nil)
|
12
12
|
@delegate = delegate
|
13
13
|
end
|
14
|
+
|
15
|
+
def direct_raw_output_to=(stream)
|
16
|
+
@output_stream = stream
|
17
|
+
end
|
18
|
+
|
19
|
+
def beginning_translation_of_line(line)
|
20
|
+
(@output_stream << line) if @output_stream
|
21
|
+
end
|
14
22
|
|
15
23
|
private
|
16
24
|
|
@@ -11,35 +11,48 @@ module XcodeBuild
|
|
11
11
|
|
12
12
|
def build_started(params)
|
13
13
|
@build = Build.new(params)
|
14
|
-
notify :build_started,
|
14
|
+
notify :build_started, build
|
15
15
|
end
|
16
16
|
|
17
17
|
def build_step(params)
|
18
|
-
if
|
19
|
-
notify :build_step_finished,
|
18
|
+
if build.last_step
|
19
|
+
notify :build_step_finished, build.last_step
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
build.add_step(params)
|
23
23
|
|
24
|
-
notify :build_step_started,
|
24
|
+
notify :build_step_started, build.last_step
|
25
25
|
end
|
26
26
|
|
27
27
|
def build_error_detected(params)
|
28
|
-
|
28
|
+
build.last_step.add_error(params)
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_env_variable_detected(key, value)
|
32
|
+
build.set_environment_variable(key, value)
|
29
33
|
end
|
30
34
|
|
31
|
-
def build_succeeded
|
32
|
-
|
35
|
+
def build_succeeded(archive_or_build)
|
36
|
+
build.label = archive_or_build
|
37
|
+
|
38
|
+
# for some reason, archive reports a success even if there was an error
|
39
|
+
if build.has_errors?
|
40
|
+
build.failure!
|
41
|
+
else
|
42
|
+
build.success!
|
43
|
+
end
|
44
|
+
|
33
45
|
build_finished
|
34
46
|
end
|
35
47
|
|
36
|
-
def build_failed
|
37
|
-
|
48
|
+
def build_failed(archive_or_build)
|
49
|
+
build.label = archive_or_build
|
50
|
+
build.failure!
|
38
51
|
build_finished
|
39
52
|
end
|
40
53
|
|
41
54
|
def build_step_failed(params)
|
42
|
-
if step =
|
55
|
+
if step = build.step_with_params(params)
|
43
56
|
step.failed = true
|
44
57
|
end
|
45
58
|
end
|
@@ -47,14 +60,30 @@ module XcodeBuild
|
|
47
60
|
private
|
48
61
|
|
49
62
|
def build_finished
|
50
|
-
if
|
51
|
-
notify :build_step_finished,
|
63
|
+
if build.last_step
|
64
|
+
notify :build_step_finished, build.last_step
|
52
65
|
end
|
53
66
|
|
54
|
-
notify :build_finished,
|
67
|
+
notify :build_finished, build
|
55
68
|
end
|
56
69
|
|
57
70
|
class Build < BuildAction
|
71
|
+
attr_reader :environment
|
72
|
+
attr_writer :label
|
73
|
+
|
74
|
+
def initialize(metadata)
|
75
|
+
super(metadata)
|
76
|
+
@environment = {}
|
77
|
+
@label = "Build"
|
78
|
+
end
|
79
|
+
|
80
|
+
def set_environment_variable(key, value)
|
81
|
+
@environment[key] = value
|
82
|
+
end
|
83
|
+
|
84
|
+
def target_build_directory
|
85
|
+
@environment["TARGET_BUILD_DIR"]
|
86
|
+
end
|
58
87
|
end
|
59
88
|
end
|
60
89
|
end
|
@@ -9,7 +9,7 @@ module XcodeBuild
|
|
9
9
|
|
10
10
|
def clean_started(params)
|
11
11
|
@clean = Clean.new(params)
|
12
|
-
notify :clean_started,
|
12
|
+
notify :clean_started, clean
|
13
13
|
end
|
14
14
|
|
15
15
|
def clean_step(params)
|
@@ -53,6 +53,10 @@ module XcodeBuild
|
|
53
53
|
end
|
54
54
|
|
55
55
|
class Clean < BuildAction
|
56
|
+
def initialize(metadata)
|
57
|
+
super(metadata)
|
58
|
+
@label = "Clean"
|
59
|
+
end
|
56
60
|
end
|
57
61
|
end
|
58
62
|
end
|
@@ -3,6 +3,8 @@ require 'rake/tasklib'
|
|
3
3
|
module XcodeBuild
|
4
4
|
module Tasks
|
5
5
|
class BuildTask < ::Rake::TaskLib
|
6
|
+
include Rake::DSL if defined?(Rake::DSL)
|
7
|
+
|
6
8
|
attr_accessor :project_name
|
7
9
|
attr_accessor :target
|
8
10
|
attr_accessor :workspace
|
@@ -14,16 +16,36 @@ module XcodeBuild
|
|
14
16
|
attr_accessor :output_to
|
15
17
|
attr_accessor :formatter
|
16
18
|
attr_accessor :invoke_from_within
|
17
|
-
attr_accessor :
|
19
|
+
attr_accessor :reporter_klass
|
18
20
|
|
19
21
|
def initialize(namespace = :xcode, &block)
|
20
22
|
@namespace = namespace
|
21
23
|
@output_to = STDOUT
|
22
24
|
@invoke_from_within = "."
|
25
|
+
@reporter_klass = XcodeBuild::Reporter
|
26
|
+
@hooks = {}
|
23
27
|
|
24
28
|
yield self if block_given?
|
25
29
|
define
|
26
30
|
end
|
31
|
+
|
32
|
+
def after_build(&block)
|
33
|
+
@hooks[:after_build] = block
|
34
|
+
end
|
35
|
+
|
36
|
+
def after_clean(&block)
|
37
|
+
@hooks[:after_clean] = block
|
38
|
+
end
|
39
|
+
|
40
|
+
def after_archive(&block)
|
41
|
+
@hooks[:after_archive] = block
|
42
|
+
end
|
43
|
+
|
44
|
+
def execute_hook(name, *args)
|
45
|
+
if hook = @hooks[name.to_sym]
|
46
|
+
hook.call(*args)
|
47
|
+
end
|
48
|
+
end
|
27
49
|
|
28
50
|
def run(task)
|
29
51
|
Rake::Task["#{@namespace}:#{task}"].invoke
|
@@ -41,44 +63,72 @@ module XcodeBuild
|
|
41
63
|
opts << "-xcconfig #{xcconfig}" if xcconfig
|
42
64
|
end
|
43
65
|
end
|
66
|
+
|
67
|
+
def reporter
|
68
|
+
@reporter ||= @reporter_klass.new(formatter)
|
69
|
+
end
|
44
70
|
|
45
71
|
private
|
46
72
|
|
47
73
|
def output_buffer
|
48
|
-
|
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
|
74
|
+
@output_buffer ||= XcodeBuild::OutputTranslator.new(reporter)
|
56
75
|
end
|
57
76
|
|
58
77
|
def build_opts_string(*additional_opts)
|
59
|
-
(build_opts + additional_opts).join(" ")
|
78
|
+
(build_opts + additional_opts).compact.join(" ")
|
79
|
+
end
|
80
|
+
|
81
|
+
def xcodebuild(action)
|
82
|
+
reporter.direct_raw_output_to = output_to unless formatter
|
83
|
+
|
84
|
+
status = Dir.chdir(invoke_from_within) do
|
85
|
+
XcodeBuild.run(build_opts_string(action), output_buffer)
|
86
|
+
end
|
87
|
+
|
88
|
+
check_status(status)
|
89
|
+
|
90
|
+
if reporter.build && reporter.build.failed?
|
91
|
+
# sometimes, a build/archive can fail and xcodebuild won't return a non-zero code
|
92
|
+
raise "xcodebuild failed (#{reporter.build.failed_steps.length} steps failed)"
|
93
|
+
end
|
94
|
+
|
95
|
+
case action
|
96
|
+
when :build
|
97
|
+
execute_hook(:after_build, reporter.build)
|
98
|
+
when :archive
|
99
|
+
execute_hook(:after_build, reporter.build)
|
100
|
+
execute_hook(:after_archive, reporter.build)
|
101
|
+
when :clean
|
102
|
+
execute_hook(:after_clean, reporter.clean)
|
103
|
+
end
|
60
104
|
end
|
61
105
|
|
62
106
|
def define
|
63
107
|
namespace(@namespace) do
|
108
|
+
desc "Creates an archive build of the specified target(s)."
|
109
|
+
task :archive do
|
110
|
+
raise "You need to specify a `scheme' in order to be able to create an archive build!" unless scheme
|
111
|
+
xcodebuild :archive
|
112
|
+
end
|
113
|
+
|
64
114
|
desc "Builds the specified target(s)."
|
65
115
|
task :build do
|
66
|
-
|
67
|
-
XcodeBuild.run(build_opts_string, output_buffer)
|
68
|
-
end
|
116
|
+
xcodebuild :build
|
69
117
|
end
|
70
118
|
|
71
119
|
desc "Cleans the build using the same build settings."
|
72
120
|
task :clean do
|
73
|
-
|
74
|
-
XcodeBuild.run(build_opts_string("clean"), output_buffer)
|
75
|
-
end
|
121
|
+
xcodebuild :clean
|
76
122
|
end
|
77
123
|
|
78
124
|
desc "Builds the specified target(s) from a clean slate."
|
79
125
|
task :cleanbuild => [:clean, :build]
|
80
126
|
end
|
81
127
|
end
|
128
|
+
|
129
|
+
def check_status(status)
|
130
|
+
raise "xcodebuild failed (exited with status: #{status})" unless status == 0
|
131
|
+
end
|
82
132
|
end
|
83
133
|
end
|
84
134
|
end
|