Merge branch 'Homebrew:master' into info-json-time

This commit is contained in:
Jack Haden-Enneking 2022-10-03 09:53:08 -07:00 committed by GitHub
commit 316568e78d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 544 additions and 170 deletions

View File

@ -58,7 +58,7 @@ GEM
mime-types-data (3.2022.0105)
mini_portile2 (2.8.0)
minitest (5.16.3)
msgpack (1.5.6)
msgpack (1.6.0)
mustache (1.1.1)
net-http-digest_auth (1.4.1)
net-http-persistent (4.0.1)
@ -122,7 +122,7 @@ GEM
rspec-support (3.11.1)
rspec-wait (0.0.9)
rspec (>= 3, < 4)
rspec_junit_formatter (0.5.1)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.35.1)
json (~> 2.3)

View File

@ -508,18 +508,9 @@ else
: "${HOMEBREW_OS_VERSION:=$(uname -r)}"
HOMEBREW_OS_USER_AGENT_VERSION="${HOMEBREW_OS_VERSION}"
# This is set by the user environment.
# shellcheck disable=SC2154
if [[ -n "${HOMEBREW_ON_DEBIAN7}" ]]
then
# Special version for our debian 7 docker container used to build binutils
HOMEBREW_MINIMUM_CURL_VERSION="7.25.0"
HOMEBREW_SYSTEM_CA_CERTIFICATES_TOO_OLD="1"
HOMEBREW_FORCE_BREWED_CA_CERTIFICATES="1"
else
# Ensure the system Curl is a version that supports modern HTTPS certificates.
HOMEBREW_MINIMUM_CURL_VERSION="7.41.0"
fi
# Ensure the system Curl is a version that supports modern HTTPS certificates.
HOMEBREW_MINIMUM_CURL_VERSION="7.41.0"
curl_version_output="$(${HOMEBREW_CURL} --version 2>/dev/null)"
curl_name_and_version="${curl_version_output%% (*}"
# shellcheck disable=SC2248

View File

@ -56,7 +56,8 @@ module Cask
require_sha: nil,
quarantine: nil,
quiet: nil,
zap: nil
zap: nil,
dry_run: nil
)
odie "Installing casks is supported only on macOS" unless OS.mac?
@ -73,6 +74,27 @@ module Cask
options[:quarantine] = true if options[:quarantine].nil?
if dry_run
if (casks_to_install = casks.reject(&:installed?).presence)
plural = "cask".pluralize(casks_to_install.count)
ohai "Would install #{casks_to_install.count} #{plural}:"
puts casks_to_install.map(&:full_name).join(" ")
end
casks.each do |cask|
dep_names = CaskDependent.new(cask)
.runtime_dependencies
.reject(&:installed?)
.map(&:to_formula)
.map(&:name)
next if dep_names.blank?
plural = "dependency".pluralize(dep_names.count)
ohai "Would install #{dep_names.count} #{plural} for #{cask.full_name}:"
puts dep_names.join(" ")
end
return
end
require "cask/installer"
casks.each do |cask|

View File

@ -30,6 +30,9 @@ module Homebrew
sig { returns(T::Boolean) }
def newer_only?; end
sig { returns(T::Boolean) }
def resources?; end
sig { returns(T::Boolean) }
def full_name?; end

View File

@ -45,6 +45,8 @@ module Homebrew
"(binaries and symlinks are excluded, unless originally from the same cask)."
switch "-v", "--verbose",
description: "Print the verification and postinstall steps."
switch "-n", "--dry-run",
description: "Show what would be installed, but do not actually install anything."
[
[:switch, "--formula", "--formulae", {
description: "Treat all named arguments as formulae.",
@ -193,6 +195,7 @@ module Homebrew
skip_cask_deps: args.skip_cask_deps?,
quarantine: args.quarantine?,
quiet: args.quiet?,
dry_run: args.dry_run?,
)
end
@ -242,6 +245,7 @@ module Homebrew
debug: args.debug?,
quiet: args.quiet?,
verbose: args.verbose?,
dry_run: args.dry_run?,
)
Upgrade.check_installed_dependents(
@ -257,9 +261,10 @@ module Homebrew
debug: args.debug?,
quiet: args.quiet?,
verbose: args.verbose?,
dry_run: args.dry_run?,
)
Cleanup.periodic_clean!
Cleanup.periodic_clean!(dry_run: args.dry_run?)
Homebrew.messages.display_messages(display_times: args.display_times?)
rescue FormulaUnreadableError, FormulaClassUnavailableError,

View File

@ -188,19 +188,6 @@ module Homebrew
GitHub.create_bump_pr(pr_info, args: args)
end
def fetch_cask(contents, config: nil)
cask = Cask::CaskLoader.load(contents)
cask.config = config if config.present?
old_hash = cask.sha256.to_s
cask_download = Cask::Download.new(cask, quarantine: true)
download = cask_download.fetch(verify_download_integrity: false)
Utils::Tar.validate_file(download)
new_hash = download.sha256
[old_hash, new_hash]
end
def check_open_pull_requests(cask, args:)
tap_remote_repo = cask.tap.remote_repo || cask.tap.full_name
GitHub.check_for_duplicate_pull_requests(cask.token, tap_remote_repo,

View File

@ -72,17 +72,18 @@ module Homebrew
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) }
ambiguous_casks = formulae_and_casks \
.group_by { |item| Livecheck.package_or_resource_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) }
(formulae_and_casks - ambiguous_casks).group_by { |item| Livecheck.package_or_resource_name(item) }
.values
.select { |items| items.length > 1 }
.flatten
@ -92,7 +93,7 @@ module Homebrew
puts if i.positive?
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)
name = Livecheck.package_or_resource_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
@ -157,7 +158,7 @@ module Homebrew
rescue
next
end
name = Livecheck.formula_or_cask_name(formula_or_cask)
name = Livecheck.package_or_resource_name(formula_or_cask)
ambiguous_cask = begin
formula_or_cask.is_a?(Cask::Cask) && !args.cask? && Formula[name]
rescue FormulaUnavailableError
@ -178,7 +179,7 @@ module Homebrew
end
def livecheck_result(formula_or_cask)
name = Livecheck.formula_or_cask_name(formula_or_cask)
name = Livecheck.package_or_resource_name(formula_or_cask)
referenced_formula_or_cask, =
Livecheck.resolve_livecheck_reference(formula_or_cask, full_name: false, debug: false)

