Class: Pod::Validator

Inherits:
Object
  • Object
show all
Includes:
Config::Mixin
Defined in:
lib/cocoapods/validator.rb

Overview

Validates a Specification.

Extends the Linter from the Core to add additional which require the LocalPod and the Installer.

In detail it checks that the file patterns defined by the user match actually do match at least a file and that the Pod builds, by installing it without integration and building the project with xcodebuild.

Defined Under Namespace

Classes: Result

Constant Summary collapse

DEFAULT_SWIFT_VERSION =

The default version of Swift to use when linting pods

'4.0'.freeze
VALID_PLATFORMS =

The valid platforms for linting

Platform.all.freeze
FILE_PATTERNS =
%i(source_files resources preserve_paths vendored_libraries
vendored_frameworks public_header_files preserve_paths
project_header_files private_header_files resource_bundles).freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Config::Mixin

#config

Constructor Details

#initialize(spec_or_path, source_urls, platforms = []) ⇒ Validator

Initialize a new instance

Parameters:

  • spec_or_path (Specification, Pathname, String)

    the Specification or the path of the podspec file to lint.

  • source_urls (Array<String>)

    the Source URLs to use in creating a Podfile.

  • platforms (Array<String>) (defaults to: [])

    the platforms to lint.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/cocoapods/validator.rb', line 41

def initialize(spec_or_path, source_urls, platforms = [])
  @use_frameworks = true
  @linter = Specification::Linter.new(spec_or_path)
  @source_urls = if @linter.spec && @linter.spec.dependencies.empty? && @linter.spec.recursive_subspecs.all? { |s| s.dependencies.empty? }
                   []
                 else
                   source_urls.map { |url| config.sources_manager.source_with_name_or_url(url) }.map(&:url)
                 end

  @platforms = platforms.map do |platform|
    result =  case platform.to_s.downcase
              # Platform doesn't recognize 'macos' as being the same as 'osx' when initializing
              when 'macos' then Platform.macos
              else Platform.new(platform, nil)
              end
    unless valid_platform?(result)
      raise Informative, "Unrecognized platform `#{platform}`. Valid platforms: #{VALID_PLATFORMS.join(', ')}"
    end
    result
  end
end

Instance Attribute Details

#allow_warningsBoolean

Returns Whether the validator should fail on warnings, or only on errors.

Returns:

  • (Boolean)

    Whether the validator should fail on warnings, or only on errors.



231
232
233
# File 'lib/cocoapods/validator.rb', line 231

def allow_warnings
  @allow_warnings
end

#analyzeBoolean

Returns Whether the validator should run Xcode Static Analysis.

Returns:

  • (Boolean)

    Whether the validator should run Xcode Static Analysis.



251
252
253
# File 'lib/cocoapods/validator.rb', line 251

def analyze
  @analyze
end

#configurationObject

Returns the value of attribute configuration.



283
284
285
# File 'lib/cocoapods/validator.rb', line 283

def configuration
  @configuration
end

#consumerConsumer (private)

Returns the consumer for the current platform being validated.

Returns:

  • (Consumer)

    the consumer for the current platform being validated



437
438
439
# File 'lib/cocoapods/validator.rb', line 437

def consumer
  @consumer
end

#external_podspecsString

Returns A glob for podspecs to be used during building of the local Podfile via :podspec.

Returns:

  • (String)

    A glob for podspecs to be used during building of the local Podfile via :podspec.



278
279
280
# File 'lib/cocoapods/validator.rb', line 278

def external_podspecs
  @external_podspecs
end

#fail_fastBoolean

Returns whether the linter should fail as soon as the first build variant causes an error. Helpful for i.e. multi-platforms specs, specs with subspecs.

Returns:

  • (Boolean)

    whether the linter should fail as soon as the first build variant causes an error. Helpful for i.e. multi-platforms specs, specs with subspecs.



219
220
221
# File 'lib/cocoapods/validator.rb', line 219

def fail_fast
  @fail_fast
end

#file_accessorSandbox::FileAccessor

Returns the file accessor for the spec.

Returns:



102
103
104
# File 'lib/cocoapods/validator.rb', line 102

def file_accessor
  @file_accessor
end

#ignore_public_only_resultsBoolean

Returns Whether attributes that affect only public sources Bool be skipped.

Returns:

  • (Boolean)

    Whether attributes that affect only public sources Bool be skipped.



268
269
270
# File 'lib/cocoapods/validator.rb', line 268

def ignore_public_only_results
  @ignore_public_only_results
end

#include_podspecsString

Returns A glob for podspecs to be used during building of the local Podfile via :path.

Returns:

  • (String)

    A glob for podspecs to be used during building of the local Podfile via :path.



273
274
275
# File 'lib/cocoapods/validator.rb', line 273

def include_podspecs
  @include_podspecs
end

#linterSpecification::Linter (readonly)

Returns the linter instance from CocoaPods Core.

Returns:

  • (Specification::Linter)

    the linter instance from CocoaPods Core.



28
29
30
# File 'lib/cocoapods/validator.rb', line 28

def linter
  @linter
end

#localBoolean Also known as: local?

Note:

Uses the :path option of the Podfile.

Returns whether the validation should be performed against the root of the podspec instead to its original source.

Returns:

  • (Boolean)

    whether the validation should be performed against the root of the podspec instead to its original source.



226
227
228
# File 'lib/cocoapods/validator.rb', line 226

def local
  @local
end

#no_cleanBoolean

Returns whether the linter should not clean up temporary files for inspection.

Returns:

  • (Boolean)

    whether the linter should not clean up temporary files for inspection.



213
214
215
# File 'lib/cocoapods/validator.rb', line 213

def no_clean
  @no_clean
end

#no_subspecsBoolean

Returns Whether the validator should validate all subspecs.

Returns:

  • (Boolean)

    Whether the validator should validate all subspecs.



239
240
241
# File 'lib/cocoapods/validator.rb', line 239

def no_subspecs
  @no_subspecs
end

#only_subspecString

Returns name of the subspec to check, if nil all subspecs are checked.

Returns:

  • (String)

    name of the subspec to check, if nil all subspecs are checked.



235
236
237
# File 'lib/cocoapods/validator.rb', line 235

def only_subspec
  @only_subspec
end

#quickBoolean

Returns whether the validation should skip the checks that requires the download of the library.

Returns:

  • (Boolean)

    whether the validation should skip the checks that requires the download of the library.



208
209
210
# File 'lib/cocoapods/validator.rb', line 208

def quick
  @quick
end

#resultsObject (readonly)

