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.
- checksums.yaml +5 -5
- data/README.md +7 -10
- data/lib/cocoapods-core/build_type.rb +121 -0
- data/lib/cocoapods-core/cdn_source.rb +501 -0
- data/lib/cocoapods-core/core_ui.rb +4 -3
- data/lib/cocoapods-core/dependency.rb +100 -73
- data/lib/cocoapods-core/gem_version.rb +1 -2
- data/lib/cocoapods-core/github.rb +32 -5
- data/lib/cocoapods-core/http.rb +86 -0
- data/lib/cocoapods-core/lockfile.rb +161 -56
- data/lib/cocoapods-core/metrics.rb +47 -0
- data/lib/cocoapods-core/platform.rb +99 -11
- data/lib/cocoapods-core/podfile/dsl.rb +623 -124
- data/lib/cocoapods-core/podfile/target_definition.rb +662 -109
- data/lib/cocoapods-core/podfile.rb +138 -65
- data/lib/cocoapods-core/requirement.rb +37 -8
- data/lib/cocoapods-core/source/acceptor.rb +16 -13
- data/lib/cocoapods-core/source/aggregate.rb +79 -103
- data/lib/cocoapods-core/source/health_reporter.rb +9 -18
- data/lib/cocoapods-core/source/manager.rb +488 -0
- data/lib/cocoapods-core/source/metadata.rb +79 -0
- data/lib/cocoapods-core/source.rb +241 -70
- data/lib/cocoapods-core/specification/consumer.rb +187 -47
- data/lib/cocoapods-core/specification/dsl/attribute.rb +49 -85
- data/lib/cocoapods-core/specification/dsl/attribute_support.rb +6 -8
- data/lib/cocoapods-core/specification/dsl/deprecations.rb +9 -126
- data/lib/cocoapods-core/specification/dsl/platform_proxy.rb +30 -20
- data/lib/cocoapods-core/specification/dsl.rb +943 -296
- data/lib/cocoapods-core/specification/json.rb +64 -23
- data/lib/cocoapods-core/specification/linter/analyzer.rb +218 -0
- data/lib/cocoapods-core/specification/linter/result.rb +128 -0
- data/lib/cocoapods-core/specification/linter.rb +310 -309
- data/lib/cocoapods-core/specification/root_attribute_accessors.rb +90 -39
- data/lib/cocoapods-core/specification/set/presenter.rb +35 -71
- data/lib/cocoapods-core/specification/set.rb +42 -96
- data/lib/cocoapods-core/specification.rb +368 -130
- data/lib/cocoapods-core/standard_error.rb +45 -24
- data/lib/cocoapods-core/trunk_source.rb +14 -0
- data/lib/cocoapods-core/vendor/requirement.rb +133 -53
- data/lib/cocoapods-core/vendor/version.rb +197 -156
- data/lib/cocoapods-core/vendor.rb +1 -5
- data/lib/cocoapods-core/version.rb +137 -42
- data/lib/cocoapods-core/yaml_helper.rb +334 -0
- data/lib/cocoapods-core.rb +10 -4
- metadata +100 -27
- data/lib/cocoapods-core/source/abstract_data_provider.rb +0 -71
- data/lib/cocoapods-core/source/file_system_data_provider.rb +0 -150
- data/lib/cocoapods-core/source/github_data_provider.rb +0 -143
- data/lib/cocoapods-core/specification/set/statistics.rb +0 -266
- data/lib/cocoapods-core/yaml_converter.rb +0 -192
@@ -1,13 +1,14 @@
|
|
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
|
10
|
-
|
11
12
|
# @return [Specification] the specification to lint.
|
12
13
|
#
|
13
14
|
attr_reader :spec
|
@@ -17,6 +18,8 @@ module Pod
|
|
17
18
|
#
|
18
19
|
attr_reader :file
|
19
20
|
|
21
|
+
attr_reader :results
|
22
|
+
|
20
23
|
# @param [Specification, Pathname, String] spec_or_path
|
21
24
|
# the Specification or the path of the `podspec` file to lint.
|
22
25
|
#
|
@@ -28,7 +31,7 @@ module Pod
|
|
28
31
|
@file = Pathname.new(spec_or_path)
|
29
32
|
begin
|
30
33
|
@spec = Specification.from_file(@file)
|
31
|
-
rescue
|
34
|
+
rescue => e
|
32
35
|
@spec = nil
|
33
36
|
@raise_message = e.message
|
34
37
|
end
|
@@ -36,20 +39,21 @@ module Pod
|
|
36
39
|
end
|
37
40
|
|
38
41
|
# Lints the specification adding a {Result} for any failed check to the
|
39
|
-
# {#results}
|
42
|
+
# {#results} object.
|
40
43
|
#
|
41
|
-
# @return [
|
44
|
+
# @return [Boolean] whether the specification passed validation.
|
42
45
|
#
|
43
46
|
def lint
|
44
|
-
@results =
|
47
|
+
@results = Results.new
|
45
48
|
if spec
|
46
|
-
|
47
|
-
|
49
|
+
validate_root_name
|
50
|
+
check_required_attributes
|
51
|
+
check_requires_arc_attribute
|
48
52
|
run_root_validation_hooks
|
49
53
|
perform_all_specs_analysis
|
50
54
|
else
|
51
|
-
|
52
|
-
"
|
55
|
+
results.add_error('spec', "The specification defined in `#{file}` "\
|
56
|
+
"could not be loaded.\n\n#{@raise_message}")
|
53
57
|
end
|
54
58
|
results.empty?
|
55
59
|
end
|
@@ -60,10 +64,6 @@ module Pod
|
|
60
64
|
|
61
65
|
public
|
62
66
|
|
63
|
-
# @return [Array<Result>] all the results generated by the Linter.
|
64
|
-
#
|
65
|
-
attr_reader :results
|
66
|
-
|
67
67
|
# @return [Array<Result>] all the errors generated by the Linter.
|
68
68
|
#
|
69
69
|
def errors
|
@@ -82,48 +82,58 @@ module Pod
|
|
82
82
|
|
83
83
|
# !@group Lint steps
|
84
84
|
|
85
|
-
#
|
86
|
-
# to features that are or will be deprecated
|
85
|
+
# Checks that the spec's root name matches the filename.
|
87
86
|
#
|
88
87
|
# @return [void]
|
89
88
|
#
|
90
|
-
def
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
89
|
+
def validate_root_name
|
90
|
+
if spec.root.name && file
|
91
|
+
acceptable_names = [
|
92
|
+
spec.root.name + '.podspec',
|
93
|
+
spec.root.name + '.podspec.json',
|
94
|
+
]
|
95
|
+
names_match = acceptable_names.include?(file.basename.to_s)
|
96
|
+
unless names_match
|
97
|
+
results.add_error('name', 'The name of the spec should match the ' \
|
98
|
+
'name of the file.')
|
99
|
+
end
|
98
100
|
end
|
101
|
+
end
|
99
102
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
if
|
107
|
-
|
108
|
-
|
103
|
+
# Generates a warning if the requires_arc attribute has true or false string values.
|
104
|
+
#
|
105
|
+
# @return [void]
|
106
|
+
#
|
107
|
+
def check_requires_arc_attribute
|
108
|
+
attribute = DSL.attributes.values.find { |attr| attr.name == :requires_arc }
|
109
|
+
if attribute
|
110
|
+
value = spec.send(attribute.name)
|
111
|
+
if value == 'true' || value == 'false'
|
112
|
+
results.add_warning('requires_arc', value + ' is considered to be the name of a file.')
|
113
|
+
end
|
109
114
|
end
|
110
115
|
end
|
111
116
|
|
112
|
-
# Checks that every
|
117
|
+
# Checks that every required attribute has a value.
|
113
118
|
#
|
114
119
|
# @return [void]
|
115
120
|
#
|
116
|
-
def
|
117
|
-
attributes = DSL.attributes.values.select(&:
|
121
|
+
def check_required_attributes
|
122
|
+
attributes = DSL.attributes.values.select(&:required?)
|
118
123
|
attributes.each do |attr|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
124
|
+
begin
|
125
|
+
value = spec.send(attr.name)
|
126
|
+
unless value && (!value.respond_to?(:empty?) || !value.empty?)
|
127
|
+
if attr.name == :license
|
128
|
+
results.add_warning('attributes', 'Missing required attribute ' \
|
129
|
+
"`#{attr.name}`.")
|
130
|
+
else
|
131
|
+
results.add_error('attributes', 'Missing required attribute ' \
|
132
|
+
"`#{attr.name}`.")
|
133
|
+
end
|
126
134
|
end
|
135
|
+
rescue => exception
|
136
|
+
results.add_error('attributes', "Unable to parse attribute `#{attr.name}` due to error: #{exception}")
|
127
137
|
end
|
128
138
|
end
|
129
139
|
end
|
@@ -134,16 +144,10 @@ module Pod
|
|
134
144
|
#
|
135
145
|
def run_root_validation_hooks
|
136
146
|
attributes = DSL.attributes.values.select(&:root_only?)
|
137
|
-
attributes
|
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
|
147
|
+
run_validation_hooks(attributes, spec)
|
144
148
|
end
|
145
149
|
|
146
|
-
# Run validations for multi-platform attributes activating
|
150
|
+
# Run validations for multi-platform attributes activating.
|
147
151
|
#
|
148
152
|
# @return [void]
|
149
153
|
#
|
@@ -152,12 +156,12 @@ module Pod
|
|
152
156
|
all_specs.each do |current_spec|
|
153
157
|
current_spec.available_platforms.each do |platform|
|
154
158
|
@consumer = Specification::Consumer.new(current_spec, platform)
|
159
|
+
results.consumer = @consumer
|
155
160
|
run_all_specs_validation_hooks
|
156
|
-
|
157
|
-
|
158
|
-
check_if_spec_is_empty
|
159
|
-
check_install_hooks
|
161
|
+
analyzer = Analyzer.new(@consumer, results)
|
162
|
+
results = analyzer.analyze
|
160
163
|
@consumer = nil
|
164
|
+
results.consumer = nil
|
161
165
|
end
|
162
166
|
end
|
163
167
|
end
|
@@ -172,57 +176,81 @@ module Pod
|
|
172
176
|
#
|
173
177
|
def run_all_specs_validation_hooks
|
174
178
|
attributes = DSL.attributes.values.reject(&:root_only?)
|
175
|
-
attributes
|
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
|
179
|
+
run_validation_hooks(attributes, consumer)
|
182
180
|
end
|
183
181
|
|
184
182
|
# Runs the validation hook for each attribute.
|
185
183
|
#
|
186
184
|
# @note Hooks are called only if there is a value for the attribute as
|
187
185
|
# required attributes are already checked by the
|
188
|
-
# {#
|
186
|
+
# {#check_required_attributes} step.
|
189
187
|
#
|
190
188
|
# @return [void]
|
191
189
|
#
|
192
|
-
|
193
|
-
|
194
|
-
|
190
|
+
def run_validation_hooks(attributes, target)
|
191
|
+
attributes.each do |attr|
|
192
|
+
validation_hook = "_validate_#{attr.name}"
|
193
|
+
next unless respond_to?(validation_hook, true)
|
194
|
+
begin
|
195
|
+
value = target.send(attr.name)
|
196
|
+
next unless value
|
197
|
+
send(validation_hook, value)
|
198
|
+
rescue => e
|
199
|
+
results.add_error(attr.name, "Unable to validate due to exception: #{e}")
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
195
203
|
|
196
204
|
#-----------------------------------------------------------------------#
|
197
205
|
|
198
206
|
private
|
199
207
|
|
200
|
-
# @!group Root spec validation helpers
|
201
|
-
|
202
208
|
# Performs validations related to the `name` attribute.
|
203
209
|
#
|
204
|
-
def _validate_name(
|
205
|
-
if
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
210
|
+
def _validate_name(name)
|
211
|
+
if name =~ %r{/}
|
212
|
+
results.add_error('name', 'The name of a spec should not contain ' \
|
213
|
+
'a slash.')
|
214
|
+
end
|
215
|
+
|
216
|
+
if name =~ /\s/
|
217
|
+
results.add_error('name', 'The name of a spec should not contain ' \
|
218
|
+
'whitespace.')
|
219
|
+
end
|
220
|
+
|
221
|
+
if name[0, 1] == '.'
|
222
|
+
results.add_error('name', 'The name of a spec should not begin' \
|
223
|
+
' with a period.')
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# @!group Root spec validation helpers
|
214
228
|
|
215
|
-
|
216
|
-
|
229
|
+
# Performs validations related to the `authors` attribute.
|
230
|
+
#
|
231
|
+
def _validate_authors(a)
|
232
|
+
if a.is_a? Hash
|
233
|
+
if a == { 'YOUR NAME HERE' => 'YOUR EMAIL HERE' }
|
234
|
+
results.add_error('authors', 'The authors have not been updated ' \
|
235
|
+
'from default')
|
217
236
|
end
|
218
237
|
end
|
219
238
|
end
|
220
239
|
|
240
|
+
# Performs validations related to the `version` attribute.
|
241
|
+
#
|
221
242
|
def _validate_version(v)
|
222
243
|
if v.to_s.empty?
|
223
|
-
|
224
|
-
|
225
|
-
|
244
|
+
results.add_error('version', 'A version is required.')
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# Performs validations related to the `module_name` attribute.
|
249
|
+
#
|
250
|
+
def _validate_module_name(m)
|
251
|
+
unless m.nil? || m =~ /^[a-z_][0-9a-z_]*$/i
|
252
|
+
results.add_error('module_name', 'The module name of a spec' \
|
253
|
+
' should be a valid C99 identifier.')
|
226
254
|
end
|
227
255
|
end
|
228
256
|
|
@@ -230,33 +258,37 @@ module Pod
|
|
230
258
|
#
|
231
259
|
def _validate_summary(s)
|
232
260
|
if s.length > 140
|
233
|
-
|
234
|
-
|
261
|
+
results.add_warning('summary', 'The summary should be a short ' \
|
262
|
+
'version of `description` (max 140 characters).')
|
235
263
|
end
|
236
264
|
if s =~ /A short description of/
|
237
|
-
|
265
|
+
results.add_warning('summary', 'The summary is not meaningful.')
|
238
266
|
end
|
239
267
|
end
|
240
268
|
|
241
269
|
# Performs validations related to the `description` attribute.
|
242
270
|
#
|
243
271
|
def _validate_description(d)
|
244
|
-
if d =~ /An optional longer description of/
|
245
|
-
warning "The description is not meaningful."
|
246
|
-
end
|
247
272
|
if d == spec.summary
|
248
|
-
|
273
|
+
results.add_warning('description', 'The description is equal to' \
|
274
|
+
' the summary.')
|
249
275
|
end
|
250
|
-
|
251
|
-
|
276
|
+
|
277
|
+
if d.strip.empty?
|
278
|
+
results.add_error('description', 'The description is empty.')
|
279
|
+
elsif spec.summary && d.length < spec.summary.length
|
280
|
+
results.add_warning('description', 'The description is shorter ' \
|
281
|
+
'than the summary.')
|
252
282
|
end
|
253
283
|
end
|
254
284
|
|
255
285
|
# Performs validations related to the `homepage` attribute.
|
256
286
|
#
|
257
287
|
def _validate_homepage(h)
|
288
|
+
return unless h.is_a?(String)
|
258
289
|
if h =~ %r{http://EXAMPLE}
|
259
|
-
|
290
|
+
results.add_warning('homepage', 'The homepage has not been updated' \
|
291
|
+
' from default')
|
260
292
|
end
|
261
293
|
end
|
262
294
|
|
@@ -264,7 +296,8 @@ module Pod
|
|
264
296
|
#
|
265
297
|
def _validate_frameworks(frameworks)
|
266
298
|
if frameworks_invalid?(frameworks)
|
267
|
-
|
299
|
+
results.add_error('frameworks', 'A framework should only be' \
|
300
|
+
' specified by its name')
|
268
301
|
end
|
269
302
|
end
|
270
303
|
|
@@ -272,15 +305,32 @@ module Pod
|
|
272
305
|
#
|
273
306
|
def _validate_weak_frameworks(frameworks)
|
274
307
|
if frameworks_invalid?(frameworks)
|
275
|
-
|
308
|
+
results.add_error('weak_frameworks', 'A weak framework should only be' \
|
309
|
+
' specified by its name')
|
276
310
|
end
|
277
311
|
end
|
278
312
|
|
279
313
|
# Performs validations related to the `libraries` attribute.
|
280
314
|
#
|
281
315
|
def _validate_libraries(libs)
|
282
|
-
|
283
|
-
|
316
|
+
libs.each do |lib|
|
317
|
+
lib = lib.downcase
|
318
|
+
if lib.end_with?('.a') || lib.end_with?('.dylib')
|
319
|
+
results.add_error('libraries', 'Libraries should not include the' \
|
320
|
+
' extension ' \
|
321
|
+
"(`#{lib}`)")
|
322
|
+
end
|
323
|
+
|
324
|
+
if lib.start_with?('lib')
|
325
|
+
results.add_error('libraries', 'Libraries should omit the `lib`' \
|
326
|
+
' prefix ' \
|
327
|
+
" (`#{lib}`)")
|
328
|
+
end
|
329
|
+
|
330
|
+
if lib.include?(',')
|
331
|
+
results.add_error('libraries', 'Libraries should not include comas ' \
|
332
|
+
"(`#{lib}`)")
|
333
|
+
end
|
284
334
|
end
|
285
335
|
end
|
286
336
|
|
@@ -288,294 +338,245 @@ module Pod
|
|
288
338
|
#
|
289
339
|
def _validate_license(l)
|
290
340
|
type = l[:type]
|
341
|
+
file = l[:file]
|
291
342
|
if type.nil?
|
292
|
-
|
343
|
+
results.add_warning('license', 'Missing license type.')
|
293
344
|
end
|
294
|
-
if type && type.
|
295
|
-
|
345
|
+
if type && type.delete(' ').delete("\n").empty?
|
346
|
+
results.add_warning('license', 'Invalid license type.')
|
296
347
|
end
|
297
348
|
if type && type =~ /\(example\)/
|
298
|
-
|
349
|
+
results.add_error('license', 'Sample license type.')
|
350
|
+
end
|
351
|
+
if file && Pathname.new(file).extname !~ /^(\.(txt|md|markdown|))?$/i
|
352
|
+
results.add_error('license', 'Invalid file type')
|
299
353
|
end
|
300
354
|
end
|
301
355
|
|
302
356
|
# Performs validations related to the `source` attribute.
|
303
357
|
#
|
304
358
|
def _validate_source(s)
|
359
|
+
return unless s.is_a?(Hash)
|
305
360
|
if git = s[:git]
|
306
361
|
tag, commit = s.values_at(:tag, :commit)
|
307
362
|
version = spec.version.to_s
|
308
363
|
|
309
364
|
if git =~ %r{http://EXAMPLE}
|
310
|
-
|
365
|
+
results.add_error('source', 'The Git source still contains the ' \
|
366
|
+
'example URL.')
|
311
367
|
end
|
312
368
|
if commit && commit.downcase =~ /head/
|
313
|
-
|
369
|
+
results.add_error('source', 'The commit of a Git source cannot be' \
|
370
|
+
' `HEAD`.')
|
314
371
|
end
|
315
|
-
if tag && !tag.include?(version)
|
316
|
-
|
372
|
+
if tag && !tag.to_s.include?(version)
|
373
|
+
results.add_warning('source', 'The version should be included in' \
|
374
|
+
' the Git tag.')
|
317
375
|
end
|
318
|
-
|
319
|
-
|
320
|
-
if commit.nil? && tag.nil?
|
321
|
-
error 'Git sources should specify either a commit or a tag.'
|
322
|
-
end
|
323
|
-
else
|
324
|
-
warning 'Git sources should specify a tag.' if tag.nil?
|
376
|
+
if tag.nil?
|
377
|
+
results.add_warning('source', 'Git sources should specify a tag.', true)
|
325
378
|
end
|
326
379
|
end
|
327
380
|
|
328
381
|
perform_github_source_checks(s)
|
382
|
+
check_git_ssh_source(s)
|
329
383
|
end
|
330
384
|
|
331
|
-
# Performs validations related to
|
385
|
+
# Performs validations related to the `deprecated_in_favor_of` attribute.
|
332
386
|
#
|
333
|
-
def
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
]
|
338
|
-
|
339
|
-
if git = s[:git]
|
340
|
-
is_github = git.include?('github.com')
|
341
|
-
if is_github
|
342
|
-
unless git.end_with?('.git')
|
343
|
-
warning "Github repositories should end in `.git`."
|
344
|
-
end
|
345
|
-
unless supported_domains.find { |domain| git.start_with?(domain) }
|
346
|
-
warning "Github repositories should use `https` link."
|
347
|
-
end
|
348
|
-
end
|
387
|
+
def _validate_deprecated_in_favor_of(d)
|
388
|
+
if spec.root.name == Specification.root_name(d)
|
389
|
+
results.add_error('deprecated_in_favor_of', 'a spec cannot be ' \
|
390
|
+
'deprecated in favor of itself')
|
349
391
|
end
|
350
392
|
end
|
351
393
|
|
352
|
-
|
353
|
-
|
354
|
-
|
394
|
+
# Performs validations related to the `test_type` attribute.
|
395
|
+
#
|
396
|
+
def _validate_test_type(t)
|
397
|
+
supported_test_types = Specification::DSL::SUPPORTED_TEST_TYPES.map(&:to_s)
|
398
|
+
unless supported_test_types.include?(t.to_s)
|
399
|
+
results.add_error('test_type', "The test type `#{t}` is not supported. " \
|
400
|
+
"Supported test type values are #{supported_test_types}.")
|
401
|
+
end
|
402
|
+
end
|
355
403
|
|
356
|
-
|
404
|
+
def _validate_app_host_name(n)
|
405
|
+
unless consumer.requires_app_host?
|
406
|
+
results.add_error('app_host_name', '`requires_app_host` must be set to ' \
|
407
|
+
'`true` when `app_host_name` is specified.')
|
408
|
+
end
|
357
409
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
if flags.join(' ').split(' ').any? { |flag| flag.start_with?('-Wno') }
|
362
|
-
warning "Warnings must not be disabled (`-Wno' compiler flags)."
|
410
|
+
unless consumer.dependencies.map(&:name).include?(n)
|
411
|
+
results.add_error('app_host_name', "The app host name (#{n}) specified by `#{consumer.spec.name}` could " \
|
412
|
+
'not be found. You must explicitly declare a dependency on that app spec.')
|
363
413
|
end
|
364
414
|
end
|
365
415
|
|
366
|
-
#
|
367
|
-
#
|
368
|
-
# @todo Check the attributes hash directly.
|
416
|
+
# Performs validations related to the `script_phases` attribute.
|
369
417
|
#
|
370
|
-
def
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
418
|
+
def _validate_script_phases(s)
|
419
|
+
s.each do |script_phase|
|
420
|
+
keys = script_phase.keys
|
421
|
+
unrecognized_keys = keys - Specification::ALL_SCRIPT_PHASE_KEYS
|
422
|
+
unless unrecognized_keys.empty?
|
423
|
+
results.add_error('script_phases', "Unrecognized option(s) `#{unrecognized_keys.join(', ')}` in script phase `#{script_phase[:name]}`. " \
|
424
|
+
"Available options are `#{Specification::ALL_SCRIPT_PHASE_KEYS.join(', ')}`.")
|
376
425
|
end
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
426
|
+
missing_required_keys = Specification::SCRIPT_PHASE_REQUIRED_KEYS - keys
|
427
|
+
unless missing_required_keys.empty?
|
428
|
+
results.add_error('script_phases', "Missing required shell script phase options `#{missing_required_keys.join(', ')}` in script phase `#{script_phase[:name]}`.")
|
429
|
+
end
|
430
|
+
unless Specification::EXECUTION_POSITION_KEYS.include?(script_phase[:execution_position])
|
431
|
+
results.add_error('script_phases', "Invalid execution position value `#{script_phase[:execution_position]}` in shell script `#{script_phase[:name]}`. " \
|
432
|
+
"Available options are `#{Specification::EXECUTION_POSITION_KEYS.join(', ')}`.")
|
382
433
|
end
|
383
434
|
end
|
384
435
|
end
|
385
436
|
|
386
|
-
#
|
437
|
+
# Performs validations related to the `on_demand_resources` attribute.
|
387
438
|
#
|
388
|
-
def
|
389
|
-
|
390
|
-
|
391
|
-
"
|
439
|
+
def _validate_on_demand_resources(h)
|
440
|
+
h.values.each do |value|
|
441
|
+
unless Specification::ON_DEMAND_RESOURCES_CATEGORY_KEYS.include?(value[:category])
|
442
|
+
results.add_error('on_demand_resources', "Invalid on demand resources category value `#{value[:category]}`. " \
|
443
|
+
"Available options are `#{Specification::ON_DEMAND_RESOURCES_CATEGORY_KEYS.join(', ')}`.")
|
444
|
+
end
|
392
445
|
end
|
393
446
|
end
|
394
447
|
|
395
|
-
#
|
448
|
+
# Performs validation related to the `scheme` attribute.
|
396
449
|
#
|
397
|
-
def
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
450
|
+
def _validate_scheme(s)
|
451
|
+
unless s.empty?
|
452
|
+
if consumer.spec.subspec? && consumer.spec.library_specification?
|
453
|
+
results.add_error('scheme', 'Scheme configuration is not currently supported for subspecs.')
|
454
|
+
return
|
455
|
+
end
|
456
|
+
if s.key?(:launch_arguments) && !s[:launch_arguments].is_a?(Array)
|
457
|
+
results.add_error('scheme', 'Expected an array for key `launch_arguments`.')
|
458
|
+
end
|
459
|
+
if s.key?(:environment_variables) && !s[:environment_variables].is_a?(Hash)
|
460
|
+
results.add_error('scheme', 'Expected a hash for key `environment_variables`.')
|
461
|
+
end
|
462
|
+
if s.key?(:code_coverage) && ![true, false].include?(s[:code_coverage])
|
463
|
+
results.add_error('scheme', 'Expected a boolean for key `code_coverage`.')
|
464
|
+
end
|
465
|
+
if s.key?(:parallelizable) && ![true, false].include?(s[:parallelizable])
|
466
|
+
results.add_error('scheme', 'Expected a boolean for key `parallelizable`.')
|
467
|
+
end
|
468
|
+
if s.key?(:build_configurations) && !s[:build_configurations].is_a?(Hash)
|
469
|
+
results.add_error('scheme', 'Expected a hash for key `build_configurations`.')
|
470
|
+
end
|
405
471
|
end
|
406
472
|
end
|
407
473
|
|
408
|
-
#
|
474
|
+
# Performs validations related to github sources.
|
409
475
|
#
|
410
|
-
def
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
476
|
+
def perform_github_source_checks(s)
|
477
|
+
require 'uri'
|
478
|
+
|
479
|
+
if git = s[:git]
|
480
|
+
return unless git =~ /^#{URI.regexp}$/
|
481
|
+
git_uri = URI.parse(git)
|
482
|
+
if git_uri.host
|
483
|
+
perform_github_uri_checks(git, git_uri) if git_uri.host.end_with?('github.com')
|
484
|
+
end
|
415
485
|
end
|
486
|
+
end
|
416
487
|
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
488
|
+
def perform_github_uri_checks(git, git_uri)
|
489
|
+
if git_uri.host.start_with?('www.')
|
490
|
+
results.add_warning('github_sources', 'Github repositories should ' \
|
491
|
+
'not use `www` in their URL.')
|
492
|
+
end
|
493
|
+
unless git.end_with?('.git')
|
494
|
+
results.add_warning('github_sources', 'Github repositories ' \
|
495
|
+
'should end in `.git`.')
|
496
|
+
end
|
497
|
+
unless git_uri.scheme == 'https'
|
498
|
+
results.add_warning('github_sources', 'Github repositories ' \
|
499
|
+
'should use an `https` link.', true)
|
421
500
|
end
|
422
501
|
end
|
423
502
|
|
424
|
-
#
|
503
|
+
# Performs validations related to SSH sources
|
425
504
|
#
|
426
|
-
|
427
|
-
|
505
|
+
def check_git_ssh_source(s)
|
506
|
+
if git = s[:git]
|
507
|
+
if git =~ %r{\w+\@(\w|\.)+\:(/\w+)*}
|
508
|
+
results.add_warning('source', 'Git SSH URLs will NOT work for ' \
|
509
|
+
'people behind firewalls configured to only allow HTTP, ' \
|
510
|
+
'therefore HTTPS is preferred.', true)
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
# Performs validations related to the `social_media_url` attribute.
|
428
516
|
#
|
429
|
-
|
517
|
+
def _validate_social_media_url(s)
|
518
|
+
if s =~ %r{https://twitter.com/EXAMPLE}
|
519
|
+
results.add_warning('social_media_url', 'The social media URL has ' \
|
520
|
+
'not been updated from the default.')
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
# Performs validations related to the `readme` attribute.
|
430
525
|
#
|
431
|
-
def
|
432
|
-
|
526
|
+
def _validate_readme(s)
|
527
|
+
if s =~ %r{https://www.example.com/README}
|
528
|
+
results.add_warning('readme', 'The readme has ' \
|
529
|
+
'not been updated from the default.')
|
530
|
+
end
|
433
531
|
end
|
434
532
|
|
435
|
-
#
|
533
|
+
# Performs validations related to the `changelog` attribute.
|
436
534
|
#
|
437
|
-
|
438
|
-
|
535
|
+
def _validate_changelog(s)
|
536
|
+
if s =~ %r{https://www.example.com/CHANGELOG}
|
537
|
+
results.add_warning('changelog', 'The changelog has ' \
|
538
|
+
'not been updated from the default.')
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
542
|
+
# @param [Hash,Object] value
|
439
543
|
#
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
544
|
+
def _validate_info_plist(value)
|
545
|
+
return if value.empty?
|
546
|
+
if consumer.spec.subspec? && consumer.spec.library_specification?
|
547
|
+
results.add_error('info_plist', 'Info.plist configuration is not currently supported for subspecs.')
|
548
|
+
end
|
444
549
|
end
|
445
550
|
|
446
551
|
#-----------------------------------------------------------------------#
|
447
552
|
|
448
|
-
#
|
553
|
+
# @!group All specs validation helpers
|
449
554
|
|
450
555
|
private
|
451
556
|
|
452
|
-
#
|
453
|
-
#
|
454
|
-
# @param [String] message
|
455
|
-
# The message of the result.
|
456
|
-
#
|
457
|
-
# @return [void]
|
458
|
-
#
|
459
|
-
def error(message)
|
460
|
-
add_result(:error, message)
|
461
|
-
end
|
462
|
-
|
463
|
-
# Adds an warning result with the given message.
|
464
|
-
#
|
465
|
-
# @param [String] message
|
466
|
-
# The message of the result.
|
467
|
-
#
|
468
|
-
# @return [void]
|
557
|
+
# Performs validations related to the `compiler_flags` attribute.
|
469
558
|
#
|
470
|
-
def
|
471
|
-
|
559
|
+
def _validate_compiler_flags(flags)
|
560
|
+
if flags.join(' ').split(' ').any? { |flag| flag.start_with?('-Wno') }
|
561
|
+
results.add_warning('compiler_flags', 'Warnings must not be disabled' \
|
562
|
+
'(`-Wno compiler` flags).')
|
563
|
+
end
|
472
564
|
end
|
473
565
|
|
474
|
-
#
|
475
|
-
# current platform it is added to the result. If a result with the same
|
476
|
-
# type and the same message is already available the current platform is
|
477
|
-
# added to the existing result.
|
478
|
-
#
|
479
|
-
# @param [Symbol] type
|
480
|
-
# The type of the result (`:error`, `:warning`).
|
566
|
+
# Returns whether the frameworks are valid
|
481
567
|
#
|
482
|
-
# @param
|
483
|
-
#
|
568
|
+
# @param frameworks [Array<String>]
|
569
|
+
# The frameworks to be validated
|
484
570
|
#
|
485
|
-
# @return [
|
571
|
+
# @return [Boolean] true if a framework contains any
|
572
|
+
# non-alphanumeric character or includes an extension.
|
486
573
|
#
|
487
|
-
def
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
results << result
|
492
|
-
end
|
493
|
-
result.platforms << consumer.platform_name if consumer
|
494
|
-
end
|
495
|
-
|
496
|
-
#-----------------------------------------------------------------------#
|
497
|
-
|
498
|
-
class Result
|
499
|
-
|
500
|
-
# @return [Symbol] the type of result.
|
501
|
-
#
|
502
|
-
attr_reader :type
|
503
|
-
|
504
|
-
# @return [String] the message associated with result.
|
505
|
-
#
|
506
|
-
attr_reader :message
|
507
|
-
|
508
|
-
# @param [Symbol] type @see type
|
509
|
-
# @param [String] message @see message
|
510
|
-
#
|
511
|
-
def initialize(type, message)
|
512
|
-
@type = type
|
513
|
-
@message = message
|
514
|
-
@platforms = []
|
515
|
-
end
|
516
|
-
|
517
|
-
# @return [Array<Platform>] the platforms where this result was
|
518
|
-
# generated.
|
519
|
-
#
|
520
|
-
attr_reader :platforms
|
521
|
-
|
522
|
-
# @return [String] a string representation suitable for UI output.
|
523
|
-
#
|
524
|
-
def to_s
|
525
|
-
r = "[#{type.to_s.upcase}] #{message}"
|
526
|
-
if platforms != Specification::PLATFORMS
|
527
|
-
platforms_names = platforms.uniq.map do |p|
|
528
|
-
Platform.string_name(p)
|
529
|
-
end
|
530
|
-
r << " [#{platforms_names * ' - '}]" unless platforms.empty?
|
531
|
-
end
|
532
|
-
r
|
574
|
+
def frameworks_invalid?(frameworks)
|
575
|
+
frameworks.any? do |framework|
|
576
|
+
framework_regex = /[^\w\-\+]/
|
577
|
+
framework =~ framework_regex
|
533
578
|
end
|
534
579
|
end
|
535
|
-
|
536
|
-
#-----------------------------------------------------------------------#
|
537
|
-
|
538
580
|
end
|
539
581
|
end
|
540
582
|
end
|
541
|
-
|
542
|
-
# # TODO
|
543
|
-
# # Converts the resources file patterns to a hash defaulting to the
|
544
|
-
# # resource key if they are defined as an Array or a String.
|
545
|
-
# #
|
546
|
-
# # @param [String, Array, Hash] value.
|
547
|
-
# # The value of the attribute as specified by the user.
|
548
|
-
# #
|
549
|
-
# # @return [Hash] the resources.
|
550
|
-
# #
|
551
|
-
# def _prepare_deployment_target(deployment_target)
|
552
|
-
# unless @define_for_platforms.count == 1
|
553
|
-
# raise StandardError, "The deployment target must be defined per platform like `s.ios.deployment_target = '5.0'`."
|
554
|
-
# end
|
555
|
-
# Version.new(deployment_target)
|
556
|
-
# end
|
557
|
-
|
558
|
-
# # TODO
|
559
|
-
# # Converts the resources file patterns to a hash defaulting to the
|
560
|
-
# # resource key if they are defined as an Array or a String.
|
561
|
-
# #
|
562
|
-
# # @param [String, Array, Hash] value.
|
563
|
-
# # The value of the attribute as specified by the user.
|
564
|
-
# #
|
565
|
-
# # @return [Hash] the resources.
|
566
|
-
# #
|
567
|
-
# def _prepare_platform(name_and_deployment_target)
|
568
|
-
# return nil if name_and_deployment_target.nil?
|
569
|
-
# if name_and_deployment_target.is_a?(Array)
|
570
|
-
# name = name_and_deployment_target.first
|
571
|
-
# deployment_target = name_and_deployment_target.last
|
572
|
-
# else
|
573
|
-
# name = name_and_deployment_target
|
574
|
-
# deployment_target = nil
|
575
|
-
# end
|
576
|
-
# unless PLATFORMS.include?(name)
|
577
|
-
# raise StandardError, "Unsupported platform `#{name}`. The available " \
|
578
|
-
# "names are `#{PLATFORMS.inspect}`"
|
579
|
-
# end
|
580
|
-
# Platform.new(name, deployment_target)
|
581
|
-
# end
|