View File

@ -37,6 +37,8 @@ module Homebrew
description: "Show the latest version only if it's newer than the formula/cask."
switch "--json",
description: "Output information in JSON format."
switch "-r", "--resources",
description: "Also check resources for formulae."
switch "-q", "--quiet",
description: "Suppress warnings, don't print a progress bar for JSON output."
switch "--formula", "--formulae",
@ -101,6 +103,7 @@ module Homebrew
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
@ -111,6 +114,7 @@ module Homebrew
json: args.json?,
full_name: args.full_name?,
handle_name_conflict: !args.formula? && !args.cask?,
check_resources: args.resources?,
newer_only: args.newer_only?,
quiet: args.quiet?,
debug: args.debug?,

View File

@ -7,6 +7,7 @@ class LinkageChecker
# Libraries provided by glibc and gcc.
SYSTEM_LIBRARY_ALLOWLIST = %w[
ld-linux-x86-64.so.2
ld-linux-aarch64.so.1
libanl.so.1
libatomic.so.1
libc.so.6

View File

@ -11,7 +11,7 @@ module Hardware
INTEL_64BIT_ARCHS = [:x86_64].freeze
PPC_32BIT_ARCHS = [:ppc, :ppc32, :ppc7400, :ppc7450, :ppc970].freeze
PPC_64BIT_ARCHS = [:ppc64, :ppc64le, :ppc970].freeze
ARM_64BIT_ARCHS = [:arm64].freeze
ARM_64BIT_ARCHS = [:arm64, :aarch64].freeze
ALL_ARCHS = [
*INTEL_32BIT_ARCHS,
*INTEL_64BIT_ARCHS,

View File

@ -278,10 +278,11 @@ module Homebrew
overwrite: false,
debug: false,
quiet: false,
verbose: false
verbose: false,
dry_run: false
)
formula_installers = formulae_to_install.map do |f|
Migrator.migrate_if_needed(f, force: force)
Migrator.migrate_if_needed(f, force: force, dry_run: dry_run)
build_options = f.build
fi = FormulaInstaller.new(
@ -307,8 +308,10 @@ module Homebrew
)
begin
fi.prelude
fi.fetch
unless dry_run
fi.prelude
fi.fetch
end
fi
rescue CannotInstallFormulaError => e
ofail e.message
@ -319,6 +322,20 @@ module Homebrew
end
end.compact
if dry_run
if (formulae_name_to_install = formulae_to_install.map(&:name))
plural = "formula".pluralize(formulae_name_to_install.count)
ohai "Would install #{formulae_name_to_install.count} #{plural}:"
puts formulae_name_to_install.join(" ")
formula_installers.each do |fi|
f = fi.formula
print_dry_run_dependencies(f, fi.compute_dependencies, &:name)
end
end
return
end
formula_installers.each do |fi|
install_formula(fi)
Cleanup.install_formula_clean!(fi.formula)
@ -333,6 +350,15 @@ module Homebrew
Upgrade.install_formula(formula_installer, upgrade: upgrade)
end
private_class_method :install_formula
def print_dry_run_dependencies(formula, dependencies, &block)
return if dependencies.empty?
plural = "dependency".pluralize(dependencies.count)
ohai "Would install #{dependencies.count} #{plural} for #{formula.name}:"
formula_names = dependencies.map(&:first).map(&:to_formula).map(&block)
puts formula_names.join(" ")
end
end
end

View File

@ -126,11 +126,11 @@ module Homebrew
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)
puts package_or_resource_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)
puts package_or_resource_name(ref_formula_or_cask, full_name: full_name)
end
end
@ -157,11 +157,14 @@ module Homebrew
# Executes the livecheck logic for each formula/cask in the
# `formulae_and_casks_to_check` array and prints the results.
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
sig {
params(
formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)],
full_name: T::Boolean,
handle_name_conflict: T::Boolean,
check_resources: T::Boolean,
json: T::Boolean,
newer_only: T::Boolean,
debug: T::Boolean,
@ -171,24 +174,25 @@ module Homebrew
}
def run_checks(
formulae_and_casks_to_check,
full_name: false, handle_name_conflict: false, json: false, newer_only: false,
full_name: false, handle_name_conflict: false, check_resources: 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) }
ambiguous_casks = formulae_and_casks_to_check \
.group_by { |item| package_or_resource_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) }
(formulae_and_casks_to_check - ambiguous_casks).group_by { |item| package_or_resource_name(item) }
.values
.select { |items| items.length > 1 }
.flatten
@ -218,7 +222,7 @@ module Homebrew
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
use_full_name = full_name || ambiguous_names.include?(formula_or_cask)
name = formula_or_cask_name(formula_or_cask, full_name: use_full_name)
name = package_or_resource_name(formula_or_cask, full_name: use_full_name)
referenced_formula_or_cask, livecheck_references =
resolve_livecheck_reference(formula_or_cask, full_name: use_full_name, debug: debug)
@ -282,6 +286,30 @@ module Homebrew
version_info[:latest] if version_info.present?
end
check_for_resources = check_resources && formula_or_cask.is_a?(Formula) && formula_or_cask.resources.present?
if check_for_resources
resource_version_info = formula_or_cask.resources.map do |resource|
res_skip_info ||= SkipConditions.skip_information(resource, verbose: verbose)
if res_skip_info.present?
res_skip_info
else
res_version_info = resource_version(
resource,
json: json,
debug: debug,
quiet: quiet,
verbose: verbose,
)
if res_version_info.empty?
status_hash(resource, "error", ["Unable to get versions"], verbose: verbose)
else
res_version_info
end
end
end.compact_blank
Homebrew.failed = true if resource_version_info.any? { |info| info[:status] == "error" }
end
if latest.blank?
no_versions_msg = "Unable to get versions"
raise Livecheck::Error, no_versions_msg unless json
@ -289,7 +317,14 @@ 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: use_full_name, verbose: verbose)
latest_info = status_hash(formula_or_cask, "error", [no_versions_msg], full_name: use_full_name,
verbose: verbose)
if check_for_resources
resource_version_info.map! { |r| r.except!(:meta) } unless verbose
latest_info[:resources] = resource_version_info
end
next latest_info
end
if (m = latest.to_s.match(/(.*)-release$/)) && !current.to_s.match(/.*-release$/)
@ -324,6 +359,8 @@ module Homebrew
info[:meta][:head_only] = true if formula&.head_only?
info[:meta].merge!(version_info[:meta]) if version_info.present? && version_info.key?(:meta)
info[:resources] = resource_version_info if check_for_resources
next if newer_only && !info[:version][:outdated]
has_a_newer_upstream_version ||= true
@ -331,10 +368,12 @@ module Homebrew
if json
progress&.increment
info.except!(:meta) unless verbose
resource_version_info.map! { |r| r.except!(:meta) } if check_for_resources && !verbose
next info
end
puts if debug
print_latest_version(info, verbose: verbose, ambiguous_cask: ambiguous_casks.include?(formula_or_cask))
print_resources_info(resource_version_info, verbose: verbose) if check_for_resources
nil
rescue => e
Homebrew.failed = true
@ -344,11 +383,12 @@ module Homebrew
progress&.increment
status_hash(formula_or_cask, "error", [e.to_s], full_name: use_full_name, verbose: verbose) unless quiet
elsif !quiet
name = formula_or_cask_name(formula_or_cask, full_name: use_full_name)
name = package_or_resource_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)
print_resources_info(resource_version_info, verbose: verbose) if check_for_resources
nil
end
end
@ -367,16 +407,20 @@ module Homebrew
puts JSON.pretty_generate(formulae_checked.compact)
end
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity
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)
case formula_or_cask
sig { params(package_or_resource: T.any(Formula, Cask::Cask, Resource), full_name: T::Boolean).returns(String) }
def package_or_resource_name(package_or_resource, full_name: false)
case package_or_resource
when Formula
formula_name(formula_or_cask, full_name: full_name)
formula_name(package_or_resource, full_name: full_name)
when Cask::Cask
cask_name(formula_or_cask, full_name: full_name)
cask_name(package_or_resource, full_name: full_name)
when Resource
package_or_resource.name
else
T.absurd(formula_or_cask)
T.absurd(package_or_resource)
end
end
@ -396,40 +440,44 @@ module Homebrew
sig {
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,
package_or_resource: T.any(Formula, Cask::Cask, Resource),
status_str: String,
messages: T.nilable(T::Array[String]),
full_name: T::Boolean,
verbose: T::Boolean,
).returns(Hash)
}
def status_hash(formula_or_cask, status_str, messages = nil, full_name: false, verbose: false)
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
def status_hash(package_or_resource, status_str, messages = nil, full_name: false, verbose: false)
formula = package_or_resource if package_or_resource.is_a?(Formula)
cask = package_or_resource if package_or_resource.is_a?(Cask::Cask)
resource = package_or_resource if package_or_resource.is_a?(Resource)
status_hash = {}
if formula
status_hash[:formula] = formula_name(formula, full_name: full_name)
elsif cask
status_hash[:cask] = cask_name(formula_or_cask, full_name: full_name)
status_hash[:cask] = cask_name(cask, full_name: full_name)
elsif resource
status_hash[:resource] = resource.name
end
status_hash[:status] = status_str
status_hash[:messages] = messages if messages.is_a?(Array)
status_hash[:meta] = {
livecheckable: formula_or_cask.livecheckable?,
livecheckable: package_or_resource.livecheckable?,
}
status_hash[:meta][:head_only] = true if formula&.head_only?
status_hash
end
# Formats and prints the livecheck result for a formula.
# Formats and prints the livecheck result for a formula/cask/resource.
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
def print_latest_version(info, verbose: false, ambiguous_cask: false)
package_or_resource_s = info[:resource].present? ? " " : ""
package_or_resource_s += "#{Tty.blue}#{info[:formula] || info[:cask] || info[:resource]}#{Tty.reset}"
package_or_resource_s += " (cask)" if ambiguous_cask
package_or_resource_s += " (guessed)" if verbose && !info[:meta][:livecheckable]
current_s = if info[:version][:newer_than_upstream]
"#{Tty.red}#{info[:version][:current]}#{Tty.reset}"
@ -443,47 +491,61 @@ module Homebrew
info[:version][:latest]
end
puts "#{formula_or_cask_s}: #{current_s} ==> #{latest_s}"
puts "#{package_or_resource_s}: #{current_s} ==> #{latest_s}"
end
# Prints the livecheck result for the resources of a given Formula.
sig { params(info: T::Array[Hash], verbose: T::Boolean).void }
def print_resources_info(info, verbose: false)
info.each do |r_info|
if r_info[:status] && r_info[:messages]
SkipConditions.print_skip_information(r_info)
else
print_latest_version(r_info, verbose: verbose)
end
end
end
sig {
params(
livecheck_url: T.any(String, Symbol),
formula_or_cask: T.any(Formula, Cask::Cask),
livecheck_url: T.any(String, Symbol),
package_or_resource: T.any(Formula, Cask::Cask, Resource),
).returns(T.nilable(String))
}
def livecheck_url_to_string(livecheck_url, formula_or_cask)
def livecheck_url_to_string(livecheck_url, package_or_resource)
case livecheck_url
when String
livecheck_url
when :url
formula_or_cask.url&.to_s if formula_or_cask.is_a?(Cask::Cask)
package_or_resource.url&.to_s if package_or_resource.is_a?(Cask::Cask) || package_or_resource.is_a?(Resource)
when :head, :stable
formula_or_cask.send(livecheck_url)&.url if formula_or_cask.is_a?(Formula)
package_or_resource.send(livecheck_url)&.url if package_or_resource.is_a?(Formula)
when :homepage
formula_or_cask.homepage
package_or_resource.homepage unless package_or_resource.is_a?(Resource)
end
end
# Returns an Array containing the formula/cask URLs that can be used by livecheck.
sig { params(formula_or_cask: T.any(Formula, Cask::Cask)).returns(T::Array[String]) }
def checkable_urls(formula_or_cask)
# Returns an Array containing the formula/cask/resource URLs that can be used by livecheck.
sig { params(package_or_resource: T.any(Formula, Cask::Cask, Resource)).returns(T::Array[String]) }
def checkable_urls(package_or_resource)
urls = []
case formula_or_cask
case package_or_resource
when Formula
if formula_or_cask.stable
urls << formula_or_cask.stable.url
urls.concat(formula_or_cask.stable.mirrors)
if package_or_resource.stable
urls << package_or_resource.stable.url
urls.concat(package_or_resource.stable.mirrors)
end
urls << formula_or_cask.head.url if formula_or_cask.head
urls << formula_or_cask.homepage if formula_or_cask.homepage
urls << package_or_resource.head.url if package_or_resource.head
urls << package_or_resource.homepage if package_or_resource.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
urls << package_or_resource.appcast.to_s if package_or_resource.appcast
urls << package_or_resource.url.to_s if package_or_resource.url
urls << package_or_resource.homepage if package_or_resource.homepage
when Resource
urls << package_or_resource.url
else
T.absurd(formula_or_cask)
T.absurd(package_or_resource)
end
urls.compact.uniq
@ -561,7 +623,7 @@ module Homebrew
homebrew_curl_root_domains.include?(url_root_domain)
end
# Identifies the latest version of the formula and returns a Hash containing
# Identifies the latest version of the formula/cask and returns a Hash containing
# the version information. Returns nil if a latest version couldn't be found.
# rubocop:disable Metrics/CyclomaticComplexity
sig {
@ -713,7 +775,6 @@ module Homebrew
version.to_s.include?(rejection)
end
end
next if match_version_map.blank?
if debug
@ -770,6 +831,195 @@ module Homebrew
nil
end
# rubocop:enable Metrics/CyclomaticComplexity
# Identifies the latest version of a resource and returns a Hash containing the
# version information. Returns nil if a latest version couldn't be found.
sig {
params(
resource: Resource,
json: T::Boolean,
debug: T::Boolean,
quiet: T::Boolean,
verbose: T::Boolean,
).returns(Hash)
}
def resource_version(
resource,
json: false,
debug: false,
quiet: false,
verbose: false
)
has_livecheckable = resource.livecheckable?
if debug
puts "\n\n"
puts "Resource: #{resource.name}"
puts "Livecheckable?: #{has_livecheckable ? "Yes" : "No"}"
end
resource_version_info = {}
livecheck = resource.livecheck
livecheck_url = livecheck.url
livecheck_regex = livecheck.regex
livecheck_strategy = livecheck.strategy
livecheck_strategy_block = livecheck.strategy_block
livecheck_url_string = livecheck_url_to_string(livecheck_url, resource)
urls = [livecheck_url_string] if livecheck_url_string
urls ||= checkable_urls(resource)
checked_urls = []
# rubocop:disable Metrics/BlockLength
urls.each_with_index do |original_url, i|
# Only preprocess the URL when it's appropriate
url = if STRATEGY_SYMBOLS_TO_SKIP_PREPROCESS_URL.include?(livecheck_strategy)
original_url
else
preprocess_url(original_url)
end
next if checked_urls.include?(url)
strategies = Strategy.from_url(
url,
livecheck_strategy: livecheck_strategy,
url_provided: livecheck_url.present?,
regex_provided: livecheck_regex.present?,
block_provided: livecheck_strategy_block.present?,
)
strategy = Strategy.from_symbol(livecheck_strategy) || strategies.first
strategy_name = livecheck_strategy_names[strategy]
if debug
puts
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
puts "URL (processed): #{url}" if url != original_url
if strategies.present? && verbose
puts "Strategies: #{strategies.map { |s| livecheck_strategy_names[s] }.join(", ")}"
end
puts "Strategy: #{strategy.blank? ? "None" : strategy_name}"
puts "Regex: #{livecheck_regex.inspect}" if livecheck_regex.present?
end
if livecheck_strategy.present?
if livecheck_url.blank? && strategy.method(:find_versions).parameters.include?([:keyreq, :url])
odebug "#{strategy_name} strategy requires a URL"
next
elsif livecheck_strategy != :page_match && strategies.exclude?(strategy)
odebug "#{strategy_name} strategy does not apply to this URL"
next
end
end
puts if debug && strategy.blank?
next if strategy.blank?
strategy_data = strategy.find_versions(
url: url,
regex: livecheck_regex,
homebrew_curl: false,
&livecheck_strategy_block
)
match_version_map = strategy_data[:matches]
regex = strategy_data[:regex]
messages = strategy_data[:messages]
checked_urls << url
if messages.is_a?(Array) && match_version_map.blank?
puts messages unless json
next if i + 1 < urls.length
return status_hash(resource, "error", messages, verbose: verbose)
end
if debug
if strategy_data[:url].present? && strategy_data[:url] != url
puts "URL (strategy): #{strategy_data[:url]}"
end
puts "URL (final): #{strategy_data[:final_url]}" if strategy_data[:final_url].present?
if strategy_data[:regex].present? && strategy_data[:regex] != livecheck_regex
puts "Regex (strategy): #{strategy_data[:regex].inspect}"
end
puts "Cached?: Yes" if strategy_data[:cached] == true
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
next if match_version_map.blank?
if debug
puts
puts "Matched Versions:"
if verbose
match_version_map.each do |match, version|
puts "#{match} => #{version.inspect}"
end
else
puts match_version_map.values.join(", ")
end
end
res_current = resource.version
res_latest = Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(resource, v) })
return status_hash(resource, "error", ["Unable to get versions"], verbose: verbose) if res_latest.blank?
is_outdated = res_current < res_latest
is_newer_than_upstream = res_current > res_latest
resource_version_info = {
resource: resource.name,
version: {
current: res_current.to_s,
latest: res_latest.to_s,
outdated: is_outdated,
newer_than_upstream: is_newer_than_upstream,
},
}
resource_version_info[:meta] = { livecheckable: has_livecheckable, url: {} }
if livecheck_url.is_a?(Symbol) && livecheck_url_string
resource_version_info[:meta][:url][:symbol] = livecheck_url
end
resource_version_info[:meta][:url][:original] = original_url
resource_version_info[:meta][:url][:processed] = url if url != original_url
if strategy_data[:url].present? && strategy_data[:url] != url
resource_version_info[:meta][:url][:strategy] = strategy_data[:url]
end
resource_version_info[:meta][:url][:final] = strategy_data[:final_url] if strategy_data[:final_url]
resource_version_info[:meta][:strategy] = strategy.present? ? strategy_name : nil
if strategies.present?
resource_version_info[:meta][:strategies] = strategies.map { |s| livecheck_strategy_names[s] }
end
resource_version_info[:meta][:regex] = regex.inspect if regex.present?
resource_version_info[:meta][:cached] = true if strategy_data[:cached] == true
rescue => e
Homebrew.failed = true
if json
status_hash(resource, "error", [e.to_s], verbose: verbose)
elsif !quiet
onoe "#{Tty.blue}#{resource.name}#{Tty.reset}: #{e}"
$stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error)
nil
end
end
# rubocop:enable Metrics/BlockLength
resource_version_info
end
end
# rubocop:enable Metrics/ModuleLength
end

