cocoapods 1.7.5 → 1.8.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +175 -11
  3. data/LICENSE +13 -8
  4. data/README.md +2 -1
  5. data/lib/cocoapods/command/init.rb +18 -16
  6. data/lib/cocoapods/command/install.rb +2 -1
  7. data/lib/cocoapods/command/lib/create.rb +1 -2
  8. data/lib/cocoapods/command/lib/lint.rb +12 -11
  9. data/lib/cocoapods/command/repo/add.rb +2 -2
  10. data/lib/cocoapods/command/repo/list.rb +7 -5
  11. data/lib/cocoapods/command/repo/push.rb +15 -12
  12. data/lib/cocoapods/command/setup.rb +2 -88
  13. data/lib/cocoapods/command/spec/lint.rb +10 -9
  14. data/lib/cocoapods/command/update.rb +5 -4
  15. data/lib/cocoapods/config.rb +9 -8
  16. data/lib/cocoapods/external_sources/path_source.rb +1 -1
  17. data/lib/cocoapods/gem_version.rb +1 -1
  18. data/lib/cocoapods/generator/embed_frameworks_script.rb +1 -1
  19. data/lib/cocoapods/generator/info_plist_file.rb +2 -2
  20. data/lib/cocoapods/installer.rb +32 -12
  21. data/lib/cocoapods/installer/analyzer.rb +132 -97
  22. data/lib/cocoapods/installer/analyzer/target_inspector.rb +6 -8
  23. data/lib/cocoapods/installer/installation_options.rb +4 -0
  24. data/lib/cocoapods/installer/pod_source_installer.rb +17 -1
  25. data/lib/cocoapods/installer/podfile_validator.rb +26 -6
  26. data/lib/cocoapods/installer/project_cache/project_cache_analyzer.rb +37 -27
  27. data/lib/cocoapods/installer/project_cache/project_cache_version.rb +1 -1
  28. data/lib/cocoapods/installer/project_cache/project_installation_cache.rb +3 -3
  29. data/lib/cocoapods/installer/project_cache/project_metadata_cache.rb +12 -6
  30. data/lib/cocoapods/installer/project_cache/target_cache_key.rb +32 -8
  31. data/lib/cocoapods/installer/project_cache/target_metadata.rb +6 -2
  32. data/lib/cocoapods/installer/sandbox_dir_cleaner.rb +12 -0
  33. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +1 -1
  34. data/lib/cocoapods/installer/xcode/multi_pods_project_generator.rb +3 -1
  35. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +2 -2
  36. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +18 -3
  37. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +53 -11
  38. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +92 -60
  39. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +66 -50
  40. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +12 -0
  41. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +6 -2
  42. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +2 -2
  43. data/lib/cocoapods/installer/xcode/target_validator.rb +30 -14
  44. data/lib/cocoapods/native_target_extension.rb +11 -5
  45. data/lib/cocoapods/open-uri.rb +1 -1
  46. data/lib/cocoapods/project.rb +13 -7
  47. data/lib/cocoapods/resolver.rb +63 -53
  48. data/lib/cocoapods/resolver/lazy_specification.rb +14 -5
  49. data/lib/cocoapods/sandbox.rb +35 -2
  50. data/lib/cocoapods/sandbox/pod_dir_cleaner.rb +3 -4
  51. data/lib/cocoapods/sources_manager.rb +72 -43
  52. data/lib/cocoapods/target.rb +7 -1
  53. data/lib/cocoapods/target/aggregate_target.rb +13 -8
  54. data/lib/cocoapods/target/build_settings.rb +33 -10
  55. data/lib/cocoapods/target/pod_target.rb +114 -30
  56. data/lib/cocoapods/user_interface/error_report.rb +9 -5
  57. data/lib/cocoapods/validator.rb +55 -11
  58. data/lib/cocoapods/version_metadata.rb +14 -1
  59. metadata +6 -7
  60. data/lib/cocoapods/command/spec/env_spec.rb +0 -53
@@ -60,32 +60,40 @@ module Pod
60
60
 
61
61
  input_paths_by_config = {}
62
62
  output_paths_by_config = {}
