cocoapods 1.4.0 → 1.5.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +149 -0
  3. data/lib/cocoapods.rb +1 -0
  4. data/lib/cocoapods/command/outdated.rb +2 -2
  5. data/lib/cocoapods/command/repo/push.rb +5 -0
  6. data/lib/cocoapods/command/update.rb +21 -5
  7. data/lib/cocoapods/gem_version.rb +1 -1
  8. data/lib/cocoapods/generator/acknowledgements.rb +6 -3
  9. data/lib/cocoapods/generator/constant.rb +19 -0
  10. data/lib/cocoapods/generator/copy_resources_script.rb +15 -3
  11. data/lib/cocoapods/generator/embed_frameworks_script.rb +11 -2
  12. data/lib/cocoapods/generator/module_map.rb +56 -5
  13. data/lib/cocoapods/generator/xcconfig/aggregate_xcconfig.rb +19 -13
  14. data/lib/cocoapods/generator/xcconfig/pod_xcconfig.rb +4 -6
  15. data/lib/cocoapods/generator/xcconfig/xcconfig_helper.rb +25 -2
  16. data/lib/cocoapods/installer.rb +17 -8
  17. data/lib/cocoapods/installer/analyzer.rb +48 -38
  18. data/lib/cocoapods/installer/analyzer/analysis_result.rb +11 -0
  19. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +7 -6
  20. data/lib/cocoapods/installer/analyzer/pod_variant.rb +8 -8
  21. data/lib/cocoapods/installer/analyzer/pod_variant_set.rb +3 -3
  22. data/lib/cocoapods/installer/analyzer/podfile_dependency_cache.rb +54 -0
  23. data/lib/cocoapods/installer/analyzer/specs_state.rb +16 -16
  24. data/lib/cocoapods/installer/analyzer/target_inspector.rb +7 -11
  25. data/lib/cocoapods/installer/pod_source_installer.rb +2 -3
  26. data/lib/cocoapods/installer/podfile_validator.rb +11 -10
  27. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +72 -28
  28. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +8 -2
  29. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +9 -0
  30. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +32 -24
  31. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +97 -54
  32. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +9 -11
  33. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +4 -9
  34. data/lib/cocoapods/installer/xcode/target_validator.rb +32 -18
  35. data/lib/cocoapods/project.rb +32 -17
  36. data/lib/cocoapods/resolver.rb +59 -31
  37. data/lib/cocoapods/resolver/lazy_specification.rb +28 -18
  38. data/lib/cocoapods/sandbox.rb +2 -4
  39. data/lib/cocoapods/sandbox/file_accessor.rb +25 -9
  40. data/lib/cocoapods/sandbox/headers_store.rb +31 -6
  41. data/lib/cocoapods/sandbox/path_list.rb +36 -46
  42. data/lib/cocoapods/target.rb +7 -4
  43. data/lib/cocoapods/target/aggregate_target.rb +10 -8
  44. data/lib/cocoapods/target/pod_target.rb +87 -20
  45. data/lib/cocoapods/user_interface/error_report.rb +1 -1
  46. data/lib/cocoapods/user_interface/inspector_reporter.rb +4 -4
  47. data/lib/cocoapods/validator.rb +40 -29
  48. metadata +11 -9
@@ -55,12 +55,16 @@ module Pod
55
55
  includes_static_libs = !target.requires_frameworks?
56
56
  includes_static_libs ||= pod_targets.flat_map(&:file_accessors).any? { |fa| !fa.vendored_static_artifacts.empty? }
57
57
  config = {
58
+ 'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ',
59
+ 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
60
+ 'HEADER_SEARCH_PATHS' => '$(inherited) ',
61
+ 'LIBRARY_SEARCH_PATHS' => '$(inherited) ',
62
+ 'OTHER_CFLAGS' => '$(inherited) ',
58
63
  'OTHER_LDFLAGS' => '$(inherited) ' + XCConfigHelper.default_ld_flags(target, includes_static_libs),
64
+ 'OTHER_SWIFT_FLAGS' => '$(inherited) ',
59
65
  'PODS_PODFILE_DIR_PATH' => target.podfile_dir_relative_path,
60
66
  'PODS_ROOT' => target.relative_pods_root,
61
- 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
62
- 'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ',
63
- 'LIBRARY_SEARCH_PATHS' => '$(inherited) ',
67
+ 'SWIFT_INCLUDE_PATHS' => '$(inherited) ',
64
68
  }.merge(embedded_content_settings)
