cocoapods-core 0.30.0 → 1.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +7 -10
  3. data/lib/cocoapods-core/build_type.rb +121 -0
  4. data/lib/cocoapods-core/cdn_source.rb +501 -0
  5. data/lib/cocoapods-core/core_ui.rb +4 -3
  6. data/lib/cocoapods-core/dependency.rb +100 -73
  7. data/lib/cocoapods-core/gem_version.rb +1 -2
  8. data/lib/cocoapods-core/github.rb +32 -5
  9. data/lib/cocoapods-core/http.rb +86 -0
  10. data/lib/cocoapods-core/lockfile.rb +161 -56
  11. data/lib/cocoapods-core/metrics.rb +47 -0
  12. data/lib/cocoapods-core/platform.rb +99 -11
  13. data/lib/cocoapods-core/podfile/dsl.rb +623 -124
  14. data/lib/cocoapods-core/podfile/target_definition.rb +662 -109
  15. data/lib/cocoapods-core/podfile.rb +138 -65
  16. data/lib/cocoapods-core/requirement.rb +37 -8
  17. data/lib/cocoapods-core/source/acceptor.rb +16 -13
  18. data/lib/cocoapods-core/source/aggregate.rb +79 -103
  19. data/lib/cocoapods-core/source/health_reporter.rb +9 -18
  20. data/lib/cocoapods-core/source/manager.rb +488 -0
  21. data/lib/cocoapods-core/source/metadata.rb +79 -0
  22. data/lib/cocoapods-core/source.rb +241 -70
  23. data/lib/cocoapods-core/specification/consumer.rb +187 -47
  24. data/lib/cocoapods-core/specification/dsl/attribute.rb +49 -85
  25. data/lib/cocoapods-core/specification/dsl/attribute_support.rb +6 -8
  26. data/lib/cocoapods-core/specification/dsl/deprecations.rb +9 -126
  27. data/lib/cocoapods-core/specification/dsl/platform_proxy.rb +30 -20
  28. data/lib/cocoapods-core/specification/dsl.rb +943 -296
  29. data/lib/cocoapods-core/specification/json.rb +64 -23
  30. data/lib/cocoapods-core/specification/linter/analyzer.rb +218 -0
  31. data/lib/cocoapods-core/specification/linter/result.rb +128 -0
  32. data/lib/cocoapods-core/specification/linter.rb +310 -309
  33. data/lib/cocoapods-core/specification/root_attribute_accessors.rb +90 -39
  34. data/lib/cocoapods-core/specification/set/presenter.rb +35 -71
  35. data/lib/cocoapods-core/specification/set.rb +42 -96
  36. data/lib/cocoapods-core/specification.rb +368 -130
  37. data/lib/cocoapods-core/standard_error.rb +45 -24
  38. data/lib/cocoapods-core/trunk_source.rb +14 -0
  39. data/lib/cocoapods-core/vendor/requirement.rb +133 -53
  40. data/lib/cocoapods-core/vendor/version.rb +197 -156
  41. data/lib/cocoapods-core/vendor.rb +1 -5
  42. data/lib/cocoapods-core/version.rb +137 -42
  43. data/lib/cocoapods-core/yaml_helper.rb +334 -0
  44. data/lib/cocoapods-core.rb +10 -4
  45. metadata +100 -27
  46. data/lib/cocoapods-core/source/abstract_data_provider.rb +0 -71
  47. data/lib/cocoapods-core/source/file_system_data_provider.rb +0 -150
  48. data/lib/cocoapods-core/source/github_data_provider.rb +0 -143
  49. data/lib/cocoapods-core/specification/set/statistics.rb +0 -266
  50. data/lib/cocoapods-core/yaml_converter.rb +0 -192
@@ -1,5 +1,4 @@
1
1
  module Pod
2
-
3
2
  # The Dependency allows to specify dependencies of a {Podfile} or a
4
3
  # {Specification} on a Pod. It stores the name of the dependency, version
5
4
  # requirements and external sources information.
@@ -10,7 +9,6 @@ module Pod
10
9
  # [MIT license](https://github.com/rubygems/rubygems/blob/master/MIT.txt).
11
10
  #
12
11
  class Dependency
13
-
14
12
  # @return [String] The name of the Pod described by this dependency.
15
13
  #
16
14
  attr_accessor :name
@@ -21,12 +19,10 @@ module Pod
21
19
  #
22
20
  attr_accessor :external_source
23
21
 
