317 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			317 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # typed: true
 | |
| # frozen_string_literal: true
 | |
| 
 | |
| require "livecheck/livecheck"
 | |
| 
 | |
| module Homebrew
 | |
|   module Livecheck
 | |
|     # The `Livecheck::SkipConditions` module primarily contains methods that
 | |
|     # check for various formula/cask/resource conditions where a check should be skipped.
 | |
|     #
 | |
|     # @api private
 | |
|     module SkipConditions
 | |
|       module_function
 | |
| 
 | |
|       sig {
 | |
|         params(
 | |
|           package_or_resource: T.any(Formula, Cask::Cask, Resource),
 | |
|           livecheckable:       T::Boolean,
 | |
|           full_name:           T::Boolean,
 | |
|           verbose:             T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def package_or_resource_skip(package_or_resource, livecheckable, full_name: false, verbose: false)
 | |
|         formula = package_or_resource if package_or_resource.is_a?(Formula)
 | |
| 
 | |
|         if (stable_url = formula&.stable&.url)
 | |
|           stable_is_gist = stable_url.match?(%r{https?://gist\.github(?:usercontent)?\.com/}i)
 | |
|           stable_from_google_code_archive = stable_url.match?(
 | |
|             %r{https?://storage\.googleapis\.com/google-code-archive-downloads/}i,
 | |
|           )
 | |
|           stable_from_internet_archive = stable_url.match?(%r{https?://web\.archive\.org/}i)
 | |
|         end
 | |
| 
 | |
|         skip_message = if package_or_resource.livecheck.skip_msg.present?
 | |
|           package_or_resource.livecheck.skip_msg
 | |
|         elsif !livecheckable
 | |
|           if stable_from_google_code_archive
 | |
|             "Stable URL is from Google Code Archive"
 | |
|           elsif stable_from_internet_archive
 | |
|             "Stable URL is from Internet Archive"
 | |
|           elsif stable_is_gist
 | |
|             "Stable URL is a GitHub Gist"
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         return {} if !package_or_resource.livecheck.skip? && skip_message.blank?
 | |
| 
 | |
|         skip_messages = skip_message ? [skip_message] : nil
 | |
|         Livecheck.status_hash(package_or_resource, "skipped", skip_messages, full_name: full_name, verbose: verbose)
 | |
|       end
 | |
| 
 | |
|       sig {
 | |
|         params(
 | |
|           formula:        Formula,
 | |
|           _livecheckable: T::Boolean,
 | |
|           full_name:      T::Boolean,
 | |
|           verbose:        T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def formula_head_only(formula, _livecheckable, full_name: false, verbose: false)
 | |
|         return {} if !formula.head_only? || formula.any_version_installed?
 | |
| 
 | |
|         Livecheck.status_hash(
 | |
|           formula,
 | |
|           "error",
 | |
|           ["HEAD only formula must be installed to be livecheckable"],
 | |
|           full_name: full_name,
 | |
|           verbose:   verbose,
 | |
|         )
 | |
|       end
 | |
| 
 | |
|       sig {
 | |
|         params(
 | |
|           formula:       Formula,
 | |
|           livecheckable: T::Boolean,
 | |
|           full_name:     T::Boolean,
 | |
|           verbose:       T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def formula_deprecated(formula, livecheckable, full_name: false, verbose: false)
 | |
|         return {} if !formula.deprecated? || livecheckable
 | |
| 
 | |
|         Livecheck.status_hash(formula, "deprecated", full_name: full_name, verbose: verbose)
 | |
|       end
 | |
| 
 | |
|       sig {
 | |
|         params(
 | |
|           formula:       Formula,
 | |
|           livecheckable: T::Boolean,
 | |
|           full_name:     T::Boolean,
 | |
|           verbose:       T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def formula_disabled(formula, livecheckable, full_name: false, verbose: false)
 | |
|         return {} if !formula.disabled? || livecheckable
 | |
| 
 | |
|         Livecheck.status_hash(formula, "disabled", full_name: full_name, verbose: verbose)
 | |
|       end
 | |
| 
 | |
|       sig {
 | |
|         params(
 | |
|           formula:       Formula,
 | |
|           livecheckable: T::Boolean,
 | |
|           full_name:     T::Boolean,
 | |
|           verbose:       T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def formula_versioned(formula, livecheckable, full_name: false, verbose: false)
 | |
|         return {} if !formula.versioned_formula? || livecheckable
 | |
| 
 | |
|         Livecheck.status_hash(formula, "versioned", full_name: full_name, verbose: verbose)
 | |
|       end
 | |
| 
 | |
|       sig {
 | |
|         params(
 | |
|           cask:          Cask::Cask,
 | |
|           livecheckable: T::Boolean,
 | |
|           full_name:     T::Boolean,
 | |
|           verbose:       T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def cask_discontinued(cask, livecheckable, full_name: false, verbose: false)
 | |
|         return {} if !cask.discontinued? || livecheckable
 | |
| 
 | |
|         Livecheck.status_hash(cask, "discontinued", full_name: full_name, verbose: verbose)
 | |
|       end
 | |
| 
 | |
|       sig {
 | |
|         params(
 | |
|           cask:          Cask::Cask,
 | |
|           livecheckable: T::Boolean,
 | |
|           full_name:     T::Boolean,
 | |
|           verbose:       T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def cask_deprecated(cask, livecheckable, full_name: false, verbose: false)
 | |
|         return {} if !cask.deprecated? || livecheckable
 | |
| 
 | |
|         Livecheck.status_hash(cask, "deprecated", full_name: full_name, verbose: verbose)
 | |
|       end
 | |
| 
 | |
|       sig {
 | |
|         params(
 | |
|           cask:          Cask::Cask,
 | |
|           livecheckable: T::Boolean,
 | |
|           full_name:     T::Boolean,
 | |
|           verbose:       T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def cask_disabled(cask, livecheckable, full_name: false, verbose: false)
 | |
|         return {} if !cask.disabled? || livecheckable
 | |
| 
 | |
|         Livecheck.status_hash(cask, "disabled", full_name: full_name, verbose: verbose)
 | |
|       end
 | |
| 
 | |
|       sig {
 | |
|         params(
 | |
|           cask:          Cask::Cask,
 | |
|           livecheckable: T::Boolean,
 | |
|           full_name:     T::Boolean,
 | |
|           verbose:       T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def cask_version_latest(cask, livecheckable, full_name: false, verbose: false)
 | |
|         return {} if !(cask.present? && cask.version&.latest?) || livecheckable
 | |
| 
 | |
|         Livecheck.status_hash(cask, "latest", full_name: full_name, verbose: verbose)
 | |
|       end
 | |
| 
 | |
|       sig {
 | |
|         params(
 | |
|           cask:          Cask::Cask,
 | |
|           livecheckable: T::Boolean,
 | |
|           full_name:     T::Boolean,
 | |
|           verbose:       T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def cask_url_unversioned(cask, livecheckable, full_name: false, verbose: false)
 | |
|         return {} if !(cask.present? && cask.url&.unversioned?) || livecheckable
 | |
| 
 | |
|         Livecheck.status_hash(cask, "unversioned", full_name: full_name, verbose: verbose)
 | |
|       end
 | |
| 
 | |
|       # Skip conditions for formulae.
 | |
|       FORMULA_CHECKS = [
 | |
|         :package_or_resource_skip,
 | |
|         :formula_head_only,
 | |
|         :formula_deprecated,
 | |
|         :formula_disabled,
 | |
|         :formula_versioned,
 | |
|       ].freeze
 | |
| 
 | |
|       # Skip conditions for casks.
 | |
|       CASK_CHECKS = [
 | |
|         :package_or_resource_skip,
 | |
|         :cask_discontinued,
 | |
|         :cask_deprecated,
 | |
|         :cask_disabled,
 | |
|         :cask_version_latest,
 | |
|         :cask_url_unversioned,
 | |
|       ].freeze
 | |
| 
 | |
|       # Skip conditions for resources.
 | |
|       RESOURCE_CHECKS = [
 | |
|         :package_or_resource_skip,
 | |
|       ].freeze
 | |
| 
 | |
|       # If a formula/cask/resource should be skipped, we return a hash from
 | |
|       # `Livecheck#status_hash`, which contains a `status` type and sometimes
 | |
|       # error `messages`.
 | |
|       sig {
 | |
|         params(
 | |
|           package_or_resource: T.any(Formula, Cask::Cask, Resource),
 | |
|           full_name:           T::Boolean,
 | |
|           verbose:             T::Boolean,
 | |
|         ).returns(Hash)
 | |
|       }
 | |
|       def skip_information(package_or_resource, full_name: false, verbose: false)
 | |
|         livecheckable = package_or_resource.livecheckable?
 | |
| 
 | |
|         checks = case package_or_resource
 | |
|         when Formula
 | |
|           FORMULA_CHECKS
 | |
|         when Cask::Cask
 | |
|           CASK_CHECKS
 | |
|         when Resource
 | |
|           RESOURCE_CHECKS
 | |
|         end
 | |
|         return {} unless checks
 | |
| 
 | |
|         checks.each do |method_name|
 | |
|           skip_hash = send(method_name, package_or_resource, livecheckable, full_name: full_name, verbose: verbose)
 | |
|           return skip_hash if skip_hash.present?
 | |
|         end
 | |
| 
 | |
|         {}
 | |
|       end
 | |
| 
 | |
|       # Skip conditions for formulae/casks/resources referenced in a `livecheck` block
 | |
|       # are treated differently than normal. We only respect certain skip
 | |
|       # conditions (returning the related hash) and others are treated as
 | |
|       # errors.
 | |
|       sig {
 | |
|         params(
 | |
|           livecheck_package_or_resource:     T.any(Formula, Cask::Cask, Resource),
 | |
|           original_package_or_resource_name: String,
 | |
|           full_name:                         T::Boolean,
 | |
|           verbose:                           T::Boolean,
 | |
|         ).returns(T.nilable(Hash))
 | |
|       }
 | |
|       def referenced_skip_information(
 | |
|         livecheck_package_or_resource,
 | |
|         original_package_or_resource_name,
 | |
|         full_name: false,
 | |
|         verbose: false
 | |
|       )
 | |
|         skip_info = SkipConditions.skip_information(
 | |
|           livecheck_package_or_resource,
 | |
|           full_name: full_name,
 | |
|           verbose:   verbose,
 | |
|         )
 | |
|         return if skip_info.blank?
 | |
| 
 | |
|         referenced_name = Livecheck.package_or_resource_name(livecheck_package_or_resource, full_name: full_name)
 | |
|         referenced_type = case livecheck_package_or_resource
 | |
|         when Formula
 | |
|           :formula
 | |
|         when Cask::Cask
 | |
|           :cask
 | |
|         when Resource
 | |
|           :resource
 | |
|         end
 | |
| 
 | |
|         if skip_info[:status] != "error" &&
 | |
|            !(skip_info[:status] == "skipped" && livecheck_package_or_resource.livecheck.skip?)
 | |
|           error_msg_end = if skip_info[:status] == "skipped"
 | |
|             "automatically skipped"
 | |
|           else
 | |
|             "skipped as #{skip_info[:status]}"
 | |
|           end
 | |
| 
 | |
|           raise "Referenced #{referenced_type} (#{referenced_name}) is #{error_msg_end}"
 | |
|         end
 | |
| 
 | |
|         skip_info[referenced_type] = original_package_or_resource_name
 | |
|         skip_info
 | |
|       end
 | |
| 
 | |
|       # Prints default livecheck output in relation to skip conditions.
 | |
|       sig { params(skip_hash: Hash).void }
 | |
|       def print_skip_information(skip_hash)
 | |
|         return unless skip_hash.is_a?(Hash)
 | |
| 
 | |
|         name = if skip_hash[:formula].is_a?(String)
 | |
|           skip_hash[:formula]
 | |
|         elsif skip_hash[:cask].is_a?(String)
 | |
|           skip_hash[:cask]
 | |
|         elsif skip_hash[:resource].is_a?(String)
 | |
|           "  #{skip_hash[:resource]}"
 | |
|         end
 | |
|         return unless name
 | |
| 
 | |
|         if skip_hash[:messages].is_a?(Array) && skip_hash[:messages].count.positive?
 | |
|           # TODO: Handle multiple messages, only if needed in the future
 | |
|           if skip_hash[:status] == "skipped"
 | |
|             puts "#{Tty.red}#{name}#{Tty.reset}: skipped - #{skip_hash[:messages][0]}"
 | |
|           else
 | |
|             puts "#{Tty.red}#{name}#{Tty.reset}: #{skip_hash[:messages][0]}"
 | |
|           end
 | |
|         elsif skip_hash[:status].present?
 | |
|           puts "#{Tty.red}#{name}#{Tty.reset}: #{skip_hash[:status]}"
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 | 
