Merge pull request #10651 from nandahkrishna/formula-cask-disambiguation

livecheck and bump: formula/cask disambiguation
This commit is contained in:
Mike McQuaid 2021-03-15 11:37:34 +00:00 committed by GitHub
commit 3afa9b078e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 126 additions and 61 deletions

View File

@ -16,6 +16,8 @@ module Homebrew
Display out-of-date brew formulae and the latest version available.
Also displays whether a pull request has been opened with the URL.
EOS
switch "--full-name",
description: "Print formulae/casks with fully-qualified names."
switch "--no-pull-requests",
description: "Do not retrieve pull requests from GitHub."
switch "--formula", "--formulae",
@ -39,11 +41,14 @@ module Homebrew
end
formulae_and_casks = if args.formula?
args.named.to_formulae.presence
args.named.to_formulae
elsif args.cask?
args.named.to_casks.presence
args.named.to_casks
else
args.named.to_formulae_and_casks.presence
args.named.to_formulae_and_casks
end
formulae_and_casks = formulae_and_casks&.sort_by do |formula_or_cask|
formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
end
limit = args.limit.to_i if args.limit.present?
@ -51,10 +56,29 @@ module Homebrew
if formulae_and_casks
Livecheck.load_other_tap_strategies(formulae_and_casks)
ambiguous_casks = []
if !args.formula? && !args.cask?
ambiguous_casks = formulae_and_casks.group_by { |item| Livecheck.formula_or_cask_name(item, full_name: true) }
.values
.select { |items| items.length > 1 }
.flatten
.select { |item| item.is_a?(Cask::Cask) }
end
ambiguous_names = []
unless args.full_name?
ambiguous_names =
(formulae_and_casks - ambiguous_casks).group_by { |item| Livecheck.formula_or_cask_name(item) }
.values
.select { |items| items.length > 1 }
.flatten
end
formulae_and_casks.each_with_index do |formula_or_cask, i|
puts if i.positive?
name = Livecheck.formula_or_cask_name(formula_or_cask)
use_full_name = args.full_name? || ambiguous_names.include?(formula_or_cask)
name = Livecheck.formula_or_cask_name(formula_or_cask, full_name: use_full_name)
repository = if formula_or_cask.is_a?(Formula)
if formula_or_cask.head_only?
ohai name
@ -68,7 +92,13 @@ module Homebrew
end
package_data = Repology.single_package_query(name, repository: repository)
retrieve_and_display_info(formula_or_cask, name, package_data&.values&.first, args: args)
retrieve_and_display_info(
formula_or_cask,
name,
package_data&.values&.first,
args: args,
ambiguous_cask: ambiguous_casks.include?(formula_or_cask),
)
end
else
api_response = {}
@ -105,9 +135,14 @@ module Homebrew
next
end
name = Livecheck.formula_or_cask_name(formula_or_cask)
ambiguous_cask = begin
formula_or_cask.is_a?(Cask::Cask) && !args.cask? && Formula[name]
rescue FormulaUnavailableError
false
end
puts if i.positive?
retrieve_and_display_info(formula_or_cask, name, repositories, args: args)
retrieve_and_display_info(formula_or_cask, name, repositories, args: args, ambiguous_cask: ambiguous_cask)
break if limit && i >= limit
end
@ -145,7 +180,7 @@ module Homebrew
pull_requests
end
def retrieve_and_display_info(formula_or_cask, name, repositories, args:)
def retrieve_and_display_info(formula_or_cask, name, repositories, args:, ambiguous_cask: false)
current_version = if formula_or_cask.is_a?(Formula)
formula_or_cask.stable.version
else
@ -161,6 +196,7 @@ module Homebrew
livecheck_latest = livecheck_result(formula_or_cask)
pull_requests = retrieve_pull_requests(formula_or_cask, name) unless args.no_pull_requests?
name += " (cask)" if ambiguous_cask
title = if current_version == repology_latest &&
current_version == livecheck_latest
"#{name} is up to date!"

View File

