cocoapods 1.7.5 → 1.8.0.beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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