cocoapods-core 0.31.1 → 0.32.0

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cocoapods-core/core_ui.rb +0 -3
  3. data/lib/cocoapods-core/dependency.rb +2 -5
  4. data/lib/cocoapods-core/gem_version.rb +1 -2
  5. data/lib/cocoapods-core/github.rb +2 -5
  6. data/lib/cocoapods-core/lockfile.rb +9 -12
  7. data/lib/cocoapods-core/platform.rb +15 -6
  8. data/lib/cocoapods-core/podfile/dsl.rb +3 -5
  9. data/lib/cocoapods-core/podfile/target_definition.rb +2 -5
  10. data/lib/cocoapods-core/podfile.rb +6 -12
  11. data/lib/cocoapods-core/requirement.rb +3 -7
  12. data/lib/cocoapods-core/source/abstract_data_provider.rb +6 -9
  13. data/lib/cocoapods-core/source/acceptor.rb +36 -10
  14. data/lib/cocoapods-core/source/aggregate.rb +2 -5
  15. data/lib/cocoapods-core/source/file_system_data_provider.rb +7 -10
  16. data/lib/cocoapods-core/source/github_data_provider.rb +13 -12
  17. data/lib/cocoapods-core/source/health_reporter.rb +1 -5
  18. data/lib/cocoapods-core/source.rb +0 -3
  19. data/lib/cocoapods-core/specification/consumer.rb +3 -37
  20. data/lib/cocoapods-core/specification/dsl/attribute.rb +15 -8
  21. data/lib/cocoapods-core/specification/dsl/attribute_support.rb +0 -2
  22. data/lib/cocoapods-core/specification/dsl/deprecations.rb +8 -7
  23. data/lib/cocoapods-core/specification/dsl/platform_proxy.rb +4 -6
  24. data/lib/cocoapods-core/specification/dsl.rb +146 -144
  25. data/lib/cocoapods-core/specification/json.rb +1 -3
  26. data/lib/cocoapods-core/specification/linter/analyzer.rb +93 -0
  27. data/lib/cocoapods-core/specification/linter/result.rb +113 -0
  28. data/lib/cocoapods-core/specification/linter.rb +66 -278
  29. data/lib/cocoapods-core/specification/root_attribute_accessors.rb +26 -16
  30. data/lib/cocoapods-core/specification/set/presenter.rb +4 -7
  31. data/lib/cocoapods-core/specification/set/statistics.rb +1 -4
  32. data/lib/cocoapods-core/specification/set.rb +1 -4
  33. data/lib/cocoapods-core/specification.rb +10 -10
  34. data/lib/cocoapods-core/standard_error.rb +3 -5
  35. data/lib/cocoapods-core/vendor.rb +0 -4
  36. data/lib/cocoapods-core/version.rb +1 -4
  37. data/lib/cocoapods-core/{yaml_converter.rb → yaml_helper.rb} +22 -6
  38. data/lib/cocoapods-core.rb +1 -3
  39. metadata +5 -3
