xcodeproj 1.3.3 → 1.4.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: 04c4429d5bd1901ac79b9057825d4506a3d4677a
4
- data.tar.gz: 41170f0792b8529c15600b5837f94949f0114cfb
3
+ metadata.gz: c1d9e25f8e263946cf8049c3fd87d32eb60774e2
4
+ data.tar.gz: 1aa69336dac41f7c9192ee45b11157bf2d6ab372
5
5
  SHA512:
6
- metadata.gz: bd83e86802491f25727e5ea74b1ff9d4edab9cb183254cb89482dd92998bc6ef96051d7a2f43be7d51e1e9dd5d635950d3c61f95e8dc253696b9b43112516553
7
- data.tar.gz: 549778943ec9f0d3a9cea8277be5fe90b71b16d5c9404c17917a66caa5a49430bceedd652ccb30244189855aecc96ccb83f60aa52a773f639cdb95eafb4ed42a
6
+ metadata.gz: c7ddb7c072f0d6ccf2af6bbb5dd1c6093007986edd5f91802ea4d304dcf373d0385a161ae74584b99de9ffa06f37364c39435cb96cb6ba6dbae5b1c597452058
7
+ data.tar.gz: 01eff04f86c6cfe00adea390ef346c0a2650447dd8a324b624ac3d070a54329afa6b2a20cbb217b24d0a318e62db6193eb10aa22f9ebf9c16b85928fcd75dae7
@@ -1,5 +1,5 @@
1
1
  module Xcodeproj
2
2
  # The version of the xcodeproj gem.
3
3
  #
4
- VERSION = '1.3.3'.freeze unless defined? Xcodeproj::VERSION
4
+ VERSION = '1.4.0'.freeze unless defined? Xcodeproj::VERSION
5
5
  end
@@ -1,10 +1,10 @@
1
+ autoload :Nanaimo, 'nanaimo'
2
+ autoload :CFPropertyList, 'cfpropertylist'
3
+
1
4
  module Xcodeproj
2
5
  # Provides support for loading and serializing property list files.
3
6
  #
4
7
  module Plist
5
- autoload :FFI, 'xcodeproj/plist/ffi'
6
- autoload :PlistGem, 'xcodeproj/plist/plist_gem'
7
-
8
8
  # @return [Hash] Returns the native objects loaded from a property list
9
9
  # file.
10
10
  #
@@ -16,10 +16,16 @@ module Xcodeproj
16
16
  unless File.exist?(path)
17
17
  raise Informative, "The plist file at path `#{path}` doesn't exist."
18
18
  end
19
- if file_in_conflict?(path)
19
+ contents = File.read(path)
20
+ if file_in_conflict?(contents)
20
21
  raise Informative, "The file `#{path}` is in a merge conflict."
21
22
  end
22
- implementation.read_from_path(path)
23
+ case Nanaimo::Reader.plist_type(contents)
24
+ when :xml, :binary
25
+ CFPropertyList.native_types(CFPropertyList::List.new(:data => contents).value)
26
+ else
27
+ Nanaimo::Reader.new(contents).parse!.as_ruby
28
+ end
23
29
  end
24
30
 
25
31
  # Serializes a hash as an XML property list file.
@@ -43,47 +49,39 @@ module Xcodeproj
43
49
  end
44
50
  path = path.to_s
45
51
  raise IOError, 'Empty path.' if path.empty?
46
- implementation.write_to_path(hash, path)
52
+
53
+ File.open(path, 'w') do |f|
54
+ plist = Nanaimo::Plist.new(hash, :xml)
55
+ Nanaimo::Writer::XMLWriter.new(plist, true, f).write
56
+ end
47
57
  end
48
58
 
49
59
  # The known modules that can serialize plists.
50
60
  #
51
- KNOWN_IMPLEMENTATIONS = [:FFI, :PlistGem]
61
+ KNOWN_IMPLEMENTATIONS = []
52
62
 
53
63
  class << self
54
- # @return The module used to implement plist serialization.
64
+ # @deprecated This method will be removed in 2.0
65
+ #
66
+ # @return [Nil]
55
67
  #
56
68
  attr_accessor :implementation
57
- def implementation
58
- @implementation ||= autoload_implementation
59
- end
60
69
  end
61
70
 
62
- # Attempts to autoload a known plist implementation.
71
+ # @deprecated This method will be removed in 2.0
63
72
  #
64
- # @return a successfully loaded plist serialization implementation.
73
+ # @return [Nil]
65
74
  #
