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 CHANGED
@@ -19,7 +19,7 @@ You will need to install the gem:
19
19
  and then require the gem in your project/rakefile/etc
20
20
 
21
21
  require 'xcoder'
22
-
22
+
23
23
  ### Load a project
24
24
 
25
25
  project = Xcode.project('MyProject') # Can be the name, the file (e.g. MyProject.xcodeproj) or the path
@@ -27,20 +27,24 @@ and then require the gem in your project/rakefile/etc
27
27
  ### Finding all projects from the current directory down
28
28
 
29
29
  Xcode.find_projects.each {|p| puts p.name }
30
-
30
+
31
31
  ### Find a configuration for a target on a project
32
32
 
33
33
  config = Xcode.project(:MyProject).target(:Target).config(:Debug) # returns an Xcode::Configuration object
34
34
 
35
35
  ### Building a configuration
36
36
 
37
+ config = Xcode.project(:MyProject).target(:Target).config(:Debug)
37
38
  builder = config.builder
38
39
  builder.profile = 'Profiles/MyAdHoc.mobileprovision' # This will remove old profiles and install the profile
39
40
  builder.identity = 'iPhone Developer: Ray Hilton' # The name of the identity to use to sign the IPA (optional)
41
+ builder.clean
40
42
  builder.build
41
-
43
+ # Building uses the targets's default sdk, which you can override:
44
+ builder.build :sdk => :iphonesimulator
45
+
42
46
  ### Working with Keychains
43
-
47
+
44
48
  You will not normally need to worry about manipulating keychains unless you want to automate importing of certificates (in a CI system with many clients) or opening of specific keychains for different builds (the old two-certs-with-same-identity-name workaround).
45
49
 
46
50
  You can either use the user's login keychain, another named keychain, or simply use a temporary keychain that will be blown away after the build.
@@ -51,26 +55,26 @@ You can either use the user's login keychain, another named keychain, or simply
51
55
  # import certs into the keychain
52
56
  # perform builds within this keychain's context
53
57
  end # Keychain is deleted
54
-
58
+
55
59
  Or, you can create a temporary keychain that will be deleted when the process exits:
56
60
 
57
61
  keychain = Xcode::Keychain.temp
58
62
 
59
-
63
+
60
64
  #### Importing a certificate
61
65
 
62
66
  You can import a certificate from a .p12 file into a keychain. Here we simply create a temporary keychain, import a certificate, set the identity onto the builder and then perform a build.
63
-
64
- keychain.import 'Certs/MyCert.p12', 'mycertpassword'
67
+
68
+ keychain.import 'Certs/MyCert.p12', 'mycertpassword'
65
69
  builder.keychain = keychain # Tell the builder to use the temp keychain
66
70
  builder.identity = keychain.identities.first # Get the first (only) identity name from the keychain
67
-
71
+
68
72
  ### Packaging a built .app
69
73
 
70
74
  After performing the above build, you can create a versioned, well named .ipa and .dSYM.zip
71
75
 
72
76
  builder.package
73
-
77
+
74
78
  This will produce something like: MyProject-Debug-1.0.ipa and MyProject-Debug-1.0.dSYM.zip
75
79
 
76
80
  ### Incrementing the build number
@@ -85,15 +89,15 @@ This will produce something like: MyProject-Debug-1.0.ipa and MyProject-Debug-1.
85
89
  Loading workspaces can be done in a similar way to projects:
86
90
 
87
91
  Xcode.workspaces.each do |w|
88
- w.describe # prints a recursive description of the
92
+ w.describe # prints a recursive description of the
89
93
  # structure of the workspace and its projects
90
94
  end
91
-
95
+
92
96
  Or, if you know the name:
93
97
 
94
98
  workspace = Xcode.workspace('MyWorkspace') # Can be the name, the file (e.g. MyWorkspace.xcworkspace) or the path
95
-
96
-
99
+
100
+
97
101
  ### Schemes
98
102
 
99
103
  There is basic support for schemes, you can enumerate them from a project like so:
@@ -101,11 +105,11 @@ There is basic support for schemes, you can enumerate them from a project like s
101
105
  project.schemes.each do |s|
