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 CHANGED
@@ -5,6 +5,7 @@ gem 'builder'
5
5
  gem 'json'
6
6
  gem 'plist'
7
7
  gem 'rest-client'
8
+ gem 'yard'
8
9
 
9
10
  group :test do
10
11
  gem 'rspec'
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  A ruby wrapper around various xcode tools and project, schemes and workspace configuration files
4
4
 
5
+ Full documentation can be found here: http://rayh.github.com/xcoder/
6
+
5
7
  ## Example Usage
6
8
 
7
9
  You will need to install the gem:
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
 
@@ -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.with_properties file_identifier
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
@@ -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.with_properties(file.identifier)
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
- parser
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.build?" unless File.exists? ipa_path
63
- raise "Can't fins #{dsym_zip_path}, do you need to call builder.build?" unless File.exists? dsym_zip_path
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
@@ -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.certificates.first
60
+ builder.identity = @values[:identity] || kc.identities.first
61
61
  builder.keychain = kc
62
62
 
63
63
  puts "[#{label}] CLEAN"
@@ -125,7 +125,7 @@ module Xcode
125
125
  # @see Builder
126
126
  #
127
127
  def builder
128
- puts "Making a Builder with #{self} #{self.methods}"
128
+ #puts "Making a Builder with #{self} #{self.methods}"
129
129
  Xcode::Builder.new(self)
130
130
  end
131
131
 
@@ -41,10 +41,19 @@ module Xcode
41
41
  #
42
42
  # Generate the properties for a system framework.
43
43
  #
44
- # @param [String] name of the system framework
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
- create_child_object FileReference.framework(framework_properties)
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
- create_child_object FileReference.system_framework(name)
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 objects to the registry and add the
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
@@ -10,9 +10,11 @@ module Xcode
10
10
  #
11
11
  # @param [String] the name of the keychain
12
12
  #
13
- def initialize(name)
14
- @name = name
15
- @path = File.expand_path "~/Library/Keychains/#{name}"
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 '#{@path}'"
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 << "#{@name}"
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 << "#{@name}"
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(name, password)
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 << "#{name}"
81
+ cmd << "\"#{path}\""
80
82
  Xcode::Shell.execute(cmd)
81
83
 
82
- Xcode::Keychain.new(name)
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 #{name}"
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.temp_keychain(name, &block)
104
- kc = Xcode::Keychain.create(name, TEMP_PASSWORD)
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.login_keychain
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