View File

@ -11,15 +11,17 @@ module Homebrew
include Comparable
sig { params(formula_or_cask: T.any(Formula, Cask::Cask), version: Version).returns(LivecheckVersion) }
def self.create(formula_or_cask, version)
versions = case formula_or_cask
when Formula
sig {
params(package_or_resource: T.any(Formula, Cask::Cask, Resource), version: Version).returns(LivecheckVersion)
}
def self.create(package_or_resource, version)
versions = case package_or_resource
when Formula, Resource
[version]
when Cask::Cask
version.to_s.split(/[,:]/).map { |s| Version.new(s) }
else
T.absurd(formula_or_cask)
T.absurd(package_or_resource)
end
new(versions)
end

View File

@ -6,7 +6,7 @@ require "livecheck/livecheck"
module Homebrew
module Livecheck
# The `Livecheck::SkipConditions` module primarily contains methods that
# check for various formula/cask conditions where a check should be skipped.
# check for various formula/cask/resource conditions where a check should be skipped.
#
# @api private
module SkipConditions
@ -16,14 +16,14 @@ module Homebrew
sig {
params(
formula_or_cask: T.any(Formula, Cask::Cask),
livecheckable: T::Boolean,
full_name: T::Boolean,
verbose: T::Boolean,
package_or_resource: T.any(Formula, Cask::Cask, Resource),
livecheckable: T::Boolean,
full_name: T::Boolean,
verbose: T::Boolean,
).returns(Hash)
}
def formula_or_cask_skip(formula_or_cask, livecheckable, full_name: false, verbose: false)
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
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)
@ -33,8 +33,8 @@ module Homebrew
stable_from_internet_archive = stable_url.match?(%r{https?://web\.archive\.org/}i)
end
skip_message = if formula_or_cask.livecheck.skip_msg.present?
formula_or_cask.livecheck.skip_msg
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"
@ -45,10 +45,10 @@ module Homebrew
end
end
return {} if !formula_or_cask.livecheck.skip? && skip_message.blank?
return {} if !package_or_resource.livecheck.skip? && skip_message.blank?
skip_messages = skip_message ? [skip_message] : nil
Livecheck.status_hash(formula_or_cask, "skipped", skip_messages, full_name: full_name, verbose: verbose)
Livecheck.status_hash(package_or_resource, "skipped", skip_messages, full_name: full_name, verbose: verbose)
end
sig {
@ -157,7 +157,7 @@ module Homebrew
# Skip conditions for formulae.
FORMULA_CHECKS = [
:formula_or_cask_skip,
:package_or_resource_skip,
:formula_head_only,
:formula_deprecated,
:formula_disabled,
@ -166,76 +166,85 @@ module Homebrew
# Skip conditions for casks.
CASK_CHECKS = [
:formula_or_cask_skip,
:package_or_resource_skip,
:cask_discontinued,
:cask_version_latest,
:cask_url_unversioned,
].freeze
# If a formula/cask should be skipped, we return a hash from
# 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(
formula_or_cask: T.any(Formula, Cask::Cask),
full_name: T::Boolean,
verbose: T::Boolean,
package_or_resource: T.any(Formula, Cask::Cask, Resource),
full_name: T::Boolean,
verbose: T::Boolean,
).returns(Hash)
}
def skip_information(formula_or_cask, full_name: false, verbose: false)
livecheckable = formula_or_cask.livecheckable?
def skip_information(package_or_resource, full_name: false, verbose: false)
livecheckable = package_or_resource.livecheckable?
checks = case formula_or_cask
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, formula_or_cask, livecheckable, full_name: full_name, verbose: verbose)
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 referenced in a `livecheck` block
# 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_formula_or_cask: T.any(Formula, Cask::Cask),
original_formula_or_cask_name: String,
full_name: T::Boolean,
verbose: T::Boolean,
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_formula_or_cask,
original_formula_or_cask_name,
livecheck_package_or_resource,
original_package_or_resource_name,
full_name: false,
verbose: false
)
skip_info = SkipConditions.skip_information(
livecheck_formula_or_cask,
livecheck_package_or_resource,
full_name: full_name,
verbose: verbose,
)
return if skip_info.blank?
referenced_name = Livecheck.formula_or_cask_name(livecheck_formula_or_cask, full_name: full_name)
referenced_type = case livecheck_formula_or_cask
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_formula_or_cask.livecheck.skip?)
!(skip_info[:status] == "skipped" && livecheck_package_or_resource.livecheck.skip?)
error_msg_end = if skip_info[:status] == "skipped"
"automatically skipped"
else
@ -245,7 +254,7 @@ module Homebrew
raise "Referenced #{referenced_type} (#{referenced_name}) is #{error_msg_end}"
end
skip_info[referenced_type] = original_formula_or_cask_name
skip_info[referenced_type] = original_package_or_resource_name
skip_info
end
@ -258,6 +267,8 @@ module Homebrew
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