63
- if use_input_output_paths
64
- dependent_targets = if spec.test_specification?
65
- target.dependent_targets_for_test_spec(spec)
66
- else
67
- target.dependent_targets_for_app_spec(spec)
68
- end
69
- resource_paths = dependent_targets.flat_map do |dependent_target|
70
- spec_paths_to_include = dependent_target.library_specs.map(&:name)
71
- spec_paths_to_include << spec.name if dependent_target == target
72
- dependent_target.resource_paths.values_at(*spec_paths_to_include).flatten.compact
73
- end.uniq
74
-
75
- unless resource_paths.empty?
76
- input_file_list_path = target.copy_resources_script_input_files_path_for_spec(spec)
77
- input_file_list_relative_path = "${PODS_ROOT}/#{input_file_list_path.relative_path_from(target.sandbox.root)}"
78
- input_paths_key = UserProjectIntegrator::TargetIntegrator::XCFileListConfigKey.new(input_file_list_path, input_file_list_relative_path)
79
- input_paths_by_config[input_paths_key] = [script_path] + resource_paths
80
-
81
- output_file_list_path = target.copy_resources_script_output_files_path_for_spec(spec)
82
- output_file_list_relative_path = "${PODS_ROOT}/#{output_file_list_path.relative_path_from(target.sandbox.root)}"
83
- output_paths_key = UserProjectIntegrator::TargetIntegrator::XCFileListConfigKey.new(output_file_list_path, output_file_list_relative_path)
84
- output_paths_by_config[output_paths_key] = UserProjectIntegrator::TargetIntegrator.resource_output_paths(resource_paths)
85
- end
63
+
64
+ dependent_targets = if spec.test_specification?
65
+ target.dependent_targets_for_test_spec(spec)
66
+ else
67
+ target.dependent_targets_for_app_spec(spec)
68
+ end
69
+ host_target_spec_names = target.app_host_dependent_targets_for_spec(spec).flat_map do |pt|
70
+ pt.specs.map(&:name)
71
+ end.uniq
72
+ resource_paths = dependent_targets.flat_map do |dependent_target|
73
+ spec_paths_to_include = dependent_target.library_specs.map(&:name)
74
+ spec_paths_to_include -= host_target_spec_names
75
+ spec_paths_to_include << spec.name if dependent_target == target
76
+ dependent_target.resource_paths.values_at(*spec_paths_to_include).flatten.compact
77
+ end.uniq
78
+
79
+ if use_input_output_paths? && !resource_paths.empty?
80
+ input_file_list_path = target.copy_resources_script_input_files_path_for_spec(spec)
81
+ input_file_list_relative_path = "${PODS_ROOT}/#{input_file_list_path.relative_path_from(target.sandbox.root)}"
82
+ input_paths_key = UserProjectIntegrator::TargetIntegrator::XCFileListConfigKey.new(input_file_list_path, input_file_list_relative_path)
83
+ input_paths_by_config[input_paths_key] = [script_path] + resource_paths
84
+
85
+ output_file_list_path = target.copy_resources_script_output_files_path_for_spec(spec)
86
+ output_file_list_relative_path = "${PODS_ROOT}/#{output_file_list_path.relative_path_from(target.sandbox.root)}"
87
+ output_paths_key = UserProjectIntegrator::TargetIntegrator::XCFileListConfigKey.new(output_file_list_path, output_file_list_relative_path)
88
+ output_paths_by_config[output_paths_key] = UserProjectIntegrator::TargetIntegrator.resource_output_paths(resource_paths)
86
89
  end
87
90
 
88
- UserProjectIntegrator::TargetIntegrator.create_or_update_copy_resources_script_phase_to_target(native_target, script_path, input_paths_by_config, output_paths_by_config)
91
+ if resource_paths.empty?
92
+ UserProjectIntegrator::TargetIntegrator.remove_copy_resources_script_phase_from_target(native_target)
93
+ else
94
+ UserProjectIntegrator::TargetIntegrator.create_or_update_copy_resources_script_phase_to_target(
95
+ native_target, script_path, input_paths_by_config, output_paths_by_config)
96
+ end
89
97
  end
90
98
 
91
99
  # Find or create a 'Embed Pods Frameworks' Copy Files Build Phase
@@ -97,35 +105,43 @@ module Pod
97
105
 
98
106
  input_paths_by_config = {}
99
107
  output_paths_by_config = {}
