xcoder 0.1.13 → 0.1.14
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +37 -33
- data/lib/xcode/builder.rb +3 -234
- data/lib/xcode/builder/base_builder.rb +204 -0
- data/lib/xcode/builder/project_target_config_builder.rb +14 -0
- data/lib/xcode/builder/scheme_builder.rb +32 -0
- data/lib/xcode/configuration.rb +1 -1
- data/lib/xcode/keychain.rb +14 -21
- data/lib/xcode/project.rb +109 -109
- data/lib/xcode/registry.rb +1 -1
- data/lib/xcode/scheme.rb +82 -35
- data/lib/xcode/shell.rb +3 -1
- data/lib/xcode/shell/command.rb +42 -0
- data/lib/xcode/version.rb +1 -1
- data/lib/xcode/workspace.rb +2 -1
- data/spec/builder_spec.rb +68 -62
- data/spec/registry_spec.rb +51 -0
- data/spec/scheme_spec.rb +5 -5
- data/spec/xcode_spec.rb +1 -0
- metadata +18 -12
data/lib/xcode/registry.rb
CHANGED
data/lib/xcode/scheme.rb
CHANGED
@@ -1,60 +1,107 @@
|
|
1
1
|
require 'nokogiri'
|
2
2
|
|
3
3
|
module Xcode
|
4
|
-
|
4
|
+
|
5
5
|
# Schemes are an XML file that describe build, test, launch and profile actions
|
6
6
|
# For the purposes of Xcoder, we want to be able to build and test
|
7
|
-
# The scheme's build action only describes a target, so we need to look at launch for the config
|
8
7
|
class Scheme
|
9
|
-
attr_reader :path, :name, :
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@launch = parse_action(doc, 'launch')
|
17
|
-
@test = parse_action(doc, 'test')
|
8
|
+
attr_reader :parent, :path, :name, :build_config, :build_targets
|
9
|
+
|
10
|
+
#
|
11
|
+
# Parse all the schemes given the current project.
|
12
|
+
#
|
13
|
+
def self.find_in_project(project)
|
14
|
+
find_in_path(project, project.path)
|
18
15
|
end
|
19
|
-
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
16
|
+
|
17
|
+
#
|
18
|
+
# Parse all the schemes given the current workspace.
|
19
|
+
#
|
20
|
+
def self.find_in_workspace(workspace)
|
21
|
+
schemes = find_in_path(workspace, workspace.path)
|
22
|
+
|
23
|
+
# Project level schemes
|
24
|
+
workspace.projects.each do |project|
|
25
|
+
schemes+=project.schemes
|
26
|
+
end
|
27
|
+
|
28
|
+
schemes
|
26
29
|
end
|
27
30
|
|
28
|
-
#
|
29
|
-
# Parse all the scheme files that can be found in the given project or workspace. Schemes
|
31
|
+
# Parse all the scheme files that can be found at the given path. Schemes
|
30
32
|
# can be defined as `shared` schemes and then `user` specific schemes. Parsing
|
31
33
|
# the schemes will load the shared ones and then the current acting user's
|
32
34
|
# schemes.
|
35
|
+
#
|
33
36
|
#
|
37
|
+
# @param project or workspace in which the scheme is contained
|
34
38
|
# @return [Array<Scheme>] the shared schemes and user specific schemes found
|
35
|
-
# within the
|
39
|
+
# within the project/workspace at the path defined for schemes.
|
36
40
|
#
|
37
|
-
def self.find_in_path(path)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
(shared_schemes + user_specific_schemes).map do |scheme|
|
42
|
-
Xcode::Scheme.new(scheme)
|
41
|
+
def self.find_in_path(parent, path)
|
42
|
+
all_schemes_paths(path).map do |scheme_path|
|
43
|
+
Xcode::Scheme.new(parent: parent, root: path, path: scheme_path)
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
def initialize(params={})
|
48
|
+
@parent = params[:parent]
|
49
|
+
@path = File.expand_path params[:path]
|
50
|
+
@root = File.expand_path(File.join(params[:root],'..'))
|
51
|
+
@name = File.basename(path).gsub(/\.xcscheme$/,'')
|
52
|
+
doc = Nokogiri::XML(open(@path))
|
52
53
|
|
54
|
+
parse_build_actions(doc)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns a builder for building this scheme
|
58
|
+
def builder
|
59
|
+
Xcode::Builder::SchemeBuilder.new(self)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
#
|
65
|
+
# @return an array of all the scheme filepaths found within the project
|
66
|
+
# or workspace path provided.
|
67
|
+
#
|
68
|
+
def self.all_schemes_paths(path)
|
69
|
+
shared_schemes_paths(path) + current_user_schemes_paths(path)
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# @return an array of all the shared scheme filespaths found within the
|
74
|
+
# project or workspace path provided.
|
75
|
+
#
|
76
|
+
def self.shared_schemes_paths(root)
|
77
|
+
Dir["#{root}/xcshareddata/xcschemes/*.xcscheme"]
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# @return an array of all the current user's scheme filespaths found within the
|
82
|
+
# project or workspace path provided.
|
83
|
+
#
|
84
|
+
def self.current_user_schemes_paths(root)
|
85
|
+
Dir["#{root}/xcuserdata/#{ENV['USER']}.xcuserdatad/xcschemes/*.xcscheme"]
|
86
|
+
end
|
87
|
+
|
88
|
+
def target_from_build_reference(buildableReference)
|
53
89
|
project_name = buildableReference['ReferencedContainer'].gsub(/^container:/,'')
|
54
|
-
project = Xcode.project "#{@root}/#{project_name}"
|
55
90
|
target_name = buildableReference['BlueprintName']
|
91
|
+
project_path = File.join @root, project_name
|
92
|
+
project = Xcode.project project_path
|
93
|
+
project.target(target_name)
|
94
|
+
end
|
95
|
+
|
96
|
+
def parse_build_actions(doc)
|
97
|
+
# Build Config
|
98
|
+
@build_targets = []
|
56
99
|
|
57
|
-
|
100
|
+
@build_config = doc.xpath("//LaunchAction").first['buildConfiguration']
|
101
|
+
|
102
|
+
build_action_entries = doc.xpath("//BuildAction//BuildableReference").each do |ref|
|
103
|
+
@build_targets << target_from_build_reference(ref)
|
104
|
+
end
|
58
105
|
end
|
59
106
|
|
60
107
|
end
|
data/lib/xcode/shell.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'xcode/shell/command.rb'
|
2
|
+
|
1
3
|
module Xcode
|
2
4
|
module Shell
|
3
5
|
|
@@ -5,7 +7,7 @@ module Xcode
|
|
5
7
|
|
6
8
|
def self.execute(bits, show_output=true)
|
7
9
|
out = []
|
8
|
-
cmd = bits.is_a?(
|
10
|
+
cmd = bits.is_a?(Xcode::Shell::Command) ? bits.to_s : bits
|
9
11
|
|
10
12
|
puts "EXECUTE: #{cmd}"
|
11
13
|
IO.popen (cmd) do |f|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Xcode
|
4
|
+
module Shell
|
5
|
+
class Command
|
6
|
+
attr_accessor :env
|
7
|
+
|
8
|
+
def initialize(cmd, environment={})
|
9
|
+
@cmd = cmd
|
10
|
+
@args = []
|
11
|
+
@env = environment
|
12
|
+
end
|
13
|
+
|
14
|
+
def <<(arg)
|
15
|
+
@args << arg
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"#{to_a.join(' ')}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_a
|
23
|
+
out = []
|
24
|
+
out << @cmd
|
25
|
+
out+=@args
|
26
|
+
out+=(@env.map {|k,v| "#{k}=#{v}"})
|
27
|
+
out
|
28
|
+
end
|
29
|
+
|
30
|
+
def ==(obj)
|
31
|
+
return false unless obj.is_a? Xcode::Shell::Command
|
32
|
+
# to_s==obj.to_s
|
33
|
+
Set.new(obj.to_a) == Set.new(self.to_a)
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute(show_output=true, &block) #:yield: output
|
37
|
+
Xcode::Shell.execute(self, show_output, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/xcode/version.rb
CHANGED
data/lib/xcode/workspace.rb
CHANGED
data/spec/builder_spec.rb
CHANGED
@@ -10,25 +10,35 @@ describe Xcode::Builder do
|
|
10
10
|
|
11
11
|
describe "#build" do
|
12
12
|
|
13
|
-
let(:default_build_parameters) do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
let(:default_build_parameters) do
|
14
|
+
cmd = Xcode::Shell::Command.new "xcodebuild"
|
15
|
+
cmd << "-project \"#{configuration.target.project.path}\""
|
16
|
+
cmd << "-target \"#{configuration.target.name}\""
|
17
|
+
cmd << "-config \"#{configuration.name}\""
|
18
|
+
cmd << "-sdk #{configuration.target.project.sdk}"
|
19
|
+
cmd.env["OBJROOT"]="\"#{File.dirname(configuration.target.project.path)}/build/\""
|
20
|
+
cmd.env["SYMROOT"]="\"#{File.dirname(configuration.target.project.path)}/build/\""
|
21
|
+
cmd
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:macosx_build_parameters) do
|
25
|
+
cmd = Xcode::Shell::Command.new "xcodebuild"
|
26
|
+
cmd << "-project \"#{configuration.target.project.path}\""
|
27
|
+
cmd << "-target \"#{configuration.target.name}\""
|
28
|
+
cmd << "-config \"#{configuration.name}\""
|
29
|
+
cmd << "-sdk macosx10.7"
|
30
|
+
cmd.env["OBJROOT"]="\"#{File.dirname(configuration.target.project.path)}/build/\""
|
31
|
+
cmd.env["SYMROOT"]="\"#{File.dirname(configuration.target.project.path)}/build/\""
|
32
|
+
cmd
|
21
33
|
end
|
22
34
|
|
23
35
|
it "should build the project with the default parameters" do
|
24
|
-
Xcode::Shell.should_receive(:execute).with(default_build_parameters)
|
36
|
+
Xcode::Shell.should_receive(:execute).with(default_build_parameters,true)
|
25
37
|
subject.build
|
26
38
|
end
|
27
39
|
|
28
40
|
it "should allow the override of the sdk" do
|
29
|
-
|
30
|
-
expected[1] = '-sdk macosx10.7'
|
31
|
-
Xcode::Shell.should_receive(:execute).with(expected)
|
41
|
+
Xcode::Shell.should_receive(:execute).with(macosx_build_parameters, true)
|
32
42
|
subject.build :sdk => 'macosx10.7'
|
33
43
|
end
|
34
44
|
|
@@ -70,27 +80,27 @@ describe Xcode::Builder do
|
|
70
80
|
end
|
71
81
|
|
72
82
|
let(:iphonesimulator_test_parameters) do
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
83
|
+
cmd = Xcode::Shell::Command.new "xcodebuild"
|
84
|
+
cmd << "-project \"#{configuration.target.project.path}\""
|
85
|
+
cmd << "-target \"#{configuration.target.name}\""
|
86
|
+
cmd << "-config \"#{configuration.name}\""
|
87
|
+
cmd << "-sdk iphonesimulator"
|
88
|
+
cmd.env["OBJROOT"]="\"#{File.dirname(configuration.target.project.path)}/build/\""
|
89
|
+
cmd.env["SYMROOT"]="\"#{File.dirname(configuration.target.project.path)}/build/\""
|
90
|
+
cmd.env["TEST_AFTER_BUILD"]="YES"
|
91
|
+
cmd
|
82
92
|
end
|
83
93
|
|
84
94
|
let(:macosx_test_parameters) do
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
95
|
+
cmd = Xcode::Shell::Command.new "xcodebuild"
|
96
|
+
cmd << "-project \"#{configuration.target.project.path}\""
|
97
|
+
cmd << "-target \"#{configuration.target.name}\""
|
98
|
+
cmd << "-config \"#{configuration.name}\""
|
99
|
+
cmd << "-sdk macosx10.7"
|
100
|
+
cmd.env["OBJROOT"]="\"#{File.dirname(configuration.target.project.path)}/build/\""
|
101
|
+
cmd.env["SYMROOT"]="\"#{File.dirname(configuration.target.project.path)}/build/\""
|
102
|
+
cmd.env["TEST_AFTER_BUILD"]="YES"
|
103
|
+
cmd
|
94
104
|
end
|
95
105
|
|
96
106
|
|
@@ -99,15 +109,8 @@ describe Xcode::Builder do
|
|
99
109
|
subject.test :sdk => 'iphonesimulator'
|
100
110
|
end
|
101
111
|
|
102
|
-
it "should be able to run the test target on macosx10.7" do
|
103
|
-
Xcode::Shell.should_receive(:execute).with(macosx_test_parameters, false)
|
104
|
-
subject.test :sdk => 'macosx10.7'
|
105
|
-
end
|
106
|
-
|
107
112
|
it "should allow the override of the sdk" do
|
108
|
-
|
109
|
-
expected[1] = '-sdk macosx10.7'
|
110
|
-
Xcode::Shell.should_receive(:execute).with(expected, false)
|
113
|
+
Xcode::Shell.should_receive(:execute).with(macosx_test_parameters, false)
|
111
114
|
subject.test :sdk => 'macosx10.7'
|
112
115
|
end
|
113
116
|
|
@@ -125,19 +128,20 @@ describe Xcode::Builder do
|
|
125
128
|
describe "#clean" do
|
126
129
|
|
127
130
|
let(:default_clean_parameters) do
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
131
|
+
cmd = Xcode::Shell::Command.new "xcodebuild"
|
132
|
+
cmd << "-project \"#{configuration.target.project.path}\""
|
133
|
+
cmd << "-target \"#{configuration.target.name}\""
|
134
|
+
cmd << "-config \"#{configuration.name}\""
|
135
|
+
cmd << "-sdk iphoneos"
|
136
|
+
cmd << "clean"
|
137
|
+
cmd.env["OBJROOT"]="\"#{File.dirname(configuration.target.project.path)}/build/\""
|
138
|
+
cmd.env["SYMROOT"]="\"#{File.dirname(configuration.target.project.path)}/build/\""
|
139
|
+
cmd
|
136
140
|
end
|
137
141
|
|
138
142
|
|
139
143
|
it "should clean the project with the default parameter" do
|
140
|
-
Xcode::Shell.should_receive(:execute).with(default_clean_parameters)
|
144
|
+
Xcode::Shell.should_receive(:execute).with(default_clean_parameters, true)
|
141
145
|
subject.clean
|
142
146
|
end
|
143
147
|
|
@@ -154,16 +158,17 @@ describe Xcode::Builder do
|
|
154
158
|
describe "#build" do
|
155
159
|
|
156
160
|
let(:default_build_parameters) do
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
161
|
+
cmd = Xcode::Shell::Command.new "xcodebuild"
|
162
|
+
cmd << "-project \"#{scheme.build_targets.last.project.path}\""
|
163
|
+
cmd << "-scheme \"#{scheme.name}\""
|
164
|
+
cmd << "-sdk iphoneos"
|
165
|
+
cmd.env["OBJROOT"]="\"#{File.dirname(scheme.build_targets.last.project.path)}/build/\""
|
166
|
+
cmd.env["SYMROOT"]="\"#{File.dirname(scheme.build_targets.last.project.path)}/build/\""
|
167
|
+
cmd
|
163
168
|
end
|
164
169
|
|
165
170
|
it "should build the project with the default parameters" do
|
166
|
-
Xcode::Shell.should_receive(:execute).with(default_build_parameters)
|
171
|
+
Xcode::Shell.should_receive(:execute).with(default_build_parameters, true)
|
167
172
|
subject.build
|
168
173
|
end
|
169
174
|
|
@@ -172,18 +177,19 @@ describe Xcode::Builder do
|
|
172
177
|
describe "#clean" do
|
173
178
|
|
174
179
|
let(:default_clean_parameters) do
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
180
|
+
cmd = Xcode::Shell::Command.new "xcodebuild"
|
181
|
+
cmd << "-project \"#{scheme.build_targets.last.project.path}\""
|
182
|
+
cmd << "-scheme \"#{scheme.name}\""
|
183
|
+
cmd << "-sdk iphoneos"
|
184
|
+
cmd << "clean"
|
185
|
+
cmd.env["OBJROOT"]="\"#{File.dirname(scheme.build_targets.last.project.path)}/build/\""
|
186
|
+
cmd.env["SYMROOT"]="\"#{File.dirname(scheme.build_targets.last.project.path)}/build/\""
|
187
|
+
cmd
|
182
188
|
end
|
183
189
|
|
184
190
|
|
185
191
|
it "should clean the project with the default parameter" do
|
186
|
-
Xcode::Shell.should_receive(:execute).with(default_clean_parameters)
|
192
|
+
Xcode::Shell.should_receive(:execute).with(default_clean_parameters, true)
|
187
193
|
subject.clean
|
188
194
|
end
|
189
195
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Xcode::Registry do
|
4
|
+
|
5
|
+
def self.is_identifier? value
|
6
|
+
value =~ /^[0-9A-F]{24,}$/
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "ClassMethods" do
|
10
|
+
subject { described_class }
|
11
|
+
|
12
|
+
describe "#is_identifier?" do
|
13
|
+
context "when the value is valid hexadecimal 24 character length string" do
|
14
|
+
context "when it is all uppercase" do
|
15
|
+
let(:input) { "0123456789ABCDEF01234567" }
|
16
|
+
|
17
|
+
it "should be an identifier" do
|
18
|
+
subject.is_identifier?(input).should be_true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when it uses lowercase characters" do
|
23
|
+
let(:input) { "0123456789abcdef01234567" }
|
24
|
+
|
25
|
+
it "should be an identifier" do
|
26
|
+
subject.is_identifier?(input).should be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when the value is less than 24 characters" do
|
32
|
+
let(:input) { "0123456789ABCDEF" }
|
33
|
+
|
34
|
+
it "should not be an identifier" do
|
35
|
+
subject.is_identifier?(input).should be_false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when it contains other than hexadecimal characters" do
|
40
|
+
let(:input) { "0123456789ABCDEFGHIJKLMNO" }
|
41
|
+
|
42
|
+
it "should not be an identifier" do
|
43
|
+
subject.is_identifier?(input).should be_false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|