View File

@ -11,6 +11,7 @@ describe Homebrew::Livecheck do
let(:homepage_url) { "https://brew.sh" }
let(:livecheck_url) { "https://formulae.brew.sh/api/formula/ruby.json" }
let(:stable_url) { "https://brew.sh/test-0.0.1.tgz" }
let(:resource_url) { "https://brew.sh/foo-1.0.tar.gz" }
let(:f) do
formula("test") do
@ -23,9 +24,21 @@ describe Homebrew::Livecheck do
url "https://formulae.brew.sh/api/formula/ruby.json"
regex(/"stable":"(\d+(?:\.\d+)+)"/i)
end
resource "foo" do
url "https://brew.sh/foo-1.0.tar.gz"
sha256 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
livecheck do
url "https://brew.sh/test/releases"
regex(/foo[._-]v?(\d+(?:\.\d+)+)\.t/i)
end
end
end
end
let(:r) { f.resources.first }
let(:c) do
Cask::CaskLoader.load(+<<-RUBY)
cask "test" do
@ -44,15 +57,6 @@ describe Homebrew::Livecheck do
RUBY
end
let(:f_duplicate_urls) do
formula("test_duplicate_urls") do
desc "Test formula with a duplicate URL"
homepage "https://github.com/Homebrew/brew.git"
url "https://brew.sh/test-0.0.1.tgz"
head "https://github.com/Homebrew/brew.git"
end
end
describe "::resolve_livecheck_reference" do
context "when a formula/cask has a livecheck block without formula/cask methods" do
it "returns [nil, []]" do
@ -83,7 +87,7 @@ describe Homebrew::Livecheck do
end
describe "::status_hash" do
it "returns a hash containing the livecheck status" do
it "returns a hash containing the livecheck status for a formula" do
expect(livecheck.status_hash(f, "error", ["Unable to get versions"]))
.to eq({
formula: "test",
@ -94,6 +98,18 @@ describe Homebrew::Livecheck do
},
})
end
it "returns a hash containing the livecheck status for a resource" do
expect(livecheck.status_hash(r, "error", ["Unable to get versions"]))
.to eq({
resource: "foo",
status: "error",
messages: ["Unable to get versions"],
meta: {
livecheckable: true,
},
})
end
end
describe "::livecheck_url_to_string" do
@ -101,15 +117,28 @@ describe Homebrew::Livecheck do
homepage_url_s = homepage_url
stable_url_s = stable_url
head_url_s = head_url
resource_url_s = resource_url
formula("test_livecheck_url") do
desc "Test Livecheck URL formula"
homepage homepage_url_s
url stable_url_s
head head_url_s
resource "foo" do
url resource_url_s
sha256 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
livecheck do
url "https://brew.sh/test/releases"
regex(/foo[._-]v?(\d+(?:\.\d+)+)\.t/i)
end
end
end
end
let(:r_livecheck_url) { f_livecheck_url.resources.first }
let(:c_livecheck_url) do
Cask::CaskLoader.load(+<<-RUBY)
cask "test_livecheck_url" do
@ -123,30 +152,48 @@ describe Homebrew::Livecheck do
RUBY
end
it "returns a URL string when given a livecheck_url string" do
it "returns a URL string when given a livecheck_url string for a formula" do
expect(livecheck.livecheck_url_to_string(livecheck_url, f_livecheck_url)).to eq(livecheck_url)
end
it "returns a URL string when given a livecheck_url string for a resource" do
expect(livecheck.livecheck_url_to_string(livecheck_url, r_livecheck_url)).to eq(livecheck_url)
end
it "returns a URL symbol when given a valid livecheck_url symbol" do
expect(livecheck.livecheck_url_to_string(:head, f_livecheck_url)).to eq(head_url)
expect(livecheck.livecheck_url_to_string(:homepage, f_livecheck_url)).to eq(homepage_url)
expect(livecheck.livecheck_url_to_string(:homepage, c_livecheck_url)).to eq(homepage_url)
expect(livecheck.livecheck_url_to_string(:stable, f_livecheck_url)).to eq(stable_url)
expect(livecheck.livecheck_url_to_string(:url, c_livecheck_url)).to eq(cask_url)
expect(livecheck.livecheck_url_to_string(:url, r_livecheck_url)).to eq(resource_url)
end
it "returns nil when not given a string or valid symbol" do
expect(livecheck.livecheck_url_to_string(nil, f_livecheck_url)).to be_nil
expect(livecheck.livecheck_url_to_string(nil, c_livecheck_url)).to be_nil
expect(livecheck.livecheck_url_to_string(nil, r_livecheck_url)).to be_nil
expect(livecheck.livecheck_url_to_string(:invalid_symbol, f_livecheck_url)).to be_nil
expect(livecheck.livecheck_url_to_string(:invalid_symbol, c_livecheck_url)).to be_nil
expect(livecheck.livecheck_url_to_string(:invalid_symbol, r_livecheck_url)).to be_nil
end
end
describe "::checkable_urls" do
let(:resource_url) { "https://brew.sh/foo-1.0.tar.gz" }
let(:f_duplicate_urls) do
formula("test_duplicate_urls") do
desc "Test formula with a duplicate URL"
homepage "https://github.com/Homebrew/brew.git"
url "https://brew.sh/test-0.0.1.tgz"
head "https://github.com/Homebrew/brew.git"
end
end
it "returns the list of URLs to check" do
expect(livecheck.checkable_urls(f)).to eq([stable_url, head_url, homepage_url])
expect(livecheck.checkable_urls(c)).to eq([cask_url, homepage_url])
expect(livecheck.checkable_urls(r)).to eq([resource_url])
expect(livecheck.checkable_urls(f_duplicate_urls)).to eq([stable_url, head_url])
end
end

