cocoapods 0.13.0 → 0.14.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +97 -16
- data/lib/cocoapods.rb +2 -1
- data/lib/cocoapods/command.rb +46 -19
- data/lib/cocoapods/command/install.rb +11 -12
- data/lib/cocoapods/command/linter.rb +3 -1
- data/lib/cocoapods/command/outdated.rb +51 -0
- data/lib/cocoapods/command/push.rb +6 -6
- data/lib/cocoapods/command/setup.rb +1 -1
- data/lib/cocoapods/command/spec.rb +1 -1
- data/lib/cocoapods/command/update.rb +21 -0
- data/lib/cocoapods/config.rb +14 -1
- data/lib/cocoapods/dependency.rb +56 -13
- data/lib/cocoapods/downloader/git.rb +1 -0
- data/lib/cocoapods/downloader/subversion.rb +6 -2
- data/lib/cocoapods/installer.rb +48 -64
- data/lib/cocoapods/local_pod.rb +50 -12
- data/lib/cocoapods/lockfile.rb +267 -0
- data/lib/cocoapods/podfile.rb +4 -0
- data/lib/cocoapods/project.rb +9 -4
- data/lib/cocoapods/resolver.rb +164 -20
- data/lib/cocoapods/specification.rb +11 -13
- data/lib/cocoapods/specification/set.rb +10 -13
- data/lib/cocoapods/version.rb +19 -2
- metadata +7 -4
@@ -0,0 +1,267 @@
|
|
1
|
+
module Pod
|
2
|
+
class Lockfile
|
3
|
+
|
4
|
+
# @return [Lockfile] Returns the Lockfile saved in path.
|
5
|
+
# Returns {nil} If the file can't be loaded.
|
6
|
+
#
|
7
|
+
def self.from_file(path)
|
8
|
+
return nil unless path.exist?
|
9
|
+
hash = YAML.load(File.open(path))
|
10
|
+
lockfile = Lockfile.new(hash)
|
11
|
+
lockfile.defined_in_file = path
|
12
|
+
lockfile
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Lockfile] Generates a lockfile from a {Podfile} and the
|
16
|
+
# list of {Specifications} that were installed.
|
17
|
+
#
|
18
|
+
def self.generate(podfile, specs)
|
19
|
+
Lockfile.new(generate_hash_from_podfile(podfile, specs))
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [String] The file where this Lockfile is defined.
|
23
|
+
#
|
24
|
+
attr_accessor :defined_in_file
|
25
|
+
|
26
|
+
# @return [String] The hash used to initialize the Lockfile.
|
27
|
+
#
|
28
|
+
attr_reader :to_hash
|
29
|
+
|
30
|
+
# @param [Hash] hash A Hash representation of a Lockfile.
|
31
|
+
#
|
32
|
+
def initialize(hash)
|
33
|
+
@to_hash = hash
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Array<String, Hash{String => Array[String]}>] The pods installed
|
37
|
+
# and their dependencies.
|
38
|
+
#
|
39
|
+
def pods
|
40
|
+
@pods ||= to_hash['PODS'] || []
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Array<Dependency>] The Podfile dependencies used during the last
|
44
|
+
# install.
|
45
|
+
#
|
46
|
+
def dependencies
|
47
|
+
@dependencies ||= to_hash['DEPENDENCIES'].map { |dep| dependency_from_string(dep) } || []
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Hash{String => Hash}] A hash where the name of the pods are
|
51
|
+
# the keys and the values are the parameters of an {AbstractExternalSource}
|
52
|
+
# of the dependency that required the pod.
|
53
|
+
#
|
54
|
+
def external_sources
|
55
|
+
@external_sources ||= to_hash["EXTERNAL SOURCES"] || {}
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [Array<String>] The names of the installed Pods.
|
59
|
+
#
|
60
|
+
def pods_names
|
61
|
+
@pods_names ||= pods.map do |pod|
|
62
|
+
pod = pod.keys.first unless pod.is_a?(String)
|
63
|
+
name_and_version_for_pod(pod)[0]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Hash{String => Version}] A Hash containing the name
|
68
|
+
# of the installed Pods as the keys and their corresponding {Version}
|
69
|
+
# as the values.
|
70
|
+
#
|
71
|
+
def pods_versions
|
72
|
+
unless @pods_versions
|
73
|
+
@pods_versions = {}
|
74
|
+
pods.each do |pod|
|
75
|
+
pod = pod.keys.first unless pod.is_a?(String)
|
76
|
+
name, version = name_and_version_for_pod(pod)
|
77
|
+
@pods_versions[name] = version
|
78
|
+
end
|
79
|
+
end
|
80
|
+
@pods_versions
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [Dependency] A dependency that describes the exact installed version
|
84
|
+
# of a Pod.
|
85
|
+
#
|
86
|
+
def dependency_for_installed_pod_named(name)
|
87
|
+
version = pods_versions[name]
|
88
|
+
raise Informative, "Attempt to lock a Pod without an known version." unless version
|
89
|
+
dependency = Dependency.new(name, version)
|
90
|
+
if external_source = external_sources[name]
|
91
|
+
dependency.external_source = Dependency::ExternalSources.from_params(dependency.name, external_source)
|
92
|
+
end
|
93
|
+
dependency
|
94
|
+
end
|
95
|
+
|
96
|
+
# @param [String] The string that describes a {Specification} generated
|
97
|
+
# from {Specification#to_s}.
|
98
|
+
#
|
99
|
+
# @example Strings examples
|
100
|
+
# "libPusher"
|
101
|
+
# "libPusher (1.0)"
|
102
|
+
# "libPusher (HEAD based on 1.0)"
|
103
|
+
# "RestKit/JSON"
|
104
|
+
#
|
105
|
+
# @return [String, Version] The name and the version of a
|
106
|
+
# pod.
|
107
|
+
#
|
108
|
+
def name_and_version_for_pod(string)
|
109
|
+
match_data = string.match(/(\S*) \((.*)\)/)
|
110
|
+
name = match_data[1]
|
111
|
+
vers = Version.from_string(match_data[2])
|
112
|
+
[name, vers]
|
113
|
+
end
|
114
|
+
|
115
|
+
# @param [String] The string that describes a {Dependency} generated
|
116
|
+
# from {Dependency#to_s}.
|
117
|
+
#
|
118
|
+
# @example Strings examples
|
119
|
+
# "libPusher"
|
120
|
+
# "libPusher (= 1.0)"
|
121
|
+
# "libPusher (~> 1.0.1)"
|
122
|
+
# "libPusher (> 1.0, < 2.0)"
|
123
|
+
# "libPusher (HEAD)"
|
124
|
+
# "libPusher (from `www.example.com')"
|
125
|
+
# "libPusher (defined in Podfile)"
|
126
|
+
# "RestKit/JSON"
|
127
|
+
#
|
128
|
+
# @return [Dependency] The dependency described by the string.
|
129
|
+
#
|
130
|
+
def dependency_from_string(string)
|
131
|
+
match_data = string.match(/(\S*)( (.*))?/)
|
132
|
+
name = match_data[1]
|
133
|
+
version = match_data[2]
|
134
|
+
version = version.gsub(/[()]/,'') if version
|
135
|
+
case version
|
136
|
+
when nil
|
137
|
+
Dependency.new(name)
|
138
|
+
when /defined in Podfile/
|
139
|
+
# @TODO: store the whole spec?, the version?
|
140
|
+
Dependency.new(name)
|
141
|
+
when /from `(.*)'/
|
142
|
+
external_source_info = external_sources[name]
|
143
|
+
Dependency.new(name, external_source_info)
|
144
|
+
when /HEAD/
|
145
|
+
# @TODO: find a way to serialize from the Downloader the information
|
146
|
+
# necessary to restore a head version.
|
147
|
+
Dependency.new(name, :head)
|
148
|
+
else
|
149
|
+
Dependency.new(name, version)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Analyzes the {Lockfile} and detects any changes applied to the {Podfile}
|
154
|
+
# since the last installation.
|
155
|
+
#
|
156
|
+
# For each Pod, it detects one state among the following:
|
157
|
+
#
|
158
|
+
# - added: Pods that weren't present in the Podfile.
|
159
|
+
# - changed: Pods that were present in the Podfile but changed:
|
160
|
+
# - Pods whose version is not compatible anymore with Podfile,
|
161
|
+
# - Pods that changed their head or external options.
|
162
|
+
# - removed: Pods that were removed form the Podfile.
|
163
|
+
# - unchanged: Pods that are still compatible with Podfile.
|
164
|
+
#
|
165
|
+
# @TODO: detect changes for inline dependencies?
|
166
|
+
#
|
167
|
+
# @return [Hash{Symbol=>Array[Strings]}] A hash where pods are grouped
|
168
|
+
# by the state in which they are.
|
169
|
+
#
|
170
|
+
def detect_changes_with_podfile(podfile)
|
171
|
+
previous_podfile_deps = dependencies.map(&:name)
|
172
|
+
user_installed_pods = pods_names.reject { |name| !previous_podfile_deps.include?(name) }
|
173
|
+
deps_to_install = podfile.dependencies.dup
|
174
|
+
|
175
|
+
result = {}
|
176
|
+
result[:added] = []
|
177
|
+
result[:changed] = []
|
178
|
+
result[:removed] = []
|
179
|
+
result[:unchanged] = []
|
180
|
+
|
181
|
+
user_installed_pods.each do |pod_name|
|
182
|
+
dependency = deps_to_install.find { |d| d.name == pod_name }
|
183
|
+
deps_to_install.delete(dependency)
|
184
|
+
version = pods_versions[pod_name]
|
185
|
+
external_source = Dependency::ExternalSources.from_params(pod_name, external_sources[pod_name])
|
186
|
+
|
187
|
+
if dependency.nil?
|
188
|
+
result[:removed] << pod_name
|
189
|
+
elsif !dependency.match_version?(version) || dependency.external_source != external_source
|
190
|
+
result[:changed] << pod_name
|
191
|
+
else
|
192
|
+
result[:unchanged] << pod_name
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
deps_to_install.each do |dependency|
|
197
|
+
result[:added] << dependency.name
|
198
|
+
end
|
199
|
+
result
|
200
|
+
end
|
201
|
+
|
202
|
+
# @return [void] Writes the Lockfile to {#path}.
|
203
|
+
#
|
204
|
+
def write_to_disk(path)
|
205
|
+
File.open(path, 'w') {|f| f.write(to_yaml) }
|
206
|
+
defined_in_file = path
|
207
|
+
end
|
208
|
+
|
209
|
+
# @return [String] A string useful to represent the Lockfile in a message
|
210
|
+
# presented to the user.
|
211
|
+
#
|
212
|
+
def to_s
|
213
|
+
"Podfile.lock"
|
214
|
+
end
|
215
|
+
|
216
|
+
# @return [String] The YAML representation of the Lockfile, used for
|
217
|
+
# serialization.
|
218
|
+
#
|
219
|
+
def to_yaml
|
220
|
+
to_hash.to_yaml.gsub(/^--- ?\n/,"").gsub(/^([A-Z])/,"\n\\1")
|
221
|
+
end
|
222
|
+
|
223
|
+
# @return [Hash] The Hash representation of the Lockfile generated from
|
224
|
+
# a given Podfile and the list of resolved Specifications.
|
225
|
+
#
|
226
|
+
def self.generate_hash_from_podfile(podfile, specs)
|
227
|
+
hash = {}
|
228
|
+
|
229
|
+
# Get list of [name, dependencies] pairs.
|
230
|
+
pod_and_deps = specs.map do |spec|
|
231
|
+
[spec.to_s, spec.dependencies.map(&:to_s).sort]
|
232
|
+
end.uniq
|
233
|
+
|
234
|
+
# Merge dependencies of iOS and OS X version of the same pod.
|
235
|
+
tmp = {}
|
236
|
+
pod_and_deps.each do |name, deps|
|
237
|
+
if tmp[name]
|
238
|
+
tmp[name].concat(deps).uniq!
|
239
|
+
else
|
240
|
+
tmp[name] = deps
|
241
|
+
end
|
242
|
+
end
|
243
|
+
pod_and_deps = tmp.sort_by(&:first).map do |name, deps|
|
244
|
+
deps.empty? ? name : { name => deps }
|
245
|
+
end
|
246
|
+
hash["PODS"] = pod_and_deps
|
247
|
+
|
248
|
+
hash["DEPENDENCIES"] = podfile.dependencies.map{ |d| d.to_s }.sort
|
249
|
+
|
250
|
+
external_sources = {}
|
251
|
+
deps = podfile.dependencies.select(&:external?).sort{ |d, other| d.name <=> other.name}
|
252
|
+
deps.each{ |d| external_sources[d.name] = d.external_source.params }
|
253
|
+
hash["EXTERNAL SOURCES"] = external_sources unless external_sources.empty?
|
254
|
+
|
255
|
+
checksums = {}
|
256
|
+
specs.select { |spec| !spec.defined_in_file.nil? }.each do |spec|
|
257
|
+
checksum = Digest::SHA1.hexdigest(File.read(spec.defined_in_file))
|
258
|
+
checksum = checksum.encode('UTF-8') if checksum.respond_to?(:encode)
|
259
|
+
checksums[spec.name] = checksum
|
260
|
+
end
|
261
|
+
hash["SPEC CHECKSUMS"] = checksums unless checksums.empty?
|
262
|
+
hash["COCOAPODS"] = VERSION
|
263
|
+
hash
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
data/lib/cocoapods/podfile.rb
CHANGED
data/lib/cocoapods/project.rb
CHANGED
@@ -31,15 +31,20 @@ module Pod
|
|
31
31
|
|
32
32
|
# Shortcut access to the `Pods' PBXGroup.
|
33
33
|
def pods
|
34
|
-
|
34
|
+
@pods ||= groups.where(:name => 'Pods') || groups.new('name' => 'Pods')
|
35
|
+
end
|
36
|
+
|
37
|
+
# Shortcut access to the `Local Pods' PBXGroup.
|
38
|
+
def local_pods
|
39
|
+
@local_pods ||= groups.where(:name => 'Local Pods') || groups.new('name' => 'Local Pods')
|
35
40
|
end
|
36
41
|
|
37
42
|
# Adds a group as child to the `Pods' group namespacing subspecs.
|
38
|
-
def add_spec_group(name)
|
39
|
-
groups =
|
43
|
+
def add_spec_group(name, parent_group)
|
44
|
+
groups = parent_group.groups
|
40
45
|
group = nil
|
41
46
|
name.split('/').each do |name|
|
42
|
-
group = groups.
|
47
|
+
group = groups.where(:name => name) || groups.new('name' => name)
|
43
48
|
groups = group.groups
|
44
49
|
end
|
45
50
|
group
|
data/lib/cocoapods/resolver.rb
CHANGED
@@ -4,44 +4,169 @@ module Pod
|
|
4
4
|
class Resolver
|
5
5
|
include Config::Mixin
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
# @return [Bool] Whether the resolver should find the pods to install or
|
8
|
+
# the pods to update.
|
9
|
+
#
|
10
|
+
attr_accessor :update_mode
|
11
|
+
|
12
|
+
# @return [Bool] Whether the resolver should update the external specs
|
13
|
+
# in the resolution process.
|
14
|
+
#
|
15
|
+
attr_accessor :update_external_specs
|
16
|
+
|
17
|
+
# @return [Podfile] The Podfile used by the resolver.
|
18
|
+
#
|
19
|
+
attr_reader :podfile
|
20
|
+
|
21
|
+
# @return [Lockfile] The Lockfile used by the resolver.
|
22
|
+
#
|
23
|
+
attr_reader :lockfile
|
24
|
+
|
25
|
+
# @return [Sandbox] The Sandbox used by the resolver to find external
|
26
|
+
# dependencies.
|
27
|
+
#
|
28
|
+
attr_reader :sandbox
|
29
|
+
|
30
|
+
# @return [Array<Strings>] The name of the pods that have an
|
31
|
+
# external source.
|
32
|
+
#
|
33
|
+
attr_reader :pods_from_external_sources
|
34
|
+
|
35
|
+
# @return [Array<Set>] A cache of the sets used to resolve the dependencies.
|
36
|
+
#
|
37
|
+
attr_reader :cached_sets
|
38
|
+
|
39
|
+
# @return [Source::Aggregate] A cache of the sources needed to find the
|
40
|
+
# podspecs.
|
41
|
+
#
|
42
|
+
attr_reader :cached_sources
|
43
|
+
|
44
|
+
# @return [Hash{Podfile::TargetDefinition => Array<Specification>}]
|
45
|
+
# Returns the resolved specifications grouped by target.
|
46
|
+
#
|
47
|
+
attr_reader :specs_by_target
|
48
|
+
|
49
|
+
def initialize(podfile, lockfile, sandbox)
|
50
|
+
@podfile = podfile
|
51
|
+
@lockfile = lockfile
|
52
|
+
@sandbox = sandbox
|
53
|
+
@update_external_specs = true
|
9
54
|
|
10
|
-
def initialize(podfile, sandbox)
|
11
|
-
@podfile = podfile
|
12
|
-
@sandbox = sandbox
|
13
55
|
@cached_sets = {}
|
14
56
|
@cached_sources = Source::Aggregate.new
|
15
|
-
@log_indent = 0;
|
16
57
|
end
|
17
58
|
|
59
|
+
# Identifies the specifications that should be installed according whether
|
60
|
+
# the resolver is in update mode or not.
|
61
|
+
#
|
62
|
+
# @return [Hash{Podfile::TargetDefinition => Array<Specification>}] specs_by_target
|
63
|
+
#
|
18
64
|
def resolve
|
19
|
-
@
|
20
|
-
|
65
|
+
@cached_specs = {}
|
66
|
+
@specs_by_target = {}
|
67
|
+
@pods_from_external_sources = []
|
68
|
+
@pods_to_lock = []
|
69
|
+
@log_indent = 0
|
70
|
+
|
71
|
+
if @lockfile
|
72
|
+
puts "\nFinding added, modified or removed dependencies:".green if config.verbose?
|
73
|
+
@pods_by_state = @lockfile.detect_changes_with_podfile(podfile)
|
74
|
+
if config.verbose?
|
75
|
+
@pods_by_state.each do |symbol, pod_names|
|
76
|
+
case symbol
|
77
|
+
when :added
|
78
|
+
mark = "A".green
|
79
|
+
when :changed
|
80
|
+
mark = "M".yellow
|
81
|
+
when :removed
|
82
|
+
mark = "R".red
|
83
|
+
when :unchanged
|
84
|
+
mark = "-"
|
85
|
+
end
|
86
|
+
pod_names.each do |pod_name|
|
87
|
+
puts " #{mark} " << pod_name
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
@pods_to_lock = (lockfile.pods_names - @pods_by_state[:added] - @pods_by_state[:changed] - @pods_by_state[:removed]).uniq
|
92
|
+
end
|
21
93
|
|
22
94
|
@podfile.target_definitions.values.each do |target_definition|
|
23
|
-
puts "\nResolving dependencies for target `#{target_definition.name}' (#{target_definition.platform})".green if config.verbose?
|
95
|
+
puts "\nResolving dependencies for target `#{target_definition.name}' (#{target_definition.platform}):".green if config.verbose?
|
24
96
|
@loaded_specs = []
|
25
97
|
find_dependency_specs(@podfile, target_definition.dependencies, target_definition)
|
26
|
-
|
98
|
+
@specs_by_target[target_definition] = @cached_specs.values_at(*@loaded_specs).sort_by(&:name)
|
99
|
+
end
|
100
|
+
|
101
|
+
@cached_specs.values.sort_by(&:name)
|
102
|
+
@specs_by_target
|
103
|
+
end
|
104
|
+
|
105
|
+
# @return [Array<Specification>] The specifications loaded by the resolver.
|
106
|
+
#
|
107
|
+
def specs
|
108
|
+
@cached_specs.values.uniq
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Bool] Whether a pod should be installed/reinstalled.
|
112
|
+
#
|
113
|
+
def should_install?(name)
|
114
|
+
pods_to_install.include? name
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [Array<Strings>] The name of the pods that should be
|
118
|
+
# installed/reinstalled.
|
119
|
+
#
|
120
|
+
def pods_to_install
|
121
|
+
unless @pods_to_install
|
122
|
+
if lockfile
|
123
|
+
@pods_to_install = specs.select do |spec|
|
124
|
+
spec.version != lockfile.pods_versions[spec.pod_name]
|
125
|
+
end.map(&:name)
|
126
|
+
if update_mode
|
127
|
+
@pods_to_install += specs.select do |spec|
|
128
|
+
spec.version.head? || pods_from_external_sources.include?(spec.pod_name)
|
129
|
+
end.map(&:name)
|
130
|
+
end
|
131
|
+
@pods_to_install += @pods_by_state[:added] + @pods_by_state[:changed]
|
132
|
+
else
|
133
|
+
@pods_to_install = specs.map(&:name)
|
134
|
+
end
|
27
135
|
end
|
136
|
+
@pods_to_install
|
137
|
+
end
|
28
138
|
|
29
|
-
|
30
|
-
|
139
|
+
# @return [Array<Strings>] The name of the pods that were installed
|
140
|
+
# but don't have any dependency anymore. The name of the Pods are
|
141
|
+
# stripped from subspecs.
|
142
|
+
#
|
143
|
+
def removed_pods
|
144
|
+
return [] unless lockfile
|
145
|
+
unless @removed_pods
|
146
|
+
previusly_installed = lockfile.pods_names.map { |pod_name| pod_name.split('/').first }
|
147
|
+
installed = specs.map { |spec| spec.name.split('/').first }
|
148
|
+
@removed_pods = previusly_installed - installed
|
149
|
+
end
|
150
|
+
@removed_pods
|
31
151
|
end
|
32
152
|
|
33
153
|
private
|
34
154
|
|
155
|
+
# @return [Set] The cached set for a given dependency.
|
156
|
+
#
|
35
157
|
def find_cached_set(dependency, platform)
|
36
158
|
set_name = dependency.name.split('/').first
|
37
159
|
@cached_sets[set_name] ||= begin
|
38
160
|
if dependency.specification
|
39
161
|
Specification::Set::External.new(dependency.specification)
|
40
162
|
elsif external_source = dependency.external_source
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
163
|
+
if update_mode && update_external_specs
|
164
|
+
# Always update external sources in update mode.
|
165
|
+
specification = external_source.specification_from_external(@sandbox, platform)
|
166
|
+
else
|
167
|
+
# Don't update external sources in install mode if not needed.
|
168
|
+
specification = external_source.specification_from_sandbox(@sandbox, platform)
|
169
|
+
end
|
45
170
|
set = Specification::Set::External.new(specification)
|
46
171
|
if dependency.subspec_dependency?
|
47
172
|
@cached_sets[dependency.top_level_spec_name] ||= set
|
@@ -53,29 +178,48 @@ module Pod
|
|
53
178
|
end
|
54
179
|
end
|
55
180
|
|
181
|
+
# Resolves the dependencies of a specification and stores them in @cached_specs
|
182
|
+
#
|
183
|
+
# @param [Specification] dependent_specification
|
184
|
+
# @param [Array<Dependency>] dependencies
|
185
|
+
# @param [TargetDefinition] target_definition
|
186
|
+
#
|
187
|
+
# @return [void]
|
188
|
+
#
|
56
189
|
def find_dependency_specs(dependent_specification, dependencies, target_definition)
|
57
190
|
@log_indent += 1
|
58
191
|
dependencies.each do |dependency|
|
192
|
+
# Replace the dependency with a more specific one if the pod is already installed.
|
193
|
+
if !update_mode && @pods_to_lock.include?(dependency.name)
|
194
|
+
dependency = lockfile.dependency_for_installed_pod_named(dependency.name)
|
195
|
+
end
|
196
|
+
|
59
197
|
puts ' ' * @log_indent + "- #{dependency}" if config.verbose?
|
60
198
|
set = find_cached_set(dependency, target_definition.platform)
|
61
|
-
set.required_by(dependent_specification)
|
199
|
+
set.required_by(dependency, dependent_specification.to_s)
|
200
|
+
|
62
201
|
# Ensure we don't resolve the same spec twice for one target
|
63
202
|
unless @loaded_specs.include?(dependency.name)
|
64
203
|
spec = set.specification_by_name(dependency.name)
|
204
|
+
@pods_from_external_sources << spec.pod_name if dependency.external?
|
65
205
|
@loaded_specs << spec.name
|
66
|
-
@
|
206
|
+
@cached_specs[spec.name] = spec
|
67
207
|
# Configure the specification
|
68
208
|
spec.activate_platform(target_definition.platform)
|
69
209
|
spec.version.head = dependency.head?
|
70
210
|
# And recursively load the dependencies of the spec.
|
71
211
|
find_dependency_specs(spec, spec.dependencies, target_definition) if spec.dependencies
|
72
212
|
end
|
73
|
-
validate_platform
|
213
|
+
validate_platform(spec || @cached_specs[dependency.name], target_definition)
|
74
214
|
end
|
75
215
|
@log_indent -= 1
|
76
216
|
end
|
77
217
|
|
78
|
-
|
218
|
+
# Ensures that a spec is compatible with platform of a target.
|
219
|
+
#
|
220
|
+
# @raises If the spec is not supported by the target.
|
221
|
+
#
|
222
|
+
def validate_platform(spec, target)
|
79
223
|
unless spec.available_platforms.any? { |platform| target.platform.supports?(platform) }
|
80
224
|
raise Informative, "[!] The platform of the target `#{target.name}' (#{target.platform}) is not compatible with `#{spec}' which has a minimun requirement of #{spec.available_platforms.join(' - ')}.".red
|
81
225
|
end
|