102
106
  s.builder.build
103
107
  end
104
-
108
+
105
109
  Or, access them by name:
106
110
 
107
111
  builder = project.scheme('MyScheme').builder
108
-
112
+
109
113
  Note: The builder behaves the same as the builder for the target/config approach and will force xcodebuild to use the local build/ directory (as per xcode3) rather than a generated temporary directory in DerivedData. This may or may not be a good thing.
110
114
 
111
115
  Note: Shared schemes and user (current logged in user) specific schemes are both loaded. They may share names and other similarities that make them hard to distinguish. Currently the priority loading order is shared schemes and then user specific schemes.
@@ -115,9 +119,9 @@ Note: Shared schemes and user (current logged in user) specific schemes are both
115
119
  The library provides a mechanism to install/uninstall a provisioning profile. This normally happens as part of a build (if a profile is provided to the builder, see above), but you can do this manually:
116
120
 
117
121
  Xcode::ProvisioningProfile.new("Myprofile.mobileprovision").install # installs profile into ~/Library
118
-
122
+
119
123
  Or enumerate installed profiles:
120
-
124
+
121
125
  Xcode::ProvisioningProfile.installed_profiles.each do |p|
122
126
  p.uninstall # Removes the profile from ~/Library/
123
127
  end
@@ -131,7 +135,7 @@ The common output of this build/package process is to upload to Testflight. Thi
131
135
  tf.notify = true # Whether to send a notification to users, default is true
132
136
  tf.lists << "AList" # The lists to distribute the build to
133
137
  end
134
-
138
+
135
139
  You can also optionally set a .proxy= property or just set the HTTP_PROXY environment variable.
136
140
 
137
141
  ### OCUnit to JUnit reports
@@ -140,14 +144,14 @@ You can invoke your test target/bundle from the builder
140
144
 
141
145
  builder.test do |report|
142
146
  report.debug = false # default false, set to true to see raw output from xcodebuild
143
-
147
+
144
148
  # The following is the default setup, you wouldnt normally need to do this unless
145
149
  # you want to add new formatters
146
150
  report.formatters = []
147
151
  report.add_formatter :junit, 'test-reports' # Output JUnit format results to test-reports/
148
152
  report.add_formatter :stdout # Output a simplified output to STDOUT
149
153
  end
150
-
154
+
151
155
  This will invoke the test target, capture the output and write the junit reports to the test-reports directory. Currently only junit is supported, although you can write your own formatter quite easily (for an example, look at Xcode::Test::Formatters::JunitFormatter).
152
156
 
153
157
  ## Rake Tasks
@@ -157,13 +161,13 @@ Xcoder provides a rake task to assist with make it easier to perform common Xcod
157
161
  Within your `Rakefile` add the following:
158
162
 
159
163
  require 'xcoder/rake_task'
160
-
164
+
161
165
  Then define your Rake Task:
162
166
 
163
167
  Xcode::RakeTask.new
164
168
 
165
169
  By default this will generate rake tasks within the 'xcode' namespace for
166
- all the projects (within the current working directory), all their targets,
170
+ all the projects (within the current working directory), all their targets,
167
171
  and all their configs. This will also generate tasks for all of a projects
168
172
  schemes as well.
169
173
 
@@ -173,14 +177,14 @@ schemes as well.
173
177
 
174
178
  This will generate rake tasks that appear similar to the following:
175
179
 
176
- rake xcode:project-name:targetname:debug:build
177
- rake xcode:project-name:targetname:debug:clean
180
+ rake xcode:project-name:targetname:debug:build
181
+ rake xcode:project-name:targetname:debug:clean
178
182
  # ...
179
183
 
180
184
  You can specify a parameter to change the root rake namespace:
181
185
 
182
186
  Xcode::RakeTask.new :apple
183
-
187
+
184
188
  # Resulting Rake Tasks:
185
189
  # rake apple:project-name:targetname:debug:build
186
190
  # rake apple:project-name:targetname:debug:clean
@@ -192,7 +196,7 @@ You can also supply a block to provide additional configuration to specify the f
192
196
  xcoder.directory = "projects"
193
197
  xcoder.projects = [ "Project Alpha", "Project Beta" ]
