cocoapods-dylint 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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