View File

@ -6,6 +6,7 @@ require "livecheck/livecheck_version"
describe Homebrew::Livecheck::LivecheckVersion do
let(:formula) { instance_double(Formula) }
let(:cask) { instance_double(Cask::Cask) }
let(:resource) { instance_double(Resource) }
before do
# Case statements use #=== for case equality purposes
@ -13,6 +14,8 @@ describe Homebrew::Livecheck::LivecheckVersion do
allow(Formula).to receive(:===).with(formula).and_return(true)
allow(Cask::Cask).to receive(:===).and_call_original
allow(Cask::Cask).to receive(:===).with(cask).and_return(true)
allow(Resource).to receive(:===).and_call_original
allow(Resource).to receive(:===).with(resource).and_return(true)
end
specify "::create" do
@ -28,5 +31,11 @@ describe Homebrew::Livecheck::LivecheckVersion do
.to eq ["1.0", "100", "1426778671"]
expect(described_class.create(cask, Version.new("0.17.0,20210111183933,226")).versions)
.to eq ["0.17.0", "20210111183933", "226"]
expect(described_class.create(resource, Version.new("1.1.6")).versions).to eq ["1.1.6"]
expect(described_class.create(resource, Version.new("2.19.0,1.8.0")).versions).to eq ["2.19.0,1.8.0"]
expect(described_class.create(resource, Version.new("1.0,100:1426778671")).versions).to eq ["1.0,100:1426778671"]
expect(described_class.create(resource, Version.new("0.17.0,20210111183933,226")).versions)
.to eq ["0.17.0,20210111183933,226"]
end
end