100
- if use_input_output_paths?
101
- dependent_targets = if spec.test_specification?
102
- target.dependent_targets_for_test_spec(spec)
103
- else
104
- target.dependent_targets_for_app_spec(spec)
105
- end
106
- framework_paths = dependent_targets.flat_map do |dependent_target|
107
- spec_paths_to_include = dependent_target.library_specs.map(&:name)
108
- spec_paths_to_include << spec.name if dependent_target == target
109
- dependent_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact
110
- end.uniq
111
-
112
- unless framework_paths.empty?
113
- input_file_list_path = target.embed_frameworks_script_input_files_path_for_spec(spec)
114
- input_file_list_relative_path = "${PODS_ROOT}/#{input_file_list_path.relative_path_from(target.sandbox.root)}"
115
- input_paths_key = UserProjectIntegrator::TargetIntegrator::XCFileListConfigKey.new(input_file_list_path, input_file_list_relative_path)
116
- input_paths = input_paths_by_config[input_paths_key] = [script_path]
117
- framework_paths.each do |path|
118
- input_paths.concat(path.all_paths)
119
- end
120
-
121
- output_file_list_path = target.embed_frameworks_script_output_files_path_for_spec(spec)
122
- output_file_list_relative_path = "${PODS_ROOT}/#{output_file_list_path.relative_path_from(target.sandbox.root)}"
123
- output_paths_key = UserProjectIntegrator::TargetIntegrator::XCFileListConfigKey.new(output_file_list_path, output_file_list_relative_path)
124
- output_paths_by_config[output_paths_key] = UserProjectIntegrator::TargetIntegrator.framework_output_paths(framework_paths)
108
+
109
+ dependent_targets = if spec.test_specification?
110
+ target.dependent_targets_for_test_spec(spec)
111
+ else
112
+ target.dependent_targets_for_app_spec(spec)
113
+ end
114
+ host_target_spec_names = target.app_host_dependent_targets_for_spec(spec).flat_map do |pt|
115
+ pt.specs.map(&:name)
116
+ end.uniq
117
+ framework_paths = dependent_targets.flat_map do |dependent_target|
118
+ spec_paths_to_include = dependent_target.library_specs.map(&:name)
119
+ spec_paths_to_include -= host_target_spec_names
120
+ spec_paths_to_include << spec.name if dependent_target == target
121
+ dependent_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact
122
+ end.uniq
123
+
124
+ if use_input_output_paths? && !framework_paths.empty?
125
+ input_file_list_path = target.embed_frameworks_script_input_files_path_for_spec(spec)
126
+ input_file_list_relative_path = "${PODS_ROOT}/#{input_file_list_path.relative_path_from(target.sandbox.root)}"
127
+ input_paths_key = UserProjectIntegrator::TargetIntegrator::XCFileListConfigKey.new(input_file_list_path, input_file_list_relative_path)
128
+ input_paths = input_paths_by_config[input_paths_key] = [script_path]
129
+ framework_paths.each do |path|
130
+ input_paths.concat(path.all_paths)
125
131
  end
132
+
133
+ output_file_list_path = target.embed_frameworks_script_output_files_path_for_spec(spec)
134
+ output_file_list_relative_path = "${PODS_ROOT}/#{output_file_list_path.relative_path_from(target.sandbox.root)}"
135
+ output_paths_key = UserProjectIntegrator::TargetIntegrator::XCFileListConfigKey.new(output_file_list_path, output_file_list_relative_path)
136
+ output_paths_by_config[output_paths_key] = UserProjectIntegrator::TargetIntegrator.framework_output_paths(framework_paths)
126
137
  end
127
138
 
128
- UserProjectIntegrator::TargetIntegrator.create_or_update_embed_frameworks_script_phase_to_target(native_target, script_path, input_paths_by_config, output_paths_by_config)
139
+ if framework_paths.empty?
140
+ UserProjectIntegrator::TargetIntegrator.remove_embed_frameworks_script_phase_from_target(native_target)
141
+ else
142
+ UserProjectIntegrator::TargetIntegrator.create_or_update_embed_frameworks_script_phase_to_target(
143
+ native_target, script_path, input_paths_by_config, output_paths_by_config)
144
+ end
129
145
  end
130
146
 
131
147
  # @return [String] the message that should be displayed for the target
@@ -110,6 +110,18 @@ module Pod
110
110
  test_specs_by_native_target.merge(app_specs_by_native_target)
111
111
  end
112
112
 
113
+ # @param label [String] the label of the app host target.
114
+ #
115
+ # @return [PBXNativeTarget] the app host target with the given target label.
116
+ #
117
+ def app_host_target_labelled(label)
118
+ app_native_targets.find do |app_native_target|
119
+ app_native_target.name == label
120
+ end || test_app_host_targets.find do |app_native_target|
121
+ app_native_target.name == label
122
+ end
123
+ end
124
+
113
125
  private
114
126
 
115
127
  def test_native_target_from_spec(spec)
@@ -135,10 +135,14 @@ module Pod
135
135
  # @param [Symbol] bundle_package_type
136
136
  # the CFBundlePackageType of the target this Info.plist file is for.
137
137
  #
138
+ # @param [Hash] additional_entries
139
+ # additional entries for the generated Info.plist
140
+ #
138
141
  # @return [void]
139
142
  #
140
- def create_info_plist_file(path, native_target, version, platform, bundle_package_type = :fmwk)
141
- create_info_plist_file_with_sandbox(@sandbox, path, native_target, version, platform, bundle_package_type)
143
+ def create_info_plist_file(path, native_target, version, platform, bundle_package_type = :fmwk, additional_entries: {})
144
+ create_info_plist_file_with_sandbox(@sandbox, path, native_target, version, platform, bundle_package_type,
145
+ :additional_entries => additional_entries)
142
146
  add_file_to_support_group(path)
143
147
  end
144
148
 
@@ -36,7 +36,7 @@ module Pod
36
36
  # @param [PBXNativeTarget] native_target
37
37
  # the native target to link the generated Info.plist file into.
38
38
  #