24
- # @return [Bool] whether the dependency should use the podspec with the
25
- # highest know version but force the downloader to checkout the
26
- # `head` of the source repository.
27
- #
28
- attr_accessor :head
29
- alias_method :head?, :head
22
+ # @return [String] The source URL of the podspec repo to use to resolve
23
+ # this dependency. If not set then the standard source list
24
+ # should be used to resolve the dependency.
25
+ attr_accessor :podspec_repo
30
26
 
31
27
  # @overload initialize(name, requirements)
32
28
  #
@@ -54,36 +50,48 @@ module Pod
54
50
  # @example Initialization with an external source.
55
51
  #
56
52
  # Dependency.new('libPusher', {:git => 'example.com/repo.git'})
57
- # Dependency.new('libPusher', {:path => 'path/to/folder'})
53
+ # Dependency.new('libPusher', {:path => 'path/to/folder'})
58
54
  # Dependency.new('libPusher', {:podspec => 'example.com/libPusher.podspec'})
59
55
  #
60
- # @overload initialize(name, is_head)
56
+ # @overload initialize(name, requirements, podspec_repo)
61
57
  #
62
58
  # @param [String] name
63
59
  # the name of the Pod.
64
60
  #
65
- # @param [Symbol] is_head
66
- # a symbol that can be `:head` or nil.
61
+ # @param [Array, Version, String, Requirement] requirements
62
+ # an array specifying the version requirements of the
63
+ # dependency.
64
+ #
65
+ # @param [Hash] podspec_repo
66
+ # The URL of the specific podspec repo to resolve this dependency from.
67
67
  #
68
- # @example Initialization with the head option
68
+ # @example Initialization with a specific podspec repo
69
69
  #
70
- # Dependency.new('RestKit', :head)
70
+ # Dependency.new('Artsy+UILabels', '~> 1.0', :source => 'https://github.com/Artsy/Specs.git')
71
71
  #
72
72
  def initialize(name = nil, *requirements)
73
73
  if requirements.last.is_a?(Hash)
74
- @external_source = requirements.pop
75
- unless requirements.empty?
76
- raise Informative, "A dependency with an external source may not " \
77
- "specify version requirements (#{name})."
74
+ additional_params = requirements.pop.select { |_, v| !v.nil? }
75
+ additional_params = nil if additional_params.empty?
76
+
77
+ if additional_params && @podspec_repo = additional_params[:source]
78
+ # This dependency specifies the exact source podspec repo to use.
79
+ additional_params.delete(:source)
80
+ unless additional_params.empty?
81
+ raise Informative, 'A dependency with a specified podspec repo may ' \
82
+ "not include other source parameters (#{name})."
83
+ end
84
+ elsif @external_source = additional_params
85
+ unless requirements.empty?
86
+ raise Informative, 'A dependency with an external source may not ' \
87
+ "specify version requirements (#{name})."
88
+ end
78
89
  end
79
90
 
80
91
  elsif requirements.last == :head
81
- @head = true
82
- requirements.pop
83
- unless requirements.empty?
84
- raise Informative, "A `:head` dependency may not specify version " \
85
- "requirements (#{name})."
86
- end
92
+ raise Informative, '`:head` dependencies have been removed. Please use ' \
93
+ "normal external source dependencies (`:git => 'GIT_REPO_URL'`) " \
94
+ "instead of `:head` for `#{name}`."
87
95
  end
88
96
 
89
97
  if requirements.length == 1 && requirements.first.is_a?(Requirement)
@@ -91,44 +99,47 @@ module Pod
91
99
  end
92
100
  @name = name
93
101
  @requirement = Requirement.create(requirements)
102
+ @specific_requirement ||= nil
103
+ @external_source ||= nil
94
104
  end
95
105
 
96
106
  # @return [Version] whether the dependency points to a specific version.
97
107
  #
98
- attr_accessor :specific_version
108
+ attr_reader :specific_version
99
109
 
100
110
  # @return [Requirement] the requirement of this dependency (a set of
101
111
  # one or more version restrictions).
102
112
  #
103
- # @todo The specific version is stripped from head information because
104
- # because its string representation would not parse. It would
105
- # be better to add something like Version#display_string.
106
- #
107
113
  def requirement
108
- if specific_version
109
- Requirement.new(Version.new(specific_version.version))
110
- else
111
- @requirement
112
- end
114
+ @specific_requirement || @requirement
115
+ end
116
+
117
+ # @param [Version] version the specific version to point to
118
+ #
119
+ def specific_version=(version)
120
+ @specific_version = version
121
+ @specific_requirement = if version
122
+ Requirement.new(Version.new(version.version))
123
+ end
113
124
  end