@@ -0,0 +1,113 @@
1
+ module Pod
2
+ class Specification
3
+ class Linter
4
+ class Result
5
+ # @return [Symbol] the type of result.
6
+ #
7
+ attr_reader :type
8
+
9
+ # @return [String] the message associated with result.
10
+ #
11
+ attr_reader :message
12
+
13
+ # @param [Symbol] type @see type
14
+ # @param [String] message @see message
15
+ #
16
+ def initialize(type, message)
17
+ @type = type
18
+ @message = message
19
+ @platforms = []
20
+ end
21
+
22
+ # @return [Array<Platform>] the platforms where this result was
23
+ # generated.
24
+ #
25
+ attr_reader :platforms
26
+
27
+ # @return [String] a string representation suitable for UI output.
28
+ #
29
+ def to_s
30
+ r = "[#{type.to_s.upcase}] #{message}"
31
+ if platforms != Specification::PLATFORMS
32
+ platforms_names = platforms.uniq.map do |p|
33
+ Platform.string_name(p)
34
+ end
35
+ r << " [#{platforms_names * ' - '}]" unless platforms.empty?
36
+ end
37
+ r
38
+ end
39
+ end
40
+
41
+ module ResultHelpers
42
+ public
43
+
44
+ # @return [Array<Result>] all of the generated results.
45
+ #
46
+ attr_reader :results
47
+
48
+ private
49
+
50
+ # Adds an error result with the given message.
51
+ #
52
+ # @param [String] message
53
+ # The message of the result.
54
+ #
55
+ # @return [void]
56
+ #
57
+ def error(message)
58
+ add_result(:error, message)
59
+ end
60
+
61
+ # Adds an warning result with the given message.
62
+ #
63
+ # @param [String] message
64
+ # The message of the result.
65
+ #
66
+ # @return [void]
67
+ #
68
+ def warning(message)
69
+ add_result(:warning, message)
70
+ end
71
+
72
+ # Merges results passed in with the current results
73
+ #
74
+ # @param [Array<Result>] results
75
+ # The results to be merged.
76
+ #
77
+ # @return [void]
78
+ #
79
+ def add_results(results)
80
+ results.each do |result|
81
+ if result.type == :warning
82
+ warning(result.message)
83
+ else
84
+ error(result.message)
85
+ end
86
+ end
87
+ end
88
+
89
+ # Adds a result of the given type with the given message. If there is a
90
+ # current platform it is added to the result. If a result with the same
91
+ # type and the same message is already available the current platform is
92
+ # added to the existing result.
93
+ #
94
+ # @param [Symbol] type
95
+ # The type of the result (`:error`, `:warning`).
96
+ #
97
+ # @param [String] message
98
+ # The message of the result.
99
+ #
100
+ # @return [void]
101
+ #
102
+ def add_result(type, message)
103
+ result = results.find { |r| r.type == type && r.message == message }
104
+ unless result
105
+ result = Result.new(type, message)
106
+ results << result
107
+ end
108
+ result.platforms << consumer.platform_name if consumer
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -1,12 +1,15 @@
1
+ require 'cocoapods-core/specification/linter/result'
2
+ require 'cocoapods-core/specification/linter/analyzer'
3
+
1
4
  module Pod
2
5
  class Specification
3
-
4
6
  # The Linter check specifications for errors and warnings.
5
7
  #
6
8
  # It is designed not only to guarantee the formal functionality of a
7
9
  # specification, but also to support the maintenance of sources.
8
10
  #
9
11
  class Linter
12
+ include ResultHelpers
10
13
 
11
14
  # @return [Specification] the specification to lint.
12
15
  #
@@ -43,7 +46,6 @@ module Pod
43
46
  def lint
44
47
  @results = []
45
48
  if spec
46
- perform_textual_analysis
47
49
  check_required_root_attributes
48
50
  run_root_validation_hooks
49
51
  perform_all_specs_analysis
@@ -60,10 +62,6 @@ module Pod
60
62
 
61
63
  public
62
64
 
63
- # @return [Array<Result>] all the results generated by the Linter.
64
- #
65
- attr_reader :results
66
-
67
65
  # @return [Array<Result>] all the errors generated by the Linter.
68
66
  #
69
67
  def errors
@@ -82,33 +80,6 @@ module Pod
82
80
 
83
81
  # !@group Lint steps
84
82
 