65
69
 
66
70
  @xcconfig = Xcodeproj::Config.new(config)
@@ -139,13 +143,15 @@ module Pod
139
143
  "#{target.build_product_path}/Headers"
140
144
  end
141
145
  build_settings = {
146
+ # TODO: remove quote imports in CocoaPods 2.0
142
147
  # Make framework headers discoverable by `import "…"`
143
- 'OTHER_CFLAGS' => '$(inherited) ' + XCConfigHelper.quote(framework_header_search_paths, '-iquote'),
148
+ 'OTHER_CFLAGS' => XCConfigHelper.quote(framework_header_search_paths, '-iquote'),
144
149
  }
145
150
  if pod_targets.any? { |t| !t.should_build? }
146
151
  # Make library headers discoverable by `#import "…"`
147
152
  library_header_search_paths = target.sandbox.public_headers.search_paths(target.platform)
148
- build_settings['HEADER_SEARCH_PATHS'] = '$(inherited) ' + XCConfigHelper.quote(library_header_search_paths)
153
+ # TODO: remove quote imports in CocoaPods 2.0
154
+ build_settings['HEADER_SEARCH_PATHS'] = XCConfigHelper.quote(library_header_search_paths)
149
155
  build_settings['OTHER_CFLAGS'] += ' ' + XCConfigHelper.quote(library_header_search_paths, '-isystem')
150
156
  end
151
157
  build_settings
@@ -153,21 +159,22 @@ module Pod
153
159
  # Make headers discoverable from $PODS_ROOT/Headers directory
154
160
  header_search_paths = target.sandbox.public_headers.search_paths(target.platform)
155
161
  {
162
+ # TODO: remove quote imports in CocoaPods 2.0
156
163
  # by `#import "…"`
157
- 'HEADER_SEARCH_PATHS' => '$(inherited) ' + XCConfigHelper.quote(header_search_paths),
164
+ 'HEADER_SEARCH_PATHS' => XCConfigHelper.quote(header_search_paths),
158
165
  # by `#import <…>`
159
- 'OTHER_CFLAGS' => '$(inherited) ' + XCConfigHelper.quote(header_search_paths, '-isystem'),
166
+ 'OTHER_CFLAGS' => XCConfigHelper.quote(header_search_paths, '-isystem'),
160
167
  }
161
168
  end
162
169
  end
163
170
 
164
171
  private
165
172
 
166
- # Add build settings, which ensure that the pod targets can be imported
167
- # from the integrating target by all sort of imports, which are:
168
- # - `#import <…>`
169
- # - `#import "…"`
170
- # - `@import …;` / `import …`
173
+ # Add build settings, which ensure that the pod targets can be imported from the integrating target.
174
+ # For >= 1.5.0 we use modular (stricter) header search paths this means that the integrated target will only be
175
+ # able to import public headers using `<>` or `@import` notation, but never import any private headers.
176
+ #
177
+ # For < 1.5.0 legacy header search paths the same rules apply: It's the wild west.
171
178
  #
172
179
  def generate_settings_to_import_pod_targets
173
180
  @xcconfig.merge! XCConfigHelper.search_paths_for_dependent_targets(target, pod_targets)
@@ -176,7 +183,6 @@ module Pod
176
183
  generator = AggregateXCConfig.new(search_paths_target, configuration_name)
177
184
  @xcconfig.merge! XCConfigHelper.search_paths_for_dependent_targets(nil, search_paths_target.pod_targets)
178
185
  @xcconfig.merge!(generator.settings_to_import_pod_targets)
179
-
180
186
  # Propagate any HEADER_SEARCH_PATHS settings from the search paths.
181
187
  XCConfigHelper.propagate_header_search_paths_from_search_paths(search_paths_target, @xcconfig)
182
188
  end
@@ -44,22 +44,20 @@ module Pod
44
44
  # @return [Xcodeproj::Config]
