cocoapods-core 0.33.1 → 0.34.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -38,7 +38,6 @@ module Pod
38
38
  # spec.source = { :git => 'https://github.com/tonymillion/Reachability.git', :tag => 'v3.1.0' }
39
39
  # spec.source_files = 'Reachability.{h,m}'
40
40
  # spec.framework = 'SystemConfiguration'
41
- # spec.requires_arc = true
42
41
  # end
43
42
  #
44
43
  module DSL
@@ -179,6 +178,8 @@ module Pod
179
178
  # Unless the source contains a file named `LICENSE.*` or `LICENCE.*`,
180
179
  # the path of the license file **or** the integral text of the notice
181
180
  # commonly used for the license type must be specified.
181
+ # If a license file is specified, it either must be without a file
182
+ # extensions or be one of `txt`, `md`, or `markdown`.
182
183
  #
183
184
  # This information is used by CocoaPods to generate acknowledgement
184
185
  # files (markdown and plist) which can be used in the acknowledgements
@@ -245,17 +246,12 @@ module Pod
245
246
  # @example Specifying a Git source with a tag. This is how most OSS Podspecs work.
246
247
  #
247
248
  # spec.source = { :git => 'https://github.com/AFNetworking/AFNetworking.git',
248
- # :tag => 'v0.0.1' }
249
+ # :tag => spec.version.to_s }
249
250
  #
250
- # @example Using the version of the Pod to identify the Git commit and using submodules.
251
+ # @example Using a tag prefixed with 'v' and submodules.
251
252
  #
252
- # spec.source = { :git => 'https://github.com/AFNetworking/AFNetworking.git',
253
- # :commit => "v#{spec.version}", :submodules => true }
254
- #
255
- # @example Using the version of the Pod to identify the Git branch.
256
- #
257
- # spec.source = { :git => 'https://github.com/AFNetworking/AFNetworking.git',
258
- # :branch => "orta_fixes"}
253
+ # spec.source = { :git => 'https://github.com/typhoon-framework/Typhoon.git',
254
+ # :tag => "v#{spec.version}", :submodules => true }
259
255
  #
260
256
  # @example Using Subversion with a tag.
261
257
  #
@@ -525,7 +521,7 @@ module Pod
525
521
  # @param [String] args
526
522
  # The deployment target of the platform.
527
523
  #
528
- def deployment_target=(*args)
524
+ def deployment_target=(*_args)
529
525
  raise Informative, 'The deployment target can be declared only per ' \
530
526
  'platform.'
531
527
  end
@@ -599,24 +595,20 @@ module Pod
599
595
 
600
596
  # @!method requires_arc=(flag)
601
597
  #
602
- # Wether the library requires ARC to be compiled. If true the
598
+ # Whether the library requires ARC to be compiled. If true the
603
599
  # `-fobjc-arc` flag will be added to the compiler flags.
604
- #
605
- # ---
606
- #
607
- # The default value of this attribute is __transitioning__ from `false`
608
- # to `true`, and in the meanwhile this attribute is always required.
600
+ # The default value of this attribute is __transitioning__ is `true`.
609
601
  #
610
602
  # @example
611
603
  #
612
- # spec.requires_arc = true
604
+ # spec.requires_arc = false
613
605
  #
614
606
  # @param [Bool] flag
615
607
  # whether the source files require ARC.
616
608
  #
617
609
  attribute :requires_arc,
618
610
  :types => [TrueClass, FalseClass],
619
- :default_value => false,
611
+ :default_value => true,
620
612
  :inherited => true
621
613
 
622
614
  #------------------#
@@ -5,7 +5,7 @@ module Pod
5
5
  #
6
6
  def to_json(*a)
7
7
  require 'json'
8
- to_hash.to_json(*a)
8
+ to_hash.to_json(*a) << "\n"
9
9
  end
10
10
 
11
11
  #-----------------------------------------------------------------------#
@@ -16,7 +16,7 @@ module Pod
16
16
  def to_hash
17
17
  hash = attributes_hash.dup
18
18
  unless subspecs.empty?