39
- # @param [Version] version
39
+ # @param [String] version
40
40
  # the version to use for when generating this Info.plist file.
41
41
  #
42
42
  # @param [Platform] platform
@@ -51,7 +51,7 @@ module Pod
51
51
  # @return [void]
52
52
  #
53
53
  def create_info_plist_file_with_sandbox(sandbox, path, native_target, version, platform,
54
- bundle_package_type = :fmwk, additional_entries = {})
54
+ bundle_package_type = :fmwk, additional_entries: {})
55
55
  UI.message "- Generating Info.plist file at #{UI.path(path)}" do
56
56
  generator = Generator::InfoPlistFile.new(version, platform, bundle_package_type, additional_entries)
57
57
  update_changed_file(generator, path)
@@ -5,8 +5,7 @@ module Pod
5
5
  # configuration is valid for installation.
6
6
  #
7
7
  class TargetValidator
8
- # @return [Array<AggregateTarget>] The aggregate targets that should be
9
- # validated.
8
+ # @return [Array<AggregateTarget>] The aggregate targets that should be validated.
10
9
  #
11
10
  attr_reader :aggregate_targets
12
11
 
@@ -14,18 +13,21 @@ module Pod
14
13
  #
15
14
  attr_reader :pod_targets
16
15
 
16
+ # @return [InstallationOptions] The installation options used during this installation.
17
+ #
18
+ attr_reader :installation_options
19
+
17
20
  # Create a new TargetValidator with aggregate and pod targets to
18
21
  # validate.
19
22
  #
20
- # @param [Array<AggregateTarget>] aggregate_targets
21
- # The aggregate targets to validate.
22
- #
23
- # @param [Array<PodTarget>] pod_targets
24
- # The pod targets to validate.
23
+ # @param [Array<AggregateTarget>] aggregate_targets #see #aggregate_targets
24
+ # @param [Array<PodTarget>] pod_targets see #pod_targets
25
+ # @param [InstallationOptions] installation_options see #installation_options
25
26
  #
26
- def initialize(aggregate_targets, pod_targets)
27
+ def initialize(aggregate_targets, pod_targets, installation_options)
27
28
  @aggregate_targets = aggregate_targets
28
29
  @pod_targets = pod_targets
30
+ @installation_options = installation_options
29
31
  end
30
32
 
31
33
  # Perform the validation steps for the provided aggregate and pod
@@ -36,15 +38,16 @@ module Pod
36
38
  verify_no_static_framework_transitive_dependencies
37
39
  verify_swift_pods_swift_version
38
40
  verify_swift_pods_have_module_dependencies
41
+ verify_no_multiple_project_names if installation_options.generate_multiple_pod_projects?
39
42
  end
40
43
 
41
44
  private
42
45
 
43
46
  def verify_no_duplicate_framework_and_library_names
44
47
  aggregate_targets.each do |aggregate_target|
45
- aggregate_target.user_build_configurations.keys.each do |config|
48
+ aggregate_target.user_build_configurations.each_key do |config|
46
49
  pod_targets = aggregate_target.pod_targets_for_build_configuration(config)
47
- file_accessors = pod_targets.flat_map(&:file_accessors)
50
+ file_accessors = pod_targets.flat_map(&:file_accessors).select { |fa| fa.spec.library_specification? }
48
51
 
49
52
  frameworks = file_accessors.flat_map(&:vendored_frameworks).uniq.map(&:basename)
50
53
  frameworks += pod_targets.select { |pt| pt.should_build? && pt.build_as_framework? }.map(&:product_module_name).uniq
@@ -58,7 +61,7 @@ module Pod
58
61
  end
59
62
 
60
63
  def verify_no_duplicate_names(names, label, type)
61
- duplicates = names.map { |n| n.to_s.downcase }.group_by { |f| f }.select { |_, v| v.size > 1 }.keys
64
+ duplicates = names.group_by { |n| n.to_s.downcase }.select { |_, v| v.size > 1 }.keys
62
65
 
63
66
  unless duplicates.empty?
64
67
  raise Informative, "The '#{label}' target has " \
@@ -73,8 +76,8 @@ module Pod
73
76
  built_targets, unbuilt_targets = pod_targets.partition(&:should_build?)
74
77
  dynamic_pod_targets = built_targets.select(&:build_as_dynamic?)
75
78
 
76
- dependencies = dynamic_pod_targets.flat_map(&:dependencies)
77
- depended_upon_targets = unbuilt_targets.select { |t| dependencies.include?(t.pod_name) }
79
+ dependencies = dynamic_pod_targets.flat_map(&:dependent_targets).uniq
80
+ depended_upon_targets = unbuilt_targets & dependencies
78
81
 
79
82
  static_libs = depended_upon_targets.flat_map(&:file_accessors).flat_map(&:vendored_static_artifacts)
80
83
  unless static_libs.empty?
