cocoapods-core 0.33.1 → 0.34.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.
@@ -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