Merge remote-tracking branch 'origin/master' into metacollin/master
This commit is contained in:
commit
f42cbebd48
@ -23,4 +23,3 @@ require "cask/staged"
|
||||
require "cask/topological_hash"
|
||||
require "cask/url"
|
||||
require "cask/utils"
|
||||
require "cask/verify"
|
||||
|
||||
@ -255,20 +255,20 @@ module Cask
|
||||
add_error "you should use sha256 :no_check when version is :latest"
|
||||
end
|
||||
|
||||
def check_sha256_actually_256(sha256: cask.sha256, stanza: "sha256")
|
||||
odebug "Verifying #{stanza} string is a legal SHA-256 digest"
|
||||
return unless sha256.is_a?(String)
|
||||
return if sha256.length == 64 && sha256[/^[0-9a-f]+$/i]
|
||||
def check_sha256_actually_256
|
||||
odebug "Verifying sha256 string is a legal SHA-256 digest"
|
||||
return unless cask.sha256.is_a?(Checksum)
|
||||
return if cask.sha256.length == 64 && cask.sha256[/^[0-9a-f]+$/i]
|
||||
|
||||
add_error "#{stanza} string must be of 64 hexadecimal characters"
|
||||
add_error "sha256 string must be of 64 hexadecimal characters"
|
||||
end
|
||||
|
||||
def check_sha256_invalid(sha256: cask.sha256, stanza: "sha256")
|
||||
odebug "Verifying #{stanza} is not a known invalid value"
|
||||
def check_sha256_invalid
|
||||
odebug "Verifying sha256 is not a known invalid value"
|
||||
empty_sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
return unless sha256 == empty_sha256
|
||||
return unless cask.sha256 == empty_sha256
|
||||
|
||||
add_error "cannot use the sha256 for an empty string in #{stanza}: #{empty_sha256}"
|
||||
add_error "cannot use the sha256 for an empty string: #{empty_sha256}"
|
||||
end
|
||||
|
||||
def check_latest_with_appcast
|
||||
@ -428,8 +428,7 @@ module Cask
|
||||
return unless download && cask.url
|
||||
|
||||
odebug "Auditing download"
|
||||
downloaded_path = download.perform
|
||||
Verify.all(cask, downloaded_path)
|
||||
download.fetch
|
||||
rescue => e
|
||||
add_error "download not possible: #{e}"
|
||||
end
|
||||
|
||||
@ -32,7 +32,6 @@ module Cask
|
||||
require "cask/installer"
|
||||
|
||||
options = {
|
||||
force: args.force?,
|
||||
quarantine: args.quarantine?,
|
||||
}.compact
|
||||
|
||||
@ -41,8 +40,9 @@ module Cask
|
||||
casks.each do |cask|
|
||||
puts Installer.caveats(cask)
|
||||
ohai "Downloading external files for Cask #{cask}"
|
||||
downloaded_path = Download.new(cask, **options).perform
|
||||
Verify.all(cask, downloaded_path)
|
||||
download = Download.new(cask, **options)
|
||||
download.clear_cache if args.force?
|
||||
downloaded_path = download.fetch
|
||||
ohai "Success! Downloaded to -> #{downloaded_path}"
|
||||
end
|
||||
end
|
||||
|
||||
@ -32,6 +32,15 @@ module Cask
|
||||
|
||||
sig { void }
|
||||
def run
|
||||
self.class.zap_casks(*casks, verbose: args.verbose?, force: args.force?)
|
||||
end
|
||||
|
||||
sig { params(casks: Cask, force: T.nilable(T::Boolean), verbose: T.nilable(T::Boolean)).void }
|
||||
def self.zap_casks(
|
||||
*casks,
|
||||
force: nil,
|
||||
verbose: nil
|
||||
)
|
||||
require "cask/installer"
|
||||
|
||||
casks.each do |cask|
|
||||
@ -43,10 +52,10 @@ module Cask
|
||||
cask = CaskLoader.load(installed_caskfile)
|
||||
end
|
||||
else
|
||||
raise CaskNotInstalledError, cask unless args.force?
|
||||
raise CaskNotInstalledError, cask unless force
|
||||
end
|
||||
|
||||
Installer.new(cask, verbose: args.verbose?, force: args.force?).zap
|
||||
Installer.new(cask, verbose: verbose, force: force).zap
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -4,25 +4,32 @@
|
||||
require "fileutils"
|
||||
require "cask/cache"
|
||||
require "cask/quarantine"
|
||||
require "cask/verify"
|
||||
|
||||
module Cask
|
||||
# A download corresponding to a {Cask}.
|
||||
#
|
||||
# @api private
|
||||
class Download
|
||||
include Context
|
||||
|
||||
attr_reader :cask
|
||||
|
||||
def initialize(cask, force: false, quarantine: nil)
|
||||
def initialize(cask, quarantine: nil)
|
||||
@cask = cask
|
||||
@force = force
|
||||
@quarantine = quarantine
|
||||
end
|
||||
|
||||
def perform
|
||||
clear_cache
|
||||
fetch
|
||||
quarantine
|
||||
def fetch(verify_download_integrity: true)
|
||||
downloaded_path = begin
|
||||
downloader.fetch
|
||||
downloader.cached_location
|
||||
rescue => e
|
||||
error = CaskError.new("Download failed on Cask '#{cask}' with message: #{e}")
|
||||
error.set_backtrace e.backtrace
|
||||
raise error
|
||||
end
|
||||
quarantine(downloaded_path)
|
||||
self.verify_download_integrity(downloaded_path) if verify_download_integrity
|
||||
downloaded_path
|
||||
end
|
||||
|
||||
@ -33,32 +40,43 @@ module Cask
|
||||
end
|
||||
end
|
||||
|
||||
def clear_cache
|
||||
downloader.clear_cache
|
||||
end
|
||||
|
||||
def cached_download
|
||||
downloader.cached_location
|
||||
end
|
||||
|
||||
def verify_download_integrity(fn)
|
||||
if @cask.sha256 == :no_check
|
||||
opoo "No checksum defined for cask '#{@cask}', skipping verification."
|
||||
return
|
||||
end
|
||||
|
||||
begin
|
||||
ohai "Verifying checksum for cask '#{@cask}'." if verbose?
|
||||
fn.verify_checksum(@cask.sha256)
|
||||
rescue ChecksumMissingError
|
||||
opoo <<~EOS
|
||||
Cannot verify integrity of '#{fn.basename}'.
|
||||
No checksum was provided for this cask.
|
||||
For your reference, the checksum is:
|
||||
sha256 "#{fn.sha256}"
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :force
|
||||
attr_accessor :downloaded_path
|
||||
|
||||
def clear_cache
|
||||
downloader.clear_cache if force
|
||||
end
|
||||
|
||||
def fetch
|
||||
downloader.fetch
|
||||
@downloaded_path = downloader.cached_location
|
||||
rescue => e
|
||||
error = CaskError.new("Download failed on Cask '#{cask}' with message: #{e}")
|
||||
error.set_backtrace e.backtrace
|
||||
raise error
|
||||
end
|
||||
|
||||
def quarantine
|
||||
def quarantine(path)
|
||||
return if @quarantine.nil?
|
||||
return unless Quarantine.available?
|
||||
|
||||
if @quarantine
|
||||
Quarantine.cask!(cask: @cask, download_path: @downloaded_path)
|
||||
Quarantine.cask!(cask: @cask, download_path: path)
|
||||
else
|
||||
Quarantine.release!(download_path: @downloaded_path)
|
||||
Quarantine.release!(download_path: path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -205,11 +205,14 @@ module Cask
|
||||
|
||||
def sha256(arg = nil)
|
||||
set_unique_stanza(:sha256, arg.nil?) do
|
||||
if !arg.is_a?(String) && arg != :no_check
|
||||
case arg
|
||||
when :no_check
|
||||
arg
|
||||
when String
|
||||
Checksum.new(:sha256, arg)
|
||||
else
|
||||
raise CaskInvalidError.new(cask, "invalid 'sha256' value: '#{arg.inspect}'")
|
||||
end
|
||||
|
||||
arg
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -207,76 +207,6 @@ module Cask
|
||||
end
|
||||
end
|
||||
|
||||
# Error with a cask's checksum.
|
||||
#
|
||||
# @api private
|
||||
class CaskSha256Error < AbstractCaskErrorWithToken
|
||||
attr_reader :expected, :actual
|
||||
|
||||
def initialize(token, expected = nil, actual = nil)
|
||||
super(token)
|
||||
@expected = expected
|
||||
@actual = actual
|
||||
end
|
||||
end
|
||||
|
||||
# Error when a cask's checksum is missing.
|
||||
#
|
||||
# @api private
|
||||
class CaskSha256MissingError < CaskSha256Error
|
||||
extend T::Sig
|
||||
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
<<~EOS
|
||||
Cask '#{token}' requires a checksum:
|
||||
#{Formatter.identifier("sha256 \"#{actual}\"")}
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
# Error when a cask's checksum does not match.
|
||||
#
|
||||
# @api private
|
||||
class CaskSha256MismatchError < CaskSha256Error
|
||||
extend T::Sig
|
||||
|
||||
attr_reader :path
|
||||
|
||||
def initialize(token, expected, actual, path)
|
||||
super(token, expected, actual)
|
||||
@path = path
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
<<~EOS
|
||||
Checksum for Cask '#{token}' does not match.
|
||||
Expected: #{Formatter.success(expected.to_s)}
|
||||
Actual: #{Formatter.error(actual.to_s)}
|
||||
File: #{path}
|
||||
To retry an incomplete download, remove the file above.
|
||||
If the issue persists, visit:
|
||||
#{Formatter.url("https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/reporting_bugs/checksum_does_not_match_error.md")}
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
# Error when a cask has no checksum and the `--require-sha` flag is passed.
|
||||
#
|
||||
# @api private
|
||||
class CaskNoShasumError < CaskSha256Error
|
||||
extend T::Sig
|
||||
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
<<~EOS
|
||||
Cask '#{token}' does not have a sha256 checksum defined and was not installed.
|
||||
This means you have the #{Formatter.identifier("--require-sha")} option set, perhaps in your HOMEBREW_CASK_OPTS.
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
# Error during quarantining of a file.
|
||||
#
|
||||
# @api private
|
||||
|
||||
@ -8,7 +8,6 @@ require "cask/topological_hash"
|
||||
require "cask/config"
|
||||
require "cask/download"
|
||||
require "cask/staged"
|
||||
require "cask/verify"
|
||||
require "cask/quarantine"
|
||||
|
||||
require "cgi"
|
||||
@ -68,7 +67,6 @@ module Cask
|
||||
satisfy_dependencies
|
||||
|
||||
download
|
||||
verify
|
||||
end
|
||||
|
||||
def stage
|
||||
@ -156,7 +154,7 @@ module Cask
|
||||
return @downloaded_path if @downloaded_path
|
||||
|
||||
odebug "Downloading"
|
||||
@downloaded_path = Download.new(@cask, force: false, quarantine: quarantine?).perform
|
||||
@downloaded_path = Download.new(@cask, quarantine: quarantine?).fetch
|
||||
odebug "Downloaded to -> #{@downloaded_path}"
|
||||
@downloaded_path
|
||||
end
|
||||
@ -165,11 +163,10 @@ module Cask
|
||||
odebug "Checking cask has checksum"
|
||||
return unless @cask.sha256 == :no_check
|
||||
|
||||
raise CaskNoShasumError, @cask.token
|
||||
end
|
||||
|
||||
def verify
|
||||
Verify.all(@cask, @downloaded_path)
|
||||
raise CaskError, <<~EOS
|
||||
Cask '#{@cask}' does not have a sha256 checksum defined and was not installed.
|
||||
This means you have the #{Formatter.identifier("--require-sha")} option set, perhaps in your HOMEBREW_CASK_OPTS.
|
||||
EOS
|
||||
end
|
||||
|
||||
def primary_container
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Cask
|
||||
# Helper module for verifying a cask's checksum.
|
||||
#
|
||||
# @api private
|
||||
module Verify
|
||||
module_function
|
||||
|
||||
def all(cask, downloaded_path)
|
||||
if cask.sha256 == :no_check
|
||||
ohai "No SHA-256 checksum defined for Cask '#{cask}', skipping verification."
|
||||
return
|
||||
end
|
||||
|
||||
ohai "Verifying SHA-256 checksum for Cask '#{cask}'."
|
||||
|
||||
expected = cask.sha256
|
||||
computed = downloaded_path.sha256
|
||||
|
||||
raise CaskSha256MissingError.new(cask.token, expected, computed) if expected.nil? || expected.empty?
|
||||
|
||||
return if expected == computed
|
||||
|
||||
ohai "Note: Running `brew update` may fix SHA-256 checksum errors."
|
||||
raise CaskSha256MismatchError.new(cask.token, expected, computed, downloaded_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -13,12 +13,19 @@ class Checksum
|
||||
|
||||
def initialize(hash_type, hexdigest)
|
||||
@hash_type = hash_type
|
||||
@hexdigest = hexdigest
|
||||
@hexdigest = hexdigest.downcase
|
||||
end
|
||||
|
||||
delegate [:empty?, :to_s] => :@hexdigest
|
||||
delegate [:empty?, :to_s, :length, :[]] => :@hexdigest
|
||||
|
||||
def ==(other)
|
||||
hash_type == other&.hash_type && hexdigest == other.hexdigest
|
||||
case other
|
||||
when String
|
||||
to_s == other.downcase
|
||||
when Checksum
|
||||
hash_type == other.hash_type && hexdigest == other.hexdigest
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -113,7 +113,7 @@ module Homebrew
|
||||
|
||||
def build_from_source_formulae
|
||||
if build_from_source? || build_bottle?
|
||||
named.to_formulae.map(&:full_name)
|
||||
named.to_formulae_and_casks.select { |f| f.is_a?(Formula) }.map(&:full_name)
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
@ -35,10 +35,10 @@ module Homebrew
|
||||
@to_formulae ||= to_formulae_and_casks(only: :formula).freeze
|
||||
end
|
||||
|
||||
def to_formulae_and_casks(only: nil, method: nil)
|
||||
def to_formulae_and_casks(only: nil, ignore_unavailable: nil, method: nil)
|
||||
@to_formulae_and_casks ||= {}
|
||||
@to_formulae_and_casks[only] ||= begin
|
||||
to_objects(only: only, method: method).reject { |o| o.is_a?(Tap) }.freeze
|
||||
to_objects(only: only, ignore_unavailable: ignore_unavailable, method: method).freeze
|
||||
end
|
||||
end
|
||||
|
||||
@ -49,10 +49,10 @@ module Homebrew
|
||||
.map(&:freeze).freeze
|
||||
end
|
||||
|
||||
def to_formulae_and_casks_and_unavailable(method: nil)
|
||||
def to_formulae_and_casks_and_unavailable(only: nil, method: nil)
|
||||
@to_formulae_casks_unknowns ||= {}
|
||||
@to_formulae_casks_unknowns[method] = downcased_unique_named.map do |name|
|
||||
load_formula_or_cask(name, method: method)
|
||||
load_formula_or_cask(name, only: only, method: method)
|
||||
rescue FormulaOrCaskUnavailableError => e
|
||||
e
|
||||
end.uniq.freeze
|
||||
@ -68,6 +68,9 @@ module Homebrew
|
||||
resolve_formula(name)
|
||||
when :keg
|
||||
resolve_keg(name)
|
||||
when :kegs
|
||||
rack = Formulary.to_rack(name)
|
||||
rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : []
|
||||
else
|
||||
raise
|
||||
end
|
||||
@ -108,10 +111,12 @@ module Homebrew
|
||||
# Convert named arguments to {Formula} or {Cask} objects.
|
||||
# If both a formula and cask exist with the same name, returns the
|
||||
# formula and prints a warning unless `only` is specified.
|
||||
def to_objects(only: nil, method: nil)
|
||||
def to_objects(only: nil, ignore_unavailable: nil, method: nil)
|
||||
@to_objects ||= {}
|
||||
@to_objects[only] ||= downcased_unique_named.map do |name|
|
||||
@to_objects[only] ||= downcased_unique_named.flat_map do |name|
|
||||
load_formula_or_cask(name, only: only, method: method)
|
||||
rescue NoSuchKegError, FormulaUnavailableError, Cask::CaskUnavailableError
|
||||
ignore_unavailable ? [] : raise
|
||||
end.uniq.freeze
|
||||
end
|
||||
private :to_objects
|
||||
@ -142,7 +147,7 @@ module Homebrew
|
||||
paths << formula_path if formula_path.exist?
|
||||
paths << cask_path if cask_path.exist?
|
||||
|
||||
paths.empty? ? name : paths
|
||||
paths.empty? ? Pathname(name) : paths
|
||||
end
|
||||
end.uniq.freeze
|
||||
end
|
||||
@ -159,11 +164,17 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(only: T.nilable(Symbol)).returns([T::Array[Keg], T::Array[Cask::Cask]]) }
|
||||
def to_kegs_to_casks(only: nil)
|
||||
@to_kegs_to_casks ||= to_formulae_and_casks(only: only, method: :keg)
|
||||
.partition { |o| o.is_a?(Keg) }
|
||||
.map(&:freeze).freeze
|
||||
sig do
|
||||
params(only: T.nilable(Symbol), ignore_unavailable: T.nilable(T::Boolean), all_kegs: T.nilable(T::Boolean))
|
||||
.returns([T::Array[Keg], T::Array[Cask::Cask]])
|
||||
end
|
||||
def to_kegs_to_casks(only: nil, ignore_unavailable: nil, all_kegs: nil)
|
||||
method = all_kegs ? :kegs : :keg
|
||||
@to_kegs_to_casks ||= {}
|
||||
@to_kegs_to_casks[method] ||=
|
||||
to_formulae_and_casks(only: only, ignore_unavailable: ignore_unavailable, method: method)
|
||||
.partition { |o| o.is_a?(Keg) }
|
||||
.map(&:freeze).freeze
|
||||
end
|
||||
|
||||
sig { returns(T::Array[String]) }
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
require "formula"
|
||||
require "fetch"
|
||||
require "cli/parser"
|
||||
require "cask/download"
|
||||
|
||||
module Homebrew
|
||||
extend T::Sig
|
||||
@ -18,8 +19,8 @@ module Homebrew
|
||||
usage_banner <<~EOS
|
||||
`fetch` [<options>] <formula>
|
||||
|
||||
Download a bottle (if available) or source packages for <formula>.
|
||||
For tarballs, also print SHA-256 checksums.
|
||||
Download a bottle (if available) or source packages for <formula>e
|
||||
and binaries for <cask>s. For files, also print SHA-256 checksums.
|
||||
EOS
|
||||
switch "--HEAD",
|
||||
description: "Fetch HEAD version instead of stable version."
|
||||
@ -42,58 +43,98 @@ module Homebrew
|
||||
switch "--force-bottle",
|
||||
description: "Download a bottle if it exists for the current or newest version of macOS, "\
|
||||
"even if it would not be used during installation."
|
||||
switch "--[no-]quarantine",
|
||||
description: "Disable/enable quarantining of downloads (default: enabled).",
|
||||
env: :cask_opts_quarantine
|
||||
|
||||
switch "--formula", "--formulae",
|
||||
description: "Treat all named arguments as formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Treat all named arguments as casks."
|
||||
conflicts "--formula", "--cask"
|
||||
|
||||
conflicts "--devel", "--HEAD"
|
||||
conflicts "--build-from-source", "--build-bottle", "--force-bottle"
|
||||
min_named :formula
|
||||
conflicts "--cask", "--HEAD"
|
||||
conflicts "--cask", "--devel"
|
||||
conflicts "--cask", "--deps"
|
||||
conflicts "--cask", "-s"
|
||||
conflicts "--cask", "--build-bottle"
|
||||
conflicts "--cask", "--force-bottle"
|
||||
|
||||
min_named :formula_or_cask
|
||||
end
|
||||
end
|
||||
|
||||
def fetch
|
||||
args = fetch_args.parse
|
||||
|
||||
if args.deps?
|
||||
bucket = []
|
||||
args.named.to_formulae.each do |f|
|
||||
bucket << f
|
||||
bucket.concat f.recursive_dependencies.map(&:to_formula)
|
||||
end
|
||||
bucket.uniq!
|
||||
else
|
||||
bucket = args.named.to_formulae
|
||||
end
|
||||
only = :formula if args.formula? && !args.cask?
|
||||
only = :cask if args.cask? && !args.formula?
|
||||
|
||||
puts "Fetching: #{bucket * ", "}" if bucket.size > 1
|
||||
bucket.each do |f|
|
||||
f.print_tap_action verb: "Fetching"
|
||||
bucket = if args.deps?
|
||||
args.named.to_formulae_and_casks.flat_map do |formula_or_cask|
|
||||
case formula_or_cask
|
||||
when Formula
|
||||
f = formula_or_cask
|
||||
|
||||
fetched_bottle = false
|
||||
if fetch_bottle?(f, args: args)
|
||||
begin
|
||||
fetch_formula(f.bottle, args: args)
|
||||
rescue Interrupt
|
||||
raise
|
||||
rescue => e
|
||||
raise if Homebrew::EnvConfig.developer?
|
||||
|
||||
fetched_bottle = false
|
||||
onoe e.message
|
||||
opoo "Bottle fetch failed: fetching the source."
|
||||
[f, *f.recursive_dependencies.map(&:to_formula)]
|
||||
else
|
||||
fetched_bottle = true
|
||||
formula_or_cask
|
||||
end
|
||||
end
|
||||
else
|
||||
args.named.to_formulae_and_casks(only: only)
|
||||
end.uniq
|
||||
|
||||
next if fetched_bottle
|
||||
puts "Fetching: #{bucket * ", "}" if bucket.size > 1
|
||||
bucket.each do |formula_or_cask|
|
||||
case formula_or_cask
|
||||
when Formula
|
||||
f = formula_or_cask
|
||||
|
||||
fetch_formula(f, args: args)
|
||||
f.print_tap_action verb: "Fetching"
|
||||
|
||||
f.resources.each do |r|
|
||||
fetch_resource(r, args: args)
|
||||
r.patches.each { |p| fetch_patch(p, args: args) if p.external? }
|
||||
fetched_bottle = false
|
||||
if fetch_bottle?(f, args: args)
|
||||
begin
|
||||
fetch_formula(f.bottle, args: args)
|
||||
rescue Interrupt
|
||||
raise
|
||||
rescue => e
|
||||
raise if Homebrew::EnvConfig.developer?
|
||||
|
||||
fetched_bottle = false
|
||||
onoe e.message
|
||||
opoo "Bottle fetch failed: fetching the source."
|
||||
else
|
||||
fetched_bottle = true
|
||||
end
|
||||
end
|
||||
|
||||
next if fetched_bottle
|
||||
|
||||
fetch_formula(f, args: args)
|
||||
|
||||
f.resources.each do |r|
|
||||
fetch_resource(r, args: args)
|
||||
r.patches.each { |p| fetch_patch(p, args: args) if p.external? }
|
||||
end
|
||||
|
||||
f.patchlist.each { |p| fetch_patch(p, args: args) if p.external? }
|
||||
else
|
||||
cask = formula_or_cask
|
||||
|
||||
options = {
|
||||
force: args.force?,
|
||||
quarantine: args.quarantine?,
|
||||
}.compact
|
||||
|
||||
options[:quarantine] = true if options[:quarantine].nil?
|
||||
|
||||
download = Cask::Download.new(cask, **options)
|
||||
fetch_cask(download, args: args)
|
||||
end
|
||||
|
||||
f.patchlist.each { |p| fetch_patch(p, args: args) if p.external? }
|
||||
end
|
||||
end
|
||||
|
||||
@ -112,6 +153,13 @@ module Homebrew
|
||||
opoo "Formula reports different #{e.hash_type}: #{e.expected}"
|
||||
end
|
||||
|
||||
def fetch_cask(cask_download, args:)
|
||||
fetch_fetchable cask_download, args: args
|
||||
rescue ChecksumMismatchError => e
|
||||
retry if retry_fetch?(cask_download, args: args)
|
||||
opoo "Cask reports different #{e.hash_type}: #{e.expected}"
|
||||
end
|
||||
|
||||
def fetch_patch(p, args:)
|
||||
fetch_fetchable p, args: args
|
||||
rescue ChecksumMismatchError => e
|
||||
|
||||
@ -25,11 +25,11 @@ module Homebrew
|
||||
def info_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
usage_banner <<~EOS
|
||||
`info` [<options>] [<formula>]
|
||||
`info` [<options>] [<formula>|<cask>]
|
||||
|
||||
Display brief statistics for your Homebrew installation.
|
||||
|
||||
If <formula> is provided, show summary of information about <formula>.
|
||||
If a <formula> or <cask> is provided, show summary of information about it.
|
||||
EOS
|
||||
switch "--analytics",
|
||||
description: "List global Homebrew analytics data or, if specified, installation and "\
|
||||
@ -61,13 +61,23 @@ module Homebrew
|
||||
switch "-v", "--verbose",
|
||||
description: "Show more verbose analytics data for <formula>."
|
||||
|
||||
switch "--formula", "--formulae",
|
||||
description: "Treat all named arguments as formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Treat all named arguments as casks."
|
||||
conflicts "--formula", "--cask"
|
||||
|
||||
conflicts "--installed", "--all"
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def info
|
||||
args = info_args.parse
|
||||
|
||||
only = :formula if args.formula? && !args.cask?
|
||||
only = :cask if args.cask? && !args.formula?
|
||||
|
||||
if args.analytics?
|
||||
if args.days.present? && !VALID_DAYS.include?(args.days)
|
||||
raise UsageError, "--days must be one of #{VALID_DAYS.join(", ")}"
|
||||
@ -83,20 +93,21 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
print_analytics(args: args)
|
||||
print_analytics(args: args, only: only)
|
||||
elsif args.json
|
||||
print_json(args: args)
|
||||
print_json(args: args, only: only)
|
||||
elsif args.github?
|
||||
raise FormulaOrCaskUnspecifiedError if args.no_named?
|
||||
|
||||
exec_browser(*args.named.to_formulae_and_casks.map { |f| github_info(f) })
|
||||
exec_browser(*args.named.to_formulae_and_casks(only: only).map { |f| github_info(f) })
|
||||
elsif args.no_named?
|
||||
print_statistics
|
||||
else
|
||||
print_info(args: args)
|
||||
print_info(args: args, only: only)
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def print_statistics
|
||||
return unless HOMEBREW_CELLAR.exist?
|
||||
|
||||
@ -104,13 +115,14 @@ module Homebrew
|
||||
puts "#{count} #{"keg".pluralize(count)}, #{HOMEBREW_CELLAR.dup.abv}"
|
||||
end
|
||||
|
||||
def print_analytics(args:)
|
||||
sig { params(args: CLI::Args, only: T.nilable(Symbol)).void }
|
||||
def print_analytics(args:, only: nil)
|
||||
if args.no_named?
|
||||
Utils::Analytics.output(args: args)
|
||||
return
|
||||
end
|
||||
|
||||
args.named.to_formulae_and_casks_and_unavailable.each_with_index do |obj, i|
|
||||
args.named.to_formulae_and_casks_and_unavailable(only: only).each_with_index do |obj, i|
|
||||
puts unless i.zero?
|
||||
|
||||
case obj
|
||||
@ -126,8 +138,9 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
def print_info(args:)
|
||||
args.named.to_formulae_and_casks_and_unavailable.each_with_index do |obj, i|
|
||||
sig { params(args: CLI::Args, only: T.nilable(Symbol)).void }
|
||||
def print_info(args:, only: nil)
|
||||
args.named.to_formulae_and_casks_and_unavailable(only: only).each_with_index do |obj, i|
|
||||
puts unless i.zero?
|
||||
|
||||
case obj
|
||||
@ -159,7 +172,8 @@ module Homebrew
|
||||
version_hash[version]
|
||||
end
|
||||
|
||||
def print_json(args:)
|
||||
sig { params(args: CLI::Args, only: T.nilable(Symbol)).void }
|
||||
def print_json(args:, only: nil)
|
||||
raise FormulaOrCaskUnspecifiedError if !(args.all? || args.installed?) && args.no_named?
|
||||
|
||||
json = case json_version(args.json)
|
||||
@ -179,7 +193,7 @@ module Homebrew
|
||||
elsif args.installed?
|
||||
[Formula.installed.sort, Cask::Caskroom.casks.sort_by(&:full_name)]
|
||||
else
|
||||
args.named.to_formulae_to_casks
|
||||
args.named.to_formulae_to_casks(only: only)
|
||||
end
|
||||
|
||||
{
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "keg"
|
||||
@ -19,12 +19,17 @@ module Homebrew
|
||||
def uninstall_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
usage_banner <<~EOS
|
||||
`uninstall`, `rm`, `remove` [<options>] <formula>
|
||||
`uninstall`, `rm`, `remove` [<options>] <formula>|<cask>
|
||||
|
||||
Uninstall <formula>.
|
||||
Uninstall a <formula> or <cask>.
|
||||
EOS
|
||||
switch "-f", "--force",
|
||||
description: "Delete all installed versions of <formula>."
|
||||
description: "Delete all installed versions of <formula>. Uninstall even if <cask> is not " \
|
||||
"installed, overwrite existing files and ignore errors when removing files."
|
||||
switch "--zap",
|
||||
description: "Remove all files associated with a <cask>. " \
|
||||
"*May remove files which are shared between applications.*"
|
||||
conflicts "--formula", "--zap"
|
||||
switch "--ignore-dependencies",
|
||||
description: "Don't fail uninstall, even if <formula> is a dependency of any installed "\
|
||||
"formulae."
|
||||
@ -35,7 +40,7 @@ module Homebrew
|
||||
description: "Treat all named arguments as casks."
|
||||
conflicts "--formula", "--cask"
|
||||
|
||||
min_named :formula
|
||||
min_named :formula_or_cask
|
||||
end
|
||||
end
|
||||
|
||||
@ -45,51 +50,29 @@ module Homebrew
|
||||
only = :formula if args.formula? && !args.cask?
|
||||
only = :cask if args.cask? && !args.formula?
|
||||
|
||||
if args.force?
|
||||
casks = []
|
||||
kegs_by_rack = {}
|
||||
all_kegs, casks = args.named.to_kegs_to_casks(only: only, ignore_unavailable: args.force?, all_kegs: args.force?)
|
||||
kegs_by_rack = all_kegs.group_by(&:rack)
|
||||
|
||||
args.named.each do |name|
|
||||
if only != :cask
|
||||
rack = Formulary.to_rack(name)
|
||||
kegs_by_rack[rack] = rack.subdirs.map { |d| Keg.new(d) } if rack.directory?
|
||||
end
|
||||
|
||||
next if only == :formula
|
||||
|
||||
begin
|
||||
casks << Cask::CaskLoader.load(name)
|
||||
rescue Cask::CaskUnavailableError
|
||||
# Since the uninstall was forced, ignore any unavailable casks.
|
||||
end
|
||||
end
|
||||
else
|
||||
all_kegs, casks = args.named.to_kegs_to_casks(only: only)
|
||||
kegs_by_rack = all_kegs.group_by(&:rack)
|
||||
end
|
||||
|
||||
Uninstall.uninstall_kegs(kegs_by_rack,
|
||||
force: args.force?,
|
||||
ignore_dependencies: args.ignore_dependencies?,
|
||||
named_args: args.named)
|
||||
|
||||
return if casks.blank?
|
||||
|
||||
Cask::Cmd::Uninstall.uninstall_casks(
|
||||
*casks,
|
||||
binaries: EnvConfig.cask_opts_binaries?,
|
||||
verbose: args.verbose?,
|
||||
force: args.force?,
|
||||
Uninstall.uninstall_kegs(
|
||||
kegs_by_rack,
|
||||
force: args.force?,
|
||||
ignore_dependencies: args.ignore_dependencies?,
|
||||
named_args: args.named,
|
||||
)
|
||||
rescue MultipleVersionsInstalledError => e
|
||||
ofail e
|
||||
ensure
|
||||
# If we delete Cellar/newname, then Cellar/oldname symlink
|
||||
# can become broken and we have to remove it.
|
||||
if HOMEBREW_CELLAR.directory?
|
||||
HOMEBREW_CELLAR.children.each do |rack|
|
||||
rack.unlink if rack.symlink? && !rack.resolved_path_exists?
|
||||
end
|
||||
|
||||
if args.zap?
|
||||
Cask::Cmd::Zap.zap_casks(
|
||||
*casks,
|
||||
verbose: args.verbose?,
|
||||
force: args.force?,
|
||||
)
|
||||
else
|
||||
Cask::Cmd::Uninstall.uninstall_casks(
|
||||
*casks,
|
||||
binaries: EnvConfig.cask_opts_binaries?,
|
||||
verbose: args.verbose?,
|
||||
force: args.force?,
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "formula"
|
||||
@ -13,17 +13,27 @@ module Homebrew
|
||||
def edit_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
usage_banner <<~EOS
|
||||
`edit` [<formula>]
|
||||
`edit` [<formula>|<cask>]
|
||||
|
||||
Open <formula> in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, or open the
|
||||
Homebrew repository for editing if no formula is provided.
|
||||
Open a <formula> or <cask> in the editor set by `EDITOR` or `HOMEBREW_EDITOR`,
|
||||
or open the Homebrew repository for editing if no formula is provided.
|
||||
EOS
|
||||
|
||||
switch "--formula", "--formulae",
|
||||
description: "Treat all named arguments as formulae."
|
||||
switch "--cask", "--casks",
|
||||
description: "Treat all named arguments as casks."
|
||||
conflicts "--formula", "--cask"
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def edit
|
||||
args = edit_args.parse
|
||||
|
||||
only = :formula if args.formula? && !args.cask?
|
||||
only = :cask if args.cask? && !args.formula?
|
||||
|
||||
unless (HOMEBREW_REPOSITORY/".git").directory?
|
||||
raise <<~EOS
|
||||
Changes will be lost!
|
||||
@ -32,7 +42,7 @@ module Homebrew
|
||||
EOS
|
||||
end
|
||||
|
||||
paths = args.named.to_formulae_paths.select do |path|
|
||||
paths = args.named.to_paths(only: only).select do |path|
|
||||
next path if path.exist?
|
||||
|
||||
raise UsageError, "#{path} doesn't exist on disk. " \
|
||||
|
||||
@ -617,15 +617,15 @@ class ChecksumMissingError < ArgumentError; end
|
||||
class ChecksumMismatchError < RuntimeError
|
||||
attr_reader :expected, :hash_type
|
||||
|
||||
def initialize(fn, expected, actual)
|
||||
def initialize(path, expected, actual)
|
||||
@expected = expected
|
||||
@hash_type = expected.hash_type.to_s.upcase
|
||||
|
||||
super <<~EOS
|
||||
#{@hash_type} mismatch
|
||||
Expected: #{expected}
|
||||
Actual: #{actual}
|
||||
Archive: #{fn}
|
||||
Expected: #{Formatter.success(expected.to_s)}
|
||||
Actual: #{Formatter.error(actual.to_s)}
|
||||
File: #{path}
|
||||
To retry an incomplete download, remove the file above.
|
||||
EOS
|
||||
end
|
||||
|
||||
@ -27,11 +27,13 @@ class JavaRequirement < Requirement
|
||||
|
||||
def java_home_cmd
|
||||
# TODO: enable for all macOS versions and Linux on next minor release
|
||||
# but --version is broken on Big Sur today.
|
||||
if @version && MacOS.version >= :big_sur
|
||||
odisabled "depends_on :java",
|
||||
'"depends_on "openjdk@11", "depends_on "openjdk@8" or "depends_on "openjdk"'
|
||||
# but --version with ranges is broken on Big Sur today.
|
||||
if MacOS.version >= :big_sur && @version&.end_with?("+")
|
||||
odisabled %Q(depends_on java: "#{@version}"),
|
||||
'depends_on "openjdk@11", depends_on "openjdk@8" or depends_on "openjdk"'
|
||||
end
|
||||
# odeprecated "depends_on :java",
|
||||
# 'depends_on "openjdk@11", depends_on "openjdk@8" or depends_on "openjdk"'
|
||||
|
||||
return unless File.executable?("/usr/libexec/java_home")
|
||||
|
||||
|
||||
@ -654,7 +654,7 @@ class FormulaInstaller
|
||||
@show_header = true unless deps.empty?
|
||||
end
|
||||
|
||||
sig { params(dep: Formula).void }
|
||||
sig { params(dep: Dependency).void }
|
||||
def fetch_dependency(dep)
|
||||
df = dep.to_formula
|
||||
fi = FormulaInstaller.new(
|
||||
@ -675,7 +675,7 @@ class FormulaInstaller
|
||||
fi.fetch
|
||||
end
|
||||
|
||||
sig { params(dep: Formula, inherited_options: Options).void }
|
||||
sig { params(dep: Dependency, inherited_options: Options).void }
|
||||
def install_dependency(dep, inherited_options)
|
||||
df = dep.to_formula
|
||||
tab = Tab.for_formula(df)
|
||||
|
||||
@ -146,13 +146,16 @@ class Resource
|
||||
|
||||
def verify_download_integrity(fn)
|
||||
if fn.file?
|
||||
ohai "Verifying #{fn.basename} checksum" if verbose?
|
||||
ohai "Verifying checksum for '#{fn.basename}'." if verbose?
|
||||
fn.verify_checksum(checksum)
|
||||
end
|
||||
rescue ChecksumMissingError
|
||||
opoo "Cannot verify integrity of #{fn.basename}"
|
||||
puts "A checksum was not provided for this resource."
|
||||
puts "For your reference the SHA-256 is: #{fn.sha256}"
|
||||
opoo <<~EOS
|
||||
Cannot verify integrity of '#{fn.basename}'.
|
||||
No checksum was provided for this resource.
|
||||
For your reference, the checksum is:
|
||||
sha256 "#{fn.sha256}"
|
||||
EOS
|
||||
end
|
||||
|
||||
Checksum::TYPES.each do |type|
|
||||
|
||||
@ -10,7 +10,7 @@ module Homebrew
|
||||
|
||||
attr_reader :name, :path, :tap_audit_exceptions, :problems
|
||||
|
||||
sig { params(tap: Tap, strict: T::Boolean).void }
|
||||
sig { params(tap: Tap, strict: T.nilable(T::Boolean)).void }
|
||||
def initialize(tap, strict:)
|
||||
@name = tap.name
|
||||
@path = tap.path
|
||||
|
||||
@ -808,7 +808,6 @@ describe Cask::Audit, :cask do
|
||||
let(:cask_token) { "with-binary" }
|
||||
let(:cask) { Cask::CaskLoader.load(cask_token) }
|
||||
let(:download_double) { instance_double(Cask::Download) }
|
||||
let(:verify) { class_double(Cask::Verify).as_stubbed_const }
|
||||
let(:message) { "Download Failed" }
|
||||
|
||||
before do
|
||||
@ -817,19 +816,12 @@ describe Cask::Audit, :cask do
|
||||
end
|
||||
|
||||
it "when download and verification succeed it does not fail" do
|
||||
expect(download_double).to receive(:perform)
|
||||
expect(verify).to receive(:all)
|
||||
expect(download_double).to receive(:fetch)
|
||||
expect(subject).to pass
|
||||
end
|
||||
|
||||
it "when download fails it fails" do
|
||||
expect(download_double).to receive(:perform).and_raise(StandardError.new(message))
|
||||
expect(subject).to fail_with(/#{message}/)
|
||||
end
|
||||
|
||||
it "when verification fails it fails" do
|
||||
expect(download_double).to receive(:perform)
|
||||
expect(verify).to receive(:all).and_raise(StandardError.new(message))
|
||||
expect(download_double).to receive(:fetch).and_raise(StandardError.new(message))
|
||||
expect(subject).to fail_with(/#{message}/)
|
||||
end
|
||||
end
|
||||
|
||||
@ -36,7 +36,7 @@ describe Cask::Cmd::Fetch, :cask do
|
||||
end
|
||||
|
||||
it "prevents double fetch (without nuking existing installation)" do
|
||||
cached_location = Cask::Download.new(local_transmission).perform
|
||||
cached_location = Cask::Download.new(local_transmission).fetch
|
||||
|
||||
old_ctime = File.stat(cached_location).ctime
|
||||
|
||||
@ -47,7 +47,7 @@ describe Cask::Cmd::Fetch, :cask do
|
||||
end
|
||||
|
||||
it "allows double fetch with --force" do
|
||||
cached_location = Cask::Download.new(local_transmission).perform
|
||||
cached_location = Cask::Download.new(local_transmission).fetch
|
||||
|
||||
old_ctime = File.stat(cached_location).ctime
|
||||
sleep(1)
|
||||
|
||||
@ -11,7 +11,6 @@ describe Cask::Cmd::Install, :cask do
|
||||
it "displays the installation progress" do
|
||||
output = Regexp.new <<~EOS
|
||||
==> Downloading file:.*caffeine.zip
|
||||
==> Verifying SHA-256 checksum for Cask 'local-caffeine'.
|
||||
==> Installing Cask local-caffeine
|
||||
==> Moving App 'Caffeine.app' to '.*Caffeine.app'.
|
||||
.*local-caffeine was successfully installed!
|
||||
|
||||
@ -14,7 +14,6 @@ describe Cask::Cmd::Reinstall, :cask do
|
||||
output = Regexp.new <<~EOS
|
||||
==> Downloading file:.*caffeine.zip
|
||||
Already downloaded: .*--caffeine.zip
|
||||
==> Verifying SHA-256 checksum for Cask 'local-caffeine'.
|
||||
==> Uninstalling Cask local-caffeine
|
||||
==> Backing App 'Caffeine.app' up to '.*Caffeine.app'.
|
||||
==> Removing App '.*Caffeine.app'.
|
||||
|
||||
@ -75,7 +75,7 @@ describe Cask::Cmd::Style, :cask do
|
||||
end
|
||||
|
||||
it "tries to find paths for all tokens" do
|
||||
expect(Cask::CaskLoader).to receive(:load).twice.and_return(double("cask", sourcefile_path: nil))
|
||||
expect(Cask::CaskLoader).to receive(:load).twice.and_return(instance_double(Cask::Cask, sourcefile_path: nil))
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
@ -344,7 +344,7 @@ describe Cask::Cmd::Upgrade, :cask do
|
||||
|
||||
expect {
|
||||
described_class.run("bad-checksum")
|
||||
}.to raise_error(Cask::CaskSha256MismatchError).and(not_to_output(output_reverted).to_stderr)
|
||||
}.to raise_error(ChecksumMismatchError).and(not_to_output(output_reverted).to_stderr)
|
||||
|
||||
expect(bad_checksum).to be_installed
|
||||
expect(bad_checksum_path).to be_a_directory
|
||||
|
||||
@ -2,26 +2,30 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Cask
|
||||
describe Verify, :cask do
|
||||
describe "::all" do
|
||||
subject(:verification) { described_class.all(cask, downloaded_path) }
|
||||
describe Download, :cask do
|
||||
describe "#verify_download_integrity" do
|
||||
subject(:verification) { described_class.new(cask).verify_download_integrity(downloaded_path) }
|
||||
|
||||
let(:cask) { instance_double(Cask, token: "cask", sha256: expected_sha256) }
|
||||
let(:cafebabe) { "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" }
|
||||
let(:deadbeef) { "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" }
|
||||
let(:computed_sha256) { cafebabe }
|
||||
let(:downloaded_path) { instance_double(Pathname, sha256: computed_sha256) }
|
||||
let(:downloaded_path) { Pathname.new("cask.zip") }
|
||||
|
||||
before do
|
||||
allow(downloaded_path).to receive(:sha256).and_return(computed_sha256)
|
||||
end
|
||||
|
||||
context "when the expected checksum is :no_check" do
|
||||
let(:expected_sha256) { :no_check }
|
||||
|
||||
it "skips the check" do
|
||||
expect { verification }.to output(/skipping verification/).to_stdout
|
||||
expect { verification }.to output(/skipping verification/).to_stderr
|
||||
end
|
||||
end
|
||||
|
||||
context "when expected and computed checksums match" do
|
||||
let(:expected_sha256) { cafebabe }
|
||||
let(:expected_sha256) { Checksum.new(:sha256, cafebabe) }
|
||||
|
||||
it "does not raise an error" do
|
||||
expect { verification }.not_to raise_error
|
||||
@ -31,24 +35,24 @@ module Cask
|
||||
context "when the expected checksum is nil" do
|
||||
let(:expected_sha256) { nil }
|
||||
|
||||
it "raises an error" do
|
||||
expect { verification }.to raise_error(CaskSha256MissingError, /sha256 "#{computed_sha256}"/)
|
||||
it "outputs an error" do
|
||||
expect { verification }.to output(/sha256 "#{computed_sha256}"/).to_stderr
|
||||
end
|
||||
end
|
||||
|
||||
context "when the expected checksum is empty" do
|
||||
let(:expected_sha256) { "" }
|
||||
let(:expected_sha256) { Checksum.new(:sha256, "") }
|
||||
|
||||
it "raises an error" do
|
||||
expect { verification }.to raise_error(CaskSha256MissingError, /sha256 "#{computed_sha256}"/)
|
||||
it "outputs an error" do
|
||||
expect { verification }.to output(/sha256 "#{computed_sha256}"/).to_stderr
|
||||
end
|
||||
end
|
||||
|
||||
context "when expected and computed checksums do not match" do
|
||||
let(:expected_sha256) { deadbeef }
|
||||
let(:expected_sha256) { Checksum.new(:sha256, deadbeef) }
|
||||
|
||||
it "raises an error" do
|
||||
expect { verification }.to raise_error CaskSha256MismatchError
|
||||
expect { verification }.to raise_error ChecksumMismatchError
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -65,14 +65,14 @@ describe Cask::Installer, :cask do
|
||||
bad_checksum = Cask::CaskLoader.load(cask_path("bad-checksum"))
|
||||
expect {
|
||||
described_class.new(bad_checksum).install
|
||||
}.to raise_error(Cask::CaskSha256MismatchError)
|
||||
}.to raise_error(ChecksumMismatchError)
|
||||
end
|
||||
|
||||
it "blows up on a missing checksum" do
|
||||
missing_checksum = Cask::CaskLoader.load(cask_path("missing-checksum"))
|
||||
expect {
|
||||
described_class.new(missing_checksum).install
|
||||
}.to raise_error(Cask::CaskSha256MissingError)
|
||||
}.to output(/Cannot verify integrity/).to_stderr
|
||||
end
|
||||
|
||||
it "installs fine if sha256 :no_check is used" do
|
||||
@ -87,7 +87,7 @@ describe Cask::Installer, :cask do
|
||||
no_checksum = Cask::CaskLoader.load(cask_path("no-checksum"))
|
||||
expect {
|
||||
described_class.new(no_checksum, require_sha: true).install
|
||||
}.to raise_error(Cask::CaskNoShasumError)
|
||||
}.to raise_error(/--require-sha/)
|
||||
end
|
||||
|
||||
it "installs fine if sha256 :no_check is used with --require-sha and --force" do
|
||||
@ -116,7 +116,6 @@ describe Cask::Installer, :cask do
|
||||
}.to output(
|
||||
<<~EOS,
|
||||
==> Downloading file://#{HOMEBREW_LIBRARY_PATH}/test/support/fixtures/cask/caffeine.zip
|
||||
==> Verifying SHA-256 checksum for Cask 'with-installer-manual'.
|
||||
==> Installing Cask with-installer-manual
|
||||
To complete the installation of Cask with-installer-manual, you must also
|
||||
run the installer at:
|
||||
|
||||
@ -31,7 +31,7 @@ describe Cask::Quarantine, :cask do
|
||||
it "quarantines Cask fetches" do
|
||||
Cask::Cmd::Fetch.run("local-transmission")
|
||||
local_transmission = Cask::CaskLoader.load(cask_path("local-transmission"))
|
||||
cached_location = Cask::Download.new(local_transmission).perform
|
||||
cached_location = Cask::Download.new(local_transmission).fetch
|
||||
|
||||
expect(cached_location).to be_quarantined
|
||||
end
|
||||
@ -40,7 +40,7 @@ describe Cask::Quarantine, :cask do
|
||||
Cask::Cmd::Audit.run("local-transmission", "--download")
|
||||
|
||||
local_transmission = Cask::CaskLoader.load(cask_path("local-transmission"))
|
||||
cached_location = Cask::Download.new(local_transmission).perform
|
||||
cached_location = Cask::Download.new(local_transmission).fetch
|
||||
|
||||
expect(cached_location).to be_quarantined
|
||||
end
|
||||
@ -142,7 +142,7 @@ describe Cask::Quarantine, :cask do
|
||||
it "does not quarantine Cask fetches" do
|
||||
Cask::Cmd::Fetch.run("local-transmission", "--no-quarantine")
|
||||
local_transmission = Cask::CaskLoader.load(cask_path("local-transmission"))
|
||||
cached_location = Cask::Download.new(local_transmission).perform
|
||||
cached_location = Cask::Download.new(local_transmission).fetch
|
||||
|
||||
expect(cached_location).not_to be_quarantined
|
||||
end
|
||||
@ -151,7 +151,7 @@ describe Cask::Quarantine, :cask do
|
||||
Cask::Cmd::Audit.run("local-transmission", "--download", "--no-quarantine")
|
||||
|
||||
local_transmission = Cask::CaskLoader.load(cask_path("local-transmission"))
|
||||
cached_location = Cask::Download.new(local_transmission).perform
|
||||
cached_location = Cask::Download.new(local_transmission).fetch
|
||||
|
||||
expect(cached_location).not_to be_quarantined
|
||||
end
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
cask "invalid-manpage-no-section" do
|
||||
version "1.2.3"
|
||||
sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"
|
||||
sha256 "68b7e71a2ca7585b004f52652749589941e3029ff0884e8aa3b099594e0282c0"
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/AppWithManpage.zip"
|
||||
homepage "https://brew.sh/with-generic-artifact"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
cask "with-autodetected-manpage-section" do
|
||||
version "1.2.3"
|
||||
sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"
|
||||
sha256 "68b7e71a2ca7585b004f52652749589941e3029ff0884e8aa3b099594e0282c0"
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/AppWithManpage.zip"
|
||||
homepage "https://brew.sh/with-autodetected-manpage-section"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
cask "with-non-executable-binary" do
|
||||
version "1.2.3"
|
||||
sha256 "d5b2dfbef7ea28c25f7a77cd7fa14d013d82b626db1d82e00e25822464ba19e2"
|
||||
sha256 "306c6ca7407560340797866e077e053627ad409277d1b9da58106fce4cf717cb"
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/naked_non_executable"
|
||||
homepage "https://brew.sh/with-binary"
|
||||
|
||||
@ -82,6 +82,16 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue MultipleVersionsInstalledError => e
|
||||
ofail e
|
||||
ensure
|
||||
# If we delete Cellar/newname, then Cellar/oldname symlink
|
||||
# can become broken and we have to remove it.
|
||||
if HOMEBREW_CELLAR.directory?
|
||||
HOMEBREW_CELLAR.children.each do |rack|
|
||||
rack.unlink if rack.symlink? && !rack.resolved_path_exists?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def handle_unsatisfied_dependents(kegs_by_rack, ignore_dependencies: false, named_args: [])
|
||||
|
||||
@ -199,8 +199,8 @@ an issue; just ignore this.
|
||||
|
||||
### `fetch` [*`options`*] *`formula`*
|
||||
|
||||
Download a bottle (if available) or source packages for *`formula`*.
|
||||
For tarballs, also print SHA-256 checksums.
|
||||
Download a bottle (if available) or source packages for *`formula`*e
|
||||
and binaries for *`cask`*s. For files, also print SHA-256 checksums.
|
||||
|
||||
* `--HEAD`:
|
||||
Fetch HEAD version instead of stable version.
|
||||
@ -220,6 +220,12 @@ For tarballs, also print SHA-256 checksums.
|
||||
Download source packages (for eventual bottling) rather than a bottle.
|
||||
* `--force-bottle`:
|
||||
Download a bottle if it exists for the current or newest version of macOS, even if it would not be used during installation.
|
||||
* `--[no-]quarantine`:
|
||||
Disable/enable quarantining of downloads (default: enabled).
|
||||
* `--formula`:
|
||||
Treat all named arguments as formulae.
|
||||
* `--cask`:
|
||||
Treat all named arguments as casks.
|
||||
|
||||
### `formulae`
|
||||
|
||||
@ -242,11 +248,11 @@ error message if no logs are found.
|
||||
Open *`formula`*'s homepage in a browser, or open Homebrew's own homepage
|
||||
if no formula is provided.
|
||||
|
||||
### `info` [*`options`*] [*`formula`*]
|
||||
### `info` [*`options`*] [*`formula`*|*`cask`*]
|
||||
|
||||
Display brief statistics for your Homebrew installation.
|
||||
|
||||
If *`formula`* is provided, show summary of information about *`formula`*.
|
||||
If a *`formula`* or *`cask`* is provided, show summary of information about it.
|
||||
|
||||
* `--analytics`:
|
||||
List global Homebrew analytics data or, if specified, installation and build error data for *`formula`* (provided neither `HOMEBREW_NO_ANALYTICS` nor `HOMEBREW_NO_GITHUB_API` are set).
|
||||
@ -264,6 +270,10 @@ If *`formula`* is provided, show summary of information about *`formula`*.
|
||||
Print JSON of all available formulae.
|
||||
* `-v`, `--verbose`:
|
||||
Show more verbose analytics data for *`formula`*.
|
||||
* `--formula`:
|
||||
Treat all named arguments as formulae.
|
||||
* `--cask`:
|
||||
Treat all named arguments as casks.
|
||||
|
||||
### `install` [*`options`*] *`formula`*|*`cask`*
|
||||
|
||||
@ -567,12 +577,14 @@ If no *`tap`* names are provided, display brief statistics for all installed tap
|
||||
* `--json`:
|
||||
Print a JSON representation of *`tap`*. Currently the default and only accepted value for *`version`* is `v1`. See the docs for examples of using the JSON output: <https://docs.brew.sh/Querying-Brew>
|
||||
|
||||
### `uninstall`, `rm`, `remove` [*`options`*] *`formula`*
|
||||
### `uninstall`, `rm`, `remove` [*`options`*] *`formula`*|*`cask`*
|
||||
|
||||
Uninstall *`formula`*.
|
||||
Uninstall a *`formula`* or *`cask`*.
|
||||
|
||||
* `-f`, `--force`:
|
||||
Delete all installed versions of *`formula`*.
|
||||
Delete all installed versions of *`formula`*. Uninstall even if *`cask`* is not installed, overwrite existing files and ignore errors when removing files.
|
||||
* `--zap`:
|
||||
Remove all files associated with a *`cask`*. *May remove files which are shared between applications.*
|
||||
* `--ignore-dependencies`:
|
||||
Don't fail uninstall, even if *`formula`* is a dependency of any installed formulae.
|
||||
* `--formula`:
|
||||
@ -1001,10 +1013,15 @@ the Cellar and then link it into Homebrew's prefix with `brew link`.
|
||||
* `--version`:
|
||||
Explicitly set the *`version`* of the package being installed.
|
||||
|
||||
### `edit` [*`formula`*]
|
||||
### `edit` [*`formula`*|*`cask`*]
|
||||
|
||||
Open *`formula`* in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, or open the
|
||||
Homebrew repository for editing if no formula is provided.
|
||||
Open a *`formula`* or *`cask`* in the editor set by `EDITOR` or `HOMEBREW_EDITOR`,
|
||||
or open the Homebrew repository for editing if no formula is provided.
|
||||
|
||||
* `--formula`:
|
||||
Treat all named arguments as formulae.
|
||||
* `--cask`:
|
||||
Treat all named arguments as casks.
|
||||
|
||||
### `extract` [*`options`*] *`formula`* *`tap`*
|
||||
|
||||
|
||||
@ -254,7 +254,7 @@ List all audit methods, which can be run individually if provided as arguments\.
|
||||
Enable debugging and profiling of audit methods\.
|
||||
.
|
||||
.SS "\fBfetch\fR [\fIoptions\fR] \fIformula\fR"
|
||||
Download a bottle (if available) or source packages for \fIformula\fR\. For tarballs, also print SHA\-256 checksums\.
|
||||
Download a bottle (if available) or source packages for \fIformula\fRe and binaries for \fIcask\fRs\. For files, also print SHA\-256 checksums\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-HEAD\fR
|
||||
@ -292,6 +292,18 @@ Download source packages (for eventual bottling) rather than a bottle\.
|
||||
\fB\-\-force\-bottle\fR
|
||||
Download a bottle if it exists for the current or newest version of macOS, even if it would not be used during installation\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-[no\-]quarantine\fR
|
||||
Disable/enable quarantining of downloads (default: enabled)\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-formula\fR
|
||||
Treat all named arguments as formulae\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-cask\fR
|
||||
Treat all named arguments as casks\.
|
||||
.
|
||||
.SS "\fBformulae\fR"
|
||||
List all locally installable formulae including short names\.
|
||||
.
|
||||
@ -313,11 +325,11 @@ The Gist will be marked private and will not appear in listings but will be acce
|
||||
.SS "\fBhome\fR [\fIformula\fR]"
|
||||
Open \fIformula\fR\'s homepage in a browser, or open Homebrew\'s own homepage if no formula is provided\.
|
||||
.
|
||||
.SS "\fBinfo\fR [\fIoptions\fR] [\fIformula\fR]"
|
||||
.SS "\fBinfo\fR [\fIoptions\fR] [\fIformula\fR|\fIcask\fR]"
|
||||
Display brief statistics for your Homebrew installation\.
|
||||
.
|
||||
.P
|
||||
If \fIformula\fR is provided, show summary of information about \fIformula\fR\.
|
||||
If a \fIformula\fR or \fIcask\fR is provided, show summary of information about it\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-analytics\fR
|
||||
@ -351,6 +363,14 @@ Print JSON of all available formulae\.
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Show more verbose analytics data for \fIformula\fR\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-formula\fR
|
||||
Treat all named arguments as formulae\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-cask\fR
|
||||
Treat all named arguments as casks\.
|
||||
.
|
||||
.SS "\fBinstall\fR [\fIoptions\fR] \fIformula\fR|\fIcask\fR"
|
||||
Install a \fIformula\fR or \fIcask\fR\. Additional options specific to a \fIformula\fR may be appended to the command\.
|
||||
.
|
||||
@ -785,12 +805,16 @@ Show information on each installed tap\.
|
||||
\fB\-\-json\fR
|
||||
Print a JSON representation of \fItap\fR\. Currently the default and only accepted value for \fIversion\fR is \fBv1\fR\. See the docs for examples of using the JSON output: \fIhttps://docs\.brew\.sh/Querying\-Brew\fR
|
||||
.
|
||||
.SS "\fBuninstall\fR, \fBrm\fR, \fBremove\fR [\fIoptions\fR] \fIformula\fR"
|
||||
Uninstall \fIformula\fR\.
|
||||
.SS "\fBuninstall\fR, \fBrm\fR, \fBremove\fR [\fIoptions\fR] \fIformula\fR|\fIcask\fR"
|
||||
Uninstall a \fIformula\fR or \fIcask\fR\.
|
||||
.
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-force\fR
|
||||
Delete all installed versions of \fIformula\fR\.
|
||||
Delete all installed versions of \fIformula\fR\. Uninstall even if \fIcask\fR is not installed, overwrite existing files and ignore errors when removing files\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-zap\fR
|
||||
Remove all files associated with a \fIcask\fR\. \fIMay remove files which are shared between applications\.\fR
|
||||
.
|
||||
.TP
|
||||
\fB\-\-ignore\-dependencies\fR
|
||||
@ -1396,8 +1420,16 @@ Explicitly set the \fIname\fR of the package being installed\.
|
||||
\fB\-\-version\fR
|
||||
Explicitly set the \fIversion\fR of the package being installed\.
|
||||
.
|
||||
.SS "\fBedit\fR [\fIformula\fR]"
|
||||
Open \fIformula\fR in the editor set by \fBEDITOR\fR or \fBHOMEBREW_EDITOR\fR, or open the Homebrew repository for editing if no formula is provided\.
|
||||
.SS "\fBedit\fR [\fIformula\fR|\fIcask\fR]"
|
||||
Open a \fIformula\fR or \fIcask\fR in the editor set by \fBEDITOR\fR or \fBHOMEBREW_EDITOR\fR, or open the Homebrew repository for editing if no formula is provided\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-formula\fR
|
||||
Treat all named arguments as formulae\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-cask\fR
|
||||
Treat all named arguments as casks\.
|
||||
.
|
||||
.SS "\fBextract\fR [\fIoptions\fR] \fIformula\fR \fItap\fR"
|
||||
Look through repository history to find the most recent version of \fIformula\fR and create a copy in \fItap\fR\fB/Formula/\fR\fIformula\fR\fB@\fR\fIversion\fR\fB\.rb\fR\. If the tap is not installed yet, attempt to install/clone the tap before continuing\. To extract a formula from a tap that is not \fBhomebrew/core\fR use its fully\-qualified form of \fIuser\fR\fB/\fR\fIrepo\fR\fB/\fR\fIformula\fR\.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user