cocoapods 1.10.2 → 1.11.0

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 +214 -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/cat.rb +3 -1
  7. data/lib/cocoapods/command/spec/lint.rb +1 -1
  8. data/lib/cocoapods/command/spec/which.rb +3 -1
  9. data/lib/cocoapods/command/spec.rb +18 -9
  10. data/lib/cocoapods/config.rb +1 -1
  11. data/lib/cocoapods/downloader/cache.rb +95 -6
  12. data/lib/cocoapods/downloader.rb +4 -2
  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 +4 -48
  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/analyzer/sandbox_analyzer.rb +31 -4
  22. data/lib/cocoapods/installer/analyzer.rb +12 -8
  23. data/lib/cocoapods/installer/podfile_validator.rb +2 -2
  24. data/lib/cocoapods/installer/pre_integrate_hooks_context.rb +9 -0
  25. data/lib/cocoapods/installer/project_cache/project_cache_analyzer.rb +9 -2
  26. data/lib/cocoapods/installer/project_cache/project_installation_cache.rb +15 -2
  27. data/lib/cocoapods/installer/project_cache/target_cache_key.rb +7 -4
  28. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +149 -9
  29. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +10 -3
  30. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +25 -6
  31. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +6 -19
  32. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +63 -56
  33. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +48 -6
  34. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +2 -2
  35. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +2 -5
  36. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +1 -1
  37. data/lib/cocoapods/installer.rb +52 -4
  38. data/lib/cocoapods/resolver.rb +4 -4
  39. data/lib/cocoapods/sandbox/file_accessor.rb +48 -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 +26 -19
@@ -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
@@ -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