mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Add cask install receipts
This commit is contained in:
parent
5e7765ca60
commit
acd60181c2
@ -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"
|
||||||
|
@ -34,6 +34,12 @@ module Cask
|
|||||||
directives.keys.map(&:to_s).join(", ")
|
directives.keys.map(&:to_s).join(", ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def uninstall?
|
||||||
|
directives.keys.any? do |key|
|
||||||
|
key.to_s.start_with?("uninstall_")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def class_for_dsl_key(dsl_key)
|
def class_for_dsl_key(dsl_key)
|
||||||
|
@ -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,12 @@ module Cask
|
|||||||
languages.any? || artifacts.any?(Artifact::AbstractFlightBlock)
|
languages.any? || artifacts.any?(Artifact::AbstractFlightBlock)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def uninstall_flight_blocks?
|
||||||
|
artifacts.any? do |artifact|
|
||||||
|
artifact.is_a?(Artifact::AbstractFlightBlock) && artifact.uninstall?
|
||||||
|
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 +216,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 +476,25 @@ module Cask
|
|||||||
hash
|
hash
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def artifacts_list(compact: false, uninstall_only: false)
|
||||||
|
artifacts.filter_map do |artifact|
|
||||||
|
case artifact
|
||||||
|
when Artifact::AbstractFlightBlock
|
||||||
|
next if uninstall_only && !artifact.uninstall?
|
||||||
|
|
||||||
|
# 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
|
||||||
|
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 +512,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)
|
||||||
|
@ -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.present? && tabfile.exist?
|
||||||
|
@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
|
||||||
|
120
Library/Homebrew/cask/tab.rb
Normal file
120
Library/Homebrew/cask/tab.rb
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# 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)
|
||||||
|
attributes = generic_attributes(cask).merge({
|
||||||
|
"tabfile" => cask.metadata_main_container_path/FILENAME,
|
||||||
|
"uninstall_flight_blocks" => cask.uninstall_flight_blocks?,
|
||||||
|
"runtime_dependencies" => Tab.runtime_deps_hash(cask, cask.depends_on),
|
||||||
|
"source" => {
|
||||||
|
"path" => cask.sourcefile_path.to_s,
|
||||||
|
"tap" => cask.tap&.name,
|
||||||
|
"tap_git_head" => nil, # Filled in later if possible
|
||||||
|
"version" => cask.version.to_s,
|
||||||
|
},
|
||||||
|
"uninstall_artifacts" => cask.artifacts_list(uninstall_only: true),
|
||||||
|
})
|
||||||
|
|
||||||
|
# We can only get `tap_git_head` if the tap is installed locally
|
||||||
|
attributes["source"]["tap_git_head"] = cask.tap.git_head if cask.tap&.installed?
|
||||||
|
|
||||||
|
new(attributes)
|
||||||
|
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" => nil,
|
||||||
|
"version" => cask.version.to_s,
|
||||||
|
}
|
||||||
|
tab.uninstall_artifacts = cask.artifacts_list(uninstall_only: true)
|
||||||
|
tab.source["tap_git_head"] = cask.tap.git_head if cask.tap&.installed?
|
||||||
|
|
||||||
|
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, depends_on)
|
||||||
|
mappable_types = [:cask, :formula]
|
||||||
|
depends_on.to_h do |type, deps|
|
||||||
|
next [type, deps] unless mappable_types.include? type
|
||||||
|
|
||||||
|
deps = deps.map do |dep|
|
||||||
|
if type == :cask
|
||||||
|
c = CaskLoader.load(dep)
|
||||||
|
{
|
||||||
|
"full_name" => c.full_name,
|
||||||
|
"version" => c.version.to_s,
|
||||||
|
"declared_directly" => cask.depends_on.cask.include?(dep),
|
||||||
|
}
|
||||||
|
elsif type == :formula
|
||||||
|
f = Formulary.factory(dep, warn: false)
|
||||||
|
{
|
||||||
|
"full_name" => f.full_name,
|
||||||
|
"version" => f.version.to_s,
|
||||||
|
"revision" => f.revision,
|
||||||
|
"pkg_version" => f.pkg_version.to_s,
|
||||||
|
"declared_directly" => cask.depends_on.formula.include?(dep),
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dep
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
[type, deps]
|
||||||
|
end
|
||||||
|
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
|
@ -501,7 +501,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
|
||||||
|
@ -636,7 +636,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,41 @@ 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,
|
def self.generic_attributes(formula_or_cask)
|
||||||
:changed_files, :loaded_from_api, :time, :stdlib, :aliases, :arch, :source,
|
{
|
||||||
: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 = {
|
|
||||||
"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" => {
|
|
||||||
"path" => formula.specified_path.to_s,
|
|
||||||
"tap" => formula.tap&.name,
|
|
||||||
"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)
|
|
||||||
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,30 +62,122 @@ 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 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
|
||||||
|
|
||||||
|
# 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 = generic_attributes(formula).merge({
|
||||||
|
"used_options" => build.used_options.as_flags,
|
||||||
|
"unused_options" => build.unused_options.as_flags,
|
||||||
|
"tabfile" => formula.prefix/FILENAME,
|
||||||
|
"built_as_bottle" => build.bottle?,
|
||||||
|
"poured_from_bottle" => false,
|
||||||
|
"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),
|
||||||
|
"source" => {
|
||||||
|
"path" => formula.specified_path.to_s,
|
||||||
|
"tap" => formula.tap&.name,
|
||||||
|
"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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Like {from_file}, but bypass the cache.
|
||||||
|
def self.from_file_content(content, path)
|
||||||
|
tab = super
|
||||||
|
|
||||||
|
tab.source_modified_time ||= 0
|
||||||
|
tab.source ||= {}
|
||||||
|
|
||||||
|
tapped_from = tab.instance_variable_get(:@tapped_from)
|
||||||
|
tab.tap = tapped_from if !tapped_from.nil? && 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?
|
if tab.source["versions"].nil?
|
||||||
attributes["source"]["versions"] = {
|
tab.source["versions"] = {
|
||||||
"stable" => nil,
|
"stable" => nil,
|
||||||
"head" => nil,
|
"head" => nil,
|
||||||
"version_scheme" => 0,
|
"version_scheme" => 0,
|
||||||
@ -131,10 +186,10 @@ class Tab
|
|||||||
|
|
||||||
# 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},
|
||||||
@ -213,37 +268,24 @@ class Tab
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.empty
|
def self.empty
|
||||||
attributes = {
|
tab = super
|
||||||
"homebrew_version" => HOMEBREW_VERSION,
|
|
||||||
"used_options" => [],
|
tab.used_options = []
|
||||||
"unused_options" => [],
|
tab.unused_options = []
|
||||||
"built_as_bottle" => false,
|
tab.built_as_bottle = false
|
||||||
"installed_as_dependency" => false,
|
tab.poured_from_bottle = false
|
||||||
"installed_on_request" => false,
|
tab.source_modified_time = 0
|
||||||
"poured_from_bottle" => false,
|
tab.stdlib = nil
|
||||||
"loaded_from_api" => false,
|
tab.compiler = DevelopmentTools.default_compiler
|
||||||
"time" => nil,
|
tab.aliases = []
|
||||||
"source_modified_time" => 0,
|
tab.source["spec"] = "stable"
|
||||||
"stdlib" => nil,
|
tab.source["versions"] = {
|
||||||
"compiler" => DevelopmentTools.default_compiler,
|
"stable" => nil,
|
||||||
"aliases" => [],
|
"head" => nil,
|
||||||
"runtime_dependencies" => nil,
|
"version_scheme" => 0,
|
||||||
"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
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.runtime_deps_hash(formula, deps)
|
def self.runtime_deps_hash(formula, deps)
|
||||||
@ -259,10 +301,6 @@ class Tab
|
|||||||
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 +345,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 +365,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 +437,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) }
|
||||||
|
@ -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