66
75
  def self.autoload_implementation
67
- failures = KNOWN_IMPLEMENTATIONS.map do |impl|
68
- begin
69
- impl = Plist.const_get(impl)
70
- failure = impl.attempt_to_load!
71
- return impl if failure.nil?
72
- failure
73
- rescue NameError, LoadError => e
74
- e.message
75
- end
76
- end.compact
77
- raise Informative, "Unable to load a plist implementation:\n\n#{failures.join("\n\n")}"
78
76
  end
79
77
 
80
78
  # @return [Bool] Checks whether there are merge conflicts in the file.
81
79
  #
82
80
  # @param [#to_s] path
83
- # The path of the file.
81
+ # The contents of the file.
84
82
  #
85
- def self.file_in_conflict?(path)
86
- File.read(path).match(/^(<|=|>){7}/)
83
+ def self.file_in_conflict?(contents)
84
+ contents.match(/^(<|=|>){7}/)
87
85
  end
88
86
  end
89
87
  end
@@ -277,6 +277,24 @@ module Xcodeproj
277
277
  plist
278
278
  end
279
279
 
280
+ def to_ascii_plist
281
+ plist = {}
282
+ objects_dictionary = {}
283
+ objects
284
+ .sort_by { |o| [o.isa, o.uuid] }
285
+ .each do |obj|
286
+ key = Nanaimo::String.new(obj.uuid, obj.ascii_plist_annotation)
287
+ value = obj.to_ascii_plist.tap { |a| a.annotation = nil }
288
+ objects_dictionary[key] = value
289
+ end
290
+ plist['archiveVersion'] = archive_version.to_s
291
+ plist['classes'] = classes
292
+ plist['objectVersion'] = object_version.to_s
293
+ plist['objects'] = objects_dictionary
294
+ plist['rootObject'] = Nanaimo::String.new(root_object.uuid, root_object.ascii_plist_annotation)
295
+ Nanaimo::Plist.new.tap { |p| p.root_object = plist }
296
+ end
297
+
280
298
  # Converts the objects tree to a hash substituting the hash
281
299
  # of the referenced to their UUID reference. As a consequence the hash of
282
300
  # an object might appear multiple times and the information about their
@@ -332,7 +350,7 @@ module Xcodeproj
332
350
  @dirty = false if save_path == path
333
351
  FileUtils.mkdir_p(save_path)
334
352
  file = File.join(save_path, 'project.pbxproj')
335
- Plist.write_to_path(to_hash, file)
353
+ File.open(file, 'w') { |f| Nanaimo::XcodeProjectWriter.new(to_ascii_plist, true, f).write }
336
354
  end
337
355
 
338
356
  # Marks the project as dirty, that is, modified from what is on disk.
@@ -373,6 +373,10 @@ module Xcodeproj
373
373
  # array.
374
374
  #
375
375
  def to_hash
376
+ to_hash_as
377
+ end
378
+
379
+ def to_hash_as(method = :to_hash)
376
380
  plist = {}
377
381
  plist['isa'] = isa
378
382
 
@@ -383,21 +387,39 @@ module Xcodeproj
383
387
 
384
388
  to_one_attributes.each do |attrb|
385
389
  obj = attrb.get_value(self)
386
- plist[attrb.plist_name] = obj.uuid if obj
390
+ plist[attrb.plist_name] = nested_object_for_hash(obj, method) if obj
387
391
  end
388
392
 
389
393
  to_many_attributes.each do |attrb|
390
394
  list = attrb.get_value(self)
391
- plist[attrb.plist_name] = list.uuids
395
+ plist[attrb.plist_name] = list.map { |o| nested_object_for_hash(o, method) }
392
396
  end
393
397
 
394
398
  references_by_keys_attributes.each do |attrb|
395
399
  list = attrb.get_value(self)
396
- plist[attrb.plist_name] = list.map(&:to_hash)
400
+ plist[attrb.plist_name] = list.map(&method)
397
401
  end
398
402
 
399
403
  plist
400
404
  end
405
+ private :to_hash_as
406
+
407
+ def nested_object_for_hash(object, method)
408
+ case method
409
+ when :to_ascii_plist
410
+ Nanaimo::String.new(object.uuid, object.ascii_plist_annotation)
411
+ else
412
+ object.uuid
413
+ end
414
+ end
415
+
416
+ def ascii_plist_annotation
417
+ " #{display_name} "
418
+ end
419
+
420
+ def to_ascii_plist
421
+ Nanaimo::Dictionary.new(to_hash_as(:to_ascii_plist), ascii_plist_annotation)
422
+ end
401
423
 