@@ -82,7 +85,7 @@ module Pod
82
85
  "transitive dependencies that include statically linked binaries: (#{static_libs.to_sentence})"
83
86
  end
84
87
 
85
- static_deps = dynamic_pod_targets.flat_map(&:recursive_dependent_targets).select(&:build_as_static?).uniq
88
+ static_deps = dynamic_pod_targets.flat_map(&:recursive_dependent_targets).uniq.select(&:build_as_static?)
86
89
  unless static_deps.empty?
87
90
  raise Informative, "The '#{aggregate_target.label}' target has " \
88
91
  "transitive dependencies that include statically linked binaries: (#{static_deps.flat_map(&:name).to_sentence})"
@@ -148,6 +151,19 @@ module Pod
148
151
  raise Informative, 'The following Swift pods cannot yet be integrated '\
149
152
  "as static libraries:\n\n#{error_messages.join("\n\n")}"
150
153
  end
154
+
155
+ def verify_no_multiple_project_names
156
+ error_messages = pod_targets.map do |pod_target|
157
+ project_names = pod_target.target_definitions.map { |td| td.project_name_for_pod(pod_target.pod_name) }.compact.uniq
158
+ next unless project_names.count > 1
159
+ "- `#{pod_target.name}` specifies multiple project names (#{project_names.map { |pn| "`#{pn}`" }.to_sentence}) " \
160
+ "in different targets (#{pod_target.target_definitions.map { |td| "`#{td.name}`" }.to_sentence})."
161
+ end.compact
162
+ return if error_messages.empty?
163
+
164
+ raise Informative, 'The following pods cannot be integrated:' \
165
+ "\n\n#{error_messages.join("\n\n")}"
166
+ end
151
167
  end
152
168
  end
153
169
  end
@@ -2,6 +2,9 @@ module Pod
2
2
  class Project
3
3
  # Adds a dependency on the given metadata cache.
4
4
  #
5
+ # @param [Sandbox] sandbox
6
+ # The sandbox used for this installation.
7
+ #
5
8
  # @param [AbstractTarget] target
6
9
  # The parent target used to add a cached dependency.
7
10
  #
@@ -10,11 +13,11 @@ module Pod
10
13
  #
11
14
  # @return [void]
12
15
  #
13
- def self.add_cached_dependency(target, metadata)
14
- return if dependency_for_cached_target?(target, metadata)
16
+ def self.add_cached_dependency(sandbox, target, metadata)
17
+ return if dependency_for_cached_target?(sandbox, target, metadata)
15
18
  container_proxy = target.project.new(Xcodeproj::Project::PBXContainerItemProxy)
16
19
 
17
- subproject_reference = target.project.reference_for_path(metadata.container_project_path)
20
+ subproject_reference = target.project.reference_for_path(sandbox.root + metadata.container_project_path)
18
21
  raise ArgumentError, "add_dependency received target (#{target}) that belongs to a project that is not this project (#{self}) and is not a subproject of this project" unless subproject_reference
19
22
  container_proxy.container_portal = subproject_reference.uuid
20
23
 
@@ -31,6 +34,9 @@ module Pod
31
34
 
32
35
  # Checks whether this target has a dependency on the given target.
33
36
  #
37
+ # @param [Sandbox] sandbox
38
+ # The sandbox used for this installation.
39
+ #
34
40
  # @param [AbstractTarget] target
35
41
  # The parent target used to add a cached dependency.
36
42
  #
@@ -39,10 +45,10 @@ module Pod
39
45
  #
40
46
  # @return [Bool]
41
47
  #
42
- def self.dependency_for_cached_target?(target, cached_target)
48
+ def self.dependency_for_cached_target?(sandbox, target, cached_target)
43
49
  target.dependencies.find do |dep|
44
50
  if dep.target_proxy.remote?
45
- subproject_reference = target.project.reference_for_path(cached_target.container_project_path)
51
+ subproject_reference = target.project.reference_for_path(sandbox.root + cached_target.container_project_path)
46
52
  uuid = subproject_reference.uuid if subproject_reference
47
53
  dep.target_proxy.remote_global_id_string == cached_target.native_target_uuid && dep.target_proxy.container_portal == uuid
48
54
  else
@@ -1,4 +1,4 @@
1
- # rubocop:disable Style/FileName
1
+ # rubocop:disable Naming/FileName
2
2
 
3
3
  require 'open-uri'
4
4
 
@@ -53,7 +53,7 @@ module Pod
53
53
  @development_pods = new_group('Development Pods')
54
54
  @dependencies_group = new_group('Dependencies')
55
55
  @pod_target_subproject = pod_target_subproject
56
- @project_name = Pathname(path).basename('.*')
56
+ @project_name = Pathname(path).basename('.*').to_s
57
57
  self.symroot = LEGACY_BUILD_ROOT
58
58
  end
59
59
 
@@ -108,10 +108,10 @@ module Pod
108
108
  # The path to the root of the Pod.