19
- hash['subspecs'] = subspecs.map { |spec| spec.to_hash }
19
+ hash['subspecs'] = subspecs.map(&:to_hash)
20
20
  end
21
21
  hash
22
22
  end
@@ -12,8 +12,8 @@ module Pod
12
12
  end
13
13
 
14
14
  def analyze
15
+ check_attributes
15
16
  validate_file_patterns
16
- check_tmp_arc_not_nil
17
17
  check_if_spec_is_empty
18
18
  end
19
19
 
@@ -21,6 +21,46 @@ module Pod
21
21
 
22
22
  attr_reader :consumer
23
23
 
24
+ # Checks the attributes hash for any unknown key which might be the
25
+ # result of a misspelling in a JSON file.
26
+ #
27
+ # @note Sub-keys are not checked per-platform as
28
+ # there is no attribute supporting this combination.
29
+ #
30
+ # @note The keys of sub-keys are not checked as they are only used by
31
+ # the `source` attribute and they are subject
32
+ # to change according to the support in the
33
+ # `cocoapods-downloader` gem.
34
+ #
35
+ def check_attributes
36
+ attributes_keys = Pod::Specification::DSL.attributes.keys.map(&:to_s)
37
+ platform_keys = Specification::DSL::PLATFORMS.map(&:to_s)
38
+ valid_keys = attributes_keys + platform_keys
39
+ attributes_hash = consumer.spec.attributes_hash
40
+ keys = attributes_hash.keys
41
+ Specification::DSL::PLATFORMS.each do |platform|
42
+ if attributes_hash[platform.to_s]
43
+ keys += attributes_hash[platform.to_s].keys
44
+ end
45
+ end
46
+ unknown_keys = keys - valid_keys
47
+
48
+ unknown_keys.each do |key|
49
+ warning "Unrecognized `#{key}` key"
50
+ end
51
+
52
+ Pod::Specification::DSL.attributes.each do |_key, attribute|
53
+ if attribute.keys && attribute.name != :platforms
54
+ if attribute.root_only?
55
+ value = consumer.spec.send(attribute.name)
56
+ else
57
+ value = consumer.send(attribute.name)
58
+ end
59
+ validate_attribute_value(attribute, value) if value
60
+ end
61
+ end
62
+ end
63
+
24
64
  # Checks the attributes that represent file patterns.
25
65
  #
26
66
  # @todo Check the attributes hash directly.
@@ -41,25 +81,6 @@ module Pod
41
81
  end
42
82
  end
43
83
 
44
- # @todo remove after the switch to true
45
- #
46
- def check_tmp_arc_not_nil
47
- spec = consumer.spec
48
- declared = false
49
- loop do
50
- declared = true unless spec.attributes_hash['requires_arc'].nil?
51
- declared = true unless spec.attributes_hash[consumer.platform_name.to_s].nil?
52
- spec = spec.parent
53
- break unless spec
54
- end
55
-
56
- unless declared
57
- warning '[requires_arc] A value for `requires_arc` should be' \
58
- ' specified until the ' \
59
- 'migration to a `true` default.'
60
- end
61
- end
62
-
63
84
  # Check empty subspec attributes
64
85
  #
65
86
  def check_if_spec_is_empty
@@ -75,6 +96,54 @@ module Pod
75
96
  'or subspecs).'
76
97
  end
77
98
  end
