cocoapods 1.10.0 → 1.11.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +237 -5
  3. data/README.md +11 -11
  4. data/lib/cocoapods/command/outdated.rb +12 -1
  5. data/lib/cocoapods/command/repo/push.rb +17 -0
  6. data/lib/cocoapods/command/spec.rb +18 -9
  7. data/lib/cocoapods/command/spec/cat.rb +3 -1
  8. data/lib/cocoapods/command/spec/lint.rb +1 -1
  9. data/lib/cocoapods/command/spec/which.rb +3 -1
  10. data/lib/cocoapods/config.rb +1 -1
  11. data/lib/cocoapods/downloader.rb +4 -2
  12. data/lib/cocoapods/downloader/cache.rb +95 -6
  13. data/lib/cocoapods/external_sources/podspec_source.rb +1 -1
  14. data/lib/cocoapods/gem_version.rb +1 -1
  15. data/lib/cocoapods/generator/acknowledgements.rb +1 -1
  16. data/lib/cocoapods/generator/app_target_helper.rb +7 -3
  17. data/lib/cocoapods/generator/copy_dsyms_script.rb +4 -4
  18. data/lib/cocoapods/generator/copy_xcframework_script.rb +2 -18
  19. data/lib/cocoapods/generator/embed_frameworks_script.rb +2 -1
  20. data/lib/cocoapods/generator/script_phase_constants.rb +1 -0
  21. data/lib/cocoapods/installer.rb +52 -4
  22. data/lib/cocoapods/installer/analyzer.rb +12 -8
  23. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +31 -4
  24. data/lib/cocoapods/installer/podfile_validator.rb +2 -2
  25. data/lib/cocoapods/installer/pre_integrate_hooks_context.rb +9 -0
  26. data/lib/cocoapods/installer/project_cache/project_cache_analyzer.rb +9 -2
  27. data/lib/cocoapods/installer/project_cache/project_installation_cache.rb +15 -2
  28. data/lib/cocoapods/installer/project_cache/target_cache_key.rb +7 -4
  29. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +149 -9
  30. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +1 -1
  31. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +10 -3
  32. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +25 -6
  33. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +6 -19
  34. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +70 -58
  35. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +48 -6
  36. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +2 -2
  37. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +2 -5
  38. data/lib/cocoapods/resolver.rb +4 -4
  39. data/lib/cocoapods/sandbox/file_accessor.rb +57 -10
  40. data/lib/cocoapods/sandbox/headers_store.rb +3 -1
  41. data/lib/cocoapods/sandbox/path_list.rb +1 -1
  42. data/lib/cocoapods/sandbox/pod_dir_cleaner.rb +1 -1
  43. data/lib/cocoapods/sources_manager.rb +14 -8
  44. data/lib/cocoapods/target.rb +1 -1
  45. data/lib/cocoapods/target/aggregate_target.rb +23 -1
  46. data/lib/cocoapods/target/build_settings.rb +45 -20
  47. data/lib/cocoapods/target/pod_target.rb +47 -22
  48. data/lib/cocoapods/user_interface.rb +4 -0
  49. data/lib/cocoapods/validator.rb +25 -5
  50. data/lib/cocoapods/version_metadata.rb +1 -1
  51. data/lib/cocoapods/xcode/xcframework.rb +8 -3
  52. data/lib/cocoapods/xcode/xcframework/xcframework_slice.rb +10 -1
  53. metadata +28 -21
@@ -35,7 +35,7 @@ module Pod
35
35
  #
36
36
  attr_reader :podfile
37
37
 
38
- # @return [Lockfile] The Lockfile, if available, that stores the information about the Pods previously installed.
38
+ # @return [Lockfile, nil] The Lockfile, if available, that stores the information about the Pods previously installed.
39
39
  #
40
40
  attr_reader :lockfile
41
41
 
@@ -67,7 +67,7 @@ module Pod
67
67
  #
68
68
  # @param [Sandbox] sandbox @see #sandbox
69
69
  # @param [Podfile] podfile @see #podfile
70
- # @param [Lockfile] lockfile @see #lockfile
70
+ # @param [Lockfile, nil] lockfile @see #lockfile
71
71
  # @param [Array<Source>] plugin_sources @see #plugin_sources
72
72
  # @param [Boolean] has_dependencies @see #has_dependencies
73
73
  # @param [Hash, Boolean, nil] pods_to_update @see #pods_to_update
@@ -565,12 +565,11 @@ module Pod
565
565
  pod_targets_by_build_config = Hash.new([].freeze)
566
566
  build_configurations.each { |config| pod_targets_by_build_config[config] = [] }
567
567
 
568
+ dependencies_by_root_name = @podfile_dependency_cache.target_definition_dependencies(target_definition).group_by(&:root_name)
569
+
568
570
  pod_targets_by_target_definition[target_definition].each do |pod_target|
569
571
  pod_name = pod_target.pod_name
570
-
571
- dependencies = @podfile_dependency_cache.target_definition_dependencies(target_definition).select do |dependency|
572
- Specification.root_name(dependency.name) == pod_name
573
- end
572
+ dependencies = dependencies_by_root_name[pod_name] || []
574
573
 
575
574
  build_configurations.each do |configuration_name|
576
575
  whitelists = dependencies.map do |dependency|
@@ -714,7 +713,12 @@ module Pod
714
713
  dependencies.map do |root_spec, deps|
715
714
  pod_targets_by_name[root_spec.name].find do |t|
716
715
  next false if t.platform.symbolic_name != target.platform.symbolic_name ||
717
- t.build_as_framework? != target.build_as_framework? # rather than target type or requires_frameworks? since we want to group by what was specified in that _target definition_
716
+ # In the case of variants we must ensure that the platform this target is meant for is the same
717
+ # as the one we are interested in.
718
+ t.target_definitions.first.platform != target.target_definitions.first.platform ||
719
+ # rather than target type or requires_frameworks? since we want to group by what was specified in that
720
+ # _target definition_.
721
+ t.build_as_framework? != target.build_as_framework?
718
722
  spec_names = t.specs.map(&:name)
719
723
  deps.all? { |dep| spec_names.include?(dep.name) }
720
724
  end
@@ -1115,7 +1119,7 @@ module Pod
1115
1119
  def generate_sandbox_state(specifications)
1116
1120
  sandbox_state = nil
1117
1121
  UI.section 'Comparing resolved specification to the sandbox manifest' do
1118
- sandbox_analyzer = SandboxAnalyzer.new(sandbox, specifications, update_mode?)
1122
+ sandbox_analyzer = SandboxAnalyzer.new(sandbox, podfile, specifications, update_mode?)
1119
1123
  sandbox_state = sandbox_analyzer.analyze
1120
1124
  sandbox_state.print
1121
1125
  end
@@ -31,6 +31,10 @@ module Pod
31
31
  #
32
32
  attr_reader :sandbox
33
33
 
34
+ # @return [Podfile] The Podfile to analyze dependencies.
35
+ #
36
+ attr_reader :podfile
37
+
34
38
  # @return [Array<Specifications>] The specifications returned by the
35
39
  # resolver.
36
40
  #
@@ -45,11 +49,13 @@ module Pod
45
49
  # Init a new SandboxAnalyzer
46
50
  #
47
51
  # @param [Sandbox] sandbox @see sandbox
52
+ # @param [Podfile] podfile @see podfile
48
53
  # @param [Array<Specifications>] specs @see specs
49
54
  # @param [Bool] update_mode @see update_mode
50
55
  #
51
- def initialize(sandbox, specs, update_mode)
56
+ def initialize(sandbox, podfile, specs, update_mode)
52
57
  @sandbox = sandbox
58
+ @podfile = podfile
53
59
  @specs = specs
54
60
  @update_mode = update_mode
55
61
  end
@@ -103,7 +109,7 @@ module Pod
103
109
  #
104
110
  def pod_added?(pod)
105
111
  return true if resolved_pods.include?(pod) && !sandbox_pods.include?(pod)
106
- return true if !folder_exist?(pod) && !sandbox.local?(pod)
112
+ return true if !sandbox.local?(pod) && !folder_exist?(pod)
107
113
  false
108
114
  end
109
115
 
@@ -139,6 +145,7 @@ module Pod
139
145
  return true if spec.version != sandbox_version(pod)
140
146
  return true if spec.checksum != sandbox_checksum(pod)
141
147
  return true if resolved_spec_names(pod) != sandbox_spec_names(pod)
148
+ return true if podfile_dependency(pod) != sandbox_dependency(pod)
142
149
  return true if sandbox.predownloaded?(pod)
143
150
  return true if folder_empty?(pod)
144
151
  false
@@ -161,14 +168,14 @@ module Pod
161
168
  # @return [Array<String>] The name of the resolved Pods.
162
169
  #
163
170
  def resolved_pods
164
- specs.map { |spec| spec.root.name }.uniq
171
+ @resolved_pods ||= specs.map { |spec| spec.root.name }.uniq
165
172
  end
166
173
 
167
174
  # @return [Array<String>] The name of the Pods stored in the sandbox
168
175
  # manifest.
169
176
  #
170
177
  def sandbox_pods
171
- sandbox_manifest.pod_names.map { |name| Specification.root_name(name) }.uniq
178
+ @sandbox_pods ||= sandbox_manifest.pod_names.map { |name| Specification.root_name(name) }.uniq
172
179
  end
173
180
 
174
181
  # @return [Array<String>] The name of the resolved specifications
@@ -223,6 +230,26 @@ module Pod
223
230
  sandbox_manifest.checksum(pod)
224
231
  end
225
232
 
233
+ # @return [Dependency, nil] The dependency with the given name stored in the sandbox.
234
+ #
235
+ # @param [String] pod
236
+ # the name of the Pod.
237
+ #
238
+ def sandbox_dependency(pod)
239
+ sandbox_manifest.dependencies.find { |d| d.name == pod }
240
+ end
241
+
242
+ #--------------------------------------#
243
+
244
+ # @return [Dependency, nil] The dependency with the given name from the podfile.
245
+ #
246
+ # @param [String] pod
247
+ # the name of the Pod.
248
+ #
249
+ def podfile_dependency(pod)
250
+ podfile.dependencies.find { |d| d.name == pod }
251
+ end
252
+
226
253
  #--------------------------------------#
227
254
 
228
255
  def folder_exist?(pod)
@@ -8,11 +8,11 @@ module Pod
8
8
  #
9
9
  attr_reader :podfile
10
10
 
11
- # @return [Array<String>] any errors that have occured during the validation
11
+ # @return [Array<String>] any errors that have occurred during the validation
12
12
  #
13
13
  attr_reader :errors
14
14
 
15
- # @return [Array<String>] any warnings that have occured during the validation
15
+ # @return [Array<String>] any warnings that have occurred during the validation
16
16
  #
17
17
  attr_reader :warnings
18
18
 
@@ -0,0 +1,9 @@
1
+ module Pod
2
+ class Installer
3
+ # Context object designed to be used with the HooksManager which describes
4
+ # the context of the installer.
5
+ #
6
+ class PreIntegrateHooksContext < BaseInstallHooksContext
7
+ end
8
+ end
9
+ end
@@ -34,6 +34,10 @@ module Pod
34
34
  #
35
35
  attr_reader :aggregate_targets
36
36
 
37
+ # @return [Hash<Symbol, Object>] Hash of installation options.
38
+ #
39
+ attr_reader :installation_options
40
+
37
41
  # @return [Bool] Flag indicating if we want to ignore the cache and force a clean installation.
38
42
  #
39
43
  attr_reader :clean_install
@@ -47,9 +51,10 @@ module Pod
47
51
  # @param [Hash<String, Hash>] podfile_plugins @see #podfile_plugins
48
52
  # @param [Array<PodTarget>] pod_targets @see #pod_targets
49
53
  # @param [Array<AggregateTarget>] aggregate_targets @see #aggregate_targets
54
+ # @param [Hash<Symbol, Object>] installation_options @see #installation_options
50
55
  # @param [Bool] clean_install @see #clean_install
51
56
  #
52
- def initialize(sandbox, cache, build_configurations, project_object_version, podfile_plugins, pod_targets, aggregate_targets,
57
+ def initialize(sandbox, cache, build_configurations, project_object_version, podfile_plugins, pod_targets, aggregate_targets, installation_options,
53
58
  clean_install: false)
54
59
  @sandbox = sandbox
55
60
  @cache = cache
@@ -58,6 +63,7 @@ module Pod
58
63
  @pod_targets = pod_targets
59
64
  @aggregate_targets = aggregate_targets
60
65
  @project_object_version = project_object_version
66
+ @installation_options = installation_options
61
67
  @clean_install = clean_install
62
68
  end
63
69
 
@@ -78,7 +84,8 @@ module Pod
78
84
  # Bail out early since these properties affect all targets and their associate projects.
79
85
  if cache.build_configurations != build_configurations ||
80
86
  cache.project_object_version != project_object_version ||
81
- YAMLHelper.convert(cache.podfile_plugins) != YAMLHelper.convert(podfile_plugins)
87
+ YAMLHelper.convert(cache.podfile_plugins) != YAMLHelper.convert(podfile_plugins) ||
88
+ YAMLHelper.convert(cache.installation_options) != YAMLHelper.convert(installation_options)
82
89
  UI.message 'Ignoring project cache due to project configuration changes.'
83
90
  return full_install_results
84
91
  end
@@ -26,18 +26,25 @@ module Pod
26
26
  #
27
27
  attr_reader :podfile_plugins
28
28
 
29
+ # @return [Hash<Symbol, Object>]
30
+ # Configured installation options
31
+ #
32
+ attr_reader :installation_options
33
+
29
34
  # Initializes a new instance.
30
35
  #
31
36
  # @param [Hash{String => TargetCacheKey}] cache_key_by_target_label @see #cache_key_by_target_label
32
37
  # @param [Hash{String => Symbol}] build_configurations @see #build_configurations
33
38
  # @param [Integer] project_object_version @see #project_object_version
34
39
  # @param [Hash<String, Hash>] podfile_plugins @see #podfile_plugins
40
+ # @param [Hash<Symbol, Object>] installation_options @see #installation_options
35
41
  #
36
- def initialize(cache_key_by_target_label = {}, build_configurations = nil, project_object_version = nil, podfile_plugins = {})
42
+ def initialize(cache_key_by_target_label = {}, build_configurations = nil, project_object_version = nil, podfile_plugins = {}, installation_options = {})
37
43
  @cache_key_by_target_label = cache_key_by_target_label
38
44
  @build_configurations = build_configurations
39
45
  @project_object_version = project_object_version
40
46
  @podfile_plugins = podfile_plugins
47
+ @installation_options = installation_options
41
48
  end
42
49
 
43
50
  def update_cache_key_by_target_label!(cache_key_by_target_label)
@@ -56,6 +63,10 @@ module Pod
56
63
  @podfile_plugins = podfile_plugins
57
64
  end
58
65
 
66
+ def update_installation_options!(installation_options)
67
+ @installation_options = installation_options
68
+ end
69
+
59
70
  def save_as(path)
60
71
  Pathname(path).dirname.mkpath
61
72
  Sandbox.update_changed_file(path, YAMLHelper.convert(to_hash))
@@ -71,7 +82,8 @@ module Pod
71
82
  project_object_version = contents['OBJECT_VERSION']
72
83
  build_configurations = contents['BUILD_CONFIGURATIONS']
73
84
  podfile_plugins = contents['PLUGINS']
74
- ProjectInstallationCache.new(cache_key_by_target_label, build_configurations, project_object_version, podfile_plugins)
85
+ installation_options = contents['INSTALLATION_OPTIONS']
86
+ ProjectInstallationCache.new(cache_key_by_target_label, build_configurations, project_object_version, podfile_plugins, installation_options)
75
87
  end
76
88
 
77
89
  def to_hash
@@ -82,6 +94,7 @@ module Pod
82
94
  contents['BUILD_CONFIGURATIONS'] = build_configurations if build_configurations
83
95
  contents['OBJECT_VERSION'] = project_object_version if project_object_version
84
96
  contents['PLUGINS'] = podfile_plugins if podfile_plugins
97
+ contents['INSTALLATION_OPTIONS'] = installation_options if installation_options
85
98
  contents
86
99
  end
87
100
  end
@@ -136,7 +136,7 @@ module Pod
136
136
  'PROJECT_NAME' => pod_target.project_name,
137
137
  }
138
138
  if is_local_pod
139
- relative_file_paths = pod_target.all_files.map { |f| Pathname.new(f).relative_path_from(sandbox.root).to_s }
139
+ relative_file_paths = pod_target.all_files.map { |f| f.relative_path_from(sandbox.root).to_s }
140
140
  contents['FILES'] = relative_file_paths.sort_by(&:downcase)
141
141
  end
142
142
  contents['CHECKOUT_OPTIONS'] = checkout_options if checkout_options
@@ -161,9 +161,12 @@ module Pod
161
161
  contents = {
162
162
  'BUILD_SETTINGS_CHECKSUM' => build_settings,
163
163
  }
164
- if aggregate_target.includes_resources?
165
- relative_file_paths = aggregate_target.resource_paths_by_config.values.flatten.uniq
166
- contents['FILES'] = relative_file_paths.sort_by(&:downcase)
164
+ if aggregate_target.includes_resources? || aggregate_target.includes_on_demand_resources?
165
+ relative_resource_file_paths = aggregate_target.resource_paths_by_config.values.flatten.uniq
166
+ relative_on_demand_resource_file_paths = aggregate_target.on_demand_resources.map do |res|
167
+ res.relative_path_from(sandbox.project_path.dirname).to_s
168
+ end
169
+ contents['FILES'] = (relative_resource_file_paths + relative_on_demand_resource_file_paths).sort_by(&:downcase)
167
170
  end
168
171
  TargetCacheKey.new(sandbox, :aggregate, contents)
169
172
  end
@@ -32,7 +32,8 @@ module Pod
32
32
  # For messages extensions, this only applies if it's embedded in a messages
33
33
  # application.
34
34
  #
35
- EMBED_FRAMEWORK_TARGET_TYPES = [:application, :application_on_demand_install_capable, :unit_test_bundle, :ui_test_bundle, :watch2_extension, :messages_application].freeze
35
+ EMBED_FRAMEWORK_TARGET_TYPES = [:application, :application_on_demand_install_capable, :unit_test_bundle,
36
+ :ui_test_bundle, :watch2_extension, :messages_application].freeze
36
37
 
37
38
  # @return [String] the name of the embed frameworks phase
38
39
  #
@@ -326,11 +327,18 @@ module Pod
326
327
 
327
328
  def reorder_script_phase(native_target, script_phase, execution_position)
328
329
  return if execution_position == :any || execution_position.to_s.empty?
329
- target_phase_type = Xcodeproj::Project::Object::PBXSourcesBuildPhase
330
+ target_phase_type = case execution_position
331
+ when :before_compile, :after_compile
332
+ Xcodeproj::Project::Object::PBXSourcesBuildPhase
333
+ when :before_headers, :after_headers
334
+ Xcodeproj::Project::Object::PBXHeadersBuildPhase
335
+ else
336
+ raise ArgumentError, "Unknown execution position `#{execution_position}`"
337
+ end
330
338
  order_before = case execution_position
331
- when :before_compile
339
+ when :before_compile, :before_headers
332
340
  true
333
- when :after_compile
341
+ when :after_compile, :after_headers
334
342
  false
335
343
  else
336
344
  raise ArgumentError, "Unknown execution position `#{execution_position}`"
@@ -387,10 +395,10 @@ module Pod
387
395
 
388
396
  # Returns the framework input paths for the given framework paths
389
397
  #
390
- # @param [Hash<Array<Xcode::FrameworkPaths>>] framework_paths
398
+ # @param [Array<Xcode::FrameworkPaths>] framework_paths
391
399
  # The target's framework paths to map to input paths.
392
400
  #
393
- # @param [Hash<Array<XCFramework>>] xcframeworks
401
+ # @param [Array<XCFramework>] xcframeworks
394
402
  # The target's xcframeworks to map to input paths.
395
403
  #
396
404
  # @return [Array<String>] The embed frameworks script input paths
@@ -426,6 +434,119 @@ module Pod
426
434
  end
427
435
  paths + xcframework_paths
428
436
  end
