cocoapods-core 0.17.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +36 -0
- data/lib/cocoapods-core/core_ui.rb +19 -0
- data/lib/cocoapods-core/dependency.rb +295 -0
- data/lib/cocoapods-core/gem_version.rb +6 -0
- data/lib/cocoapods-core/lockfile.rb +440 -0
- data/lib/cocoapods-core/platform.rb +171 -0
- data/lib/cocoapods-core/podfile/dsl.rb +459 -0
- data/lib/cocoapods-core/podfile/target_definition.rb +503 -0
- data/lib/cocoapods-core/podfile.rb +345 -0
- data/lib/cocoapods-core/requirement.rb +15 -0
- data/lib/cocoapods-core/source/validator.rb +183 -0
- data/lib/cocoapods-core/source.rb +284 -0
- data/lib/cocoapods-core/specification/consumer.rb +356 -0
- data/lib/cocoapods-core/specification/dsl/attribute.rb +245 -0
- data/lib/cocoapods-core/specification/dsl/attribute_support.rb +76 -0
- data/lib/cocoapods-core/specification/dsl/deprecations.rb +47 -0
- data/lib/cocoapods-core/specification/dsl/platform_proxy.rb +67 -0
- data/lib/cocoapods-core/specification/dsl.rb +1110 -0
- data/lib/cocoapods-core/specification/linter.rb +436 -0
- data/lib/cocoapods-core/specification/root_attribute_accessors.rb +152 -0
- data/lib/cocoapods-core/specification/set/presenter.rb +229 -0
- data/lib/cocoapods-core/specification/set/statistics.rb +277 -0
- data/lib/cocoapods-core/specification/set.rb +171 -0
- data/lib/cocoapods-core/specification/yaml.rb +60 -0
- data/lib/cocoapods-core/specification.rb +592 -0
- data/lib/cocoapods-core/standard_error.rb +84 -0
- data/lib/cocoapods-core/vendor/dependency.rb +264 -0
- data/lib/cocoapods-core/vendor/requirement.rb +208 -0
- data/lib/cocoapods-core/vendor/version.rb +333 -0
- data/lib/cocoapods-core/vendor.rb +56 -0
- data/lib/cocoapods-core/version.rb +99 -0
- data/lib/cocoapods-core/yaml_converter.rb +202 -0
- data/lib/cocoapods-core.rb +23 -0
- metadata +154 -0
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'active_support/core_ext/array/conversions'
|
2
|
+
|
3
|
+
module Pod
|
4
|
+
class Specification
|
5
|
+
class Set
|
6
|
+
|
7
|
+
# Provides support for presenting a Pod described by a {Set} in a
|
8
|
+
# consistent way across clients of CocoaPods-Core.
|
9
|
+
#
|
10
|
+
class Presenter
|
11
|
+
|
12
|
+
# @return [Set] the set that should be presented.
|
13
|
+
#
|
14
|
+
attr_accessor :set
|
15
|
+
|
16
|
+
# @param [Set] set @see #set.
|
17
|
+
#
|
18
|
+
def initialize(set)
|
19
|
+
@set = set
|
20
|
+
end
|
21
|
+
|
22
|
+
#-----------------------------------------------------------------------#
|
23
|
+
|
24
|
+
# @!group Set Information
|
25
|
+
|
26
|
+
# @return [String] the name of the Pod.
|
27
|
+
#
|
28
|
+
def name
|
29
|
+
@set.name
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Version] the highest version of available for the Pod.
|
33
|
+
#
|
34
|
+
def version
|
35
|
+
@set.versions.first
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [Array<Version>] all the versions available sorted
|
39
|
+
# ascendingly.
|
40
|
+
#
|
41
|
+
def versions
|
42
|
+
@set.versions.sort.reverse
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [String] all the versions available sorted from the highest
|
46
|
+
# to the lowest.
|
47
|
+
#
|
48
|
+
# @example Return example
|
49
|
+
#
|
50
|
+
# "1.5pre, 1.4 [master repo] - 1.4 [test_repo repo]"
|
51
|
+
#
|
52
|
+
# @note This method orders the sources by name.
|
53
|
+
#
|
54
|
+
def verions_by_source
|
55
|
+
result = []
|
56
|
+
versions_by_source = @set.versions_by_source
|
57
|
+
@set.sources.sort.each do |source|
|
58
|
+
versions = versions_by_source[source]
|
59
|
+
result << "#{versions.map(&:to_s) * ', '} [#{source.name} repo]"
|
60
|
+
end
|
61
|
+
result * ' - '
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [Array<String>] The name of the sources that contain the Pod
|
65
|
+
# sorted alphabetically.
|
66
|
+
#
|
67
|
+
def sources
|
68
|
+
@set.sources.map(&:name).sort
|
69
|
+
end
|
70
|
+
|
71
|
+
#-----------------------------------------------------------------------#
|
72
|
+
|
73
|
+
# @!group Specification Information
|
74
|
+
|
75
|
+
# @return [Specification] the specification of the {Set}. If no
|
76
|
+
# versions requirements where passed to the set it returns the
|
77
|
+
# highest available version.
|
78
|
+
#
|
79
|
+
def spec
|
80
|
+
@set.specification
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [String] the list of the authors of the Pod in sentence
|
84
|
+
# format.
|
85
|
+
#
|
86
|
+
# @example Output example
|
87
|
+
#
|
88
|
+
# "Author 1, Author 2 and Author 3"
|
89
|
+
#
|
90
|
+
# @note In ruby 1.8.7 the authors are sorted by name because the
|
91
|
+
# hash doesn't preserve the order in which they are defined
|
92
|
+
# in the podspec.
|
93
|
+
#
|
94
|
+
def authors
|
95
|
+
return '' unless spec.authors
|
96
|
+
if RUBY_VERSION == '1.8.7'
|
97
|
+
spec.authors.keys.sort.to_sentence
|
98
|
+
else
|
99
|
+
spec.authors.keys.to_sentence
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# @return [String] the homepage of the pod.
|
104
|
+
#
|
105
|
+
def homepage
|
106
|
+
spec.homepage
|
107
|
+
end
|
108
|
+
|
109
|
+
# @return [String] a short description, expected to be 140 characters
|
110
|
+
# long of the Pod.
|
111
|
+
#
|
112
|
+
def summary
|
113
|
+
spec.summary
|
114
|
+
end
|
115
|
+
|
116
|
+
# @return [String] the description of the Pod, if no description is
|
117
|
+
# available the summary is returned.
|
118
|
+
#
|
119
|
+
def description
|
120
|
+
spec.description || spec.summary
|
121
|
+
end
|
122
|
+
|
123
|
+
# @return [String] the URL of the source of the Pod.
|
124
|
+
#
|
125
|
+
def source_url
|
126
|
+
url_keys = [:git, :svn, :http, :hg, :local ]
|
127
|
+
key = spec.source.keys.find { |k| url_keys.include?(k) }
|
128
|
+
key ? spec.source[key] : 'No source url'
|
129
|
+
end
|
130
|
+
|
131
|
+
# @return [String] the platforms supported by the Pod.
|
132
|
+
#
|
133
|
+
# @example
|
134
|
+
#
|
135
|
+
# "iOS"
|
136
|
+
# "iOS - OS X"
|
137
|
+
#
|
138
|
+
def platform
|
139
|
+
spec.available_platforms.sort { |a,b| a.to_s.downcase <=> b.to_s.downcase }.join(' - ')
|
140
|
+
end
|
141
|
+
|
142
|
+
# @return [String] the type of the license of the Pod.
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
#
|
146
|
+
# "MIT"
|
147
|
+
#
|
148
|
+
def license
|
149
|
+
spec.license[:type] if spec.license
|
150
|
+
end
|
151
|
+
|
152
|
+
# @return [Array] an array containing all the subspecs of the Pod.
|
153
|
+
#
|
154
|
+
def subspecs
|
155
|
+
(spec.recursive_subspecs.any? && spec.recursive_subspecs) || nil
|
156
|
+
end
|
157
|
+
|
158
|
+
#-----------------------------------------------------------------------#
|
159
|
+
|
160
|
+
# @!group Statistics
|
161
|
+
|
162
|
+
# @return [Time] the creation date of the first known `podspec` of the
|
163
|
+
# Pod.
|
164
|
+
#
|
165
|
+
def creation_date
|
166
|
+
Statistics.instance.creation_date(@set)
|
167
|
+
end
|
168
|
+
|
169
|
+
# @return [Integer] the GitHub likes of the repo of the Pod.
|
170
|
+
#
|
171
|
+
def github_watchers
|
172
|
+
Statistics.instance.github_watchers(@set)
|
173
|
+
end
|
174
|
+
|
175
|
+
# @return [Integer] the GitHub forks of the repo of the Pod.
|
176
|
+
#
|
177
|
+
def github_forks
|
178
|
+
Statistics.instance.github_forks(@set)
|
179
|
+
end
|
180
|
+
|
181
|
+
# @return [String] the relative time of the last push of the repo the Pod.
|
182
|
+
#
|
183
|
+
def github_last_activity
|
184
|
+
distance_from_now_in_words(Statistics.instance.github_pushed_at(@set))
|
185
|
+
end
|
186
|
+
|
187
|
+
#-----------------------------------------------------------------------#
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
# Computes a human readable string that represents a past date in
|
192
|
+
# relative terms.
|
193
|
+
#
|
194
|
+
# @param [Time, String] from_time
|
195
|
+
# the date that should be represented.
|
196
|
+
#
|
197
|
+
# @example Possible outputs
|
198
|
+
#
|
199
|
+
# "less than a week ago"
|
200
|
+
# "15 days ago"
|
201
|
+
# "3 month ago"
|
202
|
+
# "more than a year ago"
|
203
|
+
#
|
204
|
+
# @return [String] a string that represents a past date.
|
205
|
+
#
|
206
|
+
def distance_from_now_in_words(from_time)
|
207
|
+
return nil unless from_time
|
208
|
+
from_time = Time.parse(from_time) unless from_time.is_a?(Time)
|
209
|
+
to_time = Time.now
|
210
|
+
distance_in_days = (((to_time - from_time).abs)/60/60/24).round
|
211
|
+
|
212
|
+
case distance_in_days
|
213
|
+
when 0..7
|
214
|
+
"less than a week ago"
|
215
|
+
when 8..29
|
216
|
+
"#{distance_in_days} days ago"
|
217
|
+
when 30..45
|
218
|
+
"1 month ago"
|
219
|
+
when 46..365
|
220
|
+
"#{(distance_in_days.to_f / 30).round} months ago"
|
221
|
+
else
|
222
|
+
"more than a year ago"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
@@ -0,0 +1,277 @@
|
|
1
|
+
module Pod
|
2
|
+
class Specification
|
3
|
+
class Set
|
4
|
+
|
5
|
+
# The statistics class provides information about one or more {Set} that
|
6
|
+
# is not readily available because expensive to compute or provided by a
|
7
|
+
# remote source.
|
8
|
+
#
|
9
|
+
# The class provides also facilities to work with a collection of sets.
|
10
|
+
# It always caches in memory the computed values and it can take an
|
11
|
+
# optional path to cache file that it is responsible of populating and
|
12
|
+
# invalidating.
|
13
|
+
#
|
14
|
+
# To reuse the in memory cache and to minimize the disk access to the
|
15
|
+
# cache file a shared instance is also available.
|
16
|
+
#
|
17
|
+
class Statistics
|
18
|
+
|
19
|
+
# @return [Statistics] the shared statistics instance.
|
20
|
+
#
|
21
|
+
def self.instance
|
22
|
+
@instance ||= new
|
23
|
+
end
|
24
|
+
|
25
|
+
# Allows to set the shared instance.
|
26
|
+
#
|
27
|
+
# @param [Statistics] instance
|
28
|
+
# the new shared instance or nil.
|
29
|
+
#
|
30
|
+
# @return [Statistics] the shared statistics instance.
|
31
|
+
#
|
32
|
+
def self.instance=(instance)
|
33
|
+
@instance = instance
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Pathname] the path to the optional cache file.
|
37
|
+
#
|
38
|
+
# @note The cache file can be specified after initialization, but
|
39
|
+
# it has to be configured before requiring any value, otherwise
|
40
|
+
# it is ignored.
|
41
|
+
#
|
42
|
+
attr_accessor :cache_file
|
43
|
+
|
44
|
+
# @return [Integer] the number of seconds after which the caches of
|
45
|
+
# values that might changed are discarded.
|
46
|
+
#
|
47
|
+
# @note If not specified on initialization defaults to 3 days.
|
48
|
+
#
|
49
|
+
attr_accessor :cache_expiration
|
50
|
+
|
51
|
+
# @param [Pathname] cache_file @see cache_file
|
52
|
+
#
|
53
|
+
# @param [Integer] cache_expiration @see cache_expiration
|
54
|
+
#
|
55
|
+
def initialize(cache_file = nil, cache_expiration = (60 * 60 * 24 * 3))
|
56
|
+
require 'yaml'
|
57
|
+
# This is to make sure Faraday doesn't warn the user about the
|
58
|
+
# `system_timer` gem missing.
|
59
|
+
old_warn, $-w = $-w, nil
|
60
|
+
begin
|
61
|
+
require 'faraday'
|
62
|
+
ensure
|
63
|
+
$-w = old_warn
|
64
|
+
end
|
65
|
+
require 'octokit'
|
66
|
+
|
67
|
+
@cache_file = cache_file
|
68
|
+
@cache_expiration = cache_expiration
|
69
|
+
end
|
70
|
+
|
71
|
+
#---------------------------------------------------------------------#
|
72
|
+
|
73
|
+
# @!group Accessing the statistics
|
74
|
+
|
75
|
+
# Computes the date in which the first podspec of a set was committed
|
76
|
+
# on its git source.
|
77
|
+
#
|
78
|
+
# @param [Set] set
|
79
|
+
# the set for the Pod whose creation date is needed.
|
80
|
+
#
|
81
|
+
# @note The set should be generated with only the source that is
|
82
|
+
# analyzed. If there are more than one the first one is
|
83
|
+
# processed.
|
84
|
+
#
|
85
|
+
# @note This method needs to traverse the git history of the repo and
|
86
|
+
# thus incurs in a performance hit.
|
87
|
+
#
|
88
|
+
# @return [Time] the date in which a Pod appeared for the first time on
|
89
|
+
# the {Source}.
|
90
|
+
#
|
91
|
+
def creation_date(set)
|
92
|
+
date = compute_creation_date(set)
|
93
|
+
save_cache
|
94
|
+
date
|
95
|
+
end
|
96
|
+
|
97
|
+
# Computes the date in which the first podspec of each given set was
|
98
|
+
# committed on its git source.
|
99
|
+
#
|
100
|
+
# @param [Array<Set>] sets
|
101
|
+
# the list of the sets for the Pods whose creation date is
|
102
|
+
# needed.
|
103
|
+
#
|
104
|
+
# @note @see creation_date
|
105
|
+
#
|
106
|
+
# @note This method is optimized for multiple sets because it saves
|
107
|
+
# the cache file only once.
|
108
|
+
#
|
109
|
+
# @return [Array<Time>] the list of the dates in which the Pods
|
110
|
+
# appeared for the first time on the {Source}.
|
111
|
+
#
|
112
|
+
def creation_dates(sets)
|
113
|
+
dates = {}
|
114
|
+
sets.each { |set| dates[set.name] = compute_creation_date(set) }
|
115
|
+
save_cache
|
116
|
+
dates
|
117
|
+
end
|
118
|
+
|
119
|
+
# Computes the number of likes that a Pod has on Github.
|
120
|
+
#
|
121
|
+
# @param [Set] set
|
122
|
+
# the set of the Pod.
|
123
|
+
#
|
124
|
+
# @return [Integer] the number of likes or nil if the Pod is not hosted
|
125
|
+
# on GitHub.
|
126
|
+
#
|
127
|
+
def github_watchers(set)
|
128
|
+
github_stats_if_needed(set)
|
129
|
+
get_value(set, :gh_watchers)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Computes the number of forks that a Pod has on Github.
|
133
|
+
#
|
134
|
+
# @param [Set] set @see github_watchers
|
135
|
+
#
|
136
|
+
# @return [Integer] the number of forks or nil if the Pod is not hosted
|
137
|
+
# on GitHub.
|
138
|
+
#
|
139
|
+
def github_forks(set)
|
140
|
+
github_stats_if_needed(set)
|
141
|
+
get_value(set, :gh_forks)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Computes the number of likes that a Pod has on Github.
|
145
|
+
#
|
146
|
+
# @param [Set] set @see github_watchers
|
147
|
+
#
|
148
|
+
# @return [Time] the time of the last push or nil if the Pod is not
|
149
|
+
# hosted on GitHub.
|
150
|
+
#
|
151
|
+
def github_pushed_at(set)
|
152
|
+
github_stats_if_needed(set)
|
153
|
+
string_time = get_value(set, :pushed_at)
|
154
|
+
Time.parse(string_time) if string_time
|
155
|
+
end
|
156
|
+
|
157
|
+
#---------------------------------------------------------------------#
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
# @return [Hash{String => Hash}] the in-memory cache, where for each
|
162
|
+
# set is stored a hash with the result of the computations.
|
163
|
+
#
|
164
|
+
def cache
|
165
|
+
unless @cache
|
166
|
+
if cache_file && cache_file.exist?
|
167
|
+
@cache = YAML.load(cache_file.read)
|
168
|
+
else
|
169
|
+
@cache = {}
|
170
|
+
end
|
171
|
+
end
|
172
|
+
@cache
|
173
|
+
end
|
174
|
+
|
175
|
+
# Returns the value for the given key of a set stored in the cache, if
|
176
|
+
# available.
|
177
|
+
#
|
178
|
+
# @param [Set] set
|
179
|
+
# the set for which the value is needed.
|
180
|
+
#
|
181
|
+
# @param [Symbol] key
|
182
|
+
# the key of the value.
|
183
|
+
#
|
184
|
+
# @return [Object] the value or nil.
|
185
|
+
#
|
186
|
+
def get_value(set, key)
|
187
|
+
if cache[set.name] && cache[set.name][key]
|
188
|
+
cache[set.name][key]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Stores the given value of a set for the given key in the cache.
|
193
|
+
#
|
194
|
+
# @param [Set] set
|
195
|
+
# the set for which the value has to be stored.
|
196
|
+
#
|
197
|
+
# @param [Symbol] key
|
198
|
+
# the key of the value.
|
199
|
+
#
|
200
|
+
# @param [Object] value
|
201
|
+
# the value to store.
|
202
|
+
#
|
203
|
+
# @return [Object] the value or nil.
|
204
|
+
#
|
205
|
+
def set_value(set, key, value)
|
206
|
+
cache[set.name] ||= {}
|
207
|
+
cache[set.name][key] = value
|
208
|
+
end
|
209
|
+
|
210
|
+
# Saves the in-memory cache to the path of cache file if specified.
|
211
|
+
#
|
212
|
+
# @return [void]
|
213
|
+
#
|
214
|
+
def save_cache
|
215
|
+
if cache_file
|
216
|
+
yaml = YAML.dump(cache)
|
217
|
+
File.open(cache_file, 'w') { |f| f.write(yaml) }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Analyzes the history of the git repository of the {Source} of the
|
222
|
+
# given {Set} to find when its folder was created.
|
223
|
+
#
|
224
|
+
# @param [Set] set
|
225
|
+
# the set for which the creation date is needed.
|
226
|
+
#
|
227
|
+
# @return [Time] the date in which a Pod was created.
|
228
|
+
#
|
229
|
+
def compute_creation_date(set)
|
230
|
+
date = get_value(set, :creation_date)
|
231
|
+
unless date
|
232
|
+
Dir.chdir(set.sources.first.repo) do
|
233
|
+
git_log = `git log --first-parent --format=%ct #{set.name}`
|
234
|
+
creation_date = git_log.split("\n").last.to_i
|
235
|
+
date = Time.at(creation_date)
|
236
|
+
end
|
237
|
+
set_value(set, :creation_date, date)
|
238
|
+
end
|
239
|
+
date
|
240
|
+
end
|
241
|
+
|
242
|
+
# Retrieved the GitHub information from the API for the given set and
|
243
|
+
# stores it in the in-memory cache.
|
244
|
+
#
|
245
|
+
# @note If there is a valid cache and it was generated withing the
|
246
|
+
# expiration time frame this method does nothing.
|
247
|
+
#
|
248
|
+
# @param [Set] set
|
249
|
+
# the set for which the GitHub information is needed.
|
250
|
+
#
|
251
|
+
# @return [void]
|
252
|
+
#
|
253
|
+
def github_stats_if_needed(set)
|
254
|
+
update_date = get_value(set, :gh_date)
|
255
|
+
return if update_date && update_date > (Time.now - cache_expiration)
|
256
|
+
|
257
|
+
spec = set.specification
|
258
|
+
url = spec.source[:git] || ''
|
259
|
+
repo_id = url[/github.com\/([^\/\.]*\/[^\/\.]*)\.*/, 1]
|
260
|
+
return unless repo_id
|
261
|
+
|
262
|
+
begin
|
263
|
+
repo = Octokit.repo(repo_id)
|
264
|
+
rescue
|
265
|
+
return
|
266
|
+
end
|
267
|
+
|
268
|
+
set_value(set, :gh_watchers, repo['watchers'])
|
269
|
+
set_value(set, :gh_forks, repo['forks'])
|
270
|
+
set_value(set, :pushed_at, repo['pushed_at'])
|
271
|
+
set_value(set, :gh_date, Time.now)
|
272
|
+
save_cache
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'active_support/core_ext/array/conversions'
|
2
|
+
|
3
|
+
require 'cocoapods-core/specification/set/presenter'
|
4
|
+
require 'cocoapods-core/specification/set/statistics'
|
5
|
+
|
6
|
+
|
7
|
+
module Pod
|
8
|
+
class Specification
|
9
|
+
|
10
|
+
# A Specification::Set is responsible of handling all the specifications of
|
11
|
+
# a Pod. This class stores the information of the dependencies that required
|
12
|
+
# a Pod in the resolution process.
|
13
|
+
#
|
14
|
+
# @note The alphabetical order of the sets is used to select a
|
15
|
+
# specification if multiple are available for a given version.
|
16
|
+
#
|
17
|
+
# @note The set class is not and should be not aware of the backing store
|
18
|
+
# of a Source.
|
19
|
+
#
|
20
|
+
class Set
|
21
|
+
|
22
|
+
# @return [String] the name of the Pod.
|
23
|
+
#
|
24
|
+
attr_reader :name
|
25
|
+
|
26
|
+
# @return [Array<Source>] the sources that contain the specifications for
|
27
|
+
# the available versions of a Pod.
|
28
|
+
#
|
29
|
+
attr_reader :sources
|
30
|
+
|
31
|
+
# @param [String] name
|
32
|
+
# the name of the Pod.
|
33
|
+
#
|
34
|
+
# @param [Array<Source>,Source] sources
|
35
|
+
# the sources that contain a Pod.
|
36
|
+
#
|
37
|
+
def initialize(name, sources = [])
|
38
|
+
@name = name
|
39
|
+
sources = sources.is_a?(Array) ? sources : [sources]
|
40
|
+
@sources = sources.sort_by(&:name)
|
41
|
+
@required_by = []
|
42
|
+
@dependencies = []
|
43
|
+
end
|
44
|
+
|
45
|
+
# Stores a dependency on the Pod.
|
46
|
+
#
|
47
|
+
# @param [Dependency] dependency
|
48
|
+
# a dependency that requires the Pod.
|
49
|
+
#
|
50
|
+
# @param [String] dependent_name
|
51
|
+
# the name of the owner of the dependency. It is used only to
|
52
|
+
# display the Pod::Informative.
|
53
|
+
#
|
54
|
+
# @raise If the versions requirement of the dependency are not
|
55
|
+
# compatible with the previously stored dependencies.
|
56
|
+
#
|
57
|
+
# @todo This should simply return a boolean. Is cocoaPods that should raise.
|
58
|
+
#
|
59
|
+
# @return [void]
|
60
|
+
#
|
61
|
+
def required_by(dependency, dependent_name)
|
62
|
+
unless @required_by.empty? || dependency.requirement.satisfied_by?(Version.new(required_version.to_s))
|
63
|
+
raise StandardError, "#{dependent_name} tries to activate `#{dependency}', but already activated version `#{required_version}' by #{@required_by.to_sentence}."
|
64
|
+
end
|
65
|
+
@specification = nil
|
66
|
+
@required_by << dependent_name
|
67
|
+
@dependencies << dependency
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Dependency] a dependency that includes all the versions
|
71
|
+
# requirements of the stored dependencies.
|
72
|
+
#
|
73
|
+
def dependency
|
74
|
+
@dependencies.inject(Dependency.new(name)) do |previous, dependency|
|
75
|
+
previous.merge(dependency.to_root_dependency)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [Specification] the top level specification of the Pod for the
|
80
|
+
# {#required_version}.
|
81
|
+
#
|
82
|
+
# @note If multiple sources have a specification for the
|
83
|
+
# {#required_version} The alphabetical order of their names is
|
84
|
+
# used to disambiguate.
|
85
|
+
#
|
86
|
+
def specification
|
87
|
+
unless @specification
|
88
|
+
sources = []
|
89
|
+
versions_by_source.each{ |source, versions| sources << source if versions.include?(required_version) }
|
90
|
+
source = sources.sort_by(&:name).first
|
91
|
+
@specification = source.specification(name, required_version)
|
92
|
+
end
|
93
|
+
@specification
|
94
|
+
end
|
95
|
+
|
96
|
+
# @return [Version] the highest version that satisfies the stored
|
97
|
+
# dependencies.
|
98
|
+
#
|
99
|
+
# @todo This should simply return nil. CocoaPods should raise instead.
|
100
|
+
#
|
101
|
+
def required_version
|
102
|
+
versions.find { |v| dependency.match?(name, v) } ||
|
103
|
+
(raise StandardError, "Required version (#{dependency}) not found for `#{name}'.\nAvailable versions: #{versions.join(', ')}")
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Array<Version>] all the available versions for the Pod, sorted
|
107
|
+
# from highest to lowest.
|
108
|
+
#
|
109
|
+
def versions
|
110
|
+
versions_by_source.values.flatten.uniq.sort.reverse
|
111
|
+
end
|
112
|
+
|
113
|
+
# @return [Hash{Source => Version}] all the available versions for the
|
114
|
+
# Pod grouped by source.
|
115
|
+
#
|
116
|
+
def versions_by_source
|
117
|
+
result = {}
|
118
|
+
sources.each do |source|
|
119
|
+
result[source] = source.versions(name)
|
120
|
+
end
|
121
|
+
result
|
122
|
+
end
|
123
|
+
|
124
|
+
def ==(other)
|
125
|
+
self.class === other && @name == other.name && @sources.map(&:name) == other.sources.map(&:name)
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_s
|
129
|
+
"#<#{self.class.name} for `#{name}' with required version `#{required_version}' available at `#{sources.map(&:name) * ', '}'>"
|
130
|
+
end
|
131
|
+
alias_method :inspect, :to_s
|
132
|
+
|
133
|
+
#-------------------------------------------------------------------------#
|
134
|
+
|
135
|
+
# The Set::External class handles Pods from external sources. Pods from
|
136
|
+
# external sources don't use the {Source} and are initialized by a given
|
137
|
+
# specification.
|
138
|
+
#
|
139
|
+
# @note External sources *don't* support subspecs.
|
140
|
+
#
|
141
|
+
class External < Set
|
142
|
+
|
143
|
+
attr_reader :specification
|
144
|
+
|
145
|
+
def initialize(spec)
|
146
|
+
@specification = spec.root
|
147
|
+
super(@specification.name)
|
148
|
+
end
|
149
|
+
|
150
|
+
def ==(other)
|
151
|
+
self.class === other && @specification == other.specification
|
152
|
+
end
|
153
|
+
|
154
|
+
def required_by(dependency, dependent_name)
|
155
|
+
before = @specification
|
156
|
+
super(dependency, dependent_name)
|
157
|
+
ensure
|
158
|
+
@specification = before
|
159
|
+
end
|
160
|
+
|
161
|
+
def specification_path
|
162
|
+
raise StandardError, "specification_path"
|
163
|
+
end
|
164
|
+
|
165
|
+
def versions
|
166
|
+
[@specification.version]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|