Merge pull request #8578 from SeekingMeaning/livecheck/casks
livecheck: add support for casks
This commit is contained in:
commit
baac12b0bd
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
require "locale"
|
require "locale"
|
||||||
require "lazy_object"
|
require "lazy_object"
|
||||||
|
require "livecheck"
|
||||||
|
|
||||||
require "cask/artifact"
|
require "cask/artifact"
|
||||||
|
|
||||||
@ -81,6 +82,8 @@ module Cask
|
|||||||
:version,
|
:version,
|
||||||
:appdir,
|
:appdir,
|
||||||
:discontinued?,
|
:discontinued?,
|
||||||
|
:livecheck,
|
||||||
|
:livecheckable?,
|
||||||
*ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key),
|
*ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key),
|
||||||
*ACTIVATABLE_ARTIFACT_CLASSES.map(&:dsl_key),
|
*ACTIVATABLE_ARTIFACT_CLASSES.map(&:dsl_key),
|
||||||
*ARTIFACT_BLOCK_CLASSES.flat_map { |klass| [klass.dsl_key, klass.uninstall_dsl_key] },
|
*ARTIFACT_BLOCK_CLASSES.flat_map { |klass| [klass.dsl_key, klass.uninstall_dsl_key] },
|
||||||
@ -273,6 +276,20 @@ module Cask
|
|||||||
set_unique_stanza(:auto_updates, auto_updates.nil?) { auto_updates }
|
set_unique_stanza(:auto_updates, auto_updates.nil?) { auto_updates }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def livecheck(&block)
|
||||||
|
@livecheck ||= Livecheck.new(self)
|
||||||
|
return @livecheck unless block
|
||||||
|
|
||||||
|
raise CaskInvalidError.new(cask, "'livecheck' stanza may only appear once.") if @livecheckable
|
||||||
|
|
||||||
|
@livecheckable = true
|
||||||
|
@livecheck.instance_eval(&block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def livecheckable?
|
||||||
|
@livecheckable == true
|
||||||
|
end
|
||||||
|
|
||||||
ORDINARY_ARTIFACT_CLASSES.each do |klass|
|
ORDINARY_ARTIFACT_CLASSES.each do |klass|
|
||||||
define_method(klass.dsl_key) do |*args|
|
define_method(klass.dsl_key) do |*args|
|
||||||
if [*artifacts.map(&:class), klass].include?(Artifact::StageOnly) &&
|
if [*artifacts.map(&:class), klass].include?(Artifact::StageOnly) &&
|
||||||
|
|||||||
@ -20,29 +20,35 @@ module Homebrew
|
|||||||
def livecheck_args
|
def livecheck_args
|
||||||
Homebrew::CLI::Parser.new do
|
Homebrew::CLI::Parser.new do
|
||||||
usage_banner <<~EOS
|
usage_banner <<~EOS
|
||||||
`livecheck` [<formulae>]
|
`livecheck` [<formulae>|<casks>]
|
||||||
|
|
||||||
Check for newer versions of formulae from upstream.
|
Check for newer versions of formulae and/or casks from upstream.
|
||||||
|
|
||||||
If no formula argument is passed, the list of formulae to check is taken from `HOMEBREW_LIVECHECK_WATCHLIST`
|
If no formula or cask argument is passed, the list of formulae and
|
||||||
or `~/.brew_livecheck_watchlist`.
|
casks to check is taken from `HOMEBREW_LIVECHECK_WATCHLIST` or
|
||||||
|
`~/.brew_livecheck_watchlist`.
|
||||||
EOS
|
EOS
|
||||||
switch "--full-name",
|
switch "--full-name",
|
||||||
description: "Print formulae with fully-qualified names."
|
description: "Print formulae/casks with fully-qualified names."
|
||||||
flag "--tap=",
|
flag "--tap=",
|
||||||
description: "Check formulae within the given tap, specified as <user>`/`<repo>."
|
description: "Check formulae/casks within the given tap, specified as <user>`/`<repo>."
|
||||||
switch "--all",
|
switch "--all",
|
||||||
description: "Check all available formulae."
|
description: "Check all available formulae/casks."
|
||||||
switch "--installed",
|
switch "--installed",
|
||||||
description: "Check formulae that are currently installed."
|
description: "Check formulae/casks that are currently installed."
|
||||||
switch "--newer-only",
|
switch "--newer-only",
|
||||||
description: "Show the latest version only if it's newer than the formula."
|
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 "-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",
|
||||||
|
description: "Only check formulae."
|
||||||
|
switch "--cask", "--casks",
|
||||||
|
description: "Only check casks."
|
||||||
conflicts "--debug", "--json"
|
conflicts "--debug", "--json"
|
||||||
conflicts "--tap=", "--all", "--installed"
|
conflicts "--tap=", "--all", "--installed"
|
||||||
|
conflicts "--cask", "--formula"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -54,28 +60,47 @@ module Homebrew
|
|||||||
puts ENV["HOMEBREW_LIVECHECK_WATCHLIST"] if ENV["HOMEBREW_LIVECHECK_WATCHLIST"].present?
|
puts ENV["HOMEBREW_LIVECHECK_WATCHLIST"] if ENV["HOMEBREW_LIVECHECK_WATCHLIST"].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
formulae_to_check = if args.tap
|
formulae_and_casks_to_check = if args.tap
|
||||||
Tap.fetch(args.tap).formula_names.map { |name| Formula[name] }
|
tap = Tap.fetch(args.tap)
|
||||||
|
formulae = args.cask? ? [] : tap.formula_files.map { |path| Formulary.factory(path) }
|
||||||
|
casks = args.formula? ? [] : tap.cask_files.map { |path| Cask::CaskLoader.load(path) }
|
||||||
|
formulae + casks
|
||||||
elsif args.installed?
|
elsif args.installed?
|
||||||
Formula.installed
|
formulae = args.cask? ? [] : Formula.installed
|
||||||
|
casks = args.formula? ? [] : Cask::Caskroom.casks
|
||||||
|
formulae + casks
|
||||||
elsif args.all?
|
elsif args.all?
|
||||||
Formula
|
formulae = args.cask? ? [] : Formula.to_a
|
||||||
elsif (formulae_args = args.named.to_formulae) && formulae_args.present?
|
casks = args.formula? ? [] : Cask::Cask.to_a
|
||||||
formulae_args
|
formulae + casks
|
||||||
|
elsif args.named.present?
|
||||||
|
if args.formula?
|
||||||
|
args.named.to_formulae
|
||||||
|
elsif args.cask?
|
||||||
|
args.named.to_casks
|
||||||
|
else
|
||||||
|
args.named.to_formulae_and_casks
|
||||||
|
end
|
||||||
elsif File.exist?(WATCHLIST_PATH)
|
elsif File.exist?(WATCHLIST_PATH)
|
||||||
begin
|
begin
|
||||||
Pathname.new(WATCHLIST_PATH).read.lines.map do |line|
|
names = Pathname.new(WATCHLIST_PATH).read.lines
|
||||||
next if line.start_with?("#")
|
.reject { |line| line.start_with?("#") || line.blank? }
|
||||||
|
.map(&:strip)
|
||||||
|
|
||||||
Formula[line.strip]
|
named_args = T.unsafe(CLI::NamedArgs).new(*names)
|
||||||
end.compact
|
named_args.to_formulae_and_casks.reject do |formula_or_cask|
|
||||||
|
(args.formula? && !formula_or_cask.is_a?(Formula)) ||
|
||||||
|
(args.cask? && !formula_or_cask.is_a?(Cask::Cask))
|
||||||
|
end
|
||||||
rescue Errno::ENOENT => e
|
rescue Errno::ENOENT => e
|
||||||
onoe e
|
onoe e
|
||||||
end
|
end
|
||||||
|
end.sort_by do |formula_or_cask|
|
||||||
|
formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
|
||||||
end
|
end
|
||||||
|
|
||||||
raise UsageError, "No formulae to check." if formulae_to_check.blank?
|
raise UsageError, "No formulae or casks to check." if formulae_and_casks_to_check.blank?
|
||||||
|
|
||||||
Livecheck.livecheck_formulae(formulae_to_check, args)
|
Livecheck.run_checks(formulae_and_casks_to_check, args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,20 +1,20 @@
|
|||||||
# typed: true
|
# typed: true
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# The {Livecheck} class implements the DSL methods used in a formula's
|
# The {Livecheck} class implements the DSL methods used in a formula's or cask's
|
||||||
# `livecheck` block and stores related instance variables. Most of these methods
|
# `livecheck` block and stores related instance variables. Most of these methods
|
||||||
# also return the related instance variable when no argument is provided.
|
# also return the related instance variable when no argument is provided.
|
||||||
#
|
#
|
||||||
# This information is used by the `brew livecheck` command to control its
|
# This information is used by the `brew livecheck` command to control its
|
||||||
# behavior.
|
# behavior.
|
||||||
class Livecheck
|
class Livecheck
|
||||||
# A very brief description of why the formula is skipped (e.g. `No longer
|
# A very brief description of why the formula/cask is skipped (e.g. `No longer
|
||||||
# developed or maintained`).
|
# developed or maintained`).
|
||||||
# @return [String, nil]
|
# @return [String, nil]
|
||||||
attr_reader :skip_msg
|
attr_reader :skip_msg
|
||||||
|
|
||||||
def initialize(formula)
|
def initialize(formula_or_cask)
|
||||||
@formula = formula
|
@formula_or_cask = formula_or_cask
|
||||||
@regex = nil
|
@regex = nil
|
||||||
@skip = false
|
@skip = false
|
||||||
@skip_msg = nil
|
@skip_msg = nil
|
||||||
@ -40,10 +40,10 @@ class Livecheck
|
|||||||
|
|
||||||
# Sets the `@skip` instance variable to `true` and sets the `@skip_msg`
|
# Sets the `@skip` instance variable to `true` and sets the `@skip_msg`
|
||||||
# instance variable if a `String` is provided. `@skip` is used to indicate
|
# instance variable if a `String` is provided. `@skip` is used to indicate
|
||||||
# that the formula should be skipped and the `skip_msg` very briefly describes
|
# that the formula/cask should be skipped and the `skip_msg` very briefly
|
||||||
# why the formula is skipped (e.g. "No longer developed or maintained").
|
# describes why it is skipped (e.g. "No longer developed or maintained").
|
||||||
#
|
#
|
||||||
# @param skip_msg [String] string describing why the formula is skipped
|
# @param skip_msg [String] string describing why the formula/cask is skipped
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def skip(skip_msg = nil)
|
def skip(skip_msg = nil)
|
||||||
if skip_msg.is_a?(String)
|
if skip_msg.is_a?(String)
|
||||||
@ -55,7 +55,7 @@ class Livecheck
|
|||||||
@skip = true
|
@skip = true
|
||||||
end
|
end
|
||||||
|
|
||||||
# Should `livecheck` skip this formula?
|
# Should `livecheck` skip this formula/cask?
|
||||||
def skip?
|
def skip?
|
||||||
@skip
|
@skip
|
||||||
end
|
end
|
||||||
@ -81,18 +81,21 @@ class Livecheck
|
|||||||
# Sets the `@url` instance variable to the provided argument or returns the
|
# Sets the `@url` instance variable to the provided argument or returns the
|
||||||
# `@url` instance variable when no argument is provided. The argument can be
|
# `@url` instance variable when no argument is provided. The argument can be
|
||||||
# a `String` (a URL) or a supported `Symbol` corresponding to a URL in the
|
# a `String` (a URL) or a supported `Symbol` corresponding to a URL in the
|
||||||
# formula (e.g. `:stable`, `:homepage`, or `:head`).
|
# formula/cask (e.g. `:stable`, `:homepage`, `:head`, `:cask_url`, `:appcast`).
|
||||||
#
|
|
||||||
# @param val [String, Symbol] URL to check for version information
|
# @param val [String, Symbol] URL to check for version information
|
||||||
# @return [String, nil]
|
# @return [String, nil]
|
||||||
def url(val = nil)
|
def url(val = nil)
|
||||||
@url = case val
|
@url = case val
|
||||||
when nil
|
when nil
|
||||||
return @url
|
return @url
|
||||||
|
when :appcast
|
||||||
|
@formula_or_cask.appcast.to_s
|
||||||
|
when :cask_url
|
||||||
|
@formula_or_cask.url.to_s
|
||||||
when :head, :stable
|
when :head, :stable
|
||||||
@formula.send(val).url
|
@formula_or_cask.send(val).url
|
||||||
when :homepage
|
when :homepage
|
||||||
@formula.homepage
|
@formula_or_cask.homepage
|
||||||
when String
|
when String
|
||||||
val
|
val
|
||||||
else
|
else
|
||||||
|
|||||||
@ -41,18 +41,18 @@ module Homebrew
|
|||||||
rc
|
rc
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
# Executes the livecheck logic for each formula in the `formulae_to_check` array
|
# Executes the livecheck logic for each formula/cask in the
|
||||||
# and prints the results.
|
# `formulae_and_casks_to_check` array and prints the results.
|
||||||
# @return [nil]
|
# @return [nil]
|
||||||
def livecheck_formulae(formulae_to_check, args)
|
def run_checks(formulae_and_casks_to_check, args)
|
||||||
# Identify any non-homebrew/core taps in use for current formulae
|
# Identify any non-homebrew/core taps in use for current formulae
|
||||||
non_core_taps = {}
|
non_core_taps = {}
|
||||||
formulae_to_check.each do |f|
|
formulae_and_casks_to_check.each do |formula_or_cask|
|
||||||
next if f.tap.blank?
|
next if formula_or_cask.tap.blank?
|
||||||
next if f.tap.name == CoreTap.instance.name
|
next if formula_or_cask.tap.name == CoreTap.instance.name
|
||||||
next if non_core_taps[f.tap.name]
|
next if non_core_taps[formula_or_cask.tap.name]
|
||||||
|
|
||||||
non_core_taps[f.tap.name] = f.tap
|
non_core_taps[formula_or_cask.tap.name] = formula_or_cask.tap
|
||||||
end
|
end
|
||||||
non_core_taps = non_core_taps.sort.to_h
|
non_core_taps = non_core_taps.sort.to_h
|
||||||
|
|
||||||
@ -73,10 +73,10 @@ module Homebrew
|
|||||||
has_a_newer_upstream_version = false
|
has_a_newer_upstream_version = false
|
||||||
|
|
||||||
if args.json? && !args.quiet? && $stderr.tty?
|
if args.json? && !args.quiet? && $stderr.tty?
|
||||||
total_formulae = if formulae_to_check == Formula
|
formulae_and_casks_total = if formulae_and_casks_to_check == Formula
|
||||||
formulae_to_check.count
|
formulae_and_casks_to_check.count
|
||||||
else
|
else
|
||||||
formulae_to_check.length
|
formulae_and_casks_to_check.length
|
||||||
end
|
end
|
||||||
|
|
||||||
Tty.with($stderr) do |stderr|
|
Tty.with($stderr) do |stderr|
|
||||||
@ -84,7 +84,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
progress = ProgressBar.create(
|
progress = ProgressBar.create(
|
||||||
total: total_formulae,
|
total: formulae_and_casks_total,
|
||||||
progress_mark: "#",
|
progress_mark: "#",
|
||||||
remainder_mark: ".",
|
remainder_mark: ".",
|
||||||
format: " %t: [%B] %c/%C ",
|
format: " %t: [%B] %c/%C ",
|
||||||
@ -92,7 +92,10 @@ module Homebrew
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
formulae_checked = formulae_to_check.sort.map.with_index do |formula, i|
|
formulae_checked = formulae_and_casks_to_check.map.with_index do |formula_or_cask, i|
|
||||||
|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
||||||
|
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
|
||||||
|
|
||||||
if args.debug? && i.positive?
|
if args.debug? && i.positive?
|
||||||
puts <<~EOS
|
puts <<~EOS
|
||||||
|
|
||||||
@ -101,25 +104,29 @@ module Homebrew
|
|||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
skip_result = skip_conditions(formula, args: args)
|
skip_result = skip_conditions(formula_or_cask, args: args)
|
||||||
next skip_result if skip_result != false
|
next skip_result if skip_result != false
|
||||||
|
|
||||||
formula.head&.downloader&.shutup!
|
formula&.head&.downloader&.shutup!
|
||||||
|
|
||||||
# Use the `stable` version for comparison except for installed
|
# Use the `stable` version for comparison except for installed
|
||||||
# head-only formulae. A formula with `stable` and `head` that's
|
# head-only formulae. A formula with `stable` and `head` that's
|
||||||
# installed using `--head` will still use the `stable` version for
|
# installed using `--head` will still use the `stable` version for
|
||||||
# comparison.
|
# comparison.
|
||||||
current = if formula.head_only?
|
current = if formula
|
||||||
formula.any_installed_version.version.commit
|
if formula.head_only?
|
||||||
|
formula.any_installed_version.version.commit
|
||||||
|
else
|
||||||
|
formula.stable.version
|
||||||
|
end
|
||||||
else
|
else
|
||||||
formula.stable.version
|
Version.new(formula_or_cask.version)
|
||||||
end
|
end
|
||||||
|
|
||||||
latest = if formula.head_only?
|
latest = if formula&.head_only?
|
||||||
formula.head.downloader.fetch_last_commit
|
formula.head.downloader.fetch_last_commit
|
||||||
else
|
else
|
||||||
version_info = latest_version(formula, args: args)
|
version_info = latest_version(formula_or_cask, args: args)
|
||||||
version_info[:latest] if version_info.present?
|
version_info[:latest] if version_info.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -129,14 +136,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, "error", [no_versions_msg], args: args)
|
next status_hash(formula_or_cask, "error", [no_versions_msg], args: args)
|
||||||
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$/)
|
||||||
latest = Version.new(m[1])
|
latest = Version.new(m[1])
|
||||||
end
|
end
|
||||||
|
|
||||||
is_outdated = if formula.head_only?
|
is_outdated = if formula&.head_only?
|
||||||
# A HEAD-only formula is considered outdated if the latest upstream
|
# A HEAD-only formula is considered outdated if the latest upstream
|
||||||
# commit hash is different than the installed version's commit hash
|
# commit hash is different than the installed version's commit hash
|
||||||
(current != latest)
|
(current != latest)
|
||||||
@ -144,21 +151,21 @@ module Homebrew
|
|||||||
(current < latest)
|
(current < latest)
|
||||||
end
|
end
|
||||||
|
|
||||||
is_newer_than_upstream = formula.stable? && (current > latest)
|
is_newer_than_upstream = (formula&.stable? || cask) && (current > latest)
|
||||||
|
|
||||||
info = {
|
info = {}
|
||||||
formula: formula_name(formula, args: args),
|
info[:formula] = formula_name(formula, args: args) if formula
|
||||||
version: {
|
info[:cask] = cask_name(cask, args: args) if cask
|
||||||
current: current.to_s,
|
info[:version] = {
|
||||||
latest: latest.to_s,
|
current: current.to_s,
|
||||||
outdated: is_outdated,
|
latest: latest.to_s,
|
||||||
newer_than_upstream: is_newer_than_upstream,
|
outdated: is_outdated,
|
||||||
},
|
newer_than_upstream: is_newer_than_upstream,
|
||||||
meta: {
|
|
||||||
livecheckable: formula.livecheckable?,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
info[:meta][:head_only] = true if formula.head_only?
|
info[:meta] = {
|
||||||
|
livecheckable: formula_or_cask.livecheckable?,
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
|
||||||
next if args.newer_only? && !info[:version][:outdated]
|
next if args.newer_only? && !info[:version][:outdated]
|
||||||
@ -178,9 +185,9 @@ module Homebrew
|
|||||||
|
|
||||||
if args.json?
|
if args.json?
|
||||||
progress&.increment
|
progress&.increment
|
||||||
status_hash(formula, "error", [e.to_s], args: args)
|
status_hash(formula_or_cask, "error", [e.to_s], args: args)
|
||||||
elsif !args.quiet?
|
elsif !args.quiet?
|
||||||
onoe "#{Tty.blue}#{formula_name(formula, args: args)}#{Tty.reset}: #{e}"
|
onoe "#{Tty.blue}#{formula_or_cask_name(formula_or_cask, args: args)}#{Tty.reset}: #{e}"
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -201,6 +208,19 @@ module Homebrew
|
|||||||
puts JSON.generate(formulae_checked.compact)
|
puts JSON.generate(formulae_checked.compact)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def formula_or_cask_name(formula_or_cask, args:)
|
||||||
|
case formula_or_cask
|
||||||
|
when Formula
|
||||||
|
formula_name(formula_or_cask, args: args)
|
||||||
|
when Cask::Cask
|
||||||
|
cask_name(formula_or_cask, args: args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def cask_name(cask, args:)
|
||||||
|
args.full_name? ? cask.full_name : cask.token
|
||||||
|
end
|
||||||
|
|
||||||
# Returns the fully-qualified name of a formula if the `full_name` argument is
|
# Returns the fully-qualified name of a formula if the `full_name` argument is
|
||||||
# provided; returns the name otherwise.
|
# provided; returns the name otherwise.
|
||||||
# @return [String]
|
# @return [String]
|
||||||
@ -208,18 +228,24 @@ module Homebrew
|
|||||||
args.full_name? ? formula.full_name : formula.name
|
args.full_name? ? formula.full_name : formula.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def status_hash(formula, status_str, messages = nil, args:)
|
def status_hash(formula_or_cask, status_str, messages = nil, args:)
|
||||||
status_hash = {
|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
||||||
formula: formula_name(formula, args: args),
|
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
|
||||||
status: status_str,
|
|
||||||
}
|
status_hash = {}
|
||||||
|
if formula
|
||||||
|
status_hash[:formula] = formula_name(formula, args: args)
|
||||||
|
elsif cask
|
||||||
|
status_hash[:cask] = cask_name(formula_or_cask, args: args)
|
||||||
|
end
|
||||||
|
status_hash[:status] = status_str
|
||||||
status_hash[:messages] = messages if messages.is_a?(Array)
|
status_hash[:messages] = messages if messages.is_a?(Array)
|
||||||
|
|
||||||
if args.verbose?
|
if args.verbose?
|
||||||
status_hash[:meta] = {
|
status_hash[:meta] = {
|
||||||
livecheckable: formula.livecheckable?,
|
livecheckable: formula_or_cask.livecheckable?,
|
||||||
}
|
}
|
||||||
status_hash[:meta][:head_only] = true if formula.head_only?
|
status_hash[:meta][:head_only] = true if formula&.head_only?
|
||||||
end
|
end
|
||||||
|
|
||||||
status_hash
|
status_hash
|
||||||
@ -228,29 +254,31 @@ module Homebrew
|
|||||||
# If a formula has to be skipped, it prints or returns a Hash contaning the reason
|
# If a formula has to be skipped, it prints or returns a Hash contaning the reason
|
||||||
# for doing so; returns false otherwise.
|
# for doing so; returns false otherwise.
|
||||||
# @return [Hash, nil, Boolean]
|
# @return [Hash, nil, Boolean]
|
||||||
def skip_conditions(formula, args:)
|
def skip_conditions(formula_or_cask, args:)
|
||||||
if formula.deprecated? && !formula.livecheckable?
|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
||||||
|
|
||||||
|
if formula&.deprecated? && !formula.livecheckable?
|
||||||
return status_hash(formula, "deprecated", args: args) if args.json?
|
return status_hash(formula, "deprecated", args: args) if args.json?
|
||||||
|
|
||||||
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : deprecated" unless args.quiet?
|
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : deprecated" unless args.quiet?
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if formula.disabled? && !formula.livecheckable?
|
if formula&.disabled? && !formula.livecheckable?
|
||||||
return status_hash(formula, "disabled", args: args) if args.json?
|
return status_hash(formula, "disabled", args: args) if args.json?
|
||||||
|
|
||||||
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : disabled" unless args.quiet?
|
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : disabled" unless args.quiet?
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if formula.versioned_formula? && !formula.livecheckable?
|
if formula&.versioned_formula? && !formula.livecheckable?
|
||||||
return status_hash(formula, "versioned", args: args) if args.json?
|
return status_hash(formula, "versioned", args: args) if args.json?
|
||||||
|
|
||||||
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : versioned" unless args.quiet?
|
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : versioned" unless args.quiet?
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if formula.head_only? && !formula.any_version_installed?
|
if formula&.head_only? && !formula.any_version_installed?
|
||||||
head_only_msg = "HEAD only formula must be installed to be livecheckable"
|
head_only_msg = "HEAD only formula must be installed to be livecheckable"
|
||||||
return status_hash(formula, "error", [head_only_msg], args: args) if args.json?
|
return status_hash(formula, "error", [head_only_msg], args: args) if args.json?
|
||||||
|
|
||||||
@ -258,21 +286,21 @@ module Homebrew
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
is_gist = formula.stable&.url&.include?("gist.github.com")
|
is_gist = formula&.stable&.url&.include?("gist.github.com")
|
||||||
if formula.livecheck.skip? || is_gist
|
if formula_or_cask.livecheck.skip? || is_gist
|
||||||
skip_msg = if formula.livecheck.skip_msg.is_a?(String) &&
|
skip_msg = if formula_or_cask.livecheck.skip_msg.is_a?(String) &&
|
||||||
formula.livecheck.skip_msg.present?
|
formula_or_cask.livecheck.skip_msg.present?
|
||||||
formula.livecheck.skip_msg.to_s
|
formula_or_cask.livecheck.skip_msg.to_s
|
||||||
elsif is_gist
|
elsif is_gist
|
||||||
"Stable URL is a GitHub Gist"
|
"Stable URL is a GitHub Gist"
|
||||||
else
|
else
|
||||||
""
|
""
|
||||||
end
|
end
|
||||||
|
|
||||||
return status_hash(formula, "skipped", (skip_msg.blank? ? nil : [skip_msg]), args: args) if args.json?
|
return status_hash(formula_or_cask, "skipped", (skip_msg.blank? ? nil : [skip_msg]), args: args) if args.json?
|
||||||
|
|
||||||
unless args.quiet?
|
unless args.quiet?
|
||||||
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : skipped" \
|
puts "#{Tty.red}#{formula_or_cask_name(formula_or_cask, args: args)}#{Tty.reset} : skipped" \
|
||||||
"#{" - #{skip_msg}" if skip_msg.present?}"
|
"#{" - #{skip_msg}" if skip_msg.present?}"
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
@ -284,8 +312,8 @@ module Homebrew
|
|||||||
# Formats and prints the livecheck result for a formula.
|
# Formats and prints the livecheck result for a formula.
|
||||||
# @return [nil]
|
# @return [nil]
|
||||||
def print_latest_version(info, args:)
|
def print_latest_version(info, args:)
|
||||||
formula_s = "#{Tty.blue}#{info[:formula]}#{Tty.reset}"
|
formula_or_cask_s = "#{Tty.blue}#{info[:formula] || info[:cask]}#{Tty.reset}"
|
||||||
formula_s += " (guessed)" if !info[:meta][:livecheckable] && args.verbose?
|
formula_or_cask_s += " (guessed)" if !info[:meta][:livecheckable] && args.verbose?
|
||||||
|
|
||||||
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}"
|
||||||
@ -299,19 +327,27 @@ module Homebrew
|
|||||||
info[:version][:latest]
|
info[:version][:latest]
|
||||||
end
|
end
|
||||||
|
|
||||||
puts "#{formula_s} : #{current_s} ==> #{latest_s}"
|
puts "#{formula_or_cask_s} : #{current_s} ==> #{latest_s}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an Array containing the formula URLs that can be used by livecheck.
|
# Returns an Array containing the formula/cask URLs that can be used by livecheck.
|
||||||
# @return [Array]
|
# @return [Array]
|
||||||
def checkable_urls(formula)
|
def checkable_urls(formula_or_cask)
|
||||||
urls = []
|
urls = []
|
||||||
urls << formula.head.url if formula.head
|
|
||||||
if formula.stable
|
case formula_or_cask
|
||||||
urls << formula.stable.url
|
when Formula
|
||||||
urls.concat(formula.stable.mirrors)
|
urls << formula_or_cask.head.url if formula_or_cask.head
|
||||||
|
if formula_or_cask.stable
|
||||||
|
urls << formula_or_cask.stable.url
|
||||||
|
urls.concat(formula_or_cask.stable.mirrors)
|
||||||
|
end
|
||||||
|
urls << formula_or_cask.homepage if formula_or_cask.homepage
|
||||||
|
when Cask::Cask
|
||||||
|
urls << formula_or_cask.appcast.to_s if formula_or_cask.appcast
|
||||||
|
urls << formula_or_cask.url.to_s if formula_or_cask.url
|
||||||
|
urls << formula_or_cask.homepage if formula_or_cask.homepage
|
||||||
end
|
end
|
||||||
urls << formula.homepage if formula.homepage
|
|
||||||
|
|
||||||
urls.compact
|
urls.compact
|
||||||
end
|
end
|
||||||
@ -357,20 +393,27 @@ module Homebrew
|
|||||||
# Identifies the latest version of the formula and returns a Hash containing
|
# Identifies the latest version of the formula and returns a Hash containing
|
||||||
# the version information. Returns nil if a latest version couldn't be found.
|
# the version information. Returns nil if a latest version couldn't be found.
|
||||||
# @return [Hash, nil]
|
# @return [Hash, nil]
|
||||||
def latest_version(formula, args:)
|
def latest_version(formula_or_cask, args:)
|
||||||
has_livecheckable = formula.livecheckable?
|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
||||||
livecheck = formula.livecheck
|
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
|
||||||
|
|
||||||
|
has_livecheckable = formula_or_cask.livecheckable?
|
||||||
|
livecheck = formula_or_cask.livecheck
|
||||||
livecheck_regex = livecheck.regex
|
livecheck_regex = livecheck.regex
|
||||||
livecheck_strategy = livecheck.strategy
|
livecheck_strategy = livecheck.strategy
|
||||||
livecheck_url = livecheck.url
|
livecheck_url = livecheck.url
|
||||||
|
|
||||||
urls = [livecheck_url] if livecheck_url.present?
|
urls = [livecheck_url] if livecheck_url.present?
|
||||||
urls ||= checkable_urls(formula)
|
urls ||= checkable_urls(formula_or_cask)
|
||||||
|
|
||||||
if args.debug?
|
if args.debug?
|
||||||
puts
|
puts
|
||||||
puts "Formula: #{formula_name(formula, args: args)}"
|
if formula
|
||||||
puts "Head only?: true" if formula.head_only?
|
puts "Formula: #{formula_name(formula, args: args)}"
|
||||||
|
puts "Head only?: true" if formula.head_only?
|
||||||
|
elsif cask
|
||||||
|
puts "Cask: #{cask_name(formula_or_cask, args: args)}"
|
||||||
|
end
|
||||||
puts "Livecheckable?: #{has_livecheckable ? "Yes" : "No"}"
|
puts "Livecheckable?: #{has_livecheckable ? "Yes" : "No"}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ module RuboCop
|
|||||||
[:version, :sha256],
|
[:version, :sha256],
|
||||||
[:language],
|
[:language],
|
||||||
[:url, :appcast, :name, :desc, :homepage],
|
[:url, :appcast, :name, :desc, :homepage],
|
||||||
|
[:livecheck],
|
||||||
[
|
[
|
||||||
:auto_updates,
|
:auto_updates,
|
||||||
:conflicts_with,
|
:conflicts_with,
|
||||||
|
|||||||
@ -74,6 +74,23 @@ describe Homebrew::Livecheck do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:c) do
|
||||||
|
Cask::CaskLoader.load(+<<-RUBY)
|
||||||
|
cask "test" do
|
||||||
|
version "0.0.1,2"
|
||||||
|
|
||||||
|
url "https://brew.sh/test-0.0.1.tgz"
|
||||||
|
name "Test"
|
||||||
|
homepage "https://brew.sh"
|
||||||
|
|
||||||
|
livecheck do
|
||||||
|
url "https://formulae.brew.sh/api/formula/ruby.json"
|
||||||
|
regex(/"stable":"(\d+(?:\.\d+)+)"/i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
let(:args) { double("livecheck_args", full_name?: false, json?: false, quiet?: false, verbose?: true) }
|
let(:args) { double("livecheck_args", full_name?: false, json?: false, quiet?: false, verbose?: true) }
|
||||||
|
|
||||||
describe "::formula_name" do
|
describe "::formula_name" do
|
||||||
@ -88,6 +105,18 @@ describe Homebrew::Livecheck do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "::cask_name" do
|
||||||
|
it "returns the token of the cask" do
|
||||||
|
expect(livecheck.cask_name(c, args: args)).to eq("test")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the full name of the cask" do
|
||||||
|
allow(args).to receive(:full_name?).and_return(true)
|
||||||
|
|
||||||
|
expect(livecheck.cask_name(c, args: args)).to eq("test")
|
||||||
|
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" do
|
||||||
expect(livecheck.status_hash(f, "error", ["Unable to get versions"], args: args))
|
expect(livecheck.status_hash(f, "error", ["Unable to get versions"], args: args))
|
||||||
@ -142,6 +171,10 @@ describe Homebrew::Livecheck do
|
|||||||
it "returns false for a non-skippable formula" do
|
it "returns false for a non-skippable formula" do
|
||||||
expect(livecheck.skip_conditions(f, args: args)).to eq(false)
|
expect(livecheck.skip_conditions(f, args: args)).to eq(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns false for a non-skippable cask" do
|
||||||
|
expect(livecheck.skip_conditions(c, args: args)).to eq(false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "::checkable_urls" do
|
describe "::checkable_urls" do
|
||||||
@ -150,6 +183,7 @@ describe Homebrew::Livecheck do
|
|||||||
.to eq(
|
.to eq(
|
||||||
["https://github.com/Homebrew/brew.git", "https://brew.sh/test-0.0.1.tgz", "https://brew.sh"],
|
["https://github.com/Homebrew/brew.git", "https://brew.sh/test-0.0.1.tgz", "https://brew.sh"],
|
||||||
)
|
)
|
||||||
|
expect(livecheck.checkable_urls(c)).to eq(["https://brew.sh/test-0.0.1.tgz", "https://brew.sh"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1044,27 +1044,32 @@ provided, check all kegs. Raises an error if run on uninstalled formulae.
|
|||||||
* `--cached`:
|
* `--cached`:
|
||||||
Print the cached linkage values stored in `HOMEBREW_CACHE`, set by a previous `brew linkage` run.
|
Print the cached linkage values stored in `HOMEBREW_CACHE`, set by a previous `brew linkage` run.
|
||||||
|
|
||||||
### `livecheck` [*`formulae`*]
|
### `livecheck` [*`formulae`*|*`casks`*]
|
||||||
|
|
||||||
Check for newer versions of formulae from upstream.
|
Check for newer versions of formulae and/or casks from upstream.
|
||||||
|
|
||||||
If no formula argument is passed, the list of formulae to check is taken from `HOMEBREW_LIVECHECK_WATCHLIST`
|
If no formula or cask argument is passed, the list of formulae and
|
||||||
or `~/.brew_livecheck_watchlist`.
|
casks to check is taken from `HOMEBREW_LIVECHECK_WATCHLIST` or
|
||||||
|
`~/.brew_livecheck_watchlist`.
|
||||||
|
|
||||||
* `--full-name`:
|
* `--full-name`:
|
||||||
Print formulae with fully-qualified names.
|
Print formulae/casks with fully-qualified names.
|
||||||
* `--tap`:
|
* `--tap`:
|
||||||
Check formulae within the given tap, specified as *`user`*`/`*`repo`*.
|
Check formulae/casks within the given tap, specified as *`user`*`/`*`repo`*.
|
||||||
* `--all`:
|
* `--all`:
|
||||||
Check all available formulae.
|
Check all available formulae/casks.
|
||||||
* `--installed`:
|
* `--installed`:
|
||||||
Check formulae that are currently installed.
|
Check formulae/casks that are currently installed.
|
||||||
* `--newer-only`:
|
* `--newer-only`:
|
||||||
Show the latest version only if it's newer than the formula.
|
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.
|
||||||
* `-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`:
|
||||||
|
Only check formulae.
|
||||||
|
* `--cask`:
|
||||||
|
Only check casks.
|
||||||
|
|
||||||
### `man` [*`options`*]
|
### `man` [*`options`*]
|
||||||
|
|
||||||
|
|||||||
@ -1442,31 +1442,31 @@ For every library that a keg references, print its dylib path followed by the bi
|
|||||||
\fB\-\-cached\fR
|
\fB\-\-cached\fR
|
||||||
Print the cached linkage values stored in \fBHOMEBREW_CACHE\fR, set by a previous \fBbrew linkage\fR run\.
|
Print the cached linkage values stored in \fBHOMEBREW_CACHE\fR, set by a previous \fBbrew linkage\fR run\.
|
||||||
.
|
.
|
||||||
.SS "\fBlivecheck\fR [\fIformulae\fR]"
|
.SS "\fBlivecheck\fR [\fIformulae\fR|\fIcasks\fR]"
|
||||||
Check for newer versions of formulae from upstream\.
|
Check for newer versions of formulae and/or casks from upstream\.
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
If no formula argument is passed, the list of formulae to check is taken from \fBHOMEBREW_LIVECHECK_WATCHLIST\fR or \fB~/\.brew_livecheck_watchlist\fR\.
|
If no formula or cask argument is passed, the list of formulae and casks to check is taken from \fBHOMEBREW_LIVECHECK_WATCHLIST\fR or \fB~/\.brew_livecheck_watchlist\fR\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-full\-name\fR
|
\fB\-\-full\-name\fR
|
||||||
Print formulae with fully\-qualified names\.
|
Print formulae/casks with fully\-qualified names\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-tap\fR
|
\fB\-\-tap\fR
|
||||||
Check formulae within the given tap, specified as \fIuser\fR\fB/\fR\fIrepo\fR\.
|
Check formulae/casks within the given tap, specified as \fIuser\fR\fB/\fR\fIrepo\fR\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-all\fR
|
\fB\-\-all\fR
|
||||||
Check all available formulae\.
|
Check all available formulae/casks\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-installed\fR
|
\fB\-\-installed\fR
|
||||||
Check formulae that are currently installed\.
|
Check formulae/casks that are currently installed\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-newer\-only\fR
|
\fB\-\-newer\-only\fR
|
||||||
Show the latest version only if it\'s newer than the formula\.
|
Show the latest version only if it\'s newer than the formula/cask\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-json\fR
|
\fB\-\-json\fR
|
||||||
@ -1476,6 +1476,14 @@ Output information in JSON format\.
|
|||||||
\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\.
|
||||||
.
|
.
|
||||||
|
.TP
|
||||||
|
\fB\-\-formula\fR
|
||||||
|
Only check formulae\.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
\fB\-\-cask\fR
|
||||||
|
Only check casks\.
|
||||||
|
.
|
||||||
.SS "\fBman\fR [\fIoptions\fR]"
|
.SS "\fBman\fR [\fIoptions\fR]"
|
||||||
Generate Homebrew\'s manpages\.
|
Generate Homebrew\'s manpages\.
|
||||||
.
|
.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user