85
- # It reads a podspec file and checks for strings corresponding
86
- # to features that are or will be deprecated
87
- #
88
- # @return [void]
89
- #
90
- def perform_textual_analysis
91
- return unless @file
92
- text = @file.read
93
- if text =~ /config\..?os.?/
94
- error "`config.ios?` and `config.osx?` are deprecated."
95
- end
96
- if text =~ /clean_paths/
97
- error "clean_paths are deprecated (use preserve_paths)."
98
- end
99
-
100
- all_lines_count = text.lines.count
101
- comments_lines_count = text.scan(/^\s*#\s+/).length
102
- comments_ratio = comments_lines_count.fdiv(all_lines_count)
103
- if comments_lines_count > 20 && comments_ratio > 0.2
104
- warning "Comments must be deleted."
105
- end
106
- if text.lines.first =~ /^\s*#\s+/
107
- warning "Comments placed at the top of the specification must be " \
108
- "deleted."
109
- end
110
- end
111
-
112
83
  # Checks that every root only attribute which is required has a value.
113
84
  #
114
85
  # @return [void]
@@ -134,13 +105,7 @@ module Pod
134
105
  #
135
106
  def run_root_validation_hooks
136
107
  attributes = DSL.attributes.values.select(&:root_only?)
137
- attributes.each do |attr|
138
- validation_hook = "_validate_#{attr.name}"
139
- next unless respond_to?(validation_hook, true)
140
- value = spec.send(attr.name)
141
- next unless value
142
- send(validation_hook, value)
143
- end
108
+ run_validation_hooks(attributes, spec)
144
109
  end
145
110
 
146
111
  # Run validations for multi-platform attributes activating .
@@ -153,10 +118,9 @@ module Pod
153
118
  current_spec.available_platforms.each do |platform|
154
119
  @consumer = Specification::Consumer.new(current_spec, platform)
155
120
  run_all_specs_validation_hooks
156
- validate_file_patterns
157
- check_tmp_arc_not_nil
158
- check_if_spec_is_empty
159
- check_install_hooks
121
+ analyzer = Analyzer.new(@consumer)
122
+ analyzer.analyze
123
+ add_results(analyzer.results)
160
124
  @consumer = nil
161
125
  end
162
126
  end
@@ -172,13 +136,7 @@ module Pod
172
136
  #
173
137
  def run_all_specs_validation_hooks
174
138
  attributes = DSL.attributes.values.reject(&:root_only?)
175
- attributes.each do |attr|
176
- validation_hook = "_validate_#{attr.name}"
177
- next unless respond_to?(validation_hook, true)
178
- value = consumer.send(attr.name)
179
- next unless value
180
- send(validation_hook, value)
181
- end
139
+ run_validation_hooks(attributes, consumer)
182
140
  end
183
141
 
184
142
  # Runs the validation hook for each attribute.
@@ -189,9 +147,15 @@ module Pod
189
147
  #
190
148
  # @return [void]
191
149
  #
192
- # def run_validation_hooks(attributes)
193
- #
194
- # end
150
+ def run_validation_hooks(attributes, target)
151
+ attributes.each do |attr|
152
+ validation_hook = "_validate_#{attr.name}"
153
+ next unless respond_to?(validation_hook, true)
154
+ value = target.send(attr.name)
155
+ next unless value
156
+ send(validation_hook, value)
157
+ end
158
+ end
195
159
 
196
160
  #-----------------------------------------------------------------------#
197
161
 
@@ -209,20 +173,24 @@ module Pod
209
173
  ]
210
174
  names_match = acceptable_names.include?(file.basename.to_s)
211
175
  unless names_match
212
- error "The name of the spec should match the name of the file."
176
+ error 'The name of the spec should match the name of the file.'
213
177
  end
214
178
 
215
179
  if spec.root.name =~ /\s/
216
- error "The name of a spec should not contain whitespace."
180
+ error 'The name of a spec should not contain whitespace.'
181
+ end
182
+
183
+ if spec.root.name[0, 1] == '.'
184
+ error 'The name of a spec should not begin with a period.'
217
185
  end
218
186
  end
219
187
  end
220
188
 
221
189
  def _validate_version(v)
222
190
  if v.to_s.empty?
223
- error "A version is required."
191
+ error 'A version is required.'
224
192
  elsif v <= Version::ZERO
225
- error "The version of the spec should be higher than 0."
193
+ error 'The version of the spec should be higher than 0.'
226
194
  end
227
195
  end
228
196
 
@@ -234,7 +202,7 @@ module Pod
234
202
  "(max 140 characters)."
235
203
  end
236
204
  if s =~ /A short description of/