@ -61,54 +61,55 @@ module Homebrew
puts ENV["HOMEBREW_LIVECHECK_WATCHLIST"] if ENV["HOMEBREW_LIVECHECK_WATCHLIST"].present?
end
formulae_and_casks_to_check =
if args.tap
tap = Tap.fetch(args.tap)
formulae = args.cask? ? [] : tap.formula_files.map { |path| Formulary.factory(path) }
casks = args.formula? ? [] : tap.cask_files.map { |path| Cask::CaskLoader.load(path) }
formulae + casks
elsif args.installed?
formulae = args.cask? ? [] : Formula.installed
casks = args.formula? ? [] : Cask::Caskroom.casks
formulae + casks
elsif args.all?
formulae = args.cask? ? [] : Formula.to_a
casks = args.formula? ? [] : Cask::Cask.to_a
formulae + casks
elsif args.named.present?
if args.formula?
args.named.to_formulae
elsif args.cask?
args.named.to_casks
else
args.named.to_formulae_and_casks
end
elsif File.exist?(WATCHLIST_PATH)
begin
names = Pathname.new(WATCHLIST_PATH).read.lines
.reject { |line| line.start_with?("#") || line.blank? }
.map(&:strip)
named_args = T.unsafe(CLI::NamedArgs).new(*names, parent: args)
named_args.to_formulae_and_casks(ignore_unavailable: true)
rescue Errno::ENOENT => e
onoe e
end
formulae_and_casks_to_check = if args.tap
tap = Tap.fetch(args.tap)
formulae = args.cask? ? [] : tap.formula_files.map { |path| Formulary.factory(path) }
casks = args.formula? ? [] : tap.cask_files.map { |path| Cask::CaskLoader.load(path) }
formulae + casks
elsif args.installed?
formulae = args.cask? ? [] : Formula.installed
casks = args.formula? ? [] : Cask::Caskroom.casks
formulae + casks
elsif args.all?
formulae = args.cask? ? [] : Formula.to_a
casks = args.formula? ? [] : Cask::Cask.to_a
formulae + casks
elsif args.named.present?
if args.formula?
args.named.to_formulae
elsif args.cask?
args.named.to_casks
else
raise UsageError, "A watchlist file is required when no arguments are given."
end&.sort_by do |formula_or_cask|
formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
args.named.to_formulae_and_casks
end
elsif File.exist?(WATCHLIST_PATH)
begin
names = Pathname.new(WATCHLIST_PATH).read.lines
.reject { |line| line.start_with?("#") || line.blank? }
.map(&:strip)
named_args = T.unsafe(CLI::NamedArgs).new(*names, parent: args)
named_args.to_formulae_and_casks(ignore_unavailable: true)
rescue Errno::ENOENT => e
onoe e
end
else
raise UsageError, "A watchlist file is required when no arguments are given."
end
formulae_and_casks_to_check = formulae_and_casks_to_check.sort_by do |formula_or_cask|
formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
end
raise UsageError, "No formulae or casks to check." if formulae_and_casks_to_check.blank?
options = {
json: args.json?,
full_name: args.full_name?,
newer_only: args.newer_only?,
quiet: args.quiet?,
debug: args.debug?,
verbose: args.verbose?,
json: args.json?,
full_name: args.full_name?,
handle_name_conflict: !args.formula? && !args.cask?,
newer_only: args.newer_only?,
quiet: args.quiet?,
debug: args.debug?,
verbose: args.verbose?,
}.compact
Livecheck.run_checks(formulae_and_casks_to_check, **options)

View File

