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

View File

@ -508,18 +508,9 @@ else
: "${HOMEBREW_OS_VERSION:=$(uname -r)}" : "${HOMEBREW_OS_VERSION:=$(uname -r)}"
HOMEBREW_OS_USER_AGENT_VERSION="${HOMEBREW_OS_VERSION}" HOMEBREW_OS_USER_AGENT_VERSION="${HOMEBREW_OS_VERSION}"
# This is set by the user environment. # Ensure the system Curl is a version that supports modern HTTPS certificates.
# shellcheck disable=SC2154 HOMEBREW_MINIMUM_CURL_VERSION="7.41.0"
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
curl_version_output="$(${HOMEBREW_CURL} --version 2>/dev/null)" curl_version_output="$(${HOMEBREW_CURL} --version 2>/dev/null)"
curl_name_and_version="${curl_version_output%% (*}" curl_name_and_version="${curl_version_output%% (*}"
# shellcheck disable=SC2248 # shellcheck disable=SC2248

View File

@ -56,7 +56,8 @@ module Cask
require_sha: nil, require_sha: nil,
quarantine: nil, quarantine: nil,
quiet: nil, quiet: nil,
zap: nil zap: nil,
dry_run: nil
) )
odie "Installing casks is supported only on macOS" unless OS.mac? odie "Installing casks is supported only on macOS" unless OS.mac?
@ -73,6 +74,27 @@ module Cask
options[:quarantine] = true if options[:quarantine].nil? 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" require "cask/installer"
casks.each do |cask| casks.each do |cask|

View File

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

View File