Returns the value of attribute results.



291
292
293
# File 'lib/cocoapods/validator.rb', line 291

def results
  @results
end

#skip_import_validationObject Also known as: skip_import_validation?

Returns the value of attribute skip_import_validation.



280
281
282
# File 'lib/cocoapods/validator.rb', line 280

def skip_import_validation
  @skip_import_validation
end

#skip_testsBoolean

Returns Whether the validator should skip building and running tests.

Returns:

  • (Boolean)

    Whether the validator should skip building and running tests.



243
244
245
# File 'lib/cocoapods/validator.rb', line 243

def skip_tests
  @skip_tests
end

#source_urlsArray<String> (readonly, private)

Returns an array of source URLs used to create the Podfile used in the linting process.

Returns:

  • (Array<String>)

    an array of source URLs used to create the Podfile used in the linting process



990
991
992
# File 'lib/cocoapods/validator.rb', line 990

def source_urls
  @source_urls
end

#subspec_nameString, Nil (private)

Returns the name of the current subspec being validated, or nil if none.

Returns:

  • (String, Nil)

    the name of the current subspec being validated, or nil if none



441
442
443
# File 'lib/cocoapods/validator.rb', line 441

def subspec_name
  @subspec_name
end

#swift_versionString

--swift-version parameter during validation.

Returns:

  • (String)

    The SWIFT_VERSION that should be used to validate the pod. This is set by passing the



335
336
337
# File 'lib/cocoapods/validator.rb', line 335

def swift_version
  @swift_version
end

#test_specsArray<String>

Returns List of test_specs to run. If nil, all tests are run (unless skip_tests is specified).

Returns:

  • (Array<String>)

    List of test_specs to run. If nil, all tests are run (unless skip_tests is specified).



247
248
249
# File 'lib/cocoapods/validator.rb', line 247

def test_specs
  @test_specs
end

#use_frameworksBoolean

Returns Whether frameworks should be used for the installation.

Returns:

  • (Boolean)

    Whether frameworks should be used for the installation.



255
256
257
# File 'lib/cocoapods/validator.rb', line 255

def use_frameworks
  @use_frameworks
end

#use_modular_headersBoolean

Returns Whether modular headers should be used for the installation.

Returns:

  • (Boolean)

    Whether modular headers should be used for the installation.



259
260
261
# File 'lib/cocoapods/validator.rb', line 259

def use_modular_headers
  @use_modular_headers
end

#use_static_frameworksBoolean

Returns Whether static frameworks should be used for the installation.

Returns:

  • (Boolean)

    Whether static frameworks should be used for the installation.



263
264
265
# File 'lib/cocoapods/validator.rb', line 263

def use_static_frameworks
  @use_static_frameworks
end

Instance Method Details

#_validate_header_files(attr_name) ⇒ Object (private)

Ensures that a list of header files only contains header files.



884
885
886
887
888
889
890
891
892
893
894
895
896
897
# File 'lib/cocoapods/validator.rb', line 884

def _validate_header_files(attr_name)
  header_files = file_accessor.send(attr_name)
  non_header_files = header_files.
    select { |f| !Sandbox::FileAccessor::HEADER_EXTENSIONS.include?(f.extname) }.
    map { |f| f.relative_path_from(file_accessor.root) }
  unless non_header_files.empty?
    error(attr_name, "The pattern matches non-header files (#{non_header_files.join(', ')}).")
  end
  non_source_files = header_files - file_accessor.source_files
  unless non_source_files.empty?
    error(attr_name, 'The pattern includes header files that are not listed ' \
      "in source_files (#{non_source_files.join(', ')}).")
  end
end

#_validate_header_mappings_dirObject (private)



899
900
901
902
903
904
905
906
907
908
909
910
911
# File 'lib/cocoapods/validator.rb', line 899

def _validate_header_mappings_dir
  return unless header_mappings_dir = file_accessor.spec_consumer.header_mappings_dir
  absolute_mappings_dir = file_accessor.root + header_mappings_dir
  unless absolute_mappings_dir.directory?
    error('header_mappings_dir', "The header_mappings_dir (`#{header_mappings_dir}`) is not a directory.")
  end
  non_mapped_headers = file_accessor.headers.
    reject { |h| h.to_path.start_with?(absolute_mappings_dir.to_path) }.
    map { |f| f.relative_path_from(file_accessor.root) }
  unless non_mapped_headers.empty?
    error('header_mappings_dir', "There are header files outside of the header_mappings_dir (#{non_mapped_headers.join(', ')}).")
  end
end

#_validate_licenseObject (private)



857
858
859
860
861
# File 'lib/cocoapods/validator.rb', line 857

def _validate_license
  unless file_accessor.license || spec.license && (spec.license[:type] == 'Public Domain' || spec.license[:text])
    warning('license', 'Unable to find a license file')
  end
end

#_validate_module_mapObject (private)



863
864
865
866
867
868
869
870
871
872
873
# File 'lib/cocoapods/validator.rb', line 863

def _validate_module_map
  if spec.module_map
    unless file_accessor.module_map.exist?
      error('module_map', 'Unable to find the specified module map file.')
    end
    unless file_accessor.module_map.extname == '.modulemap'
      relative_path = file_accessor.module_map.relative_path_from file_accessor.root
      error('module_map', "Unexpected file extension for modulemap file (#{relative_path}).")
    end
  end
end

#_validate_private_header_filesObject (private)



847
848
849
850
# File 'lib/cocoapods/validator.rb', line 847

def _validate_private_header_files
  _validate_header_files(:private_header_files)
  validate_nonempty_patterns(:private_header_files, :warning)
end

#_validate_project_header_filesObject (private)



842
843
844
845
# File 'lib/cocoapods/validator.rb', line 842

def _validate_project_header_files
  _validate_header_files(:project_header_files)
  validate_nonempty_patterns(:project_header_files, :warning)
end

#_validate_public_header_filesObject (private)



852
853
854
855
# File 'lib/cocoapods/validator.rb', line 852

def _validate_public_header_files
  _validate_header_files(:public_header_files)
  validate_nonempty_patterns(:public_header_files, :warning)
end

#_validate_resource_bundlesObject (private)



875
876
877
878
879
880
# File 'lib/cocoapods/validator.rb', line 875

def _validate_resource_bundles
  file_accessor.resource_bundles.each do |bundle, resource_paths|
    next unless resource_paths.empty?
    error('file patterns', "The `resource_bundles` pattern for `#{bundle}` did not match any file.")
  end
end

#_validate_vendored_librariesObject (private)