402
424
  # Returns a cascade representation of the object without UUIDs.
403
425
  #
@@ -38,6 +38,12 @@ module Xcodeproj
38
38
  { name => data }
39
39
  end
40
40
 
41
+ def to_hash_as(method = :to_hash)
42
+ super.tap do |hash|
43
+ normalize_array_settings(hash['buildSettings'])
44
+ end
45
+ end
46
+
41
47
  # Sorts the build settings. Valid only in Ruby > 1.9.2 because in
42
48
  # previous versions the hash are not sorted.
43
49
  #
@@ -74,6 +80,52 @@ module Xcodeproj
74
80
  sorted
75
81
  end
76
82
 
83
+ # yes, they are case-sensitive.
84
+ # no, Xcode doesn't do this for other PathList settings nor other
85
+ # settings ending in SEARCH_PATHS.
86
+ ARRAY_SETTINGS = %w(
87
+ ALTERNATE_PERMISSIONS_FILES
88
+ ARCHS
89
+ BUILD_VARIANTS
90
+ EXCLUDED_SOURCE_FILE_NAMES
91
+ FRAMEWORK_SEARCH_PATHS
92
+ GCC_PREPROCESSOR_DEFINITIONS
93
+ GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS
94
+ HEADER_SEARCH_PATHS
95
+ INFOPLIST_PREPROCESSOR_DEFINITIONS
96
+ LIBRARY_SEARCH_PATHS
97
+ OTHER_CFLAGS
98
+ OTHER_CPLUSPLUSFLAGS
99
+ OTHER_LDFLAGS
100
+ REZ_SEARCH_PATHS
101
+ SECTORDER_FLAGS
102
+ WARNING_CFLAGS
103
+ WARNING_LDFLAGS
104
+ ).freeze
105
+ private_constant :ARRAY_SETTINGS
106
+
107
+ def normalize_array_settings(settings)
108
+ return unless settings
109
+ settings.keys.each do |key|
110
+ next unless value = settings[key]
111
+ case value
112
+ when String
113
+ next unless ARRAY_SETTINGS.include?(key)
114
+ array_value = split_build_setting_array_to_string(value)
115
+ next unless array_value.size > 1
116
+ settings[key] = array_value
117
+ when Array
118
+ next if value.size > 1 && ARRAY_SETTINGS.include?(key)
119
+ settings[key] = value.join(' ')
120
+ end
121
+ end
122
+ end
123
+
124
+ def split_build_setting_array_to_string(string)
125
+ regexp = / *((['"]?).*?[^\\]\2)(?=( |\z))/
126
+ string.scan(regexp).map(&:first)
127
+ end
128
+
77
129
  #---------------------------------------------------------------------#
78
130
  end
79
131
  end
@@ -59,6 +59,10 @@ module Xcodeproj
59
59
  end
60
60
  end
61
61
 
62
+ def ascii_plist_annotation
63
+ " #{display_name} in #{GroupableHelper.parent(self).display_name} "
64
+ end
65
+
62
66
  #---------------------------------------------------------------------#
63
67
  end
64
68
  end
@@ -127,6 +127,14 @@ module Xcodeproj
127
127
  end
128
128
  end
129
129
  alias_method :clear_build_files, :clear
130
+
131
+ def display_name
132
+ super.gsub(/BuildPhase$/, '')
133
+ end
134
+
135
+ def ascii_plist_annotation
136
+ " #{display_name} "
137
+ end
130
138
  end
131
139
 
132
140
  #-----------------------------------------------------------------------#
@@ -80,6 +80,10 @@ module Xcodeproj
80
80
  def output_files_and_flags
81
81
  (output_files || []).zip(output_files_compiler_flags || [])
82
82
  end
83
+
84
+ def ascii_plist_annotation
85
+ " #{isa} "
86
+ end
83
87
  end
84
88
  end
85
89
  end
@@ -90,7 +90,16 @@ module Xcodeproj
90
90
  end
91
91
  end
92
92
 
93
+ def target
94
+ return project.root_object if project.build_configuration_list.uuid == uuid
95
+ project.targets.find { |t| t.build_configuration_list.uuid == uuid }
96
+ end
97
+
93
98
  #---------------------------------------------------------------------#
99
+
100
+ def ascii_plist_annotation
101
+ " Build configuration list for #{target.isa} \"#{target}\" "
102
+ end
94
103
  end
95
104
  end
96
105
  end
@@ -79,13 +79,36 @@ module Xcodeproj
79
79
  # @return [AbstractObject]
80
80
  #
81
81
  def proxied_object
82
+ container_portal_object.objects_by_uuid[remote_global_id_string]
83
+ end
84
+
85
+ def container_portal_object
82
86
  if remote?
83
87
  container_portal_file_ref = project.objects_by_uuid[container_portal]
84
- container_portal_object = Project.open(container_portal_file_ref.real_path)
88
+ Project.open(container_portal_file_ref.real_path)
85
89
  else
86
- container_portal_object = project
90
+ project
87
91
  end
88
- container_portal_object.objects_by_uuid[remote_global_id_string]
92
+ end
93
+
94
+ def container_portal_annotation
95
+ if remote?
96
+ " #{File.basename(project.objects_by_uuid[container_portal].real_path)} "
97
+ else
98
+ project.root_object.ascii_plist_annotation
99
+ end
100
+ end
101
+
102
+ def to_hash_as(method = :to_hash)
103
+ hash = super
104
+ if method == :to_ascii_plist
105
+ hash['containerPortal'] = Nanaimo::String.new(container_portal, container_portal_annotation)
106
+ end
107
+ hash
108
+ end
109
+
110
+ def ascii_plist_annotation
111
+ " #{isa} "
89
112
  end
90
113
  end
91
114
  end
@@ -123,7 +123,13 @@ module Xcodeproj
123
123
  # needed.
124
124
  #
125
125
  def display_name
126
- name || (File.basename(path) if path)
126
+ if name
127
+ name
128
+ elsif (class << GroupableHelper; self; end)::SOURCE_TREES_BY_KEY[:built_products] == source_tree
129
+ path
130
+ elsif path
131
+ File.basename(path)
132
+ end
127
133
  end
128
134
 
129
135
  # @return [PBXGroup, PBXProject] the parent of the file.
@@ -412,6 +412,10 @@ module Xcodeproj
412
412
  end
413
413
  end
414
414
 
415
+ def ascii_plist_annotation
416
+ super unless self.equal?(project.main_group)
417
+ end
418
+
415
419
  # Sorts the to many attributes of the object according to the display
416
420
  # name.
417
421
  #
@@ -48,6 +48,10 @@ module Xcodeproj
48
48
  end
49
49
 
50
50
  #---------------------------------------------------------------------#
51
+
52
+ def ascii_plist_annotation
53
+ " #{name || path && File.basename(path)} "
54
+ end
51
55
  end
52
56
  end
53
57
  end
@@ -67,6 +67,20 @@ module Xcodeproj
67
67
  has_many_references_by_keys :project_references,
68
68
  :project_ref => PBXFileReference,
69
69
  :product_group => PBXGroup
70
+
71
+ def name
72
+ project.path.basename('.xcodeproj').to_s
73
+ end
74
+
75
+ def ascii_plist_annotation
76
+ ' Project object '
77
+ end
78
+
79
+ def to_ascii_plist
80
+ plist = super
81
+ plist.value.delete('projectReferences') if plist.value['projectReferences'].empty?
82
+ plist
83
+ end
70
84
  end
71
85
  end
72
86
  end
@@ -39,6 +39,10 @@ module Xcodeproj
39
39
  return target_proxy.remote_info if target_proxy
40
40
  end
41
41
 
42
+ def ascii_plist_annotation
43
+ " #{isa} "
44
+ end
45
+
42
46
  # @return [String] uuid of the target, if the dependency
43
47
  # is a native target, otherwise the uuid of the
44
48
  # target in the sub-project if the dependency is
@@ -117,12 +117,16 @@ module Xcodeproj
117
117
  each do |key, obj|
118
118
  if obj
119
119
  plist_key = Object::CaseConverter.convert_to_plist(key, nil)
120
- result[plist_key] = obj.uuid
120
+ result[plist_key] = Nanaimo::String.new(obj.uuid, obj.ascii_plist_annotation)
121
121
  end
122
122
  end
123
123
  result
124
124
  end
125
125
 
126
+ def to_ascii_plist
127
+ to_hash
128
+ end
129
+
126
130
  # @return [Hash<String => String>] Returns a cascade representation of
127
131
  # the object without UUIDs.
128
132
  #