xcodeproj 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5c359551b32f6801f62a0e83d2a9d682c9f2d3ca
4
- data.tar.gz: e78c1b11fef93c796cbd67f38ee8affd8662d3aa
3
+ metadata.gz: f165be51aaefe9f3f60310905c4a81e9c01d7868
4
+ data.tar.gz: 9f07f26df8ac52efd7b8f7f3f922113d13c2f077
5
5
  SHA512:
6
- metadata.gz: 9d50bcf42f47d040b98ce2d32f707861f159d215d2524b8671f6ccd61e5361f9f1fb1545cbcbf8bbf2cf88b3051eee9e02fd41d76b65c619c1fdedcbd083ff1e
7
- data.tar.gz: 7cdeaca5ded94e74cd365bdb0adf7af3bf3128998792147dfb17ddbcae089b58f16aa70c9d8744dc89364dba601a25454e5c0d65a208aca21846e25e7a3e5f5c
6
+ metadata.gz: e4059f10f78ab4dcd313288657e33684bf535d57a4ae8c6060b044a1e435d1f8d7d57263dcdf80b891b86dd61ce146754302aadf7ac48795858448386b9e056b
7
+ data.tar.gz: d8c324cc0aace1bc07dbcca1996bb8ea269024093b5d4f28139cc36856174201612d8d87d0bd457a5ac27f4b6bc84a40bea62df1c82be768779570da1ece7d0d
@@ -80,7 +80,10 @@ hash_set(const void *keyRef, const void *valueRef, void *hash) {
80
80
  CFTypeID valueType = CFGetTypeID(valueRef);
81
81
  if (valueType == CFStringGetTypeID()) {
82
82
  value = cfstr_to_str(valueRef);
83
-
83
+ } else if (valueRef == kCFBooleanTrue) {
84
+ value = Qtrue;
85
+ } else if (valueRef == kCFBooleanFalse) {
86
+ value = Qfalse;
84
87
  } else if (valueType == CFDictionaryGetTypeID()) {
85
88
  value = rb_hash_new();
86
89
  CFDictionaryApplyFunction(valueRef, hash_set, (void *)value);
@@ -146,7 +149,10 @@ dictionary_set(st_data_t key, st_data_t value, CFMutableDictionaryRef dict) {
146
149
  CFArrayAppendValue((CFMutableArrayRef)valueRef, elementRef);
147
150
  CFRelease(elementRef);
148
151
  }
149
-
152
+ } else if (value == Qtrue) {
153
+ valueRef = kCFBooleanTrue;
154
+ } else if (value == Qfalse) {
155
+ valueRef = kCFBooleanFalse;
150
156
  } else {
151
157
  valueRef = str_to_cfstr(value);
152
158
  }
@@ -6,7 +6,7 @@ module Xcodeproj
6
6
 
7
7
  # @return [String] The last known iOS SDK (stable).
8
8
  #
9
- LAST_KNOWN_IOS_SDK = '6.1'
9
+ LAST_KNOWN_IOS_SDK = '7.0'
10
10
 
11
11
  # @return [String] The last known OS X SDK (stable).
12
12
  #
@@ -70,7 +70,7 @@ module Xcodeproj
70
70
  #
71
71
  FILE_TYPES_BY_EXTENSION = {
72
72
  'a' => 'archive.ar',
73
- 'application' => 'wrapper.application',
73
+ 'app' => 'wrapper.application',
74
74
  'dylib' => 'compiled.mach-o.dylib',
75
75
  'framework' => 'wrapper.framework',
76
76
  'bundle' => 'wrapper.plug-in',
@@ -96,6 +96,16 @@ module Xcodeproj
96
96
  :bundle => 'com.apple.product-type.bundle',
97
97
  }.freeze
98
98
 
99
+ # @return [Hash] The extensions or the various product UTIs.
100
+ #
101
+ PRODUCT_UTI_EXTENSIONS = {
102
+ :application => 'app',
103
+ :framework => 'framework',
104
+ :dynamic_library => 'dylib',
105
+ :static_library => 'a',
106
+ :bundle => 'bundle',
107
+ }.freeze
108
+
99
109
  # @return [Hash] The common build settings grouped by platform, and build
100
110
  # configuration name.
101
111
  #
@@ -152,10 +162,39 @@ module Xcodeproj
152
162
  # @return [Hash] The default build settings for a new project.
153
163
  #
154
164
  PROJECT_DEFAULT_BUILD_SETTINGS = {
165
+ :all => {
166
+ 'ALWAYS_SEARCH_USER_PATHS' => 'NO',
167
+ 'CLANG_CXX_LANGUAGE_STANDARD' => "gnu++0x",
168
+ 'CLANG_CXX_LIBRARY' => "libc++",
169
+ 'CLANG_ENABLE_OBJC_ARC' => 'YES',
170
+ 'CLANG_WARN_BOOL_CONVERSION' => 'YES',
171
+ 'CLANG_WARN_CONSTANT_CONVERSION' => 'YES',
172
+ 'CLANG_WARN_DIRECT_OBJC_ISA_USAGE' => 'YES_ERROR',
173
+ 'CLANG_WARN_EMPTY_BODY' => 'YES',
174
+ 'CLANG_WARN_ENUM_CONVERSION' => 'YES',
175
+ 'CLANG_WARN_INT_CONVERSION' => 'YES',
176
+ 'CLANG_WARN_OBJC_ROOT_CLASS' => 'YES_ERROR',
177
+ 'CLANG_ENABLE_MODULES' => 'YES',
178
+ 'GCC_C_LANGUAGE_STANDARD' => 'gnu99',
179
+ 'GCC_WARN_64_TO_32_BIT_CONVERSION' => 'YES',
180
+ 'GCC_WARN_ABOUT_RETURN_TYPE' => 'YES_ERROR',
181
+ 'GCC_WARN_UNDECLARED_SELECTOR' => 'YES',
182
+ 'GCC_WARN_UNINITIALIZED_AUTOS' => 'YES',
183
+ 'GCC_WARN_UNUSED_FUNCTION' => 'YES',
184
+ 'GCC_WARN_UNUSED_VARIABLE' => 'YES',
185
+ },
155
186
  :release => {
187
+ 'COPY_PHASE_STRIP' => 'NO',
188
+ 'ENABLE_NS_ASSERTIONS' => 'NO',
189
+ 'VALIDATE_PRODUCT' => 'YES',
156
190
  }.freeze,
157
191
  :debug => {
158
- 'ONLY_ACTIVE_ARCH' => 'YES',
192
+ 'ONLY_ACTIVE_ARCH' => 'YES',
193
+ 'COPY_PHASE_STRIP' => 'YES',
194
+ 'GCC_DYNAMIC_NO_PIC' => 'NO',
195
+ 'GCC_OPTIMIZATION_LEVEL' => '0',
196
+ 'GCC_PREPROCESSOR_DEFINITIONS' => ["DEBUG=1", "$(inherited)"],
197
+ 'GCC_SYMBOLS_PRIVATE_EXTERN' => 'NO',
159
198
  }.freeze,
160
199
  }.freeze
161
200
 
@@ -1,6 +1,6 @@
1
1
  module Xcodeproj
2
2
  # The version of the xcodeproj gem.
3
3
  #
4
- VERSION = '0.11.1' unless defined? Xcodeproj::VERSION
4
+ VERSION = '0.12.0' unless defined? Xcodeproj::VERSION
5
5
  end
6
6
 
@@ -84,6 +84,7 @@ module Xcodeproj
84
84
  # Project.open("path/to/Project.xcodeproj")
85
85
  #
86
86
  def self.open(path)
87
+ path = Pathname.pwd + path
87
88
  unless Pathname.new(path).exist?
88
89
  raise "[Xcodeproj] Unable to open `#{path}` because it doesn't exist."
89
90
  end
@@ -605,7 +606,10 @@ module Xcodeproj
605
606
  unless build_configuration_list[name]
606
607
  build_configuration = new(XCBuildConfiguration)
607
608
  build_configuration.name = name
608
- build_configuration.build_settings = Constants::PROJECT_DEFAULT_BUILD_SETTINGS[type].dup
609
+ common_settings = Constants::PROJECT_DEFAULT_BUILD_SETTINGS
610
+ settings = ProjectHelper.deep_dup(common_settings[:all])
611
+ settings.merge!(ProjectHelper.deep_dup(common_settings[type]))
612
+ build_configuration.build_settings = settings
609
613
  build_configuration_list.build_configurations << build_configuration
610
614
  build_configuration
611
615
  end
@@ -613,16 +617,21 @@ module Xcodeproj
613
617
 
614
618
  # Sorts the project.
615
619
  #
620
+ # @param [Hash] options
621
+ # the sorting options.
622
+ # @option options [Symbol] :groups_position
623
+ # the position of the groups can be either `:above` or `:below`.
624
+ #
616
625
  # @return [void]
617
626
  #
618
- def sort
619
- root_object.sort_recursively
627
+ def sort(options = nil)
628
+ root_object.sort_recursively(options)
620
629
  end
621
630
 
622
631
 
623
632
  public
624
633
 
625
- # @!group Helpers
634
+ # @!group Schemes
626
635
  #-------------------------------------------------------------------------#
627
636
 
628
637
  # Get list of shared schemes in project
@@ -640,6 +649,34 @@ module Xcodeproj
640
649
  schemes
641
650
  end
642
651
 
652
+ # Recreates the user schemes of the project from scratch (removes the
653
+ # folder) and optionally hides them.
654
+ #
655
+ # @param [Bool] visible
656
+ # Wether the schemes should be visible or hidden.
657
+ #
658
+ # @return [void]
659
+ #
660
+ def recreate_user_schemes(visible = true)
661
+ schemes_dir = XCScheme.user_data_dir(path)
662
+ FileUtils.rm_rf(schemes_dir)
663
+
664
+ xcschememanagement = {}
665
+ xcschememanagement['SchemeUserState'] = {}
666
+ xcschememanagement['SuppressBuildableAutocreation'] = {}
667
+
668
+ targets.each do |target|
669
+ scheme = XCScheme.new
670
+ scheme.add_build_target(target)
671
+ scheme.save_as(path, target.name, false)
672
+ xcschememanagement['SchemeUserState']["#{target.name}.xcscheme"] = {}
673
+ xcschememanagement['SchemeUserState']["#{target.name}.xcscheme"]['isShown'] = visible
674
+ end
675
+
676
+ xcschememanagement_path = schemes_dir + 'xcschememanagement.plist'
677
+ Xcodeproj.write_plist(xcschememanagement, xcschememanagement_path)
678
+ end
679
+
643
680
  #-------------------------------------------------------------------------#
644
681
 
645
682
  end
@@ -136,7 +136,7 @@ module Xcodeproj
136
136
  # Sorts the to many attributes of the object according to the display
137
137
  # name.
138
138
  #
139
- def sort
139
+ def sort(options = nil)
140
140
  to_many_attributes.each do |attrb|
141
141
  list = attrb.get_value(self)
142
142
  list.sort! do |x, y|
@@ -147,25 +147,33 @@ module Xcodeproj
147
147
 
148
148
  # Sorts the object and the objects that it references.
149
149
  #
150
- # @note Some objects may in turn refer back to objects higher in the
151
- # object tree, which will lead to stack level deep errors. These
152
- # objects should **not** try to perform a recursive sort, also
153
- # because these objects would get sorted through other paths in the
154
- # tree anyways.
150
+ # @param [Hash] options
151
+ # the sorting options.
152
+ # @option options [Symbol] :groups_position
153
+ # the position of the groups can be either `:above` or
154
+ # `:below`.
155
155
  #
156
- # At the time of writing the only known case is `PBXTargetDependency`.
157
- def sort_recursively
156
+ # @note Some objects may in turn refer back to objects higher in the
157
+ # object tree, which will lead to stack level deep errors.
158
+ # These objects should **not** try to perform a recursive sort,
159
+ # also because these objects would get sorted through other
160
+ # paths in the tree anyways.
161
+ #
162
+ # At the time of writing the only known case is
163
+ # `PBXTargetDependency`.
164
+ #
165
+ def sort_recursively(options = nil)
158
166
  to_one_attributes.each do |attrb|
159
167
  value = attrb.get_value(self)
160
- value.sort_recursively if value
168
+ value.sort_recursively(options) if value
161
169
  end
162
170
 
163
171
  to_many_attributes.each do |attrb|
164
172
  list = attrb.get_value(self)
165
- list.each(&:sort_recursively)
173
+ list.each { |entry| entry.sort_recursively(options) }
166
174
  end
167
175
 
168
- sort
176
+ sort(options)
169
177
  end
170
178
 
171
179
  # @!group Reference counting
@@ -52,7 +52,7 @@ module Xcodeproj
52
52
  #
53
53
  # @return [void]
54
54
  #
55
- def sort
55
+ def sort(options = nil)
56
56
  sorted = {}
57
57
  build_settings.keys.sort.each do |key|
58
58
  sorted[key] = build_settings[key]
@@ -43,7 +43,11 @@ module Xcodeproj
43
43
  # user.
44
44
  #
45
45
  def display_name
46
- file_ref.display_name
46
+ if file_ref
47
+ file_ref.display_name
48
+ else
49
+ super
50
+ end
47
51
  end
48
52
 
49
53
  # @return [Hash{String => Hash}, String] A hash suitable to display the
@@ -134,6 +134,13 @@ module Xcodeproj
134
134
  GroupableHelper.parent(self)
135
135
  end
136
136
 
137
+ # @return [Array<PBXGroup, PBXProject>] The list of the parents of the
138
+ # reference.
139
+ #
140
+ def parents
141
+ GroupableHelper.parents(self)
142
+ end
143
+
137
144
  # @return [String] A representation of the reference hierarchy.
138
145
  #
139
146
  def hierarchy_path
@@ -90,6 +90,13 @@ module Xcodeproj
90
90
  GroupableHelper.parent(self)
91
91
  end
92
92
 
93
+ # @return [Array<PBXGroup, PBXProject>] The list of the parents of the
94
+ # group.
95
+ #
96
+ def parents
97
+ GroupableHelper.parents(self)
98
+ end
99
+
93
100
  # @return [String] A representation of the group hierarchy.
94
101
  #
95
102
  def hierarchy_path
@@ -180,6 +187,20 @@ module Xcodeproj
180
187
  result
181
188
  end
182
189
 
190
+ # @return [Array<PBXGroup,PBXFileReference,PBXReferenceProxy>] the
191
+ # recursive list of the children of the group.
192
+ #
193
+ def recursive_children
194
+ result = []
195
+ children.each do |child|
196
+ result << child
197
+ if child.is_a?(PBXGroup)
198
+ result.concat(child.recursive_children)
199
+ end
200
+ end
201
+ result
202
+ end
203
+
183
204
  # @return [Bool] Whether the group is empty.
184
205
  #
185
206
  def empty?
@@ -212,8 +233,8 @@ module Xcodeproj
212
233
  #
213
234
  # @return [PBXFileReference] The new file reference.
214
235
  #
215
- def new_static_library(product_name)
216
- FileReferencesFactory.new_static_library(self, product_name)
236
+ def new_product_ref_for_target(target_name, product_type)
237
+ FileReferencesFactory.new_product_ref_for_target(self, target_name, product_type)
217
238
  end
218
239
 
219
240
  # Creates a file reference to a new bundle.
@@ -342,12 +363,11 @@ module Xcodeproj
342
363
  #
343
364
  # @return [void]
344
365
  #
345
- def recursively_sort_by_type
346
- groups.each { |group| group.recursively_sort_by_type }
366
+ def sort_recursively_by_type
367
+ groups.each { |group| group.sort_recursively_by_type }
347
368
  sort_by_type
348
369
  end
349
370
 
350
-
351
371
  public
352
372
 
353
373
  # @!group AbstractObject Hooks
@@ -369,8 +389,32 @@ module Xcodeproj
369
389
  # Sorts the to many attributes of the object according to the display
370
390
  # name.
371
391
  #
372
- def sort
373
- sort_by_type
392
+ # @param [Hash] options
393
+ # the sorting options.
394
+ # @option options [Symbol] :groups_position
395
+ # the position of the groups can be either `:above` or
396
+ # `:below`.
397
+ #
398
+ # @return [void]
399
+ #
400
+ def sort(options = nil)
401
+ children.sort! do |x, y|
402
+ if options && groups_position = options[:groups_position]
403
+ raise ArgumentError unless [:above, :below].include?(groups_position)
404
+ if x.isa == 'PBXGroup' && !(y.isa == 'PBXGroup')
405
+ next groups_position == :above ? -1 : 1
406
+ elsif !(x.isa == 'PBXGroup') && y.isa == 'PBXGroup'
407
+ next groups_position == :above ? 1 : -1
408
+ end
409
+ end
410
+
411
+ result = File.basename(x.display_name, ".*" ) <=> File.basename(y.display_name, ".*" )
412
+ if result.zero?
413
+ File.extname(x.display_name) <=> File.extname(y.display_name)
414
+ else
415
+ result
416
+ end
417
+ end
374
418
  end
375
419
  end
376
420
 
@@ -44,8 +44,12 @@ module Xcodeproj
44
44
  #
45
45
  # @return [PBXFileReference] The new file reference.
46
46
  #
47
- def new_static_library(group, product_name)
48
- ref = new_reference(group, "lib#{product_name}.a", :built_products)
47
+ def new_product_ref_for_target(group, target_name, product_type)
48
+ if product_type == :static_library
49
+ prefix = 'lib'
50
+ end
51
+ extension = Constants::PRODUCT_UTI_EXTENSIONS[product_type]
52
+ ref = new_reference(group, "#{prefix}#{target_name}.#{extension}", :built_products)
49
53
  ref.include_in_index = '0'
50
54
  ref.set_explicit_file_type
51
55
  ref
@@ -10,8 +10,21 @@ module Xcodeproj
10
10
  # @return [PBXGroup, PBXProject] The parent of the object.
11
11
  #
12
12
  def parent(object)
13
- check_parents_integrity(object)
14
- object.referrers.first
13
+ referrers = object.referrers.uniq
14
+ if referrers.count > 1
15
+ referrers = referrers.select{ |obj| obj.isa == 'PBXGroup' }
16
+ end
17
+
18
+ if referrers.count == 0
19
+ raise "[Xcodeproj] Consistency issue: no parent " \
20
+ "for object `#{object.display_name}`: "\
21
+ "`#{object.referrers.join('`, `')}`"
22
+ elsif referrers.count > 1
23
+ raise "[Xcodeproj] Consistency issue: unexpected multiple parents " \
24
+ "for object `#{object.display_name}`: "\
25
+ "#{object.referrers}"
26
+ end
27
+ referrers.first
15
28
  end
16
29
 
17
30
  # @param [PBXGroup, PBXFileReference] object
@@ -187,28 +200,6 @@ module Xcodeproj
187
200
  # @group Helpers
188
201
  #-------------------------------------------------------------------#
189
202
 
190
- # Checks whether there is a single identifiable parent and raises
191
- # otherwise.
192
- #
193
- # @return [void]
194
- #
195
- def check_parents_integrity(object)
196
- referrers_count = object.referrers.uniq.count
197
- if referrers_count > 1
198
- referrers_count = object.referrers.select{ |obj| obj.isa == 'PBXGroup' }.count
199
- end
200
-
201
- if referrers_count == 0
202
- raise "[Xcodeproj] Consistency issue: no parent " \
203
- "for object `#{object.display_name}`: "\
204
- "`#{object.referrers.join('`, `')}`"
205
- elsif referrers_count > 1
206
- raise "[Xcodeproj] Consistency issue: unexpected multiple parents " \
207
- "for object `#{object.display_name}`: "\
208
- "#{object.referrers}"
209
- end
210
- end
211
-
212
203
  # Converts the given source tree to its string value.
213
204
  #
214
205
  # @param [Symbol, String] source_tree
@@ -52,6 +52,12 @@ module Xcodeproj
52
52
  end
53
53
  end
54
54
 
55
+ # @return [String] the version of the SDK.
56
+ #
57
+ def sdk_version
58
+ sdk.scan(/[0-9.]+/).first
59
+ end
60
+
55
61
  # @return [String] the deployment target of the target according to its
56
62
  # platform.
57
63
  #
@@ -192,13 +198,35 @@ module Xcodeproj
192
198
  # @param [Array<String>, String] name
193
199
  # The name or the list of the names of the framework.
194
200
  #
201
+ # @note Xcode behaviour is following: if the target has the same SDK
202
+ # of the project it adds the reference relative to the SDK root
203
+ # otherwise the reference is added relative to the Developer
204
+ # directory. This can create confusion or duplication of the
205
+ # references of frameworks linked by iOS and OS X targets. For
206
+ # this reason the new Xcodeproj behaviour is to add the
207
+ # frameworks in a subgroup according to the platform.
208
+ #
195
209
  # @return [void]
196
210
  #
197
211
  def add_system_framework(names)
198
212
  Array(names).each do |name|
199
- path = "System/Library/Frameworks/#{name}.framework"
200
- unless ref = project.frameworks_group.find_file_by_path(path)
201
- ref = project.frameworks_group.new_file(path, :sdk_root)
213
+
214
+ case platform_name
215
+ when :ios
216
+ group = project.frameworks_group['iOS'] || project.frameworks_group.new_group('iOS')
217
+ path_sdk_name = 'iPhoneOS'
218
+ path_sdk_version = sdk_version || Constants::LAST_KNOWN_IOS_SDK
219
+ when :osx
220
+ group = project.frameworks_group['OS X'] || project.frameworks_group.new_group('OS X')
221
+ path_sdk_name = 'MacOSX'
222
+ path_sdk_version = sdk_version || Constants::LAST_KNOWN_OSX_SDK
223
+ else
224
+ raise "Unknown platform for target"
225
+ end
226
+
227
+ path = "Platforms/#{path_sdk_name}.platform/Developer/SDKs/#{path_sdk_name}#{path_sdk_version}.sdk/System/Library/Frameworks/#{name}.framework"
228
+ unless ref = group.find_file_by_path(path)
229
+ ref = group.new_file(path, :developer_dir)
202
230
  end
203
231
  frameworks_build_phase.add_file_reference(ref, true)
204
232
  ref
@@ -259,7 +287,7 @@ module Xcodeproj
259
287
 
260
288
  # @return [String] the build product type identifier.
261
289
  #
262
- attribute :product_type, String, 'com.apple.product-type.library.static'
290
+ attribute :product_type, String
263
291
 
264
292
  # @return [PBXFileReference] the reference to the product file.
265
293
  #
@@ -284,6 +312,13 @@ module Xcodeproj
284
312
  # @!group Helpers
285
313
  #--------------------------------------#
286
314
 
315
+ # @return [Symbol] The type of the target expressed as a symbol.
316
+ #
317
+ def symbol_type
318
+ pair = Constants::PRODUCT_TYPE_UTI.find { |key, value| value == product_type }
319
+ pair.first
320
+ end
321
+
287
322
  # Adds source files to the target.
288
323
  #
289
324
  # @param [Array<PBXFileReference>] file_references
@@ -409,7 +444,7 @@ module Xcodeproj
409
444
  #
410
445
  # Build phases are not sorted as they order is relevant.
411
446
  #
412
- def sort
447
+ def sort(options = nil)
413
448
  attributes_to_sort = to_many_attributes.reject { |attr| attr.name == :build_phases }
414
449
  attributes_to_sort.each do |attrb|
415
450
  list = attrb.get_value(self)
@@ -47,7 +47,7 @@ module Xcodeproj
47
47
  #
48
48
  # @see AbstractObject#sort_recursively
49
49
  #
50
- def sort_recursively
50
+ def sort_recursively(options = nil)
51
51
  end
52
52
  end
53
53
  end
@@ -46,7 +46,7 @@ module Xcodeproj
46
46
  target.build_configuration_list = configuration_list(project, platform, deployment_target)
47
47
 
48
48
  # Product
49
- product = product_group.new_static_library(name)
49
+ product = product_group.new_product_ref_for_target(name, type)
50
50
  target.product_reference = product
51
51
 
52
52
  # Build phases
@@ -13,152 +13,138 @@ module Xcodeproj
13
13
  #
14
14
  attr_reader :doc
15
15
 
16
- # @return [String] the name of the container (the project name file without
17
- # the extension) that have the targets used by the scheme.
18
- #
19
- attr_reader :container
20
-
21
- # @return [Xcodeproj::Project::Object::AbstractTarget] the target used by
22
- # scheme in the build step.
23
- #
24
- attr_reader :build_target
25
-
26
- # @return [Xcodeproj::Project::Object::AbstractTarget] the target used by
27
- # scheme in the test step.
28
- #
29
- attr_reader :test_target
30
-
31
16
  # Create a new XCScheme instance
32
17
  #
33
- # @param [String] container
34
- # The name of the container (the project name file without the extension) that have the targets used by the
35
- # scheme.
36
- #
37
- # @param [Xcodeproj::Project::Object::AbstractTarget] build_target
38
- # The target used by scheme in the build step.
39
- #
40
- # @param [Xcodeproj::Project::Object::AbstractTarget] test_target
41
- # The target used by scheme in the test step.
42
- #
43
- # @example
44
- # Xcodeproj::XCScheme.new 'Cocoa Application', project.targets[0], project.targets[1]
45
- #
46
- def initialize(container, build_target, test_target = nil)
47
- @container = container
48
- @build_target = build_target
49
- @test_target = test_target
50
-
18
+ def initialize
51
19
  @doc = REXML::Document.new
52
20
  @doc << REXML::XMLDecl.new(REXML::XMLDecl::DEFAULT_VERSION, 'UTF-8')
53
21
  @doc.context[:attribute_quote] = :quote
54
22
 
55
- scheme = @doc.add_element 'Scheme'
56
- scheme.attributes['LastUpgradeVersion'] = Constants::LAST_UPGRADE_CHECK
57
- scheme.attributes['version'] = '1.3'
58
-
59
- build_action = scheme.add_element 'BuildAction'
60
- build_action.attributes['parallelizeBuildables'] = 'YES'
61
- build_action.attributes['buildImplicitDependencies'] = 'YES'
62
-
63
- if (build_target.product_type == 'com.apple.product-type.application') then
64
- build_action_entries = build_action.add_element 'BuildActionEntries'
65
-
66
- build_action_entry = build_action_entries.add_element 'BuildActionEntry'
67
- build_action_entry.attributes['buildForTesting'] = 'YES'
68
- build_action_entry.attributes['buildForRunning'] = 'YES'
69
- build_action_entry.attributes['buildForProfiling'] = 'YES'
70
- build_action_entry.attributes['buildForArchiving'] = 'YES'
71
- build_action_entry.attributes['buildForAnalyzing'] = 'YES'
72
-
73
- buildable_reference = build_action_entry.add_element 'BuildableReference'
74
- buildable_reference.attributes['BuildableIdentifier'] = 'primary'
75
- buildable_reference.attributes['BlueprintIdentifier'] = build_target.uuid
76
- buildable_reference.attributes['BuildableName'] = "#{build_target.name}.app"
77
- buildable_reference.attributes['BlueprintName'] = build_target.name
78
- buildable_reference.attributes['ReferencedContainer'] = "container:#{container}.xcodeproj"
79
- end
80
-
81
- test_action = scheme.add_element 'TestAction'
82
- test_action.attributes['selectedDebuggerIdentifier'] = 'Xcode.DebuggerFoundation.Debugger.LLDB'
83
- test_action.attributes['selectedLauncherIdentifier'] = 'Xcode.DebuggerFoundation.Launcher.LLDB'
84
- test_action.attributes['shouldUseLaunchSchemeArgsEnv'] = 'YES'
85
- test_action.attributes['buildConfiguration'] = 'Debug'
86
-
87
- testables = test_action.add_element 'Testables'
88
-
89
- if (test_target != nil) then
90
- testable_reference = testables.add_element 'TestableReference'
91
- testable_reference.attributes['skipped'] = 'NO'
92
-
93
- buildable_reference = testable_reference.add_element 'BuildableReference'
94
- buildable_reference.attributes['BuildableIdentifier'] = 'primary'
95
- buildable_reference.attributes['BlueprintIdentifier'] = test_target.uuid
96
- buildable_reference.attributes['BuildableName'] = "#{test_target.name}.octest"
97
- buildable_reference.attributes['BlueprintName'] = test_target.name
98
- buildable_reference.attributes['ReferencedContainer'] = "container:#{container}.xcodeproj"
99
-
100
- if (build_target.product_type == 'com.apple.product-type.application') then
101
- macro_expansion = test_action.add_element 'MacroExpansion'
102
-
103
- buildable_reference = macro_expansion.add_element 'BuildableReference'
104
- buildable_reference.attributes['BuildableIdentifier'] = 'primary'
105
- buildable_reference.attributes['BlueprintIdentifier'] = build_target.uuid
106
- buildable_reference.attributes['BuildableName'] = "#{build_target.name}.app"
107
- buildable_reference.attributes['BlueprintName'] = build_target.name
108
- buildable_reference.attributes['ReferencedContainer'] = "container:#{container}.xcodeproj"
109
- end
110
- end
111
-
112
- launch_action = scheme.add_element 'LaunchAction'
113
- launch_action.attributes['selectedDebuggerIdentifier'] = 'Xcode.DebuggerFoundation.Debugger.LLDB'
114
- launch_action.attributes['selectedLauncherIdentifier'] = 'Xcode.DebuggerFoundation.Launcher.LLDB'
115
- launch_action.attributes['launchStyle'] = '0'
116
- launch_action.attributes['useCustomWorkingDirectory'] = 'NO'
117
- launch_action.attributes['buildConfiguration'] = 'Debug'
118
- launch_action.attributes['ignoresPersistentStateOnLaunch'] = 'NO'
119
- launch_action.attributes['debugDocumentVersioning'] = 'YES'
120
- launch_action.attributes['allowLocationSimulation'] = 'YES'
121
-
122
- if (build_target.product_type == 'com.apple.product-type.application') then
123
- buildable_product_runnable = launch_action.add_element 'BuildableProductRunnable'
124
-
125
- buildable_reference = buildable_product_runnable.add_element 'BuildableReference'
126
- buildable_reference.attributes['BuildableIdentifier'] = 'primary'
127
- buildable_reference.attributes['BlueprintIdentifier'] = build_target.uuid
128
- buildable_reference.attributes['BuildableName'] = "#{build_target.name}.app"
129
- buildable_reference.attributes['BlueprintName'] = build_target.name
130
- buildable_reference.attributes['ReferencedContainer'] = "container:#{container}.xcodeproj"
131
- end
23
+ @scheme = @doc.add_element 'Scheme'
24
+ @scheme.attributes['LastUpgradeVersion'] = Constants::LAST_UPGRADE_CHECK
25
+ @scheme.attributes['version'] = '1.3'
26
+
27
+ @build_action = @scheme.add_element 'BuildAction'
28
+ @build_action.attributes['parallelizeBuildables'] = 'YES'
29
+ @build_action.attributes['buildImplicitDependencies'] = 'YES'
30
+ @build_action_entries = nil
31
+
32
+ @test_action = @scheme.add_element 'TestAction'
33
+ @test_action.attributes['selectedDebuggerIdentifier'] = 'Xcode.DebuggerFoundation.Debugger.LLDB'
34
+ @test_action.attributes['selectedLauncherIdentifier'] = 'Xcode.DebuggerFoundation.Launcher.LLDB'
35
+ @test_action.attributes['shouldUseLaunchSchemeArgsEnv'] = 'YES'
36
+ @test_action.attributes['buildConfiguration'] = 'Debug'
37
+
38
+ @testables = @test_action.add_element 'Testables'
39
+
40
+ @launch_action = @scheme.add_element 'LaunchAction'
41
+ @launch_action.attributes['selectedDebuggerIdentifier'] = 'Xcode.DebuggerFoundation.Debugger.LLDB'
42
+ @launch_action.attributes['selectedLauncherIdentifier'] = 'Xcode.DebuggerFoundation.Launcher.LLDB'
43
+ @launch_action.attributes['launchStyle'] = '0'
44
+ @launch_action.attributes['useCustomWorkingDirectory'] = 'NO'
45
+ @launch_action.attributes['buildConfiguration'] = 'Debug'
46
+ @launch_action.attributes['ignoresPersistentStateOnLaunch'] = 'NO'
47
+ @launch_action.attributes['debugDocumentVersioning'] = 'YES'
48
+ @launch_action.attributes['allowLocationSimulation'] = 'YES'
49
+ additional_options = @launch_action.add_element 'AdditionalOptions'
50
+
51
+ @profile_action = @scheme.add_element 'ProfileAction'
52
+ @profile_action.attributes['shouldUseLaunchSchemeArgsEnv'] = 'YES'
53
+ @profile_action.attributes['savedToolIdentifier'] = ''
54
+ @profile_action.attributes['useCustomWorkingDirectory'] = 'NO'
55
+ @profile_action.attributes['buildConfiguration'] = 'Release'
56
+ @profile_action.attributes['debugDocumentVersioning'] = 'YES'
57
+
58
+ analyze_action = @scheme.add_element 'AnalyzeAction'
59
+ analyze_action.attributes['buildConfiguration'] = 'Debug'
132
60
 
133
- additional_options = launch_action.add_element 'AdditionalOptions'
61
+ archive_action = @scheme.add_element 'ArchiveAction'
62
+ archive_action.attributes['buildConfiguration'] = 'Release'
63
+ archive_action.attributes['revealArchiveInOrganizer'] = 'YES'
64
+ end
134
65
 
135
- profile_action = scheme.add_element 'ProfileAction'
136
- profile_action.attributes['shouldUseLaunchSchemeArgsEnv'] = 'YES'
137
- profile_action.attributes['savedToolIdentifier'] = ''
138
- profile_action.attributes['useCustomWorkingDirectory'] = 'NO'
139
- profile_action.attributes['buildConfiguration'] = 'Release'
140
- profile_action.attributes['debugDocumentVersioning'] = 'YES'
66
+ public
141
67
 
142
- if (build_target.product_type == 'com.apple.product-type.application') then
143
- buildable_product_runnable = profile_action.add_element 'BuildableProductRunnable'
68
+ # @!group Target methods
144
69
 
145
- buildable_reference = buildable_product_runnable.add_element 'BuildableReference'
146
- buildable_reference.attributes['BuildableIdentifier'] = 'primary'
147
- buildable_reference.attributes['BlueprintIdentifier'] = build_target.uuid
148
- buildable_reference.attributes['BuildableName'] = "#{build_target.name}.app"
149
- buildable_reference.attributes['BlueprintName'] = build_target.name
150
- buildable_reference.attributes['ReferencedContainer'] = "container:#{container}.xcodeproj"
70
+ # Add a target to the list of targets to build in the build action.
71
+ #
72
+ # @param [Xcodeproj::Project::Object::AbstractTarget] build_target
73
+ # A target used by scheme in the build step.
74
+ #
75
+ # @param [Bool] build_for_running
76
+ # Whether to build this target in the launch action. Often false for test targets.
77
+ #
78
+ def add_build_target(build_target, build_for_running = true)
79
+ if !@build_action_entries then
80
+ @build_action_entries = @build_action.add_element 'BuildActionEntries'
151
81
  end
152
82
 
153
- analyze_action = scheme.add_element 'AnalyzeAction'
154
- analyze_action.attributes['buildConfiguration'] = 'Debug'
83
+ build_action_entry = @build_action_entries.add_element 'BuildActionEntry'
84
+ build_action_entry.attributes['buildForTesting'] = 'YES'
85
+ build_action_entry.attributes['buildForRunning'] = build_for_running ? 'YES' : 'NO'
86
+ build_action_entry.attributes['buildForProfiling'] = 'YES'
87
+ build_action_entry.attributes['buildForArchiving'] = 'YES'
88
+ build_action_entry.attributes['buildForAnalyzing'] = 'YES'
89
+
90
+ buildable_reference = build_action_entry.add_element 'BuildableReference'
91
+ buildable_reference.attributes['BuildableIdentifier'] = 'primary'
92
+ buildable_reference.attributes['BlueprintIdentifier'] = build_target.uuid
93
+ buildable_reference.attributes['BuildableName'] = File.basename(build_target.product_reference.path)
94
+ buildable_reference.attributes['BlueprintName'] = build_target.name
95
+ buildable_reference.attributes['ReferencedContainer'] = "container:#{build_target.project.path.basename}"
96
+ end
155
97
 
156
- archive_action = scheme.add_element 'ArchiveAction'
157
- archive_action.attributes['buildConfiguration'] = 'Release'
158
- archive_action.attributes['revealArchiveInOrganizer'] = 'YES'
98
+ # Add a target to the list of targets to build in the build action.
99
+ #
100
+ # @param [Xcodeproj::Project::Object::AbstractTarget] test_target
101
+ # A target used by scheme in the test step.
102
+ #
103
+ def add_test_target(test_target)
104
+ testable_reference = @testables.add_element 'TestableReference'
105
+ testable_reference.attributes['skipped'] = 'NO'
106
+
107
+ buildable_reference = testable_reference.add_element 'BuildableReference'
108
+ buildable_reference.attributes['BuildableIdentifier'] = 'primary'
109
+ buildable_reference.attributes['BlueprintIdentifier'] = test_target.uuid
110
+ buildable_reference.attributes['BuildableName'] = "#{test_target.name}.octest"
111
+ buildable_reference.attributes['BlueprintName'] = test_target.name
112
+ buildable_reference.attributes['ReferencedContainer'] = "container:#{test_target.project.path.basename}"
159
113
  end
160
114
 
161
- public
115
+ # Sets a runnable target target to be the target of the launch action of the scheme.
116
+ #
117
+ # @param [Xcodeproj::Project::Object::AbstractTarget] build_target
118
+ # A target used by scheme in the launch step.
119
+ #
120
+ def set_launch_target(build_target)
121
+ launch_product_runnable = @launch_action.add_element 'BuildableProductRunnable'
122
+
123
+ launch_buildable_reference = launch_product_runnable.add_element 'BuildableReference'
124
+ launch_buildable_reference.attributes['BuildableIdentifier'] = 'primary'
125
+ launch_buildable_reference.attributes['BlueprintIdentifier'] = build_target.uuid
126
+ launch_buildable_reference.attributes['BuildableName'] = "#{build_target.name}.app"
127
+ launch_buildable_reference.attributes['BlueprintName'] = build_target.name
128
+ launch_buildable_reference.attributes['ReferencedContainer'] = "container:#{build_target.project.path.basename}"
129
+
130
+ profile_product_runnable = @profile_action.add_element 'BuildableProductRunnable'
131
+
132
+ profile_buildable_reference = profile_product_runnable.add_element 'BuildableReference'
133
+ profile_buildable_reference.attributes['BuildableIdentifier'] = 'primary'
134
+ profile_buildable_reference.attributes['BlueprintIdentifier'] = build_target.uuid
135
+ profile_buildable_reference.attributes['BuildableName'] = "#{build_target.name}.app"
136
+ profile_buildable_reference.attributes['BlueprintName'] = build_target.name
137
+ profile_buildable_reference.attributes['ReferencedContainer'] = "container:#{build_target.project.path.basename}"
138
+
139
+ macro_expansion = @test_action.add_element 'MacroExpansion'
140
+
141
+ buildable_reference = macro_expansion.add_element 'BuildableReference'
142
+ buildable_reference.attributes['BuildableIdentifier'] = 'primary'
143
+ buildable_reference.attributes['BlueprintIdentifier'] = build_target.uuid
144
+ buildable_reference.attributes['BuildableName'] = File.basename(build_target.product_reference.path)
145
+ buildable_reference.attributes['BlueprintName'] = build_target.name
146
+ buildable_reference.attributes['ReferencedContainer'] = "container:#{build_target.project.path.basename}"
147
+ end
162
148
 
163
149
  # @!group Class methods
164
150
 
@@ -201,84 +187,24 @@ module Xcodeproj
201
187
 
202
188
  public
203
189
 
204
- # @!group
205
-
206
- #-------------------------------------------------------------------------#
207
-
208
- # Returns the current value if the build target must be runned during the
209
- # build step.
210
- #
211
- # @return [Boolean]
212
- # true => run during the build step
213
- # false => not run during the build step
214
- #
215
- def build_target_for_running?
216
- build_target_for_running = ''
217
-
218
- if build_action = @doc.root.elements['BuildAction']
219
- if build_action_entries = build_action.elements['BuildActionEntries']
220
- if build_action_entry = build_action_entries.elements['BuildActionEntry']
221
- build_target_for_running = build_action_entry.attributes['buildForRunning']
222
- end
223
- end
224
- end
225
-
226
- build_target_for_running == 'YES'
227
- end
228
-
229
- # Set the build target to run or not run during the build step. Useful for
230
- # cases where the build target is a unit test bundle.
231
- #
232
- # @param [Boolean] build_target_for_running
233
- # true => run during the build step
234
- # false => not run during the build step
235
- #
236
- def build_target_for_running=(build_target_for_running)
237
- build_action = @doc.root.elements['BuildAction']
238
-
239
- if (build_action.elements['BuildActionEntries'] == nil) then
240
- build_action_entries = build_action.add_element('BuildActionEntries')
241
- else
242
- build_action_entries = build_action.elements['BuildActionEntries']
243
- end
244
-
245
- if (build_action_entries.elements['BuildActionEntry'] == nil) then
246
- build_action_entry = build_action_entries.add_element 'BuildActionEntry'
247
- build_action_entry.attributes['buildForTesting'] = 'YES'
248
- build_action_entry.attributes['buildForProfiling'] = 'NO'
249
- build_action_entry.attributes['buildForArchiving'] = 'NO'
250
- build_action_entry.attributes['buildForAnalyzing'] = 'NO'
251
- else
252
- build_action_entry = build_action_entries.elements['BuildActionEntry']
253
- end
254
-
255
- build_action_entry.attributes['buildForRunning'] = build_target_for_running ? 'YES' : 'NO'
256
-
257
- if (build_action_entry.elements['BuildableReference'] == nil) then
258
- buildable_reference = build_action_entry.add_element 'BuildableReference'
259
- buildable_reference.attributes['BuildableIdentifier'] = 'primary'
260
- buildable_reference.attributes['BlueprintIdentifier'] = build_target.uuid
261
- buildable_reference.attributes['BuildableName'] = "#{build_target.name}.octest"
262
- buildable_reference.attributes['BlueprintName'] = build_target.name
263
- buildable_reference.attributes['ReferencedContainer'] = "container:#{container}.xcodeproj"
264
- end
265
- end
266
-
267
- public
268
-
269
190
  # @!group Serialization
270
191
 
271
192
  #-------------------------------------------------------------------------#
272
193
 
273
194
  # Serializes the current state of the object to a String.
274
195
  #
196
+ # @note The goal of the string representation is to match Xcode output as
197
+ # close as possible to aide comparison.
198
+ #
275
199
  # @return [String] the XML string value of the current state of the object.
276
200
  #
277
201
  def to_s
278
- formatter = REXML::Formatters::Pretty.new(2)
279
- formatter.compact = true
202
+ formatter = XML_Fromatter.new(2)
203
+ formatter.compact = false
280
204
  out = ''
281
205
  formatter.write(@doc, out)
206
+ out.gsub!("<?xml version='1.0' encoding='UTF-8'?>", '<?xml version="1.0" encoding="UTF-8"?>')
207
+ out << "\n"
282
208
  out
283
209
  end
284
210
 
@@ -287,6 +213,9 @@ module Xcodeproj
287
213
  # @param [String, Pathname] project_path
288
214
  # The path where the ".xcscheme" file should be stored.
289
215
  #
216
+ # @param [String] name
217
+ # The name of the scheme, to have ".xcscheme" appended.
218
+ #
290
219
  # @param [Boolean] shared
291
220
  # true => if the scheme must be a shared scheme (default value)
292
221
  # false => if the scheme must be a user scheme
@@ -296,14 +225,14 @@ module Xcodeproj
296
225
  # @example Saving a scheme
297
226
  # scheme.save_as('path/to/Project.xcodeproj') #=> true
298
227
  #
299
- def save_as(project_path, shared = true)
228
+ def save_as(project_path, name, shared = true)
300
229
  if shared
301
230
  scheme_folder_path = self.class.shared_data_dir(project_path)
302
231
  else
303
232
  scheme_folder_path = self.class.user_data_dir(project_path)
304
233
  end
305
234
  scheme_folder_path.mkpath
306
- scheme_path = scheme_folder_path + "#{build_target.name}.xcscheme"
235
+ scheme_path = scheme_folder_path + "#{name}.xcscheme"
307
236
  File.open(scheme_path, 'w') do |f|
308
237
  f.write(to_s)
309
238
  end
@@ -311,5 +240,36 @@ module Xcodeproj
311
240
 
312
241
  #-------------------------------------------------------------------------#
313
242
 
243
+ # XML formatter which closely mimics the output generated by Xcode.
244
+ #
245
+ class XML_Fromatter < REXML::Formatters::Pretty
246
+ def write_element(node, output)
247
+ @indentation = 3
248
+ output << ' '*@level
249
+ output << "<#{node.expanded_name}"
250
+
251
+ @level += @indentation
252
+ node.attributes.each_attribute do |attr|
253
+ output << "\n"
254
+ output << ' '*@level
255
+ output << attr.to_string.gsub(/=/, ' = ')
256
+ end unless node.attributes.empty?
257
+
258
+ output << ">"
259
+
260
+ output << "\n"
261
+ node.children.each { |child|
262
+ next if child.kind_of?(REXML::Text) and child.to_s.strip.length == 0
263
+ write(child, output)
264
+ output << "\n"
265
+ }
266
+ @level -= @indentation
267
+ output << ' '*@level
268
+ output << "</#{node.expanded_name}>"
269
+ end
270
+ end
271
+
272
+ #-------------------------------------------------------------------------#
273
+
314
274
  end
315
275
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcodeproj
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eloy Duran
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-21 00:00:00.000000000 Z
11
+ date: 2013-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport