cocoapods 1.10.2 → 1.11.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +175 -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 +1 -17
  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 +3 -3
  29. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +106 -5
  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 +63 -56
  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 +42 -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/aggregate_target.rb +23 -1
  45. data/lib/cocoapods/target/build_settings.rb +45 -20
  46. data/lib/cocoapods/target/pod_target.rb +47 -22
  47. data/lib/cocoapods/user_interface.rb +4 -0
  48. data/lib/cocoapods/validator.rb +24 -4
  49. data/lib/cocoapods/version_metadata.rb +1 -1
  50. data/lib/cocoapods/xcode/xcframework.rb +8 -3
  51. metadata +28 -21
@@ -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,8 +161,8 @@ 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
164
+ if aggregate_target.includes_resources? || aggregate_target.includes_on_demand_resources?
165
+ relative_file_paths = aggregate_target.resource_paths_by_config.values.flatten.uniq + aggregate_target.on_demand_resources.map(&:to_s)
166
166
  contents['FILES'] = relative_file_paths.sort_by(&:downcase)
167
167
  end
168
168
  TargetCacheKey.new(sandbox, :aggregate, contents)
@@ -326,11 +326,18 @@ module Pod
326
326
 
327
327
  def reorder_script_phase(native_target, script_phase, execution_position)
328
328
  return if execution_position == :any || execution_position.to_s.empty?
329
- target_phase_type = Xcodeproj::Project::Object::PBXSourcesBuildPhase
329
+ target_phase_type = case execution_position
330
+ when :before_compile, :after_compile
331
+ Xcodeproj::Project::Object::PBXSourcesBuildPhase
332
+ when :before_headers, :after_headers
333
+ Xcodeproj::Project::Object::PBXHeadersBuildPhase
334
+ else
335
+ raise ArgumentError, "Unknown execution position `#{execution_position}`"
336
+ end
330
337
  order_before = case execution_position
331
- when :before_compile
338
+ when :before_compile, :before_headers
332
339
  true
333
- when :after_compile
340
+ when :after_compile, :after_headers
334
341
  false
335
342
  else
336
343
  raise ArgumentError, "Unknown execution position `#{execution_position}`"
@@ -387,10 +394,10 @@ module Pod
387
394
 
388
395
  # Returns the framework input paths for the given framework paths
389
396
  #
390
- # @param [Hash<Array<Xcode::FrameworkPaths>>] framework_paths
397
+ # @param [Array<Xcode::FrameworkPaths>] framework_paths
391
398
  # The target's framework paths to map to input paths.
392
399
  #
393
- # @param [Hash<Array<XCFramework>>] xcframeworks
400
+ # @param [Array<XCFramework>] xcframeworks
394
401
  # The target's xcframeworks to map to input paths.
395
402
  #
396
403
  # @return [Array<String>] The embed frameworks script input paths
@@ -426,6 +433,85 @@ module Pod
426
433
  end
427
434
  paths + xcframework_paths
428
435
  end
436
+
437
+ # Updates a projects native targets to include on demand resources specified by the supplied parameters.
438
+ # Note that currently, only app level targets are allowed to include on demand resources.
439
+ #
440
+ # @param [Sandbox] sandbox
441
+ # The sandbox to use for calculating ODR file references.
442
+ #
443
+ # @param [Xcodeproj::Project] project
444
+ # The project to update known asset tags as well as add the ODR group.
445
+ #
446
+ # @param [Xcodeproj::PBXNativeTarget, Array<Xcodeproj::PBXNativeTarget>] native_targets
447
+ # The native targets to integrate on demand resources into.
448
+ #
449
+ # @param [Sandbox::FileAccessor, Array<Sandbox::FileAccessor>] file_accessors
450
+ # The file accessors that that provide the ODRs to integrate.
451
+ #
452
+ # @param [Xcodeproj::PBXGroup] parent_odr_group
453
+ # The group to use as the parent to add ODR file references into.
454
+ #
455
+ # @param [String] target_odr_group_name
456
+ # The name to use for the group created that contains the ODR file references.
457
+ #
458
+ # @return [void]
459
+ #
460
+ def add_on_demand_resources(sandbox, project, native_targets, file_accessors, parent_odr_group,
461
+ target_odr_group_name)
462
+ asset_tags_added = Set.new
463
+ file_accessors = Array(file_accessors)
464
+ native_targets = Array(native_targets)
465
+
466
+ # Target no longer provides ODR references so remove everything related to this target.
467
+ if file_accessors.all? { |fa| fa.on_demand_resources.empty? }
468
+ old_target_odr_group = parent_odr_group[target_odr_group_name]
469
+ old_odr_file_refs = old_target_odr_group&.recursive_children_groups&.each_with_object({}) do |group, hash|
470
+ hash[group.name] = group.files
471
+ end || {}
472
+ native_targets.each do |user_target|
473
+ user_target.remove_on_demand_resources(old_odr_file_refs)
474
+ end
475
+ old_target_odr_group&.remove_from_project
476
+ return
477
+ end
478
+
479
+ target_odr_group = parent_odr_group[target_odr_group_name] || parent_odr_group.new_group(target_odr_group_name)
480
+ current_file_refs = target_odr_group.recursive_children_groups.flat_map(&:files)
481
+
482
+ added_file_refs = file_accessors.flat_map do |file_accessor|
483
+ target_odr_files_refs = Hash[file_accessor.on_demand_resources.map do |tag, resources|
484
+ tag_group = target_odr_group[tag] || target_odr_group.new_group(tag)
485
+ asset_tags_added << tag
486
+ resources_file_refs = resources.map do |resource|
487
+ odr_resource_file_ref = Pathname.new(resource).relative_path_from(sandbox.root)
488
+ tag_group.find_file_by_path(odr_resource_file_ref.to_s) || tag_group.new_file(odr_resource_file_ref)
489
+ end
490
+ [tag, resources_file_refs]
491
+ end]
492
+ native_targets.each do |user_target|
493
+ user_target.add_on_demand_resources(target_odr_files_refs)
494
+ end
495
+ target_odr_files_refs.values.flatten
496
+ end
497
+
498
+ # if the target ODR file references were updated, make sure we remove the ones that are no longer present
499
+ # for the target.
500
+ remaining_refs = current_file_refs - added_file_refs
501
+ remaining_refs.each do |ref|
502
+ native_targets.each do |user_target|
503
+ user_target.resources_build_phase.remove_file_reference(ref)
504
+ end
505
+ ref.remove_from_project
506
+ end
507
+ target_odr_group.recursive_children_groups.each { |g| g.remove_from_project if g.empty? }
508
+
509
+ unless asset_tags_added.empty?
510
+ attributes = project.root_object.attributes
511
+ attributes['KnownAssetTags'] = (attributes['KnownAssetTags'] ||= []) | asset_tags_added.to_a
512
+ project.root_object.attributes = attributes
513
+ end
514
+ end
429
515
  end
430
516
 
431
517
  # Integrates the user project targets. Only the targets that do **not**
@@ -445,6 +531,7 @@ module Pod
445
531
  add_copy_resources_script_phase
446
532
  add_check_manifest_lock_script_phase
447
533
  add_user_script_phases
534
+ add_on_demand_resources
448
535
  end
449
536
  end
450
537
 
@@ -624,6 +711,20 @@ module Pod
624
711
  end
625
712
  end
626
713
 
714
+ def add_on_demand_resources
715
+ target.pod_targets.each do |pod_target|
716
+ # When integrating with the user's project we are only interested in integrating ODRs from library specs
717
+ # and not test specs or app specs.
718
+ library_file_accessors = pod_target.file_accessors.select { |fa| fa.spec.library_specification? }
719
+ target_odr_group_name = "#{pod_target.label}-OnDemandResources"
720
+ # The 'Pods' group would always be there for production code however for tests its sometimes not added.
721
+ # This ensures its always present and makes it easier for existing and new tests.
722
+ parent_odr_group = target.user_project.main_group['Pods'] || target.user_project.new_group('Pods')
723
+ TargetIntegrator.add_on_demand_resources(target.sandbox, target.user_project, target.user_targets,
724
+ library_file_accessors, parent_odr_group, target_odr_group_name)
725
+ end
726
+ end
727
+
627
728
  private
628
729
 
629
730
  # @!group Private Helpers
@@ -247,7 +247,7 @@ module Pod
247
247
  end
248
248
  is_custom_host = !hosted_test_specs_by_host.empty?
249
249
  specs.each do |spec|
250
- scheme_name = spec.spec_type == :library ? pod_target.label : pod_target.non_library_spec_label(spec)
250
+ scheme_name = pod_target.spec_label(spec)
251
251
  scheme_configuration = pod_target.scheme_for_spec(spec)
252
252
  if !scheme_configuration.empty? || is_custom_host
253
253
  scheme_path = Xcodeproj::XCScheme.user_data_dir(project.path) + "#{scheme_name}.xcscheme"
@@ -45,6 +45,11 @@ module Pod
45
45
  #
46
46
  attr_reader :info_plist_entries
47
47
 
48
+ # @return [String] product_basename
49
+ # The product basename to use for the target.
50
+ #
51
+ attr_reader :product_basename
52
+
48
53
  # Initialize a new instance
49
54
  #
50
55
  # @param [Sandbox] sandbox @see #sandbox
@@ -55,8 +60,9 @@ module Pod
55
60
  # @param [String] app_target_label see #app_target_label
56
61
  # @param [Boolean] add_main see #add_main
57
62
  # @param [Hash] info_plist_entries see #info_plist_entries
63
+ # @param [String] product_basename see #product_basename
58
64
  #
59
- def initialize(sandbox, project, platform, subgroup_name, group_name, app_target_label, add_main: true, add_launchscreen_storyboard: platform == :ios, info_plist_entries: {})
65
+ def initialize(sandbox, project, platform, subgroup_name, group_name, app_target_label, add_main: true, add_launchscreen_storyboard: platform == :ios, info_plist_entries: {}, product_basename: nil)
60
66
  @sandbox = sandbox
61
67
  @project = project
62
68
  @platform = platform
@@ -66,6 +72,7 @@ module Pod
66
72
  @add_main = add_main
67
73
  @add_launchscreen_storyboard = add_launchscreen_storyboard
68
74
  @info_plist_entries = info_plist_entries
75
+ @product_basename = product_basename || app_target_label
69
76
  target_group = project.pod_group(group_name)
70
77
  @group = target_group[subgroup_name] || target_group.new_group(subgroup_name)
71
78
  end
@@ -75,9 +82,9 @@ module Pod
75
82
  def install!
76
83
  platform_name = platform.name
77
84
  app_host_target = Pod::Generator::AppTargetHelper.add_app_target(project, platform_name, deployment_target,
78
- app_target_label)
85
+ app_target_label, product_basename)
79
86
  app_host_target.build_configurations.each do |configuration|
80
- configuration.build_settings['PRODUCT_NAME'] = app_target_label
87
+ configuration.build_settings['PRODUCT_NAME'] = product_basename
81
88
  configuration.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
82
89
  if platform == :osx
83
90
  configuration.build_settings['CODE_SIGN_IDENTITY'] = ''
@@ -6,6 +6,9 @@ module Pod
6
6
  # specifications in the Pods project.
7
7
  #
8
8
  class FileReferencesInstaller
9
+ # Regex for extracting the region portion of a localized file path. Ex. `Resources/en.lproj` --> `en`
10
+ LOCALIZATION_REGION_FILEPATTERN_REGEX = /(\/|^)(?<region>[^\/]*?)\.lproj(\/|$)/
11
+
9
12
  # @return [Sandbox] The sandbox of the installation.
10
13
  #
11
14
  attr_reader :sandbox
@@ -126,8 +129,9 @@ module Pod
126
129
  #
127
130
  def add_resources
128
131
  UI.message '- Adding resources' do
129
- add_file_accessors_paths_to_pods_group(:resources, :resources, true)
130
- add_file_accessors_paths_to_pods_group(:resource_bundle_files, :resources, true)
132
+ refs = add_file_accessors_paths_to_pods_group(:resources, :resources, true)
133
+ refs.concat add_file_accessors_paths_to_pods_group(:resource_bundle_files, :resources, true)
134
+ add_known_regions(refs)
131
135
  end
132
136
  end
133
137
 
@@ -207,20 +211,20 @@ module Pod
207
211
  # Whether organizing a local pod's files in subgroups inside
208
212
  # the pod's group is allowed.
209
213
  #
210
- # @return [void]
214
+ # @return [Array<PBXFileReference>] the added file references
211
215
  #
212
216
  def add_file_accessors_paths_to_pods_group(file_accessor_key, group_key = nil, reflect_file_system_structure = false)
213
- file_accessors.each do |file_accessor|
217
+ file_accessors.flat_map do |file_accessor|
214
218
  paths = file_accessor.send(file_accessor_key)
215
219
  paths = allowable_project_paths(paths)
216
- next if paths.empty?
220
+ next [] if paths.empty?
217
221
 
218
222
  pod_name = file_accessor.spec.name
219
223
  preserve_pod_file_structure_flag = (sandbox.local?(pod_name) || preserve_pod_file_structure) && reflect_file_system_structure
220
224
  base_path = preserve_pod_file_structure_flag ? common_path(paths) : nil
221
225
  actual_group_key = preserve_pod_file_structure_flag ? nil : group_key
222
226
  group = pods_project.group_for_spec(pod_name, actual_group_key)
223
- paths.each do |path|
227
+ paths.map do |path|
224
228
  pods_project.add_file_reference(path, group, preserve_pod_file_structure_flag, base_path)
225
229
  end
226
230
  end
@@ -302,6 +306,21 @@ module Pod
302
306
  return result unless result.to_s == '' || result.to_s == '/'
303
307
  end
304
308
 
309
+ # Adds the known localization regions to the root of the project
310
+ #
311
+ # @param [Array<PBXFileReferences>] file_references the resource file references
312
+ #
313
+ def add_known_regions(file_references)
314
+ pattern = LOCALIZATION_REGION_FILEPATTERN_REGEX
315
+ regions = file_references.map do |ref|
316
+ if (match = ref.path.to_s.match(pattern))
317
+ match[:region]
318
+ end
319
+ end.compact
320
+
321
+ pods_project.root_object.known_regions = (pods_project.root_object.known_regions | regions).sort
322
+ end
323
+
305
324
  #-----------------------------------------------------------------------#
306
325
  end
307
326
  end