237
- warning "The summary is not meaningful."
205
+ warning 'The summary is not meaningful.'
238
206
  end
239
207
  end
240
208
 
@@ -242,13 +210,13 @@ module Pod
242
210
  #
243
211
  def _validate_description(d)
244
212
  if d =~ /An optional longer description of/
245
- warning "The description is not meaningful."
213
+ warning 'The description is not meaningful.'
246
214
  end
247
215
  if d == spec.summary
248
- warning "The description is equal to the summary."
216
+ warning 'The description is equal to the summary.'
249
217
  end
250
218
  if d.length < spec.summary.length
251
- warning "The description is shorter than the summary."
219
+ warning 'The description is shorter than the summary.'
252
220
  end
253
221
  end
254
222
 
@@ -256,7 +224,7 @@ module Pod
256
224
  #
257
225
  def _validate_homepage(h)
258
226
  if h =~ %r{http://EXAMPLE}
259
- warning "The homepage has not been updated from default"
227
+ warning 'The homepage has not been updated from default'
260
228
  end
261
229
  end
262
230
 
@@ -264,7 +232,7 @@ module Pod
264
232
  #
265
233
  def _validate_frameworks(frameworks)
266
234
  if frameworks_invalid?(frameworks)
267
- error "A framework should only be specified by its name"
235
+ error 'A framework should only be specified by its name'
268
236
  end
269
237
  end
270
238
 
@@ -272,15 +240,26 @@ module Pod
272
240
  #
273
241
  def _validate_weak_frameworks(frameworks)
274
242
  if frameworks_invalid?(frameworks)
275
- error "A weak framework should only be specified by its name"
243
+ error 'A weak framework should only be specified by its name'
276
244
  end
277
245
  end
278
246
 
279
247
  # Performs validations related to the `libraries` attribute.
280
248
  #
281
249
  def _validate_libraries(libs)
282
- if libraries_invalid?(libs)
283
- error "A library should only be specified by its name"
250
+ libs.each do |lib|
251
+ lib = lib.downcase
252
+ if lib.end_with?('.a') || lib.end_with?('.dylib')
253
+ error "Libraries should not include the extension (`#{lib}`)"
254
+ end
255
+
256
+ if lib.start_with?('lib')
257
+ error "Libraries should omit the `lib` prefix (`#{lib}`)"
258
+ end
259
+
260
+ if lib.include?(',')
261
+ error "Libraries should not include comas (`#{lib}`)"
262
+ end
284
263
  end
285
264
  end
286
265
 
@@ -289,13 +268,13 @@ module Pod
289
268
  def _validate_license(l)
290
269
  type = l[:type]
291
270
  if type.nil?
292
- warning "Missing license type."
271
+ warning 'Missing license type.'
293
272
  end
294
273
  if type && type.gsub(' ', '').gsub("\n", '').empty?
295
- warning "Invalid license type."
274
+ warning 'Invalid license type.'
296
275
  end
297
276
  if type && type =~ /\(example\)/
298
- error "Sample license type."
277
+ error 'Sample license type.'
299
278
  end
300
279
  end
301
280
 
@@ -307,7 +286,7 @@ module Pod
307
286
  version = spec.version.to_s
308
287
 
309
288
  if git =~ %r{http://EXAMPLE}
310
- error "The Git source still contains the example URL."
289
+ error 'The Git source still contains the example URL.'
311
290
  end
312
291
  if commit && commit.downcase =~ /head/
313
292
  error 'The commit of a Git source cannot be `HEAD`.'
@@ -337,15 +316,23 @@ module Pod
337
316
  git_uri = URI.parse(git)
338
317
  if git_uri.host == 'github.com' || git_uri.host == 'gist.github.com'
339
318
  unless git.end_with?('.git')
340
- warning "Github repositories should end in `.git`."
319
+ warning 'Github repositories should end in `.git`.'
341
320
  end
342
321
  unless git_uri.scheme == 'https'
343
- warning "Github repositories should use `https` link."
322
+ warning 'Github repositories should use `https` link.'
344
323
  end
345
324
  end
346
325
  end
347
326
  end
348
327
 
328
+ # Performs validations related to the `social_media_url` attribute.
329
+ #
330
+ def _validate_social_media_url(s)
331
+ if s =~ %r{https://twitter.com/EXAMPLE}
332
+ warning 'The social media URL has not been updated from default'
333
+ end
334
+ end
335
+
349
336
  #-----------------------------------------------------------------------#
350
337
 
351
338
  # @!group All specs validation helpers
@@ -360,219 +347,20 @@ module Pod
360
347
  end
361
348
  end
362
349
 
363
- # Checks the attributes that represent file patterns.
364
- #
365
- # @todo Check the attributes hash directly.
366
- #
367
- def validate_file_patterns
368
- attributes = DSL.attributes.values.select(&:file_patterns?)
369
- attributes.each do |attrb|
370
- patterns = consumer.send(attrb.name)
371
- if patterns.is_a?(Hash)
372
- patterns = patterns.values.flatten(1)
373
- end
374
- patterns.each do |pattern|
375
- if pattern.start_with?('/')
376
- error "File patterns must be relative and cannot start with a " \
377
- "slash (#{attrb.name})."
378
- end
379
- end
380
- end
381
- end
382
-
383
- # @todo remove in 0.18 and switch the default to true.
384
- #
385
- def check_tmp_arc_not_nil
386
- if consumer.spec.attributes_hash["requires_arc"].nil?
387
- warning "A value for `requires_arc` should be specified until the " \
388
- "migration to a `true` default."
389
- end
390
- end
391
-
392
- # Check empty subspec attributes
393
- #
394
- def check_if_spec_is_empty
395
- methods = %w(source_files resources preserve_paths dependencies vendored_libraries vendored_frameworks)
396
- empty_patterns = methods.all? { |m| consumer.send(m).empty? }
397
- empty = empty_patterns && consumer.spec.subspecs.empty?
398
- if empty
399
- error "The #{consumer.spec} spec is empty (no source files, " \
400
- "resources, preserve paths, vendored libraries, " \
401
- "vendored frameworks, dependencies or subspecs)."
402
- end
403
- end
404
-
405
- # Check the hooks
406
- #
407
- def check_install_hooks
408
- unless consumer.spec.pre_install_callback.nil?
409
- warning "The pre install hook of the specification DSL has been " \
410
- "deprecated, use the `resource_bundles` or the " \
411
- "`prepare_command` attributes."
412
- end
413
-
414
- unless consumer.spec.post_install_callback.nil?
415
- warning "The post install hook of the specification DSL has been " \
416
- "deprecated, use the `resource_bundles` or the " \
417
- " `prepare_command` attributes."
418
- end
419
- end
420
-
421
350
  # Returns whether the frameworks are valid
422
351
  #
423
- # @params frameworks [Array<String>]
352
+ # @param frameworks [Array<String>]
424
353
  # The frameworks to be validated
425
354
  #
426
- # @return [Boolean] true if a framework ends in `.framework`
355
+ # @return [Boolean] true if a framework contains any
356
+ # non-alphanumeric character or includes an extension.
427
357
  #
428
358
  def frameworks_invalid?(frameworks)
429
- frameworks.any? { |framework| framework.end_with?('.framework') }
430
- end
431
-
432
- # Returns whether the libraries are valid
433
- #
434
- # @params libs [Array<String>]
435
- # The libraries to be validated
436
- #
437
- # @return [Boolean] true if a library ends with `.a`, `.dylib`, or
438
- # starts with `lib`.
439
- def libraries_invalid?(libs)
440
- libs.any? { |lib| lib.end_with?('.a', '.dylib') || lib.start_with?('lib') }
441
- end
442
-
443
- #-----------------------------------------------------------------------#
444
-
445
- # !@group Result Helpers
446
-
447
- private
448
-
449
- # Adds an error result with the given message.
450
- #
451
- # @param [String] message
452
- # The message of the result.
453
- #
454
- # @return [void]
455
- #
456
- def error(message)
457
- add_result(:error, message)
458
- end
459
-
460
- # Adds an warning result with the given message.
461
- #
462
- # @param [String] message
463
- # The message of the result.
464
- #
465
- # @return [void]
466
- #
467
- def warning(message)
468
- add_result(:warning, message)
469
- end
470
-
471
- # Adds a result of the given type with the given message. If there is a
472
- # current platform it is added to the result. If a result with the same
473
- # type and the same message is already available the current platform is
474
- # added to the existing result.
475
- #
476
- # @param [Symbol] type
477
- # The type of the result (`:error`, `:warning`).
478
- #
479
- # @param [String] message
480
- # The message of the result.
481
- #
482
- # @return [void]
483
- #
484
- def add_result(type, message)
485
- result = results.find { |r| r.type == type && r.message == message }
486
- unless result
487
- result = Result.new(type, message)
488
- results << result
489
- end
490
- result.platforms << consumer.platform_name if consumer
491
- end
492
-
493
- #-----------------------------------------------------------------------#
494
-
495
- class Result
496
-
497
- # @return [Symbol] the type of result.
498
- #
499
- attr_reader :type
500
-
501
- # @return [String] the message associated with result.
502
- #
503
- attr_reader :message
504
-
505
- # @param [Symbol] type @see type
506
- # @param [String] message @see message
507
- #
508
- def initialize(type, message)
509
- @type = type
510
- @message = message
511
- @platforms = []
512
- end
513
-
514
- # @return [Array<Platform>] the platforms where this result was
515
- # generated.
516
- #
517
- attr_reader :platforms
518
-
519
- # @return [String] a string representation suitable for UI output.
520
- #
521
- def to_s
522
- r = "[#{type.to_s.upcase}] #{message}"
523
- if platforms != Specification::PLATFORMS
524
- platforms_names = platforms.uniq.map do |p|
525
- Platform.string_name(p)
526
- end
527
- r << " [#{platforms_names * ' - '}]" unless platforms.empty?
528
- end
529
- r
359
+ frameworks.any? do |framework|
360
+ framework_regex = /[^\w\-\+]/
361
+ framework =~ framework_regex
530
362
  end
531
363
  end
532
-
533
- #-----------------------------------------------------------------------#
534
-
535
364
  end
536
365
  end
537
366
  end
538
-
539
- # # TODO
540
- # # Converts the resources file patterns to a hash defaulting to the
541
- # # resource key if they are defined as an Array or a String.
542
- # #
543
- # # @param [String, Array, Hash] value.
544
- # # The value of the attribute as specified by the user.
545
- # #
546
- # # @return [Hash] the resources.
547
- # #
548
- # def _prepare_deployment_target(deployment_target)
549
- # unless @define_for_platforms.count == 1
550
- # raise StandardError, "The deployment target must be defined per platform like `s.ios.deployment_target = '5.0'`."
551
- # end
552
- # Version.new(deployment_target)
553
- # end
554
-
555
- # # TODO
556
- # # Converts the resources file patterns to a hash defaulting to the
557
- # # resource key if they are defined as an Array or a String.
558
- # #
559
- # # @param [String, Array, Hash] value.
560
- # # The value of the attribute as specified by the user.
561
- # #
562
- # # @return [Hash] the resources.
563
- # #
564
- # def _prepare_platform(name_and_deployment_target)
565
- # return nil if name_and_deployment_target.nil?
566
- # if name_and_deployment_target.is_a?(Array)
567
- # name = name_and_deployment_target.first
568
- # deployment_target = name_and_deployment_target.last
569
- # else
570
- # name = name_and_deployment_target
571
- # deployment_target = nil
572
- # end
573
- # unless PLATFORMS.include?(name)
574
- # raise StandardError, "Unsupported platform `#{name}`. The available " \
575
- # "names are `#{PLATFORMS.inspect}`"
576
- # end
577
- # Platform.new(name, deployment_target)
578
- # end