45
45
  #
46
46
  def generate
47
- target_search_paths = target.build_headers.search_paths(target.platform)
48
- sandbox_search_paths = target.sandbox.public_headers.search_paths(target.platform)
49
- search_paths = target_search_paths.concat(sandbox_search_paths).uniq
50
-
51
47
  config = {
52
48
  'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ',
53
49
  'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
54
- 'HEADER_SEARCH_PATHS' => XCConfigHelper.quote(search_paths),
50
+ 'HEADER_SEARCH_PATHS' => '$(inherited) ' + XCConfigHelper.quote(target.header_search_paths(@test_xcconfig)),
55
51
  'LIBRARY_SEARCH_PATHS' => '$(inherited) ',
52
+ 'OTHER_CFLAGS' => '$(inherited) ',
56
53
  'OTHER_LDFLAGS' => XCConfigHelper.default_ld_flags(target, @test_xcconfig),
54
+ 'OTHER_SWIFT_FLAGS' => '$(inherited) ',
57
55
  'PODS_ROOT' => '${SRCROOT}',
58
56
  'PODS_TARGET_SRCROOT' => target.pod_target_srcroot,
59
57
  'PRODUCT_BUNDLE_IDENTIFIER' => 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}',
60
58
  'SKIP_INSTALL' => 'YES',
61
59
  'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => '$(inherited) ',
62
- # 'USE_HEADERMAP' => 'NO'
60
+ 'SWIFT_INCLUDE_PATHS' => '$(inherited) ',
63
61
  }
64
62
 
65
63
  @xcconfig = Xcodeproj::Config.new(config)
@@ -140,8 +140,7 @@ module Pod
140
140
  #
141
141
  def self.links_dependency?(aggregate_target, pod_target)
142
142
  return true if aggregate_target.nil? || aggregate_target.target_definition.inheritance == 'complete'
143
- targets = aggregate_target.pod_targets - aggregate_target.search_paths_aggregate_targets.flat_map(&:pod_targets)
144
- targets.include?(pod_target)
143
+ aggregate_target.pod_targets_to_link.include?(pod_target)
145
144
  end
146
145
 
147
146
  # Adds build settings for dynamic vendored frameworks and libraries.
@@ -329,19 +328,43 @@ module Pod
329
328
  build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)
330
329
  end
331
330
 
331
+ module_map_files = []
332
332
  unless dependent_targets.empty?
333
333
  framework_search_paths = []
334
334
  library_search_paths = []
335
+ swift_import_paths = []
335
336
  dependent_targets.each do |dependent_target|
336
337
  if dependent_target.requires_frameworks?
337
338
  framework_search_paths << dependent_target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)
338
339
  else
339
340
  library_search_paths << dependent_target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)
341
+ if dependent_target.defines_module?
342
+ module_map_file = if dependent_target.uses_swift?
343
+ # for swift, we have a custom build phase that copies in the module map, appending the .Swift module
344
+ "${PODS_CONFIGURATION_BUILD_DIR}/#{dependent_target.label}/#{dependent_target.product_module_name}.modulemap"
345
+ else
346
+ "${PODS_ROOT}/#{dependent_target.module_map_path.relative_path_from(dependent_target.sandbox.root)}"
347
+ end
348
+ module_map_files << %(-fmodule-map-file="#{module_map_file}")
349
+ swift_import_paths << dependent_target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE) if dependent_target.uses_swift?
350
+ end
340
351
  end
341
352
  end
353
+
342
354
  build_settings['FRAMEWORK_SEARCH_PATHS'] = XCConfigHelper.quote(framework_search_paths.uniq)
343
355
  build_settings['LIBRARY_SEARCH_PATHS'] = XCConfigHelper.quote(library_search_paths.uniq)
356
+ build_settings['SWIFT_INCLUDE_PATHS'] = XCConfigHelper.quote(swift_import_paths.uniq)
357
+ end
358
+
359
+ other_swift_flags = module_map_files.tap(&:uniq!).flat_map { |f| ['-Xcc', f] }
360
+ if target.is_a?(PodTarget) && !target.requires_frameworks? && target.defines_module?
361
+ # make it possible for a mixed swift/objc static library to be able to import the objc from within swift
362
+ other_swift_flags += ['-import-underlying-module', '-Xcc', '-fmodule-map-file="${SRCROOT}/${MODULEMAP_FILE}"']
344
363
  end