831
832
833
834
835
836
837
838
839
840
# File 'lib/cocoapods/validator.rb', line 831

def _validate_vendored_libraries
  file_accessor.vendored_libraries.each do |lib|
    basename = File.basename(lib)
    lib_name = basename.downcase
    unless lib_name.end_with?('.a', '.dylib') && lib_name.start_with?('lib')
      warning('vendored_libraries', "`#{basename}` does not match the expected library name format `lib[name].a` or `lib[name].dylib`")
    end
  end
  validate_nonempty_patterns(:vendored_libraries, :warning)
end

#_xcodebuild(command, raise_on_failure = false) ⇒ String (private)

Executes the given command in the current working directory.

Returns:

  • (String)

    The output of the given command



1132
1133
1134
# File 'lib/cocoapods/validator.rb', line 1132

def _xcodebuild(command, raise_on_failure = false)
  Executable.execute_command('xcodebuild', command, raise_on_failure)
end

#add_app_project_importObject (private)



611
612
613
614
615
616
617
618
619
620
621
622
# File 'lib/cocoapods/validator.rb', line 611

def add_app_project_import
  app_project = Xcodeproj::Project.open(validation_dir + 'App.xcodeproj')
  app_target = app_project.targets.first
  pod_target = validation_pod_target
  Pod::Generator::AppTargetHelper.add_app_project_import(app_project, app_target, pod_target, consumer.platform_name)
  Pod::Generator::AppTargetHelper.add_xctest_search_paths(app_target) if @installer.pod_targets.any? { |pt| pt.spec_consumers.any? { |c| c.frameworks.include?('XCTest') || c.weak_frameworks.include?('XCTest') } }
  Pod::Generator::AppTargetHelper.add_empty_swift_file(app_project, app_target) if @installer.pod_targets.any?(&:uses_swift?)
  app_project.save
  Xcodeproj::XCScheme.share_scheme(app_project.path, 'App')
  # Share the pods xcscheme only if it exists. For pre-built vendored pods there is no xcscheme generated.
  Xcodeproj::XCScheme.share_scheme(@installer.pods_project.path, pod_target.label) if shares_pod_target_xcscheme?(pod_target)
end

#add_result(type, attribute_name, message, public_only = false) ⇒ Object (private)



958
959
960
961
962
963
964
965
966
967
968
# File 'lib/cocoapods/validator.rb', line 958

def add_result(type, attribute_name, message, public_only = false)
  result = results.find do |r|
    r.type == type && r.attribute_name && r.message == message && r.public_only? == public_only
  end
  unless result
    result = Result.new(type, attribute_name, message, public_only)
    results << result
  end
  result.platforms << consumer.platform_name if consumer
  result.subspecs << subspec_name if subspec_name && !result.subspecs.include?(subspec_name)
end

#build_podvoid (private)

Note:

Xcode warnings are treated as notes because the spec maintainer might not be the author of the library

This method returns an undefined value.

Performs platform specific analysis. It requires to download the source at each iteration



719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
# File 'lib/cocoapods/validator.rb', line 719

def build_pod
  if !xcodebuild_available?
    UI.warn "Skipping compilation with `xcodebuild` because it can't be found.\n".yellow
  else
    UI.message "\nBuilding with `xcodebuild`.\n".yellow do
      scheme = if skip_import_validation?
                 validation_pod_target.label if validation_pod_target.should_build?
               else
                 'App'
               end
      if scheme.nil?
        UI.warn "Skipping compilation with `xcodebuild` because target contains no sources.\n".yellow
      else
        requested_configuration = configuration ? configuration : 'Release'
        if analyze
          output = xcodebuild('analyze', scheme, requested_configuration, :deployment_target => deployment_target)
          find_output = Executable.execute_command('find', [validation_dir, '-name', '*.html'], false)
          if find_output != ''
            message = 'Static Analysis failed.'
            message += ' You can use `--verbose` for more information.' unless config.verbose?
            message += ' You can use `--no-clean` to save a reproducible buid environment.' unless no_clean
            error('build_pod', message)
          end
        else
          output = xcodebuild('build', scheme, requested_configuration, :deployment_target => deployment_target)
        end
        parsed_output = parse_xcodebuild_output(output)
        translate_output_to_linter_messages(parsed_output)
      end
    end
  end
end

#check_file_patternsvoid (private)

This method returns an undefined value.

It checks that every file pattern specified in a spec yields at least one file. It requires the pods to be already present in the current working directory under Pods/spec.name.



803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
# File 'lib/cocoapods/validator.rb', line 803

def check_file_patterns
  FILE_PATTERNS.each do |attr_name|
    if respond_to?("_validate_#{attr_name}", true)
      send("_validate_#{attr_name}")
    else
      validate_nonempty_patterns(attr_name, :error)
    end
  end

  _validate_header_mappings_dir
  if consumer.spec.root?
    _validate_license
    _validate_module_map
  end
end

#clean!Object (private)



560
561
562
# File 'lib/cocoapods/validator.rb', line 560

def clean!
  validation_dir.rmtree
end

#configure_pod_targets(target_installation_results) ⇒ Object (private)

Parameters:

  • target_installation_results (Array<Hash{String, TargetInstallationResult}>)

    The installation results to configure



646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
# File 'lib/cocoapods/validator.rb', line 646

def configure_pod_targets(target_installation_results)
  target_installation_results.first.values.each do |pod_target_installation_result|
    pod_target = pod_target_installation_result.target
    native_target = pod_target_installation_result.native_target
    native_target.build_configuration_list.build_configurations.each do |build_configuration|
      (build_configuration.build_settings['OTHER_CFLAGS'] ||= '$(inherited)') << ' -Wincomplete-umbrella'
      if pod_target.uses_swift?
        # The Swift version for the target being validated can be overridden by `--swift-version` or the
        # `.swift-version` file so we always use the derived Swift version.
        #
        # For dependencies, if the derived Swift version is supported then it is the one used. Otherwise, the Swift
        # version for dependencies is inferred by the target that is integrating them.
        swift_version = if pod_target == validation_pod_target
                          derived_swift_version
                        else
                          pod_target.spec_swift_versions.map(&:to_s).find do |v|
                            v == derived_swift_version
                          end || pod_target.swift_version
                        end
        build_configuration.build_settings['SWIFT_VERSION'] = swift_version
      end
    end
    pod_target_installation_result.test_specs_by_native_target.each do |test_native_target, test_spec|
      if pod_target.uses_swift_for_spec?(test_spec)
        test_native_target.build_configuration_list.build_configurations.each do |build_configuration|
          swift_version = pod_target == validation_pod_target ? derived_swift_version : pod_target.swift_version
          build_configuration.build_settings['SWIFT_VERSION'] = swift_version
        end
      end
    end
  end