437
+
438
+ # Updates a projects native targets to include on demand resources specified by the supplied parameters.
439
+ # Note that currently, only app level targets are allowed to include on demand resources.
440
+ #
441
+ # @param [Sandbox] sandbox
442
+ # The sandbox to use for calculating ODR file references.
443
+ #
444
+ # @param [Xcodeproj::Project] project
445
+ # The project to update known asset tags as well as add the ODR group.
446
+ #
447
+ # @param [Xcodeproj::PBXNativeTarget, Array<Xcodeproj::PBXNativeTarget>] native_targets
448
+ # The native targets to integrate on demand resources into.
449
+ #
450
+ # @param [Sandbox::FileAccessor, Array<Sandbox::FileAccessor>] file_accessors
451
+ # The file accessors that that provide the ODRs to integrate.
452
+ #
453
+ # @param [Xcodeproj::PBXGroup] parent_odr_group
454
+ # The group to use as the parent to add ODR file references into.
455
+ #
456
+ # @param [String] target_odr_group_name
457
+ # The name to use for the group created that contains the ODR file references.
458
+ #
459
+ # @return [void]
460
+ #
461
+ def update_on_demand_resources(sandbox, project, native_targets, file_accessors, parent_odr_group,
462
+ target_odr_group_name)
463
+ category_to_tags = {}
464
+ file_accessors = Array(file_accessors)
465
+ native_targets = Array(native_targets)
466
+
467
+ # Target no longer provides ODR references so remove everything related to this target.
468
+ if file_accessors.all? { |fa| fa.on_demand_resources.empty? }
469
+ old_target_odr_group = parent_odr_group[target_odr_group_name]
470
+ old_odr_file_refs = old_target_odr_group&.recursive_children_groups&.each_with_object({}) do |group, hash|
471
+ hash[group.name] = group.files
472
+ end || {}
473
+ native_targets.each do |native_target|
474
+ native_target.remove_on_demand_resources(old_odr_file_refs)
475
+ update_on_demand_resources_build_settings(native_target, nil => old_odr_file_refs.keys)
476
+ end
477
+ old_target_odr_group&.remove_from_project
478
+ return
479
+ end
480
+
481
+ target_odr_group = parent_odr_group[target_odr_group_name] || parent_odr_group.new_group(target_odr_group_name)
482
+ current_file_refs = target_odr_group.recursive_children_groups.flat_map(&:files)
483
+
484
+ added_file_refs = file_accessors.flat_map do |file_accessor|
485
+ target_odr_files_refs = Hash[file_accessor.on_demand_resources.map do |tag, value|
486
+ tag_group = target_odr_group[tag] || target_odr_group.new_group(tag)
487
+ category_to_tags[value[:category]] ||= []
488
+ category_to_tags[value[:category]] << tag
489
+ resources_file_refs = value[:paths].map do |resource|
490
+ odr_resource_file_ref = Pathname.new(resource).relative_path_from(sandbox.root)
491
+ tag_group.find_file_by_path(odr_resource_file_ref.to_s) || tag_group.new_file(odr_resource_file_ref)
492
+ end
493
+ [tag, resources_file_refs]
494
+ end]
495
+ native_targets.each do |native_target|
496
+ native_target.add_on_demand_resources(target_odr_files_refs)
497
+ end
498
+ target_odr_files_refs.values.flatten
499
+ end
500
+
501
+ # if the target ODR file references were updated, make sure we remove the ones that are no longer present
502
+ # for the target.
503
+ remaining_refs = current_file_refs - added_file_refs
504
+ remaining_refs.each do |ref|
505
+ native_targets.each do |user_target|
506
+ user_target.resources_build_phase.remove_file_reference(ref)
507
+ end
508
+ ref.remove_from_project
509
+ end
510
+ target_odr_group.recursive_children_groups.each { |g| g.remove_from_project if g.empty? }
511
+
512
+ attributes = project.root_object.attributes
513
+ attributes['KnownAssetTags'] = (attributes['KnownAssetTags'] ||= []) | category_to_tags.values.flatten
514
+ project.root_object.attributes = attributes
515
+
516
+ native_targets.each do |native_target|
517
+ update_on_demand_resources_build_settings(native_target, category_to_tags)
518
+ end
519
+ end
520
+
521
+ def update_on_demand_resources_build_settings(native_target, category_to_tags)
522
+ %w[ON_DEMAND_RESOURCES_INITIAL_INSTALL_TAGS ON_DEMAND_RESOURCES_PREFETCH_ORDER].each do |category_key|
523
+ native_target.build_configurations.each do |c|
524
+ key = case category_key
525
+ when 'ON_DEMAND_RESOURCES_INITIAL_INSTALL_TAGS'
526
+ :initial_install
527
+ when 'ON_DEMAND_RESOURCES_PREFETCH_ORDER'
528
+ :prefetched
529
+ else
530
+ :download_on_demand
531
+ end
532
+ tags_for_category = (c.build_settings[category_key] || '').split
533
+ category_to_tags_dup = category_to_tags.dup
534
+ tags_to_add = category_to_tags_dup.delete(key) || []
535
+ tags_to_delete = category_to_tags_dup.values.flatten
536
+ tags_for_category = (tags_for_category + tags_to_add - tags_to_delete).flatten.compact.uniq
537
+ if tags_for_category.empty?
538
+ val = c.build_settings.delete(category_key)
539
+ native_target.project.mark_dirty! unless val.nil?
540
+ else
541
+ tags = tags_for_category.join(' ')
542
+ unless c.build_settings[category_key] == tags
543
+ c.build_settings[category_key] = tags
544
+ native_target.project.mark_dirty!
545
+ end
546
+ end
547
+ end
548
+ end
549
+ end
429
550
  end