114
125
 
115
- # @return [Bool] whether the dependency points to a subspec.
126
+ # @return [Boolean] whether the dependency points to a subspec.
116
127
  #
117
128
  def subspec_dependency?
118
129
  @name.include?('/')
119
130
  end
120
131
 
121
- # @return [Bool] whether the dependency points to an external source.
132
+ # @return [Boolean] whether the dependency points to an external source.
122
133
  #
123
134
  def external?
124
135
  !@external_source.nil?
125
136
  end
126
137
 
127
- # @return [Bool] whether the dependency points to a local path.
138
+ # @return [Boolean] whether the dependency points to a local path.
128
139
  #
129
140
  def local?
130
141
  if external_source
131
- !(external_source[:path] || external_source[:local]).nil?
142
+ external_source[:path]
132
143
  end
133
144
  end
134
145
 
@@ -174,28 +185,27 @@ module Pod
174
185
  # @note This is used by the Lockfile to check if a stored dependency is
175
186
  # still compatible with the Podfile.
176
187
  #
177
- # @return [Bool] whether the dependency is compatible with the given one.
188
+ # @return [Boolean] whether the dependency is compatible with the given one.
178
189
  #
179
190
  def compatible?(other)
180
191
  return false unless name == other.name
181
- return false unless head? == other.head?
182
192
  return false unless external_source == other.external_source
183
193
 
184
- other.requirement.requirements.all? do | operator, version |
194
+ other.requirement.requirements.all? do |_operator, version|
185
195
  requirement.satisfied_by? Version.new(version)
186
196
  end
187
197
  end
188
198
 
189
- # @return [Bool] whether the dependency is equal to another taking into
199
+ # @return [Boolean] whether the dependency is equal to another taking into
190
200
  # account the loaded specification, the head options and the
191
201
  # external source.
192
202
  #
193
203
  def ==(other)
194
204
  self.class == other.class &&
195
205
  name == other.name &&
196
- requirement == other.requirement &&
197
- head? == other.head? &&
198
- external_source == other.external_source
206
+ external_source == other.external_source &&
207
+ podspec_repo == other.podspec_repo &&
208
+ requirement == other.requirement
199
209
  end
200
210
  alias_method :eql?, :==
201
211
 
@@ -218,35 +228,60 @@ module Pod
218
228
  # @param [Dependency] other
219
229
  # the other dependency to merge with.
220
230
  #
221
- # @note If one of the decencies specifies an external source or is head,
231
+ # @note If one of the dependencies specifies an external source or is head,
222
232
  # the resulting dependency preserves this attributes.
223
233
  #
224
- # @return [Dependency] a dependency (not necessary a new instance) that
225
- # includes also the version requirements of the given one.
234
+ # @return [Dependency] a dependency (not necessarily a new instance) that
235
+ # also includes the version requirements of the given one.
226
236
  #
227
237
  def merge(other)
228
238
  unless name == other.name
229
239
  raise ArgumentError, "#{self} and #{other} have different names"
230
240
  end
241
+
231
242
  default = Requirement.default
232
243
  self_req = requirement
233
244
  other_req = other.requirement
234
245
 
235
- if other_req == default
236
- dep = self.class.new(name, self_req)
237
- elsif self_req == default
238
- dep = self.class.new(name, other_req)
239
- else
240
- dep = self.class.new(name, self_req.as_list.concat(other_req.as_list))
241
- end
246
+ req = if other_req == default
247
+ self_req
248
+ elsif self_req == default
249
+ other_req
250
+ else
251
+ self_req.as_list.concat(other_req.as_list)
252
+ end
253
+
254
+ opts = {}
242
255
 
243
- dep.head = head? || other.head?
244
256
  if external_source || other.external_source
245
- self_external_source = external_source || {}
246
- other_external_source = other.external_source || {}
247
- dep.external_source = self_external_source.merge(other_external_source)
257
+ opts.
258
+ merge!(external_source || {}).
259
+ merge!(other.external_source || {})
260
+
261
+ req_to_set = req
262
+ req = []
263
+ end
264
+
265
+ if podspec_repo && other.podspec_repo && podspec_repo != other.podspec_repo
266
+ raise ArgumentError, "#{self} and #{other} have different podspec repos"
267
+ end
268
+
269
+ if repo = podspec_repo || other.podspec_repo
270
+ opts[:source] = repo
271
+ end
272
+
273
+ self.class.new(name, *req, opts).tap do |dep|
274
+ dep.instance_variable_set(:@requirement, Requirement.create(req_to_set)) if req_to_set
248
275
  end