@ -45,6 +45,8 @@ module Homebrew
"(binaries and symlinks are excluded, unless originally from the same cask)." "(binaries and symlinks are excluded, unless originally from the same cask)."
switch "-v", "--verbose", switch "-v", "--verbose",
description: "Print the verification and postinstall steps." 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", { [:switch, "--formula", "--formulae", {
description: "Treat all named arguments as formulae.", description: "Treat all named arguments as formulae.",
@ -193,6 +195,7 @@ module Homebrew
skip_cask_deps: args.skip_cask_deps?, skip_cask_deps: args.skip_cask_deps?,
quarantine: args.quarantine?, quarantine: args.quarantine?,
quiet: args.quiet?, quiet: args.quiet?,
dry_run: args.dry_run?,
) )
end end
@ -242,6 +245,7 @@ module Homebrew
debug: args.debug?, debug: args.debug?,
quiet: args.quiet?, quiet: args.quiet?,
verbose: args.verbose?, verbose: args.verbose?,
dry_run: args.dry_run?,
) )
Upgrade.check_installed_dependents( Upgrade.check_installed_dependents(
@ -257,9 +261,10 @@ module Homebrew
debug: args.debug?, debug: args.debug?,
quiet: args.quiet?, quiet: args.quiet?,
verbose: args.verbose?, 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?) Homebrew.messages.display_messages(display_times: args.display_times?)
rescue FormulaUnreadableError, FormulaClassUnavailableError, rescue FormulaUnreadableError, FormulaClassUnavailableError,

View File

@ -188,19 +188,6 @@ module Homebrew
GitHub.create_bump_pr(pr_info, args: args) GitHub.create_bump_pr(pr_info, args: args)
end 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:) def check_open_pull_requests(cask, args:)
tap_remote_repo = cask.tap.remote_repo || cask.tap.full_name tap_remote_repo = cask.tap.remote_repo || cask.tap.full_name
GitHub.check_for_duplicate_pull_requests(cask.token, tap_remote_repo, GitHub.check_for_duplicate_pull_requests(cask.token, tap_remote_repo,

View File

@ -72,17 +72,18 @@ module Homebrew
ambiguous_casks = [] ambiguous_casks = []
if !args.formula? && !args.cask? if !args.formula? && !args.cask?
ambiguous_casks = formulae_and_casks.group_by { |item| Livecheck.formula_or_cask_name(item, full_name: true) } ambiguous_casks = formulae_and_casks \
.values .group_by { |item| Livecheck.package_or_resource_name(item, full_name: true) }
.select { |items| items.length > 1 } .values
.flatten .select { |items| items.length > 1 }
.select { |item| item.is_a?(Cask::Cask) } .flatten
.select { |item| item.is_a?(Cask::Cask) }
end end
ambiguous_names = [] ambiguous_names = []
unless args.full_name? unless args.full_name?
ambiguous_names = 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 .values
.select { |items| items.length > 1 } .select { |items| items.length > 1 }
.flatten .flatten
@ -92,7 +93,7 @@ module Homebrew
puts if i.positive? puts if i.positive?
use_full_name = args.full_name? || ambiguous_names.include?(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) name = Livecheck.package_or_resource_name(formula_or_cask, full_name: use_full_name)
repository = if formula_or_cask.is_a?(Formula) repository = if formula_or_cask.is_a?(Formula)
if formula_or_cask.head_only? if formula_or_cask.head_only?
ohai name ohai name
@ -157,7 +158,7 @@ module Homebrew
rescue rescue
next next
end end
name = Livecheck.formula_or_cask_name(formula_or_cask) name = Livecheck.package_or_resource_name(formula_or_cask)
ambiguous_cask = begin ambiguous_cask = begin
formula_or_cask.is_a?(Cask::Cask) && !args.cask? && Formula[name] formula_or_cask.is_a?(Cask::Cask) && !args.cask? && Formula[name]
rescue FormulaUnavailableError rescue FormulaUnavailableError
@ -178,7 +179,7 @@ module Homebrew
end end
def livecheck_result(formula_or_cask) 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, = referenced_formula_or_cask, =
Livecheck.resolve_livecheck_reference(formula_or_cask, full_name: false, debug: false) 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." description: "Show the latest version only if it's newer than the formula/cask."
switch "--json", switch "--json",
description: "Output information in JSON format." description: "Output information in JSON format."
switch "-r", "--resources",
description: "Also check resources for formulae."
switch "-q", "--quiet", switch "-q", "--quiet",
description: "Suppress warnings, don't print a progress bar for JSON output." description: "Suppress warnings, don't print a progress bar for JSON output."
switch "--formula", "--formulae", switch "--formula", "--formulae",
@ -101,6 +103,7 @@ module Homebrew
else else
raise UsageError, "A watchlist file is required when no arguments are given." raise UsageError, "A watchlist file is required when no arguments are given."
end end
formulae_and_casks_to_check = formulae_and_casks_to_check.sort_by do |formula_or_cask| 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 formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
end end
@ -111,6 +114,7 @@ module Homebrew
json: args.json?, json: args.json?,
full_name: args.full_name?, full_name: args.full_name?,
handle_name_conflict: !args.formula? && !args.cask?, handle_name_conflict: !args.formula? && !args.cask?,
check_resources: args.resources?,
newer_only: args.newer_only?, newer_only: args.newer_only?,
quiet: args.quiet?, quiet: args.quiet?,
debug: args.debug?, debug: args.debug?,

View File

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

View File

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

View File

@ -278,10 +278,11 @@ module Homebrew
overwrite: false, overwrite: false,
debug: false, debug: false,
quiet: false, quiet: false,
verbose: false verbose: false,
dry_run: false
) )
formula_installers = formulae_to_install.map do |f| 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 build_options = f.build
fi = FormulaInstaller.new( fi = FormulaInstaller.new(
@ -307,8 +308,10 @@ module Homebrew
) )
begin begin
fi.prelude unless dry_run
fi.fetch fi.prelude
fi.fetch
end
fi fi
rescue CannotInstallFormulaError => e rescue CannotInstallFormulaError => e
ofail e.message ofail e.message
@ -319,6 +322,20 @@ module Homebrew
end end
end.compact 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| formula_installers.each do |fi|
install_formula(fi) install_formula(fi)
Cleanup.install_formula_clean!(fi.formula) Cleanup.install_formula_clean!(fi.formula)
@ -333,6 +350,15 @@ module Homebrew
Upgrade.install_formula(formula_installer, upgrade: upgrade) Upgrade.install_formula(formula_installer, upgrade: upgrade)
end end
private_class_method :install_formula 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
end end

View File