View File

@ -94,22 +94,6 @@ module Homebrew
.map { |k| Keg.new(k.resolved_path) }
end
def print_dry_run_dependencies(formula, fi_deps)
return if fi_deps.empty?
plural = "dependency".pluralize(fi_deps.count)
ohai "Would upgrade #{fi_deps.count} #{plural} for #{formula.full_specified_name}:"
formulae_upgrades = fi_deps.map(&:first).map(&:to_formula).map do |f|
name = f.full_specified_name
if f.optlinked?
"#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
else
"#{name} #{f.pkg_version}"
end
end
puts formulae_upgrades.join(", ")
end
def print_upgrade_message(formula, fi_options)
version_upgrade = if formula.optlinked?
"#{Keg.new(formula.opt_prefix).version} -> #{formula.pkg_version}"
@ -178,7 +162,14 @@ module Homebrew
formula = formula_installer.formula
if dry_run
print_dry_run_dependencies(formula, formula_installer.compute_dependencies)
Install.print_dry_run_dependencies(formula, formula_installer.compute_dependencies) do |f|
name = f.full_specified_name
if f.optlinked?
"#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
else
"#{name} #{f.pkg_version}"
end
end
return
end

View File

@ -13,8 +13,8 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/public_suffix-5.0.0/l
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/addressable-2.8.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.11/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-21/2.6.0/msgpack-1.5.6"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.5.6/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-21/2.6.0/msgpack-1.6.0"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.6.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-21/2.6.0/bootsnap-1.13.0"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.13.0/lib"
$:.unshift "#{path}/"
@ -82,7 +82,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-its-1.3.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-retry-0.6.2/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-sorbet-1.9.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec_junit_formatter-0.5.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec_junit_formatter-0.6.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.21.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.11.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-2.3.0/lib"