99
+
100
+ private
101
+
102
+ # Validates the given value for the given attribute.
103
+ #
104
+ # @param [Spec::DSL::Attribute] attribute
105
+ # The attribute.
106
+ #
107
+ # @param [Spec::DSL::Attribute] value
108
+ # The value of the attribute.
109
+ #
110
+ def validate_attribute_value(attribute, value)
111
+ if attribute.keys.is_a?(Array)
112
+ validate_attribute_array_keys(attribute, value)
113
+ elsif attribute.keys.is_a?(Hash)
114
+ validate_attribute_hash_keys(attribute, value)
115
+ else
116
+ end
117
+ end
118
+
119
+ def validate_attribute_array_keys(attribute, value)
120
+ unknown_keys = value.keys.map(&:to_s) - attribute.keys.map(&:to_s)
121
+ unknown_keys.each do |unknown_key|
122
+ warning "Unrecognized `#{unknown_key}` key for " \
123
+ "`#{attribute.name}` attribute"
124
+ end
125
+ end
126
+
127
+ def validate_attribute_hash_keys(attribute, value)
128
+ major_keys = value.keys & attribute.keys.keys
129
+ if major_keys.count.zero?
130
+ warning "Missing primary key for `#{attribute.name}` " \
131
+ 'attribute. The acceptable ones are: ' \
132
+ "`#{attribute.keys.keys.map(&:to_s).sort.join(', ')}`"
133
+ elsif major_keys.count == 1
134
+ acceptable = attribute.keys[major_keys.first]
135
+ unknown = value.keys - major_keys - acceptable
136
+ unless unknown.empty?
137
+ warning "Incompatible `#{unknown.sort.join(', ')}` key(s) " \
138
+ "with `#{major_keys.first}` primary key for " \
139
+ "`#{attribute.name}` attribute"
140
+ end
141
+ else
142
+ sorted_keys = major_keys.map(&:to_s).sort
143
+ warning "Incompatible `#{sorted_keys.join(', ')}` keys for " \
144
+ "`#{attribute.name}` attribute"
145
+ end
146
+ end
78
147
  end
79
148
  end
80
149
  end
@@ -58,7 +58,7 @@ module Pod
58
58
  add_result(:error, message)
59
59
  end
60
60
 
61
- # Adds an warning result with the given message.
61
+ # Adds a warning result with the given message.
62
62
  #
63
63
  # @param [String] message
64
64
  # The message of the result.
@@ -31,7 +31,7 @@ module Pod
31
31
  @file = Pathname.new(spec_or_path)
32
32
  begin
33
33
  @spec = Specification.from_file(@file)
34
- rescue Exception => e
34
+ rescue => e
35
35
  @spec = nil
36
36
  @raise_message = e.message
37
37
  end
@@ -166,7 +166,7 @@ module Pod
166
166
 
167
167
  # Performs validations related to the `name` attribute.
168
168
  #
169
- def _validate_name(n)
169
+ def _validate_name(_n)
170
170
  if spec.name && file
