plasmo_xcodeproj 1.21.1
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 +7 -0
- data/LICENSE +19 -0
- data/README.md +95 -0
- data/bin/xcodeproj +10 -0
- data/lib/xcodeproj/command/config_dump.rb +91 -0
- data/lib/xcodeproj/command/project_diff.rb +56 -0
- data/lib/xcodeproj/command/show.rb +60 -0
- data/lib/xcodeproj/command/sort.rb +44 -0
- data/lib/xcodeproj/command/target_diff.rb +43 -0
- data/lib/xcodeproj/command.rb +63 -0
- data/lib/xcodeproj/config/other_linker_flags_parser.rb +73 -0
- data/lib/xcodeproj/config.rb +386 -0
- data/lib/xcodeproj/constants.rb +465 -0
- data/lib/xcodeproj/differ.rb +239 -0
- data/lib/xcodeproj/gem_version.rb +5 -0
- data/lib/xcodeproj/helper.rb +30 -0
- data/lib/xcodeproj/plist.rb +94 -0
- data/lib/xcodeproj/project/case_converter.rb +90 -0
- data/lib/xcodeproj/project/object/build_configuration.rb +255 -0
- data/lib/xcodeproj/project/object/build_file.rb +84 -0
- data/lib/xcodeproj/project/object/build_phase.rb +369 -0
- data/lib/xcodeproj/project/object/build_rule.rb +109 -0
- data/lib/xcodeproj/project/object/configuration_list.rb +117 -0
- data/lib/xcodeproj/project/object/container_item_proxy.rb +116 -0
- data/lib/xcodeproj/project/object/file_reference.rb +338 -0
- data/lib/xcodeproj/project/object/group.rb +506 -0
- data/lib/xcodeproj/project/object/helpers/build_settings_array_settings_by_object_version.rb +72 -0
- data/lib/xcodeproj/project/object/helpers/file_references_factory.rb +245 -0
- data/lib/xcodeproj/project/object/helpers/groupable_helper.rb +260 -0
- data/lib/xcodeproj/project/object/native_target.rb +751 -0
- data/lib/xcodeproj/project/object/reference_proxy.rb +86 -0
- data/lib/xcodeproj/project/object/root_object.rb +100 -0
- data/lib/xcodeproj/project/object/swift_package_product_dependency.rb +29 -0
- data/lib/xcodeproj/project/object/swift_package_remote_reference.rb +33 -0
- data/lib/xcodeproj/project/object/target_dependency.rb +94 -0
- data/lib/xcodeproj/project/object.rb +534 -0
- data/lib/xcodeproj/project/object_attributes.rb +522 -0
- data/lib/xcodeproj/project/object_dictionary.rb +210 -0
- data/lib/xcodeproj/project/object_list.rb +223 -0
- data/lib/xcodeproj/project/project_helper.rb +341 -0
- data/lib/xcodeproj/project/uuid_generator.rb +132 -0
- data/lib/xcodeproj/project.rb +874 -0
- data/lib/xcodeproj/scheme/abstract_scheme_action.rb +100 -0
- data/lib/xcodeproj/scheme/analyze_action.rb +19 -0
- data/lib/xcodeproj/scheme/archive_action.rb +59 -0
- data/lib/xcodeproj/scheme/build_action.rb +298 -0
- data/lib/xcodeproj/scheme/buildable_product_runnable.rb +55 -0
- data/lib/xcodeproj/scheme/buildable_reference.rb +129 -0
- data/lib/xcodeproj/scheme/command_line_arguments.rb +162 -0
- data/lib/xcodeproj/scheme/environment_variables.rb +170 -0
- data/lib/xcodeproj/scheme/execution_action.rb +86 -0
- data/lib/xcodeproj/scheme/launch_action.rb +179 -0
- data/lib/xcodeproj/scheme/location_scenario_reference.rb +49 -0
- data/lib/xcodeproj/scheme/macro_expansion.rb +34 -0
- data/lib/xcodeproj/scheme/profile_action.rb +57 -0
- data/lib/xcodeproj/scheme/remote_runnable.rb +92 -0
- data/lib/xcodeproj/scheme/send_email_action_content.rb +84 -0
- data/lib/xcodeproj/scheme/shell_script_action_content.rb +77 -0
- data/lib/xcodeproj/scheme/test_action.rb +394 -0
- data/lib/xcodeproj/scheme/xml_element_wrapper.rb +82 -0
- data/lib/xcodeproj/scheme.rb +375 -0
- data/lib/xcodeproj/user_interface.rb +22 -0
- data/lib/xcodeproj/workspace/file_reference.rb +79 -0
- data/lib/xcodeproj/workspace/group_reference.rb +67 -0
- data/lib/xcodeproj/workspace/reference.rb +40 -0
- data/lib/xcodeproj/workspace.rb +277 -0
- data/lib/xcodeproj/xcodebuild_helper.rb +108 -0
- data/lib/xcodeproj.rb +29 -0
- metadata +208 -0
@@ -0,0 +1,341 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
class Project
|
3
|
+
module ProjectHelper
|
4
|
+
include Object
|
5
|
+
|
6
|
+
# @!group Targets
|
7
|
+
|
8
|
+
#-----------------------------------------------------------------------#
|
9
|
+
|
10
|
+
# Creates a new target and adds it to the project.
|
11
|
+
#
|
12
|
+
# The target is configured for the given platform and its file reference it
|
13
|
+
# is added to the {products_group}.
|
14
|
+
#
|
15
|
+
# The target is pre-populated with common build settings, and the
|
16
|
+
# appropriate Framework according to the platform is added to to its
|
17
|
+
# Frameworks phase.
|
18
|
+
#
|
19
|
+
# @param [Project] project
|
20
|
+
# the project to which the target should be added.
|
21
|
+
#
|
22
|
+
# @param [Symbol] type
|
23
|
+
# the type of target. Can be `:application`, `:dynamic_library`,
|
24
|
+
# `framework` or `:static_library`.
|
25
|
+
#
|
26
|
+
# @param [String] name
|
27
|
+
# the name of the target product.
|
28
|
+
#
|
29
|
+
# @param [Symbol] platform
|
30
|
+
# the platform of the target. Can be `:ios` or `:osx`.
|
31
|
+
#
|
32
|
+
# @param [String] deployment_target
|
33
|
+
# the deployment target for the platform.
|
34
|
+
#
|
35
|
+
# @param [PBXGroup] product_group
|
36
|
+
# the product group, where to add to a file reference of the
|
37
|
+
# created target.
|
38
|
+
#
|
39
|
+
# @param [Symbol] language
|
40
|
+
# the primary language of the target, can be `:objc` or `:swift`.
|
41
|
+
#
|
42
|
+
# @return [PBXNativeTarget] the target.
|
43
|
+
#
|
44
|
+
def self.new_target(project, type, name, platform, deployment_target, product_group, language, product_basename)
|
45
|
+
# Target
|
46
|
+
target = project.new(PBXNativeTarget)
|
47
|
+
project.targets << target
|
48
|
+
target.name = name
|
49
|
+
target.product_name = product_basename
|
50
|
+
target.product_type = Constants::PRODUCT_TYPE_UTI[type]
|
51
|
+
target.build_configuration_list = configuration_list(project, platform, deployment_target, type, language)
|
52
|
+
|
53
|
+
# Product
|
54
|
+
product = product_group.new_product_ref_for_target(target.product_name, type)
|
55
|
+
target.product_reference = product
|
56
|
+
|
57
|
+
# Build phases
|
58
|
+
build_phases_for_target_type(type).each { |phase| target.build_phases << project.new(phase) }
|
59
|
+
|
60
|
+
# Frameworks
|
61
|
+
unless type == :static_library
|
62
|
+
framework_name = (platform == :osx) ? 'Cocoa' : 'Foundation'
|
63
|
+
target.add_system_framework(framework_name)
|
64
|
+
end
|
65
|
+
|
66
|
+
target
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates a new resource bundles target and adds it to the project.
|
70
|
+
#
|
71
|
+
# The target is configured for the given platform and its file reference it
|
72
|
+
# is added to the {products_group}.
|
73
|
+
#
|
74
|
+
# The target is pre-populated with common build settings
|
75
|
+
#
|
76
|
+
# @param [Project] project
|
77
|
+
# the project to which the target should be added.
|
78
|
+
#
|
79
|
+
# @param [String] name
|
80
|
+
# the name of the resources bundle.
|
81
|
+
#
|
82
|
+
# @param [Symbol] platform
|
83
|
+
# the platform of the resources bundle. Can be `:ios` or `:osx`.
|
84
|
+
#
|
85
|
+
# @param [PBXGroup] product_group
|
86
|
+
# the product group, where to add to a file reference of the
|
87
|
+
# created target.
|
88
|
+
#
|
89
|
+
# @return [PBXNativeTarget] the target.
|
90
|
+
#
|
91
|
+
def self.new_resources_bundle(project, name, platform, product_group, product_basename)
|
92
|
+
# Target
|
93
|
+
target = project.new(PBXNativeTarget)
|
94
|
+
project.targets << target
|
95
|
+
target.name = name
|
96
|
+
target.product_name = product_basename
|
97
|
+
target.product_type = Constants::PRODUCT_TYPE_UTI[:bundle]
|
98
|
+
|
99
|
+
# Configuration List
|
100
|
+
cl = project.new(XCConfigurationList)
|
101
|
+
cl.default_configuration_is_visible = '0'
|
102
|
+
cl.default_configuration_name = 'Release'
|
103
|
+
release_conf = project.new(XCBuildConfiguration)
|
104
|
+
release_conf.name = 'Release'
|
105
|
+
release_conf.build_settings = common_build_settings(nil, platform, nil, target.product_type)
|
106
|
+
debug_conf = project.new(XCBuildConfiguration)
|
107
|
+
debug_conf.name = 'Debug'
|
108
|
+
debug_conf.build_settings = common_build_settings(nil, platform, nil, target.product_type)
|
109
|
+
cl.build_configurations << release_conf
|
110
|
+
cl.build_configurations << debug_conf
|
111
|
+
target.build_configuration_list = cl
|
112
|
+
|
113
|
+
# Product
|
114
|
+
product = product_group.new_bundle(target.product_name)
|
115
|
+
target.product_reference = product
|
116
|
+
|
117
|
+
# Build phases
|
118
|
+
build_phases_for_target_type(:bundle).each { |phase| target.build_phases << project.new(phase) }
|
119
|
+
|
120
|
+
target
|
121
|
+
end
|
122
|
+
|
123
|
+
# Creates a new aggregate target and adds it to the project.
|
124
|
+
#
|
125
|
+
# The target is configured for the given platform.
|
126
|
+
#
|
127
|
+
# @param [Project] project
|
128
|
+
# the project to which the target should be added.
|
129
|
+
#
|
130
|
+
# @param [String] name
|
131
|
+
# the name of the aggregate target.
|
132
|
+
#
|
133
|
+
# @param [Symbol] platform
|
134
|
+
# the platform of the aggregate target. Can be `:ios` or `:osx`.
|
135
|
+
#
|
136
|
+
# @param [String] deployment_target
|
137
|
+
# the deployment target for the platform.
|
138
|
+
#
|
139
|
+
# @return [PBXAggregateTarget] the target.
|
140
|
+
#
|
141
|
+
def self.new_aggregate_target(project, name, platform, deployment_target)
|
142
|
+
target = project.new(PBXAggregateTarget)
|
143
|
+
project.targets << target
|
144
|
+
target.name = name
|
145
|
+
target.build_configuration_list = configuration_list(project, platform, deployment_target)
|
146
|
+
target
|
147
|
+
end
|
148
|
+
|
149
|
+
# Creates a new legacy target and adds it to the project.
|
150
|
+
#
|
151
|
+
# The target is configured for the given platform.
|
152
|
+
#
|
153
|
+
# @param [Project] project
|
154
|
+
# the project to which the target should be added.
|
155
|
+
#
|
156
|
+
# @param [String] name
|
157
|
+
# the name of the aggregate target.
|
158
|
+
#
|
159
|
+
# @param [String] build_tool_path
|
160
|
+
# the build tool path to use for this target.
|
161
|
+
#
|
162
|
+
# @param [String] build_arguments_string
|
163
|
+
# the build arguments string to use for this target.
|
164
|
+
#
|
165
|
+
# @param [String] build_working_directory
|
166
|
+
# the build working directory to use for this target.
|
167
|
+
#
|
168
|
+
# @param [String] pass_build_settings_in_environment
|
169
|
+
# whether to pass build settings in the environment during execution of this target.
|
170
|
+
#
|
171
|
+
# @return [PBXLegacyTarget] the target.
|
172
|
+
#
|
173
|
+
def self.new_legacy_target(project, name, build_tool_path = '/usr/bin/make', build_arguments_string = '$(ACTION)',
|
174
|
+
build_working_directory = nil, pass_build_settings_in_environment = '1')
|
175
|
+
target = project.new(PBXLegacyTarget)
|
176
|
+
project.targets << target
|
177
|
+
target.name = name
|
178
|
+
target.build_configuration_list = configuration_list(project)
|
179
|
+
target.build_tool_path = build_tool_path
|
180
|
+
target.build_arguments_string = build_arguments_string
|
181
|
+
target.build_working_directory = build_working_directory
|
182
|
+
target.pass_build_settings_in_environment = pass_build_settings_in_environment
|
183
|
+
target
|
184
|
+
end
|
185
|
+
|
186
|
+
# @!group Private Helpers
|
187
|
+
|
188
|
+
#-----------------------------------------------------------------------#
|
189
|
+
|
190
|
+
# Returns a new configuration list, populated with release and debug
|
191
|
+
# configurations with common build settings for the given platform.
|
192
|
+
#
|
193
|
+
# @param [Project] project
|
194
|
+
# the project to which the configuration list should be added.
|
195
|
+
#
|
196
|
+
# @param [Symbol] platform
|
197
|
+
# the platform for the configuration list, can be `:ios` or `:osx`.
|
198
|
+
#
|
199
|
+
# @param [String] deployment_target
|
200
|
+
# the deployment target for the platform.
|
201
|
+
#
|
202
|
+
# @param [Symbol] target_product_type
|
203
|
+
# the product type of the target, can be any of `Constants::PRODUCT_TYPE_UTI.values`
|
204
|
+
# or `Constants::PRODUCT_TYPE_UTI.keys`.
|
205
|
+
#
|
206
|
+
# @param [Symbol] language
|
207
|
+
# the primary language of the target, can be `:objc` or `:swift`.
|
208
|
+
#
|
209
|
+
# @return [XCConfigurationList] the generated configuration list.
|
210
|
+
#
|
211
|
+
def self.configuration_list(project, platform = nil, deployment_target = nil, target_product_type = nil, language = nil)
|
212
|
+
cl = project.new(XCConfigurationList)
|
213
|
+
cl.default_configuration_is_visible = '0'
|
214
|
+
cl.default_configuration_name = 'Release'
|
215
|
+
|
216
|
+
release_conf = project.new(XCBuildConfiguration)
|
217
|
+
release_conf.name = 'Release'
|
218
|
+
release_conf.build_settings = common_build_settings(:release, platform, deployment_target, target_product_type, language)
|
219
|
+
|
220
|
+
debug_conf = project.new(XCBuildConfiguration)
|
221
|
+
debug_conf.name = 'Debug'
|
222
|
+
debug_conf.build_settings = common_build_settings(:debug, platform, deployment_target, target_product_type, language)
|
223
|
+
|
224
|
+
cl.build_configurations << release_conf
|
225
|
+
cl.build_configurations << debug_conf
|
226
|
+
|
227
|
+
existing_configurations = cl.build_configurations.map(&:name)
|
228
|
+
project.build_configurations.each do |configuration|
|
229
|
+
next if existing_configurations.include?(configuration.name)
|
230
|
+
|
231
|
+
new_config = project.new(XCBuildConfiguration)
|
232
|
+
new_config.name = configuration.name
|
233
|
+
new_config.build_settings = common_build_settings(configuration.type, platform, deployment_target, target_product_type, language)
|
234
|
+
cl.build_configurations << new_config
|
235
|
+
end
|
236
|
+
|
237
|
+
cl
|
238
|
+
end
|
239
|
+
|
240
|
+
# Returns the common build settings for a given platform and configuration
|
241
|
+
# name.
|
242
|
+
#
|
243
|
+
# @param [Symbol] type
|
244
|
+
# the type of the build configuration, can be `:release` or
|
245
|
+
# `:debug`.
|
246
|
+
#
|
247
|
+
# @param [Symbol] platform
|
248
|
+
# the platform for the build settings, can be `:ios` or `:osx`.
|
249
|
+
#
|
250
|
+
# @param [String] deployment_target
|
251
|
+
# the deployment target for the platform.
|
252
|
+
#
|
253
|
+
# @param [Symbol] target_product_type
|
254
|
+
# the product type of the target, can be any of
|
255
|
+
# `Constants::PRODUCT_TYPE_UTI.values`
|
256
|
+
# or `Constants::PRODUCT_TYPE_UTI.keys`. Default is :application.
|
257
|
+
#
|
258
|
+
# @param [Symbol] language
|
259
|
+
# the primary language of the target, can be `:objc` or `:swift`.
|
260
|
+
#
|
261
|
+
# @return [Hash] The common build settings
|
262
|
+
#
|
263
|
+
def self.common_build_settings(type, platform = nil, deployment_target = nil, target_product_type = nil, language = :objc)
|
264
|
+
target_product_type = (Constants::PRODUCT_TYPE_UTI.find { |_, v| v == target_product_type } || [target_product_type || :application])[0]
|
265
|
+
common_settings = Constants::COMMON_BUILD_SETTINGS
|
266
|
+
|
267
|
+
# Use intersecting settings for all key sets as base
|
268
|
+
settings = deep_dup(common_settings[:all])
|
269
|
+
|
270
|
+
# Match further common settings by key sets
|
271
|
+
keys = [type, platform, target_product_type, language].compact
|
272
|
+
key_combinations = (1..keys.length).flat_map { |n| keys.combination(n).to_a }
|
273
|
+
key_combinations.each do |key_combination|
|
274
|
+
settings.merge!(deep_dup(common_settings[key_combination] || {}))
|
275
|
+
end
|
276
|
+
|
277
|
+
if deployment_target
|
278
|
+
case platform
|
279
|
+
when :ios
|
280
|
+
settings['IPHONEOS_DEPLOYMENT_TARGET'] = deployment_target
|
281
|
+
settings['CLANG_ENABLE_OBJC_WEAK'] = 'NO' if deployment_target < '5'
|
282
|
+
when :osx
|
283
|
+
settings['MACOSX_DEPLOYMENT_TARGET'] = deployment_target
|
284
|
+
settings['CLANG_ENABLE_OBJC_WEAK'] = 'NO' if deployment_target < '10.7'
|
285
|
+
when :tvos
|
286
|
+
settings['TVOS_DEPLOYMENT_TARGET'] = deployment_target
|
287
|
+
when :watchos
|
288
|
+
settings['WATCHOS_DEPLOYMENT_TARGET'] = deployment_target
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
settings
|
293
|
+
end
|
294
|
+
|
295
|
+
# Creates a deep copy of the given object
|
296
|
+
#
|
297
|
+
# @param [Object] object
|
298
|
+
# the object to copy.
|
299
|
+
#
|
300
|
+
# @return [Object] The deep copy of the object.
|
301
|
+
#
|
302
|
+
def self.deep_dup(object)
|
303
|
+
case object
|
304
|
+
when Hash
|
305
|
+
new_hash = {}
|
306
|
+
object.each do |key, value|
|
307
|
+
new_hash[key] = deep_dup(value)
|
308
|
+
end
|
309
|
+
new_hash
|
310
|
+
when Array
|
311
|
+
object.map { |value| deep_dup(value) }
|
312
|
+
else
|
313
|
+
object.dup
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
# Returns the build phases, in order, that appear by default
|
318
|
+
# on a target of the given type.
|
319
|
+
#
|
320
|
+
# @param [Symbol] type
|
321
|
+
# the name of the target type.
|
322
|
+
#
|
323
|
+
# @return [Array<String>] The list of build phase class names for the target type.
|
324
|
+
#
|
325
|
+
def self.build_phases_for_target_type(type)
|
326
|
+
case type
|
327
|
+
when :static_library, :dynamic_library
|
328
|
+
%w(Headers Sources Frameworks)
|
329
|
+
when :framework
|
330
|
+
%w(Headers Sources Frameworks Resources)
|
331
|
+
when :command_line_tool
|
332
|
+
%w(Sources Frameworks)
|
333
|
+
else
|
334
|
+
%w(Sources Frameworks Resources)
|
335
|
+
end.map { |phase| "PBX#{phase}BuildPhase" }
|
336
|
+
end
|
337
|
+
|
338
|
+
#-----------------------------------------------------------------------#
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
class Project
|
3
|
+
class UUIDGenerator
|
4
|
+
require 'digest'
|
5
|
+
|
6
|
+
def initialize(projects)
|
7
|
+
@projects = Array(projects)
|
8
|
+
@paths_by_object = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate!
|
12
|
+
generate_all_paths_by_objects(@projects)
|
13
|
+
|
14
|
+
new_objects_by_project = Hash[@projects.map do |project|
|
15
|
+
[project, switch_uuids(project)]
|
16
|
+
end]
|
17
|
+
all_new_objects_by_project = new_objects_by_project.values.flat_map(&:values)
|
18
|
+
all_objects_by_uuid = @projects.map(&:objects_by_uuid).inject(:merge)
|
19
|
+
all_objects = @projects.flat_map(&:objects)
|
20
|
+
verify_no_duplicates!(all_objects, all_new_objects_by_project)
|
21
|
+
@projects.each { |project| fixup_uuid_references(project, all_objects_by_uuid) }
|
22
|
+
new_objects_by_project.each do |project, new_objects_by_uuid|
|
23
|
+
project.instance_variable_set(:@generated_uuids, project.instance_variable_get(:@available_uuids))
|
24
|
+
project.instance_variable_set(:@objects_by_uuid, new_objects_by_uuid)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
UUID_ATTRIBUTES = [:remote_global_id_string, :container_portal, :target_proxy].freeze
|
31
|
+
|
32
|
+
def verify_no_duplicates!(all_objects, all_new_objects)
|
33
|
+
duplicates = all_objects - all_new_objects
|
34
|
+
UserInterface.warn "[Xcodeproj] Generated duplicate UUIDs:\n\n" <<
|
35
|
+
duplicates.map { |d| "#{d.isa} -- #{@paths_by_object[d]}" }.join("\n") unless duplicates.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def fixup_uuid_references(target_project, all_objects_by_uuid)
|
39
|
+
fixup = ->(object, attr) do
|
40
|
+
if object.respond_to?(attr) && link = all_objects_by_uuid[object.send(attr)]
|
41
|
+
object.send(:"#{attr}=", link.uuid)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
target_project.objects.each do |object|
|
45
|
+
UUID_ATTRIBUTES.each do |attr|
|
46
|
+
fixup[object, attr]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
if (project_attributes = target_project.root_object.attributes) && project_attributes['TargetAttributes']
|
51
|
+
project_attributes['TargetAttributes'] = Hash[project_attributes['TargetAttributes'].map do |target_uuid, attributes|
|
52
|
+
if test_target_id = attributes['TestTargetID']
|
53
|
+
attributes = attributes.merge('TestTargetID' => all_objects_by_uuid[test_target_id].uuid)
|
54
|
+
end
|
55
|
+
if target_object = all_objects_by_uuid[target_uuid]
|
56
|
+
target_uuid = target_object.uuid
|
57
|
+
end
|
58
|
+
[target_uuid, attributes]
|
59
|
+
end]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def generate_all_paths_by_objects(projects)
|
64
|
+
projects.each { |project| generate_paths(project.root_object, project.path.basename.to_s) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def generate_paths(object, path = '')
|
68
|
+
existing = @paths_by_object[object] || path
|
69
|
+
return existing if @paths_by_object.key?(object)
|
70
|
+
@paths_by_object[object] = path.size > existing.size ? path : existing
|
71
|
+
|
72
|
+
object.to_one_attributes.each do |attrb|
|
73
|
+
obj = attrb.get_value(object)
|
74
|
+
generate_paths(obj, path + '/' << attrb.plist_name) if obj
|
75
|
+
end
|
76
|
+
|
77
|
+
object.to_many_attributes.each do |attrb|
|
78
|
+
attrb.get_value(object).each do |o|
|
79
|
+
generate_paths(o, path + '/' << attrb.plist_name << "/#{path_component_for_object(o)}")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
object.references_by_keys_attributes.each do |attrb|
|
84
|
+
attrb.get_value(object).each do |dictionary|
|
85
|
+
dictionary.each do |key, value|
|
86
|
+
generate_paths(value, path + '/' << attrb.plist_name << "/k:#{key}/#{path_component_for_object(value)}")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def switch_uuids(project)
|
93
|
+
project.mark_dirty!
|
94
|
+
project.objects.each_with_object({}) do |object, hash|
|
95
|
+
next unless path = @paths_by_object[object]
|
96
|
+
uuid = uuid_for_path(path)
|
97
|
+
object.instance_variable_set(:@uuid, uuid)
|
98
|
+
hash[uuid] = object
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def uuid_for_path(path)
|
103
|
+
Digest::MD5.hexdigest(path).upcase
|
104
|
+
end
|
105
|
+
|
106
|
+
def path_component_for_object(object)
|
107
|
+
@path_component_for_object ||= Hash.new do |cache, key|
|
108
|
+
component = tree_hash_to_path(key.to_tree_hash)
|
109
|
+
component << key.hierarchy_path.to_s if key.respond_to?(:hierarchy_path)
|
110
|
+
cache[key] = component
|
111
|
+
end
|
112
|
+
@path_component_for_object[object]
|
113
|
+
end
|
114
|
+
|
115
|
+
def tree_hash_to_path(object, depth = 4)
|
116
|
+
return '|' if depth.zero?
|
117
|
+
case object
|
118
|
+
when Hash
|
119
|
+
object.sort.each_with_object('') do |(key, value), string|
|
120
|
+
string << key << ':' << tree_hash_to_path(value, depth - 1) << ','
|
121
|
+
end
|
122
|
+
when Array
|
123
|
+
object.map do |value|
|
124
|
+
tree_hash_to_path(value, depth - 1)
|
125
|
+
end.join(',')
|
126
|
+
else
|
127
|
+
object.to_s
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|