View File

@ -1112,6 +1112,7 @@ _brew_instal() {
--debug-symbols
--dictionarydir
--display-times
--dry-run
--fetch-HEAD
--fontdir
--force
@ -1171,6 +1172,7 @@ _brew_install() {
--debug-symbols
--dictionarydir
--display-times
--dry-run
--fetch-HEAD
--fontdir
--force
@ -1261,6 +1263,7 @@ _brew_lc() {
--json
--newer-only
--quiet
--resources
--tap
--verbose
"
@ -1375,6 +1378,7 @@ _brew_livecheck() {
--json
--newer-only
--quiet
--resources
--tap
--verbose
"

View File

@ -798,6 +798,7 @@ __fish_brew_complete_arg 'instal' -l debug -d 'If brewing fails, open an interac
__fish_brew_complete_arg 'instal' -l debug-symbols -d 'Generate debug symbols on build. Source will be retained in a cache directory. '
__fish_brew_complete_arg 'instal' -l dictionarydir -d 'Target location for Dictionaries (default: `~/Library/Dictionaries`)'
__fish_brew_complete_arg 'instal' -l display-times -d 'Print install times for each package at the end of the run'
__fish_brew_complete_arg 'instal' -l dry-run -d 'Show what would be installed, but do not actually install anything'
__fish_brew_complete_arg 'instal' -l fetch-HEAD -d 'Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository\'s HEAD will only be checked for updates when a new stable or development version has been released'
__fish_brew_complete_arg 'instal' -l fontdir -d 'Target location for Fonts (default: `~/Library/Fonts`)'
__fish_brew_complete_arg 'instal' -l force -d 'Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask)'
@ -848,6 +849,7 @@ __fish_brew_complete_arg 'install' -l debug -d 'If brewing fails, open an intera
__fish_brew_complete_arg 'install' -l debug-symbols -d 'Generate debug symbols on build. Source will be retained in a cache directory. '
__fish_brew_complete_arg 'install' -l dictionarydir -d 'Target location for Dictionaries (default: `~/Library/Dictionaries`)'
__fish_brew_complete_arg 'install' -l display-times -d 'Print install times for each package at the end of the run'
__fish_brew_complete_arg 'install' -l dry-run -d 'Show what would be installed, but do not actually install anything'
__fish_brew_complete_arg 'install' -l fetch-HEAD -d 'Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository\'s HEAD will only be checked for updates when a new stable or development version has been released'
__fish_brew_complete_arg 'install' -l fontdir -d 'Target location for Fonts (default: `~/Library/Fonts`)'
__fish_brew_complete_arg 'install' -l force -d 'Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask)'
@ -911,6 +913,7 @@ __fish_brew_complete_arg 'lc' -l installed -d 'Check formulae and casks that are
__fish_brew_complete_arg 'lc' -l json -d 'Output information in JSON format'
__fish_brew_complete_arg 'lc' -l newer-only -d 'Show the latest version only if it\'s newer than the formula/cask'
__fish_brew_complete_arg 'lc' -l quiet -d 'Suppress warnings, don\'t print a progress bar for JSON output'
__fish_brew_complete_arg 'lc' -l resources -d 'Also check resources for formulae'
__fish_brew_complete_arg 'lc' -l tap -d 'Check formulae and casks within the given tap, specified as user`/`repo'
__fish_brew_complete_arg 'lc' -l verbose -d 'Make some output more verbose'
__fish_brew_complete_arg 'lc; and not __fish_seen_argument -l cask -l casks' -a '(__fish_brew_suggest_formulae_all)'
@ -980,6 +983,7 @@ __fish_brew_complete_arg 'livecheck' -l installed -d 'Check formulae and casks t
__fish_brew_complete_arg 'livecheck' -l json -d 'Output information in JSON format'
__fish_brew_complete_arg 'livecheck' -l newer-only -d 'Show the latest version only if it\'s newer than the formula/cask'
__fish_brew_complete_arg 'livecheck' -l quiet -d 'Suppress warnings, don\'t print a progress bar for JSON output'
__fish_brew_complete_arg 'livecheck' -l resources -d 'Also check resources for formulae'
__fish_brew_complete_arg 'livecheck' -l tap -d 'Check formulae and casks within the given tap, specified as user`/`repo'
__fish_brew_complete_arg 'livecheck' -l verbose -d 'Make some output more verbose'
__fish_brew_complete_arg 'livecheck; and not __fish_seen_argument -l cask -l casks' -a '(__fish_brew_suggest_formulae_all)'

View File

@ -983,6 +983,7 @@ _brew_instal() {
'(--cask)--debug-symbols[Generate debug symbols on build. Source will be retained in a cache directory. ]' \
'(--formula)--dictionarydir[Target location for Dictionaries (default: `~/Library/Dictionaries`)]' \
'(--cask)--display-times[Print install times for each package at the end of the run]' \
'--dry-run[Show what would be installed, but do not actually install anything]' \
'(--cask)--fetch-HEAD[Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository'\''s HEAD will only be checked for updates when a new stable or development version has been released]' \
'(--formula)--fontdir[Target location for Fonts (default: `~/Library/Fonts`)]' \
'--force[Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask)]' \
@ -1037,6 +1038,7 @@ _brew_install() {
'(--cask)--debug-symbols[Generate debug symbols on build. Source will be retained in a cache directory. ]' \
'(--formula)--dictionarydir[Target location for Dictionaries (default: `~/Library/Dictionaries`)]' \
'(--cask)--display-times[Print install times for each package at the end of the run]' \
'--dry-run[Show what would be installed, but do not actually install anything]' \
'(--cask)--fetch-HEAD[Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository'\''s HEAD will only be checked for updates when a new stable or development version has been released]' \
'(--formula)--fontdir[Target location for Fonts (default: `~/Library/Fonts`)]' \
'--force[Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask)]' \
@ -1107,6 +1109,7 @@ _brew_lc() {
'(--debug)--json[Output information in JSON format]' \
'--newer-only[Show the latest version only if it'\''s newer than the formula/cask]' \
'--quiet[Suppress warnings, don'\''t print a progress bar for JSON output]' \
'--resources[Also check resources for formulae]' \
'(--eval-all --installed)--tap[Check formulae and casks within the given tap, specified as user`/`repo]' \
'--verbose[Make some output more verbose]' \
- formula \
@ -1192,6 +1195,7 @@ _brew_livecheck() {
'(--debug)--json[Output information in JSON format]' \
'--newer-only[Show the latest version only if it'\''s newer than the formula/cask]' \
'--quiet[Suppress warnings, don'\''t print a progress bar for JSON output]' \
'--resources[Also check resources for formulae]' \
'(--eval-all --installed)--tap[Check formulae and casks within the given tap, specified as user`/`repo]' \
'--verbose[Make some output more verbose]' \
- formula \