430
551
 
431
552
  # Integrates the user project targets. Only the targets that do **not**
@@ -445,6 +566,7 @@ module Pod
445
566
  add_copy_resources_script_phase
446
567
  add_check_manifest_lock_script_phase
447
568
  add_user_script_phases
569
+ add_on_demand_resources
448
570
  end
449
571
  end
450
572
 
@@ -509,10 +631,12 @@ module Pod
509
631
  output_paths_by_config = {}
510
632
  if use_input_output_paths
511
633
  target.resource_paths_by_config.each do |config, resource_paths|
512
- input_paths_key = XCFileListConfigKey.new(target.copy_resources_script_input_files_path(config), target.copy_resources_script_input_files_relative_path)
634
+ input_paths_key = XCFileListConfigKey.new(target.copy_resources_script_input_files_path(config),
635
+ target.copy_resources_script_input_files_relative_path)
513
636
  input_paths_by_config[input_paths_key] = [script_path] + resource_paths
514
637
 
515
- output_paths_key = XCFileListConfigKey.new(target.copy_resources_script_output_files_path(config), target.copy_resources_script_output_files_relative_path)
638
+ output_paths_key = XCFileListConfigKey.new(target.copy_resources_script_output_files_path(config),
639
+ target.copy_resources_script_output_files_relative_path)
516
640
  output_paths_by_config[output_paths_key] = TargetIntegrator.resource_output_paths(resource_paths)
517
641
  end
518
642
  end
@@ -520,7 +644,9 @@ module Pod
520
644
  native_targets.each do |native_target|
521
645
  # Static library targets cannot include resources. Skip this phase from being added instead.
522
646
  next if native_target.symbol_type == :static_library
523
- TargetIntegrator.create_or_update_copy_resources_script_phase_to_target(native_target, script_path, input_paths_by_config, output_paths_by_config)
647
+ TargetIntegrator.create_or_update_copy_resources_script_phase_to_target(native_target, script_path,
648
+ input_paths_by_config,
649
+ output_paths_by_config)
524
650
  end
525
651
  end
526
652
 
@@ -624,6 +750,20 @@ module Pod
624
750
  end
625
751
  end
626
752
 
753
+ def add_on_demand_resources
754
+ target.pod_targets.each do |pod_target|
755
+ # When integrating with the user's project we are only interested in integrating ODRs from library specs
756
+ # and not test specs or app specs.
757
+ library_file_accessors = pod_target.file_accessors.select { |fa| fa.spec.library_specification? }
758
+ target_odr_group_name = "#{pod_target.label}-OnDemandResources"
759
+ # The 'Pods' group would always be there for production code however for tests its sometimes not added.
760
+ # This ensures its always present and makes it easier for existing and new tests.
761
+ parent_odr_group = target.user_project.main_group['Pods'] || target.user_project.new_group('Pods')
762
+ TargetIntegrator.update_on_demand_resources(target.sandbox, target.user_project, target.user_targets,
763
+ library_file_accessors, parent_odr_group, target_odr_group_name)
764
+ end
765
+ end
766
+
627
767
  private
628
768
 
629
769
  # @!group Private Helpers