@ -63,7 +63,7 @@ module Homebrew
# Uses `formulae_and_casks_to_check` to identify taps in use other than
# homebrew/core and homebrew/cask and loads strategies from them.
sig { params(formulae_and_casks_to_check: T::Enumerable[T.any(Formula, Cask::Cask)]).void }
sig { params(formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)]).void }
def load_other_tap_strategies(formulae_and_casks_to_check)
other_taps = {}
formulae_and_casks_to_check.each do |formula_or_cask|
@ -86,8 +86,9 @@ module Homebrew
# `formulae_and_casks_to_check` array and prints the results.
sig {
params(
formulae_and_casks_to_check: T::Enumerable[T.any(Formula, Cask::Cask)],
formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)],
full_name: T::Boolean,
handle_name_conflict: T::Boolean,
json: T::Boolean,
newer_only: T::Boolean,
debug: T::Boolean,
@ -97,10 +98,29 @@ module Homebrew
}
def run_checks(
formulae_and_casks_to_check,
full_name: false, json: false, newer_only: false, debug: false, quiet: false, verbose: false
full_name: false, handle_name_conflict: false, json: false, newer_only: false,
debug: false, quiet: false, verbose: false
)
load_other_tap_strategies(formulae_and_casks_to_check)
ambiguous_casks = []
if handle_name_conflict
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) }
end
ambiguous_names = []
unless full_name
ambiguous_names =
(formulae_and_casks_to_check - ambiguous_casks).group_by { |item| formula_or_cask_name(item) }
.values
.select { |items| items.length > 1 }
.flatten
end
has_a_newer_upstream_version = T.let(false, T::Boolean)
if json && !quiet && $stderr.tty?
@ -122,7 +142,9 @@ module Homebrew
formulae_checked = formulae_and_casks_to_check.map.with_index do |formula_or_cask, i|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
name = formula_or_cask_name(formula_or_cask, full_name: full_name)
use_full_name = full_name || ambiguous_names.include?(formula_or_cask)
name = formula_or_cask_name(formula_or_cask, full_name: use_full_name)
if debug && i.positive?
puts <<~EOS
@ -130,9 +152,11 @@ module Homebrew
----------
EOS
elsif debug
puts
end
skip_info = SkipConditions.skip_information(formula_or_cask, full_name: full_name, verbose: verbose)
skip_info = SkipConditions.skip_information(formula_or_cask, full_name: use_full_name, verbose: verbose)
if skip_info.present?
next skip_info if json
@ -164,7 +188,7 @@ module Homebrew
else
version_info = latest_version(
formula_or_cask,
json: json, full_name: full_name, verbose: verbose, debug: debug,
json: json, full_name: use_full_name, verbose: verbose, debug: debug,
)
version_info[:latest] if version_info.present?
end
@ -175,7 +199,7 @@ module Homebrew
next version_info if version_info.is_a?(Hash) && version_info[:status] && version_info[:messages]
next status_hash(formula_or_cask, "error", [no_versions_msg], full_name: full_name, verbose: verbose)
next status_hash(formula_or_cask, "error", [no_versions_msg], full_name: use_full_name, verbose: verbose)
end
if (m = latest.to_s.match(/(.*)-release$/)) && !current.to_s.match(/.*-release$/)
@ -220,15 +244,19 @@ module Homebrew
next info
end
print_latest_version(info, verbose: verbose)
print_latest_version(info, verbose: verbose, ambiguous_cask: ambiguous_casks.include?(formula_or_cask))
nil
rescue => e
Homebrew.failed = true
use_full_name = full_name || ambiguous_names.include?(formula_or_cask)
if json
progress&.increment
status_hash(formula_or_cask, "error", [e.to_s], full_name: full_name, verbose: verbose)
status_hash(formula_or_cask, "error", [e.to_s], full_name: use_full_name, verbose: verbose)
elsif !quiet
name = formula_or_cask_name(formula_or_cask, full_name: use_full_name)
name += " (cask)" if ambiguous_casks.include?(formula_or_cask)
onoe "#{Tty.blue}#{name}#{Tty.reset}: #{e}"
$stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error)
nil
@ -306,9 +334,10 @@ module Homebrew
end
# Formats and prints the livecheck result for a formula.
sig { params(info: Hash, verbose: T::Boolean).void }
def print_latest_version(info, verbose:)
sig { params(info: Hash, verbose: T::Boolean, ambiguous_cask: T::Boolean).void }
def print_latest_version(info, verbose:, ambiguous_cask: false)
formula_or_cask_s = "#{Tty.blue}#{info[:formula] || info[:cask]}#{Tty.reset}"
formula_or_cask_s += " (cask)" if ambiguous_cask
formula_or_cask_s += " (guessed)" if !info[:meta][:livecheckable] && verbose
current_s = if info[:version][:newer_than_upstream]
@ -438,7 +467,6 @@ module Homebrew
urls ||= checkable_urls(formula_or_cask)
if debug
puts
if formula
puts "Formula: #{formula_name(formula, full_name: full_name)}"
puts "Head only?: true" if formula.head_only?