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 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