249
- dep
276
+ end
277
+
278
+ # Whether the dependency has any pre-release requirements
279
+ #
280
+ # @return [Boolean] Whether the dependency has any pre-release requirements
281
+ #
282
+ def prerelease?
283
+ return @prerelease if defined?(@prerelease)
284
+ @prerelease = requirement.requirements.any? { |_op, version| version.prerelease? }
250
285
  end
251
286
 
252
287
  # Checks whether the dependency would be satisfied by the specification
@@ -258,7 +293,7 @@ module Pod
258
293
  # @param [String, Version] version
259
294
  # The proposed version.
260
295
  #
261
- # @return [Bool] Whether the dependency is satisfied.
296
+ # @return [Boolean] Whether the dependency is satisfied.
262
297
  #
263
298
  def match?(name, version)
264
299
  return false unless self.name == name
@@ -282,7 +317,6 @@ module Pod
282
317
  # "libPusher (= 1.0)"
283
318
  # "libPusher (~> 1.0.1)"
284
319
  # "libPusher (> 1.0, < 2.0)"
285
- # "libPusher (HEAD)"
286
320
  # "libPusher (from `www.example.com')"
287
321
  # "libPusher (defined in Podfile)"
288
322
  # "RestKit/JSON"
@@ -293,8 +327,6 @@ module Pod
293
327
  version = ''
294
328
  if external?
295
329
  version << external_source_description(external_source)
296
- elsif head?
297
- version << 'HEAD'
298
330
  elsif requirement != Requirement.default
299
331
  version << requirement.to_s
300
332
  end
@@ -317,17 +349,15 @@ module Pod
317
349
  # @return [Dependency] the dependency described by the string.
318
350
  #
319
351
  def self.from_string(string)