109
109
  #
110
110
  # @param [Bool] development
111
- # Wether the group should be added to the Development Pods group.
111
+ # Whether the group should be added to the Development Pods group.
112
112
  #
113
113
  # @param [Bool] absolute
114
- # Wether the path of the group should be set as absolute.
114
+ # Whether the path of the group should be set as absolute.
115
115
  #
116
116
  # @return [PBXGroup] The new group.
117
117
  #
@@ -150,6 +150,9 @@ module Pod
150
150
  # Creates a new subproject reference for the given cached metadata and configures its
151
151
  # group location.
152
152
  #
153
+ # @param [Sandbox] sandbox
154
+ # The sandbox used for installation.
155
+ #
153
156
  # @param [TargetMetadata] metadata
154
157
  # The project metadata to be added.
155
158
  #
@@ -159,9 +162,9 @@ module Pod
159
162
  #
160
163
  # @return [PBXFileReference] The new file reference.
161
164
  #
162
- def add_cached_pod_subproject(metadata, development = false)
165
+ def add_cached_pod_subproject(sandbox, metadata, development = false)
163
166
  parent_group = group_for_subproject_reference(development)
164
- add_cached_subproject_reference(metadata, parent_group)
167
+ add_cached_subproject_reference(sandbox, metadata, parent_group)
165
168
  end
166
169
 
167
170
  # @return [Array<PBXGroup>] Returns all the group of the Pods.
@@ -291,6 +294,9 @@ module Pod
291
294
 
292
295
  # Adds a file reference for a cached project as a child of the given group.
293
296
  #
297
+ # @param [Sandbox] sandbox
298
+ # The sandbox used for installation.
299
+ #
294
300
  # @param [MetadataCache] metadata
295
301
  # The metadata holding the required properties to create a subproject reference.
296
302
  #
@@ -299,8 +305,8 @@ module Pod
299
305
  #
300
306
  # @return [PBXFileReference] The new file reference.
301
307
  #
302
- def add_cached_subproject_reference(metadata, group)
303
- new_subproject_file_reference(metadata.container_project_path, group)
308
+ def add_cached_subproject_reference(sandbox, metadata, group)
309
+ new_subproject_file_reference(sandbox.root + metadata.container_project_path, group)
304
310
  end
305
311
 
306
312
  # Returns the file reference for the given absolute path.
@@ -39,6 +39,10 @@ module Pod
39
39
  attr_reader :specs_updated
40
40
  alias specs_updated? specs_updated
41
41
 
42
+ # @return [Source::Manager] the manager to use for dependency resolution
43
+ #
44
+ attr_reader :sources_manager
45
+
42
46
  # Init a new Resolver
43
47
  #
44
48
  # @param [Sandbox] sandbox @see sandbox
@@ -50,17 +54,19 @@ module Pod
50
54
  # within this Resolver.
51
55
  #
52
56
  def initialize(sandbox, podfile, locked_dependencies, sources, specs_updated,
53
- podfile_dependency_cache: Installer::Analyzer::PodfileDependencyCache.from_podfile(podfile))
57
+ podfile_dependency_cache: Installer::Analyzer::PodfileDependencyCache.from_podfile(podfile),
58
+ sources_manager: Config.instance.sources_manager)
54
59
  @sandbox = sandbox
55
60
  @podfile = podfile
56
61
  @locked_dependencies = locked_dependencies
57
62
  @sources = Array(sources)
58
63
  @specs_updated = specs_updated
59
64
  @podfile_dependency_cache = podfile_dependency_cache
65
+ @sources_manager = sources_manager
60
66
  @platforms_by_dependency = Hash.new { |h, k| h[k] = [] }
61
67
 
62
68
  @cached_sets = {}
63
- @podfile_requirements_by_root_name = @podfile_dependency_cache.podfile_dependencies.group_by(&:root_name).each_value { |a| a.map!(&:requirement) }
69
+ @podfile_requirements_by_root_name = @podfile_dependency_cache.podfile_dependencies.group_by(&:root_name).each_value { |a| a.map!(&:requirement).freeze }.freeze
64
70
  @search = {}
65
71
  @validated_platforms = Set.new
66
72
  end
@@ -83,7 +89,7 @@ module Pod
83
89
  next unless target.platform
84
90
  @platforms_by_dependency[dep].push(target.platform)
85
91
  end
86
- end
92
+ end.uniq
87
93
  @platforms_by_dependency.each_value(&:uniq!)
88
94
  @activated = Molinillo::Resolver.new(self, self).resolve(dependencies, locked_dependencies)
89
95
  resolver_specs_by_target
@@ -99,15 +105,32 @@ module Pod
99
105
  def resolver_specs_by_target
100
106
  @resolver_specs_by_target ||= {}.tap do |resolver_specs_by_target|
101
107
  @podfile_dependency_cache.target_definition_list.each do |target|