364
+ # unconditionally set these, because of (the possibility of) having to add the pod targets own module map file
365
+ build_settings['OTHER_CFLAGS'] = module_map_files.join(' ')
366
+ build_settings['OTHER_SWIFT_FLAGS'] = other_swift_flags.join(' ')
367
+
345
368
  build_settings
346
369
  end
347
370
 
@@ -219,8 +219,8 @@ module Pod
219
219
  # generated as result of the analyzer.
220
220
  #
221
221
  def pod_targets
222
- aggregate_target_pod_targets = aggregate_targets.map(&:pod_targets).flatten
223
- test_dependent_targets = aggregate_target_pod_targets.map(&:test_dependent_targets).flatten
222
+ aggregate_target_pod_targets = aggregate_targets.flat_map(&:pod_targets)
223
+ test_dependent_targets = aggregate_target_pod_targets.flat_map(&:test_dependent_targets)
224
224
  (aggregate_target_pod_targets + test_dependent_targets).uniq
225
225
  end
226
226
 
@@ -321,8 +321,17 @@ module Pod
321
321
  root_specs.sort_by(&:name).each do |spec|
322
322
  if pods_to_install.include?(spec.name)
323
323
  if sandbox_state.changed.include?(spec.name) && sandbox.manifest
324
- previous = sandbox.manifest.version(spec.name)
325
- title = "Installing #{spec.name} #{spec.version} (was #{previous})"
324
+ current_version = spec.version
325
+ previous_version = sandbox.manifest.version(spec.name)
326
+ has_changed_version = current_version != previous_version
327
+ current_repo = analysis_result.specs_by_source.detect { |key, values| break key if values.map(&:name).include?(spec.name) }
328
+ current_repo &&= current_repo.url || current_repo.name
329
+ previous_spec_repo = sandbox.manifest.spec_repo(spec.name)
330
+ has_changed_repo = !previous_spec_repo.nil? && current_repo && (current_repo != previous_spec_repo)
331
+ title = "Installing #{spec.name} #{spec.version}"
332
+ title << " (was #{previous_version} and source changed to `#{current_repo}` from `#{previous_spec_repo}`)" if has_changed_version && has_changed_repo
333
+ title << " (was #{previous_version})" if has_changed_version && !has_changed_repo
334
+ title << " (source changed to `#{current_repo}` from `#{previous_spec_repo}`)" if !has_changed_version && has_changed_repo
326
335
  else
327
336
  title = "Installing #{spec}"
328
337
  end
@@ -429,7 +438,7 @@ module Pod
429
438
  end
430
439
 
431
440
  def print_post_install_message
432
- podfile_dependencies = podfile.dependencies.uniq.size
441
+ podfile_dependencies = analysis_result.podfile_dependency_cache.podfile_dependencies.size
433
442
  pods_installed = root_specs.size
434
443
  title_options = { :verbose_prefix => '-> '.green }