View File

@ -6,14 +6,14 @@ The `brew livecheck` command finds the newest version of a formula or cask's sof
When livecheck isn't given instructions for how to check for upstream versions, it does the following by default:
1. For formulae: Collect the `head`, `stable`, and `homepage` URLs, in that order. For casks: Collect the `url` and `homepage` URLs, in that order.
1. For formulae: Collect the `stable`, `head`, and `homepage` URLs, in that order (resources simply use their `url`). For casks: Collect the `url` and `homepage` URLs, in that order.
1. Determine if any strategies apply to the first URL. If not, try the next URL.
1. If a strategy can be applied, use it to check for new versions.
1. Return the newest version (or an error if versions could not be found at any available URLs).
It's sometimes necessary to override this default behavior to create a working check. If a source doesn't provide the newest version, we need to check a different one. If livecheck doesn't correctly match version text, we need to provide an appropriate regex or `strategy` block.
This can be accomplished by adding a `livecheck` block to the formula/cask. For more information on the available methods, please refer to the [`Livecheck` class documentation](https://rubydoc.brew.sh/Livecheck.html).
This can be accomplished by adding a `livecheck` block to the formula/cask/resource. For more information on the available methods, please refer to the [`Livecheck` class documentation](https://rubydoc.brew.sh/Livecheck.html).
## Creating a check

View File

@ -329,6 +329,8 @@ is already installed but outdated.
Install formulae without checking for previously installed keg-only or non-migrated versions. When installing casks, overwrite existing files (binaries and symlinks are excluded, unless originally from the same cask).
* `-v`, `--verbose`:
Print the verification and postinstall steps.
* `-n`, `--dry-run`:
Show what would be installed, but do not actually install anything.
* `--formula`:
Treat all named arguments as formulae.
* `--ignore-dependencies`:
@ -1267,6 +1269,8 @@ casks to check is taken from `HOMEBREW_LIVECHECK_WATCHLIST` or
Show the latest version only if it's newer than the formula/cask.
* `--json`:
Output information in JSON format.
* `-r`, `--resources`:
Also check resources for formulae.
* `-q`, `--quiet`:
Suppress warnings, don't print a progress bar for JSON output.
* `--formula`:

View File

@ -432,6 +432,10 @@ Install formulae without checking for previously installed keg\-only or non\-mig
Print the verification and postinstall steps\.
.
.TP
\fB\-n\fR, \fB\-\-dry\-run\fR
Show what would be installed, but do not actually install anything\.
.
.TP
\fB\-\-formula\fR
Treat all named arguments as formulae\.
.
@ -1810,6 +1814,10 @@ Show the latest version only if it\'s newer than the formula/cask\.
Output information in JSON format\.
.
.TP
\fB\-r\fR, \fB\-\-resources\fR
Also check resources for formulae\.
.
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Suppress warnings, don\'t print a progress bar for JSON output\.
.