108
+ next if target.abstract? && !target.platform
109
+
102
110
  # can't use vertex.root? since that considers _all_ targets
103
111
  explicit_dependencies = @podfile_dependency_cache.target_definition_dependencies(target).map(&:name).to_set
104
- vertices = valid_dependencies_for_target(target)
105
112
 
106
- resolver_specs_by_target[target] = vertices.
113
+ used_by_aggregate_target_by_spec_name = {}
114
+ used_vertices_by_spec_name = {}
115
+
116
+ # it's safe to make a single pass here since we iterate in topological order,
117
+ # so all of the predecessors have been visited before we get to a node.
118
+ # #tsort returns no-children vertices first, and we want them last (i.e. we want no-parent vertices first)
119
+ @activated.tsort.reverse_each do |vertex|
120
+ spec_name = vertex.name
121
+ explicitly_included = explicit_dependencies.include?(spec_name)
122
+ if explicitly_included || vertex.incoming_edges.any? { |edge| used_vertices_by_spec_name.key?(edge.origin.name) && edge_is_valid_for_target_platform?(edge, target.platform) }
123
+ validate_platform(vertex.payload, target)
124
+ used_vertices_by_spec_name[spec_name] = vertex
125
+ used_by_aggregate_target_by_spec_name[spec_name] = vertex.payload.library_specification? &&
126
+ (explicitly_included || vertex.predecessors.any? { |predecessor| used_by_aggregate_target_by_spec_name.fetch(predecessor.name, false) })
127
+ end
128
+ end
129
+
130
+ resolver_specs_by_target[target] = used_vertices_by_spec_name.each_value.
107
131
  map do |vertex|
108
132
  payload = vertex.payload
109
- non_library = (!explicit_dependencies.include?(vertex.name) || payload.non_library_specification?) &&
110
- (vertex.recursive_predecessors & vertices).all? { |v| !explicit_dependencies.include?(v.name) || v.payload.non_library_specification? }
133
+ non_library = !used_by_aggregate_target_by_spec_name.fetch(vertex.name)
111
134
  spec_source = payload.respond_to?(:spec_source) && payload.spec_source
112
135
  ResolverSpecification.new(payload, non_library, spec_source)
113
136
  end.
@@ -133,10 +156,13 @@ module Pod
133
156
  #
134
157
  def search_for(dependency)
135
158
  @search[dependency] ||= begin
136
- locked_requirement = requirement_for_locked_pod_named(dependency.name)
137
- podfile_deps = Array(@podfile_requirements_by_root_name[dependency.root_name])
138
- podfile_deps << locked_requirement if locked_requirement
139
- specifications_for_dependency(dependency, podfile_deps)
159
+ additional_requirements = if locked_requirement = requirement_for_locked_pod_named(dependency.name)
160
+ [locked_requirement]
161
+ else
162
+ Array(@podfile_requirements_by_root_name[dependency.root_name])
163
+ end
164
+
165
+ specifications_for_dependency(dependency, additional_requirements)
140
166
  end
141
167
  @search[dependency].dup
142
168
  end
@@ -328,10 +354,11 @@ module Pod
328
354
  # @return [Array<Specification>] List of specifications satisfying given requirements.
329
355
  #
330
356
  def specifications_for_dependency(dependency, additional_requirements = [])
331
- requirement = Requirement.new(dependency.requirement.as_list + additional_requirements.flat_map(&:as_list))
357
+ requirement_list = dependency.requirement.as_list + additional_requirements.flat_map(&:as_list)
358
+ requirement_list.uniq!
359
+ requirement = Requirement.new(requirement_list)
332
360
  find_cached_set(dependency).
333
- all_specifications(warn_for_multiple_pod_sources).
334
- select { |s| requirement.satisfied_by? s.version }.
361
+ all_specifications(warn_for_multiple_pod_sources, requirement).
335
362
  map { |s| s.subspec_by_name(dependency.name, false, true) }.
336
363
  compact
337
364
  end
@@ -392,7 +419,6 @@ module Pod
392
419
  # @return [Source::Aggregate] The aggregate of the {#sources}.
393
420
  #
394
421
  def aggregate_for_dependency(dependency)
395
- sources_manager = Config.instance.sources_manager
396
422
  if dependency && dependency.podspec_repo
397
423
  sources_manager.aggregate_for_dependency(dependency)
398
424
  elsif (locked_vertex = @locked_dependencies.vertex_named(dependency.name)) && (locked_dependency = locked_vertex.payload) && locked_dependency.podspec_repo
@@ -414,7 +440,7 @@ module Pod
414
440
  unless spec.available_platforms.any? { |p| target_platform.to_sym == p.to_sym }
415
441
  raise Informative, "The platform of the target `#{target.name}` " \
416
442
  "(#{target.platform}) is not compatible with `#{spec}`, which does " \