435
444
  UI.titled_section('Pod installation complete! ' \
@@ -548,9 +557,9 @@ module Pod
548
557
  # @return [void]
549
558
  #
550
559
  def write_lockfiles
551
- external_source_pods = podfile.dependencies.select(&:external_source).map(&:root_name).uniq
560
+ external_source_pods = analysis_result.podfile_dependency_cache.podfile_dependencies.select(&:external_source).map(&:root_name).uniq
552
561
  checkout_options = sandbox.checkout_sources.select { |root_name, _| external_source_pods.include? root_name }
553
- @lockfile = Lockfile.generate(podfile, analysis_result.specifications, checkout_options)
562
+ @lockfile = Lockfile.generate(podfile, analysis_result.specifications, checkout_options, analysis_result.specs_by_source)
554
563
 
555
564
  UI.message "- Writing Lockfile in #{UI.path config.lockfile_path}" do
556
565
  @lockfile.write_to_disk(config.lockfile_path)
@@ -651,7 +660,7 @@ module Pod
651
660
  #
652
661
  def development_pod_targets
653
662
  pod_targets.select do |pod_target|
654
- sandbox.development_pods.keys.include?(pod_target.pod_name)
663
+ sandbox.local?(pod_target.pod_name)
655
664
  end
656
665
  end
657
666
 
@@ -10,11 +10,12 @@ module Pod
10
10
  delegate_installation_options { podfile }
11
11
 
12
12
  autoload :AnalysisResult, 'cocoapods/installer/analyzer/analysis_result'
13
- autoload :SandboxAnalyzer, 'cocoapods/installer/analyzer/sandbox_analyzer'
14
- autoload :SpecsState, 'cocoapods/installer/analyzer/specs_state'
15
13
  autoload :LockingDependencyAnalyzer, 'cocoapods/installer/analyzer/locking_dependency_analyzer'
14
+ autoload :PodfileDependencyCache, 'cocoapods/installer/analyzer/podfile_dependency_cache'
16
15
  autoload :PodVariant, 'cocoapods/installer/analyzer/pod_variant'
17
16
  autoload :PodVariantSet, 'cocoapods/installer/analyzer/pod_variant_set'
17
+ autoload :SandboxAnalyzer, 'cocoapods/installer/analyzer/sandbox_analyzer'
18
+ autoload :SpecsState, 'cocoapods/installer/analyzer/specs_state'
18
19
  autoload :TargetInspectionResult, 'cocoapods/installer/analyzer/target_inspection_result'
19
20
  autoload :TargetInspector, 'cocoapods/installer/analyzer/target_inspector'
20
21
 
@@ -54,6 +55,7 @@ module Pod
54
55
  @has_dependencies = true
55
56
  @test_pod_target_analyzer_cache = {}
56
57
  @test_pod_target_key = Struct.new(:name, :pod_targets)
58
+ @podfile_dependency_cache = PodfileDependencyCache.from_podfile(podfile)
57
59
  end
58
60
 
59
61
  # Performs the analysis.
@@ -71,6 +73,7 @@ module Pod
71
73
  validate_podfile!
72
74
  validate_lockfile_version!
73
75
  @result = AnalysisResult.new
76
+ @result.podfile_dependency_cache = @podfile_dependency_cache
74
77
  if installation_options.integrate_targets?
75
78
  @result.target_inspections = inspect_targets_to_integrate
76
79
  else
@@ -90,6 +93,8 @@ module Pod
90
93
  @result.specs_by_target = resolver_specs_by_target.each_with_object({}) do |rspecs_by_target, hash|
91
94
  hash[rspecs_by_target[0]] = rspecs_by_target[1].map(&:spec)
92
95
  end
96
+ @result.specs_by_source = Hash[resolver_specs_by_target.values.flatten(1).group_by(&:source).map { |source, specs| [source, specs.map(&:spec).uniq] }]
97
+ sources.each { |s| @result.specs_by_source[s] ||= [] }
93
98
  @result
94
99
  end
95
100
 
@@ -184,7 +189,7 @@ module Pod
184
189
  alias_method :specs_updated?, :specs_updated
185
190
 
186
191
  def validate_podfile!
187
- validator = Installer::PodfileValidator.new(podfile)
192
+ validator = Installer::PodfileValidator.new(podfile, @podfile_dependency_cache)
188
193
  validator.validate
189
194
 
190
195
  unless validator.valid?
@@ -232,7 +237,7 @@ module Pod
232
237
  pods_state
233
238
  else
234
239
  state = SpecsState.new
235
- state.added.merge(podfile.dependencies.map(&:root_name))
240
+ state.added.merge(@podfile_dependency_cache.podfile_dependencies.map(&:root_name))
236
241
  state
237
242
  end
238
243
  end
@@ -335,18 +340,18 @@ module Pod
335
340
  end
336
341
 
337
342
  unless embedded_targets_missing_hosts.empty?
338
- embedded_targets_missing_hosts_product_types = Set.new embedded_targets_missing_hosts.map(&:user_targets).flatten.map(&:symbol_type)
343
+ embedded_targets_missing_hosts_product_types = Set.new embedded_targets_missing_hosts.flat_map(&:user_targets).map(&:symbol_type)
344
+ target_names = embedded_targets_missing_hosts.map do |target|
345
+ target.name.sub('Pods-', '') # Make the target names more recognizable to the user
346
+ end.join ', '
339
347
  # If the targets missing hosts are only frameworks, then this is likely
340
348
  # a project for doing framework development. In that case, just warn that
341
349
  # the frameworks that these targets depend on won't be integrated anywhere
342
350
  if embedded_targets_missing_hosts_product_types.subset?(Set.new([:framework, :static_library]))
343
- UI.warn 'The Podfile contains framework or static library targets, for which the Podfile does not contain host targets (targets which embed the framework).' \
351
+ UI.warn "The Podfile contains framework or static library targets (#{target_names}), for which the Podfile does not contain host targets (targets which embed the framework)." \
344
352
  "\n" \
345
353
  'If this project is for doing framework development, you can ignore this message. Otherwise, add a target to the Podfile that embeds these frameworks to make this message go away (e.g. a test target).'
346
354
  else
347
- target_names = embedded_targets_missing_hosts.map do |target|
348
- target.name.sub('Pods-', '') # Make the target names more recognizable to the user
349
- end.join ', '
350
355
  raise Informative, "Unable to find host target(s) for #{target_names}. Please add the host targets for the embedded targets to the Podfile." \
351
356
  "\n" \
352
357
  'Certain kinds of targets require a host target. A host target is a "parent" target which embeds a "child" target. These are example types of targets that need a host target:' \
@@ -393,8 +398,7 @@ module Pod
393
398
  embedded_targets = aggregate_targets.select(&:requires_host_target?)
394
399
  analyze_host_targets_in_podfile(aggregate_targets, embedded_targets)
395
400
 
396
- use_frameworks_embedded_targets = embedded_targets.select(&:requires_frameworks?)
397
- non_use_frameworks_embedded_targets = embedded_targets.reject(&:requires_frameworks?)
401
+ use_frameworks_embedded_targets, non_use_frameworks_embedded_targets = embedded_targets.partition(&:requires_frameworks?)
398
402
  aggregate_targets.each do |target|
399
403
  # For targets that require frameworks, we always have to copy their pods to their
400
404
  # host targets because those frameworks will all be loaded from the host target's bundle
@@ -406,9 +410,9 @@ module Pod
406
410
  end
407
411
  end
408
412
  aggregate_targets.each do |target|
409
- target.search_paths_aggregate_targets = aggregate_targets.select do |aggregate_target|
413
+ target.search_paths_aggregate_targets.concat(aggregate_targets.select do |aggregate_target|
410
414
  target.target_definition.targets_to_inherit_search_paths.include?(aggregate_target.target_definition)
411
- end
415
+ end).freeze
412
416
  end
413
417
  end
414
418
 
@@ -510,8 +514,9 @@ module Pod
510
514
  hash[name] = values.sort_by { |pt| pt.specs.count }
511
515
  end
512
516
  pod_targets.each do |target|
513
- dependencies = transitive_dependencies_for_specs(target.specs.reject(&:test_specification?), target.platform, all_resolver_specs).group_by(&:root)
514
- test_dependencies = transitive_dependencies_for_specs(target.specs.select(&:test_specification?), target.platform, all_resolver_specs).group_by(&:root)
517
+ all_specs = all_resolver_specs.to_set
518
+ dependencies = transitive_dependencies_for_specs(target.non_test_specs.to_set, target.platform, all_specs).group_by(&:root)
519
+ test_dependencies = transitive_dependencies_for_specs(target.test_specs.to_set, target.platform, all_specs).group_by(&:root)
515
520
  test_dependencies.delete_if { |k| dependencies.key? k }
516
521
  target.dependent_targets = filter_dependencies(dependencies, pod_targets_by_name, target)
517
522
  target.test_dependent_targets = filter_dependencies(test_dependencies, pod_targets_by_name, target)
@@ -525,8 +530,9 @@ module Pod
525
530
  end
526
531
 
527
532
  pod_targets.each do |target|
528
- dependencies = transitive_dependencies_for_specs(target.specs.reject(&:test_specification?), target.platform, specs.map(&:spec)).group_by(&:root)
529
- test_dependencies = transitive_dependencies_for_specs(target.specs.select(&:test_specification?), target.platform, specs.map(&:spec)).group_by(&:root)
533
+ all_specs = specs.map(&:spec).to_set
534
+ dependencies = transitive_dependencies_for_specs(target.non_test_specs.to_set, target.platform, all_specs).group_by(&:root)
535
+ test_dependencies = transitive_dependencies_for_specs(target.test_specs.to_set, target.platform, all_specs).group_by(&:root)
530
536
  test_dependencies.delete_if { |k| dependencies.key? k }
531
537
  target.dependent_targets = pod_targets.reject { |t| dependencies[t.root_spec].nil? }
532
538
  target.test_dependent_targets = pod_targets.reject { |t| test_dependencies[t.root_spec].nil? }
@@ -564,16 +570,22 @@ module Pod
564
570
  #
565
571
  def transitive_dependencies_for_specs(specs, platform, all_specs)
566
572
  return [] if specs.empty? || all_specs.empty?
567
- dependent_specs = specs.flat_map do |spec|
568
- spec.consumer(platform).dependencies.flat_map do |dependency|
569
- all_specs.find do |s|
573
+
574
+ dependent_specs = Set.new
575
+ specs.each do |spec|
576
+ spec.consumer(platform).dependencies.each do |dependency|
577
+ match = all_specs.find do |s|
578
+ next false unless s.name == dependency.name
570
579
  next false if specs.include?(s)
571
- s.name == dependency.name
580
+ true
572
581
  end
573
- end.compact
574
- end.uniq
582
+ dependent_specs << match if match
583
+ end
584
+ end
585
+
575
586
  remaining_specs = all_specs - dependent_specs
576
- dependent_specs + transitive_dependencies_for_specs(dependent_specs, platform, remaining_specs)
587
+
588
+ dependent_specs.union transitive_dependencies_for_specs(dependent_specs, platform, remaining_specs)
577
589
  end
578
590
 
579
591
  # Create a target for each spec group
@@ -624,7 +636,7 @@ module Pod
624
636
  else
625
637
  pods_to_update = result.podfile_state.changed + result.podfile_state.deleted
626
638
  pods_to_update += update[:pods] if update_mode == :selected
627
- local_pod_names = podfile.dependencies.select(&:local?).map(&:root_name)
639
+ local_pod_names = @podfile_dependency_cache.podfile_dependencies.select(&:local?).map(&:root_name)
628
640
  pods_to_unlock = local_pod_names.reject do |pod_name|
629
641
  sandbox.specification(pod_name).checksum == lockfile.checksum(pod_name)
630
642
  end
@@ -665,7 +677,7 @@ module Pod
665
677
  end
666
678
 
667
679
  def verify_no_pods_with_different_sources!
668
- deps_with_different_sources = podfile.dependencies.group_by(&:root_name).
680
+ deps_with_different_sources = @podfile_dependency_cache.podfile_dependencies.group_by(&:root_name).
669
681
  select { |_root_name, dependencies| dependencies.map(&:external_source).uniq.count > 1 }
670
682
  deps_with_different_sources.each do |root_name, dependencies|
671
683
  raise Informative, 'There are multiple dependencies with different ' \
@@ -688,7 +700,7 @@ module Pod
688
700
  def dependencies_to_fetch
689
701
  @deps_to_fetch ||= begin
690
702
  deps_to_fetch = []
691
- deps_with_external_source = podfile.dependencies.select(&:external_source)
703
+ deps_with_external_source = @podfile_dependency_cache.podfile_dependencies.select(&:external_source)
692
704
 
693
705
  if update_mode == :all
694
706
  deps_to_fetch = deps_with_external_source
@@ -721,7 +733,7 @@ module Pod
721
733
  elsif update_mode == :all
722
734
  pods_to_fetch += result.podfile_state.unchanged + result.podfile_state.deleted
723
735
  end
724
- pods_to_fetch += podfile.dependencies.
736
+ pods_to_fetch += @podfile_dependency_cache.podfile_dependencies.
725
737
  select { |dep| Hash(dep.external_source).key?(:podspec) && sandbox.specification_path(dep.root_name).nil? }.
726
738
  map(&:root_name)
727
739
  pods_to_fetch
@@ -729,7 +741,7 @@ module Pod
729
741
  end
730
742
 
731
743
  def store_existing_checkout_options
732
- podfile.dependencies.select(&:external_source).each do |dep|
744
+ @podfile_dependency_cache.podfile_dependencies.select(&:external_source).each do |dep|
733
745
  if checkout_options = lockfile && lockfile.checkout_options_for_pod_named(dep.root_name)
734
746
  sandbox.store_checkout_source(dep.root_name, checkout_options)
735
747
  end
@@ -756,7 +768,7 @@ module Pod
756
768
  # grouped by target.
757
769
  #
758
770
  def resolve_dependencies
759
- duplicate_dependencies = podfile.dependencies.group_by(&:name).
771
+ duplicate_dependencies = @podfile_dependency_cache.podfile_dependencies.group_by(&:name).
760
772
  select { |_name, dependencies| dependencies.count > 1 }
761
773
  duplicate_dependencies.each do |name, dependencies|
762
774
  UI.warn "There are duplicate dependencies on `#{name}` in #{UI.path podfile.defined_in_file}:\n\n" \
@@ -765,8 +777,7 @@ module Pod
765
777
 
766
778
  resolver_specs_by_target = nil
767
779
  UI.section "Resolving dependencies of #{UI.path(podfile.defined_in_file) || 'Podfile'}" do
768
- resolver = Resolver.new(sandbox, podfile, locked_dependencies, sources)
769
- resolver.specs_updated = specs_updated?
780
+ resolver = Resolver.new(sandbox, podfile, locked_dependencies, sources, specs_updated?)
770
781
  resolver_specs_by_target = resolver.resolve
771
782
  resolver_specs_by_target.values.flatten(1).map(&:spec).each(&:validate_cocoapods_version)
772
783
  end
@@ -847,8 +858,8 @@ module Pod
847
858
  plugin_sources = @plugin_sources || []
848
859
 
849
860
  # Add any sources specified using the :source flag on individual dependencies.
850
- dependency_sources = podfile.dependencies.map(&:podspec_repo).compact
851
- all_dependencies_have_sources = dependency_sources.count == podfile.dependencies.count
861
+ dependency_sources = @podfile_dependency_cache.podfile_dependencies.map(&:podspec_repo).compact
862
+ all_dependencies_have_sources = dependency_sources.count == @podfile_dependency_cache.podfile_dependencies.count
852
863
 
853
864
  if all_dependencies_have_sources
854
865
  sources = dependency_sources
@@ -880,7 +891,7 @@ module Pod
880
891
  #
881
892
  def verify_platforms_specified!
882
893
  unless installation_options.integrate_targets?
883
- podfile.target_definition_list.each do |target_definition|
894
+ @podfile_dependency_cache.target_definition_list.each do |target_definition|
884
895
  if !target_definition.empty? && target_definition.platform.nil?
885
896
  raise Informative, 'It is necessary to specify the platform in the Podfile if not integrating.'
886
897
  end
@@ -899,7 +910,7 @@ module Pod
899
910
  def inspect_targets_to_integrate
900
911
  inspection_result = {}
901
912
  UI.section 'Inspecting targets to integrate' do
902
- inspectors = podfile.target_definition_list.map do |target_definition|
913
+ inspectors = @podfile_dependency_cache.target_definition_list.map do |target_definition|
903
914
  next if target_definition.abstract?
904
915
  TargetInspector.new(target_definition, config.installation_root)
905
916
  end.compact
@@ -907,8 +918,7 @@ module Pod
907
918
  project = Xcodeproj::Project.open(project_path)
908
919
  target_inspectors.each do |inspector|
909
920
  target_definition = inspector.target_definition
910
- inspector.user_project = project
911
- results = inspector.compute_results
921
+ results = inspector.compute_results(project)
912
922
  inspection_result[target_definition] = results
913
923
  UI.message('Using `ARCHS` setting to build architectures of ' \
914
924
  "target `#{target_definition.label}`: (`#{results.archs.join('`, `')}`)")