320
- match_data = string.match(/(\S*)( (.*))?/)
352
+ match_data = string.match(/((?:\s?[^\s(])+)( (?:.*))?/)
321
353
  name = match_data[1]
322
354
  version = match_data[2]
323
355
  version = version.gsub(/[()]/, '') if version
324
356
  case version
325
- when nil || /from `(.*)(`|')/
357
+ when nil, /from `(.*)(`|')/
326
358
  Dependency.new(name)
327
- when /HEAD/
328
- Dependency.new(name, :head)
329
359
  else
330
- version_requirements = version.split(',') if version
360
+ version_requirements = version.split(',') if version
331
361
  Dependency.new(name, version_requirements)
332
362
  end
333
363
  end
@@ -336,7 +366,7 @@ module Pod
336
366
  #
337
367
  def inspect
338
368
  "<#{self.class} name=#{name} requirements=#{requirement} " \
339
- "external_source=#{external_source || 'nil'}>"
369
+ "source=#{podspec_repo || 'nil'} external_source=#{external_source || 'nil'}>"
340
370
  end
341
371
 
342
372
  #--------------------------------------#
@@ -369,13 +399,10 @@ module Pod
369
399
  desc = "`#{source[:podspec]}`"
370
400
  elsif source.key?(:path)
371
401
  desc = "`#{source[:path]}`"
372
- elsif source.key?(:local)
373
- desc = "`#{source[:local]}`"
374
402
  else
375
403
  desc = "`#{source}`"
376
404
  end
377
405
  "from #{desc}"
378
406
  end
379
407
  end
380
-
381
408
  end
@@ -1,6 +1,5 @@
1
1
  module Pod
2
-
3
2
  # The version of the cocoapods-core.
4
3
  #
5
- CORE_VERSION = '0.30.0' unless defined? Pod::CORE_VERSION
4
+ CORE_VERSION = '1.15.2'.freeze unless defined? Pod::CORE_VERSION
6
5
  end
@@ -1,11 +1,9 @@
1
1
  module Pod
2
-
3
2
  # Allows to access information about the GitHub repos.
4
3
  #
5
4
  # This class is stored in Core because it might be used by web services.
6
5
  #
7
6
  module GitHub
8
-
9
7
  # Returns the information of a user.
10
8
  #
11
9
  # @param [String] login
@@ -78,6 +76,36 @@ module Pod
78
76
  end
79
77
  end
80
78
 
79
+ # Returns whether the repository has been updated since a given commit.
80
+ # If the request fails, the response will be true as the API is still in
81
+ # beta and likely to change.
82
+ #
83
+ # @param [String] url @see #repo
84
+ #
85
+ # @param [String] commit
86
+ # The current HEAD commit.
87
+ #
88
+ # @return [Boolean] Whether the repository has been updated since the commit.
89
+ #
90
+ def self.modified_since_commit(url, commit)
91
+ return true unless repo_id = normalized_repo_id(url)
92
+ require 'rest'
93
+ request_url = "https://api.github.com/repos/#{repo_id}/commits/master"
94
+ headers = {
95
+ 'User-Agent' => 'CocoaPods',
96
+ 'Accept' => 'application/vnd.github.v3.sha',
97
+ 'If-None-Match' => %("#{commit}"),
98
+ }
99
+
100
+ begin
101
+ response = REST.get(request_url, headers)
102
+ code = response.status_code
103
+ code != 304
104
+ rescue
105
+ raise Informative, "Failed to connect to GitHub to update the #{repo_id} specs repo - Please check if you are offline, or that GitHub is down"
106
+ end
107
+ end
108
+
81
109
  private
82
110
 
83
111
  # @!group Private helpers
@@ -103,7 +131,7 @@ module Pod
103
131
  # @return [Nil] if the given url is not a valid github repo url.
104
132
  #
105
133
  def self.repo_id_from_url(url)
106
- url[%r{github.com/([^/\.]*/[^/\.]*)\.*}, 1]
134
+ url[%r{github.com[/:]([^/]*/(?:(?!\.git)[^/])*)\.*}, 1]
107
135
  end
108
136
 
109
137
  # Performs a get request with the given URL.
@@ -116,7 +144,7 @@ module Pod
116
144
  def self.peform_request(url)
117
145
  require 'rest'
118
146
  require 'json'
119
- headers = { "User-Agent" => "CocoaPods" }
147
+ headers = { 'User-Agent' => 'CocoaPods' }
120
148
  response = REST.get(url, headers)
121
149
  body = JSON.parse(response.body)
122
150
  if response.ok?
@@ -129,6 +157,5 @@ module Pod
129
157
  end
130
158
 
131
159
  #-------------------------------------------------------------------------#
132
-
133
160
  end
134
161
  end
@@ -0,0 +1,86 @@
1
+ require 'uri'
2
+
3
+ module Pod
4
+ # Handles HTTP requests
5
+ #
6
+ module HTTP
7
+ # Resolve potential redirects and return the final URL.
8
+ #
9
+ # @return [string]
10
+ #
11
+ def self.get_actual_url(url, user_agent = nil)
12
+ redirects = 0
13
+
14
+ loop do
15
+ response = perform_head_request(url, user_agent)
16
+
17
+ if [301, 302, 303, 307, 308].include? response.status_code
18
+ location = response.headers['location'].first
19
+
20
+ if location =~ %r{://}
21
+ url = location
22
+ else
23
+ url = URI.join(url, location).to_s
24
+ end
25
+
26
+ redirects += 1
27
+ else
28
+ break
29
+ end
30
+
31
+ break unless redirects < MAX_HTTP_REDIRECTS
32
+ end
33
+
34
+ url
35
+ end
36
+
37
+ # Performs validation of a URL
38
+ #
39
+ # @return [REST::response]
40
+ #
41
+ def self.validate_url(url, user_agent = nil)
42
+ return nil unless url =~ /^#{URI.regexp}$/
43
+
44
+ begin
45
+ url = get_actual_url(url, user_agent)
46
+ resp = perform_head_request(url, user_agent)
47
+ rescue SocketError, URI::InvalidURIError, REST::Error, REST::Error::Connection
48
+ resp = nil
49
+ end
50
+
51
+ resp
52
+ end
53
+
54
+ #-------------------------------------------------------------------------#
55
+
56
+ private
57
+
58
+ # Does a HEAD request and in case of any errors a GET request
59
+ #
60
+ # @return [REST::response]
61
+ #
62
+ def self.perform_head_request(url, user_agent)
63
+ require 'rest'
64
+
65
+ user_agent ||= USER_AGENT
66
+
67
+ resp = ::REST.head(url, 'User-Agent' => user_agent)
68
+
69
+ if resp.status_code >= 400
70
+ resp = ::REST.get(url, 'User-Agent' => user_agent,
71
+ 'Range' => 'bytes=0-0')
72
+
73
+ if resp.status_code >= 400
74
+ resp = ::REST.get(url, 'User-Agent' => user_agent)
75
+ end
76
+ end
77
+
78
+ resp
79
+ end
80
+
81
+ MAX_HTTP_REDIRECTS = 3
82
+ USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/538.43.40 (KHTML, like Gecko) Version/8.0 Safari/538.43.40'
83
+
84
+ #-------------------------------------------------------------------------#
85
+ end
86
+ end