Merge pull request #17554 from Homebrew/cask-install-receipt
This commit is contained in:
commit
f39b5c1426
@ -20,5 +20,6 @@ require "cask/migrator"
|
|||||||
require "cask/pkg"
|
require "cask/pkg"
|
||||||
require "cask/quarantine"
|
require "cask/quarantine"
|
||||||
require "cask/staged"
|
require "cask/staged"
|
||||||
|
require "cask/tab"
|
||||||
require "cask/url"
|
require "cask/url"
|
||||||
require "cask/utils"
|
require "cask/utils"
|
||||||
|
|||||||
@ -7,6 +7,7 @@ require "cask/cask_loader"
|
|||||||
require "cask/config"
|
require "cask/config"
|
||||||
require "cask/dsl"
|
require "cask/dsl"
|
||||||
require "cask/metadata"
|
require "cask/metadata"
|
||||||
|
require "cask/tab"
|
||||||
require "utils/bottles"
|
require "utils/bottles"
|
||||||
require "extend/api_hashable"
|
require "extend/api_hashable"
|
||||||
|
|
||||||
@ -158,6 +159,17 @@ module Cask
|
|||||||
languages.any? || artifacts.any?(Artifact::AbstractFlightBlock)
|
languages.any? || artifacts.any?(Artifact::AbstractFlightBlock)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def uninstall_flight_blocks?
|
||||||
|
artifacts.any? do |artifact|
|
||||||
|
case artifact
|
||||||
|
when Artifact::PreflightBlock
|
||||||
|
artifact.directives.key?(:uninstall_preflight)
|
||||||
|
when Artifact::PostflightBlock
|
||||||
|
artifact.directives.key?(:uninstall_postflight)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
sig { returns(T.nilable(Time)) }
|
sig { returns(T.nilable(Time)) }
|
||||||
def install_time
|
def install_time
|
||||||
# <caskroom_path>/.metadata/<version>/<timestamp>/Casks/<token>.{rb,json} -> <timestamp>
|
# <caskroom_path>/.metadata/<version>/<timestamp>/Casks/<token>.{rb,json} -> <timestamp>
|
||||||
@ -209,6 +221,10 @@ module Cask
|
|||||||
bundle_version&.version
|
bundle_version&.version
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tab
|
||||||
|
Tab.for_cask(self)
|
||||||
|
end
|
||||||
|
|
||||||
def config_path
|
def config_path
|
||||||
metadata_main_container_path/"config.json"
|
metadata_main_container_path/"config.json"
|
||||||
end
|
end
|
||||||
@ -465,6 +481,27 @@ module Cask
|
|||||||
hash
|
hash
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def artifacts_list(compact: false, uninstall_only: false)
|
||||||
|
artifacts.filter_map do |artifact|
|
||||||
|
case artifact
|
||||||
|
when Artifact::AbstractFlightBlock
|
||||||
|
uninstall_flight_block = artifact.directives.key?(:uninstall_preflight) ||
|
||||||
|
artifact.directives.key?(:uninstall_postflight)
|
||||||
|
next if uninstall_only && !uninstall_flight_block
|
||||||
|
|
||||||
|
# Only indicate whether this block is used as we don't load it from the API
|
||||||
|
# We can skip this entirely once we move to internal JSON v3.
|
||||||
|
{ artifact.summarize.to_sym => nil } unless compact
|
||||||
|
else
|
||||||
|
zap_artifact = artifact.is_a?(Artifact::Zap)
|
||||||
|
uninstall_artifact = artifact.respond_to?(:uninstall_phase) || artifact.respond_to?(:post_uninstall_phase)
|
||||||
|
next if uninstall_only && !zap_artifact && !uninstall_artifact
|
||||||
|
|
||||||
|
{ artifact.class.dsl_key => artifact.to_args }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
sig { returns(T.nilable(Homebrew::BundleVersion)) }
|
sig { returns(T.nilable(Homebrew::BundleVersion)) }
|
||||||
@ -482,19 +519,6 @@ module Cask
|
|||||||
hash
|
hash
|
||||||
end
|
end
|
||||||
|
|
||||||
def artifacts_list(compact: false)
|
|
||||||
artifacts.filter_map do |artifact|
|
|
||||||
case artifact
|
|
||||||
when Artifact::AbstractFlightBlock
|
|
||||||
# Only indicate whether this block is used as we don't load it from the API
|
|
||||||
# We can skip this entirely once we move to internal JSON v3.
|
|
||||||
{ artifact.summarize => nil } unless compact
|
|
||||||
else
|
|
||||||
{ artifact.class.dsl_key => artifact.to_args }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def url_specs
|
def url_specs
|
||||||
url&.specs.dup.tap do |url_specs|
|
url&.specs.dup.tap do |url_specs|
|
||||||
case url_specs&.dig(:user_agent)
|
case url_specs&.dig(:user_agent)
|
||||||
|
|||||||
@ -12,7 +12,7 @@ module Cask
|
|||||||
output << "#{Formatter.url(cask.homepage)}\n" if cask.homepage
|
output << "#{Formatter.url(cask.homepage)}\n" if cask.homepage
|
||||||
deprecate_disable = DeprecateDisable.message(cask)
|
deprecate_disable = DeprecateDisable.message(cask)
|
||||||
output << "#{deprecate_disable.capitalize}\n" if deprecate_disable
|
output << "#{deprecate_disable.capitalize}\n" if deprecate_disable
|
||||||
output << installation_info(cask)
|
output << "#{installation_info(cask)}\n"
|
||||||
repo = repo_info(cask)
|
repo = repo_info(cask)
|
||||||
output << "#{repo}\n" if repo
|
output << "#{repo}\n" if repo
|
||||||
output << name_info(cask)
|
output << name_info(cask)
|
||||||
@ -37,7 +37,7 @@ module Cask
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.installation_info(cask)
|
def self.installation_info(cask)
|
||||||
return "Not installed\n" unless cask.installed?
|
return "Not installed" unless cask.installed?
|
||||||
|
|
||||||
versioned_staged_path = cask.caskroom_path.join(cask.installed_version)
|
versioned_staged_path = cask.caskroom_path.join(cask.installed_version)
|
||||||
path_details = if versioned_staged_path.exist?
|
path_details = if versioned_staged_path.exist?
|
||||||
@ -46,7 +46,12 @@ module Cask
|
|||||||
Formatter.error("does not exist")
|
Formatter.error("does not exist")
|
||||||
end
|
end
|
||||||
|
|
||||||
"Installed\n#{versioned_staged_path} (#{path_details})\n"
|
tab = Tab.for_cask(cask)
|
||||||
|
|
||||||
|
info = ["Installed"]
|
||||||
|
info << "#{versioned_staged_path} (#{path_details})"
|
||||||
|
info << " #{tab}" if tab.tabfile&.exist?
|
||||||
|
info.join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.name_info(cask)
|
def self.name_info(cask)
|
||||||
|
|||||||
@ -10,6 +10,7 @@ require "cask/config"
|
|||||||
require "cask/download"
|
require "cask/download"
|
||||||
require "cask/migrator"
|
require "cask/migrator"
|
||||||
require "cask/quarantine"
|
require "cask/quarantine"
|
||||||
|
require "cask/tab"
|
||||||
|
|
||||||
require "cgi"
|
require "cgi"
|
||||||
|
|
||||||
@ -21,8 +22,8 @@ module Cask
|
|||||||
def initialize(cask, command: SystemCommand, force: false, adopt: false,
|
def initialize(cask, command: SystemCommand, force: false, adopt: false,
|
||||||
skip_cask_deps: false, binaries: true, verbose: false,
|
skip_cask_deps: false, binaries: true, verbose: false,
|
||||||
zap: false, require_sha: false, upgrade: false, reinstall: false,
|
zap: false, require_sha: false, upgrade: false, reinstall: false,
|
||||||
installed_as_dependency: false, quarantine: true,
|
installed_as_dependency: false, installed_on_request: true,
|
||||||
verify_download_integrity: true, quiet: false)
|
quarantine: true, verify_download_integrity: true, quiet: false)
|
||||||
@cask = cask
|
@cask = cask
|
||||||
@command = command
|
@command = command
|
||||||
@force = force
|
@force = force
|
||||||
@ -35,13 +36,14 @@ module Cask
|
|||||||
@reinstall = reinstall
|
@reinstall = reinstall
|
||||||
@upgrade = upgrade
|
@upgrade = upgrade
|
||||||
@installed_as_dependency = installed_as_dependency
|
@installed_as_dependency = installed_as_dependency
|
||||||
|
@installed_on_request = installed_on_request
|
||||||
@quarantine = quarantine
|
@quarantine = quarantine
|
||||||
@verify_download_integrity = verify_download_integrity
|
@verify_download_integrity = verify_download_integrity
|
||||||
@quiet = quiet
|
@quiet = quiet
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_predicate :binaries?, :force?, :adopt?, :skip_cask_deps?, :require_sha?,
|
attr_predicate :binaries?, :force?, :adopt?, :skip_cask_deps?, :require_sha?,
|
||||||
:reinstall?, :upgrade?, :verbose?, :zap?, :installed_as_dependency?,
|
:reinstall?, :upgrade?, :verbose?, :zap?, :installed_as_dependency?, :installed_on_request?,
|
||||||
:quarantine?, :quiet?
|
:quarantine?, :quiet?
|
||||||
|
|
||||||
def self.caveats(cask)
|
def self.caveats(cask)
|
||||||
@ -112,6 +114,11 @@ module Cask
|
|||||||
|
|
||||||
install_artifacts(predecessor:)
|
install_artifacts(predecessor:)
|
||||||
|
|
||||||
|
tab = Tab.create(@cask)
|
||||||
|
tab.installed_as_dependency = installed_as_dependency?
|
||||||
|
tab.installed_on_request = installed_on_request?
|
||||||
|
tab.write
|
||||||
|
|
||||||
if (tap = @cask.tap) && tap.should_report_analytics?
|
if (tap = @cask.tap) && tap.should_report_analytics?
|
||||||
::Utils::Analytics.report_package_event(:cask_install, package_name: @cask.token, tap_name: tap.name,
|
::Utils::Analytics.report_package_event(:cask_install, package_name: @cask.token, tap_name: tap.name,
|
||||||
on_request: true)
|
on_request: true)
|
||||||
@ -356,6 +363,7 @@ on_request: true)
|
|||||||
binaries: binaries?,
|
binaries: binaries?,
|
||||||
verbose: verbose?,
|
verbose: verbose?,
|
||||||
installed_as_dependency: true,
|
installed_as_dependency: true,
|
||||||
|
installed_on_request: false,
|
||||||
force: false,
|
force: false,
|
||||||
).install
|
).install
|
||||||
else
|
else
|
||||||
@ -408,6 +416,7 @@ on_request: true)
|
|||||||
oh1 "Uninstalling Cask #{Formatter.identifier(@cask)}"
|
oh1 "Uninstalling Cask #{Formatter.identifier(@cask)}"
|
||||||
uninstall_artifacts(clear: true, successor:)
|
uninstall_artifacts(clear: true, successor:)
|
||||||
if !reinstall? && !upgrade?
|
if !reinstall? && !upgrade?
|
||||||
|
remove_tabfile
|
||||||
remove_download_sha
|
remove_download_sha
|
||||||
remove_config_file
|
remove_config_file
|
||||||
end
|
end
|
||||||
@ -415,6 +424,12 @@ on_request: true)
|
|||||||
purge_caskroom_path if force?
|
purge_caskroom_path if force?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_tabfile
|
||||||
|
tabfile = @cask.tab.tabfile
|
||||||
|
FileUtils.rm_f tabfile if tabfile
|
||||||
|
@cask.config_path.parent.rmdir_if_possible
|
||||||
|
end
|
||||||
|
|
||||||
def remove_config_file
|
def remove_config_file
|
||||||
FileUtils.rm_f @cask.config_path
|
FileUtils.rm_f @cask.config_path
|
||||||
@cask.config_path.parent.rmdir_if_possible
|
@cask.config_path.parent.rmdir_if_possible
|
||||||
|
|||||||
108
Library/Homebrew/cask/tab.rb
Normal file
108
Library/Homebrew/cask/tab.rb
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# typed: true
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "tab"
|
||||||
|
|
||||||
|
module Cask
|
||||||
|
class Tab < ::AbstractTab
|
||||||
|
attr_accessor :uninstall_flight_blocks, :uninstall_artifacts
|
||||||
|
|
||||||
|
# Instantiates a {Tab} for a new installation of a cask.
|
||||||
|
def self.create(cask)
|
||||||
|
tab = super
|
||||||
|
|
||||||
|
tab.tabfile = cask.metadata_main_container_path/FILENAME
|
||||||
|
tab.uninstall_flight_blocks = cask.uninstall_flight_blocks?
|
||||||
|
tab.runtime_dependencies = Tab.runtime_deps_hash(cask)
|
||||||
|
tab.source["version"] = cask.version.to_s
|
||||||
|
tab.source["path"] = cask.sourcefile_path.to_s
|
||||||
|
tab.uninstall_artifacts = cask.artifacts_list(uninstall_only: true)
|
||||||
|
|
||||||
|
tab
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a {Tab} for an already installed cask,
|
||||||
|
# or a fake one if the cask is not installed.
|
||||||
|
def self.for_cask(cask)
|
||||||
|
path = cask.metadata_main_container_path/FILENAME
|
||||||
|
|
||||||
|
return from_file(path) if path.exist?
|
||||||
|
|
||||||
|
tab = empty
|
||||||
|
tab.source = {
|
||||||
|
"path" => cask.sourcefile_path.to_s,
|
||||||
|
"tap" => cask.tap&.name,
|
||||||
|
"tap_git_head" => cask.tap_git_head,
|
||||||
|
"version" => cask.version.to_s,
|
||||||
|
}
|
||||||
|
tab.uninstall_artifacts = cask.artifacts_list(uninstall_only: true)
|
||||||
|
|
||||||
|
tab
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.empty
|
||||||
|
tab = super
|
||||||
|
tab.uninstall_flight_blocks = false
|
||||||
|
tab.uninstall_artifacts = []
|
||||||
|
tab.source["version"] = nil
|
||||||
|
|
||||||
|
tab
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.runtime_deps_hash(cask)
|
||||||
|
cask_and_formula_dep_graph = ::Utils::TopologicalHash.graph_package_dependencies(cask)
|
||||||
|
cask_deps, formula_deps = cask_and_formula_dep_graph.values.flatten.uniq.partition do |dep|
|
||||||
|
dep.is_a?(Cask)
|
||||||
|
end
|
||||||
|
|
||||||
|
runtime_deps = {}
|
||||||
|
|
||||||
|
if cask_deps.any?
|
||||||
|
runtime_deps[:cask] = cask_deps.map do |dep|
|
||||||
|
{
|
||||||
|
"full_name" => dep.full_name,
|
||||||
|
"version" => dep.version.to_s,
|
||||||
|
"declared_directly" => cask.depends_on.cask.include?(dep.full_name),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if formula_deps.any?
|
||||||
|
runtime_deps[:formula] = formula_deps.map do |dep|
|
||||||
|
formula_to_dep_hash(dep, cask.depends_on.formula)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
runtime_deps
|
||||||
|
end
|
||||||
|
|
||||||
|
def version
|
||||||
|
source["version"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(*_args)
|
||||||
|
attributes = {
|
||||||
|
"homebrew_version" => homebrew_version,
|
||||||
|
"loaded_from_api" => loaded_from_api,
|
||||||
|
"uninstall_flight_blocks" => uninstall_flight_blocks,
|
||||||
|
"installed_as_dependency" => installed_as_dependency,
|
||||||
|
"installed_on_request" => installed_on_request,
|
||||||
|
"time" => time,
|
||||||
|
"runtime_dependencies" => runtime_dependencies,
|
||||||
|
"source" => source,
|
||||||
|
"arch" => arch,
|
||||||
|
"uninstall_artifacts" => uninstall_artifacts,
|
||||||
|
"built_on" => built_on,
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON.pretty_generate(attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
s = ["Installed"]
|
||||||
|
s << "using the formulae.brew.sh API" if loaded_from_api
|
||||||
|
s << Time.at(time).strftime("on %Y-%m-%d at %H:%M:%S") if time
|
||||||
|
s.join(" ")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -10,7 +10,7 @@ module Homebrew
|
|||||||
class TabCmd < AbstractCommand
|
class TabCmd < AbstractCommand
|
||||||
cmd_args do
|
cmd_args do
|
||||||
description <<~EOS
|
description <<~EOS
|
||||||
Edit tab information for installed formulae.
|
Edit tab information for installed formulae or casks.
|
||||||
|
|
||||||
This can be useful when you want to control whether an installed
|
This can be useful when you want to control whether an installed
|
||||||
formula should be removed by `brew autoremove`.
|
formula should be removed by `brew autoremove`.
|
||||||
@ -19,13 +19,18 @@ module Homebrew
|
|||||||
EOS
|
EOS
|
||||||
|
|
||||||
switch "--installed-on-request",
|
switch "--installed-on-request",
|
||||||
description: "Mark <formula> as installed on request."
|
description: "Mark <installed_formula> or <installed_cask> as installed on request."
|
||||||
switch "--no-installed-on-request",
|
switch "--no-installed-on-request",
|
||||||
description: "Mark <formula> as not installed on request."
|
description: "Mark <installed_formula> or <installed_cask> as not installed on request."
|
||||||
|
switch "--formula", "--formulae",
|
||||||
|
description: "Only mark formulae."
|
||||||
|
switch "--cask", "--casks",
|
||||||
|
description: "Only mark casks."
|
||||||
|
|
||||||
|
conflicts "--formula", "--cask"
|
||||||
conflicts "--installed-on-request", "--no-installed-on-request"
|
conflicts "--installed-on-request", "--no-installed-on-request"
|
||||||
|
|
||||||
named_args :formula, min: 1
|
named_args [:installed_formula, :installed_cask], min: 1
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { override.void }
|
sig { override.void }
|
||||||
@ -37,38 +42,45 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
raise UsageError, "No marking option specified." if installed_on_request.nil?
|
raise UsageError, "No marking option specified." if installed_on_request.nil?
|
||||||
|
|
||||||
formulae = args.named.to_formulae
|
formulae, casks = args.named.to_formulae_to_casks
|
||||||
if (formulae_not_installed = formulae.reject(&:any_version_installed?)).any?
|
formulae_not_installed = formulae.reject(&:any_version_installed?)
|
||||||
formula_names = formulae_not_installed.map(&:name)
|
casks_not_installed = casks.reject(&:installed?)
|
||||||
is_or_are = (formula_names.length == 1) ? "is" : "are"
|
if formulae_not_installed.any? || casks_not_installed.any?
|
||||||
odie "#{formula_names.to_sentence} #{is_or_are} not installed."
|
names = formulae_not_installed.map(&:name) + casks_not_installed.map(&:token)
|
||||||
|
is_or_are = (names.length == 1) ? "is" : "are"
|
||||||
|
odie "#{names.to_sentence} #{is_or_are} not installed."
|
||||||
end
|
end
|
||||||
|
|
||||||
formulae.each do |formula|
|
[*formulae, *casks].each do |formula_or_cask|
|
||||||
update_tab formula, installed_on_request:
|
update_tab formula_or_cask, installed_on_request:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
sig { params(formula: Formula, installed_on_request: T::Boolean).void }
|
sig { params(formula_or_cask: T.any(Formula, Cask::Cask), installed_on_request: T::Boolean).void }
|
||||||
def update_tab(formula, installed_on_request:)
|
def update_tab(formula_or_cask, installed_on_request:)
|
||||||
tab = Tab.for_formula(formula)
|
name, tab = if formula_or_cask.is_a?(Formula)
|
||||||
unless tab.tabfile.exist?
|
[formula_or_cask.name, Tab.for_formula(formula_or_cask)]
|
||||||
|
else
|
||||||
|
[formula_or_cask.token, formula_or_cask.tab]
|
||||||
|
end
|
||||||
|
|
||||||
|
if tab.tabfile.blank? || !tab.tabfile.exist?
|
||||||
raise ArgumentError,
|
raise ArgumentError,
|
||||||
"Tab file for #{formula.name} does not exist."
|
"Tab file for #{name} does not exist."
|
||||||
end
|
end
|
||||||
|
|
||||||
installed_on_request_str = "#{"not " unless installed_on_request}installed on request"
|
installed_on_request_str = "#{"not " unless installed_on_request}installed on request"
|
||||||
if (tab.installed_on_request && installed_on_request) ||
|
if (tab.installed_on_request && installed_on_request) ||
|
||||||
(!tab.installed_on_request && !installed_on_request)
|
(!tab.installed_on_request && !installed_on_request)
|
||||||
ohai "#{formula.name} is already marked as #{installed_on_request_str}."
|
ohai "#{name} is already marked as #{installed_on_request_str}."
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
tab.installed_on_request = installed_on_request
|
tab.installed_on_request = installed_on_request
|
||||||
tab.write
|
tab.write
|
||||||
ohai "#{formula.name} is now marked as #{installed_on_request_str}."
|
ohai "#{name} is now marked as #{installed_on_request_str}."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -524,7 +524,7 @@ module Homebrew
|
|||||||
tab.time = nil
|
tab.time = nil
|
||||||
tab.changed_files = changed_files.dup
|
tab.changed_files = changed_files.dup
|
||||||
if args.only_json_tab?
|
if args.only_json_tab?
|
||||||
tab.changed_files.delete(Pathname.new(Tab::FILENAME))
|
tab.changed_files.delete(Pathname.new(AbstractTab::FILENAME))
|
||||||
tab.tabfile.unlink
|
tab.tabfile.unlink
|
||||||
else
|
else
|
||||||
tab.write
|
tab.write
|
||||||
|
|||||||
@ -637,7 +637,7 @@ class Formula
|
|||||||
# If at least one version of {Formula} is installed.
|
# If at least one version of {Formula} is installed.
|
||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def any_version_installed?
|
def any_version_installed?
|
||||||
installed_prefixes.any? { |keg| (keg/Tab::FILENAME).file? }
|
installed_prefixes.any? { |keg| (keg/AbstractTab::FILENAME).file? }
|
||||||
end
|
end
|
||||||
|
|
||||||
# The link status symlink directory for this {Formula}.
|
# The link status symlink directory for this {Formula}.
|
||||||
|
|||||||
@ -344,6 +344,9 @@ module Cask
|
|||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def installed_as_dependency?; end
|
def installed_as_dependency?; end
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
|
def installed_on_request?; end
|
||||||
|
|
||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def quarantine?; end
|
def quarantine?; end
|
||||||
|
|
||||||
|
|||||||
@ -8,78 +8,48 @@ require "development_tools"
|
|||||||
require "extend/cachable"
|
require "extend/cachable"
|
||||||
|
|
||||||
# Rather than calling `new` directly, use one of the class methods like {Tab.create}.
|
# Rather than calling `new` directly, use one of the class methods like {Tab.create}.
|
||||||
class Tab
|
class AbstractTab
|
||||||
extend Cachable
|
extend Cachable
|
||||||
|
|
||||||
FILENAME = "INSTALL_RECEIPT.json"
|
FILENAME = "INSTALL_RECEIPT.json"
|
||||||
|
|
||||||
# Check whether the formula was installed as a dependency.
|
# Check whether the formula or cask was installed as a dependency.
|
||||||
#
|
#
|
||||||
# @api internal
|
# @api internal
|
||||||
attr_accessor :installed_as_dependency
|
attr_accessor :installed_as_dependency
|
||||||
|
|
||||||
# Check whether the formula was installed on request.
|
# Check whether the formula or cask was installed on request.
|
||||||
#
|
#
|
||||||
# @api internal
|
# @api internal
|
||||||
attr_accessor :installed_on_request
|
attr_accessor :installed_on_request
|
||||||
|
|
||||||
# Check whether the formula was poured from a bottle.
|
attr_accessor :homebrew_version, :tabfile, :loaded_from_api, :time, :arch, :source, :built_on
|
||||||
|
|
||||||
|
# Returns the formula or cask runtime dependencies.
|
||||||
#
|
#
|
||||||
# @api internal
|
# @api internal
|
||||||
attr_accessor :poured_from_bottle
|
attr_accessor :runtime_dependencies
|
||||||
|
|
||||||
attr_accessor :homebrew_version, :tabfile, :built_as_bottle,
|
# Instantiates a {Tab} for a new installation of a formula or cask.
|
||||||
:changed_files, :loaded_from_api, :time, :stdlib, :aliases, :arch, :source,
|
def self.create(formula_or_cask)
|
||||||
:built_on
|
|
||||||
attr_writer :used_options, :unused_options, :compiler, :source_modified_time
|
|
||||||
|
|
||||||
# Returns the formula's runtime dependencies.
|
|
||||||
#
|
|
||||||
# @api internal
|
|
||||||
attr_writer :runtime_dependencies
|
|
||||||
|
|
||||||
# Instantiates a {Tab} for a new installation of a formula.
|
|
||||||
def self.create(formula, compiler, stdlib)
|
|
||||||
build = formula.build
|
|
||||||
runtime_deps = formula.runtime_dependencies(undeclared: false)
|
|
||||||
attributes = {
|
attributes = {
|
||||||
"homebrew_version" => HOMEBREW_VERSION,
|
"homebrew_version" => HOMEBREW_VERSION,
|
||||||
"used_options" => build.used_options.as_flags,
|
|
||||||
"unused_options" => build.unused_options.as_flags,
|
|
||||||
"tabfile" => formula.prefix/FILENAME,
|
|
||||||
"built_as_bottle" => build.bottle?,
|
|
||||||
"installed_as_dependency" => false,
|
"installed_as_dependency" => false,
|
||||||
"installed_on_request" => false,
|
"installed_on_request" => false,
|
||||||
"poured_from_bottle" => false,
|
"loaded_from_api" => formula_or_cask.loaded_from_api?,
|
||||||
"loaded_from_api" => false,
|
|
||||||
"time" => Time.now.to_i,
|
"time" => Time.now.to_i,
|
||||||
"source_modified_time" => formula.source_modified_time.to_i,
|
|
||||||
"compiler" => compiler,
|
|
||||||
"stdlib" => stdlib,
|
|
||||||
"aliases" => formula.aliases,
|
|
||||||
"runtime_dependencies" => Tab.runtime_deps_hash(formula, runtime_deps),
|
|
||||||
"arch" => Hardware::CPU.arch,
|
"arch" => Hardware::CPU.arch,
|
||||||
"source" => {
|
"source" => {
|
||||||
"path" => formula.specified_path.to_s,
|
"tap" => formula_or_cask.tap&.name,
|
||||||
"tap" => formula.tap&.name,
|
"tap_git_head" => formula_or_cask.tap_git_head,
|
||||||
"tap_git_head" => nil, # Filled in later if possible
|
|
||||||
"spec" => formula.active_spec_sym.to_s,
|
|
||||||
"versions" => {
|
|
||||||
"stable" => formula.stable&.version&.to_s,
|
|
||||||
"head" => formula.head&.version&.to_s,
|
|
||||||
"version_scheme" => formula.version_scheme,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"built_on" => DevelopmentTools.build_system_info,
|
"built_on" => DevelopmentTools.build_system_info,
|
||||||
}
|
}
|
||||||
|
|
||||||
# We can only get `tap_git_head` if the tap is installed locally
|
|
||||||
attributes["source"]["tap_git_head"] = formula.tap.git_head if formula.tap&.installed?
|
|
||||||
|
|
||||||
new(attributes)
|
new(attributes)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the {Tab} for an install receipt at `path`.
|
# Returns the {Tab} for a formula or cask install receipt at `path`.
|
||||||
#
|
#
|
||||||
# NOTE: Results are cached.
|
# NOTE: Results are cached.
|
||||||
def self.from_file(path)
|
def self.from_file(path)
|
||||||
@ -99,42 +69,132 @@ class Tab
|
|||||||
raise e, "Cannot parse #{path}: #{e}", e.backtrace
|
raise e, "Cannot parse #{path}: #{e}", e.backtrace
|
||||||
end
|
end
|
||||||
attributes["tabfile"] = path
|
attributes["tabfile"] = path
|
||||||
attributes["source_modified_time"] ||= 0
|
|
||||||
attributes["source"] ||= {}
|
|
||||||
|
|
||||||
tapped_from = attributes["tapped_from"]
|
new(attributes)
|
||||||
if !tapped_from.nil? && tapped_from != "path or URL"
|
end
|
||||||
attributes["source"]["tap"] = attributes.delete("tapped_from")
|
|
||||||
end
|
|
||||||
|
|
||||||
if attributes["source"]["tap"] == "mxcl/master" ||
|
def self.empty
|
||||||
attributes["source"]["tap"] == "Homebrew/homebrew"
|
attributes = {
|
||||||
attributes["source"]["tap"] = "homebrew/core"
|
"homebrew_version" => HOMEBREW_VERSION,
|
||||||
end
|
"installed_as_dependency" => false,
|
||||||
|
"installed_on_request" => false,
|
||||||
|
"loaded_from_api" => false,
|
||||||
|
"time" => nil,
|
||||||
|
"runtime_dependencies" => nil,
|
||||||
|
"arch" => nil,
|
||||||
|
"source" => {
|
||||||
|
"path" => nil,
|
||||||
|
"tap" => nil,
|
||||||
|
"tap_git_head" => nil,
|
||||||
|
},
|
||||||
|
"built_on" => DevelopmentTools.generic_build_system_info,
|
||||||
|
}
|
||||||
|
|
||||||
if attributes["source"]["spec"].nil?
|
new(attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.formula_to_dep_hash(formula, declared_deps)
|
||||||
|
{
|
||||||
|
"full_name" => formula.full_name,
|
||||||
|
"version" => formula.version.to_s,
|
||||||
|
"revision" => formula.revision,
|
||||||
|
"pkg_version" => formula.pkg_version.to_s,
|
||||||
|
"declared_directly" => declared_deps.include?(formula.full_name),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
private_class_method :formula_to_dep_hash
|
||||||
|
|
||||||
|
def initialize(attributes = {})
|
||||||
|
attributes.each { |key, value| instance_variable_set(:"@#{key}", value) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def parsed_homebrew_version
|
||||||
|
return Version::NULL if homebrew_version.nil?
|
||||||
|
|
||||||
|
Version.new(homebrew_version)
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { returns(T.nilable(Tap)) }
|
||||||
|
def tap
|
||||||
|
tap_name = source["tap"]
|
||||||
|
Tap.fetch(tap_name) if tap_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def tap=(tap)
|
||||||
|
tap_name = tap.respond_to?(:name) ? tap.name : tap
|
||||||
|
source["tap"] = tap_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def write
|
||||||
|
self.class.cache[tabfile] = self
|
||||||
|
tabfile.atomic_write(to_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Tab < AbstractTab
|
||||||
|
# Check whether the formula was poured from a bottle.
|
||||||
|
#
|
||||||
|
# @api internal
|
||||||
|
attr_accessor :poured_from_bottle
|
||||||
|
|
||||||
|
attr_accessor :built_as_bottle, :changed_files, :stdlib, :aliases
|
||||||
|
attr_writer :used_options, :unused_options, :compiler, :source_modified_time
|
||||||
|
attr_reader :tapped_from
|
||||||
|
|
||||||
|
# Instantiates a {Tab} for a new installation of a formula.
|
||||||
|
def self.create(formula, compiler, stdlib)
|
||||||
|
tab = super(formula)
|
||||||
|
build = formula.build
|
||||||
|
runtime_deps = formula.runtime_dependencies(undeclared: false)
|
||||||
|
|
||||||
|
tab.used_options = build.used_options.as_flags
|
||||||
|
tab.unused_options = build.unused_options.as_flags
|
||||||
|
tab.tabfile = formula.prefix/FILENAME
|
||||||
|
tab.built_as_bottle = build.bottle?
|
||||||
|
tab.poured_from_bottle = false
|
||||||
|
tab.source_modified_time = formula.source_modified_time.to_i
|
||||||
|
tab.compiler = compiler
|
||||||
|
tab.stdlib = stdlib
|
||||||
|
tab.aliases = formula.aliases
|
||||||
|
tab.runtime_dependencies = Tab.runtime_deps_hash(formula, runtime_deps)
|
||||||
|
tab.source["spec"] = formula.active_spec_sym.to_s
|
||||||
|
tab.source["path"] = formula.specified_path.to_s
|
||||||
|
tab.source["versions"] = {
|
||||||
|
"stable" => formula.stable&.version&.to_s,
|
||||||
|
"head" => formula.head&.version&.to_s,
|
||||||
|
"version_scheme" => formula.version_scheme,
|
||||||
|
}
|
||||||
|
|
||||||
|
tab
|
||||||
|
end
|
||||||
|
|
||||||
|
# Like {from_file}, but bypass the cache.
|
||||||
|
def self.from_file_content(content, path)
|
||||||
|
tab = super
|
||||||
|
|
||||||
|
tab.source_modified_time ||= 0
|
||||||
|
tab.source ||= {}
|
||||||
|
|
||||||
|
tab.tap = tab.tapped_from if !tab.tapped_from.nil? && tab.tapped_from != "path or URL"
|
||||||
|
tab.tap = "homebrew/core" if tab.tap == "mxcl/master" || tab.tap == "Homebrew/homebrew"
|
||||||
|
|
||||||
|
if tab.source["spec"].nil?
|
||||||
version = PkgVersion.parse(File.basename(File.dirname(path)))
|
version = PkgVersion.parse(File.basename(File.dirname(path)))
|
||||||
attributes["source"]["spec"] = if version.head?
|
tab.source["spec"] = if version.head?
|
||||||
"head"
|
"head"
|
||||||
else
|
else
|
||||||
"stable"
|
"stable"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if attributes["source"]["versions"].nil?
|
tab.source["versions"] ||= empty_source_versions
|
||||||
attributes["source"]["versions"] = {
|
|
||||||
"stable" => nil,
|
|
||||||
"head" => nil,
|
|
||||||
"version_scheme" => 0,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Tabs created with Homebrew 1.5.13 through 4.0.17 inclusive created empty string versions in some cases.
|
# Tabs created with Homebrew 1.5.13 through 4.0.17 inclusive created empty string versions in some cases.
|
||||||
["stable", "head"].each do |spec|
|
["stable", "head"].each do |spec|
|
||||||
attributes["source"]["versions"][spec] = attributes["source"]["versions"][spec].presence
|
tab.source["versions"][spec] = tab.source["versions"][spec].presence
|
||||||
end
|
end
|
||||||
|
|
||||||
new(attributes)
|
tab
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get the {Tab} for the given {Keg},
|
# Get the {Tab} for the given {Keg},
|
||||||
@ -198,10 +258,11 @@ class Tab
|
|||||||
tab = empty
|
tab = empty
|
||||||
tab.unused_options = formula.options.as_flags
|
tab.unused_options = formula.options.as_flags
|
||||||
tab.source = {
|
tab.source = {
|
||||||
"path" => formula.specified_path.to_s,
|
"path" => formula.specified_path.to_s,
|
||||||
"tap" => formula.tap&.name,
|
"tap" => formula.tap&.name,
|
||||||
"spec" => formula.active_spec_sym.to_s,
|
"tap_git_head" => formula.tap_git_head,
|
||||||
"versions" => {
|
"spec" => formula.active_spec_sym.to_s,
|
||||||
|
"versions" => {
|
||||||
"stable" => formula.stable&.version&.to_s,
|
"stable" => formula.stable&.version&.to_s,
|
||||||
"head" => formula.head&.version&.to_s,
|
"head" => formula.head&.version&.to_s,
|
||||||
"version_scheme" => formula.version_scheme,
|
"version_scheme" => formula.version_scheme,
|
||||||
@ -213,56 +274,37 @@ class Tab
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.empty
|
def self.empty
|
||||||
attributes = {
|
tab = super
|
||||||
"homebrew_version" => HOMEBREW_VERSION,
|
|
||||||
"used_options" => [],
|
|
||||||
"unused_options" => [],
|
|
||||||
"built_as_bottle" => false,
|
|
||||||
"installed_as_dependency" => false,
|
|
||||||
"installed_on_request" => false,
|
|
||||||
"poured_from_bottle" => false,
|
|
||||||
"loaded_from_api" => false,
|
|
||||||
"time" => nil,
|
|
||||||
"source_modified_time" => 0,
|
|
||||||
"stdlib" => nil,
|
|
||||||
"compiler" => DevelopmentTools.default_compiler,
|
|
||||||
"aliases" => [],
|
|
||||||
"runtime_dependencies" => nil,
|
|
||||||
"arch" => nil,
|
|
||||||
"source" => {
|
|
||||||
"path" => nil,
|
|
||||||
"tap" => nil,
|
|
||||||
"tap_git_head" => nil,
|
|
||||||
"spec" => "stable",
|
|
||||||
"versions" => {
|
|
||||||
"stable" => nil,
|
|
||||||
"head" => nil,
|
|
||||||
"version_scheme" => 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"built_on" => DevelopmentTools.generic_build_system_info,
|
|
||||||
}
|
|
||||||
|
|
||||||
new(attributes)
|
tab.used_options = []
|
||||||
|
tab.unused_options = []
|
||||||
|
tab.built_as_bottle = false
|
||||||
|
tab.poured_from_bottle = false
|
||||||
|
tab.source_modified_time = 0
|
||||||
|
tab.stdlib = nil
|
||||||
|
tab.compiler = DevelopmentTools.default_compiler
|
||||||
|
tab.aliases = []
|
||||||
|
tab.source["spec"] = "stable"
|
||||||
|
tab.source["versions"] = empty_source_versions
|
||||||
|
|
||||||
|
tab
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.empty_source_versions
|
||||||
|
{
|
||||||
|
"stable" => nil,
|
||||||
|
"head" => nil,
|
||||||
|
"version_scheme" => 0,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
private_class_method :empty_source_versions
|
||||||
|
|
||||||
def self.runtime_deps_hash(formula, deps)
|
def self.runtime_deps_hash(formula, deps)
|
||||||
deps.map do |dep|
|
deps.map do |dep|
|
||||||
f = dep.to_formula
|
formula_to_dep_hash(dep.to_formula, formula.deps.map(&:name))
|
||||||
{
|
|
||||||
"full_name" => f.full_name,
|
|
||||||
"version" => f.version.to_s,
|
|
||||||
"revision" => f.revision,
|
|
||||||
"pkg_version" => f.pkg_version.to_s,
|
|
||||||
"declared_directly" => formula.deps.include?(dep),
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(attributes = {})
|
|
||||||
attributes.each { |key, value| instance_variable_set(:"@#{key}", value) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def any_args_or_options?
|
def any_args_or_options?
|
||||||
!used_options.empty? || !unused_options.empty?
|
!used_options.empty? || !unused_options.empty?
|
||||||
end
|
end
|
||||||
@ -307,12 +349,6 @@ class Tab
|
|||||||
@compiler || DevelopmentTools.default_compiler
|
@compiler || DevelopmentTools.default_compiler
|
||||||
end
|
end
|
||||||
|
|
||||||
def parsed_homebrew_version
|
|
||||||
return Version::NULL if homebrew_version.nil?
|
|
||||||
|
|
||||||
Version.new(homebrew_version)
|
|
||||||
end
|
|
||||||
|
|
||||||
def runtime_dependencies
|
def runtime_dependencies
|
||||||
# Homebrew versions prior to 1.1.6 generated incorrect runtime dependency
|
# Homebrew versions prior to 1.1.6 generated incorrect runtime dependency
|
||||||
# lists.
|
# lists.
|
||||||
@ -333,17 +369,6 @@ class Tab
|
|||||||
built_as_bottle
|
built_as_bottle
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(T.nilable(Tap)) }
|
|
||||||
def tap
|
|
||||||
tap_name = source["tap"]
|
|
||||||
Tap.fetch(tap_name) if tap_name
|
|
||||||
end
|
|
||||||
|
|
||||||
def tap=(tap)
|
|
||||||
tap_name = tap.respond_to?(:name) ? tap.name : tap
|
|
||||||
source["tap"] = tap_name
|
|
||||||
end
|
|
||||||
|
|
||||||
def spec
|
def spec
|
||||||
source["spec"].to_sym
|
source["spec"].to_sym
|
||||||
end
|
end
|
||||||
@ -416,8 +441,7 @@ class Tab
|
|||||||
# will no longer be valid.
|
# will no longer be valid.
|
||||||
Formula.clear_cache unless tabfile.exist?
|
Formula.clear_cache unless tabfile.exist?
|
||||||
|
|
||||||
self.class.cache[tabfile] = self
|
super
|
||||||
tabfile.atomic_write(to_json)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(String) }
|
sig { returns(String) }
|
||||||
|
|||||||
@ -212,6 +212,115 @@ RSpec.describe Cask::Cask, :cask do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#artifacts_list" do
|
||||||
|
subject(:cask) { Cask::CaskLoader.load("many-artifacts") }
|
||||||
|
|
||||||
|
it "returns all artifacts when no options are given" do
|
||||||
|
expected_artifacts = [
|
||||||
|
{ uninstall_preflight: nil },
|
||||||
|
{ preflight: nil },
|
||||||
|
{ uninstall: [{
|
||||||
|
rmdir: "#{TEST_TMPDIR}/empty_directory_path",
|
||||||
|
trash: ["#{TEST_TMPDIR}/foo", "#{TEST_TMPDIR}/bar"],
|
||||||
|
}] },
|
||||||
|
{ pkg: ["ManyArtifacts/ManyArtifacts.pkg"] },
|
||||||
|
{ app: ["ManyArtifacts/ManyArtifacts.app"] },
|
||||||
|
{ uninstall_postflight: nil },
|
||||||
|
{ postflight: nil },
|
||||||
|
{ zap: [{
|
||||||
|
rmdir: ["~/Library/Caches/ManyArtifacts", "~/Library/Application Support/ManyArtifacts"],
|
||||||
|
trash: "~/Library/Logs/ManyArtifacts.log",
|
||||||
|
}] },
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(cask.artifacts_list).to eq(expected_artifacts)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "skips flight blocks when compact is true" do
|
||||||
|
expected_artifacts = [
|
||||||
|
{ uninstall: [{
|
||||||
|
rmdir: "#{TEST_TMPDIR}/empty_directory_path",
|
||||||
|
trash: ["#{TEST_TMPDIR}/foo", "#{TEST_TMPDIR}/bar"],
|
||||||
|
}] },
|
||||||
|
{ pkg: ["ManyArtifacts/ManyArtifacts.pkg"] },
|
||||||
|
{ app: ["ManyArtifacts/ManyArtifacts.app"] },
|
||||||
|
{ zap: [{
|
||||||
|
rmdir: ["~/Library/Caches/ManyArtifacts", "~/Library/Application Support/ManyArtifacts"],
|
||||||
|
trash: "~/Library/Logs/ManyArtifacts.log",
|
||||||
|
}] },
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(cask.artifacts_list(compact: true)).to eq(expected_artifacts)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns only uninstall artifacts when uninstall_only is true" do
|
||||||
|
expected_artifacts = [
|
||||||
|
{ uninstall_preflight: nil },
|
||||||
|
{ uninstall: [{
|
||||||
|
rmdir: "#{TEST_TMPDIR}/empty_directory_path",
|
||||||
|
trash: ["#{TEST_TMPDIR}/foo", "#{TEST_TMPDIR}/bar"],
|
||||||
|
}] },
|
||||||
|
{ app: ["ManyArtifacts/ManyArtifacts.app"] },
|
||||||
|
{ uninstall_postflight: nil },
|
||||||
|
{ zap: [{
|
||||||
|
rmdir: ["~/Library/Caches/ManyArtifacts", "~/Library/Application Support/ManyArtifacts"],
|
||||||
|
trash: "~/Library/Logs/ManyArtifacts.log",
|
||||||
|
}] },
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(cask.artifacts_list(uninstall_only: true)).to eq(expected_artifacts)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "skips flight blocks and returns only uninstall artifacts when compact and uninstall_only are true" do
|
||||||
|
expected_artifacts = [
|
||||||
|
{ uninstall: [{
|
||||||
|
rmdir: "#{TEST_TMPDIR}/empty_directory_path",
|
||||||
|
trash: ["#{TEST_TMPDIR}/foo", "#{TEST_TMPDIR}/bar"],
|
||||||
|
}] },
|
||||||
|
{ app: ["ManyArtifacts/ManyArtifacts.app"] },
|
||||||
|
{ zap: [{
|
||||||
|
rmdir: ["~/Library/Caches/ManyArtifacts", "~/Library/Application Support/ManyArtifacts"],
|
||||||
|
trash: "~/Library/Logs/ManyArtifacts.log",
|
||||||
|
}] },
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(cask.artifacts_list(compact: true, uninstall_only: true)).to eq(expected_artifacts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#uninstall_flight_blocks?" do
|
||||||
|
matcher :have_uninstall_flight_blocks do
|
||||||
|
match do |actual|
|
||||||
|
actual.uninstall_flight_blocks? == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns true when there are uninstall_preflight blocks" do
|
||||||
|
cask = Cask::CaskLoader.load("with-uninstall-preflight")
|
||||||
|
expect(cask).to have_uninstall_flight_blocks
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns true when there are uninstall_postflight blocks" do
|
||||||
|
cask = Cask::CaskLoader.load("with-uninstall-postflight")
|
||||||
|
expect(cask).to have_uninstall_flight_blocks
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false when there are only preflight blocks" do
|
||||||
|
cask = Cask::CaskLoader.load("with-preflight")
|
||||||
|
expect(cask).not_to have_uninstall_flight_blocks
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false when there are only postflight blocks" do
|
||||||
|
cask = Cask::CaskLoader.load("with-postflight")
|
||||||
|
expect(cask).not_to have_uninstall_flight_blocks
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false when there are no flight blocks" do
|
||||||
|
cask = Cask::CaskLoader.load("local-caffeine")
|
||||||
|
expect(cask).not_to have_uninstall_flight_blocks
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#to_h" do
|
describe "#to_h" do
|
||||||
let(:expected_json) { (TEST_FIXTURE_DIR/"cask/everything.json").read.strip }
|
let(:expected_json) { (TEST_FIXTURE_DIR/"cask/everything.json").read.strip }
|
||||||
|
|
||||||
|
|||||||
@ -121,4 +121,30 @@ RSpec.describe Cask::Info, :cask do
|
|||||||
Caffeine.app (App)
|
Caffeine.app (App)
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "prints install information for an installed Cask" do
|
||||||
|
cask = Cask::CaskLoader.load("local-transmission")
|
||||||
|
time = 1_720_189_863
|
||||||
|
tab = Cask::Tab.new(loaded_from_api: true, tabfile: TEST_FIXTURE_DIR/"cask_receipt.json", time:)
|
||||||
|
expect(cask).to receive(:installed?).and_return(true)
|
||||||
|
expect(cask).to receive(:installed_version).and_return("2.61")
|
||||||
|
expect(Cask::Tab).to receive(:for_cask).with(cask).and_return(tab)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
described_class.info(cask)
|
||||||
|
end.to output(<<~EOS).to_stdout
|
||||||
|
==> local-transmission: 2.61
|
||||||
|
https://transmissionbt.com/
|
||||||
|
Installed
|
||||||
|
#{HOMEBREW_PREFIX}/Caskroom/local-transmission/2.61 (does not exist)
|
||||||
|
Installed using the formulae.brew.sh API on #{Time.at(time).strftime("%Y-%m-%d at %H:%M:%S")}
|
||||||
|
From: https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/l/local-transmission.rb
|
||||||
|
==> Name
|
||||||
|
Transmission
|
||||||
|
==> Description
|
||||||
|
BitTorrent client
|
||||||
|
==> Artifacts
|
||||||
|
Transmission.app (App)
|
||||||
|
EOS
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
356
Library/Homebrew/test/cask/tab_spec.rb
Normal file
356
Library/Homebrew/test/cask/tab_spec.rb
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "cask"
|
||||||
|
|
||||||
|
RSpec.describe Cask::Tab, :cask do
|
||||||
|
matcher :be_installed_as_dependency do
|
||||||
|
match do |actual|
|
||||||
|
actual.installed_as_dependency == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
matcher :be_installed_on_request do
|
||||||
|
match do |actual|
|
||||||
|
actual.installed_on_request == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
matcher :be_loaded_from_api do
|
||||||
|
match do |actual|
|
||||||
|
actual.loaded_from_api == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
matcher :have_uninstall_flight_blocks do
|
||||||
|
match do |actual|
|
||||||
|
actual.uninstall_flight_blocks == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subject(:tab) do
|
||||||
|
described_class.new(
|
||||||
|
"homebrew_version" => HOMEBREW_VERSION,
|
||||||
|
"loaded_from_api" => false,
|
||||||
|
"uninstall_flight_blocks" => true,
|
||||||
|
"installed_as_dependency" => false,
|
||||||
|
"installed_on_request" => true,
|
||||||
|
"time" => time,
|
||||||
|
"runtime_dependencies" => {
|
||||||
|
"cask" => [{ "full_name" => "bar", "version" => "2.0", "declared_directly" => false }],
|
||||||
|
},
|
||||||
|
"source" => {
|
||||||
|
"path" => CoreCaskTap.instance.path.to_s,
|
||||||
|
"tap" => CoreCaskTap.instance.to_s,
|
||||||
|
"tap_git_head" => "8b79aa759500f0ffdf65a23e12950cbe3bf8fe17",
|
||||||
|
"version" => "1.2.3",
|
||||||
|
},
|
||||||
|
"arch" => Hardware::CPU.arch,
|
||||||
|
"uninstall_artifacts" => [{ "app" => ["Foo.app"] }],
|
||||||
|
"built_on" => DevelopmentTools.build_system_info,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:time) { Time.now.to_i }
|
||||||
|
|
||||||
|
let(:f) { formula { url "foo-1.0" } }
|
||||||
|
let(:f_tab_path) { f.prefix/"INSTALL_RECEIPT.json" }
|
||||||
|
let(:f_tab_content) { (TEST_FIXTURE_DIR/"receipt.json").read }
|
||||||
|
|
||||||
|
specify "defaults" do
|
||||||
|
stub_const("HOMEBREW_VERSION", "4.3.7")
|
||||||
|
|
||||||
|
tab = described_class.empty
|
||||||
|
|
||||||
|
expect(tab.homebrew_version).to eq(HOMEBREW_VERSION)
|
||||||
|
expect(tab).not_to be_installed_as_dependency
|
||||||
|
expect(tab).not_to be_installed_on_request
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
|
expect(tab).not_to have_uninstall_flight_blocks
|
||||||
|
expect(tab.tap).to be_nil
|
||||||
|
expect(tab.time).to be_nil
|
||||||
|
expect(tab.runtime_dependencies).to be_nil
|
||||||
|
expect(tab.source["path"]).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "#runtime_dependencies" do
|
||||||
|
tab = described_class.new
|
||||||
|
expect(tab.runtime_dependencies).to be_nil
|
||||||
|
|
||||||
|
tab.runtime_dependencies = {}
|
||||||
|
expect(tab.runtime_dependencies).not_to be_nil
|
||||||
|
|
||||||
|
tab.runtime_dependencies = {
|
||||||
|
"cask" => [{ "full_name" => "bar", "version" => "2.0", "declared_directly" => false }],
|
||||||
|
}
|
||||||
|
expect(tab.runtime_dependencies).not_to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::runtime_deps_hash" do
|
||||||
|
specify "with no dependencies" do
|
||||||
|
cask = Cask::CaskLoader.load("local-transmission")
|
||||||
|
|
||||||
|
expect(described_class.runtime_deps_hash(cask)).to eq({})
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "with cask dependencies" do
|
||||||
|
cask = Cask::CaskLoader.load("with-depends-on-cask")
|
||||||
|
|
||||||
|
expected_hash = {
|
||||||
|
cask: [
|
||||||
|
{ "full_name"=>"local-transmission", "version"=>"2.61", "declared_directly"=>true },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
expect(described_class.runtime_deps_hash(cask)).to eq(expected_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores macos symbol dependencies" do
|
||||||
|
cask = Cask::CaskLoader.load("with-depends-on-macos-symbol")
|
||||||
|
|
||||||
|
expect(described_class.runtime_deps_hash(cask)).to eq({})
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores macos array dependencies" do
|
||||||
|
cask = Cask::CaskLoader.load("with-depends-on-macos-array")
|
||||||
|
|
||||||
|
expect(described_class.runtime_deps_hash(cask)).to eq({})
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores arch dependencies" do
|
||||||
|
cask = Cask::CaskLoader.load("with-depends-on-arch")
|
||||||
|
|
||||||
|
expect(described_class.runtime_deps_hash(cask)).to eq({})
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "with all types of dependencies" do
|
||||||
|
cask = Cask::CaskLoader.load("with-depends-on-everything")
|
||||||
|
|
||||||
|
unar = instance_double(Formula, full_name: "unar", version: "1.2", revision: 0, pkg_version: "1.2",
|
||||||
|
deps: [], requirements: [])
|
||||||
|
expect(Formulary).to receive(:factory).with("unar").and_return(unar)
|
||||||
|
|
||||||
|
expected_hash = {
|
||||||
|
cask: [
|
||||||
|
{ "full_name"=>"local-caffeine", "version"=>"1.2.3", "declared_directly"=>true },
|
||||||
|
{ "full_name"=>"with-depends-on-cask", "version"=>"1.2.3", "declared_directly"=>true },
|
||||||
|
{ "full_name"=>"local-transmission", "version"=>"2.61", "declared_directly"=>false },
|
||||||
|
],
|
||||||
|
formula: [
|
||||||
|
{ "full_name"=>"unar", "version"=>"1.2", "revision"=>0, "pkg_version"=>"1.2", "declared_directly"=>true },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime_deps_hash = described_class.runtime_deps_hash(cask)
|
||||||
|
tab = described_class.new
|
||||||
|
tab.runtime_dependencies = runtime_deps_hash
|
||||||
|
expect(tab.runtime_dependencies).to eql(expected_hash)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "other attributes" do
|
||||||
|
expect(tab.tap.name).to eq("homebrew/cask")
|
||||||
|
expect(tab.time).to eq(time)
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
|
expect(tab).to have_uninstall_flight_blocks
|
||||||
|
expect(tab).not_to be_installed_as_dependency
|
||||||
|
expect(tab).to be_installed_on_request
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::from_file" do
|
||||||
|
it "parses a cask Tab from a file" do
|
||||||
|
path = Pathname.new("#{TEST_FIXTURE_DIR}/cask_receipt.json")
|
||||||
|
tab = described_class.from_file(path)
|
||||||
|
source_path = "/opt/homebrew/Library/Taps/homebrew/homebrew-cask/Casks/f/foo.rb"
|
||||||
|
runtime_dependencies = {
|
||||||
|
"cask" => [
|
||||||
|
{
|
||||||
|
"full_name" => "bar",
|
||||||
|
"version" => "2.0",
|
||||||
|
"declared_directly" => true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"formula" => [
|
||||||
|
{
|
||||||
|
"full_name" => "baz",
|
||||||
|
"version" => "3.0",
|
||||||
|
"revision" => 0,
|
||||||
|
"pkg_version" => "3.0",
|
||||||
|
"declared_directly" => true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"macos" => {
|
||||||
|
">=" => [
|
||||||
|
"12",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
|
expect(tab).to have_uninstall_flight_blocks
|
||||||
|
expect(tab).not_to be_installed_as_dependency
|
||||||
|
expect(tab).to be_installed_on_request
|
||||||
|
expect(tab.time).to eq(Time.at(1_719_289_256).to_i)
|
||||||
|
expect(tab.runtime_dependencies).to eq(runtime_dependencies)
|
||||||
|
expect(tab.source["path"]).to eq(source_path)
|
||||||
|
expect(tab.version).to eq("1.2.3")
|
||||||
|
expect(tab.tap.name).to eq("homebrew/cask")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::from_file_content" do
|
||||||
|
it "parses a cask Tab from a file" do
|
||||||
|
path = Pathname.new("#{TEST_FIXTURE_DIR}/cask_receipt.json")
|
||||||
|
tab = described_class.from_file_content(path.read, path)
|
||||||
|
source_path = "/opt/homebrew/Library/Taps/homebrew/homebrew-cask/Casks/f/foo.rb"
|
||||||
|
runtime_dependencies = {
|
||||||
|
"cask" => [
|
||||||
|
{
|
||||||
|
"full_name" => "bar",
|
||||||
|
"version" => "2.0",
|
||||||
|
"declared_directly" => true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"formula" => [
|
||||||
|
{
|
||||||
|
"full_name" => "baz",
|
||||||
|
"version" => "3.0",
|
||||||
|
"revision" => 0,
|
||||||
|
"pkg_version" => "3.0",
|
||||||
|
"declared_directly" => true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"macos" => {
|
||||||
|
">=" => [
|
||||||
|
"12",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
|
expect(tab).to have_uninstall_flight_blocks
|
||||||
|
expect(tab).not_to be_installed_as_dependency
|
||||||
|
expect(tab).to be_installed_on_request
|
||||||
|
expect(tab.tabfile).to eq(path)
|
||||||
|
expect(tab.time).to eq(Time.at(1_719_289_256).to_i)
|
||||||
|
expect(tab.runtime_dependencies).to eq(runtime_dependencies)
|
||||||
|
expect(tab.source["path"]).to eq(source_path)
|
||||||
|
expect(tab.version).to eq("1.2.3")
|
||||||
|
expect(tab.tap.name).to eq("homebrew/cask")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises a parse exception message including the Tab filename" do
|
||||||
|
expect { described_class.from_file_content("''", "cask_receipt.json") }.to raise_error(
|
||||||
|
JSON::ParserError,
|
||||||
|
/receipt.json:/,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::create" do
|
||||||
|
it "creates a cask Tab" do
|
||||||
|
cask = Cask::CaskLoader.load("local-caffeine")
|
||||||
|
expected_artifacts = [
|
||||||
|
{ app: ["Caffeine.app"] },
|
||||||
|
{ zap: [{ trash: "#{TEST_FIXTURE_DIR}/cask/caffeine/org.example.caffeine.plist" }] },
|
||||||
|
]
|
||||||
|
|
||||||
|
tab = described_class.create(cask)
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
|
expect(tab).not_to have_uninstall_flight_blocks
|
||||||
|
expect(tab).not_to be_installed_as_dependency
|
||||||
|
expect(tab).not_to be_installed_on_request
|
||||||
|
expect(tab.source).to eq({
|
||||||
|
"path" => "#{CoreCaskTap.instance.path}/Casks/local-caffeine.rb",
|
||||||
|
"tap" => CoreCaskTap.instance.name,
|
||||||
|
"tap_git_head" => nil,
|
||||||
|
"version" => "1.2.3",
|
||||||
|
})
|
||||||
|
expect(tab.runtime_dependencies).to eq({})
|
||||||
|
expect(tab.uninstall_artifacts).to eq(expected_artifacts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::for_cask" do
|
||||||
|
let(:cask) { Cask::CaskLoader.load("local-transmission") }
|
||||||
|
let(:cask_tab_path) { cask.metadata_main_container_path/AbstractTab::FILENAME }
|
||||||
|
let(:cask_tab_content) { (TEST_FIXTURE_DIR/"cask_receipt.json").read }
|
||||||
|
|
||||||
|
it "creates a Tab for a given cask" do
|
||||||
|
tab = described_class.for_cask(cask)
|
||||||
|
expect(tab.source["path"]).to eq(cask.sourcefile_path.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a Tab for a given cask with existing Tab" do
|
||||||
|
cask_tab_path.dirname.mkpath
|
||||||
|
cask_tab_path.write cask_tab_content
|
||||||
|
|
||||||
|
tab = described_class.for_cask(cask)
|
||||||
|
expect(tab.tabfile).to eq(cask_tab_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can create a Tab for a non-existent cask" do
|
||||||
|
cask_tab_path.dirname.mkpath
|
||||||
|
|
||||||
|
tab = described_class.for_cask(cask)
|
||||||
|
expect(tab.tabfile).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "#to_json" do
|
||||||
|
json_tab = described_class.new(JSON.parse(tab.to_json))
|
||||||
|
expect(json_tab.homebrew_version).to eq(tab.homebrew_version)
|
||||||
|
expect(json_tab.loaded_from_api).to eq(tab.loaded_from_api)
|
||||||
|
expect(json_tab.uninstall_flight_blocks).to eq(tab.uninstall_flight_blocks)
|
||||||
|
expect(json_tab.installed_as_dependency).to eq(tab.installed_as_dependency)
|
||||||
|
expect(json_tab.installed_on_request).to eq(tab.installed_on_request)
|
||||||
|
expect(json_tab.time).to eq(tab.time)
|
||||||
|
expect(json_tab.runtime_dependencies).to eq(tab.runtime_dependencies)
|
||||||
|
expect(json_tab.source["path"]).to eq(tab.source["path"])
|
||||||
|
expect(json_tab.tap).to eq(tab.tap)
|
||||||
|
expect(json_tab.source["tap_git_head"]).to eq(tab.source["tap_git_head"])
|
||||||
|
expect(json_tab.version).to eq(tab.version)
|
||||||
|
expect(json_tab.arch).to eq(tab.arch.to_s)
|
||||||
|
expect(json_tab.uninstall_artifacts).to eq(tab.uninstall_artifacts)
|
||||||
|
expect(json_tab.built_on["os"]).to eq(tab.built_on["os"])
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
let(:time_string) { Time.at(1_720_189_863).strftime("%Y-%m-%d at %H:%M:%S") }
|
||||||
|
|
||||||
|
it "returns install information for a Tab with a time that was loaded from the API" do
|
||||||
|
tab = described_class.new(
|
||||||
|
loaded_from_api: true,
|
||||||
|
time: 1_720_189_863,
|
||||||
|
)
|
||||||
|
output = "Installed using the formulae.brew.sh API on #{time_string}"
|
||||||
|
expect(tab.to_s).to eq(output)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns install information for a Tab with a time that was not loaded from the API" do
|
||||||
|
tab = described_class.new(
|
||||||
|
loaded_from_api: false,
|
||||||
|
time: 1_720_189_863,
|
||||||
|
)
|
||||||
|
output = "Installed on #{time_string}"
|
||||||
|
expect(tab.to_s).to eq(output)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns install information for a Tab without a time that was loaded from the API" do
|
||||||
|
tab = described_class.new(
|
||||||
|
loaded_from_api: true,
|
||||||
|
time: nil,
|
||||||
|
)
|
||||||
|
output = "Installed using the formulae.brew.sh API"
|
||||||
|
expect(tab.to_s).to eq(output)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns install information for a Tab without a time that was not loaded from the API" do
|
||||||
|
tab = described_class.new(
|
||||||
|
loaded_from_api: false,
|
||||||
|
time: nil,
|
||||||
|
)
|
||||||
|
output = "Installed"
|
||||||
|
expect(tab.to_s).to eq(output)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -32,7 +32,7 @@ RSpec.describe Homebrew::Cmd::Deps do
|
|||||||
# Mock `Formula#any_version_installed?` by creating the tab in a plausible keg directory
|
# Mock `Formula#any_version_installed?` by creating the tab in a plausible keg directory
|
||||||
keg_dir = HOMEBREW_CELLAR/"installed"/"1.0"
|
keg_dir = HOMEBREW_CELLAR/"installed"/"1.0"
|
||||||
keg_dir.mkpath
|
keg_dir.mkpath
|
||||||
touch keg_dir/Tab::FILENAME
|
touch keg_dir/AbstractTab::FILENAME
|
||||||
|
|
||||||
expect { brew "deps", "baz", "--include-test", "--missing", "--skip-recommended" }
|
expect { brew "deps", "baz", "--include-test", "--missing", "--skip-recommended" }
|
||||||
.to be_a_success
|
.to be_a_success
|
||||||
|
|||||||
@ -33,7 +33,7 @@ RSpec.describe Homebrew::Cmd::Untap do
|
|||||||
keg_path = HOMEBREW_CELLAR/name/"1.2.3"
|
keg_path = HOMEBREW_CELLAR/name/"1.2.3"
|
||||||
keg_path.mkpath
|
keg_path.mkpath
|
||||||
|
|
||||||
tab_path = keg_path/Tab::FILENAME
|
tab_path = keg_path/AbstractTab::FILENAME
|
||||||
tab_path.write <<~JSON
|
tab_path.write <<~JSON
|
||||||
{
|
{
|
||||||
"source": {
|
"source": {
|
||||||
|
|||||||
@ -36,7 +36,7 @@ RSpec.describe Homebrew::Cmd::Uses do
|
|||||||
%w[foo installed].each do |formula_name|
|
%w[foo installed].each do |formula_name|
|
||||||
keg_dir = HOMEBREW_CELLAR/formula_name/"1.0"
|
keg_dir = HOMEBREW_CELLAR/formula_name/"1.0"
|
||||||
keg_dir.mkpath
|
keg_dir.mkpath
|
||||||
touch keg_dir/Tab::FILENAME
|
touch keg_dir/AbstractTab::FILENAME
|
||||||
end
|
end
|
||||||
|
|
||||||
expect { brew "uses", "foo", "--eval-all", "--include-optional", "--missing", "--recursive" }
|
expect { brew "uses", "foo", "--eval-all", "--include-optional", "--missing", "--recursive" }
|
||||||
|
|||||||
@ -264,7 +264,7 @@ RSpec.describe Formula do
|
|||||||
|
|
||||||
prefix = HOMEBREW_CELLAR/f.name/"0.1"
|
prefix = HOMEBREW_CELLAR/f.name/"0.1"
|
||||||
prefix.mkpath
|
prefix.mkpath
|
||||||
FileUtils.touch prefix/Tab::FILENAME
|
FileUtils.touch prefix/AbstractTab::FILENAME
|
||||||
|
|
||||||
expect(f).to have_any_version_installed
|
expect(f).to have_any_version_installed
|
||||||
end
|
end
|
||||||
@ -279,7 +279,7 @@ RSpec.describe Formula do
|
|||||||
|
|
||||||
oldname_prefix.mkpath
|
oldname_prefix.mkpath
|
||||||
oldname_tab = Tab.empty
|
oldname_tab = Tab.empty
|
||||||
oldname_tab.tabfile = oldname_prefix/Tab::FILENAME
|
oldname_tab.tabfile = oldname_prefix/AbstractTab::FILENAME
|
||||||
oldname_tab.write
|
oldname_tab.write
|
||||||
|
|
||||||
expect(f).not_to need_migration
|
expect(f).not_to need_migration
|
||||||
@ -346,7 +346,7 @@ RSpec.describe Formula do
|
|||||||
head_prefix.mkpath
|
head_prefix.mkpath
|
||||||
|
|
||||||
tab = Tab.empty
|
tab = Tab.empty
|
||||||
tab.tabfile = head_prefix/Tab::FILENAME
|
tab.tabfile = head_prefix/AbstractTab::FILENAME
|
||||||
tab.source["versions"] = { "stable" => "1.0" }
|
tab.source["versions"] = { "stable" => "1.0" }
|
||||||
tab.write
|
tab.write
|
||||||
|
|
||||||
@ -378,7 +378,7 @@ RSpec.describe Formula do
|
|||||||
prefix.mkpath
|
prefix.mkpath
|
||||||
|
|
||||||
tab = Tab.empty
|
tab = Tab.empty
|
||||||
tab.tabfile = prefix/Tab::FILENAME
|
tab.tabfile = prefix/AbstractTab::FILENAME
|
||||||
tab.source_modified_time = stamp
|
tab.source_modified_time = stamp
|
||||||
tab.write
|
tab.write
|
||||||
end
|
end
|
||||||
@ -1106,7 +1106,7 @@ RSpec.describe Formula do
|
|||||||
prefix = f.prefix(version)
|
prefix = f.prefix(version)
|
||||||
prefix.mkpath
|
prefix.mkpath
|
||||||
tab = Tab.empty
|
tab = Tab.empty
|
||||||
tab.tabfile = prefix/Tab::FILENAME
|
tab.tabfile = prefix/AbstractTab::FILENAME
|
||||||
tab.source_modified_time = 1
|
tab.source_modified_time = 1
|
||||||
tab.write
|
tab.write
|
||||||
end
|
end
|
||||||
@ -1340,7 +1340,7 @@ RSpec.describe Formula do
|
|||||||
def setup_tab_for_prefix(prefix, options = {})
|
def setup_tab_for_prefix(prefix, options = {})
|
||||||
prefix.mkpath
|
prefix.mkpath
|
||||||
tab = Tab.empty
|
tab = Tab.empty
|
||||||
tab.tabfile = prefix/Tab::FILENAME
|
tab.tabfile = prefix/AbstractTab::FILENAME
|
||||||
tab.source["path"] = options[:path].to_s if options[:path]
|
tab.source["path"] = options[:path].to_s if options[:path]
|
||||||
tab.source["tap"] = options[:tap] if options[:tap]
|
tab.source["tap"] = options[:tap] if options[:tap]
|
||||||
tab.source["versions"] = options[:versions] if options[:versions]
|
tab.source["versions"] = options[:versions] if options[:versions]
|
||||||
|
|||||||
@ -61,7 +61,7 @@ RSpec.describe InstalledDependents do
|
|||||||
def tab_dependencies(keg, deps, homebrew_version: "1.1.6")
|
def tab_dependencies(keg, deps, homebrew_version: "1.1.6")
|
||||||
alter_tab(keg) do |tab|
|
alter_tab(keg) do |tab|
|
||||||
tab.homebrew_version = homebrew_version
|
tab.homebrew_version = homebrew_version
|
||||||
tab.tabfile = keg/Tab::FILENAME
|
tab.tabfile = keg/AbstractTab::FILENAME
|
||||||
tab.runtime_dependencies = deps
|
tab.runtime_dependencies = deps
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
cask "many-artifacts" do
|
||||||
|
version "1.2.3"
|
||||||
|
sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b"
|
||||||
|
|
||||||
|
url "file://#{TEST_FIXTURE_DIR}/cask/ManyArtifacts.zip"
|
||||||
|
homepage "https://brew.sh/many-artifacts"
|
||||||
|
|
||||||
|
app "ManyArtifacts/ManyArtifacts.app"
|
||||||
|
pkg "ManyArtifacts/ManyArtifacts.pkg"
|
||||||
|
|
||||||
|
preflight do
|
||||||
|
# do nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
postflight do
|
||||||
|
# do nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
uninstall_preflight do
|
||||||
|
# do nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
uninstall_postflight do
|
||||||
|
# do nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
uninstall trash: ["#{TEST_TMPDIR}/foo", "#{TEST_TMPDIR}/bar"],
|
||||||
|
rmdir: "#{TEST_TMPDIR}/empty_directory_path"
|
||||||
|
|
||||||
|
zap trash: "~/Library/Logs/ManyArtifacts.log",
|
||||||
|
rmdir: ["~/Library/Caches/ManyArtifacts", "~/Library/Application Support/ManyArtifacts"]
|
||||||
|
end
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
cask "with-depends-on-everything" do
|
||||||
|
version "1.2.3"
|
||||||
|
sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"
|
||||||
|
|
||||||
|
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||||
|
homepage "https://brew.sh/with-depends-on-everything"
|
||||||
|
|
||||||
|
depends_on arch: [:intel, :arm64]
|
||||||
|
depends_on cask: "local-caffeine"
|
||||||
|
depends_on cask: "with-depends-on-cask"
|
||||||
|
depends_on formula: "unar"
|
||||||
|
depends_on macos: ">= :el_capitan"
|
||||||
|
|
||||||
|
app "Caffeine.app"
|
||||||
|
end
|
||||||
53
Library/Homebrew/test/support/fixtures/cask_receipt.json
Normal file
53
Library/Homebrew/test/support/fixtures/cask_receipt.json
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"homebrew_version": "4.3.7",
|
||||||
|
"loaded_from_api": false,
|
||||||
|
"uninstall_flight_blocks": true,
|
||||||
|
"installed_as_dependency": false,
|
||||||
|
"installed_on_request": true,
|
||||||
|
"time": 1719289256,
|
||||||
|
"runtime_dependencies": {
|
||||||
|
"cask": [
|
||||||
|
{
|
||||||
|
"full_name": "bar",
|
||||||
|
"version": "2.0",
|
||||||
|
"declared_directly": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"formula": [
|
||||||
|
{
|
||||||
|
"full_name": "baz",
|
||||||
|
"version": "3.0",
|
||||||
|
"revision": 0,
|
||||||
|
"pkg_version": "3.0",
|
||||||
|
"declared_directly": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"macos": {
|
||||||
|
">=": [
|
||||||
|
"12"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"path": "/opt/homebrew/Library/Taps/homebrew/homebrew-cask/Casks/f/foo.rb",
|
||||||
|
"tap": "homebrew/cask",
|
||||||
|
"tap_git_head": "8b79aa759500f0ffdf65a23e12950cbe3bf8fe17",
|
||||||
|
"version": "1.2.3"
|
||||||
|
},
|
||||||
|
"arch": "arm64",
|
||||||
|
"uninstall_artifacts": [
|
||||||
|
{
|
||||||
|
"app": [
|
||||||
|
"Foo.app"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"built_on": {
|
||||||
|
"os": "Macintosh",
|
||||||
|
"os_version": "macOS 14",
|
||||||
|
"cpu_family": "arm_firestorm_icestorm",
|
||||||
|
"xcode": "15.4",
|
||||||
|
"clt": "15.3.0.0.1.1708646388",
|
||||||
|
"preferred_perl": "5.34"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,6 +10,9 @@
|
|||||||
],
|
],
|
||||||
"built_as_bottle": false,
|
"built_as_bottle": false,
|
||||||
"poured_from_bottle": true,
|
"poured_from_bottle": true,
|
||||||
|
"loaded_from_api": false,
|
||||||
|
"installed_as_dependency": false,
|
||||||
|
"installed_on_request": true,
|
||||||
"changed_files": [
|
"changed_files": [
|
||||||
"INSTALL_RECEIPT.json",
|
"INSTALL_RECEIPT.json",
|
||||||
"bin/foo"
|
"bin/foo"
|
||||||
@ -27,12 +30,12 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "/usr/local/Library/Taps/homebrew/homebrew-core/Formula/foo.rb",
|
"path": "/usr/local/Library/Taps/homebrew/homebrew-core/Formula/foo.rb",
|
||||||
"tap": "homebrew/core",
|
"tap": "homebrew/core",
|
||||||
"spec": "stable",
|
"spec": "stable",
|
||||||
"versions": {
|
"versions": {
|
||||||
"stable": "2.14",
|
"stable": "2.14",
|
||||||
"head": "HEAD-0000000"
|
"head": "HEAD-0000000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -191,7 +191,7 @@ RSpec.shared_context "integration test" do # rubocop:disable RSpec/ContextWordin
|
|||||||
keg.mkpath
|
keg.mkpath
|
||||||
|
|
||||||
tab = Tab.for_name(name)
|
tab = Tab.for_name(name)
|
||||||
tab.tabfile ||= keg/Tab::FILENAME
|
tab.tabfile ||= keg/AbstractTab::FILENAME
|
||||||
tab_attributes.each do |key, value|
|
tab_attributes.each do |key, value|
|
||||||
tab.instance_variable_set(:"@#{key}", value)
|
tab.instance_variable_set(:"@#{key}", value)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -18,20 +18,40 @@ RSpec.describe Tab do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
matcher :be_installed_as_dependency do
|
||||||
|
match do |actual|
|
||||||
|
actual.installed_as_dependency == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
matcher :be_installed_on_request do
|
||||||
|
match do |actual|
|
||||||
|
actual.installed_on_request == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
matcher :be_loaded_from_api do
|
||||||
|
match do |actual|
|
||||||
|
actual.loaded_from_api == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
subject(:tab) do
|
subject(:tab) do
|
||||||
described_class.new(
|
described_class.new(
|
||||||
"homebrew_version" => HOMEBREW_VERSION,
|
"homebrew_version" => HOMEBREW_VERSION,
|
||||||
"used_options" => used_options.as_flags,
|
"used_options" => used_options.as_flags,
|
||||||
"unused_options" => unused_options.as_flags,
|
"unused_options" => unused_options.as_flags,
|
||||||
"built_as_bottle" => false,
|
"built_as_bottle" => false,
|
||||||
"poured_from_bottle" => true,
|
"poured_from_bottle" => true,
|
||||||
"changed_files" => [],
|
"installed_as_dependency" => false,
|
||||||
"time" => time,
|
"installed_on_request" => true,
|
||||||
"source_modified_time" => 0,
|
"changed_files" => [],
|
||||||
"compiler" => "clang",
|
"time" => time,
|
||||||
"stdlib" => "libcxx",
|
"source_modified_time" => 0,
|
||||||
"runtime_dependencies" => [],
|
"compiler" => "clang",
|
||||||
"source" => {
|
"stdlib" => "libcxx",
|
||||||
|
"runtime_dependencies" => [],
|
||||||
|
"source" => {
|
||||||
"tap" => CoreTap.instance.to_s,
|
"tap" => CoreTap.instance.to_s,
|
||||||
"path" => CoreTap.instance.path.to_s,
|
"path" => CoreTap.instance.path.to_s,
|
||||||
"spec" => "stable",
|
"spec" => "stable",
|
||||||
@ -40,8 +60,8 @@ RSpec.describe Tab do
|
|||||||
"head" => "HEAD-1111111",
|
"head" => "HEAD-1111111",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"arch" => Hardware::CPU.arch,
|
"arch" => Hardware::CPU.arch,
|
||||||
"built_on" => DevelopmentTools.build_system_info,
|
"built_on" => DevelopmentTools.build_system_info,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -65,6 +85,9 @@ RSpec.describe Tab do
|
|||||||
expect(tab.changed_files).to be_nil
|
expect(tab.changed_files).to be_nil
|
||||||
expect(tab).not_to be_built_as_bottle
|
expect(tab).not_to be_built_as_bottle
|
||||||
expect(tab).not_to be_poured_from_bottle
|
expect(tab).not_to be_poured_from_bottle
|
||||||
|
expect(tab).not_to be_installed_as_dependency
|
||||||
|
expect(tab).not_to be_installed_on_request
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
expect(tab).to be_stable
|
expect(tab).to be_stable
|
||||||
expect(tab).not_to be_head
|
expect(tab).not_to be_head
|
||||||
expect(tab.tap).to be_nil
|
expect(tab.tap).to be_nil
|
||||||
@ -132,18 +155,69 @@ RSpec.describe Tab do
|
|||||||
expect(tab.runtime_dependencies).not_to be_nil
|
expect(tab.runtime_dependencies).not_to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "::runtime_deps_hash" do
|
describe "::runtime_deps_hash" do
|
||||||
runtime_deps = [Dependency.new("foo")]
|
it "handles older Homebrew versions correctly" do
|
||||||
foo = formula("foo") { url "foo-1.0" }
|
runtime_deps = [Dependency.new("foo")]
|
||||||
stub_formula_loader foo
|
foo = formula("foo") { url "foo-1.0" }
|
||||||
runtime_deps_hash = described_class.runtime_deps_hash(foo, runtime_deps)
|
stub_formula_loader foo
|
||||||
tab = described_class.new
|
runtime_deps_hash = described_class.runtime_deps_hash(foo, runtime_deps)
|
||||||
tab.homebrew_version = "1.1.6"
|
tab = described_class.new
|
||||||
tab.runtime_dependencies = runtime_deps_hash
|
tab.homebrew_version = "1.1.6"
|
||||||
expect(tab.runtime_dependencies).to eql(
|
tab.runtime_dependencies = runtime_deps_hash
|
||||||
[{ "full_name" => "foo", "version" => "1.0", "revision" => 0, "pkg_version" => "1.0",
|
expect(tab.runtime_dependencies).to eql(
|
||||||
"declared_directly" => false }],
|
[{ "full_name" => "foo", "version" => "1.0", "revision" => 0, "pkg_version" => "1.0",
|
||||||
)
|
"declared_directly" => false }],
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "include declared dependencies" do
|
||||||
|
foo = formula("foo") { url "foo-1.0" }
|
||||||
|
stub_formula_loader foo
|
||||||
|
|
||||||
|
runtime_deps = [Dependency.new("foo")]
|
||||||
|
formula = instance_double(Formula, deps: runtime_deps)
|
||||||
|
|
||||||
|
expected_output = [
|
||||||
|
{
|
||||||
|
"full_name" => "foo",
|
||||||
|
"version" => "1.0",
|
||||||
|
"revision" => 0,
|
||||||
|
"pkg_version" => "1.0",
|
||||||
|
"declared_directly" => true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
expect(described_class.runtime_deps_hash(formula, runtime_deps)).to eq(expected_output)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "includes recursive dependencies" do
|
||||||
|
foo = formula("foo") { url "foo-1.0" }
|
||||||
|
bar = formula("bar") { url "bar-2.0" }
|
||||||
|
stub_formula_loader foo
|
||||||
|
stub_formula_loader bar
|
||||||
|
|
||||||
|
# Simulating dependencies formula => foo => bar
|
||||||
|
formula_declared_deps = [Dependency.new("foo")]
|
||||||
|
formula_recursive_deps = [Dependency.new("foo"), Dependency.new("bar")]
|
||||||
|
formula = instance_double(Formula, deps: formula_declared_deps)
|
||||||
|
|
||||||
|
expected_output = [
|
||||||
|
{
|
||||||
|
"full_name" => "foo",
|
||||||
|
"version" => "1.0",
|
||||||
|
"revision" => 0,
|
||||||
|
"pkg_version" => "1.0",
|
||||||
|
"declared_directly" => true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"full_name" => "bar",
|
||||||
|
"version" => "2.0",
|
||||||
|
"revision" => 0,
|
||||||
|
"pkg_version" => "2.0",
|
||||||
|
"declared_directly" => false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
expect(described_class.runtime_deps_hash(formula, formula_recursive_deps)).to eq(expected_output)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "#cxxstdlib" do
|
specify "#cxxstdlib" do
|
||||||
@ -156,10 +230,13 @@ RSpec.describe Tab do
|
|||||||
expect(tab.time).to eq(time)
|
expect(tab.time).to eq(time)
|
||||||
expect(tab).not_to be_built_as_bottle
|
expect(tab).not_to be_built_as_bottle
|
||||||
expect(tab).to be_poured_from_bottle
|
expect(tab).to be_poured_from_bottle
|
||||||
|
expect(tab).not_to be_installed_as_dependency
|
||||||
|
expect(tab).to be_installed_on_request
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "::from_file" do
|
describe "::from_file" do
|
||||||
it "parses a Tab from a file" do
|
it "parses a formula Tab from a file" do
|
||||||
path = Pathname.new("#{TEST_FIXTURE_DIR}/receipt.json")
|
path = Pathname.new("#{TEST_FIXTURE_DIR}/receipt.json")
|
||||||
tab = described_class.from_file(path)
|
tab = described_class.from_file(path)
|
||||||
source_path = "/usr/local/Library/Taps/homebrew/homebrew-core/Formula/foo.rb"
|
source_path = "/usr/local/Library/Taps/homebrew/homebrew-core/Formula/foo.rb"
|
||||||
@ -171,6 +248,9 @@ RSpec.describe Tab do
|
|||||||
expect(tab.changed_files).to eq(changed_files)
|
expect(tab.changed_files).to eq(changed_files)
|
||||||
expect(tab).not_to be_built_as_bottle
|
expect(tab).not_to be_built_as_bottle
|
||||||
expect(tab).to be_poured_from_bottle
|
expect(tab).to be_poured_from_bottle
|
||||||
|
expect(tab).not_to be_installed_as_dependency
|
||||||
|
expect(tab).to be_installed_on_request
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
expect(tab).to be_stable
|
expect(tab).to be_stable
|
||||||
expect(tab).not_to be_head
|
expect(tab).not_to be_head
|
||||||
expect(tab.tap.name).to eq("homebrew/core")
|
expect(tab.tap.name).to eq("homebrew/core")
|
||||||
@ -186,7 +266,7 @@ RSpec.describe Tab do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "::from_file_content" do
|
describe "::from_file_content" do
|
||||||
it "parses a Tab from a file" do
|
it "parses a formula Tab from a file" do
|
||||||
path = Pathname.new("#{TEST_FIXTURE_DIR}/receipt.json")
|
path = Pathname.new("#{TEST_FIXTURE_DIR}/receipt.json")
|
||||||
tab = described_class.from_file_content(path.read, path)
|
tab = described_class.from_file_content(path.read, path)
|
||||||
source_path = "/usr/local/Library/Taps/homebrew/homebrew-core/Formula/foo.rb"
|
source_path = "/usr/local/Library/Taps/homebrew/homebrew-core/Formula/foo.rb"
|
||||||
@ -198,6 +278,9 @@ RSpec.describe Tab do
|
|||||||
expect(tab.changed_files).to eq(changed_files)
|
expect(tab.changed_files).to eq(changed_files)
|
||||||
expect(tab).not_to be_built_as_bottle
|
expect(tab).not_to be_built_as_bottle
|
||||||
expect(tab).to be_poured_from_bottle
|
expect(tab).to be_poured_from_bottle
|
||||||
|
expect(tab).not_to be_installed_as_dependency
|
||||||
|
expect(tab).to be_installed_on_request
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
expect(tab).to be_stable
|
expect(tab).to be_stable
|
||||||
expect(tab).not_to be_head
|
expect(tab).not_to be_head
|
||||||
expect(tab.tap.name).to eq("homebrew/core")
|
expect(tab.tap.name).to eq("homebrew/core")
|
||||||
@ -211,7 +294,7 @@ RSpec.describe Tab do
|
|||||||
expect(tab.source["path"]).to eq(source_path)
|
expect(tab.source["path"]).to eq(source_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can parse an old Tab file" do
|
it "can parse an old formula Tab file" do
|
||||||
path = Pathname.new("#{TEST_FIXTURE_DIR}/receipt_old.json")
|
path = Pathname.new("#{TEST_FIXTURE_DIR}/receipt_old.json")
|
||||||
tab = described_class.from_file_content(path.read, path)
|
tab = described_class.from_file_content(path.read, path)
|
||||||
|
|
||||||
@ -219,6 +302,9 @@ RSpec.describe Tab do
|
|||||||
expect(tab.unused_options.sort).to eq(unused_options.sort)
|
expect(tab.unused_options.sort).to eq(unused_options.sort)
|
||||||
expect(tab).not_to be_built_as_bottle
|
expect(tab).not_to be_built_as_bottle
|
||||||
expect(tab).to be_poured_from_bottle
|
expect(tab).to be_poured_from_bottle
|
||||||
|
expect(tab).not_to be_installed_as_dependency
|
||||||
|
expect(tab).not_to be_installed_on_request
|
||||||
|
expect(tab).not_to be_loaded_from_api
|
||||||
expect(tab).to be_stable
|
expect(tab).to be_stable
|
||||||
expect(tab).not_to be_head
|
expect(tab).not_to be_head
|
||||||
expect(tab.tap.name).to eq("homebrew/core")
|
expect(tab.tap.name).to eq("homebrew/core")
|
||||||
@ -238,7 +324,7 @@ RSpec.describe Tab do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "::create" do
|
describe "::create" do
|
||||||
it "creates a Tab" do
|
it "creates a formula Tab" do
|
||||||
# < 1.1.7 runtime dependencies were wrong so are ignored
|
# < 1.1.7 runtime dependencies were wrong so are ignored
|
||||||
stub_const("HOMEBREW_VERSION", "1.1.7")
|
stub_const("HOMEBREW_VERSION", "1.1.7")
|
||||||
|
|
||||||
@ -277,7 +363,7 @@ RSpec.describe Tab do
|
|||||||
expect(tab.source["path"]).to eq(f.path.to_s)
|
expect(tab.source["path"]).to eq(f.path.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can create a Tab from an alias" do
|
it "can create a formula Tab from an alias" do
|
||||||
alias_path = CoreTap.instance.alias_dir/"bar"
|
alias_path = CoreTap.instance.alias_dir/"bar"
|
||||||
f = formula(alias_path:) { url "foo-1.0" }
|
f = formula(alias_path:) { url "foo-1.0" }
|
||||||
compiler = DevelopmentTools.default_compiler
|
compiler = DevelopmentTools.default_compiler
|
||||||
@ -395,6 +481,62 @@ RSpec.describe Tab do
|
|||||||
expect(json_tab.built_on["os"]).to eq(tab.built_on["os"])
|
expect(json_tab.built_on["os"]).to eq(tab.built_on["os"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
let(:time_string) { Time.at(1_720_189_863).strftime("%Y-%m-%d at %H:%M:%S") }
|
||||||
|
|
||||||
|
it "returns install information for the Tab" do
|
||||||
|
tab = described_class.new(
|
||||||
|
poured_from_bottle: true,
|
||||||
|
loaded_from_api: true,
|
||||||
|
time: 1_720_189_863,
|
||||||
|
used_options: %w[--with-foo --without-bar],
|
||||||
|
)
|
||||||
|
output = "Poured from bottle using the formulae.brew.sh API on #{time_string} " \
|
||||||
|
"with: --with-foo --without-bar"
|
||||||
|
expect(tab.to_s).to eq(output)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "includes 'Poured from bottle' if the formula was installed from a bottle" do
|
||||||
|
tab = described_class.new(poured_from_bottle: true)
|
||||||
|
expect(tab.to_s).to include("Poured from bottle")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "includes 'Built from source' if the formula was not installed from a bottle" do
|
||||||
|
tab = described_class.new(poured_from_bottle: false)
|
||||||
|
expect(tab.to_s).to include("Built from source")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "includes 'using the formulae.brew.sh API' if the formula was installed from the API" do
|
||||||
|
tab = described_class.new(loaded_from_api: true)
|
||||||
|
expect(tab.to_s).to include("using the formulae.brew.sh API")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not include 'using the formulae.brew.sh API' if the formula was not installed from the API" do
|
||||||
|
tab = described_class.new(loaded_from_api: false)
|
||||||
|
expect(tab.to_s).not_to include("using the formulae.brew.sh API")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "includes the time value if specified" do
|
||||||
|
tab = described_class.new(time: 1_720_189_863)
|
||||||
|
expect(tab.to_s).to include("on #{time_string}")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not include the time value if not specified" do
|
||||||
|
tab = described_class.new(time: nil)
|
||||||
|
expect(tab.to_s).not_to match(/on %d+-%d+-%d+ at %d+:%d+:%d+/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "includes options if specified" do
|
||||||
|
tab = described_class.new(used_options: %w[--with-foo --without-bar])
|
||||||
|
expect(tab.to_s).to include("with: --with-foo --without-bar")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "not to include options if not specified" do
|
||||||
|
tab = described_class.new(used_options: [])
|
||||||
|
expect(tab.to_s).not_to include("with: ")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
specify "::remap_deprecated_options" do
|
specify "::remap_deprecated_options" do
|
||||||
deprecated_options = [DeprecatedOption.new("with-foo", "with-foo-new")]
|
deprecated_options = [DeprecatedOption.new("with-foo", "with-foo-new")]
|
||||||
remapped_options = described_class.remap_deprecated_options(deprecated_options, tab.used_options)
|
remapped_options = described_class.remap_deprecated_options(deprecated_options, tab.used_options)
|
||||||
|
|||||||
@ -33,7 +33,7 @@ RSpec.describe Homebrew::Uninstall do
|
|||||||
|
|
||||||
tab = Tab.empty
|
tab = Tab.empty
|
||||||
tab.homebrew_version = "1.1.6"
|
tab.homebrew_version = "1.1.6"
|
||||||
tab.tabfile = dependent_formula.latest_installed_prefix/Tab::FILENAME
|
tab.tabfile = dependent_formula.latest_installed_prefix/AbstractTab::FILENAME
|
||||||
tab.runtime_dependencies = [
|
tab.runtime_dependencies = [
|
||||||
{ "full_name" => "dependency", "version" => "1" },
|
{ "full_name" => "dependency", "version" => "1" },
|
||||||
]
|
]
|
||||||
|
|||||||
@ -106,7 +106,7 @@ module Utils
|
|||||||
|
|
||||||
def load_tab(formula)
|
def load_tab(formula)
|
||||||
keg = Keg.new(formula.prefix)
|
keg = Keg.new(formula.prefix)
|
||||||
tabfile = keg/Tab::FILENAME
|
tabfile = keg/AbstractTab::FILENAME
|
||||||
bottle_json_path = formula.local_bottle_path&.sub(/\.(\d+\.)?tar\.gz$/, ".json")
|
bottle_json_path = formula.local_bottle_path&.sub(/\.(\d+\.)?tar\.gz$/, ".json")
|
||||||
|
|
||||||
if (tab_attributes = formula.bottle_tab_attributes.presence)
|
if (tab_attributes = formula.bottle_tab_attributes.presence)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user