xcodeproj 0.11.1 → 0.12.0

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