171
171
  acceptable_names = [
172
172
  spec.root.name + '.podspec',
@@ -273,6 +273,7 @@ module Pod
273
273
  #
274
274
  def _validate_license(l)
275
275
  type = l[:type]
276
+ file = l[:file]
276
277
  if type.nil?
277
278
  warning '[license] Missing license type.'
278
279
  end
@@ -282,6 +283,9 @@ module Pod
282
283
  if type && type =~ /\(example\)/
283
284
  error '[license] Sample license type.'
284
285
  end
286
+ if file && Pathname.new(file).extname !~ /^(txt|md|markdown|)$/i
287
+ error '[license] Invalid file type'
288
+ end
285
289
  end
286
290
 
287
291
  # Performs validations related to the `source` attribute.
@@ -311,6 +315,7 @@ module Pod
311
315
  end
312
316
 
313
317
  perform_github_source_checks(s)
318
+ check_git_ssh_source(s)
314
319
  end
315
320
 
316
321
  # Performs validations related to github sources.
@@ -338,6 +343,18 @@ module Pod
338
343
  end
339
344
  end
340
345
 
346
+ # Performs validations related to SSH sources
347
+ #
348
+ def check_git_ssh_source(s)
349
+ if git = s[:git]
350
+ if git =~ /\w+\@(\w|\.)+\:(\/\w+)*/
351
+ warning '[source] Git SSH URLs will NOT work for people behind' \
352
+ 'firewalls configured to only allow HTTP, therefor HTTPS is' \
353
+ 'preferred.'
354
+ end
355
+ end
356
+ end
357
+
341
358
  # Performs validations related to the `social_media_url` attribute.
342
359
  #
343
360
  def _validate_social_media_url(s)
@@ -158,6 +158,13 @@ module Pod
158
158
  attributes_hash['deprecated_in_favor_of']
159
159
  end
160
160
 
161
+ # @return [Bool] Wether the pod is deprecated either in favor of some other
162
+ # pod or simply deprecated.
163
+ #
164
+ def deprecated?
165
+ deprecated || !deprecated_in_favor_of.nil?
166
+ end
167
+
161
168
  #---------------------------------------------------------------------#
162
169
 
163
170
  private
@@ -123,6 +123,28 @@ module Pod
123
123
  spec.description || spec.summary
124
124
  end
125
125
 
126
+ # @return [String] A string that describes the deprecation of the pod.
127
+ # If the pod is deprecated in favor of another pod it will contain
128
+ # information about that. If the pod is not deprecated returns nil.
129
+ #
130
+ # @example Output example
131
+ #
132
+ # "[DEPRECATED]"
133
+ # "[DEPRECATED in favor of NewAwesomePod]"
134
+ #
135
+ def deprecation_description
136
+ if spec.deprecated?
137
+ description = '[DEPRECATED'
138
+ if spec.deprecated_in_favor_of.nil?
139
+ description += ']'
140
+ else
141
+ description += " in favor of #{spec.deprecated_in_favor_of}]"
142
+ end
143
+
144
+ description
145
+ end
146
+ end
147
+
126
148
  # @return [String] the URL of the source of the Pod.
127
149
  #
128
150
  def source_url
@@ -27,8 +27,8 @@ module Pod
27
27
  #
28
28
  # @return [Statistics] the shared statistics instance.
29
29
  #
30
- def self.instance=(instance)
31
- @instance = instance
30
+ class << self
31
+ attr_writer :instance
32
32
  end
33
33
 
34
34
  # @return [Pathname] the path to the optional cache file.
@@ -153,7 +153,7 @@ module Pod
153
153
  def cache
154
154
  unless @cache
155
155
  if cache_file && cache_file.exist?
156
- @cache = YAMLHelper.load(cache_file.read)
156
+ @cache = YAMLHelper.load_string(cache_file.read)
157
157
  else
158
158
  @cache = {}
159
159
  end
@@ -94,7 +94,7 @@ module Pod
94
94
 
95
95
  # TODO
96
96
  #
97
- def specification_path_for_version(version)
97
+ def specification_path_for_version(_version)
98
98
  sources = []
99
99
  versions_by_source.each do |source, source_versions|
100
100
  sources << source if source_versions.include?(required_version)
@@ -120,12 +120,12 @@ module Pod
120
120
  # pod.
121
121
  #
122
122
  def self.name_and_version_from_string(string_representation)
123
- match_data = string_representation.match(/(\S*) \((.*)\)/)
123
+ match_data = string_representation.match(/\A(\S*)(?: \((.+)\))?\Z/)
124
124
  unless match_data
125
125
  raise Informative, 'Invalid string representation for a ' \
126
- "Specification: `#{string_representation}`." \
127
- 'String representation should include the name and ' \
128
- 'the version of a pod.'
126
+ "specification: `#{string_representation}`. " \
127
+ 'The string representation should include the name and ' \
128
+ 'optionally the version of the Pod.'
129
129
  end
130
130
  name = match_data[1]
131
131
  vers = Version.new(match_data[2])
@@ -563,7 +563,7 @@ module Pod
563
563
  # rubocop:disable Eval
564
564
  eval(string, nil, path.to_s)
565
565
  # rubocop:enable Eval
566
- rescue Exception => e
566
+ rescue => e
567
567
  message = "Invalid `#{path.basename}` file: #{e.message}"
568
568
  raise DSLError.new(message, path, e.backtrace)
569
569
  end
@@ -17,14 +17,14 @@ module Pod
17
17
  class YAMLHelper
18
18
  class << self
19
19
  # Returns the YAML representation of the given object. If the given object
20
- # is an Hash it accepts an optional hint for sorting the keys.
20
+ # is a Hash, it accepts an optional hint for sorting the keys.
21
21
  #
22
22
  # @param [String, Symbol, Array, Hash] object
23
23
  # the object to convert
24
24
  #
25
25
  # @param [Array] hash_keys_hint
26
26
  # an array to use as a hint for sorting the keys of the object to
27
- # convert if it is an hash.
27
+ # convert if it is a hash.
28
28
  #
29
29
  # @return [String] the YAML representation of the given object.
30
30
  #
@@ -38,18 +38,39 @@ module Pod
38
38
  result << "\n"
39
39
  end
40
40
 
41
- # Load a YAML file and provide more informative error messages in special cases like merge conflict.
42
- # @param A YAML string.
43
- def load(yaml_string)
41
+ # Loads a YAML string and provide more informative
42
+ # error messages in special cases like merge conflict.
43
+ #
44
+ # @param [String] yaml_string
45
+ # The YAML String to be loaded
46
+ #
47
+ # @param [Pathname] file_path
48
+ # The (optional) file path to be used for read for the YAML file
49
+ #
50
+ # @return [Hash, Array] the Ruby YAML representaton
51
+ #
52
+ def load_string(yaml_string, file_path = nil)
44
53
  YAML.load(yaml_string)
45
- rescue Exception => exception
46
- if yaml_has_merge_error(yaml_string)
47
- raise Informative, 'Merge conflict(s) detected'
54
+ rescue
55
+ if yaml_has_merge_error?(yaml_string)
56
+ raise Informative, yaml_merge_conflict_msg(yaml_string, file_path)
48
57
  else
49
- raise exception
58
+ raise Informative, yaml_parsing_error_msg(yaml_string, file_path)
50
59
  end
51
60
  end
52
61
 
62
+ # Loads a YAML file and leans on the #load_string imp
63
+ # to do error detection
64
+ #
65
+ # @param [Pathname] file_path
66
+ # The file path to be used for read for the YAML file
67
+ #
68
+ # @return [Hash, Array] the Ruby YAML representaton
69
+ #
70
+ def load_file(file_path)
71
+ load_string(File.read(file_path), file_path)
72
+ end
73
+
53
74
  #-----------------------------------------------------------------------#
54
75
 
55
76
  private
@@ -130,12 +151,52 @@ module Pod
130
151
  end
131
152
 
132
153
  # Check for merge errors in a YAML string.
133
- # @param A YAML string.
154
+ #
155
+ # @param [String] yaml_string
156
+ # A YAML string to evaluate
157
+ #
134
158
  # @return If a merge error was detected or not.
135
- def yaml_has_merge_error(yaml_string)
159
+ #
160
+ def yaml_has_merge_error?(yaml_string)
136
161
  yaml_string.include?('<<<<<<< HEAD')
137
162
  end
138
163
 
164
+ # Error message describing that a merge conflict was found
165
+ # while parsing the YAML.
166
+ #
167
+ # @param [String] yaml
168
+ # Offending YAML
169
+ #
170
+ # @param [Pathname] path
171
+ # The (optional) offending path
172
+ #
173
+ # @return [String] The Error Message
174
+ #
175
+ def yaml_merge_conflict_msg(yaml, path = nil)
176
+ err = 'ERROR: Parsing unable to continue due '
177
+ err += "to merge conflicts present in:\n"
178
+ err += "the file located at #{path}\n" if path
179
+ err += "#{yaml}"
180
+ end
181
+
182
+ # Error message describing a general error took happened
183
+ # while parsing the YAML.
184
+ #
185
+ # @param [String] yaml
186
+ # Offending YAML
187
+ #
188
+ # @param [Pathname] path
189
+ # The (optional) offending path
190
+ #
191
+ # @return [String] The Error Message
192
+ #
193
+ def yaml_parsing_error_msg(yaml, path = nil)
194
+ err = 'ERROR: Parsing unable to continue due '
195
+ err += "to parsing error:\n"
196
+ err += "contained in the file located at #{path}\n" if path
197
+ err += "#{yaml}"
198
+ end
199
+
139
200
  #-----------------------------------------------------------------------#
140
201
 
141
202
  private
@@ -7,7 +7,7 @@ module Pod
7
7
  #
8
8
  class PlainInformative < StandardError; end
9
9
 
10
- # Indicates an user error.
10
+ # Indicates a user error.
11
11
  #
12
12
  class Informative < PlainInformative; end
13
13