mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Support casks in brew fetch
.
This commit is contained in:
parent
12495bc804
commit
7a83f34dd1
@ -23,4 +23,3 @@ require "cask/staged"
|
|||||||
require "cask/topological_hash"
|
require "cask/topological_hash"
|
||||||
require "cask/url"
|
require "cask/url"
|
||||||
require "cask/utils"
|
require "cask/utils"
|
||||||
require "cask/verify"
|
|
||||||
|
@ -255,20 +255,20 @@ module Cask
|
|||||||
add_error "you should use sha256 :no_check when version is :latest"
|
add_error "you should use sha256 :no_check when version is :latest"
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_sha256_actually_256(sha256: cask.sha256, stanza: "sha256")
|
def check_sha256_actually_256
|
||||||
odebug "Verifying #{stanza} string is a legal SHA-256 digest"
|
odebug "Verifying sha256 string is a legal SHA-256 digest"
|
||||||
return unless sha256.is_a?(String)
|
return unless cask.sha256.is_a?(Checksum)
|
||||||
return if sha256.length == 64 && sha256[/^[0-9a-f]+$/i]
|
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
|
end
|
||||||
|
|
||||||
def check_sha256_invalid(sha256: cask.sha256, stanza: "sha256")
|
def check_sha256_invalid
|
||||||
odebug "Verifying #{stanza} is not a known invalid value"
|
odebug "Verifying sha256 is not a known invalid value"
|
||||||
empty_sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
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
|
end
|
||||||
|
|
||||||
def check_latest_with_appcast
|
def check_latest_with_appcast
|
||||||
@ -428,8 +428,7 @@ module Cask
|
|||||||
return unless download && cask.url
|
return unless download && cask.url
|
||||||
|
|
||||||
odebug "Auditing download"
|
odebug "Auditing download"
|
||||||
downloaded_path = download.perform
|
download.fetch
|
||||||
Verify.all(cask, downloaded_path)
|
|
||||||
rescue => e
|
rescue => e
|
||||||
add_error "download not possible: #{e}"
|
add_error "download not possible: #{e}"
|
||||||
end
|
end
|
||||||
|
@ -32,7 +32,6 @@ module Cask
|
|||||||
require "cask/installer"
|
require "cask/installer"
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
force: args.force?,
|
|
||||||
quarantine: args.quarantine?,
|
quarantine: args.quarantine?,
|
||||||
}.compact
|
}.compact
|
||||||
|
|
||||||
@ -41,8 +40,9 @@ module Cask
|
|||||||
casks.each do |cask|
|
casks.each do |cask|
|
||||||
puts Installer.caveats(cask)
|
puts Installer.caveats(cask)
|
||||||
ohai "Downloading external files for Cask #{cask}"
|
ohai "Downloading external files for Cask #{cask}"
|
||||||
downloaded_path = Download.new(cask, **options).perform
|
download = Download.new(cask, **options)
|
||||||
Verify.all(cask, downloaded_path)
|
download.clear_cache if args.force?
|
||||||
|
downloaded_path = download.fetch
|
||||||
ohai "Success! Downloaded to -> #{downloaded_path}"
|
ohai "Success! Downloaded to -> #{downloaded_path}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -4,25 +4,32 @@
|
|||||||
require "fileutils"
|
require "fileutils"
|
||||||
require "cask/cache"
|
require "cask/cache"
|
||||||
require "cask/quarantine"
|
require "cask/quarantine"
|
||||||
require "cask/verify"
|
|
||||||
|
|
||||||
module Cask
|
module Cask
|
||||||
# A download corresponding to a {Cask}.
|
# A download corresponding to a {Cask}.
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
class Download
|
class Download
|
||||||
|
include Context
|
||||||
|
|
||||||
attr_reader :cask
|
attr_reader :cask
|
||||||
|
|
||||||
def initialize(cask, force: false, quarantine: nil)
|
def initialize(cask, quarantine: nil)
|
||||||
@cask = cask
|
@cask = cask
|
||||||
@force = force
|
|
||||||
@quarantine = quarantine
|
@quarantine = quarantine
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform
|
def fetch(verify_download_integrity: true)
|
||||||
clear_cache
|
downloaded_path = begin
|
||||||
fetch
|
downloader.fetch
|
||||||
quarantine
|
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
|
downloaded_path
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -33,32 +40,44 @@ module Cask
|
|||||||
end
|
end
|
||||||
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
|
||||||
|
|
||||||
|
ohai "Verifying checksum for Cask '#{@cask}'." if verbose?
|
||||||
|
|
||||||
|
expected = @cask.sha256
|
||||||
|
actual = fn.sha256
|
||||||
|
|
||||||
|
begin
|
||||||
|
fn.verify_checksum(expected)
|
||||||
|
rescue ChecksumMissingError
|
||||||
|
raise CaskSha256MissingError.new(@cask.token, expected, actual)
|
||||||
|
rescue ChecksumMismatchError
|
||||||
|
raise CaskSha256MismatchError.new(@cask.token, expected, actual, fn)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :force
|
def quarantine(path)
|
||||||
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
|
|
||||||
return if @quarantine.nil?
|
return if @quarantine.nil?
|
||||||
return unless Quarantine.available?
|
return unless Quarantine.available?
|
||||||
|
|
||||||
if @quarantine
|
if @quarantine
|
||||||
Quarantine.cask!(cask: @cask, download_path: @downloaded_path)
|
Quarantine.cask!(cask: @cask, download_path: path)
|
||||||
else
|
else
|
||||||
Quarantine.release!(download_path: @downloaded_path)
|
Quarantine.release!(download_path: path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -205,11 +205,14 @@ module Cask
|
|||||||
|
|
||||||
def sha256(arg = nil)
|
def sha256(arg = nil)
|
||||||
set_unique_stanza(:sha256, arg.nil?) do
|
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}'")
|
raise CaskInvalidError.new(cask, "invalid 'sha256' value: '#{arg.inspect}'")
|
||||||
end
|
end
|
||||||
|
|
||||||
arg
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ require "cask/topological_hash"
|
|||||||
require "cask/config"
|
require "cask/config"
|
||||||
require "cask/download"
|
require "cask/download"
|
||||||
require "cask/staged"
|
require "cask/staged"
|
||||||
require "cask/verify"
|
|
||||||
require "cask/quarantine"
|
require "cask/quarantine"
|
||||||
|
|
||||||
require "cgi"
|
require "cgi"
|
||||||
@ -68,7 +67,6 @@ module Cask
|
|||||||
satisfy_dependencies
|
satisfy_dependencies
|
||||||
|
|
||||||
download
|
download
|
||||||
verify
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def stage
|
def stage
|
||||||
@ -156,7 +154,7 @@ module Cask
|
|||||||
return @downloaded_path if @downloaded_path
|
return @downloaded_path if @downloaded_path
|
||||||
|
|
||||||
odebug "Downloading"
|
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}"
|
odebug "Downloaded to -> #{@downloaded_path}"
|
||||||
@downloaded_path
|
@downloaded_path
|
||||||
end
|
end
|
||||||
@ -168,10 +166,6 @@ module Cask
|
|||||||
raise CaskNoShasumError, @cask.token
|
raise CaskNoShasumError, @cask.token
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify
|
|
||||||
Verify.all(@cask, @downloaded_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def primary_container
|
def primary_container
|
||||||
@primary_container ||= begin
|
@primary_container ||= begin
|
||||||
download
|
download
|
||||||
|
@ -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)
|
def initialize(hash_type, hexdigest)
|
||||||
@hash_type = hash_type
|
@hash_type = hash_type
|
||||||
@hexdigest = hexdigest
|
@hexdigest = hexdigest.downcase
|
||||||
end
|
end
|
||||||
|
|
||||||
delegate [:empty?, :to_s] => :@hexdigest
|
delegate [:empty?, :to_s, :length, :[]] => :@hexdigest
|
||||||
|
|
||||||
def ==(other)
|
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
|
||||||
end
|
end
|
||||||
|
@ -113,7 +113,7 @@ module Homebrew
|
|||||||
|
|
||||||
def build_from_source_formulae
|
def build_from_source_formulae
|
||||||
if build_from_source? || build_bottle?
|
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
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
require "formula"
|
require "formula"
|
||||||
require "fetch"
|
require "fetch"
|
||||||
require "cli/parser"
|
require "cli/parser"
|
||||||
|
require "cask/download"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
extend T::Sig
|
extend T::Sig
|
||||||
@ -18,8 +19,8 @@ module Homebrew
|
|||||||
usage_banner <<~EOS
|
usage_banner <<~EOS
|
||||||
`fetch` [<options>] <formula>
|
`fetch` [<options>] <formula>
|
||||||
|
|
||||||
Download a bottle (if available) or source packages for <formula>.
|
Download a bottle (if available) or source packages for <formula>e
|
||||||
For tarballs, also print SHA-256 checksums.
|
and binaries for <cask>s. For files, also print SHA-256 checksums.
|
||||||
EOS
|
EOS
|
||||||
switch "--HEAD",
|
switch "--HEAD",
|
||||||
description: "Fetch HEAD version instead of stable version."
|
description: "Fetch HEAD version instead of stable version."
|
||||||
@ -42,58 +43,98 @@ module Homebrew
|
|||||||
switch "--force-bottle",
|
switch "--force-bottle",
|
||||||
description: "Download a bottle if it exists for the current or newest version of macOS, "\
|
description: "Download a bottle if it exists for the current or newest version of macOS, "\
|
||||||
"even if it would not be used during installation."
|
"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 "--devel", "--HEAD"
|
||||||
conflicts "--build-from-source", "--build-bottle", "--force-bottle"
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch
|
def fetch
|
||||||
args = fetch_args.parse
|
args = fetch_args.parse
|
||||||
|
|
||||||
if args.deps?
|
only = :formula if args.formula? && !args.cask?
|
||||||
bucket = []
|
only = :cask if args.cask? && !args.formula?
|
||||||
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
|
|
||||||
|
|
||||||
puts "Fetching: #{bucket * ", "}" if bucket.size > 1
|
bucket = if args.deps?
|
||||||
bucket.each do |f|
|
args.named.to_formulae_and_casks.flat_map do |formula_or_cask|
|
||||||
f.print_tap_action verb: "Fetching"
|
case formula_or_cask
|
||||||
|
when Formula
|
||||||
|
f = formula_or_cask
|
||||||
|
|
||||||
fetched_bottle = false
|
[f, *f.recursive_dependencies.map(&:to_formula)]
|
||||||
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
|
else
|
||||||
fetched_bottle = true
|
formula_or_cask
|
||||||
end
|
end
|
||||||
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|
|
fetched_bottle = false
|
||||||
fetch_resource(r, args: args)
|
if fetch_bottle?(f, args: args)
|
||||||
r.patches.each { |p| fetch_patch(p, args: args) if p.external? }
|
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
|
end
|
||||||
|
|
||||||
f.patchlist.each { |p| fetch_patch(p, args: args) if p.external? }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -112,6 +153,13 @@ module Homebrew
|
|||||||
opoo "Formula reports different #{e.hash_type}: #{e.expected}"
|
opoo "Formula reports different #{e.hash_type}: #{e.expected}"
|
||||||
end
|
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:)
|
def fetch_patch(p, args:)
|
||||||
fetch_fetchable p, args: args
|
fetch_fetchable p, args: args
|
||||||
rescue ChecksumMismatchError => e
|
rescue ChecksumMismatchError => e
|
||||||
|
@ -808,7 +808,6 @@ describe Cask::Audit, :cask do
|
|||||||
let(:cask_token) { "with-binary" }
|
let(:cask_token) { "with-binary" }
|
||||||
let(:cask) { Cask::CaskLoader.load(cask_token) }
|
let(:cask) { Cask::CaskLoader.load(cask_token) }
|
||||||
let(:download_double) { instance_double(Cask::Download) }
|
let(:download_double) { instance_double(Cask::Download) }
|
||||||
let(:verify) { class_double(Cask::Verify).as_stubbed_const }
|
|
||||||
let(:message) { "Download Failed" }
|
let(:message) { "Download Failed" }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@ -817,19 +816,12 @@ describe Cask::Audit, :cask do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "when download and verification succeed it does not fail" do
|
it "when download and verification succeed it does not fail" do
|
||||||
expect(download_double).to receive(:perform)
|
expect(download_double).to receive(:fetch)
|
||||||
expect(verify).to receive(:all)
|
|
||||||
expect(subject).to pass
|
expect(subject).to pass
|
||||||
end
|
end
|
||||||
|
|
||||||
it "when download fails it fails" do
|
it "when download fails it fails" do
|
||||||
expect(download_double).to receive(:perform).and_raise(StandardError.new(message))
|
expect(download_double).to receive(:fetch).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(subject).to fail_with(/#{message}/)
|
expect(subject).to fail_with(/#{message}/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -36,7 +36,7 @@ describe Cask::Cmd::Fetch, :cask do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "prevents double fetch (without nuking existing installation)" do
|
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
|
old_ctime = File.stat(cached_location).ctime
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ describe Cask::Cmd::Fetch, :cask do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "allows double fetch with --force" do
|
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
|
old_ctime = File.stat(cached_location).ctime
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
@ -11,7 +11,6 @@ describe Cask::Cmd::Install, :cask do
|
|||||||
it "displays the installation progress" do
|
it "displays the installation progress" do
|
||||||
output = Regexp.new <<~EOS
|
output = Regexp.new <<~EOS
|
||||||
==> Downloading file:.*caffeine.zip
|
==> Downloading file:.*caffeine.zip
|
||||||
==> Verifying SHA-256 checksum for Cask 'local-caffeine'.
|
|
||||||
==> Installing Cask local-caffeine
|
==> Installing Cask local-caffeine
|
||||||
==> Moving App 'Caffeine.app' to '.*Caffeine.app'.
|
==> Moving App 'Caffeine.app' to '.*Caffeine.app'.
|
||||||
.*local-caffeine was successfully installed!
|
.*local-caffeine was successfully installed!
|
||||||
|
@ -14,7 +14,6 @@ describe Cask::Cmd::Reinstall, :cask do
|
|||||||
output = Regexp.new <<~EOS
|
output = Regexp.new <<~EOS
|
||||||
==> Downloading file:.*caffeine.zip
|
==> Downloading file:.*caffeine.zip
|
||||||
Already downloaded: .*--caffeine.zip
|
Already downloaded: .*--caffeine.zip
|
||||||
==> Verifying SHA-256 checksum for Cask 'local-caffeine'.
|
|
||||||
==> Uninstalling Cask local-caffeine
|
==> Uninstalling Cask local-caffeine
|
||||||
==> Backing App 'Caffeine.app' up to '.*Caffeine.app'.
|
==> Backing App 'Caffeine.app' up to '.*Caffeine.app'.
|
||||||
==> Removing App '.*Caffeine.app'.
|
==> Removing App '.*Caffeine.app'.
|
||||||
|
@ -2,26 +2,30 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Cask
|
module Cask
|
||||||
describe Verify, :cask do
|
describe Download, :cask do
|
||||||
describe "::all" do
|
describe "#verify_download_integrity" do
|
||||||
subject(:verification) { described_class.all(cask, downloaded_path) }
|
subject(:verification) { described_class.new(cask).verify_download_integrity(downloaded_path) }
|
||||||
|
|
||||||
let(:cask) { instance_double(Cask, token: "cask", sha256: expected_sha256) }
|
let(:cask) { instance_double(Cask, token: "cask", sha256: expected_sha256) }
|
||||||
let(:cafebabe) { "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" }
|
let(:cafebabe) { "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" }
|
||||||
let(:deadbeef) { "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" }
|
let(:deadbeef) { "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" }
|
||||||
let(:computed_sha256) { cafebabe }
|
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
|
context "when the expected checksum is :no_check" do
|
||||||
let(:expected_sha256) { :no_check }
|
let(:expected_sha256) { :no_check }
|
||||||
|
|
||||||
it "skips the check" do
|
it "skips the check" do
|
||||||
expect { verification }.to output(/skipping verification/).to_stdout
|
expect { verification }.to output(/skipping verification/).to_stderr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when expected and computed checksums match" do
|
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
|
it "does not raise an error" do
|
||||||
expect { verification }.not_to raise_error
|
expect { verification }.not_to raise_error
|
||||||
@ -37,7 +41,7 @@ module Cask
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "when the expected checksum is empty" do
|
context "when the expected checksum is empty" do
|
||||||
let(:expected_sha256) { "" }
|
let(:expected_sha256) { Checksum.new(:sha256, "") }
|
||||||
|
|
||||||
it "raises an error" do
|
it "raises an error" do
|
||||||
expect { verification }.to raise_error(CaskSha256MissingError, /sha256 "#{computed_sha256}"/)
|
expect { verification }.to raise_error(CaskSha256MissingError, /sha256 "#{computed_sha256}"/)
|
||||||
@ -45,7 +49,7 @@ module Cask
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "when expected and computed checksums do not match" do
|
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
|
it "raises an error" do
|
||||||
expect { verification }.to raise_error CaskSha256MismatchError
|
expect { verification }.to raise_error CaskSha256MismatchError
|
@ -116,7 +116,6 @@ describe Cask::Installer, :cask do
|
|||||||
}.to output(
|
}.to output(
|
||||||
<<~EOS,
|
<<~EOS,
|
||||||
==> Downloading file://#{HOMEBREW_LIBRARY_PATH}/test/support/fixtures/cask/caffeine.zip
|
==> 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
|
==> Installing Cask with-installer-manual
|
||||||
To complete the installation of Cask with-installer-manual, you must also
|
To complete the installation of Cask with-installer-manual, you must also
|
||||||
run the installer at:
|
run the installer at:
|
||||||
|
@ -31,7 +31,7 @@ describe Cask::Quarantine, :cask do
|
|||||||
it "quarantines Cask fetches" do
|
it "quarantines Cask fetches" do
|
||||||
Cask::Cmd::Fetch.run("local-transmission")
|
Cask::Cmd::Fetch.run("local-transmission")
|
||||||
local_transmission = Cask::CaskLoader.load(cask_path("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
|
expect(cached_location).to be_quarantined
|
||||||
end
|
end
|
||||||
@ -40,7 +40,7 @@ describe Cask::Quarantine, :cask do
|
|||||||
Cask::Cmd::Audit.run("local-transmission", "--download")
|
Cask::Cmd::Audit.run("local-transmission", "--download")
|
||||||
|
|
||||||
local_transmission = Cask::CaskLoader.load(cask_path("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
|
expect(cached_location).to be_quarantined
|
||||||
end
|
end
|
||||||
@ -142,7 +142,7 @@ describe Cask::Quarantine, :cask do
|
|||||||
it "does not quarantine Cask fetches" do
|
it "does not quarantine Cask fetches" do
|
||||||
Cask::Cmd::Fetch.run("local-transmission", "--no-quarantine")
|
Cask::Cmd::Fetch.run("local-transmission", "--no-quarantine")
|
||||||
local_transmission = Cask::CaskLoader.load(cask_path("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).not_to be_quarantined
|
expect(cached_location).not_to be_quarantined
|
||||||
end
|
end
|
||||||
@ -151,7 +151,7 @@ describe Cask::Quarantine, :cask do
|
|||||||
Cask::Cmd::Audit.run("local-transmission", "--download", "--no-quarantine")
|
Cask::Cmd::Audit.run("local-transmission", "--download", "--no-quarantine")
|
||||||
|
|
||||||
local_transmission = Cask::CaskLoader.load(cask_path("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).not_to be_quarantined
|
expect(cached_location).not_to be_quarantined
|
||||||
end
|
end
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
cask "invalid-manpage-no-section" do
|
cask "invalid-manpage-no-section" do
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"
|
sha256 "68b7e71a2ca7585b004f52652749589941e3029ff0884e8aa3b099594e0282c0"
|
||||||
|
|
||||||
url "file://#{TEST_FIXTURE_DIR}/cask/AppWithManpage.zip"
|
url "file://#{TEST_FIXTURE_DIR}/cask/AppWithManpage.zip"
|
||||||
homepage "https://brew.sh/with-generic-artifact"
|
homepage "https://brew.sh/with-generic-artifact"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
cask "with-autodetected-manpage-section" do
|
cask "with-autodetected-manpage-section" do
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"
|
sha256 "68b7e71a2ca7585b004f52652749589941e3029ff0884e8aa3b099594e0282c0"
|
||||||
|
|
||||||
url "file://#{TEST_FIXTURE_DIR}/cask/AppWithManpage.zip"
|
url "file://#{TEST_FIXTURE_DIR}/cask/AppWithManpage.zip"
|
||||||
homepage "https://brew.sh/with-autodetected-manpage-section"
|
homepage "https://brew.sh/with-autodetected-manpage-section"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
cask "with-non-executable-binary" do
|
cask "with-non-executable-binary" do
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
sha256 "d5b2dfbef7ea28c25f7a77cd7fa14d013d82b626db1d82e00e25822464ba19e2"
|
sha256 "306c6ca7407560340797866e077e053627ad409277d1b9da58106fce4cf717cb"
|
||||||
|
|
||||||
url "file://#{TEST_FIXTURE_DIR}/cask/naked_non_executable"
|
url "file://#{TEST_FIXTURE_DIR}/cask/naked_non_executable"
|
||||||
homepage "https://brew.sh/with-binary"
|
homepage "https://brew.sh/with-binary"
|
||||||
|
@ -199,8 +199,8 @@ an issue; just ignore this.
|
|||||||
|
|
||||||
### `fetch` [*`options`*] *`formula`*
|
### `fetch` [*`options`*] *`formula`*
|
||||||
|
|
||||||
Download a bottle (if available) or source packages for *`formula`*.
|
Download a bottle (if available) or source packages for *`formula`*e
|
||||||
For tarballs, also print SHA-256 checksums.
|
and binaries for *`cask`*s. For files, also print SHA-256 checksums.
|
||||||
|
|
||||||
* `--HEAD`:
|
* `--HEAD`:
|
||||||
Fetch HEAD version instead of stable version.
|
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.
|
Download source packages (for eventual bottling) rather than a bottle.
|
||||||
* `--force-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.
|
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.
|
||||||
|
|
||||||
### `gist-logs` [*`options`*] *`formula`*
|
### `gist-logs` [*`options`*] *`formula`*
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ List all audit methods, which can be run individually if provided as arguments\.
|
|||||||
Enable debugging and profiling of audit methods\.
|
Enable debugging and profiling of audit methods\.
|
||||||
.
|
.
|
||||||
.SS "\fBfetch\fR [\fIoptions\fR] \fIformula\fR"
|
.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
|
.TP
|
||||||
\fB\-\-HEAD\fR
|
\fB\-\-HEAD\fR
|
||||||
@ -292,6 +292,18 @@ Download source packages (for eventual bottling) rather than a bottle\.
|
|||||||
\fB\-\-force\-bottle\fR
|
\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\.
|
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 "\fBgist\-logs\fR [\fIoptions\fR] \fIformula\fR"
|
.SS "\fBgist\-logs\fR [\fIoptions\fR] \fIformula\fR"
|
||||||
Upload logs for a failed build of \fIformula\fR to a new Gist\. Presents an error message if no logs are found\.
|
Upload logs for a failed build of \fIformula\fR to a new Gist\. Presents an error message if no logs are found\.
|
||||||
.
|
.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user