cocoapods-core 0.17.0.rc1
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 +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
|