cocoapods-dylint 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7b4658775ee818d70e6eaee8d34a8b44d0c3e667
4
+ data.tar.gz: e69e6ec2f4b3958d61fdc1b42d51ad96ecebe434
5
+ SHA512:
6
+ metadata.gz: ccd5e484f3cc3481a339dcfebe58d87263e41906cdd674c9544d70709cb3dd933cc0e35ac5d79271ee096c99ff9aacbc8a03098a10a5f5239b91d0e1c6e05437
7
+ data.tar.gz: ded5dce255d40479ad8375b52baa554b33ad8f0cb51cb343e0d6492f2ca2f83ef0c576dfe32d7acc0ca69855a76a1e86cf9c795d4a9c2c12c90dbce8c0cc3bee
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ pkg
3
+ .idea/
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cocoapods-dylint.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'cocoapods'
8
+
9
+ gem 'mocha'
10
+ gem 'bacon'
11
+ gem 'mocha-on-bacon'
12
+ gem 'prettybacon'
13
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2018 黄露洋 <huangluyang@douyu.tv>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # cocoapods-dylint
2
+
3
+ 取消 `pod lib lint` 模拟器验证。
4
+
5
+ ## Installation
6
+
7
+ $ gem install cocoapods-dylint
8
+
9
+ ## Usage
10
+
11
+ $ pod lib dylint POD_NAME
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ def specs(dir)
4
+ FileList["spec/#{dir}/*_spec.rb"].shuffle.join(' ')
5
+ end
6
+
7
+ desc 'Runs all the specs'
8
+ task :specs do
9
+ sh "bundle exec bacon #{specs('**')}"
10
+ end
11
+
12
+ task :default => :specs
13
+
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pod/gem_version.rb'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cocoapods-dylint'
8
+ spec.version = CocoapodsDylint::VERSION
9
+ spec.authors = ['黄露洋']
10
+ spec.email = ['huangluyang@douyu.tv']
11
+ spec.description = %q{Validates a Pod without simulator.}
12
+ spec.summary = %q{Validates the Pod using the files in the working directory without simulator.}
13
+ spec.homepage = 'http://gitlab.douyuios.com/douyu-ios/cocoapods-dylint'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'rake'
23
+ end
@@ -0,0 +1 @@
1
+ require 'pod/gem_version'
@@ -0,0 +1 @@
1
+ require 'pod/command'
@@ -0,0 +1,135 @@
1
+ require File.expand_path('../validator.rb', __FILE__)
2
+ module Pod
3
+ class Command
4
+ # This is an example of a cocoapods plugin adding a top-level subcommand
5
+ # to the 'pod' command.
6
+ #
7
+ # You can also create subcommands of existing or new commands. Say you
8
+ # wanted to add a subcommand to `list` to show newly deprecated pods,
9
+ # (e.g. `pod list deprecated`), there are a few things that would need
10
+ # to change.
11
+ #
12
+ # - move this file to `lib/pod/command/list/deprecated.rb` and update
13
+ # the class to exist in the the Pod::Command::List namespace
14
+ # - change this class to extend from `List` instead of `Command`. This
15
+ # tells the plugin system that it is a subcommand of `list`.
16
+ # - edit `lib/cocoapods_plugins.rb` to require this file
17
+ #
18
+ # @todo Create a PR to add your plugin to CocoaPods/cocoapods.org
19
+ # in the `plugins.json` file, once your plugin is released.
20
+ #
21
+ class Lib < Command
22
+ class Dylint < Lib
23
+ self.summary = 'Validates a Pod without simulator'
24
+
25
+ self.description = <<-DESC
26
+ Validates the Pod using the files in the working directory without simulator.
27
+ DESC
28
+
29
+ def self.options
30
+ [
31
+ ['--quick', 'Lint skips checks that would require to download and build the spec'],
32
+ ['--allow-warnings', 'Lint validates even if warnings are present'],
33
+ ['--subspec=NAME', 'Lint validates only the given subspec'],
34
+ ['--no-subspecs', 'Lint skips validation of subspecs'],
35
+ ['--no-clean', 'Lint leaves the build directory intact for inspection'],
36
+ ['--fail-fast', 'Lint stops on the first failing platform or subspec'],
37
+ ['--use-libraries', 'Lint uses static libraries to install the spec'],
38
+ ['--sources=https://github.com/artsy/Specs,master', 'The sources from which to pull dependent pods ' \
39
+ '(defaults to https://github.com/CocoaPods/Specs.git). ' \
40
+ 'Multiple sources must be comma-delimited.'],
41
+ ['--private', 'Lint skips checks that apply only to public specs'],
42
+ ['--swift-version=VERSION', 'The SWIFT_VERSION that should be used to lint the spec. ' \
43
+ 'This takes precedence over a .swift-version file.'],
44
+ ['--skip-import-validation', 'Lint skips validating that the pod can be imported'],
45
+ ['--skip-tests', 'Lint skips building and running tests during validation'],
46
+ ].concat(super)
47
+ end
48
+
49
+ def initialize(argv)
50
+ @quick = argv.flag?('quick')
51
+ @allow_warnings = argv.flag?('allow-warnings')
52
+ @clean = argv.flag?('clean', true)
53
+ @fail_fast = argv.flag?('fail-fast', false)
54
+ @subspecs = argv.flag?('subspecs', true)
55
+ @only_subspec = argv.option('subspec')
56
+ @use_frameworks = !argv.flag?('use-libraries')
57
+ @source_urls = argv.option('sources', 'https://github.com/CocoaPods/Specs.git').split(',')
58
+ @private = argv.flag?('private', false)
59
+ @swift_version = argv.option('swift-version', nil)
60
+ @skip_import_validation = argv.flag?('skip-import-validation', false)
61
+ @skip_tests = argv.flag?('skip-tests', false)
62
+ @podspecs_paths = argv.arguments!
63
+ super
64
+ end
65
+
66
+ def validate!
67
+ super
68
+ end
69
+
70
+ def run
71
+ UI.puts
72
+ podspecs_to_lint.each do |podspec|
73
+ validator = Pod::DyValidator.new(podspec, @source_urls)
74
+ validator.local = true
75
+ validator.quick = @quick
76
+ validator.no_clean = !@clean
77
+ validator.fail_fast = @fail_fast
78
+ validator.allow_warnings = @allow_warnings
79
+ validator.no_subspecs = !@subspecs || @only_subspec
80
+ validator.only_subspec = @only_subspec
81
+ validator.use_frameworks = @use_frameworks
82
+ validator.ignore_public_only_results = @private
83
+ validator.swift_version = @swift_version
84
+ validator.skip_import_validation = @skip_import_validation
85
+ validator.skip_tests = @skip_tests
86
+ validator.validate
87
+
88
+ unless @clean
89
+ UI.puts "Pods workspace available at `#{validator.validation_dir}/App.xcworkspace` for inspection."
90
+ UI.puts
91
+ end
92
+ if validator.validated?
93
+ UI.puts "#{validator.spec.name} passed validation.".green
94
+ else
95
+ spec_name = podspec
96
+ spec_name = validator.spec.name if validator.spec
97
+ message = "#{spec_name} did not pass validation, due to #{validator.failure_reason}."
98
+
99
+ if @clean
100
+ message << "\nYou can use the `--no-clean` option to inspect " \
101
+ 'any issue.'
102
+ end
103
+ raise Informative, message
104
+ end
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ #----------------------------------------#
111
+
112
+ # !@group Private helpers
113
+
114
+ # @return [Pathname] The path of the podspec found in the current
115
+ # working directory.
116
+ #
117
+ # @raise If no podspec is found.
118
+ # @raise If multiple podspecs are found.
119
+ #
120
+ def podspecs_to_lint
121
+ if !@podspecs_paths.empty?
122
+ Array(@podspecs_paths)
123
+ else
124
+ podspecs = Pathname.glob(Pathname.pwd + '*.podspec{.json,}')
125
+ if podspecs.count.zero?
126
+ raise Informative, 'Unable to find a podspec in the working ' \
127
+ 'directory'
128
+ end
129
+ podspecs
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,898 @@
1
+ require 'active_support/core_ext/array'
2
+ require 'active_support/core_ext/string/inflections'
3
+
4
+ module Pod
5
+ # Validates a Specification.
6
+ #
7
+ # Extends the Linter from the Core to add additional which require the
8
+ # LocalPod and the Installer.
9
+ #
10
+ # In detail it checks that the file patterns defined by the user match
11
+ # actually do match at least a file and that the Pod builds, by installing
12
+ # it without integration and building the project with xcodebuild.
13
+ #
14
+ class DyValidator
15
+ include Config::Mixin
16
+
17
+ # The default version of Swift to use when linting pods
18
+ #
19
+ DEFAULT_SWIFT_VERSION = '3.2'.freeze
20
+
21
+ # @return [Specification::Linter] the linter instance from CocoaPods
22
+ # Core.
23
+ #
24
+ attr_reader :linter
25
+
26
+ # Initialize a new instance
27
+ #
28
+ # @param [Specification, Pathname, String] spec_or_path
29
+ # the Specification or the path of the `podspec` file to lint.
30
+ #
31
+ # @param [Array<String>] source_urls
32
+ # the Source URLs to use in creating a {Podfile}.
33
+ #
34
+ def initialize(spec_or_path, source_urls)
35
+ @linter = Specification::Linter.new(spec_or_path)
36
+ @source_urls = if @linter.spec && @linter.spec.dependencies.empty? && @linter.spec.recursive_subspecs.all? { |s| s.dependencies.empty? }
37
+ []
38
+ else
39
+ source_urls.map { |url| config.sources_manager.source_with_name_or_url(url) }.map(&:url)
40
+ end
41
+ end
42
+
43
+ #-------------------------------------------------------------------------#
44
+
45
+ # @return [Specification] the specification to lint.
46
+ #
47
+ def spec
48
+ @linter.spec
49
+ end
50
+
51
+ # @return [Pathname] the path of the `podspec` file where {#spec} is
52
+ # defined.
53
+ #
54
+ def file
55
+ @linter.file
56
+ end
57
+
58
+ # @return [Sandbox::FileAccessor] the file accessor for the spec.
59
+ #
60
+ attr_accessor :file_accessor
61
+
62
+ #-------------------------------------------------------------------------#
63
+
64
+ # Lints the specification adding a {Result} for any
65
+ # failed check to the {#results} list.
66
+ #
67
+ # @note This method shows immediately which pod is being processed and
68
+ # overrides the printed line once the result is known.
69
+ #
70
+ # @return [Bool] whether the specification passed validation.
71
+ #
72
+ def validate
73
+ @results = []
74
+
75
+ # Replace default spec with a subspec if asked for
76
+ a_spec = spec
77
+ if spec && @only_subspec
78
+ subspec_name = @only_subspec.start_with?(spec.root.name) ? @only_subspec : "#{spec.root.name}/#{@only_subspec}"
79
+ a_spec = spec.subspec_by_name(subspec_name, true, true)
80
+ @subspec_name = a_spec.name
81
+ end
82
+
83
+ UI.print " -> #{a_spec ? a_spec.name : file.basename}\r" unless config.silent?
84
+ $stdout.flush
85
+
86
+ perform_linting
87
+ perform_extensive_analysis(a_spec) if a_spec && !quick
88
+
89
+ UI.puts ' -> '.send(result_color) << (a_spec ? a_spec.to_s : file.basename.to_s)
90
+ print_results
91
+ validated?
92
+ end
93
+
94
+ # Prints the result of the validation to the user.
95
+ #
96
+ # @return [void]
97
+ #
98
+ def print_results
99
+ UI.puts results_message
100
+ end
101
+
102
+ def results_message
103
+ message = ''
104
+ results.each do |result|
105
+ if result.platforms == [:ios]
106
+ platform_message = '[iOS] '
107
+ elsif result.platforms == [:osx]
108
+ platform_message = '[OSX] '
109
+ elsif result.platforms == [:watchos]
110
+ platform_message = '[watchOS] '
111
+ elsif result.platforms == [:tvos]
112
+ platform_message = '[tvOS] '
113
+ end
114
+
115
+ subspecs_message = ''
116
+ if result.is_a?(Result)
117
+ subspecs = result.subspecs.uniq
118
+ if subspecs.count > 2
119
+ subspecs_message = '[' + subspecs[0..2].join(', ') + ', and more...] '
120
+ elsif subspecs.count > 0
121
+ subspecs_message = '[' + subspecs.join(',') + '] '
122
+ end
123
+ end
124
+
125
+ case result.type
126
+ when :error then type = 'ERROR'
127
+ when :warning then type = 'WARN'
128
+ when :note then type = 'NOTE'
129
+ else raise "#{result.type}" end
130
+ message << " - #{type.ljust(5)} | #{platform_message}#{subspecs_message}#{result.attribute_name}: #{result.message}\n"
131
+ end
132
+ message << "\n"
133
+ end
134
+
135
+ def failure_reason
136
+ results_by_type = results.group_by(&:type)
137
+ results_by_type.default = []
138
+ return nil if validated?
139
+ reasons = []
140
+ if (size = results_by_type[:error].size) && size > 0
141
+ reasons << "#{size} #{'error'.pluralize(size)}"
142
+ end
143
+ if !allow_warnings && (size = results_by_type[:warning].size) && size > 0
144
+ reason = "#{size} #{'warning'.pluralize(size)}"
145
+ pronoun = size == 1 ? 'it' : 'them'
146
+ reason << " (but you can use `--allow-warnings` to ignore #{pronoun})" if reasons.empty?
147
+ reasons << reason
148
+ end
149
+ if results.all?(&:public_only)
150
+ reasons << 'all results apply only to public specs, but you can use ' \
151
+ '`--private` to ignore them if linting the specification for a private pod'
152
+ end
153
+
154
+ reasons.to_sentence
155
+ end
156
+
157
+ #-------------------------------------------------------------------------#
158
+
159
+ #  @!group Configuration
160
+
161
+ # @return [Bool] whether the validation should skip the checks that
162
+ # requires the download of the library.
163
+ #
164
+ attr_accessor :quick
165
+
166
+ # @return [Bool] whether the linter should not clean up temporary files
167
+ # for inspection.
168
+ #
169
+ attr_accessor :no_clean
170
+
171
+ # @return [Bool] whether the linter should fail as soon as the first build
172
+ # variant causes an error. Helpful for i.e. multi-platforms specs,
173
+ # specs with subspecs.
174
+ #
175
+ attr_accessor :fail_fast
176
+
177
+ # @return [Bool] whether the validation should be performed against the root of
178
+ # the podspec instead to its original source.
179
+ #
180
+ # @note Uses the `:path` option of the Podfile.
181
+ #
182
+ attr_accessor :local
183
+ alias_method :local?, :local
184
+
185
+ # @return [Bool] Whether the validator should fail on warnings, or only on errors.
186
+ #
187
+ attr_accessor :allow_warnings
188
+
189
+ # @return [String] name of the subspec to check, if nil all subspecs are checked.
190
+ #
191
+ attr_accessor :only_subspec
192
+
193
+ # @return [Bool] Whether the validator should validate all subspecs.
194
+ #
195
+ attr_accessor :no_subspecs
196
+
197
+ # @return [Bool] Whether the validator should skip building and running tests.
198
+ #
199
+ attr_accessor :skip_tests
200
+
201
+ # @return [Bool] Whether frameworks should be used for the installation.
202
+ #
203
+ attr_accessor :use_frameworks
204
+
205
+ # @return [Boolean] Whether attributes that affect only public sources
206
+ # Bool be skipped.
207
+ #
208
+ attr_accessor :ignore_public_only_results
209
+
210
+ attr_accessor :skip_import_validation
211
+ alias_method :skip_import_validation?, :skip_import_validation
212
+
213
+ #-------------------------------------------------------------------------#
214
+
215
+ # !@group Lint results
216
+
217
+ #
218
+ #
219
+ attr_reader :results
220
+
221
+ # @return [Boolean]
222
+ #
223
+ def validated?
224
+ result_type != :error && (result_type != :warning || allow_warnings)
225
+ end
226
+
227
+ # @return [Symbol] The type, which should been used to display the result.
228
+ # One of: `:error`, `:warning`, `:note`.
229
+ #
230
+ def result_type
231
+ applicable_results = results
232
+ applicable_results = applicable_results.reject(&:public_only?) if ignore_public_only_results
233
+ types = applicable_results.map(&:type).uniq
234
+ if types.include?(:error) then :error
235
+ elsif types.include?(:warning) then :warning
236
+ else :note
237
+ end
238
+ end
239
+
240
+ # @return [Symbol] The color, which should been used to display the result.
241
+ # One of: `:green`, `:yellow`, `:red`.
242
+ #
243
+ def result_color
244
+ case result_type
245
+ when :error then :red
246
+ when :warning then :yellow
247
+ else :green end
248
+ end
249
+
250
+ # @return [Pathname] the temporary directory used by the linter.
251
+ #
252
+ def validation_dir
253
+ @validation_dir ||= Pathname(Dir.mktmpdir(['CocoaPods-Lint-', "-#{spec.name}"]))
254
+ end
255
+
256
+ # @return [String] the SWIFT_VERSION to use for validation.
257
+ #
258
+ def swift_version
259
+ return @swift_version unless @swift_version.nil?
260
+ if (version = spec.swift_version) || (version = dot_swift_version)
261
+ @swift_version = version.to_s
262
+ else
263
+ DEFAULT_SWIFT_VERSION
264
+ end
265
+ end
266
+
267
+ # Set the SWIFT_VERSION that should be used to validate the pod.
268
+ #
269
+ attr_writer :swift_version
270
+
271
+ # @return [String] the SWIFT_VERSION in the .swift-version file or nil.
272
+ #
273
+ def dot_swift_version
274
+ return unless file
275
+ swift_version_path = file.dirname + '.swift-version'
276
+ return unless swift_version_path.exist?
277
+ swift_version_path.read.strip
278
+ end
279
+
280
+ # @return [Boolean] Whether any of the pod targets part of this validator use Swift or not.
281
+ #
282
+ def uses_swift?
283
+ @installer.pod_targets.any?(&:uses_swift?)
284
+ end
285
+
286
+ #-------------------------------------------------------------------------#
287
+
288
+ private
289
+
290
+ # !@group Lint steps
291
+
292
+ #
293
+ #
294
+ def perform_linting
295
+ linter.lint
296
+ @results.concat(linter.results.to_a)
297
+ end
298
+
299
+ # Perform analysis for a given spec (or subspec)
300
+ #
301
+ def perform_extensive_analysis(spec)
302
+ if spec.test_specification?
303
+ error('spec', "Validating a test spec (`#{spec.name}`) is not supported.")
304
+ return false
305
+ end
306
+ validate_homepage(spec)
307
+ validate_screenshots(spec)
308
+ validate_social_media_url(spec)
309
+ validate_documentation_url(spec)
310
+ validate_source_url(spec)
311
+
312
+ valid = spec.available_platforms.send(fail_fast ? :all? : :each) do |platform|
313
+ UI.message "\n\n#{spec} - Analyzing on #{platform} platform.".green.reversed
314
+ @consumer = spec.consumer(platform)
315
+ setup_validation_environment
316
+ begin
317
+ create_app_project
318
+ download_pod
319
+ check_file_patterns
320
+ install_pod
321
+ validate_swift_version
322
+ add_app_project_import
323
+ validate_vendored_dynamic_frameworks
324
+ build_pod
325
+ test_pod unless skip_tests
326
+ ensure
327
+ tear_down_validation_environment
328
+ end
329
+ validated?
330
+ end
331
+ return false if fail_fast && !valid
332
+ perform_extensive_subspec_analysis(spec) unless @no_subspecs
333
+ rescue => e
334
+ message = e.to_s
335
+ message << "\n" << e.backtrace.join("\n") << "\n" if config.verbose?
336
+ error('unknown', "Encountered an unknown error (#{message}) during validation.")
337
+ false
338
+ end
339
+
340
+ # Recursively perform the extensive analysis on all subspecs
341
+ #
342
+ def perform_extensive_subspec_analysis(spec)
343
+ spec.subspecs.reject(&:test_specification?).send(fail_fast ? :all? : :each) do |subspec|
344
+ @subspec_name = subspec.name
345
+ perform_extensive_analysis(subspec)
346
+ end
347
+ end
348
+
349
+ attr_accessor :consumer
350
+ attr_accessor :subspec_name
351
+
352
+ # Performs validation of a URL
353
+ #
354
+ def validate_url(url)
355
+ resp = Pod::HTTP.validate_url(url)
356
+
357
+ if !resp
358
+ warning('url', "There was a problem validating the URL #{url}.", true)
359
+ elsif !resp.success?
360
+ warning('url', "The URL (#{url}) is not reachable.", true)
361
+ end
362
+
363
+ resp
364
+ end
365
+
366
+ # Performs validations related to the `homepage` attribute.
367
+ #
368
+ def validate_homepage(spec)
369
+ if spec.homepage
370
+ validate_url(spec.homepage)
371
+ end
372
+ end
373
+
374
+ # Performs validation related to the `screenshots` attribute.
375
+ #
376
+ def validate_screenshots(spec)
377
+ spec.screenshots.compact.each do |screenshot|
378
+ response = validate_url(screenshot)
379
+ if response && !(response.headers['content-type'] && response.headers['content-type'].first =~ /image\/.*/i)
380
+ warning('screenshot', "The screenshot #{screenshot} is not a valid image.")
381
+ end
382
+ end
383
+ end
384
+
385
+ # Performs validations related to the `social_media_url` attribute.
386
+ #
387
+ def validate_social_media_url(spec)
388
+ validate_url(spec.social_media_url) if spec.social_media_url
389
+ end
390
+
391
+ # Performs validations related to the `documentation_url` attribute.
392
+ #
393
+ def validate_documentation_url(spec)
394
+ validate_url(spec.documentation_url) if spec.documentation_url
395
+ end
396
+
397
+ # Performs validations related to the `source` -> `http` attribute (if exists)
398
+ #
399
+ def validate_source_url(spec)
400
+ return if spec.source.nil? || spec.source[:http].nil?
401
+ url = spec.source[:http]
402
+ return if url.downcase.start_with?('https://')
403
+ warning('http', "The URL (`#{url}`) doesn't use the encrypted HTTPs protocol. " \
404
+ 'It is crucial for Pods to be transferred over a secure protocol to protect your users from man-in-the-middle attacks. '\
405
+ 'This will be an error in future releases. Please update the URL to use https.')
406
+ end
407
+
408
+ # Performs validation for which version of Swift is used during validation.
409
+ #
410
+ # An error will be displayed if the user has provided a `swift_version` attribute within the podspec but is also
411
+ # using either `--swift-version` parameter or a `.swift-version with a different Swift version.
412
+ #
413
+ # The user will be warned that the default version of Swift was used if the following things are true:
414
+ # - The project uses Swift at all
415
+ # - The user did not supply a Swift version via a parameter
416
+ # - There is no `swift_version` attribute set within the specification
417
+ # - There is no `.swift-version` file present either.
418
+ #
419
+ def validate_swift_version
420
+ return unless uses_swift?
421
+ spec_swift_version = spec.swift_version
422
+ unless spec_swift_version.nil?
423
+ message = nil
424
+ if !dot_swift_version.nil? && dot_swift_version != spec_swift_version.to_s
425
+ message = "Specification `#{spec.name}` specifies an inconsistent `swift_version` (`#{spec_swift_version}`) compared to the one present in your `.swift-version` file (`#{dot_swift_version}`). " \
426
+ 'Please remove the `.swift-version` file which is now deprecated and only use the `swift_version` attribute within your podspec.'
427
+ elsif !@swift_version.nil? && @swift_version != spec_swift_version.to_s
428
+ message = "Specification `#{spec.name}` specifies an inconsistent `swift_version` (`#{spec_swift_version}`) compared to the one passed during lint (`#{@swift_version}`)."
429
+ end
430
+ unless message.nil?
431
+ error('swift', message)
432
+ return
433
+ end
434
+ end
435
+ if @swift_version.nil? && spec_swift_version.nil? && dot_swift_version.nil?
436
+ warning('swift',
437
+ 'The validator used ' \
438
+ "Swift #{DEFAULT_SWIFT_VERSION} by default because no Swift version was specified. " \
439
+ 'To specify a Swift version during validation, add the `swift_version` attribute in your podspec. ' \
440
+ 'Note that usage of the `--swift-version` parameter or a `.swift-version` file is now deprecated.')
441
+ end
442
+ end
443
+
444
+ def setup_validation_environment
445
+ validation_dir.rmtree if validation_dir.exist?
446
+ validation_dir.mkpath
447
+ @original_config = Config.instance.clone
448
+ config.installation_root = validation_dir
449
+ config.silent = !config.verbose
450
+ end
451
+
452
+ def tear_down_validation_environment
453
+ validation_dir.rmtree unless no_clean
454
+ Config.instance = @original_config
455
+ end
456
+
457
+ def deployment_target
458
+ deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name)
459
+ if consumer.platform_name == :ios && use_frameworks
460
+ minimum = Version.new('8.0')
461
+ deployment_target = [Version.new(deployment_target), minimum].max.to_s
462
+ end
463
+ deployment_target
464
+ end
465
+
466
+ def download_pod
467
+ podfile = podfile_from_spec(consumer.platform_name, deployment_target, use_frameworks, consumer.spec.test_specs.map(&:name))
468
+ sandbox = Sandbox.new(config.sandbox_root)
469
+ @installer = Installer.new(sandbox, podfile)
470
+ @installer.use_default_plugins = false
471
+ @installer.has_dependencies = !spec.dependencies.empty?
472
+ %i(prepare resolve_dependencies download_dependencies).each { |m| @installer.send(m) }
473
+ @file_accessor = @installer.pod_targets.flat_map(&:file_accessors).find { |fa| fa.spec.name == consumer.spec.name }
474
+ end
475
+
476
+ def create_app_project
477
+ app_project = Xcodeproj::Project.new(validation_dir + 'App.xcodeproj')
478
+ Pod::Generator::AppTargetHelper.add_app_target(app_project, consumer.platform_name, deployment_target)
479
+ app_project.root_object.attributes['TargetAttributes'] = {app_project.targets[0].uuid => {"ProvisioningStyle" => "Manual"}}
480
+ target = app_project.targets[0]
481
+ info_plist_path = validation_dir + 'Info.plist'
482
+ info_plist = Pod::Generator::InfoPlistFile.new('1.0', :ios, :appl)
483
+ f = File.new(info_plist_path, 'w+')
484
+ f.write(info_plist.generate)
485
+ f.close
486
+ target.build_configurations.each do |c|
487
+ c.build_settings['INFOPLIST_FILE'] = 'Info.plist'
488
+ c.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'com.douyu.app'
489
+ c.build_settings['PROVISIONING_PROFILE_SPECIFIER'] = 'match Development *'
490
+ c.build_settings['CODE_SIGN_IDENTITY'] = 'iPhone Developer'
491
+ c.build_settings['DEVELOPMENT_TEAM'] = 'KW288R5J73'
492
+ end
493
+ app_project.save
494
+ app_project.recreate_user_schemes
495
+ end
496
+
497
+ def add_app_project_import
498
+ app_project = Xcodeproj::Project.open(validation_dir + 'App.xcodeproj')
499
+ app_target = app_project.targets.first
500
+ pod_target = @installer.pod_targets.find { |pt| pt.pod_name == spec.root.name }
501
+ Pod::Generator::AppTargetHelper.add_app_project_import(app_project, app_target, pod_target, consumer.platform_name, use_frameworks)
502
+ Pod::Generator::AppTargetHelper.add_swift_version(app_target, swift_version)
503
+ Pod::Generator::AppTargetHelper.add_xctest_search_paths(app_target) if @installer.pod_targets.any? { |pt| pt.spec_consumers.any? { |c| c.frameworks.include?('XCTest') } }
504
+ app_project.save
505
+ Xcodeproj::XCScheme.share_scheme(app_project.path, 'App')
506
+ # Share the pods xcscheme only if it exists. For pre-built vendored pods there is no xcscheme generated.
507
+ Xcodeproj::XCScheme.share_scheme(@installer.pods_project.path, pod_target.label) if shares_pod_target_xcscheme?(pod_target)
508
+ end
509
+
510
+ # It creates a podfile in memory and builds a library containing the pod
511
+ # for all available platforms with xcodebuild.
512
+ #
513
+ def install_pod
514
+ %i(validate_targets generate_pods_project integrate_user_project
515
+ perform_post_install_actions).each { |m| @installer.send(m) }
516
+
517
+ deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name)
518
+ configure_pod_targets(@installer.aggregate_targets, deployment_target)
519
+ @installer.pods_project.save
520
+ end
521
+
522
+ def configure_pod_targets(targets, deployment_target)
523
+ targets.each do |target|
524
+ target.pod_targets.each do |pod_target|
525
+ next unless (native_target = pod_target.native_target)
526
+ native_target.build_configuration_list.build_configurations.each do |build_configuration|
527
+ (build_configuration.build_settings['OTHER_CFLAGS'] ||= '$(inherited)') << ' -Wincomplete-umbrella'
528
+ build_configuration.build_settings['SWIFT_VERSION'] = (pod_target.swift_version || swift_version) if pod_target.uses_swift?
529
+ end
530
+ if pod_target.uses_swift?
531
+ pod_target.test_native_targets.each do |test_native_target|
532
+ test_native_target.build_configuration_list.build_configurations.each do |build_configuration|
533
+ build_configuration.build_settings['SWIFT_VERSION'] = swift_version
534
+ end
535
+ end
536
+ end
537
+ end
538
+ if target.pod_targets.any?(&:uses_swift?) && consumer.platform_name == :ios &&
539
+ (deployment_target.nil? || Version.new(deployment_target).major < 8)
540
+ uses_xctest = target.spec_consumers.any? { |c| (c.frameworks + c.weak_frameworks).include? 'XCTest' }
541
+ error('swift', 'Swift support uses dynamic frameworks and is therefore only supported on iOS > 8.') unless uses_xctest
542
+ end
543
+ end
544
+ end
545
+
546
+ def validate_vendored_dynamic_frameworks
547
+ deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name)
548
+
549
+ unless file_accessor.nil?
550
+ dynamic_frameworks = file_accessor.vendored_dynamic_frameworks
551
+ dynamic_libraries = file_accessor.vendored_dynamic_libraries
552
+ if (dynamic_frameworks.count > 0 || dynamic_libraries.count > 0) && consumer.platform_name == :ios &&
553
+ (deployment_target.nil? || Version.new(deployment_target).major < 8)
554
+ error('dynamic', 'Dynamic frameworks and libraries are only supported on iOS 8.0 and onwards.')
555
+ end
556
+ end
557
+ end
558
+
559
+ # Performs platform specific analysis. It requires to download the source
560
+ # at each iteration
561
+ #
562
+ # @note Xcode warnings are treaded as notes because the spec maintainer
563
+ # might not be the author of the library
564
+ #
565
+ # @return [void]
566
+ #
567
+ def build_pod
568
+ if !xcodebuild_available?
569
+ UI.warn "Skipping compilation with `xcodebuild' because it can't be found.\n".yellow
570
+ else
571
+ UI.message "\nBuilding with xcodebuild.\n".yellow do
572
+ scheme = if skip_import_validation?
573
+ @installer.pod_targets.find { |pt| pt.pod_name == spec.root.name }.label
574
+ else
575
+ 'App'
576
+ end
577
+ output = xcodebuild('build', scheme, 'Release')
578
+ UI.puts output
579
+ parsed_output = parse_xcodebuild_output(output)
580
+ translate_output_to_linter_messages(parsed_output)
581
+ end
582
+ end
583
+ end
584
+
585
+ # Builds and runs all test sources associated with the current specification being validated.
586
+ #
587
+ # @note Xcode warnings are treaded as notes because the spec maintainer
588
+ # might not be the author of the library
589
+ #
590
+ # @return [void]
591
+ #
592
+ def test_pod
593
+ if !xcodebuild_available?
594
+ UI.warn "Skipping test validation with `xcodebuild' because it can't be found.\n".yellow
595
+ else
596
+ UI.message "\nTesting with xcodebuild.\n".yellow do
597
+ pod_target = @installer.pod_targets.find { |pt| pt.pod_name == spec.root.name }
598
+ consumer.spec.test_specs.each do |test_spec|
599
+ scheme = pod_target.native_target_for_spec(test_spec)
600
+ output = xcodebuild('test', scheme, 'Debug')
601
+ UI.puts output
602
+ parsed_output = parse_xcodebuild_output(output)
603
+ translate_output_to_linter_messages(parsed_output)
604
+ end
605
+ end
606
+ end
607
+ end
608
+
609
+ def xcodebuild_available?
610
+ !Executable.which('xcodebuild').nil? && ENV['COCOAPODS_VALIDATOR_SKIP_XCODEBUILD'].nil?
611
+ end
612
+
613
+ FILE_PATTERNS = %i(source_files resources preserve_paths vendored_libraries
614
+ vendored_frameworks public_header_files preserve_paths
615
+ private_header_files resource_bundles).freeze
616
+
617
+ # It checks that every file pattern specified in a spec yields
618
+ # at least one file. It requires the pods to be already present
619
+ # in the current working directory under Pods/spec.name.
620
+ #
621
+ # @return [void]
622
+ #
623
+ def check_file_patterns
624
+ FILE_PATTERNS.each do |attr_name|
625
+ if respond_to?("_validate_#{attr_name}", true)
626
+ send("_validate_#{attr_name}")
627
+ end
628
+
629
+ if !file_accessor.spec_consumer.send(attr_name).empty? && file_accessor.send(attr_name).empty?
630
+ error('file patterns', "The `#{attr_name}` pattern did not match any file.")
631
+ end
632
+ end
633
+
634
+ _validate_header_mappings_dir
635
+ if consumer.spec.root?
636
+ _validate_license
637
+ _validate_module_map
638
+ end
639
+ end
640
+
641
+ def _validate_private_header_files
642
+ _validate_header_files(:private_header_files)
643
+ end
644
+
645
+ def _validate_public_header_files
646
+ _validate_header_files(:public_header_files)
647
+ end
648
+
649
+ def _validate_license
650
+ unless file_accessor.license || spec.license && (spec.license[:type] == 'Public Domain' || spec.license[:text])
651
+ warning('license', 'Unable to find a license file')
652
+ end
653
+ end
654
+
655
+ def _validate_module_map
656
+ if spec.module_map
657
+ unless file_accessor.module_map.exist?
658
+ error('module_map', 'Unable to find the specified module map file.')
659
+ end
660
+ unless file_accessor.module_map.extname == '.modulemap'
661
+ relative_path = file_accessor.module_map.relative_path_from file_accessor.root
662
+ error('module_map', "Unexpected file extension for modulemap file (#{relative_path}).")
663
+ end
664
+ end
665
+ end
666
+
667
+ def _validate_resource_bundles
668
+ file_accessor.resource_bundles.each do |bundle, resource_paths|
669
+ next unless resource_paths.empty?
670
+ error('file patterns', "The `resource_bundles` pattern for `#{bundle}` did not match any file.")
671
+ end
672
+ end
673
+
674
+ # Ensures that a list of header files only contains header files.
675
+ #
676
+ def _validate_header_files(attr_name)
677
+ header_files = file_accessor.send(attr_name)
678
+ non_header_files = header_files.
679
+ select { |f| !Sandbox::FileAccessor::HEADER_EXTENSIONS.include?(f.extname) }.
680
+ map { |f| f.relative_path_from(file_accessor.root) }
681
+ unless non_header_files.empty?
682
+ error(attr_name, "The pattern matches non-header files (#{non_header_files.join(', ')}).")
683
+ end
684
+ non_source_files = header_files - file_accessor.source_files
685
+ unless non_source_files.empty?
686
+ error(attr_name, 'The pattern includes header files that are not listed ' \
687
+ "in source_files (#{non_source_files.join(', ')}).")
688
+ end
689
+ end
690
+
691
+ def _validate_header_mappings_dir
692
+ return unless header_mappings_dir = file_accessor.spec_consumer.header_mappings_dir
693
+ absolute_mappings_dir = file_accessor.root + header_mappings_dir
694
+ unless absolute_mappings_dir.directory?
695
+ error('header_mappings_dir', "The header_mappings_dir (`#{header_mappings_dir}`) is not a directory.")
696
+ end
697
+ non_mapped_headers = file_accessor.headers.
698
+ reject { |h| h.to_path.start_with?(absolute_mappings_dir.to_path) }.
699
+ map { |f| f.relative_path_from(file_accessor.root) }
700
+ unless non_mapped_headers.empty?
701
+ error('header_mappings_dir', "There are header files outside of the header_mappings_dir (#{non_mapped_headers.join(', ')}).")
702
+ end
703
+ end
704
+
705
+ #-------------------------------------------------------------------------#
706
+
707
+ private
708
+
709
+ # !@group Result Helpers
710
+
711
+ def error(*args)
712
+ add_result(:error, *args)
713
+ end
714
+
715
+ def warning(*args)
716
+ add_result(:warning, *args)
717
+ end
718
+
719
+ def note(*args)
720
+ add_result(:note, *args)
721
+ end
722
+
723
+ def translate_output_to_linter_messages(parsed_output)
724
+ parsed_output.each do |message|
725
+ # Checking the error for `InputFile` is to work around an Xcode
726
+ # issue where linting would fail even though `xcodebuild` actually
727
+ # succeeds. Xcode.app also doesn't fail when this issue occurs, so
728
+ # it's safe for us to do the same.
729
+ #
730
+ # For more details see https://github.com/CocoaPods/CocoaPods/issues/2394#issuecomment-56658587
731
+ #
732
+ if message.include?("'InputFile' should have")
733
+ next
734
+ end
735
+
736
+ if message =~ /\S+:\d+:\d+: error:/
737
+ error('xcodebuild', message)
738
+ elsif message =~ /\S+:\d+:\d+: warning:/
739
+ warning('xcodebuild', message)
740
+ else
741
+ note('xcodebuild', message)
742
+ end
743
+ end
744
+ end
745
+
746
+ def shares_pod_target_xcscheme?(pod_target)
747
+ Pathname.new(@installer.pods_project.path + pod_target.label).exist?
748
+ end
749
+
750
+ def add_result(type, attribute_name, message, public_only = false)
751
+ result = results.find do |r|
752
+ r.type == type && r.attribute_name && r.message == message && r.public_only? == public_only
753
+ end
754
+ unless result
755
+ result = Result.new(type, attribute_name, message, public_only)
756
+ results << result
757
+ end
758
+ result.platforms << consumer.platform_name if consumer
759
+ result.subspecs << subspec_name if subspec_name && !result.subspecs.include?(subspec_name)
760
+ end
761
+
762
+ # Specialized Result to support subspecs aggregation
763
+ #
764
+ class Result < Specification::Linter::Results::Result
765
+ def initialize(type, attribute_name, message, public_only = false)
766
+ super(type, attribute_name, message, public_only)
767
+ @subspecs = []
768
+ end
769
+
770
+ attr_reader :subspecs
771
+ end
772
+
773
+ #-------------------------------------------------------------------------#
774
+
775
+ private
776
+
777
+ # !@group Helpers
778
+
779
+ # @return [Array<String>] an array of source URLs used to create the
780
+ # {Podfile} used in the linting process
781
+ #
782
+ attr_reader :source_urls
783
+
784
+ # @param [String] platform_name
785
+ # the name of the platform, which should be declared
786
+ # in the Podfile.
787
+ #
788
+ # @param [String] deployment_target
789
+ # the deployment target, which should be declared in
790
+ # the Podfile.
791
+ #
792
+ # @param [Bool] use_frameworks
793
+ # whether frameworks should be used for the installation
794
+ #
795
+ # @param [Array<String>] test_spec_names
796
+ # the test spec names to include in the podfile.
797
+ #
798
+ # @return [Podfile] a podfile that requires the specification on the
799
+ # current platform.
800
+ #
801
+ # @note The generated podfile takes into account whether the linter is
802
+ # in local mode.
803
+ #
804
+ def podfile_from_spec(platform_name, deployment_target, use_frameworks = true, test_spec_names = [])
805
+ name = subspec_name || spec.name
806
+ podspec = file.realpath
807
+ local = local?
808
+ urls = source_urls
809
+ Pod::Podfile.new do
810
+ install! 'cocoapods', :deterministic_uuids => false
811
+ urls.each { |u| source(u) }
812
+ target 'App' do
813
+ use_frameworks!(use_frameworks)
814
+ platform(platform_name, deployment_target)
815
+ if local
816
+ pod name, :path => podspec.dirname.to_s
817
+ else
818
+ pod name, :podspec => podspec.to_s
819
+ end
820
+ test_spec_names.each do |test_spec_name|
821
+ if local
822
+ pod test_spec_name, :path => podspec.dirname.to_s
823
+ else
824
+ pod test_spec_name, :podspec => podspec.to_s
825
+ end
826
+ end
827
+ end
828
+ end
829
+ end
830
+
831
+ # Parse the xcode build output to identify the lines which are relevant
832
+ # to the linter.
833
+ #
834
+ # @param [String] output the output generated by the xcodebuild tool.
835
+ #
836
+ # @note The indentation and the temporary path is stripped form the
837
+ # lines.
838
+ #
839
+ # @return [Array<String>] the lines that are relevant to the linter.
840
+ #
841
+ def parse_xcodebuild_output(output)
842
+ lines = output.split("\n")
843
+ selected_lines = lines.select do |l|
844
+ l.include?('error: ') && (l !~ /errors? generated\./) && (l !~ /error: \(null\)/) ||
845
+ l.include?('warning: ') && (l !~ /warnings? generated\./) && (l !~ /frameworks only run on iOS 8/) ||
846
+ l.include?('note: ') && (l !~ /expanded from macro/)
847
+ end
848
+ selected_lines.map do |l|
849
+ new = l.gsub(%r{#{validation_dir}/Pods/}, '')
850
+ new.gsub!(/^ */, ' ')
851
+ end
852
+ end
853
+
854
+ # @return [String] Executes xcodebuild in the current working directory and
855
+ # returns its output (both STDOUT and STDERR).
856
+ #
857
+ def xcodebuild(action, scheme, configuration)
858
+ require 'fourflusher'
859
+ command = %W(clean #{action} -workspace #{File.join(validation_dir, 'App.xcworkspace')} -scheme #{scheme} -configuration #{configuration})
860
+ case consumer.platform_name
861
+ when :osx, :macos
862
+ command += %w(CODE_SIGN_IDENTITY=)
863
+ when :ios
864
+ #command += %w(CODE_SIGN_IDENTITY=- -sdk iphonesimulator)
865
+ #command += Fourflusher::SimControl.new.destination(:oldest, 'iOS', deployment_target)
866
+ command += %w(-sdk iphoneos -destination generic/platform=iOS)
867
+ when :watchos
868
+ command += %w(CODE_SIGN_IDENTITY=- -sdk watchsimulator)
869
+ command += Fourflusher::SimControl.new.destination(:oldest, 'watchOS', deployment_target)
870
+ when :tvos
871
+ command += %w(CODE_SIGN_IDENTITY=- -sdk appletvsimulator)
872
+ command += Fourflusher::SimControl.new.destination(:oldest, 'tvOS', deployment_target)
873
+ end
874
+
875
+ output, status = _xcodebuild(command)
876
+
877
+ unless status.success?
878
+ message = 'Returned an unsuccessful exit code.'
879
+ message += ' You can use `--verbose` for more information.' unless config.verbose?
880
+ error('xcodebuild', message)
881
+ end
882
+
883
+ output
884
+ end
885
+
886
+ # Executes the given command in the current working directory.
887
+ #
888
+ # @return [(String, Status)] The output of the given command and its
889
+ # resulting status.
890
+ #
891
+ def _xcodebuild(command)
892
+ UI.puts 'xcodebuild ' << command.join(' ') if config.verbose
893
+ Executable.capture_command('xcodebuild', command, :capture => :merge)
894
+ end
895
+
896
+ #-------------------------------------------------------------------------#
897
+ end
898
+ end
@@ -0,0 +1 @@
1
+ require 'pod/command/lib/dylint'
@@ -0,0 +1,3 @@
1
+ module CocoapodsDylint
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,12 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ module Pod
4
+ describe Command::Dylint do
5
+ describe 'CLAide' do
6
+ it 'registers it self' do
7
+ Command.parse(%w{ dylint }).should.be.instance_of Command::Dylint
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,50 @@
1
+ require 'pathname'
2
+ ROOT = Pathname.new(File.expand_path('../../', __FILE__))
3
+ $:.unshift((ROOT + 'lib').to_s)
4
+ $:.unshift((ROOT + 'spec').to_s)
5
+
6
+ require 'bundler/setup'
7
+ require 'bacon'
8
+ require 'mocha-on-bacon'
9
+ require 'pretty_bacon'
10
+ require 'pathname'
11
+ require 'cocoapods'
12
+
13
+ Mocha::Configuration.prevent(:stubbing_non_existent_method)
14
+
15
+ require 'cocoapods_plugin'
16
+
17
+ #-----------------------------------------------------------------------------#
18
+
19
+ module Pod
20
+
21
+ # Disable the wrapping so the output is deterministic in the tests.
22
+ #
23
+ UI.disable_wrap = true
24
+
25
+ # Redirects the messages to an internal store.
26
+ #
27
+ module UI
28
+ @output = ''
29
+ @warnings = ''
30
+
31
+ class << self
32
+ attr_accessor :output
33
+ attr_accessor :warnings
34
+
35
+ def puts(message = '')
36
+ @output << "#{message}\n"
37
+ end
38
+
39
+ def warn(message = '', actions = [])
40
+ @warnings << "#{message}\n"
41
+ end
42
+
43
+ def print(message)
44
+ @output << message
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ #-----------------------------------------------------------------------------#
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cocoapods-dylint
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - 黄露洋
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-01-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Validates a Pod without simulator.
42
+ email:
43
+ - huangluyang@douyu.tv
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - cocoapods-dylint.gemspec
54
+ - lib/cocoapods-dylint.rb
55
+ - lib/cocoapods_plugin.rb
56
+ - lib/pod/command.rb
57
+ - lib/pod/command/lib/dylint.rb
58
+ - lib/pod/command/lib/validator.rb
59
+ - lib/pod/gem_version.rb
60
+ - spec/command/dylint_spec.rb
61
+ - spec/spec_helper.rb
62
+ homepage: http://gitlab.douyuios.com/douyu-ios/cocoapods-dylint
63
+ licenses:
64
+ - MIT
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.6.14
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Validates the Pod using the files in the working directory without simulator.
86
+ test_files:
87
+ - spec/command/dylint_spec.rb
88
+ - spec/spec_helper.rb