end

#create_app_projectObject (private)



586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
# File 'lib/cocoapods/validator.rb', line 586

def create_app_project
  app_project = Xcodeproj::Project.new(validation_dir + 'App.xcodeproj')
  app_target = Pod::Generator::AppTargetHelper.add_app_target(app_project, consumer.platform_name, deployment_target)
  sandbox = Sandbox.new(config.sandbox_root)
  info_plist_path = app_project.path.dirname.+('App/App-Info.plist')
  Pod::Installer::Xcode::PodsProjectGenerator::TargetInstallerHelper.create_info_plist_file_with_sandbox(sandbox,
                                                                                                         info_plist_path,
                                                                                                         app_target,
                                                                                                         '1.0.0',
                                                                                                         Platform.new(consumer.platform_name),
                                                                                                         :appl,
                                                                                                         :build_setting_value => '$(SRCROOT)/App/App-Info.plist')
  Pod::Generator::AppTargetHelper.add_swift_version(app_target, derived_swift_version)
  app_target.build_configurations.each do |config|
    # Lint will fail if a AppIcon is set but no image is found with such name
    # Happens only with Static Frameworks enabled but shouldn't be set anyway
    config.build_settings.delete('ASSETCATALOG_COMPILER_APPICON_NAME')
    # Ensure this is set generally but we have seen an issue with ODRs:
    # see: https://github.com/CocoaPods/CocoaPods/issues/10933
    config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
  end
  app_project.save
  app_project.recreate_user_schemes
end

#deployment_targetString (private)

Returns The deployment targret of the library spec.

Returns:

  • (String)

    The deployment targret of the library spec.



566
567
568
569
570
571
572
573
# File 'lib/cocoapods/validator.rb', line 566

def deployment_target
  deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name)
  if consumer.platform_name == :ios && use_frameworks
    minimum = Version.new('8.0')
    deployment_target = [Version.new(deployment_target), minimum].max.to_s
  end
  deployment_target
end

#derived_swift_versionString

Returns The derived Swift version to use for validation. The order of precedence is as follows:

  • The --swift-version parameter is always checked first and honored if passed.
  • The swift_versions DSL attribute within the podspec, in which case the latest version is always chosen.
  • The Swift version within the .swift-version file if present.
  • If none of the above are set then the #DEFAULT_SWIFT_VERSION is used.

Returns:

  • (String)

    The derived Swift version to use for validation. The order of precedence is as follows:

    • The --swift-version parameter is always checked first and honored if passed.
    • The swift_versions DSL attribute within the podspec, in which case the latest version is always chosen.
    • The Swift version within the .swift-version file if present.
    • If none of the above are set then the #DEFAULT_SWIFT_VERSION is used.


352
353
354
355
356
357
358
359
360
361
362
# File 'lib/cocoapods/validator.rb', line 352

def derived_swift_version
  @derived_swift_version ||= begin
    if !swift_version.nil?
      swift_version
    elsif version = spec.swift_versions.max || dot_swift_version
      version.to_s
    else
      DEFAULT_SWIFT_VERSION
    end
  end
end

#dot_swift_versionString

Returns the SWIFT_VERSION within the .swift-version file or nil.

Returns:

  • (String)

    the SWIFT_VERSION within the .swift-version file or nil.



339
340
341
342
343
344
# File 'lib/cocoapods/validator.rb', line 339

def dot_swift_version
  return unless file
  swift_version_path = file.dirname + '.swift-version'
  return unless swift_version_path.exist?
  swift_version_path.read.strip
end

#download_podObject (private)



575
576
577
578
579
580
581
582
583
584
# File 'lib/cocoapods/validator.rb', line 575

def download_pod
  test_spec_names = consumer.spec.test_specs.select { |ts| ts.supported_on_platform?(consumer.platform_name) }.map(&:name)
  podfile = podfile_from_spec(consumer.platform_name, deployment_target, use_frameworks, test_spec_names, use_modular_headers, use_static_frameworks)
  sandbox = Sandbox.new(config.sandbox_root)
  @installer = Installer.new(sandbox, podfile)
  @installer.use_default_plugins = false
  @installer.has_dependencies = !spec.dependencies.empty?
  %i(prepare resolve_dependencies download_dependencies write_lockfiles).each { |m| @installer.send(m) }
  @file_accessor = @installer.pod_targets.flat_map(&:file_accessors).find { |fa| fa.spec.name == consumer.spec.name }
end

#error(*args) ⇒ Object (private)

!@group Result Helpers



919
920
921
# File 'lib/cocoapods/validator.rb', line 919

def error(*args)
  add_result(:error, *args)
end

#failure_reasonObject



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/cocoapods/validator.rb', line 179

def failure_reason
  results_by_type = results.group_by(&:type)
  results_by_type.default = []
  return nil if validated?
  reasons = []
  if (size = results_by_type[:error].size) && size > 0
    reasons << "#{size} #{'error'.pluralize(size)}"
  end
  if !allow_warnings && (size = results_by_type[:warning].size) && size > 0
    reason = "#{size} #{'warning'.pluralize(size)}"
    pronoun = size == 1 ? 'it' : 'them'
    reason << " (but you can use `--allow-warnings` to ignore #{pronoun})" if reasons.empty?
    reasons << reason
  end
  if results.all?(&:public_only)
    reasons << 'all results apply only to public specs, but you can use ' \
               '`--private` to ignore them if linting the specification for a private pod'
  end

  reasons.to_sentence
end

#filePathname

Returns the path of the podspec file where #spec is defined.

Returns:

  • (Pathname)

    the path of the podspec file where #spec is defined.



74
75
76
# File 'lib/cocoapods/validator.rb', line 74

def file
  @linter.file
end

#install_podObject (private)

It creates a podfile in memory and builds a library containing the pod for all available platforms with xcodebuild.



633
634
635
636
637
638
639
640
641
# File 'lib/cocoapods/validator.rb', line 633

def install_pod
  %i(validate_targets generate_pods_project integrate_user_project
     perform_post_install_actions).each { |m| @installer.send(m) }

  deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name)
  configure_pod_targets(@installer.target_installation_results)
  validate_dynamic_framework_support(@installer.aggregate_targets, deployment_target)
  @installer.pods_project.save
end

#note(*args) ⇒ Object (private)



