cocoapods 1.3.1 → 1.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +95 -1
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/lib/cocoapods/gem_version.rb +1 -1
- data/lib/cocoapods/generator/xcconfig/aggregate_xcconfig.rb +6 -3
- data/lib/cocoapods/generator/xcconfig/pod_xcconfig.rb +3 -3
- data/lib/cocoapods/generator/xcconfig/xcconfig_helper.rb +79 -23
- data/lib/cocoapods/installer.rb +6 -5
- data/lib/cocoapods/installer/analyzer.rb +78 -74
- data/lib/cocoapods/installer/analyzer/pod_variant.rb +13 -4
- data/lib/cocoapods/installer/analyzer/target_inspector.rb +2 -2
- data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +53 -8
- data/lib/cocoapods/installer/xcode/pods_project_generator.rb +20 -2
- data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +5 -3
- data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +24 -2
- data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +6 -1
- data/lib/cocoapods/installer/xcode/target_validator.rb +1 -1
- data/lib/cocoapods/resolver.rb +124 -75
- data/lib/cocoapods/target.rb +7 -1
- data/lib/cocoapods/target/aggregate_target.rb +2 -2
- data/lib/cocoapods/target/pod_target.rb +56 -34
- data/lib/cocoapods/validator.rb +11 -2
- metadata +8 -8
@@ -7,6 +7,10 @@ module Pod
|
|
7
7
|
#
|
8
8
|
attr_accessor :specs
|
9
9
|
|
10
|
+
# @return [Array<Specification>] the test specs for the target
|
11
|
+
#
|
12
|
+
attr_accessor :test_specs
|
13
|
+
|
10
14
|
# @return [Platform] the platform
|
11
15
|
#
|
12
16
|
attr_accessor :platform
|
@@ -24,16 +28,21 @@ module Pod
|
|
24
28
|
|
25
29
|
# Initialize a new instance from its attributes.
|
26
30
|
#
|
27
|
-
# @param [Array<
|
28
|
-
# @param [
|
29
|
-
# @param [
|
31
|
+
# @param [Array<Specification>] specs @see #specs
|
32
|
+
# @param [Array<Specification>] test_specs @see #test_specs
|
33
|
+
# @param [Platform] platform @see #platform
|
34
|
+
# @param [Bool] requires_frameworks @see #requires_frameworks?
|
30
35
|
#
|
31
|
-
def initialize(specs, platform, requires_frameworks = false)
|
36
|
+
def initialize(specs, test_specs, platform, requires_frameworks = false)
|
32
37
|
self.specs = specs
|
38
|
+
self.test_specs = test_specs
|
33
39
|
self.platform = platform
|
34
40
|
self.requires_frameworks = requires_frameworks
|
35
41
|
end
|
36
42
|
|
43
|
+
# @note Test specs are intentionally not included as part of the equality for pod variants since a
|
44
|
+
# pod variant should not be affected by the number of test specs included.
|
45
|
+
#
|
37
46
|
# @return [Bool] whether the {PodVariant} is equal to another taking all
|
38
47
|
# all their attributes into account
|
39
48
|
#
|
@@ -161,8 +161,8 @@ module Pod
|
|
161
161
|
"Unable to determine the platform for the `#{target_definition.name}` target."
|
162
162
|
end
|
163
163
|
|
164
|
-
UI.warn "Automatically assigning platform
|
165
|
-
"on target
|
164
|
+
UI.warn "Automatically assigning platform `#{name}` with version `#{deployment_target}` " \
|
165
|
+
"on target `#{target_definition.name}` because no platform was specified. " \
|
166
166
|
"Please specify a platform for this target in your Podfile. See `#{PLATFORM_INFO_URL}`."
|
167
167
|
|
168
168
|
target_definition.set_platform(name, deployment_target)
|
@@ -9,10 +9,15 @@ module Pod
|
|
9
9
|
class TargetIntegrator
|
10
10
|
autoload :XCConfigIntegrator, 'cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator'
|
11
11
|
|
12
|
-
# @return [String] the
|
12
|
+
# @return [String] the string to use as prefix for every build phase added to the user project
|
13
13
|
#
|
14
14
|
BUILD_PHASE_PREFIX = '[CP] '.freeze
|
15
15
|
|
16
|
+
# @return [String] the string to use as prefix for every build phase declared by the user within a podfile
|
17
|
+
# or podspec.
|
18
|
+
#
|
19
|
+
USER_BUILD_PHASE_PREFIX = '[CP-User] '.freeze
|
20
|
+
|
16
21
|
# @return [String] the name of the check manifest phase
|
17
22
|
#
|
18
23
|
CHECK_MANIFEST_PHASE_NAME = 'Check Pods Manifest.lock'.freeze
|
@@ -67,7 +72,7 @@ module Pod
|
|
67
72
|
# @return [void]
|
68
73
|
#
|
69
74
|
def add_embed_frameworks_script_phase_to_target(native_target, script_path, input_paths = [], output_paths = [])
|
70
|
-
phase = TargetIntegrator.create_or_update_build_phase(native_target, EMBED_FRAMEWORK_PHASE_NAME)
|
75
|
+
phase = TargetIntegrator.create_or_update_build_phase(native_target, BUILD_PHASE_PREFIX + EMBED_FRAMEWORK_PHASE_NAME)
|
71
76
|
phase.shell_script = %("#{script_path}"\n)
|
72
77
|
unless input_paths.empty?
|
73
78
|
phase.input_paths = input_paths
|
@@ -108,7 +113,7 @@ module Pod
|
|
108
113
|
#
|
109
114
|
def add_copy_resources_script_phase_to_target(native_target, script_path, input_paths = [], output_paths = [])
|
110
115
|
phase_name = COPY_PODS_RESOURCES_PHASE_NAME
|
111
|
-
phase = TargetIntegrator.create_or_update_build_phase(native_target, phase_name)
|
116
|
+
phase = TargetIntegrator.create_or_update_build_phase(native_target, BUILD_PHASE_PREFIX + phase_name)
|
112
117
|
phase.shell_script = %("#{script_path}"\n)
|
113
118
|
unless input_paths.empty?
|
114
119
|
phase.input_paths = input_paths
|
@@ -132,12 +137,11 @@ module Pod
|
|
132
137
|
# @return [void]
|
133
138
|
#
|
134
139
|
def create_or_update_build_phase(native_target, phase_name, phase_class = Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
|
135
|
-
prefixed_phase_name = BUILD_PHASE_PREFIX + phase_name
|
136
140
|
build_phases = native_target.build_phases.grep(phase_class)
|
137
|
-
build_phases.find { |phase| phase.name && phase.name.end_with?(phase_name) }.tap { |p| p.name =
|
141
|
+
build_phases.find { |phase| phase.name && phase.name.end_with?(phase_name) }.tap { |p| p.name = phase_name if p } ||
|
138
142
|
native_target.project.new(phase_class).tap do |phase|
|
139
|
-
UI.message("Adding Build Phase '#{
|
140
|
-
phase.name =
|
143
|
+
UI.message("Adding Build Phase '#{phase_name}' to project.") do
|
144
|
+
phase.name = phase_name
|
141
145
|
phase.show_env_vars_in_log = '0'
|
142
146
|
native_target.build_phases << phase
|
143
147
|
end
|
@@ -160,6 +164,7 @@ module Pod
|
|
160
164
|
remove_embed_frameworks_script_phase_from_embedded_targets
|
161
165
|
add_copy_resources_script_phase
|
162
166
|
add_check_manifest_lock_script_phase
|
167
|
+
update_target_script_phases
|
163
168
|
end
|
164
169
|
end
|
165
170
|
|
@@ -255,6 +260,46 @@ module Pod
|
|
255
260
|
end
|
256
261
|
end
|
257
262
|
|
263
|
+
# Updates all target script phases for the current target, including creating or updating, deleting
|
264
|
+
# and re-ordering.
|
265
|
+
#
|
266
|
+
# @return [void]
|
267
|
+
#
|
268
|
+
def update_target_script_phases
|
269
|
+
target_definition_script_phases = target.target_definition.script_phases
|
270
|
+
target_definition_script_phase_names = target_definition_script_phases.map { |k| k[:name] }
|
271
|
+
native_targets.each do |native_target|
|
272
|
+
# Delete script phases no longer present in the target definition.
|
273
|
+
native_target_script_phases = native_target.shell_script_build_phases.select { |bp| !bp.name.nil? && bp.name.start_with?(USER_BUILD_PHASE_PREFIX) }
|
274
|
+
native_target_script_phases.each do |script_phase|
|
275
|
+
script_phase_name_without_prefix = script_phase.name.sub(USER_BUILD_PHASE_PREFIX, '')
|
276
|
+
unless target_definition_script_phase_names.include?(script_phase_name_without_prefix)
|
277
|
+
native_target.build_phases.delete(script_phase)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# Create or update the ones that are expected to be.
|
282
|
+
target_definition_script_phases.each do |td_script_phase|
|
283
|
+
phase = TargetIntegrator.create_or_update_build_phase(native_target, USER_BUILD_PHASE_PREFIX + td_script_phase[:name])
|
284
|
+
phase.shell_script = td_script_phase[:script]
|
285
|
+
phase.shell_path = td_script_phase[:shell_path] if td_script_phase.key?(:shell_path)
|
286
|
+
phase.input_paths = td_script_phase[:input_files] if td_script_phase.key?(:input_files)
|
287
|
+
phase.output_paths = td_script_phase[:output_files] if td_script_phase.key?(:output_files)
|
288
|
+
phase.show_env_vars_in_log = td_script_phase[:show_env_vars_in_log] ? '1' : '0' if td_script_phase.key?(:show_env_vars_in_log)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Move script phases to their correct index if the order has changed.
|
292
|
+
offset = native_target.build_phases.count - target_definition_script_phases.count
|
293
|
+
target_definition_script_phases.each_with_index do |td_script_phase, index|
|
294
|
+
current_index = native_target.build_phases.index do |bp|
|
295
|
+
bp.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) && bp.name.sub(USER_BUILD_PHASE_PREFIX, '') == td_script_phase[:name]
|
296
|
+
end
|
297
|
+
expected_index = offset + index
|
298
|
+
native_target.build_phases.insert(expected_index, native_target.build_phases.delete_at(current_index)) if current_index != expected_index
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
258
303
|
# Adds a shell script build phase responsible for checking if the Pods
|
259
304
|
# locked in the Pods/Manifest.lock file are in sync with the Pods defined
|
260
305
|
# in the Podfile.lock.
|
@@ -267,7 +312,7 @@ module Pod
|
|
267
312
|
def add_check_manifest_lock_script_phase
|
268
313
|
phase_name = CHECK_MANIFEST_PHASE_NAME
|
269
314
|
native_targets.each do |native_target|
|
270
|
-
phase = TargetIntegrator.create_or_update_build_phase(native_target, phase_name)
|
315
|
+
phase = TargetIntegrator.create_or_update_build_phase(native_target, BUILD_PHASE_PREFIX + phase_name)
|
271
316
|
native_target.build_phases.unshift(phase).uniq! unless native_target.build_phases.first == phase
|
272
317
|
phase.shell_script = <<-SH.strip_heredoc
|
273
318
|
diff "${PODS_PODFILE_DIR_PATH}/Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null
|
@@ -208,12 +208,14 @@ module Pod
|
|
208
208
|
#
|
209
209
|
def set_target_dependencies
|
210
210
|
frameworks_group = project.frameworks_group
|
211
|
+
test_only_pod_targets = pod_targets.dup
|
211
212
|
aggregate_targets.each do |aggregate_target|
|
212
213
|
is_app_extension = !(aggregate_target.user_targets.map(&:symbol_type) &
|
213
214
|
[:app_extension, :watch_extension, :watch2_extension, :tv_extension, :messages_extension]).empty?
|
214
215
|
is_app_extension ||= aggregate_target.user_targets.any? { |ut| ut.common_resolved_build_setting('APPLICATION_EXTENSION_API_ONLY') == 'YES' }
|
215
216
|
|
216
217
|
aggregate_target.pod_targets.each do |pod_target|
|
218
|
+
test_only_pod_targets.delete(pod_target)
|
217
219
|
configure_app_extension_api_only_for_target(aggregate_target) if is_app_extension
|
218
220
|
|
219
221
|
unless pod_target.should_build?
|
@@ -225,8 +227,24 @@ module Pod
|
|
225
227
|
aggregate_target.native_target.add_dependency(pod_target.native_target)
|
226
228
|
configure_app_extension_api_only_for_target(pod_target) if is_app_extension
|
227
229
|
|
228
|
-
|
229
|
-
|
230
|
+
unless pod_target.static_framework?
|
231
|
+
add_dependent_targets_to_native_target(pod_target.dependent_targets,
|
232
|
+
pod_target.native_target, is_app_extension,
|
233
|
+
pod_target.requires_frameworks?, frameworks_group)
|
234
|
+
add_pod_target_test_dependencies(pod_target, frameworks_group)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
# Wire up remaining pod targets used only by tests and are not used by any aggregate target.
|
239
|
+
test_only_pod_targets.each do |pod_target|
|
240
|
+
unless pod_target.should_build?
|
241
|
+
add_pod_target_test_dependencies(pod_target, frameworks_group)
|
242
|
+
next
|
243
|
+
end
|
244
|
+
unless pod_target.static_framework?
|
245
|
+
add_dependent_targets_to_native_target(pod_target.dependent_targets,
|
246
|
+
pod_target.native_target, false,
|
247
|
+
pod_target.requires_frameworks?, frameworks_group)
|
230
248
|
add_pod_target_test_dependencies(pod_target, frameworks_group)
|
231
249
|
end
|
232
250
|
end
|
@@ -242,7 +242,7 @@ module Pod
|
|
242
242
|
end
|
243
243
|
|
244
244
|
# Returns a Pathname of the nearest parent from which all the given paths descend.
|
245
|
-
# Converts each Pathname to a
|
245
|
+
# Converts each Pathname to a list of path components and finds the longest common prefix
|
246
246
|
#
|
247
247
|
# @param [Array<Pathname>] paths
|
248
248
|
# The paths to files or directories on disk. Must be absolute paths
|
@@ -258,10 +258,12 @@ module Pod
|
|
258
258
|
path.dirname.to_s
|
259
259
|
end
|
260
260
|
min, max = strs.minmax
|
261
|
+
min = min.split('/')
|
262
|
+
max = max.split('/')
|
261
263
|
idx = min.size.times { |i| break i if min[i] != max[i] }
|
262
|
-
result = Pathname.new(min[0...idx])
|
264
|
+
result = Pathname.new(min[0...idx].join('/'))
|
263
265
|
# Don't consider "/" a common path
|
264
|
-
return result unless result.to_s == '/'
|
266
|
+
return result unless result.to_s == '' || result.to_s == '/'
|
265
267
|
end
|
266
268
|
|
267
269
|
# Computes the destination sub-directory in the sandbox
|
@@ -25,7 +25,9 @@ module Pod
|
|
25
25
|
create_xcconfig_file
|
26
26
|
create_test_xcconfig_files if target.contains_test_specifications?
|
27
27
|
if target.requires_frameworks?
|
28
|
-
|
28
|
+
unless target.static_framework?
|
29
|
+
create_info_plist_file
|
30
|
+
end
|
29
31
|
create_module_map
|
30
32
|
create_umbrella_header do |generator|
|
31
33
|
file_accessors = target.file_accessors
|
@@ -39,6 +41,9 @@ module Pod
|
|
39
41
|
end
|
40
42
|
end
|
41
43
|
create_build_phase_to_symlink_header_folders
|
44
|
+
if target.static_framework?
|
45
|
+
create_build_phase_to_move_static_framework_archive
|
46
|
+
end
|
42
47
|
end
|
43
48
|
create_prefix_header
|
44
49
|
create_dummy_source
|
@@ -194,6 +199,8 @@ module Pod
|
|
194
199
|
# requires frameworks. For tests we always use the test target name as the product name
|
195
200
|
# irrelevant to whether we use frameworks or not.
|
196
201
|
configuration.build_settings['PRODUCT_NAME'] = name
|
202
|
+
# We must codesign iOS XCTest bundles that contain binary frameworks to allow them to be launchable in the simulator
|
203
|
+
configuration.build_settings['CODE_SIGNING_REQUIRED'] = 'YES' unless target.platform == :osx
|
197
204
|
end
|
198
205
|
|
199
206
|
# Test native targets also need frameworks and resources to be copied over to their xctest bundle.
|
@@ -219,7 +226,6 @@ module Pod
|
|
219
226
|
bundle_target.product_reference.tap do |bundle_product|
|
220
227
|
bundle_file_name = "#{bundle_name}.bundle"
|
221
228
|
bundle_product.name = bundle_file_name
|
222
|
-
bundle_product.path = bundle_file_name
|
223
229
|
end
|
224
230
|
|
225
231
|
filter_resource_file_references(paths) do |resource_phase_refs, compile_phase_refs|
|
@@ -388,6 +394,22 @@ module Pod
|
|
388
394
|
eos
|
389
395
|
end
|
390
396
|
|
397
|
+
# Creates a build phase to put the static framework archive in the appropriate framework location
|
398
|
+
# Since Xcode does not provide template support for static library frameworks, we've built a static library
|
399
|
+
# of the form lib{LibraryName}.a. We need to move that to the framework location -
|
400
|
+
# {LibraryName}.framework/{LibraryName}.
|
401
|
+
#
|
402
|
+
# @return [void]
|
403
|
+
#
|
404
|
+
def create_build_phase_to_move_static_framework_archive
|
405
|
+
build_phase = native_target.new_shell_script_build_phase('Setup Static Framework Archive')
|
406
|
+
build_phase.shell_script = <<-eos.strip_heredoc
|
407
|
+
mkdir -p "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Modules"
|
408
|
+
cp "${BUILT_PRODUCTS_DIR}/lib${PRODUCT_NAME}.a" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/${PRODUCT_NAME}"
|
409
|
+
cp "${MODULEMAP_FILE}" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Modules/module.modulemap"
|
410
|
+
eos
|
411
|
+
end
|
412
|
+
|
391
413
|
# Creates a prefix header file which imports `UIKit` or `Cocoa` according
|
392
414
|
# to the platform of the target. This file also include any prefix header
|
393
415
|
# content reported by the specification of the pods.
|
@@ -81,7 +81,12 @@ module Pod
|
|
81
81
|
end
|
82
82
|
|
83
83
|
if target.requires_frameworks?
|
84
|
-
|
84
|
+
framework_name = target.product_module_name
|
85
|
+
settings['PRODUCT_NAME'] = framework_name
|
86
|
+
if target.static_framework?
|
87
|
+
settings['PUBLIC_HEADERS_FOLDER_PATH'] = framework_name + '.framework' + '/Headers'
|
88
|
+
settings['PRIVATE_HEADERS_FOLDER_PATH'] = framework_name + '.framework' + '/PrivateHeaders'
|
89
|
+
end
|
85
90
|
else
|
86
91
|
settings.merge!('OTHER_LDFLAGS' => '', 'OTHER_LIBTOOLFLAGS' => '')
|
87
92
|
end
|
@@ -73,7 +73,7 @@ module Pod
|
|
73
73
|
aggregate_target.user_build_configurations.keys.each do |config|
|
74
74
|
pod_targets = aggregate_target.pod_targets_for_build_configuration(config)
|
75
75
|
|
76
|
-
dependencies = pod_targets.select(&:should_build?).flat_map(&:dependencies)
|
76
|
+
dependencies = pod_targets.select(&:should_build?).reject(&:static_framework?).flat_map(&:dependencies)
|
77
77
|
depended_upon_targets = pod_targets.select { |t| dependencies.include?(t.pod_name) && !t.should_build? }
|
78
78
|
|
79
79
|
static_libs = depended_upon_targets.flat_map(&:file_accessors).flat_map(&:vendored_static_artifacts)
|
data/lib/cocoapods/resolver.rb
CHANGED
@@ -12,6 +12,39 @@ module Pod
|
|
12
12
|
# by target for a given Podfile.
|
13
13
|
#
|
14
14
|
class Resolver
|
15
|
+
# A small container that wraps a resolved specification for a given target definition. Additional metadata
|
16
|
+
# is included here such as if the specification is only used by tests.
|
17
|
+
#
|
18
|
+
class ResolverSpecification
|
19
|
+
# @return [Specification] the specification that was resolved
|
20
|
+
#
|
21
|
+
attr_reader :spec
|
22
|
+
|
23
|
+
# @return [Bool] whether this resolved specification is only used by tests.
|
24
|
+
#
|
25
|
+
attr_reader :used_by_tests_only
|
26
|
+
alias used_by_tests_only? used_by_tests_only
|
27
|
+
|
28
|
+
def initialize(spec, used_by_tests_only)
|
29
|
+
@spec = spec
|
30
|
+
@used_by_tests_only = used_by_tests_only
|
31
|
+
end
|
32
|
+
|
33
|
+
def name
|
34
|
+
spec.name
|
35
|
+
end
|
36
|
+
|
37
|
+
def root
|
38
|
+
spec.root
|
39
|
+
end
|
40
|
+
|
41
|
+
def ==(other)
|
42
|
+
self.class == other &&
|
43
|
+
spec == other.spec &&
|
44
|
+
used_by_tests_only == other.test_only
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
15
48
|
include Pod::Installer::InstallationOptions::Mixin
|
16
49
|
|
17
50
|
delegate_installation_options { podfile }
|
@@ -64,8 +97,8 @@ module Pod
|
|
64
97
|
|
65
98
|
# Identifies the specifications that should be installed.
|
66
99
|
#
|
67
|
-
# @return [Hash{TargetDefinition => Array<
|
68
|
-
# the specifications that need to be installed grouped by target
|
100
|
+
# @return [Hash{TargetDefinition => Array<ResolverSpecification>}] resolver_specs_by_target
|
101
|
+
# the resolved specifications that need to be installed grouped by target
|
69
102
|
# definition.
|
70
103
|
#
|
71
104
|
def resolve
|
@@ -75,28 +108,28 @@ module Pod
|
|
75
108
|
end
|
76
109
|
end
|
77
110
|
@activated = Molinillo::Resolver.new(self, self).resolve(dependencies, locked_dependencies)
|
78
|
-
|
111
|
+
resolver_specs_by_target
|
79
112
|
rescue Molinillo::ResolverError => e
|
80
113
|
handle_resolver_error(e)
|
81
114
|
end
|
82
115
|
|
83
|
-
# @return [Hash{Podfile::TargetDefinition => Array<
|
116
|
+
# @return [Hash{Podfile::TargetDefinition => Array<ResolverSpecification>}]
|
84
117
|
# returns the resolved specifications grouped by target.
|
85
118
|
#
|
86
119
|
# @note The returned specifications can be subspecs.
|
87
120
|
#
|
88
|
-
def
|
89
|
-
@
|
121
|
+
def resolver_specs_by_target
|
122
|
+
@resolver_specs_by_target ||= {}.tap do |resolver_specs_by_target|
|
90
123
|
podfile.target_definition_list.each do |target|
|
91
124
|
dependencies = {}
|
92
125
|
specs = target.dependencies.map(&:name).flat_map do |name|
|
93
126
|
node = @activated.vertex_named(name)
|
94
|
-
valid_dependencies_for_target_from_node(target, dependencies, node) << node
|
127
|
+
(valid_dependencies_for_target_from_node(target, dependencies, node) << node).map { |s| [s, node.payload.test_specification?] }
|
95
128
|
end
|
96
129
|
|
97
|
-
|
98
|
-
|
99
|
-
|
130
|
+
resolver_specs_by_target[target] = specs.
|
131
|
+
group_by(&:first).
|
132
|
+
map { |vertex, spec_test_only_tuples| ResolverSpecification.new(vertex.payload, spec_test_only_tuples.map { |tuple| tuple[1] }.all?) }.
|
100
133
|
sort_by(&:name)
|
101
134
|
end
|
102
135
|
end
|
@@ -179,21 +212,33 @@ module Pod
|
|
179
212
|
# @param [Specification] spec the specification in question.
|
180
213
|
#
|
181
214
|
def requirement_satisfied_by?(requirement, activated, spec)
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
215
|
+
version = spec.version
|
216
|
+
return false unless requirement.requirement.satisfied_by?(version)
|
217
|
+
shared_possibility_versions, prerelease_requirement = possibility_versions_for_root_name(requirement, activated)
|
218
|
+
return false if !shared_possibility_versions.empty? && !shared_possibility_versions.include?(version)
|
219
|
+
return false if version.prerelease? && !prerelease_requirement
|
220
|
+
return false unless spec_is_platform_compatible?(activated, requirement, spec)
|
221
|
+
true
|
222
|
+
end
|
223
|
+
|
224
|
+
def possibility_versions_for_root_name(requirement, activated)
|
225
|
+
prerelease_requirement = requirement.prerelease? || requirement.external_source
|
226
|
+
existing = activated.vertices.values.flat_map do |vertex|
|
227
|
+
next unless vertex.payload
|
228
|
+
next unless Specification.root_name(vertex.name) == requirement.root_name
|
229
|
+
|
230
|
+
prerelease_requirement ||= vertex.requirements.any? { |r| r.prerelease? || r.external_source }
|
231
|
+
|
232
|
+
if vertex.payload.respond_to?(:possibilities)
|
233
|
+
vertex.payload.possibilities.map(&:version)
|
189
234
|
else
|
190
|
-
|
235
|
+
vertex.payload.version
|
191
236
|
end
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
) && spec_is_platform_compatible?(activated, requirement, spec)
|
237
|
+
end.compact
|
238
|
+
|
239
|
+
[existing, prerelease_requirement]
|
196
240
|
end
|
241
|
+
private :possibility_versions_for_root_name
|
197
242
|
|
198
243
|
# Sort dependencies so that the ones that are easiest to resolve are first.
|
199
244
|
# Easiest to resolve is (usually) defined by:
|
@@ -399,64 +444,69 @@ module Pod
|
|
399
444
|
# @param [Molinillo::ResolverError] error
|
400
445
|
#
|
401
446
|
def handle_resolver_error(error)
|
402
|
-
message = error.message
|
447
|
+
message = error.message
|
403
448
|
type = Informative
|
404
449
|
case error
|
405
450
|
when Molinillo::VersionConflict
|
406
|
-
error.
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
451
|
+
message = error.message_with_trees(
|
452
|
+
:solver_name => 'CocoaPods',
|
453
|
+
:possibility_type => 'pod',
|
454
|
+
:version_for_spec => lambda(&:version),
|
455
|
+
:additional_message_for_conflict => lambda do |o, name, conflict|
|
456
|
+
local_pod_parent = conflict.requirement_trees.flatten.reverse.find(&:local?)
|
457
|
+
lockfile_reqs = conflict.requirements[name_for_locking_dependency_source]
|
458
|
+
if lockfile_reqs && lockfile_reqs.last && lockfile_reqs.last.prerelease? && !conflict.existing
|
459
|
+
o << "\nDue to the previous naïve CocoaPods resolver, " \
|
460
|
+
"you were using a pre-release version of `#{name}`, " \
|
461
|
+
'without explicitly asking for a pre-release version, which now leads to a conflict. ' \
|
462
|
+
'Please decide to either use that pre-release version by adding the ' \
|
463
|
+
'version requirement to your Podfile ' \
|
464
|
+
"(e.g. `pod '#{name}', '#{lockfile_reqs.map(&:requirement).join("', '")}'`) " \
|
465
|
+
"or revert to a stable version by running `pod update #{name}`."
|
466
|
+
elsif local_pod_parent && !specifications_for_dependency(conflict.requirement).empty? && !conflict.possibility && conflict.locked_requirement
|
467
|
+
# Conflict was caused by a requirement from a local dependency.
|
468
|
+
# Tell user to use `pod update`.
|
469
|
+
o << "\nIt seems like you've changed the constraints of dependency `#{name}` " \
|
470
|
+
"inside your development pod `#{local_pod_parent.name}`.\nYou should run `pod update #{name}` to apply " \
|
471
|
+
"changes you've made."
|
472
|
+
elsif (conflict.possibility && conflict.possibility.version.prerelease?) &&
|
473
|
+
(conflict.requirement && !(
|
474
|
+
conflict.requirement.prerelease? ||
|
475
|
+
conflict.requirement.external_source)
|
476
|
+
)
|
477
|
+
# Conflict was caused by not specifying an explicit version for the requirement #[name],
|
478
|
+
# and there is no available stable version satisfying constraints for the requirement.
|
479
|
+
o << "\nThere are only pre-release versions available satisfying the following requirements:\n"
|
480
|
+
conflict.requirements.values.flatten.each do |r|
|
481
|
+
unless search_for(r).empty?
|
482
|
+
o << "\n\t'#{name}', '#{r.requirement}'\n"
|
483
|
+
end
|
434
484
|
end
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
485
|
+
o << "\nYou should explicitly specify the version in order to install a pre-release version"
|
486
|
+
elsif !conflict.existing
|
487
|
+
conflicts = conflict.requirements.values.flatten.uniq
|
488
|
+
found_conflicted_specs = conflicts.reject { |c| search_for(c).empty? }
|
489
|
+
if found_conflicted_specs.empty?
|
490
|
+
# There are no existing specification inside any of the spec repos with given requirements.
|
491
|
+
type = NoSpecFoundError
|
492
|
+
dependencies = conflicts.count == 1 ? 'dependency' : 'dependencies'
|
493
|
+
o << "\nNone of your spec sources contain a spec satisfying "\
|
494
|
+
"the #{dependencies}: `#{conflicts.join(', ')}`." \
|
495
|
+
"\n\nYou have either:"
|
496
|
+
unless specs_updated?
|
497
|
+
o << "\n * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`."
|
498
|
+
end
|
499
|
+
o << "\n * mistyped the name or version." \
|
500
|
+
"\n * not added the source repo that hosts the Podspec to your Podfile." \
|
501
|
+
"\n\nNote: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default."
|
502
|
+
|
503
|
+
else
|
504
|
+
o << "\nSpecs satisfying the `#{conflicts.join(', ')}` dependency were found, " \
|
505
|
+
'but they required a higher minimum deployment target.'
|
449
506
|
end
|
450
|
-
message << "\n * mistyped the name or version." \
|
451
|
-
"\n * not added the source repo that hosts the Podspec to your Podfile." \
|
452
|
-
"\n\nNote: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default."
|
453
|
-
|
454
|
-
else
|
455
|
-
message << "\n\nSpecs satisfying the `#{conflicts.join(', ')}` dependency were found, " \
|
456
|
-
'but they required a higher minimum deployment target.'
|
457
507
|
end
|
458
|
-
end
|
459
|
-
|
508
|
+
end,
|
509
|
+
)
|
460
510
|
end
|
461
511
|
raise type, message
|
462
512
|
end
|
@@ -500,7 +550,6 @@ module Pod
|
|
500
550
|
|
501
551
|
dependency_nodes + dependency_nodes.flat_map do |item|
|
502
552
|
node_result = valid_dependencies_for_target_from_node(target, dependencies, item)
|
503
|
-
|
504
553
|
node_result
|
505
554
|
end
|
506
555
|
end
|