@ -126,11 +126,11 @@ module Homebrew
if debug if debug
# Print the chain of references for debugging # Print the chain of references for debugging
puts "Reference Chain:" 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 << referenced_formula_or_cask
references.each do |ref_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
end end
@ -157,11 +157,14 @@ module Homebrew
# Executes the livecheck logic for each formula/cask in the # Executes the livecheck logic for each formula/cask in the
# `formulae_and_casks_to_check` array and prints the results. # `formulae_and_casks_to_check` array and prints the results.
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
sig { sig {
params( params(
formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)], formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)],
full_name: T::Boolean, full_name: T::Boolean,
handle_name_conflict: T::Boolean, handle_name_conflict: T::Boolean,
check_resources: T::Boolean,
json: T::Boolean, json: T::Boolean,
newer_only: T::Boolean, newer_only: T::Boolean,
debug: T::Boolean, debug: T::Boolean,
@ -171,24 +174,25 @@ module Homebrew
} }
def run_checks( def run_checks(
formulae_and_casks_to_check, 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 debug: false, quiet: false, verbose: false
) )
load_other_tap_strategies(formulae_and_casks_to_check) load_other_tap_strategies(formulae_and_casks_to_check)
ambiguous_casks = [] ambiguous_casks = []
if handle_name_conflict if handle_name_conflict
ambiguous_casks = formulae_and_casks_to_check.group_by { |item| formula_or_cask_name(item, full_name: true) } ambiguous_casks = formulae_and_casks_to_check \
.values .group_by { |item| package_or_resource_name(item, full_name: true) }
.select { |items| items.length > 1 } .values
.flatten .select { |items| items.length > 1 }
.select { |item| item.is_a?(Cask::Cask) } .flatten
.select { |item| item.is_a?(Cask::Cask) }
end end
ambiguous_names = [] ambiguous_names = []
unless full_name unless full_name
ambiguous_names = 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 .values
.select { |items| items.length > 1 } .select { |items| items.length > 1 }
.flatten .flatten
@ -218,7 +222,7 @@ module Homebrew
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask) cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
use_full_name = full_name || ambiguous_names.include?(formula_or_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 = referenced_formula_or_cask, livecheck_references =
resolve_livecheck_reference(formula_or_cask, full_name: use_full_name, debug: debug) 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? version_info[:latest] if version_info.present?
end 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? if latest.blank?
no_versions_msg = "Unable to get versions" no_versions_msg = "Unable to get versions"
raise Livecheck::Error, no_versions_msg unless json 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 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 end
if (m = latest.to_s.match(/(.*)-release$/)) && !current.to_s.match(/.*-release$/) 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][:head_only] = true if formula&.head_only?
info[:meta].merge!(version_info[:meta]) if version_info.present? && version_info.key?(:meta) 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] next if newer_only && !info[:version][:outdated]
has_a_newer_upstream_version ||= true has_a_newer_upstream_version ||= true
@ -331,10 +368,12 @@ module Homebrew
if json if json
progress&.increment progress&.increment
info.except!(:meta) unless verbose info.except!(:meta) unless verbose
resource_version_info.map! { |r| r.except!(:meta) } if check_for_resources && !verbose
next info next info
end end
puts if debug
print_latest_version(info, verbose: verbose, ambiguous_cask: ambiguous_casks.include?(formula_or_cask)) 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 nil
rescue => e rescue => e
Homebrew.failed = true Homebrew.failed = true
@ -344,11 +383,12 @@ module Homebrew
progress&.increment progress&.increment
status_hash(formula_or_cask, "error", [e.to_s], full_name: use_full_name, verbose: verbose) unless quiet status_hash(formula_or_cask, "error", [e.to_s], full_name: use_full_name, verbose: verbose) unless quiet
elsif !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) name += " (cask)" if ambiguous_casks.include?(formula_or_cask)
onoe "#{Tty.blue}#{name}#{Tty.reset}: #{e}" onoe "#{Tty.blue}#{name}#{Tty.reset}: #{e}"
$stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error) $stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error)
print_resources_info(resource_version_info, verbose: verbose) if check_for_resources
nil nil
end end
end end
@ -367,16 +407,20 @@ module Homebrew
puts JSON.pretty_generate(formulae_checked.compact) puts JSON.pretty_generate(formulae_checked.compact)
end 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) } sig { params(package_or_resource: T.any(Formula, Cask::Cask, Resource), full_name: T::Boolean).returns(String) }
def formula_or_cask_name(formula_or_cask, full_name: false) def package_or_resource_name(package_or_resource, full_name: false)
case formula_or_cask case package_or_resource
when Formula when Formula
formula_name(formula_or_cask, full_name: full_name) formula_name(package_or_resource, full_name: full_name)
when Cask::Cask 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 else
T.absurd(formula_or_cask) T.absurd(package_or_resource)
end end
end end
@ -396,40 +440,44 @@ module Homebrew
sig { sig {
params( params(
formula_or_cask: T.any(Formula, Cask::Cask), package_or_resource: T.any(Formula, Cask::Cask, Resource),
status_str: String, status_str: String,
messages: T.nilable(T::Array[String]), messages: T.nilable(T::Array[String]),
full_name: T::Boolean, full_name: T::Boolean,
verbose: T::Boolean, verbose: T::Boolean,
).returns(Hash) ).returns(Hash)
} }
def status_hash(formula_or_cask, status_str, messages = nil, full_name: false, verbose: false) def status_hash(package_or_resource, status_str, messages = nil, full_name: false, verbose: false)
formula = formula_or_cask if formula_or_cask.is_a?(Formula) formula = package_or_resource if package_or_resource.is_a?(Formula)
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask) 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 = {} status_hash = {}
if formula if formula
status_hash[:formula] = formula_name(formula, full_name: full_name) status_hash[:formula] = formula_name(formula, full_name: full_name)
elsif cask 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 end
status_hash[:status] = status_str status_hash[:status] = status_str
status_hash[:messages] = messages if messages.is_a?(Array) status_hash[:messages] = messages if messages.is_a?(Array)
status_hash[:meta] = { 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[:meta][:head_only] = true if formula&.head_only?
status_hash status_hash
end 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 } sig { params(info: Hash, verbose: T::Boolean, ambiguous_cask: T::Boolean).void }
def print_latest_version(info, verbose:, ambiguous_cask: false) def print_latest_version(info, verbose: false, ambiguous_cask: false)
formula_or_cask_s = "#{Tty.blue}#{info[:formula] || info[:cask]}#{Tty.reset}" package_or_resource_s = info[:resource].present? ? " " : ""
formula_or_cask_s += " (cask)" if ambiguous_cask package_or_resource_s += "#{Tty.blue}#{info[:formula] || info[:cask] || info[:resource]}#{Tty.reset}"
formula_or_cask_s += " (guessed)" if !info[:meta][:livecheckable] && verbose 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] current_s = if info[:version][:newer_than_upstream]
"#{Tty.red}#{info[:version][:current]}#{Tty.reset}" "#{Tty.red}#{info[:version][:current]}#{Tty.reset}"
@ -443,47 +491,61 @@ module Homebrew
info[:version][:latest] info[:version][:latest]
end 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 end
sig { sig {
params( params(
livecheck_url: T.any(String, Symbol), livecheck_url: T.any(String, Symbol),
formula_or_cask: T.any(Formula, Cask::Cask), package_or_resource: T.any(Formula, Cask::Cask, Resource),
).returns(T.nilable(String)) ).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 case livecheck_url
when String when String
livecheck_url livecheck_url
when :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 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 when :homepage
formula_or_cask.homepage package_or_resource.homepage unless package_or_resource.is_a?(Resource)
end end
end end
# Returns an Array containing the formula/cask URLs that can be used by livecheck. # Returns an Array containing the formula/cask/resource URLs that can be used by livecheck.
sig { params(formula_or_cask: T.any(Formula, Cask::Cask)).returns(T::Array[String]) } sig { params(package_or_resource: T.any(Formula, Cask::Cask, Resource)).returns(T::Array[String]) }
def checkable_urls(formula_or_cask) def checkable_urls(package_or_resource)
urls = [] urls = []
case formula_or_cask case package_or_resource
when Formula when Formula
if formula_or_cask.stable if package_or_resource.stable
urls << formula_or_cask.stable.url urls << package_or_resource.stable.url
urls.concat(formula_or_cask.stable.mirrors) urls.concat(package_or_resource.stable.mirrors)
end end
urls << formula_or_cask.head.url if formula_or_cask.head urls << package_or_resource.head.url if package_or_resource.head
urls << formula_or_cask.homepage if formula_or_cask.homepage urls << package_or_resource.homepage if package_or_resource.homepage
when Cask::Cask when Cask::Cask
urls << formula_or_cask.appcast.to_s if formula_or_cask.appcast urls << package_or_resource.appcast.to_s if package_or_resource.appcast
urls << formula_or_cask.url.to_s if formula_or_cask.url urls << package_or_resource.url.to_s if package_or_resource.url
urls << formula_or_cask.homepage if formula_or_cask.homepage urls << package_or_resource.homepage if package_or_resource.homepage
when Resource
urls << package_or_resource.url
else else
T.absurd(formula_or_cask) T.absurd(package_or_resource)
end end
urls.compact.uniq urls.compact.uniq
@ -561,7 +623,7 @@ module Homebrew
homebrew_curl_root_domains.include?(url_root_domain) homebrew_curl_root_domains.include?(url_root_domain)
end 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. # the version information. Returns nil if a latest version couldn't be found.
# rubocop:disable Metrics/CyclomaticComplexity # rubocop:disable Metrics/CyclomaticComplexity
sig { sig {
@ -713,7 +775,6 @@ module Homebrew
version.to_s.include?(rejection) version.to_s.include?(rejection)
end end
end end
next if match_version_map.blank? next if match_version_map.blank?
if debug if debug
@ -770,6 +831,195 @@ module Homebrew
nil nil
end end
# rubocop:enable Metrics/CyclomaticComplexity # 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 end
# rubocop:enable Metrics/ModuleLength # rubocop:enable Metrics/ModuleLength
end end

View File

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

View File

@ -6,7 +6,7 @@ require "livecheck/livecheck"
module Homebrew module Homebrew
module Livecheck module Livecheck
# The `Livecheck::SkipConditions` module primarily contains methods that # 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 # @api private
module SkipConditions module SkipConditions
@ -16,14 +16,14 @@ module Homebrew
sig { sig {
params( params(
formula_or_cask: T.any(Formula, Cask::Cask), package_or_resource: T.any(Formula, Cask::Cask, Resource),
livecheckable: T::Boolean, livecheckable: T::Boolean,
full_name: T::Boolean, full_name: T::Boolean,
verbose: T::Boolean, verbose: T::Boolean,
).returns(Hash) ).returns(Hash)
} }
def formula_or_cask_skip(formula_or_cask, livecheckable, full_name: false, verbose: false) def package_or_resource_skip(package_or_resource, livecheckable, full_name: false, verbose: false)
formula = formula_or_cask if formula_or_cask.is_a?(Formula) formula = package_or_resource if package_or_resource.is_a?(Formula)
if (stable_url = formula&.stable&.url) if (stable_url = formula&.stable&.url)
stable_is_gist = stable_url.match?(%r{https?://gist\.github(?:usercontent)?\.com/}i) 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) stable_from_internet_archive = stable_url.match?(%r{https?://web\.archive\.org/}i)
end end
skip_message = if formula_or_cask.livecheck.skip_msg.present? skip_message = if package_or_resource.livecheck.skip_msg.present?
formula_or_cask.livecheck.skip_msg package_or_resource.livecheck.skip_msg
elsif !livecheckable elsif !livecheckable
if stable_from_google_code_archive if stable_from_google_code_archive
"Stable URL is from Google Code Archive" "Stable URL is from Google Code Archive"
@ -45,10 +45,10 @@ module Homebrew
end end
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 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 end
sig { sig {
@ -157,7 +157,7 @@ module Homebrew
# Skip conditions for formulae. # Skip conditions for formulae.
FORMULA_CHECKS = [ FORMULA_CHECKS = [
:formula_or_cask_skip, :package_or_resource_skip,
:formula_head_only, :formula_head_only,
:formula_deprecated, :formula_deprecated,
:formula_disabled, :formula_disabled,
@ -166,76 +166,85 @@ module Homebrew
# Skip conditions for casks. # Skip conditions for casks.
CASK_CHECKS = [ CASK_CHECKS = [
:formula_or_cask_skip, :package_or_resource_skip,
:cask_discontinued, :cask_discontinued,
:cask_version_latest, :cask_version_latest,
:cask_url_unversioned, :cask_url_unversioned,
].freeze ].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 # `Livecheck#status_hash`, which contains a `status` type and sometimes
# error `messages`. # error `messages`.
sig { sig {
params( params(
formula_or_cask: T.any(Formula, Cask::Cask), package_or_resource: T.any(Formula, Cask::Cask, Resource),
full_name: T::Boolean, full_name: T::Boolean,
verbose: T::Boolean, verbose: T::Boolean,
).returns(Hash) ).returns(Hash)
} }
def skip_information(formula_or_cask, full_name: false, verbose: false) def skip_information(package_or_resource, full_name: false, verbose: false)
livecheckable = formula_or_cask.livecheckable? livecheckable = package_or_resource.livecheckable?
checks = case formula_or_cask checks = case package_or_resource
when Formula when Formula
FORMULA_CHECKS FORMULA_CHECKS
when Cask::Cask when Cask::Cask
CASK_CHECKS CASK_CHECKS
when Resource
RESOURCE_CHECKS
end end
return {} unless checks return {} unless checks
checks.each do |method_name| 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? return skip_hash if skip_hash.present?
end end
{} {}
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 # are treated differently than normal. We only respect certain skip
# conditions (returning the related hash) and others are treated as # conditions (returning the related hash) and others are treated as
# errors. # errors.
sig { sig {
params( params(
livecheck_formula_or_cask: T.any(Formula, Cask::Cask), livecheck_package_or_resource: T.any(Formula, Cask::Cask, Resource),
original_formula_or_cask_name: String, original_package_or_resource_name: String,
full_name: T::Boolean, full_name: T::Boolean,
verbose: T::Boolean, verbose: T::Boolean,
).returns(T.nilable(Hash)) ).returns(T.nilable(Hash))
} }
def referenced_skip_information( def referenced_skip_information(
livecheck_formula_or_cask, livecheck_package_or_resource,
original_formula_or_cask_name, original_package_or_resource_name,
full_name: false, full_name: false,
verbose: false verbose: false
) )
skip_info = SkipConditions.skip_information( skip_info = SkipConditions.skip_information(
livecheck_formula_or_cask, livecheck_package_or_resource,
full_name: full_name, full_name: full_name,
verbose: verbose, verbose: verbose,
) )
return if skip_info.blank? return if skip_info.blank?
referenced_name = Livecheck.formula_or_cask_name(livecheck_formula_or_cask, full_name: full_name) referenced_name = Livecheck.package_or_resource_name(livecheck_package_or_resource, full_name: full_name)
referenced_type = case livecheck_formula_or_cask referenced_type = case livecheck_package_or_resource
when Formula when Formula
:formula :formula
when Cask::Cask when Cask::Cask
:cask :cask
when Resource
:resource
end end
if skip_info[:status] != "error" && 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" error_msg_end = if skip_info[:status] == "skipped"
"automatically skipped" "automatically skipped"
else else
@ -245,7 +254,7 @@ module Homebrew
raise "Referenced #{referenced_type} (#{referenced_name}) is #{error_msg_end}" raise "Referenced #{referenced_type} (#{referenced_name}) is #{error_msg_end}"
end end
skip_info[referenced_type] = original_formula_or_cask_name skip_info[referenced_type] = original_package_or_resource_name
skip_info skip_info
end end
@ -258,6 +267,8 @@ module Homebrew
skip_hash[:formula] skip_hash[:formula]
elsif skip_hash[:cask].is_a?(String) elsif skip_hash[:cask].is_a?(String)
skip_hash[:cask] skip_hash[:cask]
elsif skip_hash[:resource].is_a?(String)
" #{skip_hash[:resource]}"
end end
return unless name return unless name

View File

@ -11,6 +11,7 @@ describe Homebrew::Livecheck do
let(:homepage_url) { "https://brew.sh" } let(:homepage_url) { "https://brew.sh" }
let(:livecheck_url) { "https://formulae.brew.sh/api/formula/ruby.json" } let(:livecheck_url) { "https://formulae.brew.sh/api/formula/ruby.json" }
let(:stable_url) { "https://brew.sh/test-0.0.1.tgz" } 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 let(:f) do
formula("test") do formula("test") do
@ -23,9 +24,21 @@ describe Homebrew::Livecheck do
url "https://formulae.brew.sh/api/formula/ruby.json" url "https://formulae.brew.sh/api/formula/ruby.json"
regex(/"stable":"(\d+(?:\.\d+)+)"/i) regex(/"stable":"(\d+(?:\.\d+)+)"/i)
end 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
end end
let(:r) { f.resources.first }
let(:c) do let(:c) do
Cask::CaskLoader.load(+<<-RUBY) Cask::CaskLoader.load(+<<-RUBY)
cask "test" do cask "test" do
@ -44,15 +57,6 @@ describe Homebrew::Livecheck do
RUBY RUBY
end 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 describe "::resolve_livecheck_reference" do
context "when a formula/cask has a livecheck block without formula/cask methods" do context "when a formula/cask has a livecheck block without formula/cask methods" do
it "returns [nil, []]" do it "returns [nil, []]" do
@ -83,7 +87,7 @@ describe Homebrew::Livecheck do
end end
describe "::status_hash" do 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"])) expect(livecheck.status_hash(f, "error", ["Unable to get versions"]))
.to eq({ .to eq({
formula: "test", formula: "test",
@ -94,6 +98,18 @@ describe Homebrew::Livecheck do
}, },
}) })
end 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 end
describe "::livecheck_url_to_string" do describe "::livecheck_url_to_string" do
@ -101,15 +117,28 @@ describe Homebrew::Livecheck do
homepage_url_s = homepage_url homepage_url_s = homepage_url
stable_url_s = stable_url stable_url_s = stable_url
head_url_s = head_url head_url_s = head_url
resource_url_s = resource_url
formula("test_livecheck_url") do formula("test_livecheck_url") do
desc "Test Livecheck URL formula" desc "Test Livecheck URL formula"
homepage homepage_url_s homepage homepage_url_s
url stable_url_s url stable_url_s
head head_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
end end
let(:r_livecheck_url) { f_livecheck_url.resources.first }
let(:c_livecheck_url) do let(:c_livecheck_url) do
Cask::CaskLoader.load(+<<-RUBY) Cask::CaskLoader.load(+<<-RUBY)
cask "test_livecheck_url" do cask "test_livecheck_url" do
@ -123,30 +152,48 @@ describe Homebrew::Livecheck do
RUBY RUBY
end 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) expect(livecheck.livecheck_url_to_string(livecheck_url, f_livecheck_url)).to eq(livecheck_url)
end 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 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(: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, 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(: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(: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, c_livecheck_url)).to eq(cask_url)
expect(livecheck.livecheck_url_to_string(:url, r_livecheck_url)).to eq(resource_url)
end end
it "returns nil when not given a string or valid symbol" do 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, 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, 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, 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, c_livecheck_url)).to be_nil
expect(livecheck.livecheck_url_to_string(:invalid_symbol, r_livecheck_url)).to be_nil
end end
end end
describe "::checkable_urls" do 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 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(f)).to eq([stable_url, head_url, homepage_url])
expect(livecheck.checkable_urls(c)).to eq([cask_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]) expect(livecheck.checkable_urls(f_duplicate_urls)).to eq([stable_url, head_url])
end end
end end

View File

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

View File

@ -94,22 +94,6 @@ module Homebrew
.map { |k| Keg.new(k.resolved_path) } .map { |k| Keg.new(k.resolved_path) }
end 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) def print_upgrade_message(formula, fi_options)
version_upgrade = if formula.optlinked? version_upgrade = if formula.optlinked?
"#{Keg.new(formula.opt_prefix).version} -> #{formula.pkg_version}" "#{Keg.new(formula.opt_prefix).version} -> #{formula.pkg_version}"
@ -178,7 +162,14 @@ module Homebrew
formula = formula_installer.formula formula = formula_installer.formula
if dry_run 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 return
end 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/addressable-2.8.1/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.2/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}/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}/extensions/universal-darwin-21/2.6.0/msgpack-1.6.0"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.5.6/lib" $:.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}/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}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.13.0/lib"
$:.unshift "#{path}/" $:.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-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-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-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/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/ruby-progressbar-1.11.0/lib"
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-2.3.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 --debug-symbols
--dictionarydir --dictionarydir
--display-times --display-times
--dry-run
--fetch-HEAD --fetch-HEAD
--fontdir --fontdir
--force --force
@ -1171,6 +1172,7 @@ _brew_install() {
--debug-symbols --debug-symbols
--dictionarydir --dictionarydir
--display-times --display-times
--dry-run
--fetch-HEAD --fetch-HEAD
--fontdir --fontdir
--force --force
@ -1261,6 +1263,7 @@ _brew_lc() {
--json --json
--newer-only --newer-only
--quiet --quiet
--resources
--tap --tap
--verbose --verbose
" "
@ -1375,6 +1378,7 @@ _brew_livecheck() {
--json --json
--newer-only --newer-only
--quiet --quiet
--resources
--tap --tap
--verbose --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 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 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 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 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 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)' __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 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 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 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 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 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)' __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 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 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 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 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' -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)' __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 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 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 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 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' -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)' __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. ]' \ '(--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`)]' \ '(--formula)--dictionarydir[Target location for Dictionaries (default: `~/Library/Dictionaries`)]' \
'(--cask)--display-times[Print install times for each package at the end of the run]' \ '(--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]' \ '(--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`)]' \ '(--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)]' \ '--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. ]' \ '(--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`)]' \ '(--formula)--dictionarydir[Target location for Dictionaries (default: `~/Library/Dictionaries`)]' \
'(--cask)--display-times[Print install times for each package at the end of the run]' \ '(--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]' \ '(--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`)]' \ '(--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)]' \ '--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]' \ '(--debug)--json[Output information in JSON format]' \
'--newer-only[Show the latest version only if it'\''s newer than the formula/cask]' \ '--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]' \ '--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]' \ '(--eval-all --installed)--tap[Check formulae and casks within the given tap, specified as user`/`repo]' \
'--verbose[Make some output more verbose]' \ '--verbose[Make some output more verbose]' \
- formula \ - formula \
@ -1192,6 +1195,7 @@ _brew_livecheck() {
'(--debug)--json[Output information in JSON format]' \ '(--debug)--json[Output information in JSON format]' \
'--newer-only[Show the latest version only if it'\''s newer than the formula/cask]' \ '--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]' \ '--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]' \ '(--eval-all --installed)--tap[Check formulae and casks within the given tap, specified as user`/`repo]' \
'--verbose[Make some output more verbose]' \ '--verbose[Make some output more verbose]' \
- formula \ - 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: 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. 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. 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). 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. 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 ## 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). 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`: * `-v`, `--verbose`:
Print the verification and postinstall steps. Print the verification and postinstall steps.
* `-n`, `--dry-run`:
Show what would be installed, but do not actually install anything.
* `--formula`: * `--formula`:
Treat all named arguments as formulae. Treat all named arguments as formulae.
* `--ignore-dependencies`: * `--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. Show the latest version only if it's newer than the formula/cask.
* `--json`: * `--json`:
Output information in JSON format. Output information in JSON format.
* `-r`, `--resources`:
Also check resources for formulae.
* `-q`, `--quiet`: * `-q`, `--quiet`:
Suppress warnings, don't print a progress bar for JSON output. Suppress warnings, don't print a progress bar for JSON output.
* `--formula`: * `--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\. Print the verification and postinstall steps\.
. .
.TP .TP
\fB\-n\fR, \fB\-\-dry\-run\fR
Show what would be installed, but do not actually install anything\.
.
.TP
\fB\-\-formula\fR \fB\-\-formula\fR
Treat all named arguments as formulae\. 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\. Output information in JSON format\.
. .
.TP .TP
\fB\-r\fR, \fB\-\-resources\fR
Also check resources for formulae\.
.
.TP
\fB\-q\fR, \fB\-\-quiet\fR \fB\-q\fR, \fB\-\-quiet\fR
Suppress warnings, don\'t print a progress bar for JSON output\. Suppress warnings, don\'t print a progress bar for JSON output\.
. .