927
928
929
# File 'lib/cocoapods/validator.rb', line 927

def note(*args)
  add_result(:note, *args)
end

#parse_xcodebuild_output(output) ⇒ Array<String> (private)

Note:

The indentation and the temporary path is stripped form the lines.

Parse the xcode build output to identify the lines which are relevant to the linter.

Parameters:

  • output (String)

    the output generated by the xcodebuild tool.

Returns:

  • (Array<String>)

    the lines that are relevant to the linter.



1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
# File 'lib/cocoapods/validator.rb', line 1071

def parse_xcodebuild_output(output)
  lines = output.split("\n")
  selected_lines = lines.select do |l|
    l.include?('error: ') && (l !~ /errors? generated\./) && (l !~ /error: \(null\)/) ||
      l.include?('warning: ') && (l !~ /warnings? generated\./) && (l !~ /frameworks only run on iOS 8/) ||
      l.include?('note: ') && (l !~ /expanded from macro/)
  end
  selected_lines.map do |l|
    new = l.force_encoding('UTF-8').gsub(%r{#{validation_dir}/Pods/}, '')
    new.gsub!(/^ */, ' ')
  end
end

#perform_extensive_analysis(spec) ⇒ Object (private)

Perform analysis for a given spec (or subspec)



385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/cocoapods/validator.rb', line 385

def perform_extensive_analysis(spec)
  if spec.non_library_specification?
    error('spec', "Validating a non library spec (`#{spec.name}`) is not supported.")
    return false
  end
  validate_homepage(spec)
  validate_screenshots(spec)
  validate_social_media_url(spec)
  validate_documentation_url(spec)
  validate_source_url(spec)

  platforms = platforms_to_lint(spec)

  valid = platforms.send(fail_fast ? :all? : :each) do |platform|
    UI.message "\n\n#{spec} - Analyzing on #{platform} platform.".green.reversed
    @consumer = spec.consumer(platform)
    setup_validation_environment
    begin
      create_app_project
      download_pod
      check_file_patterns
      install_pod
      validate_swift_version
      add_app_project_import
      validate_vendored_dynamic_frameworks
      build_pod
      test_pod unless skip_tests
    ensure
      tear_down_validation_environment
    end
    validated?
  end
  return false if fail_fast && !valid
  perform_extensive_subspec_analysis(spec) unless @no_subspecs
rescue => e
  message = e.to_s
  message << "\n" << e.backtrace.join("\n") << "\n" if config.verbose?
  error('unknown', "Encountered an unknown error (#{message}) during validation.")
  false
end

#perform_extensive_subspec_analysis(spec) ⇒ Object (private)

Recursively perform the extensive analysis on all subspecs



428
429
430
431
432
433
# File 'lib/cocoapods/validator.rb', line 428

def perform_extensive_subspec_analysis(spec)
  spec.subspecs.reject(&:non_library_specification?).send(fail_fast ? :all? : :each) do |subspec|
    @subspec_name = subspec.name
    perform_extensive_analysis(subspec)
  end
end

#perform_lintingObject (private)



378
379
380
381
# File 'lib/cocoapods/validator.rb', line 378

def perform_linting
  linter.lint
  @results.concat(linter.results.to_a)
end

#platform_name_match?(platform, name) ⇒ Boolean (private)

Whether the provided name matches the platform

Parameters:

  • platform (Platform)

    The platform

  • name (String)

    The name to check against the provided platform

Returns:

  • (Boolean)


1171
1172
1173
# File 'lib/cocoapods/validator.rb', line 1171

def platform_name_match?(platform, name)
  [platform.name, platform.string_name].any? { |n| n.casecmp(name) == 0 }
end

#platforms_to_lint(spec) ⇒ Array<Platform>

Returns a list of platforms to lint for a given Specification

Parameters:

Returns:

  • (Array<Platform>)

    platforms to lint for the given specification



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/cocoapods/validator.rb', line 85

def platforms_to_lint(spec)
  return spec.available_platforms if @platforms.empty?

  # Validate that the platforms specified are actually supported by the spec
  results = @platforms.map do |platform|
    matching_platform = spec.available_platforms.find { |p| p.name == platform.name }
    unless matching_platform
      raise Informative, "Platform `#{platform}` is not supported by specification `#{spec}`."
    end
    matching_platform
  end.uniq

  results
end

#podfile_from_spec(platform_name, deployment_target, use_frameworks = true, test_spec_names = [], use_modular_headers = false, use_static_frameworks = false) ⇒ Podfile (private)

Note:

The generated podfile takes into account whether the linter is in local mode.

Returns a podfile that requires the specification on the current platform.

Parameters:

  • platform_name (String)

    the name of the platform, which should be declared in the Podfile.

  • deployment_target (String)

    the deployment target, which should be declared in the Podfile.

  • use_frameworks (Boolean) (defaults to: true)

    whether frameworks should be used for the installation

  • test_spec_names (Array<String>) (defaults to: [])

    the test spec names to include in the podfile.

Returns:

  • (Podfile)

    a podfile that requires the specification on the current platform.



1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
# File 'lib/cocoapods/validator.rb', line 1012

def podfile_from_spec(platform_name, deployment_target, use_frameworks = true, test_spec_names = [], use_modular_headers = false, use_static_frameworks = false)
  name     = subspec_name || spec.name
  podspec  = file.realpath
  local    = local?
  urls     = source_urls

  additional_podspec_pods = external_podspecs ? Dir.glob(external_podspecs) : []
  additional_path_pods = (include_podspecs ? Dir.glob(include_podspecs) : []) .select { |path| spec.name != Specification.from_file(path).name } - additional_podspec_pods

  Pod::Podfile.new do
    install! 'cocoapods', :deterministic_uuids => false, :warn_for_unused_master_specs_repo => false
    # By default inhibit warnings for all pods, except the one being validated.
    inhibit_all_warnings!
    urls.each { |u| source(u) }
    target 'App' do
      if use_static_frameworks
        use_frameworks!(:linkage => :static)
      else
        use_frameworks!(use_frameworks)
      end
      use_modular_headers! if use_modular_headers
      platform(platform_name, deployment_target)
      if local
        pod name, :path => podspec.dirname.to_s, :inhibit_warnings => false
      else
        pod name, :podspec => podspec.to_s, :inhibit_warnings => false
      end

      additional_path_pods.each do |podspec_path|
        podspec_name = File.basename(podspec_path, '.*')
        pod podspec_name, :path => File.dirname(podspec_path)
      end

      additional_podspec_pods.each do |podspec_path|
        podspec_name = File.basename(podspec_path, '.*')
        pod podspec_name, :podspec => podspec_path
      end

      test_spec_names.each do |test_spec_name|
        if local
          pod test_spec_name, :path => podspec.dirname.to_s, :inhibit_warnings => false
        else
          pod test_spec_name, :podspec => podspec.to_s, :inhibit_warnings => false
        end
      end
    end
  end
end

This method returns an undefined value.

Prints the result of the validation to the user.



140
141
142
# File 'lib/cocoapods/validator.rb', line 140

def print_results
  UI.puts results_message
end

#result_colorSymbol

Returns The color, which should been used to display the result. One of: :green, :yellow, :red.

Returns:

  • (Symbol)

    The color, which should been used to display the result. One of: :green, :yellow, :red.



315
316
317
318
319
320
# File 'lib/cocoapods/validator.rb', line 315

def result_color
  case result_type
  when :error   then :red
  when :warning then :yellow
  else :green end
end

#result_typeSymbol

Returns The type, which should been used to display the result. One of: :error, :warning, :note.

Returns:

  • (Symbol)

    The type, which should been used to display the result. One of: :error, :warning, :note.



302
303
304
305
306
307
308
309
310
# File 'lib/cocoapods/validator.rb', line 302

def result_type
  applicable_results = results
  applicable_results = applicable_results.reject(&:public_only?) if ignore_public_only_results
  types              = applicable_results.map(&:type).uniq
  if    types.include?(:error)   then :error
  elsif types.include?(:warning) then :warning
  else  :note
  end
end

#results_messageObject



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/cocoapods/validator.rb', line 144

def results_message
  message = ''
  results.each do |result|
    if result.platforms == [:ios]
      platform_message = '[iOS] '
    elsif result.platforms == [:osx]
      platform_message = '[OSX] '
    elsif result.platforms == [:watchos]
      platform_message = '[watchOS] '
    elsif result.platforms == [:tvos]
      platform_message = '[tvOS] '
    elsif result.platforms == [:visionos]
      platform_message = '[visionOS] '
    end

    subspecs_message = ''
    if result.is_a?(Result)
      subspecs = result.subspecs.uniq
      if subspecs.count > 2
        subspecs_message = '[' + subspecs[0..2].join(', ') + ', and more...] '
      elsif subspecs.count > 0
        subspecs_message = '[' + subspecs.join(',') + '] '
      end
    end

    case result.type
    when :error   then type = 'ERROR'
    when :warning then type = 'WARN'
    when :note    then type = 'NOTE'
    else raise "#{result.type}" end
    message << "    - #{type.ljust(5)} | #{platform_message}#{subspecs_message}#{result.attribute_name}: #{result.message}\n"
  end
  message << "\n"
end

#setup_validation_environmentObject (private)



547
548
549
550
551
552
553
# File 'lib/cocoapods/validator.rb', line 547

def setup_validation_environment
  validation_dir.rmtree if validation_dir.exist?
  validation_dir.mkpath
  @original_config = Config.instance.clone
  config.installation_root   = validation_dir
  config.silent              = !config.verbose
end

#shares_pod_target_xcscheme?(pod_target) ⇒ Boolean (private)

Returns:

  • (Boolean)


954
955
956
# File 'lib/cocoapods/validator.rb', line 954

def shares_pod_target_xcscheme?(pod_target)
  Pathname.new(@installer.pods_project.path + pod_target.label).exist?
end

#specSpecification

Returns the specification to lint.

Returns:



67
68
69
# File 'lib/cocoapods/validator.rb', line 67

def spec
  @linter.spec
end

#supported_platform?(platform, spec) ⇒ Boolean (private)

Whether the platform is supported by the specification

Parameters:

  • platform (Platform)

    The platform to check

  • spec (Specification)

    The specification which must support the provided platform

Returns:

  • (Boolean)

    Whether the platform is supported by the specification



1157
1158
1159
1160
1161
# File 'lib/cocoapods/validator.rb', line 1157

def supported_platform?(platform, spec)
  available_platforms = spec.available_platforms

  available_platforms.any? { |p| p.name == platform.name }
end

#tear_down_validation_environmentObject (private)



555
556
557
558
# File 'lib/cocoapods/validator.rb', line 555

def tear_down_validation_environment
  clean! unless no_clean
  Config.instance = @original_config
end

#test_podvoid (private)

Note:

Xcode warnings are treated as notes because the spec maintainer might not be the author of the library

This method returns an undefined value.

Builds and runs all test sources associated with the current specification being validated.



759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
# File 'lib/cocoapods/validator.rb', line 759

def test_pod
  if !xcodebuild_available?
    UI.warn "Skipping test validation with `xcodebuild` because it can't be found.\n".yellow
  else
    UI.message "\nTesting with `xcodebuild`.\n".yellow do
      pod_target = validation_pod_target
      all_test_specs = consumer.spec.test_specs
      unless test_specs.nil?
        test_spec_names = all_test_specs.map(&:base_name)
        all_test_specs.select! { |test_spec| test_specs.include? test_spec.base_name }
        test_specs.each do |test_spec|
          unless test_spec_names.include? test_spec
            UI.warn "Requested test spec `#{test_spec}` does not exist in the podspec. Existing test specs are `#{test_spec_names}`"
          end
        end
      end
      all_test_specs.each do |test_spec|
        if !test_spec.supported_on_platform?(consumer.platform_name)
          UI.warn "Skipping test spec `#{test_spec.name}` on platform `#{consumer.platform_name}` since it is not supported.\n".yellow
        else
          scheme = @installer.target_installation_results.first[pod_target.name].native_target_for_spec(test_spec)
          output = xcodebuild('test', scheme, 'Debug', :deployment_target => test_spec.deployment_target(consumer.platform_name))
          parsed_output = parse_xcodebuild_output(output)
          translate_output_to_linter_messages(parsed_output)
        end
      end
    end
  end
end

#translate_output_to_linter_messages(parsed_output) ⇒ Object (private)



931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
# File 'lib/cocoapods/validator.rb', line 931

def translate_output_to_linter_messages(parsed_output)
  parsed_output.each do |message|
    # Checking the error for `InputFile` is to work around an Xcode
    # issue where linting would fail even though `xcodebuild` actually
    # succeeds. Xcode.app also doesn't fail when this issue occurs, so
    # it's safe for us to do the same.
    #
    # For more details see https://github.com/CocoaPods/CocoaPods/issues/2394#issuecomment-56658587
    #
    if message.include?("'InputFile' should have")
      next
    end

    if message =~ /\S+:\d+:\d+: error:/
      error('xcodebuild', message)
    elsif message =~ /\S+:\d+:\d+: warning:/
      warning('xcodebuild', message)
    else
      note('xcodebuild', message)
    end
  end
end

#uses_swift?Boolean

Returns Whether any of the pod targets part of this validator use Swift or not.

Returns:

  • (Boolean)

    Whether any of the pod targets part of this validator use Swift or not.



366
367
368
# File 'lib/cocoapods/validator.rb', line 366

def uses_swift?
  @installer.pod_targets.any?(&:uses_swift?)
end

#valid_platform?(platform) ⇒ Boolean (private)

Whether the platform with the specified name is valid

Parameters:

  • platform (Platform)

    The platform to check

Returns:

  • (Boolean)

    True if the platform is valid



1143
1144
1145
# File 'lib/cocoapods/validator.rb', line 1143

def valid_platform?(platform)
  VALID_PLATFORMS.any? { |p| p.name == platform.name }
end

#validateBoolean

Note:

This method shows immediately which pod is being processed and overrides the printed line once the result is known.

Lints the specification adding a Result for any failed check to the #results list.

Returns:

  • (Boolean)

    whether the specification passed validation.



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/cocoapods/validator.rb', line 114

def validate
  @results = []

  # Replace default spec with a subspec if asked for
  a_spec = spec
  if spec && @only_subspec
    subspec_name = @only_subspec.start_with?("#{spec.root.name}/") ? @only_subspec : "#{spec.root.name}/#{@only_subspec}"
    a_spec = spec.subspec_by_name(subspec_name, true, true)
    @subspec_name = a_spec.name
  end

  UI.print " -> #{a_spec ? a_spec.name : file.basename}\r" unless config.silent?
  $stdout.flush

  perform_linting
  perform_extensive_analysis(a_spec) if a_spec && !quick

  UI.puts ' -> '.send(result_color) << (a_spec ? a_spec.to_s : file.basename.to_s)
  print_results
  validated?
end

#validate_documentation_url(spec) ⇒ Object (private)

Performs validations related to the documentation_url attribute.



484
485
486
# File 'lib/cocoapods/validator.rb', line 484

def validate_documentation_url(spec)
  validate_url(spec.documentation_url) if spec.documentation_url
end

#validate_dynamic_framework_support(aggregate_targets, deployment_target) ⇒ Object (private)

Produces an error of dynamic frameworks were requested but are not supported by the deployment target

Parameters:

  • aggregate_targets (Array<AggregateTarget>)

    The aggregate targets installed by the installer

  • deployment_target (String, Version)

    The deployment target of the installation



687
688
689
690
691
692
693
694
695
696
# File 'lib/cocoapods/validator.rb', line 687

def validate_dynamic_framework_support(aggregate_targets, deployment_target)
  return unless consumer.platform_name == :ios
  return unless deployment_target.nil? || Version.new(deployment_target).major < 8
  aggregate_targets.each do |target|
    if target.pod_targets.any?(&:uses_swift?)
      uses_xctest = target.spec_consumers.any? { |c| (c.frameworks + c.weak_frameworks).include? 'XCTest' }
      error('swift', 'Swift support uses dynamic frameworks and is therefore only supported on iOS > 8.') unless uses_xctest
    end
  end
end

#validate_homepage(spec) ⇒ Object (private)

Performs validations related to the homepage attribute.



459
460
461
462
463
# File 'lib/cocoapods/validator.rb', line 459

def validate_homepage(spec)
  if spec.homepage
    validate_url(spec.homepage)
  end
end

#validate_nonempty_patterns(attr_name, message_type) ⇒ Object (private)

Validates that the file patterns in attr_name match at least 1 file.

Parameters:

  • attr_name (String, Symbol)

    the name of the attribute to check (ex. :public_header_files)

  • message_type (String, Symbol)

    the type of message to send if the patterns are empty (ex. :error)



825
826
827
828
829
# File 'lib/cocoapods/validator.rb', line 825

def validate_nonempty_patterns(attr_name, message_type)
  return unless !file_accessor.spec_consumer.send(attr_name).empty? && file_accessor.send(attr_name).empty?

  add_result(message_type, 'file patterns', "The `#{attr_name}` pattern did not match any file.")
end

#validate_screenshots(spec) ⇒ Object (private)

Performs validation related to the screenshots attribute.



467
468
469
470
471
472
473
474
# File 'lib/cocoapods/validator.rb', line 467

def validate_screenshots(spec)
  spec.screenshots.compact.each do |screenshot|
    response = validate_url(screenshot)
    if response && !(response.headers['content-type'] && response.headers['content-type'].first =~ /image\/.*/i)
      warning('screenshot', "The screenshot #{screenshot} is not a valid image.")
    end
  end
end

#validate_social_media_url(spec) ⇒ Object (private)

Performs validations related to the social_media_url attribute.



478
479
480
# File 'lib/cocoapods/validator.rb', line 478

def validate_social_media_url(spec)
  validate_url(spec.social_media_url, 'CocoaPods') if spec.social_media_url
end

#validate_source_url(spec) ⇒ Object (private)

Performs validations related to the source -> http attribute (if exists)



490
491
492
493
494
495
496
497
# File 'lib/cocoapods/validator.rb', line 490

def validate_source_url(spec)
  return if spec.source.nil? || spec.source[:http].nil?
  url = URI(spec.source[:http])
  return if url.scheme == 'https' || url.scheme == 'file'
  warning('http', "The URL (`#{url}`) doesn't use the encrypted HTTPS protocol. " \
          'It is crucial for Pods to be transferred over a secure protocol to protect your users from man-in-the-middle attacks. '\
          'This will be an error in future releases. Please update the URL to use https.')
end

#validate_swift_versionObject (private)

Performs validation for the version of Swift used during validation.

An error will be displayed if the user has provided a swift_versions attribute within the podspec but is also using either --swift-version parameter or a .swift-version file with a Swift version that is not declared within the attribute.

The user will be warned that the default version of Swift was used if the following things are true:

  • The project uses Swift at all
  • The user did not supply a Swift version via a parameter
  • There is no swift_versions attribute set within the specification
  • There is no .swift-version file present either.


511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
# File 'lib/cocoapods/validator.rb', line 511

def validate_swift_version
  return unless uses_swift?
  spec_swift_versions = spec.swift_versions.map(&:to_s)

  unless spec_swift_versions.empty?
    message = nil
    if !dot_swift_version.nil? && !spec_swift_versions.include?(dot_swift_version)
      message = "Specification `#{spec.name}` specifies inconsistent `swift_versions` (#{spec_swift_versions.map { |s| "`#{s}`" }.to_sentence}) compared to the one present in your `.swift-version` file (`#{dot_swift_version}`). " \
                'Please remove the `.swift-version` file which is now deprecated and only use the `swift_versions` attribute within your podspec.'
    elsif !swift_version.nil? && !spec_swift_versions.include?(swift_version)
      message = "Specification `#{spec.name}` specifies inconsistent `swift_versions` (#{spec_swift_versions.map { |s| "`#{s}`" }.to_sentence}) compared to the one passed during lint (`#{swift_version}`)."
    end
    unless message.nil?
      error('swift', message)
      return
    end
  end

  if swift_version.nil? && spec.swift_versions.empty?
    if !dot_swift_version.nil?
      # The user will be warned to delete the `.swift-version` file in favor of the `swift_versions` DSL attribute.
      # This is intentionally not a lint warning since we do not want to break existing setups and instead just soft
      # deprecate this slowly.
      #
      UI.warn 'Usage of the `.swift_version` file has been deprecated! Please delete the file and use the ' \
        "`swift_versions` attribute within your podspec instead.\n".yellow
    else
      warning('swift',
              'The validator used ' \
              "Swift `#{DEFAULT_SWIFT_VERSION}` by default because no Swift version was specified. " \
              'To specify a Swift version during validation, add the `swift_versions` attribute in your podspec. ' \
              'Note that usage of a `.swift-version` file is now deprecated.')
    end
  end
end

#validate_url(url, user_agent = nil) ⇒ Object (private)

Performs validation of a URL



445
446
447
448
449
450
451
452
453
454
455
# File 'lib/cocoapods/validator.rb', line 445

def validate_url(url, user_agent = nil)
  resp = Pod::HTTP.validate_url(url, user_agent)

  if !resp
    warning('url', "There was a problem validating the URL #{url}.", true)
  elsif !resp.success?
    note('url', "The URL (#{url}) is not reachable.", true)
  end

  resp
end

#validate_vendored_dynamic_frameworksObject (private)



698
699
700
701
702
703
704
705
706
707
708
709
# File 'lib/cocoapods/validator.rb', line 698

def validate_vendored_dynamic_frameworks
  deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name)

  unless file_accessor.nil?
    dynamic_frameworks = file_accessor.vendored_dynamic_frameworks
    dynamic_libraries = file_accessor.vendored_dynamic_libraries
    if (dynamic_frameworks.count > 0 || dynamic_libraries.count > 0) && consumer.platform_name == :ios &&
        (deployment_target.nil? || Version.new(deployment_target).major < 8)
      error('dynamic', 'Dynamic frameworks and libraries are only supported on iOS 8.0 and onwards.')
    end
  end
end

#validated?Boolean

Returns:

  • (Boolean)


295
296
297
# File 'lib/cocoapods/validator.rb', line 295

def validated?
  result_type != :error && (result_type != :warning || allow_warnings)
end

#validation_dirPathname

Returns the temporary directory used by the linter.

Returns:

  • (Pathname)

    the temporary directory used by the linter.



324
325
326
# File 'lib/cocoapods/validator.rb', line 324

def validation_dir
  @validation_dir ||= Pathname(Dir.mktmpdir(['CocoaPods-Lint-', "-#{spec.name}"]))
end

#validation_dir=(validation_dir) ⇒ Object



328
329
330
# File 'lib/cocoapods/validator.rb', line 328

def validation_dir=(validation_dir)
  @validation_dir = Pathname(validation_dir) unless validation_dir.nil?
end

#validation_pod_targetObject (private)

Returns the pod target for the pod being validated. Installation must have occurred before this can be invoked.



626
627
628
# File 'lib/cocoapods/validator.rb', line 626

def validation_pod_target
  @installer.pod_targets.find { |pt| pt.pod_name == spec.root.name }
end

#warning(*args) ⇒ Object (private)



923
924
925
# File 'lib/cocoapods/validator.rb', line 923

def warning(*args)
  add_result(:warning, *args)
end

#xcodebuild(action, scheme, configuration, deployment_target:) ⇒ String (private)

Executes xcodebuild in the current working directory and returns its output (both STDOUT and STDERR).

Returns:

  • (String)

    Executes xcodebuild in the current working directory and returns its output (both STDOUT and STDERR).



1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
# File 'lib/cocoapods/validator.rb', line 1087

def xcodebuild(action, scheme, configuration, deployment_target:)
  require 'fourflusher'
  command = %W(clean #{action} -workspace #{File.join(validation_dir, 'App.xcworkspace')} -scheme #{scheme} -configuration #{configuration})
  case consumer.platform_name
  when :osx, :macos
    command += %w(CODE_SIGN_IDENTITY=)
  when :ios
    command += %w(CODE_SIGN_IDENTITY=- -sdk iphonesimulator)
    command += Fourflusher::SimControl.new.destination(:oldest, 'iOS', deployment_target)
    xcconfig = consumer.pod_target_xcconfig
    if xcconfig
      archs = xcconfig['VALID_ARCHS']
      if archs && (archs.include? 'armv7') && !(archs.include? 'i386') && (archs.include? 'x86_64')
        # Prevent Xcodebuild from testing the non-existent i386 simulator if armv7 is specified without i386
        command += %w(ARCHS=x86_64)
      end
    end
  when :watchos
    command += %w(CODE_SIGN_IDENTITY=- -sdk watchsimulator)
  when :tvos
    command += %w(CODE_SIGN_IDENTITY=- -sdk appletvsimulator)
    command += Fourflusher::SimControl.new.destination(:oldest, 'tvOS', deployment_target)
  when :visionos
    command += %w(CODE_SIGN_IDENTITY=- -sdk xrsimulator)
    command += Fourflusher::SimControl.new.destination(:oldest, 'visionOS', deployment_target)
  end

  if analyze
    command += %w(CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR=analyzer)
  end

  begin
    _xcodebuild(command, true)
  rescue => e
    message = 'Returned an unsuccessful exit code.'
    message += ' You can use `--verbose` for more information.' unless config.verbose?
    error('xcodebuild', message)
    e.message
  end
end

#xcodebuild_available?Boolean (private)

Returns:

  • (Boolean)


789
790
791
# File 'lib/cocoapods/validator.rb', line 789

def xcodebuild_available?
  !Executable.which('xcodebuild').nil? && ENV['COCOAPODS_VALIDATOR_SKIP_XCODEBUILD'].nil?
end