xcoder 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/README.md +2 -0
- data/Rakefile +9 -0
- data/lib/xcode/build_file.rb +4 -2
- data/lib/xcode/build_phase.rb +45 -3
- data/lib/xcode/builder.rb +9 -4
- data/lib/xcode/buildfile.rb +1 -1
- data/lib/xcode/configuration.rb +1 -1
- data/lib/xcode/file_reference.rb +42 -1
- data/lib/xcode/group.rb +81 -3
- data/lib/xcode/keychain.rb +20 -14
- data/lib/xcode/project.rb +37 -6
- data/lib/xcode/registry.rb +14 -0
- data/lib/xcode/target.rb +6 -6
- data/lib/xcode/version.rb +1 -1
- data/spec/Provisioning/Test.keychain +0 -0
- data/spec/TestProject/TestProject.xcodeproj/project.pbxproj +556 -801
- data/spec/build_phase_spec.rb +28 -0
- data/spec/builder_spec.rb +2 -1
- data/spec/group_spec.rb +54 -1
- data/spec/integration/cedar_install_spec.rb +15 -40
- data/spec/keychain_spec.rb +13 -5
- data/spec/project_spec.rb +12 -0
- metadata +15 -12
data/Gemfile
CHANGED
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
require "yard"
|
3
|
+
require "yard/rake/yardoc_task"
|
2
4
|
|
3
5
|
task :default => [:specs, :build]
|
4
6
|
|
@@ -10,6 +12,13 @@ task :integration do
|
|
10
12
|
system "rspec --color --format d --tag integration"
|
11
13
|
end
|
12
14
|
|
15
|
+
namespace :doc do
|
16
|
+
desc "Generate YARD docs"
|
17
|
+
YARD::Rake::YardocTask.new(:generate) do |t|
|
18
|
+
t.files = ['lib/**/*.rb', '-', 'README.md'] # optional
|
19
|
+
t.options = ["-o ../xcoder-doc"]
|
20
|
+
end
|
21
|
+
end
|
13
22
|
|
14
23
|
task :reset => ['test_project:reset']
|
15
24
|
|
data/lib/xcode/build_file.rb
CHANGED
@@ -14,8 +14,10 @@ module Xcode
|
|
14
14
|
# @param [String] file_identifier the unique identifier for the file
|
15
15
|
# @return [Hash] the properties hash for a default BuildFile.
|
16
16
|
#
|
17
|
-
def self.
|
18
|
-
{ 'isa' => "PBXBuildFile", 'fileRef' => file_identifier }
|
17
|
+
def self.buildfile(file_identifier,settings)
|
18
|
+
properties = { 'isa' => "PBXBuildFile", 'fileRef' => file_identifier }
|
19
|
+
properties.merge!('settings' => settings) unless settings.empty?
|
20
|
+
properties
|
19
21
|
end
|
20
22
|
|
21
23
|
end
|
data/lib/xcode/build_phase.rb
CHANGED
@@ -45,6 +45,17 @@ module Xcode
|
|
45
45
|
'runOnlyForDeploymentPostprocessing' => '0' }
|
46
46
|
end
|
47
47
|
|
48
|
+
#
|
49
|
+
# Return the BuildFile given the file name.
|
50
|
+
#
|
51
|
+
# @param [String] name of the FileReference that is being built.
|
52
|
+
# @return [BuildFile] the BuildFile that links to the file specified with
|
53
|
+
# the name.
|
54
|
+
#
|
55
|
+
def file(name)
|
56
|
+
files.find {|file| file.file_ref.name == name or file.file_ref.path == name }
|
57
|
+
end
|
58
|
+
|
48
59
|
#
|
49
60
|
# Return the files that are referenced by the build files. This traverses
|
50
61
|
# the level of indirection to make it easier to get to the FileReference.
|
@@ -59,7 +70,12 @@ module Xcode
|
|
59
70
|
|
60
71
|
#
|
61
72
|
# Find the first file that has the name or path that matches the specified
|
62
|
-
# parameter.
|
73
|
+
# parameter.
|
74
|
+
#
|
75
|
+
# @note this is the FileReference, the file being built and not the instance
|
76
|
+
# of the BuildFile.
|
77
|
+
#
|
78
|
+
# @see #file
|
63
79
|
#
|
64
80
|
# @param [String] name the name or the path of the file.
|
65
81
|
# @return [FileReference] the file referenced that matches the name or path;
|
@@ -76,17 +92,43 @@ module Xcode
|
|
76
92
|
# entry is added to the particular build phase. A BuildFile identifier must
|
77
93
|
# exist for each target.
|
78
94
|
#
|
95
|
+
# @example adding a source file to the sources build phase
|
96
|
+
#
|
97
|
+
# spec_file = project.group('Specs/Controller').create_file('FirstControllerSpec.m')
|
98
|
+
# project.target('Specs').sources_build_phase.add_build_file spec_file
|
99
|
+
#
|
100
|
+
# @example adding a source file, that does not use ARC, to the sources build phase
|
101
|
+
#
|
102
|
+
# spec_file = project.group('Specs/Controller').create_file('FirstControllerSpec.m')
|
103
|
+
# project.target('Specs').sources_build_phase.add_build_file spec_file, { 'COMPILER_FLAGS' => "-fno-objc-arc" }
|
104
|
+
#
|
79
105
|
# @param [FileReference] file the FileReference Resource to add to the build
|
80
106
|
# phase.
|
107
|
+
# @param [Hash] settings additional build settings that are specifically applied
|
108
|
+
# to this individual file.
|
81
109
|
#
|
82
|
-
def add_build_file(file)
|
110
|
+
def add_build_file(file,settings = {})
|
83
111
|
find_file_by = file.name || file.path
|
84
112
|
unless build_file(find_file_by)
|
85
|
-
new_build_file = @registry.add_object BuildFile.
|
113
|
+
new_build_file = @registry.add_object BuildFile.buildfile(file.identifier,settings)
|
86
114
|
@properties['files'] << new_build_file.identifier
|
87
115
|
end
|
88
116
|
end
|
89
117
|
|
118
|
+
#
|
119
|
+
# Add the specified file to the Build Phase.
|
120
|
+
#
|
121
|
+
#
|
122
|
+
#
|
123
|
+
# @param [FileReference] file the FileReference Resource to add to the build
|
124
|
+
# phase.
|
125
|
+
# @param [Hash] settings additional build settings that are specifically applied
|
126
|
+
# to this individual file.
|
127
|
+
#
|
128
|
+
def add_build_file_without_arc(file)
|
129
|
+
add_build_file file, { 'COMPILER_FLAGS' => "-fno-objc-arc" }
|
130
|
+
end
|
131
|
+
|
90
132
|
end
|
91
133
|
|
92
134
|
end
|
data/lib/xcode/builder.rb
CHANGED
@@ -13,7 +13,7 @@ module Xcode
|
|
13
13
|
config = config.launch
|
14
14
|
end
|
15
15
|
|
16
|
-
puts "CONFIG: #{config}"
|
16
|
+
#puts "CONFIG: #{config}"
|
17
17
|
@target = config.target
|
18
18
|
@sdk = @target.project.sdk
|
19
19
|
@config = config
|
@@ -38,6 +38,7 @@ module Xcode
|
|
38
38
|
def build(sdk=@sdk)
|
39
39
|
cmd = build_command(@sdk)
|
40
40
|
Xcode::Shell.execute(cmd)
|
41
|
+
self
|
41
42
|
end
|
42
43
|
|
43
44
|
def test
|
@@ -55,16 +56,17 @@ module Xcode
|
|
55
56
|
|
56
57
|
exit parser.exit_code if parser.exit_code!=0
|
57
58
|
|
58
|
-
|
59
|
+
self
|
59
60
|
end
|
60
61
|
|
61
62
|
def testflight(api_token, team_token)
|
62
|
-
raise "Can't find #{ipa_path}, do you need to call builder.
|
63
|
-
raise "Can't fins #{dsym_zip_path}, do you need to call builder.
|
63
|
+
raise "Can't find #{ipa_path}, do you need to call builder.package?" unless File.exists? ipa_path
|
64
|
+
raise "Can't fins #{dsym_zip_path}, do you need to call builder.package?" unless File.exists? dsym_zip_path
|
64
65
|
|
65
66
|
testflight = Xcode::Testflight.new(api_token, team_token)
|
66
67
|
yield(testflight) if block_given?
|
67
68
|
testflight.upload(ipa_path, dsym_zip_path)
|
69
|
+
self
|
68
70
|
end
|
69
71
|
|
70
72
|
def clean
|
@@ -87,6 +89,7 @@ module Xcode
|
|
87
89
|
# cmd = []
|
88
90
|
# cmd << "rm -Rf #{build_path}"
|
89
91
|
# Xcode::Shell.execute(cmd)
|
92
|
+
self
|
90
93
|
end
|
91
94
|
|
92
95
|
def sign
|
@@ -98,6 +101,7 @@ module Xcode
|
|
98
101
|
cmd << "--entitlements \"#{entitlements_path}\""
|
99
102
|
cmd << "\"#{ipa_path}\""
|
100
103
|
Xcode::Shell.execute(cmd)
|
104
|
+
self
|
101
105
|
end
|
102
106
|
|
103
107
|
def package
|
@@ -132,6 +136,7 @@ module Xcode
|
|
132
136
|
cmd << "\"#{dsym_path}\""
|
133
137
|
Xcode::Shell.execute(cmd)
|
134
138
|
|
139
|
+
self
|
135
140
|
end
|
136
141
|
|
137
142
|
def configuration_build_path
|
data/lib/xcode/buildfile.rb
CHANGED
@@ -57,7 +57,7 @@ module Xcode
|
|
57
57
|
Keychain.temp_keychain(@values[:project]) do |kc|
|
58
58
|
kc.import @values[:certificate], @values[:password]
|
59
59
|
|
60
|
-
builder.identity = @values[:identity] || kc.
|
60
|
+
builder.identity = @values[:identity] || kc.identities.first
|
61
61
|
builder.keychain = kc
|
62
62
|
|
63
63
|
puts "[#{label}] CLEAN"
|
data/lib/xcode/configuration.rb
CHANGED
data/lib/xcode/file_reference.rb
CHANGED
@@ -41,10 +41,19 @@ module Xcode
|
|
41
41
|
#
|
42
42
|
# Generate the properties for a system framework.
|
43
43
|
#
|
44
|
-
# @
|
44
|
+
# @example CoreGraphics.framework
|
45
|
+
#
|
46
|
+
# FileReference.system_framework "CoreGraphics.framework"
|
47
|
+
# FileReference.system_framework "Foundation"
|
48
|
+
#
|
49
|
+
# @param [String] name of the system framework which can be specified with or
|
50
|
+
# without the ".framework" suffix / extension.
|
45
51
|
# @param [Hash] properties the parameters to override for the system framework
|
46
52
|
#
|
47
53
|
def self.system_framework(name,properties = {})
|
54
|
+
|
55
|
+
name = name[/(.+)(?:\.framework)?$/,1]
|
56
|
+
|
48
57
|
default_properties = { 'isa' => 'PBXFileReference',
|
49
58
|
'lastKnownFileType' => 'wrapper.framework',
|
50
59
|
'name' => "#{name}.framework",
|
@@ -54,6 +63,27 @@ module Xcode
|
|
54
63
|
default_properties.merge(properties)
|
55
64
|
end
|
56
65
|
|
66
|
+
#
|
67
|
+
# Generate the properties for a system library
|
68
|
+
#
|
69
|
+
# @example libz.dylib
|
70
|
+
#
|
71
|
+
# FileReference.system_library "libz.dylib"
|
72
|
+
#
|
73
|
+
# @param [String] name of the system library, which can be found by default
|
74
|
+
# in the /usr/lib folder.
|
75
|
+
# @param [Types] properties the parameters to override for the system library
|
76
|
+
#
|
77
|
+
def self.system_library(name,properties = {})
|
78
|
+
default_properties = { 'isa' => 'PBXFileReference',
|
79
|
+
'lastKnownFileType' => 'compiled.mach-o.dylib',
|
80
|
+
'name' => name,
|
81
|
+
'path' => "usr/lib/#{name}",
|
82
|
+
"sourceTree" => "SDKROOT" }
|
83
|
+
|
84
|
+
default_properties.merge(properties)
|
85
|
+
end
|
86
|
+
|
57
87
|
#
|
58
88
|
# @example app product properties
|
59
89
|
#
|
@@ -72,6 +102,17 @@ module Xcode
|
|
72
102
|
'sourceTree' => "BUILT_PRODUCTS_DIR" }
|
73
103
|
end
|
74
104
|
|
105
|
+
#
|
106
|
+
# Remove the given file from the project and the supergroup of the file.
|
107
|
+
#
|
108
|
+
def remove!
|
109
|
+
# @todo the removal here does not consider if the files have
|
110
|
+
# been specified within a build phase.
|
111
|
+
yield self if block_given?
|
112
|
+
supergroup.children.delete identifier if supergroup
|
113
|
+
@registry.remove_object identifier
|
114
|
+
end
|
115
|
+
|
75
116
|
end
|
76
117
|
|
77
118
|
end
|
data/lib/xcode/group.rb
CHANGED
@@ -110,6 +110,14 @@ module Xcode
|
|
110
110
|
# Add a file to the specified group. Currently the file creation requires
|
111
111
|
# the path to the physical file.
|
112
112
|
#
|
113
|
+
# @example creating a file with just a path
|
114
|
+
#
|
115
|
+
# project.main_group.create_file 'AppDelegate.m'
|
116
|
+
#
|
117
|
+
# @example creating a file with a name and path
|
118
|
+
#
|
119
|
+
# project.main_group.create_file 'name' => 'AppDelegate.m', 'path' => 'Subfolder/AppDelegate.m'
|
120
|
+
#
|
113
121
|
# @param [String,Hash] path to the file that is being added or a hash that
|
114
122
|
# contains the values would be merged with the default values.
|
115
123
|
#
|
@@ -127,6 +135,7 @@ module Xcode
|
|
127
135
|
unless found_or_created_file
|
128
136
|
found_or_created_file = create_child_object FileReference.file(file_properties)
|
129
137
|
end
|
138
|
+
found_or_created_file.supergroup = self
|
130
139
|
|
131
140
|
found_or_created_file
|
132
141
|
end
|
@@ -134,20 +143,43 @@ module Xcode
|
|
134
143
|
#
|
135
144
|
# Create a framework within this group.
|
136
145
|
#
|
146
|
+
# @example Custom.Framework
|
147
|
+
#
|
148
|
+
# project.frameworks_group.create_framework 'name' => 'Custom.framework',
|
149
|
+
# 'path' => 'Vendor/Custom/Custom.framework'
|
150
|
+
#
|
137
151
|
# @param [Hash] framework_properties the properties to merge with the default
|
138
152
|
# properties.
|
139
153
|
#
|
140
154
|
def create_framework(framework_properties)
|
141
|
-
|
155
|
+
find_or_create_child_object FileReference.framework(framework_properties)
|
142
156
|
end
|
143
157
|
|
144
158
|
#
|
145
159
|
# Create a system framework reference within this group
|
160
|
+
#
|
161
|
+
# @example creating 'CoreGraphics' and 'Foundation' frameworks
|
162
|
+
#
|
163
|
+
# project.frameworks_group.create_system_framework "CoreGraphics.framework"
|
164
|
+
# project.frameworks_group.create_system_framework "Foundation"
|
146
165
|
#
|
147
166
|
# @param [String] name the name of the System framework to add to this group.
|
148
167
|
#
|
149
168
|
def create_system_framework(name)
|
150
|
-
|
169
|
+
find_or_create_child_object FileReference.system_framework(name)
|
170
|
+
end
|
171
|
+
|
172
|
+
#
|
173
|
+
# Create a system library reference within this group
|
174
|
+
#
|
175
|
+
# @example libz.dylib
|
176
|
+
#
|
177
|
+
# project.frameworks_group.create_system_library "libz.dylib"
|
178
|
+
#
|
179
|
+
# @param [String] name the name of the System Library to add to this group.
|
180
|
+
#
|
181
|
+
def create_system_library(name)
|
182
|
+
find_or_create_child_object FileReference.system_library(name)
|
151
183
|
end
|
152
184
|
|
153
185
|
#
|
@@ -176,10 +208,29 @@ module Xcode
|
|
176
208
|
create_child_object FileReference.app_product(name)
|
177
209
|
end
|
178
210
|
|
211
|
+
#
|
212
|
+
# Remove the resource from the registry.
|
213
|
+
#
|
214
|
+
# @note all children objects of this group are removed as well.
|
215
|
+
#
|
216
|
+
def remove!(&block)
|
217
|
+
|
218
|
+
# @note #groups and #files is used because it adds the very precious
|
219
|
+
# supergroup to each of the child items.
|
220
|
+
|
221
|
+
groups.each {|group| group.remove!(&block) }
|
222
|
+
files.each {|file| file.remove!(&block) }
|
223
|
+
yield self if block_given?
|
224
|
+
|
225
|
+
child_identifier = identifier
|
226
|
+
supergroup.instance_eval { remove_child_object(child_identifier) }
|
227
|
+
@registry.remove_object identifier
|
228
|
+
end
|
229
|
+
|
179
230
|
private
|
180
231
|
|
181
232
|
#
|
182
|
-
# This method is used internally to add
|
233
|
+
# This method is used internally to add object to the registry and add the
|
183
234
|
# object as a child of this group.
|
184
235
|
#
|
185
236
|
# @param [Hash] child_as_properties the hash of resource to add as a child
|
@@ -192,6 +243,33 @@ module Xcode
|
|
192
243
|
child_object
|
193
244
|
end
|
194
245
|
|
246
|
+
#
|
247
|
+
# This method is used internally to find the specified object or add the object
|
248
|
+
# as a child of this group.
|
249
|
+
#
|
250
|
+
# @param [Hash] child_properties the hash of resource to add as a child
|
251
|
+
# object of this group if it does not already exist as a child.
|
252
|
+
#
|
253
|
+
# @return [Resource] returns the resource that was added a child
|
254
|
+
def find_or_create_child_object(child_properties)
|
255
|
+
found_child = children.find {|child| child.name == child_properties['name'] or child.path == child_properties['path'] }
|
256
|
+
found_child = create_child_object(child_properties) unless found_child
|
257
|
+
found_child
|
258
|
+
end
|
259
|
+
|
260
|
+
#
|
261
|
+
# This method is used internally to remove a child object from this and the
|
262
|
+
# registry.
|
263
|
+
#
|
264
|
+
# @param [String] identifier of the child object to be removed.
|
265
|
+
# @return [Resource] the removed child resource
|
266
|
+
def remove_child_object(identifier)
|
267
|
+
found_child = children.find {|child| child.identifier == identifier }
|
268
|
+
@properties['children'].delete identifier
|
269
|
+
save!
|
270
|
+
found_child
|
271
|
+
end
|
272
|
+
|
195
273
|
end
|
196
274
|
|
197
275
|
end
|
data/lib/xcode/keychain.rb
CHANGED
@@ -10,9 +10,11 @@ module Xcode
|
|
10
10
|
#
|
11
11
|
# @param [String] the name of the keychain
|
12
12
|
#
|
13
|
-
def initialize(
|
14
|
-
@
|
15
|
-
@
|
13
|
+
def initialize(path)
|
14
|
+
@path = File.expand_path path
|
15
|
+
@name = File.basename path
|
16
|
+
|
17
|
+
yield(self) if block_given?
|
16
18
|
end
|
17
19
|
|
18
20
|
#
|
@@ -25,7 +27,7 @@ module Xcode
|
|
25
27
|
cmd = []
|
26
28
|
cmd << "security"
|
27
29
|
cmd << "import '#{cert}'"
|
28
|
-
cmd << "-k
|
30
|
+
cmd << "-k \"#{@path}\""
|
29
31
|
cmd << "-P #{password}"
|
30
32
|
cmd << "-T /usr/bin/codesign"
|
31
33
|
Xcode::Shell.execute(cmd)
|
@@ -42,7 +44,7 @@ module Xcode
|
|
42
44
|
cmd << "security"
|
43
45
|
cmd << "find-certificate"
|
44
46
|
cmd << "-a"
|
45
|
-
cmd << "#{@
|
47
|
+
cmd << "\"#{@path}\""
|
46
48
|
data = Xcode::Shell.execute(cmd, false).join("")
|
47
49
|
data.scan /\s+"labl"<blob>="([^"]+)"/ do |m|
|
48
50
|
names << m[0]
|
@@ -60,7 +62,7 @@ module Xcode
|
|
60
62
|
cmd << "security"
|
61
63
|
cmd << "unlock-keychain"
|
62
64
|
cmd << "-p #{password}"
|
63
|
-
cmd << "#{@
|
65
|
+
cmd << "\"#{@path}\""
|
64
66
|
Xcode::Shell.execute(cmd)
|
65
67
|
end
|
66
68
|
|
@@ -71,15 +73,17 @@ module Xcode
|
|
71
73
|
# @param [String] the password for the new keychain
|
72
74
|
# @return [Xcode::Keychain] an object representing the new keychain
|
73
75
|
#
|
74
|
-
def self.create(
|
76
|
+
def self.create(path, password)
|
75
77
|
cmd = []
|
76
78
|
cmd << "security"
|
77
79
|
cmd << "create-keychain"
|
78
80
|
cmd << "-p #{password}"
|
79
|
-
cmd << "#{
|
81
|
+
cmd << "\"#{path}\""
|
80
82
|
Xcode::Shell.execute(cmd)
|
81
83
|
|
82
|
-
Xcode::Keychain.new(
|
84
|
+
kc = Xcode::Keychain.new(path)
|
85
|
+
yield(kc) if block_given?
|
86
|
+
kc
|
83
87
|
end
|
84
88
|
|
85
89
|
#
|
@@ -90,7 +94,7 @@ module Xcode
|
|
90
94
|
def delete
|
91
95
|
cmd = []
|
92
96
|
cmd << "security"
|
93
|
-
cmd << "delete-keychain #{
|
97
|
+
cmd << "delete-keychain \"#{@path}\""
|
94
98
|
Xcode::Shell.execute(cmd)
|
95
99
|
end
|
96
100
|
|
@@ -100,8 +104,8 @@ module Xcode
|
|
100
104
|
#
|
101
105
|
# @param [String] the name of the temporary keychain to create
|
102
106
|
#
|
103
|
-
def self.
|
104
|
-
kc = Xcode::Keychain.create(
|
107
|
+
def self.temp(&block)
|
108
|
+
kc = Xcode::Keychain.create("/tmp/xcoder#{Time.now.to_i}", TEMP_PASSWORD)
|
105
109
|
begin
|
106
110
|
kc.unlock(TEMP_PASSWORD)
|
107
111
|
block.call(kc)
|
@@ -115,8 +119,10 @@ module Xcode
|
|
115
119
|
#
|
116
120
|
# @return [Xcode::Keychain] the current user's login keychain
|
117
121
|
#
|
118
|
-
def self.
|
119
|
-
Xcode::Keychain.new("login.keychain")
|
122
|
+
def self.login
|
123
|
+
kc = Xcode::Keychain.new("~/Library/Keychains/login.keychain")
|
124
|
+
yield(kc) if block_given?
|
125
|
+
kc
|
120
126
|
end
|
121
127
|
end
|
122
128
|
end
|