194
198
  end
195
-
199
+
196
200
  rake hudson:project-alpha:targetname:debug:build
197
201
  # ...
198
202
 
@@ -202,7 +206,7 @@ Guard provides the ability to launch commands when files changed. There is a [gu
202
206
 
203
207
  gem install guard
204
208
  gem install guard-xcoder
205
-
209
+
206
210
  guard init
207
211
  guard init xcoder
208
212
 
@@ -232,7 +236,7 @@ project.group('Vendor/Reachability') do
232
236
  # Create files for each source file defined above
233
237
  source_files.each |source| create_file source }
234
238
  end
235
- ```
239
+ ```
236
240
 
237
241
  Within the project file the groups in the path are created or found and then file references are added for the two specified source files. Xcoder only updates the logical project file, it does not copy physical files, that is done by the FileUtils.
238
242
 
@@ -283,7 +287,7 @@ target.config 'Release' do |config|
283
287
  end
284
288
  ```
285
289
 
286
- Configuration settings can be accessed through `get`, `set`, and `append` with their [Xcode Build Names](https://developer.apple.com/library/mac/#documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW110) or through convenience methods generated for most of the build settings (`property_name`, `property_name=`, `append_to_property_name`). The entire list of property names can be found in the [configuration](/rayh/xcoder/blob/master/lib/xcode/configuration.rb).
290
+ Configuration settings can be accessed through `get`, `set`, and `append` with their [Xcode Build Names](https://developer.apple.com/library/mac/#documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW110) or through convenience methods generated for most of the build settings (`property_name`, `property_name=`, `append_to_property_name`). The entire list of property names can be found in the [configuration](/rayh/xcoder/blob/master/lib/xcode/configuration.rb).
287
291
 
288
292
 
289
293
  ### Saving your changes!
@@ -300,10 +304,10 @@ Within the `specs/integration` folder there are more examples.
300
304
 
301
305
  ## Tests
302
306
 
303
- There are some basic RSpec tests in the project which I suspect /wont/ work on machines without my identity installed.
307
+ There are some basic RSpec tests in the project which I suspect /wont/ work on machines without my identity installed.
304
308
 
305
309
  Currently these tests only assert the basic project file parsing and build code and do not perform file modification tests (e.g. for info plists) or provisioning profile/keychain importing
306
-
310
+
307
311
  ## Feedback
308
312
 
309
- Please raise issues if you find defects or have a feature request.
313
+ Please raise issues if you find defects or have a feature request.
data/lib/xcode/builder.rb CHANGED
@@ -2,237 +2,6 @@ require 'xcode/shell'
2
2
  require 'xcode/provisioning_profile'
3
3
  require 'xcode/test/parsers/ocunit_parser.rb'
4
4
  require 'xcode/testflight'
5
-
6
- module Xcode
7
-
8
- #
9
- # This class tries to pull various bits of Xcoder together to provide a higher-level API for common
10
- # project build tasks.
11
- #
12
- class Builder
13
- attr_accessor :profile, :identity, :build_path, :keychain, :sdk, :objroot, :symroot
14
-
15
- def initialize(config)
16
- if config.is_a? Xcode::Scheme
17
- @scheme = config
18
- config = config.launch
19
- end
20
-
21
- #puts "CONFIG: #{config}"
22
- @target = config.target
23
- @sdk = @target.project.sdk
24
- @config = config
25
- @build_path = "#{File.dirname(@target.project.path)}/build/"
26
- @objroot = @build_path
27
- @symroot = @build_path
28
- end
29
-
30
-
31
- def build(options = {:sdk => @sdk})
32
- cmd = build_command(options)
33
- with_keychain do
34
- Xcode::Shell.execute(cmd)
35
- end
36
- self
37
- end
38
-
39
- #
40
- # Invoke the configuration's test target and parse the resulting output
41
- #
42
- # If a block is provided, the report is yielded for configuration before the test is run
43
- #
44
- def test(options = {:sdk => 'iphonesimulator'}) #, :parser => :OCUnit })
45
- cmd = build_command(options)
46
- cmd << "TEST_AFTER_BUILD=YES"
47
-
48
- report = Xcode::Test::Report.new
49
- if block_given?
50
- yield(report)
51
- else
52
- report.add_formatter :stdout
53
- report.add_formatter :junit, 'test-reports'
54
- end
55
-
56
- parser = Xcode::Test::Parsers::OCUnitParser.new report
57
-
58
- begin
59
- Xcode::Shell.execute(cmd, false) do |line|
60
- parser << line
61
- end
62
- rescue Xcode::Shell::ExecutionError => e
63
- puts "Test platform exited: #{e.message}"
64
- ensure
65
- parser.flush
66
- end
67
-
68
- report
69
- end
70
-
71
- def testflight(api_token, team_token)
72
- raise "Can't find #{ipa_path}, do you need to call builder.package?" unless File.exists? ipa_path
73
- raise "Can't fins #{dsym_zip_path}, do you need to call builder.package?" unless File.exists? dsym_zip_path
74
-
75
- testflight = Xcode::Testflight.new(api_token, team_token)
76
- yield(testflight) if block_given?
77
- testflight.upload(ipa_path, dsym_zip_path)
78
- end
79
-
80
- def clean
81
- cmd = []
82
- cmd << "xcodebuild"
83
- cmd << "-project \"#{@target.project.path}\""
84
- cmd << "-sdk #{@sdk}" unless @sdk.nil?
85
-
86
- cmd << "-scheme \"#{@scheme.name}\"" unless @scheme.nil?
87
- cmd << "-target \"#{@target.name}\"" if @scheme.nil?
88
- cmd << "-configuration \"#{@config.name}\"" if @scheme.nil?
89
-
90
- cmd << "OBJROOT=\"#{@build_path}\""
91
- cmd << "SYMROOT=\"#{@build_path}\""
92
- cmd << "clean"
93
- Xcode::Shell.execute(cmd)
94
-
95
- @built = false
96
- @packaged = false
97
- # FIXME: Totally not safe
98
- # cmd = []
99
- # cmd << "rm -Rf #{build_path}"
100
- # Xcode::Shell.execute(cmd)
101
- self
102
- end
103
-
104
- def sign
105
- cmd = []
106
- cmd << "codesign"
107
- cmd << "--force"
108
- cmd << "--sign \"#{@identity}\""
109
- cmd << "--resource-rules=\"#{app_path}/ResourceRules.plist\""
110
- cmd << "--entitlements \"#{entitlements_path}\""
111
- cmd << "\"#{ipa_path}\""
112
- Xcode::Shell.execute(cmd)
113
-
114
- # CodeSign build/AdHoc-iphoneos/Dial.app
115
- # cd "/Users/ray/Projects/Clients/CBAA/Community Radio"
116
- # setenv CODESIGN_ALLOCATE /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate
117
- # setenv PATH "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Developer/usr/bin:/Users/ray/.rvm/gems/ruby-1.9.2-p290@cbaa/bin:/Users/ray/.rvm/gems/ruby-1.9.2-p290@global/bin:/Users/ray/.rvm/rubies/ruby-1.9.2-p290/bin:/Users/ray/.rvm/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/usr/local/git/bin"
118
- # /usr/bin/codesign --force --sign "iPhone Distribution: Community Broadcasting Association of Australia" "--resource-rules=/Users/ray/Projects/Clients/CBAA/Community Radio/build/AdHoc-iphoneos/Dial.app/ResourceRules.plist" --keychain "\"/Users/ray/Projects/Clients/CBAA/Community\\" "Radio/Provisioning/CBAA.keychain\"" --entitlements "/Users/ray/Projects/Clients/CBAA/Community Radio/build/CommunityRadio.build/AdHoc-iphoneos/CommunityRadio.build/Dial.xcent" "/Users/ray/Projects/Clients/CBAA/Community Radio/build/AdHoc-iphoneos/Dial.app"
119
- # iPhone Distribution: Community Broadcasting Association of Australia: no identity found
120
- # Command /usr/bin/codesign failed with exit code 1
121
- self
122
- end
123
-
124
- def package
125
- raise "Can't find #{app_path}, do you need to call builder.build?" unless File.exists? app_path
126
-
127
- #package IPA
128
- cmd = []
129
- cmd << "xcrun"
130
- cmd << "-sdk #{@sdk}" unless @sdk.nil?
131
- cmd << "PackageApplication"
132
- cmd << "-v \"#{app_path}\""
133
- cmd << "-o \"#{ipa_path}\""
134
-
135
- # cmd << "OTHER_CODE_SIGN_FLAGS=\"--keychain #{@keychain.path}\"" unless @keychain.nil?
136
- #
137
- # unless @identity.nil?
138
- # cmd << "--sign \"#{@identity}\""
139
- # end
140
-
141
- unless @profile.nil?
142
- cmd << "--embed \"#{@profile}\""
143
- end
144
-
145
- with_keychain do
146
- Xcode::Shell.execute(cmd)
147
- end
148
-
149
- # package dSYM
150
- cmd = []
151
- cmd << "zip"
152
- cmd << "-r"
153
- cmd << "-T"
154
- cmd << "-y \"#{dsym_zip_path}\""
155
- cmd << "\"#{dsym_path}\""
156
- Xcode::Shell.execute(cmd)
157
-
158
- self
159
- end
160
-
161
- def configuration_build_path
162
- "#{build_path}/#{@config.name}-#{@sdk}"
163
- end
164
-
165
- def entitlements_path
166
- "#{build_path}/#{@target.name}.build/#{name}-#{@target.project.sdk}/#{@target.name}.build/#{@config.product_name}.xcent"
167
- end
168
-
169
- def app_path
170
- "#{configuration_build_path}/#{@config.product_name}.app"
171
- end
172
-
173
- def product_version_basename
174
- version = @config.info_plist.version
175
- version = "SNAPSHOT" if version.nil? or version==""
176
- "#{configuration_build_path}/#{@config.product_name}-#{@config.name}-#{version}"
177
- end
178
-
179
- def ipa_path
180
- "#{product_version_basename}.ipa"
181
- end
182
-
183
- def dsym_path
184
- "#{app_path}.dSYM"
185
- end
186
-
187
- def dsym_zip_path
188
- "#{product_version_basename}.dSYM.zip"
189
- end
190
-
191
-
192
- private
193
-
194
- def with_keychain(&block)
195
- if @keychain.nil?
196
- yield
197
- else
198
- Xcode::Keychains.with_keychain_in_search_path @keychain, &block
199
- end
200
- end
201
-
202
- def install_profile
203
- return nil if @profile.nil?
204
- # TODO: remove other profiles for the same app?
205
- p = ProvisioningProfile.new(@profile)
206
-
207
- ProvisioningProfile.installed_profiles.each do |installed|
208
- if installed.identifiers==p.identifiers and installed.uuid==p.uuid
209
- installed.uninstall
210
- end
211
- end
212
-
213
- p.install
214
- p
215
- end
216
-
217
- def build_command(options = {})
218
- options = {:sdk => @sdk}.merge options
219
- profile = install_profile
220
- cmd = []
221
- cmd << "xcodebuild"
222
- cmd << "-sdk #{options[:sdk]}" unless options[:sdk].nil?
223
- cmd << "-project \"#{@target.project.path}\""
224
-
225
- cmd << "-scheme \"#{@scheme.name}\"" unless @scheme.nil?
226
- cmd << "-target \"#{@target.name}\"" if @scheme.nil?
227
- cmd << "-configuration \"#{@config.name}\"" if @scheme.nil?
228
-
229
- cmd << "OTHER_CODE_SIGN_FLAGS='--keychain #{@keychain.path}'" unless @keychain.nil?
230
- cmd << "CODE_SIGN_IDENTITY=\"#{@identity}\"" unless @identity.nil?
231
- cmd << "OBJROOT=\"#{@objroot}\""
232
- cmd << "SYMROOT=\"#{@symroot}\""
233
- cmd << "PROVISIONING_PROFILE=#{profile.uuid}" unless profile.nil?
234
- cmd
235
- end
236
-
237
- end
238
- end
5
+ require 'xcode/builder/base_builder.rb'
6
+ require 'xcode/builder/project_target_config_builder.rb'
7
+ require 'xcode/builder/scheme_builder.rb'