xcoder 0.1.2 → 0.1.3
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/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
|