| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  | # typed: true | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-19 20:36:41 +01:00
										 |  |  | require "livecheck/error" | 
					
						
							| 
									
										
										
										
											2021-01-22 12:25:13 -08:00
										 |  |  | require "livecheck/livecheck_version" | 
					
						
							| 
									
										
										
										
											2021-01-07 15:30:22 -05:00
										 |  |  | require "livecheck/skip_conditions" | 
					
						
							| 
									
										
										
										
											2020-08-27 22:46:06 +05:30
										 |  |  | require "livecheck/strategy" | 
					
						
							| 
									
										
										
										
											2020-09-03 00:41:16 +05:30
										 |  |  | require "ruby-progressbar" | 
					
						
							| 
									
										
										
										
											2020-11-07 03:18:42 +01:00
										 |  |  | require "uri" | 
					
						
							| 
									
										
										
										
											2020-08-27 22:46:06 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | module Homebrew | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |   # rubocop:disable Metrics/ModuleLength | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # The {Livecheck} module consists of methods used by the `brew livecheck` | 
					
						
							|  |  |  |   # command. These methods print the requested livecheck information | 
					
						
							| 
									
										
										
										
											2020-08-27 22:46:06 +05:30
										 |  |  |   # for formulae. | 
					
						
							|  |  |  |   # | 
					
						
							|  |  |  |   # @api private | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |   module Livecheck | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |     extend T::Sig | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |     module_function | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-11 02:32:44 +01:00
										 |  |  |     GITEA_INSTANCES = %w[
 | 
					
						
							|  |  |  |       codeberg.org | 
					
						
							|  |  |  |       gitea.com | 
					
						
							|  |  |  |       opendev.org | 
					
						
							|  |  |  |       tildegit.org | 
					
						
							|  |  |  |     ].freeze | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     GOGS_INSTANCES = %w[
 | 
					
						
							|  |  |  |       lolg.it | 
					
						
							|  |  |  |     ].freeze | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-05 11:44:28 -05:00
										 |  |  |     STRATEGY_SYMBOLS_TO_SKIP_PREPROCESS_URL = [ | 
					
						
							|  |  |  |       :github_latest, | 
					
						
							|  |  |  |       :page_match, | 
					
						
							| 
									
										
										
										
											2021-01-06 12:34:30 +01:00
										 |  |  |       :header_match, | 
					
						
							| 
									
										
										
										
											2020-12-19 00:51:54 -05:00
										 |  |  |       :sparkle, | 
					
						
							| 
									
										
										
										
											2020-12-05 11:44:28 -05:00
										 |  |  |     ].freeze | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |     UNSTABLE_VERSION_KEYWORDS = %w[
 | 
					
						
							|  |  |  |       alpha | 
					
						
							|  |  |  |       beta | 
					
						
							|  |  |  |       bpo | 
					
						
							|  |  |  |       dev | 
					
						
							|  |  |  |       experimental | 
					
						
							|  |  |  |       prerelease | 
					
						
							|  |  |  |       preview | 
					
						
							|  |  |  |       rc | 
					
						
							|  |  |  |     ].freeze | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |     sig { returns(T::Hash[Class, String]) } | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |     def livecheck_strategy_names | 
					
						
							|  |  |  |       return @livecheck_strategy_names if defined?(@livecheck_strategy_names) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Cache demodulized strategy names, to avoid repeating this work | 
					
						
							|  |  |  |       @livecheck_strategy_names = {} | 
					
						
							| 
									
										
										
										
											2021-08-09 18:18:12 -04:00
										 |  |  |       Strategy.constants.sort.each do |const_symbol| | 
					
						
							|  |  |  |         constant = Strategy.const_get(const_symbol) | 
					
						
							|  |  |  |         next unless constant.is_a?(Class) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @livecheck_strategy_names[constant] = T.must(constant.name).demodulize | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |       end | 
					
						
							|  |  |  |       @livecheck_strategy_names.freeze | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-24 19:07:17 +05:30
										 |  |  |     # Uses `formulae_and_casks_to_check` to identify taps in use other than | 
					
						
							|  |  |  |     # homebrew/core and homebrew/cask and loads strategies from them. | 
					
						
							| 
									
										
										
										
											2021-03-04 01:01:56 +05:30
										 |  |  |     sig { params(formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)]).void } | 
					
						
							| 
									
										
										
										
											2021-01-11 08:29:34 +05:30
										 |  |  |     def load_other_tap_strategies(formulae_and_casks_to_check) | 
					
						
							|  |  |  |       other_taps = {} | 
					
						
							|  |  |  |       formulae_and_casks_to_check.each do |formula_or_cask| | 
					
						
							|  |  |  |         next if formula_or_cask.tap.blank? | 
					
						
							|  |  |  |         next if formula_or_cask.tap.name == CoreTap.instance.name | 
					
						
							|  |  |  |         next if formula_or_cask.tap.name == "homebrew/cask" | 
					
						
							|  |  |  |         next if other_taps[formula_or_cask.tap.name] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         other_taps[formula_or_cask.tap.name] = formula_or_cask.tap | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       other_taps = other_taps.sort.to_h | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       other_taps.each_value do |tap| | 
					
						
							|  |  |  |         tap_strategy_path = "#{tap.path}/livecheck/strategy" | 
					
						
							|  |  |  |         Dir["#{tap_strategy_path}/*.rb"].sort.each(&method(:require)) if Dir.exist?(tap_strategy_path) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |     # Resolve formula/cask references in `livecheck` blocks to a final formula | 
					
						
							|  |  |  |     # or cask. | 
					
						
							|  |  |  |     sig { | 
					
						
							|  |  |  |       params( | 
					
						
							|  |  |  |         formula_or_cask:       T.any(Formula, Cask::Cask), | 
					
						
							|  |  |  |         first_formula_or_cask: T.any(Formula, Cask::Cask), | 
					
						
							|  |  |  |         references:            T::Array[T.any(Formula, Cask::Cask)], | 
					
						
							|  |  |  |         full_name:             T::Boolean, | 
					
						
							|  |  |  |         debug:                 T::Boolean, | 
					
						
							|  |  |  |       ).returns(T.nilable(T::Array[T.untyped])) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     def resolve_livecheck_reference( | 
					
						
							|  |  |  |       formula_or_cask, | 
					
						
							|  |  |  |       first_formula_or_cask = formula_or_cask, | 
					
						
							|  |  |  |       references = [], | 
					
						
							|  |  |  |       full_name: false, | 
					
						
							|  |  |  |       debug: false | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |       # Check the livecheck block for a formula or cask reference | 
					
						
							|  |  |  |       livecheck = formula_or_cask.livecheck | 
					
						
							|  |  |  |       livecheck_formula = livecheck.formula | 
					
						
							|  |  |  |       livecheck_cask = livecheck.cask | 
					
						
							|  |  |  |       return [nil, references] if livecheck_formula.blank? && livecheck_cask.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Load the referenced formula or cask | 
					
						
							|  |  |  |       referenced_formula_or_cask = if livecheck_formula | 
					
						
							|  |  |  |         Formulary.factory(livecheck_formula) | 
					
						
							|  |  |  |       elsif livecheck_cask | 
					
						
							|  |  |  |         Cask::CaskLoader.load(livecheck_cask) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Error if a `livecheck` block references a formula/cask that was already | 
					
						
							|  |  |  |       # referenced (or itself) | 
					
						
							|  |  |  |       if referenced_formula_or_cask == first_formula_or_cask || | 
					
						
							|  |  |  |          referenced_formula_or_cask == formula_or_cask || | 
					
						
							|  |  |  |          references.include?(referenced_formula_or_cask) | 
					
						
							|  |  |  |         if debug | 
					
						
							|  |  |  |           # Print the chain of references for debugging | 
					
						
							|  |  |  |           puts "Reference Chain:" | 
					
						
							|  |  |  |           puts formula_or_cask_name(first_formula_or_cask, full_name: full_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           references << referenced_formula_or_cask | 
					
						
							|  |  |  |           references.each do |ref_formula_or_cask| | 
					
						
							|  |  |  |             puts formula_or_cask_name(ref_formula_or_cask, full_name: full_name) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         raise "Circular formula/cask reference encountered" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       references << referenced_formula_or_cask | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Check the referenced formula/cask for a reference | 
					
						
							|  |  |  |       next_referenced_formula_or_cask, next_references = resolve_livecheck_reference( | 
					
						
							|  |  |  |         referenced_formula_or_cask, | 
					
						
							|  |  |  |         first_formula_or_cask, | 
					
						
							|  |  |  |         references, | 
					
						
							|  |  |  |         full_name: full_name, | 
					
						
							|  |  |  |         debug:     debug, | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Returning references along with the final referenced formula/cask | 
					
						
							|  |  |  |       # allows us to print the chain of references in the debug output | 
					
						
							|  |  |  |       [ | 
					
						
							|  |  |  |         next_referenced_formula_or_cask || referenced_formula_or_cask, | 
					
						
							|  |  |  |         next_references, | 
					
						
							|  |  |  |       ] | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |     # Executes the livecheck logic for each formula/cask in the | 
					
						
							|  |  |  |     # `formulae_and_casks_to_check` array and prints the results. | 
					
						
							| 
									
										
										
										
											2021-01-17 22:45:55 -08:00
										 |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |       params( | 
					
						
							| 
									
										
										
										
											2021-03-04 01:01:56 +05:30
										 |  |  |         formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)], | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |         full_name:                   T::Boolean, | 
					
						
							| 
									
										
										
										
											2021-02-18 15:05:01 +05:30
										 |  |  |         handle_name_conflict:        T::Boolean, | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |         json:                        T::Boolean, | 
					
						
							|  |  |  |         newer_only:                  T::Boolean, | 
					
						
							|  |  |  |         debug:                       T::Boolean, | 
					
						
							|  |  |  |         quiet:                       T::Boolean, | 
					
						
							|  |  |  |         verbose:                     T::Boolean, | 
					
						
							|  |  |  |       ).void | 
					
						
							| 
									
										
										
										
											2021-01-17 22:45:55 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |     def run_checks( | 
					
						
							|  |  |  |       formulae_and_casks_to_check, | 
					
						
							| 
									
										
										
										
											2021-02-18 15:05:01 +05:30
										 |  |  |       full_name: false, handle_name_conflict: false, json: false, newer_only: false, | 
					
						
							|  |  |  |       debug: false, quiet: false, verbose: false | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |     ) | 
					
						
							| 
									
										
										
										
											2021-01-11 08:29:34 +05:30
										 |  |  |       load_other_tap_strategies(formulae_and_casks_to_check) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-04 01:01:56 +05:30
										 |  |  |       ambiguous_casks = [] | 
					
						
							|  |  |  |       if handle_name_conflict | 
					
						
							| 
									
										
										
										
											2021-03-04 23:54:25 +05:30
										 |  |  |         ambiguous_casks = formulae_and_casks_to_check.group_by { |item| formula_or_cask_name(item, full_name: true) } | 
					
						
							|  |  |  |                                                      .values | 
					
						
							|  |  |  |                                                      .select { |items| items.length > 1 } | 
					
						
							|  |  |  |                                                      .flatten | 
					
						
							|  |  |  |                                                      .select { |item| item.is_a?(Cask::Cask) } | 
					
						
							| 
									
										
										
										
											2021-03-04 01:01:56 +05:30
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-04 01:39:37 +05:30
										 |  |  |       ambiguous_names = [] | 
					
						
							|  |  |  |       unless full_name | 
					
						
							| 
									
										
										
										
											2021-03-04 23:54:25 +05:30
										 |  |  |         ambiguous_names = | 
					
						
							|  |  |  |           (formulae_and_casks_to_check - ambiguous_casks).group_by { |item| formula_or_cask_name(item) } | 
					
						
							|  |  |  |                                                          .values | 
					
						
							|  |  |  |                                                          .select { |items| items.length > 1 } | 
					
						
							|  |  |  |                                                          .flatten | 
					
						
							| 
									
										
										
										
											2021-03-04 01:39:37 +05:30
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |       has_a_newer_upstream_version = T.let(false, T::Boolean) | 
					
						
							| 
									
										
										
										
											2020-09-03 00:41:16 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |       if json && !quiet && $stderr.tty? | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |         formulae_and_casks_total = formulae_and_casks_to_check.count | 
					
						
							| 
									
										
										
										
											2020-09-03 00:41:16 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-18 02:39:52 +05:30
										 |  |  |         Tty.with($stderr) do |stderr| | 
					
						
							|  |  |  |           stderr.puts Formatter.headline("Running checks", color: :blue) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 00:41:16 +05:30
										 |  |  |         progress = ProgressBar.create( | 
					
						
							| 
									
										
										
										
											2020-12-12 10:29:25 -05:00
										 |  |  |           total:          formulae_and_casks_total, | 
					
						
							| 
									
										
										
										
											2020-09-03 00:41:16 +05:30
										 |  |  |           progress_mark:  "#", | 
					
						
							|  |  |  |           remainder_mark: ".", | 
					
						
							|  |  |  |           format:         " %t: [%B] %c/%C ", | 
					
						
							|  |  |  |           output:         $stderr, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |       # rubocop:disable Metrics/BlockLength | 
					
						
							| 
									
										
										
										
											2020-09-03 20:33:24 -07:00
										 |  |  |       formulae_checked = formulae_and_casks_to_check.map.with_index do |formula_or_cask, i| | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |         formula = formula_or_cask if formula_or_cask.is_a?(Formula) | 
					
						
							|  |  |  |         cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask) | 
					
						
							| 
									
										
										
										
											2021-03-04 01:39:37 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |         use_full_name = full_name || ambiguous_names.include?(formula_or_cask) | 
					
						
							|  |  |  |         name = formula_or_cask_name(formula_or_cask, full_name: use_full_name) | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |         referenced_formula_or_cask, livecheck_references = | 
					
						
							|  |  |  |           resolve_livecheck_reference(formula_or_cask, full_name: use_full_name, debug: debug) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         if debug && i.positive? | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           puts <<~EOS | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ---------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           EOS | 
					
						
							| 
									
										
										
										
											2021-02-18 15:05:01 +05:30
										 |  |  |         elsif debug | 
					
						
							|  |  |  |           puts | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |         # Check skip conditions for a referenced formula/cask | 
					
						
							|  |  |  |         if referenced_formula_or_cask | 
					
						
							|  |  |  |           skip_info = SkipConditions.referenced_skip_information( | 
					
						
							|  |  |  |             referenced_formula_or_cask, | 
					
						
							|  |  |  |             name, | 
					
						
							|  |  |  |             full_name: use_full_name, | 
					
						
							|  |  |  |             verbose:   verbose, | 
					
						
							|  |  |  |           ) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         skip_info ||= SkipConditions.skip_information(formula_or_cask, full_name: use_full_name, verbose: verbose) | 
					
						
							| 
									
										
										
										
											2021-01-07 15:30:22 -05:00
										 |  |  |         if skip_info.present? | 
					
						
							|  |  |  |           next skip_info if json | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           SkipConditions.print_skip_information(skip_info) unless quiet | 
					
						
							|  |  |  |           next | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-11 16:27:53 +01:00
										 |  |  |         formula&.head&.downloader&.shutup! | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 13:27:12 +05:30
										 |  |  |         # Use the `stable` version for comparison except for installed | 
					
						
							|  |  |  |         # head-only formulae. A formula with `stable` and `head` that's | 
					
						
							|  |  |  |         # installed using `--head` will still use the `stable` version for | 
					
						
							|  |  |  |         # comparison. | 
					
						
							| 
									
										
										
										
											2020-12-11 18:58:01 +01:00
										 |  |  |         current = if formula | 
					
						
							| 
									
										
										
										
											2020-12-11 16:24:49 +01:00
										 |  |  |           if formula.head_only? | 
					
						
							|  |  |  |             formula.any_installed_version.version.commit | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             formula.stable.version | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           Version.new(formula_or_cask.version) | 
					
						
							| 
									
										
										
										
											2020-08-31 09:59:02 -07:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-17 11:24:52 -08:00
										 |  |  |         current_str = current.to_s | 
					
						
							| 
									
										
										
										
											2021-01-20 09:06:37 -08:00
										 |  |  |         current = LivecheckVersion.create(formula_or_cask, current) | 
					
						
							| 
									
										
										
										
											2021-01-17 11:24:52 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-12 10:30:20 -05:00
										 |  |  |         latest = if formula&.head_only? | 
					
						
							|  |  |  |           formula.head.downloader.fetch_last_commit | 
					
						
							|  |  |  |         else | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |           version_info = latest_version( | 
					
						
							|  |  |  |             formula_or_cask, | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |             referenced_formula_or_cask: referenced_formula_or_cask, | 
					
						
							|  |  |  |             livecheck_references: livecheck_references, | 
					
						
							|  |  |  |             json: json, full_name: use_full_name, verbose: verbose, debug: debug | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |           ) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           version_info[:latest] if version_info.present? | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if latest.blank? | 
					
						
							|  |  |  |           no_versions_msg = "Unable to get versions" | 
					
						
							| 
									
										
										
										
											2020-12-19 20:36:41 +01:00
										 |  |  |           raise Livecheck::Error, no_versions_msg unless json | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |           next version_info if version_info.is_a?(Hash) && version_info[:status] && version_info[:messages] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-04 01:39:37 +05:30
										 |  |  |           next status_hash(formula_or_cask, "error", [no_versions_msg], full_name: use_full_name, verbose: verbose) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (m = latest.to_s.match(/(.*)-release$/)) && !current.to_s.match(/.*-release$/) | 
					
						
							|  |  |  |           latest = Version.new(m[1]) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-17 11:24:52 -08:00
										 |  |  |         latest_str = latest.to_s | 
					
						
							| 
									
										
										
										
											2021-01-20 09:06:37 -08:00
										 |  |  |         latest = LivecheckVersion.create(formula_or_cask, latest) | 
					
						
							| 
									
										
										
										
											2021-01-17 11:24:52 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |         is_outdated = if formula&.head_only? | 
					
						
							| 
									
										
										
										
											2020-08-29 00:32:34 +05:30
										 |  |  |           # A HEAD-only formula is considered outdated if the latest upstream | 
					
						
							|  |  |  |           # commit hash is different than the installed version's commit hash | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           (current != latest) | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           (current < latest) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |         is_newer_than_upstream = (formula&.stable? || cask) && (current > latest) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-12 11:00:02 -05:00
										 |  |  |         info = {} | 
					
						
							| 
									
										
										
										
											2021-01-07 15:30:22 -05:00
										 |  |  |         info[:formula] = name if formula | 
					
						
							|  |  |  |         info[:cask] = name if cask | 
					
						
							| 
									
										
										
										
											2020-12-12 11:00:02 -05:00
										 |  |  |         info[:version] = { | 
					
						
							| 
									
										
										
										
											2021-01-17 11:24:52 -08:00
										 |  |  |           current:             current_str, | 
					
						
							|  |  |  |           latest:              latest_str, | 
					
						
							| 
									
										
										
										
											2020-12-12 11:00:02 -05:00
										 |  |  |           outdated:            is_outdated, | 
					
						
							|  |  |  |           newer_than_upstream: is_newer_than_upstream, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         info[:meta] = { | 
					
						
							|  |  |  |           livecheckable: formula_or_cask.livecheckable?, | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |         info[:meta][:head_only] = true if formula&.head_only? | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         info[:meta].merge!(version_info[:meta]) if version_info.present? && version_info.key?(:meta) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         next if newer_only && !info[:version][:outdated] | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |         has_a_newer_upstream_version ||= true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         if json | 
					
						
							| 
									
										
										
										
											2020-09-03 00:41:16 +05:30
										 |  |  |           progress&.increment | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |           info.except!(:meta) unless verbose | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           next info | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-04 01:01:56 +05:30
										 |  |  |         print_latest_version(info, verbose: verbose, ambiguous_cask: ambiguous_casks.include?(formula_or_cask)) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         nil | 
					
						
							|  |  |  |       rescue => e | 
					
						
							|  |  |  |         Homebrew.failed = true | 
					
						
							| 
									
										
										
										
											2021-03-04 01:39:37 +05:30
										 |  |  |         use_full_name = full_name || ambiguous_names.include?(formula_or_cask) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         if json | 
					
						
							| 
									
										
										
										
											2020-09-03 00:41:16 +05:30
										 |  |  |           progress&.increment | 
					
						
							| 
									
										
										
										
											2021-03-04 01:39:37 +05:30
										 |  |  |           status_hash(formula_or_cask, "error", [e.to_s], full_name: use_full_name, verbose: verbose) | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         elsif !quiet | 
					
						
							| 
									
										
										
										
											2021-03-04 01:39:37 +05:30
										 |  |  |           name = formula_or_cask_name(formula_or_cask, full_name: use_full_name) | 
					
						
							| 
									
										
										
										
											2021-03-04 01:01:56 +05:30
										 |  |  |           name += " (cask)" if ambiguous_casks.include?(formula_or_cask) | 
					
						
							| 
									
										
										
										
											2021-02-27 22:39:12 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |           onoe "#{Tty.blue}#{name}#{Tty.reset}: #{e}" | 
					
						
							| 
									
										
										
										
											2020-12-19 20:36:41 +01:00
										 |  |  |           $stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           nil | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |       # rubocop:enable Metrics/BlockLength | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |       puts "No newer upstream versions." if newer_only && !has_a_newer_upstream_version && !debug && !json | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |       return unless json | 
					
						
							| 
									
										
										
										
											2020-09-03 00:41:16 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |       if progress | 
					
						
							|  |  |  |         progress.finish | 
					
						
							| 
									
										
										
										
											2020-09-18 02:39:52 +05:30
										 |  |  |         Tty.with($stderr) do |stderr| | 
					
						
							|  |  |  |           stderr.print "#{Tty.up}#{Tty.erase_line}" * 2
 | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-09-03 00:41:16 +05:30
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-09 14:06:21 +01:00
										 |  |  |       puts JSON.pretty_generate(formulae_checked.compact) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |     sig { params(formula_or_cask: T.any(Formula, Cask::Cask), full_name: T::Boolean).returns(String) } | 
					
						
							|  |  |  |     def formula_or_cask_name(formula_or_cask, full_name: false) | 
					
						
							| 
									
										
										
										
											2020-12-12 11:36:43 -05:00
										 |  |  |       case formula_or_cask | 
					
						
							|  |  |  |       when Formula | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         formula_name(formula_or_cask, full_name: full_name) | 
					
						
							| 
									
										
										
										
											2020-12-12 11:36:43 -05:00
										 |  |  |       when Cask::Cask | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         cask_name(formula_or_cask, full_name: full_name) | 
					
						
							| 
									
										
										
										
											2021-01-17 11:24:52 -08:00
										 |  |  |       else | 
					
						
							|  |  |  |         T.absurd(formula_or_cask) | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |     # Returns the fully-qualified name of a cask if the `full_name` argument is | 
					
						
							|  |  |  |     # provided; returns the name otherwise. | 
					
						
							|  |  |  |     sig { params(cask: Cask::Cask, full_name: T::Boolean).returns(String) } | 
					
						
							|  |  |  |     def cask_name(cask, full_name: false) | 
					
						
							|  |  |  |       full_name ? cask.full_name : cask.token | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |     # Returns the fully-qualified name of a formula if the `full_name` argument is | 
					
						
							|  |  |  |     # provided; returns the name otherwise. | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |     sig { params(formula: Formula, full_name: T::Boolean).returns(String) } | 
					
						
							|  |  |  |     def formula_name(formula, full_name: false) | 
					
						
							|  |  |  |       full_name ? formula.full_name : formula.name | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-17 22:45:55 -08:00
										 |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |       params( | 
					
						
							|  |  |  |         formula_or_cask: T.any(Formula, Cask::Cask), | 
					
						
							|  |  |  |         status_str:      String, | 
					
						
							|  |  |  |         messages:        T.nilable(T::Array[String]), | 
					
						
							|  |  |  |         full_name:       T::Boolean, | 
					
						
							|  |  |  |         verbose:         T::Boolean, | 
					
						
							|  |  |  |       ).returns(Hash) | 
					
						
							| 
									
										
										
										
											2021-01-17 22:45:55 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |     def status_hash(formula_or_cask, status_str, messages = nil, full_name: false, verbose: false) | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |       formula = formula_or_cask if formula_or_cask.is_a?(Formula) | 
					
						
							| 
									
										
										
										
											2020-12-12 11:36:43 -05:00
										 |  |  |       cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask) | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-12 11:00:02 -05:00
										 |  |  |       status_hash = {} | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |       if formula | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         status_hash[:formula] = formula_name(formula, full_name: full_name) | 
					
						
							| 
									
										
										
										
											2020-12-12 11:36:43 -05:00
										 |  |  |       elsif cask | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         status_hash[:cask] = cask_name(formula_or_cask, full_name: full_name) | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-12-12 11:00:02 -05:00
										 |  |  |       status_hash[:status] = status_str | 
					
						
							|  |  |  |       status_hash[:messages] = messages if messages.is_a?(Array) | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |       status_hash[:meta] = { | 
					
						
							|  |  |  |         livecheckable: formula_or_cask.livecheckable?, | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       status_hash[:meta][:head_only] = true if formula&.head_only? | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |       status_hash | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-27 22:46:06 +05:30
										 |  |  |     # Formats and prints the livecheck result for a formula. | 
					
						
							| 
									
										
										
										
											2021-03-04 01:01:56 +05:30
										 |  |  |     sig { params(info: Hash, verbose: T::Boolean, ambiguous_cask: T::Boolean).void } | 
					
						
							|  |  |  |     def print_latest_version(info, verbose:, ambiguous_cask: false) | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |       formula_or_cask_s = "#{Tty.blue}#{info[:formula] || info[:cask]}#{Tty.reset}" | 
					
						
							| 
									
										
										
										
											2021-03-04 01:01:56 +05:30
										 |  |  |       formula_or_cask_s += " (cask)" if ambiguous_cask | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |       formula_or_cask_s += " (guessed)" if !info[:meta][:livecheckable] && verbose | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |       current_s = if info[:version][:newer_than_upstream] | 
					
						
							|  |  |  |         "#{Tty.red}#{info[:version][:current]}#{Tty.reset}" | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         info[:version][:current] | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       latest_s = if info[:version][:outdated] | 
					
						
							|  |  |  |         "#{Tty.green}#{info[:version][:latest]}#{Tty.reset}" | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         info[:version][:latest] | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |       puts "#{formula_or_cask_s} : #{current_s} ==> #{latest_s}" | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-17 22:45:55 -08:00
										 |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2021-01-12 15:00:49 -05:00
										 |  |  |       params( | 
					
						
							|  |  |  |         livecheck_url:   T.any(String, Symbol), | 
					
						
							|  |  |  |         formula_or_cask: T.any(Formula, Cask::Cask), | 
					
						
							|  |  |  |       ).returns(T.nilable(String)) | 
					
						
							| 
									
										
										
										
											2021-01-17 22:45:55 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-12 15:00:49 -05:00
										 |  |  |     def livecheck_url_to_string(livecheck_url, formula_or_cask) | 
					
						
							|  |  |  |       case livecheck_url | 
					
						
							|  |  |  |       when String | 
					
						
							|  |  |  |         livecheck_url | 
					
						
							|  |  |  |       when :url | 
					
						
							|  |  |  |         formula_or_cask.url&.to_s if formula_or_cask.is_a?(Cask::Cask) | 
					
						
							|  |  |  |       when :head, :stable | 
					
						
							|  |  |  |         formula_or_cask.send(livecheck_url)&.url if formula_or_cask.is_a?(Formula) | 
					
						
							|  |  |  |       when :homepage | 
					
						
							|  |  |  |         formula_or_cask.homepage | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 20:43:21 -07:00
										 |  |  |     # Returns an Array containing the formula/cask URLs that can be used by livecheck. | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |     sig { params(formula_or_cask: T.any(Formula, Cask::Cask)).returns(T::Array[String]) } | 
					
						
							| 
									
										
										
										
											2020-09-03 20:43:21 -07:00
										 |  |  |     def checkable_urls(formula_or_cask) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |       urls = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 20:43:21 -07:00
										 |  |  |       case formula_or_cask | 
					
						
							|  |  |  |       when Formula | 
					
						
							|  |  |  |         if formula_or_cask.stable | 
					
						
							|  |  |  |           urls << formula_or_cask.stable.url | 
					
						
							|  |  |  |           urls.concat(formula_or_cask.stable.mirrors) | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2021-02-04 15:41:29 -05:00
										 |  |  |         urls << formula_or_cask.head.url if formula_or_cask.head | 
					
						
							| 
									
										
										
										
											2020-09-03 20:43:21 -07:00
										 |  |  |         urls << formula_or_cask.homepage if formula_or_cask.homepage | 
					
						
							|  |  |  |       when Cask::Cask | 
					
						
							|  |  |  |         urls << formula_or_cask.appcast.to_s if formula_or_cask.appcast | 
					
						
							|  |  |  |         urls << formula_or_cask.url.to_s if formula_or_cask.url | 
					
						
							|  |  |  |         urls << formula_or_cask.homepage if formula_or_cask.homepage | 
					
						
							| 
									
										
										
										
											2021-01-17 11:24:52 -08:00
										 |  |  |       else | 
					
						
							|  |  |  |         T.absurd(formula_or_cask) | 
					
						
							| 
									
										
										
										
											2020-09-03 20:43:21 -07:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |       urls.compact | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-27 22:46:06 +05:30
										 |  |  |     # Preprocesses and returns the URL used by livecheck. | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |     sig { params(url: String).returns(String) } | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |     def preprocess_url(url) | 
					
						
							| 
									
										
										
										
											2020-11-26 10:31:38 -05:00
										 |  |  |       begin | 
					
						
							|  |  |  |         uri = URI.parse url | 
					
						
							|  |  |  |       rescue URI::InvalidURIError | 
					
						
							|  |  |  |         return url | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |       host = uri.host | 
					
						
							|  |  |  |       path = uri.path | 
					
						
							|  |  |  |       return url if host.nil? || path.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       host = "github.com" if host == "github.s3.amazonaws.com" | 
					
						
							|  |  |  |       path = path.delete_prefix("/").delete_suffix(".git") | 
					
						
							| 
									
										
										
										
											2020-11-11 02:32:44 +01:00
										 |  |  |       scheme = uri.scheme | 
					
						
							| 
									
										
										
										
											2020-11-07 03:18:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-26 10:32:55 -05:00
										 |  |  |       if host.end_with?("github.com") | 
					
						
							| 
									
										
										
										
											2020-11-11 02:32:44 +01:00
										 |  |  |         return url if path.match? %r{/releases/latest/?$} | 
					
						
							| 
									
										
										
										
											2020-11-07 03:18:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-11 02:32:44 +01:00
										 |  |  |         owner, repo = path.delete_prefix("downloads/").split("/") | 
					
						
							|  |  |  |         url = "#{scheme}://#{host}/#{owner}/#{repo}.git" | 
					
						
							| 
									
										
										
										
											2020-11-26 10:32:55 -05:00
										 |  |  |       elsif host.end_with?(*GITEA_INSTANCES) | 
					
						
							| 
									
										
										
										
											2020-11-07 03:18:42 +01:00
										 |  |  |         return url if path.match? %r{/releases/latest/?$} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         owner, repo = path.split("/") | 
					
						
							| 
									
										
										
										
											2020-11-11 02:32:44 +01:00
										 |  |  |         url = "#{scheme}://#{host}/#{owner}/#{repo}.git" | 
					
						
							| 
									
										
										
										
											2020-11-26 10:32:55 -05:00
										 |  |  |       elsif host.end_with?(*GOGS_INSTANCES) | 
					
						
							| 
									
										
										
										
											2020-11-11 02:32:44 +01:00
										 |  |  |         owner, repo = path.split("/") | 
					
						
							|  |  |  |         url = "#{scheme}://#{host}/#{owner}/#{repo}.git" | 
					
						
							|  |  |  |       # sourcehut | 
					
						
							| 
									
										
										
										
											2020-11-26 10:32:55 -05:00
										 |  |  |       elsif host.end_with?("git.sr.ht") | 
					
						
							| 
									
										
										
										
											2020-11-07 03:18:42 +01:00
										 |  |  |         owner, repo = path.split("/") | 
					
						
							| 
									
										
										
										
											2020-11-11 02:32:44 +01:00
										 |  |  |         url = "#{scheme}://#{host}/#{owner}/#{repo}" | 
					
						
							| 
									
										
										
										
											2020-11-26 10:33:20 -05:00
										 |  |  |       # GitLab (gitlab.com or self-hosted) | 
					
						
							| 
									
										
										
										
											2020-11-11 02:32:44 +01:00
										 |  |  |       elsif path.include?("/-/archive/") | 
					
						
							|  |  |  |         url = url.sub(%r{/-/archive/.*$}i, ".git") | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       url | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-27 22:46:06 +05:30
										 |  |  |     # Identifies the latest version of the formula and returns a Hash containing | 
					
						
							|  |  |  |     # the version information. Returns nil if a latest version couldn't be found. | 
					
						
							| 
									
										
										
										
											2021-01-17 22:45:55 -08:00
										 |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |       params( | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |         formula_or_cask:            T.any(Formula, Cask::Cask), | 
					
						
							|  |  |  |         referenced_formula_or_cask: T.nilable(T.any(Formula, Cask::Cask)), | 
					
						
							|  |  |  |         livecheck_references:       T::Array[T.any(Formula, Cask::Cask)], | 
					
						
							|  |  |  |         json:                       T::Boolean, | 
					
						
							|  |  |  |         full_name:                  T::Boolean, | 
					
						
							|  |  |  |         verbose:                    T::Boolean, | 
					
						
							|  |  |  |         debug:                      T::Boolean, | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |       ).returns(T.nilable(Hash)) | 
					
						
							| 
									
										
										
										
											2021-01-17 22:45:55 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |     def latest_version( | 
					
						
							|  |  |  |       formula_or_cask, | 
					
						
							|  |  |  |       referenced_formula_or_cask: nil, | 
					
						
							|  |  |  |       livecheck_references: [], | 
					
						
							|  |  |  |       json: false, full_name: false, verbose: false, debug: false | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |       formula = formula_or_cask if formula_or_cask.is_a?(Formula) | 
					
						
							| 
									
										
										
										
											2020-12-12 11:36:43 -05:00
										 |  |  |       cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask) | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       has_livecheckable = formula_or_cask.livecheckable? | 
					
						
							|  |  |  |       livecheck = formula_or_cask.livecheck | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |       referenced_livecheck = referenced_formula_or_cask&.livecheck | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |       livecheck_url = livecheck.url || referenced_livecheck&.url | 
					
						
							|  |  |  |       livecheck_regex = livecheck.regex || referenced_livecheck&.regex | 
					
						
							|  |  |  |       livecheck_strategy = livecheck.strategy || referenced_livecheck&.strategy | 
					
						
							|  |  |  |       livecheck_strategy_block = livecheck.strategy_block || referenced_livecheck&.strategy_block | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       livecheck_url_string = livecheck_url_to_string( | 
					
						
							|  |  |  |         livecheck_url, | 
					
						
							|  |  |  |         referenced_formula_or_cask || formula_or_cask, | 
					
						
							|  |  |  |       ) | 
					
						
							| 
									
										
										
										
											2021-01-12 15:00:49 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |       urls = [livecheck_url_string] if livecheck_url_string | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |       urls ||= checkable_urls(referenced_formula_or_cask || formula_or_cask) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |       if debug | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |         if formula | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |           puts "Formula:          #{formula_name(formula, full_name: full_name)}" | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |           puts "Head only?:       true" if formula.head_only? | 
					
						
							| 
									
										
										
										
											2020-12-12 11:36:43 -05:00
										 |  |  |         elsif cask | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |           puts "Cask:             #{cask_name(formula_or_cask, full_name: full_name)}" | 
					
						
							| 
									
										
										
										
											2020-09-02 12:24:21 -07:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         puts "Livecheckable?:   #{has_livecheckable ? "Yes" : "No"}" | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         livecheck_references.each do |ref_formula_or_cask| | 
					
						
							|  |  |  |           case ref_formula_or_cask | 
					
						
							|  |  |  |           when Formula | 
					
						
							|  |  |  |             puts "Formula Ref:      #{formula_name(ref_formula_or_cask, full_name: full_name)}" | 
					
						
							|  |  |  |           when Cask::Cask | 
					
						
							|  |  |  |             puts "Cask Ref:         #{cask_name(ref_formula_or_cask, full_name: full_name)}" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |       # rubocop:disable Metrics/BlockLength | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |       urls.each_with_index do |original_url, i| | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         if debug | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           puts | 
					
						
							| 
									
										
										
										
											2021-01-12 15:00:49 -05:00
										 |  |  |           if livecheck_url.is_a?(Symbol) | 
					
						
							|  |  |  |             # This assumes the URL symbol will fit within the available space | 
					
						
							|  |  |  |             puts "URL (#{livecheck_url}):".ljust(18, " ") + original_url | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             puts "URL:              #{original_url}" | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-05 11:44:28 -05:00
										 |  |  |         # Only preprocess the URL when it's appropriate | 
					
						
							|  |  |  |         url = if STRATEGY_SYMBOLS_TO_SKIP_PREPROCESS_URL.include?(livecheck_strategy) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           original_url | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           preprocess_url(original_url) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-05 11:49:47 -05:00
										 |  |  |         strategies = Strategy.from_url( | 
					
						
							|  |  |  |           url, | 
					
						
							|  |  |  |           livecheck_strategy: livecheck_strategy, | 
					
						
							| 
									
										
										
										
											2020-12-14 02:09:23 +01:00
										 |  |  |           url_provided:       livecheck_url.present?, | 
					
						
							| 
									
										
										
										
											2020-12-05 11:49:47 -05:00
										 |  |  |           regex_provided:     livecheck_regex.present?, | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |           block_provided:     livecheck_strategy_block.present?, | 
					
						
							| 
									
										
										
										
											2020-12-05 11:49:47 -05:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-04-04 03:00:34 +02:00
										 |  |  |         strategy = Strategy.from_symbol(livecheck_strategy) || strategies.first | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         strategy_name = livecheck_strategy_names[strategy] | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         if debug | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           puts "URL (processed):  #{url}" if url != original_url | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |           if strategies.present? && verbose | 
					
						
							|  |  |  |             puts "Strategies:       #{strategies.map { |s| livecheck_strategy_names[s] }.join(", ")}" | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           end | 
					
						
							|  |  |  |           puts "Strategy:         #{strategy.blank? ? "None" : strategy_name}" | 
					
						
							|  |  |  |           puts "Regex:            #{livecheck_regex.inspect}" if livecheck_regex.present? | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-04 03:00:34 +02:00
										 |  |  |         if livecheck_strategy.present? | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |           if livecheck_strategy == :page_match && (livecheck_regex.blank? && livecheck_strategy_block.blank?) | 
					
						
							| 
									
										
										
										
											2021-04-04 03:00:34 +02:00
										 |  |  |             odebug "#{strategy_name} strategy requires a regex or block" | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           elsif livecheck_url.blank? | 
					
						
							|  |  |  |             odebug "#{strategy_name} strategy requires a URL" | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           elsif strategies.exclude?(strategy) | 
					
						
							|  |  |  |             odebug "#{strategy_name} strategy does not apply to this URL" | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         next if strategy.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 11:54:29 -04:00
										 |  |  |         strategy_data = strategy.find_versions( | 
					
						
							|  |  |  |           url:   url, | 
					
						
							|  |  |  |           regex: livecheck_regex, | 
					
						
							|  |  |  |           cask:  cask, | 
					
						
							|  |  |  |           &livecheck_strategy_block | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         match_version_map = strategy_data[:matches] | 
					
						
							|  |  |  |         regex = strategy_data[:regex] | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |         messages = strategy_data[:messages] | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |         if messages.is_a?(Array) && match_version_map.blank? | 
					
						
							|  |  |  |           puts messages unless json | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           next if i + 1 < urls.length | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:19 -08:00
										 |  |  |           return status_hash(formula_or_cask, "error", messages, full_name: full_name, verbose: verbose) | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         if debug | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           puts "URL (strategy):   #{strategy_data[:url]}" if strategy_data[:url] != url | 
					
						
							| 
									
										
										
										
											2020-12-24 15:00:57 -05:00
										 |  |  |           puts "URL (final):      #{strategy_data[:final_url]}" if strategy_data[:final_url] | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           puts "Regex (strategy): #{strategy_data[:regex].inspect}" if strategy_data[:regex] != livecheck_regex | 
					
						
							| 
									
										
										
										
											2020-12-24 22:19:14 -05:00
										 |  |  |           puts "Cached?:          Yes" if strategy_data[:cached] == true | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         match_version_map.delete_if do |_match, version| | 
					
						
							|  |  |  |           next true if version.blank? | 
					
						
							|  |  |  |           next false if has_livecheckable | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           UNSTABLE_VERSION_KEYWORDS.any? do |rejection| | 
					
						
							|  |  |  |             version.to_s.include?(rejection) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-04 03:00:34 +02:00
										 |  |  |         next if match_version_map.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if debug | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           puts | 
					
						
							|  |  |  |           puts "Matched Versions:" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |           if verbose | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |             match_version_map.each do |match, version| | 
					
						
							|  |  |  |               puts "#{match} => #{version.inspect}" | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             puts match_version_map.values.join(", ") | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         version_info = { | 
					
						
							| 
									
										
										
										
											2021-01-20 09:06:37 -08:00
										 |  |  |           latest: Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(formula_or_cask, v) }), | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |         if json && verbose | 
					
						
							| 
									
										
										
										
											2021-01-12 15:00:49 -05:00
										 |  |  |           version_info[:meta] = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |           if livecheck_references.present? | 
					
						
							|  |  |  |             version_info[:meta][:references] = livecheck_references.map do |ref_formula_or_cask| | 
					
						
							|  |  |  |               case ref_formula_or_cask | 
					
						
							|  |  |  |               when Formula | 
					
						
							|  |  |  |                 { formula: formula_name(ref_formula_or_cask, full_name: full_name) } | 
					
						
							|  |  |  |               when Cask::Cask | 
					
						
							|  |  |  |                 { cask: cask_name(ref_formula_or_cask, full_name: full_name) } | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-12 15:00:49 -05:00
										 |  |  |           version_info[:meta][:url] = {} | 
					
						
							|  |  |  |           version_info[:meta][:url][:symbol] = livecheck_url if livecheck_url.is_a?(Symbol) && livecheck_url_string | 
					
						
							|  |  |  |           version_info[:meta][:url][:original] = original_url | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           version_info[:meta][:url][:processed] = url if url != original_url | 
					
						
							| 
									
										
										
										
											2021-08-12 11:54:29 -04:00
										 |  |  |           if strategy_data[:url].present? && strategy_data[:url] != url | 
					
						
							|  |  |  |             version_info[:meta][:url][:strategy] = strategy_data[:url] | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-12-22 22:46:52 -05:00
										 |  |  |           version_info[:meta][:url][:final] = strategy_data[:final_url] if strategy_data[:final_url] | 
					
						
							| 
									
										
										
										
											2021-01-12 15:00:49 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |           version_info[:meta][:strategy] = strategy.present? ? strategy_name : nil | 
					
						
							| 
									
										
										
										
											2020-12-14 14:30:36 +01:00
										 |  |  |           version_info[:meta][:strategies] = strategies.map { |s| livecheck_strategy_names[s] } if strategies.present? | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |           version_info[:meta][:regex] = regex.inspect if regex.present? | 
					
						
							| 
									
										
										
										
											2020-12-24 22:19:14 -05:00
										 |  |  |           version_info[:meta][:cached] = true if strategy_data[:cached] == true | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return version_info | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |       # rubocop:enable Metrics/BlockLength | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |       nil | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2021-07-19 11:21:29 -04:00
										 |  |  |   # rubocop:enable Metrics/ModuleLength | 
					
						
							| 
									
										
										
										
											2020-08-08 07:10:48 +05:30
										 |  |  | end |