417
- "not support `#{target.platform.name}`."
443
+ "not support `#{target.platform.string_name}`."
418
444
  end
419
445
  end
420
446
 
@@ -427,6 +453,9 @@ module Pod
427
453
  def handle_resolver_error(error)
428
454
  message = error.message
429
455
  type = Informative
456
+ unless specs_updated?
457
+ specs_update_message = "\n * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`."
458
+ end
430
459
  case error
431
460
  when Molinillo::VersionConflict
432
461
  message = error.message_with_trees(
@@ -438,9 +467,9 @@ module Pod
438
467
  if local_pod_parent && !specifications_for_dependency(conflict.requirement).empty? && !conflict.possibility && conflict.locked_requirement
439
468
  # Conflict was caused by a requirement from a local dependency.
440
469
  # Tell user to use `pod update`.
441
- o << "\nIt seems like you've changed the constraints of dependency `#{name}` " \
442
- "inside your development pod `#{local_pod_parent.name}`.\nYou should run `pod update #{name}` to apply "\
443
- "changes you've made."
470
+ o << "\n\nYou have either:#{specs_update_message}" \
471
+ "\n * changed the constraints of dependency `#{name}` inside your development pod `#{local_pod_parent.name}`." \
472
+ "\n You should run `pod update #{name}` to apply changes you've made."
444
473
  elsif !conflict.possibility && conflict.locked_requirement && conflict.locked_requirement.external_source && conflict.locked_requirement.external_source[:podspec] &&
445
474
  conflict.requirement && conflict.requirement.external_source && conflict.requirement.external_source[:podspec]
446
475
  # The internal version of the Podspec doesn't match the external definition of a podspec
@@ -470,13 +499,9 @@ module Pod
470
499
  dependencies = conflicts.count == 1 ? 'dependency' : 'dependencies'
471
500
  o << "\nNone of your spec sources contain a spec satisfying "\
472
501
  "the #{dependencies}: `#{conflicts.join(', ')}`." \
473
- "\n\nYou have either:"
474
- unless specs_updated?
475
- o << "\n * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`."
476
- end
477
- o << "\n * mistyped the name or version." \
478
- "\n * not added the source repo that hosts the Podspec to your Podfile." \
479
- "\n\nNote: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default."
502
+ "\n\nYou have either:#{specs_update_message}" \
503
+ "\n * mistyped the name or version." \
504
+ "\n * not added the source repo that hosts the Podspec to your Podfile."
480
505
 
481
506
  else
482
507
  o << "\nSpecs satisfying the `#{conflicts.join(', ')}` dependency were found, " \
@@ -489,12 +514,9 @@ module Pod
489
514
  message += <<-EOS
490
515
 
491
516
 
492
- You have either:
493
- * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
517
+ You have either:#{specs_update_message}
494
518
  * mistyped the name or version.
495
519
  * not added the source repo that hosts the Podspec to your Podfile.
496
-
497
- Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.
498
520
  EOS
499
521
  end
500
522
  raise type.new(message).tap { |e| e.set_backtrace(error.backtrace) }
@@ -530,33 +552,21 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
530
552
  end
531
553
  end
532
554
 
533
- # Returns the target-appropriate nodes that are `successors` of `node`,
534
- # rejecting those that are scoped by target platform and have incompatible
535
- # targets.
536
- #
537
- # @return [Array<Molinillo::DependencyGraph::Vertex>]
538
- # An array of target-appropriate nodes whose `payload`s are
539
- # dependencies for `target`.
540
- #
541
- def valid_dependencies_for_target(target)
542
- dependencies = Set.new
543
- @podfile_dependency_cache.target_definition_dependencies(target).each do |dep|
544
- node = @activated.vertex_named(dep.name)
545
- add_valid_dependencies_from_node(node, target, dependencies)
555
+ class EdgeAndPlatform
556
+ def initialize(edge, target_platform)
557
+ @edge = edge
558
+ @target_platform = target_platform
546
559
  end
547
- dependencies
548
- end
560
+ attr_reader :edge, :target_platform
549
561
 
550
- def add_valid_dependencies_from_node(node, target, dependencies)
551
- return unless dependencies.add?(node)
552
- validate_platform(node.payload, target)
553
- node.outgoing_edges.each do |edge|
554
- next unless edge_is_valid_for_target_platform?(edge, target.platform)
555
- add_valid_dependencies_from_node(edge.destination, target, dependencies)
562
+ def eql?(other)
563
+ edge.equal?(other.edge) && target_platform.eql?(other.target_platform)
556
564
  end
557
- end
558
565
 
559
- EdgeAndPlatform = Struct.new(:edge, :target_platform)
566
+ def hash
567
+ edge.object_id ^ target_platform.hash
568
+ end
569
+ end
560
570
  private_constant :EdgeAndPlatform
561
571
 
562
572
  # Whether the given `edge` should be followed to find dependencies for the