Disable and delete code for 3.5.0

The next planned release will be 3.5.0 so let's fix things up for there.
This commit is contained in:
Mike McQuaid 2022-05-30 14:59:14 +01:00
parent a3fab022ec
commit 1bb44979ee
No known key found for this signature in database
GPG Key ID: 3338A31AFDB1D829
26 changed files with 77 additions and 205 deletions

View File

@ -441,8 +441,8 @@ then
HOMEBREW_OS_VERSION="macOS ${HOMEBREW_MACOS_VERSION}" HOMEBREW_OS_VERSION="macOS ${HOMEBREW_MACOS_VERSION}"
fi fi
# Refuse to run on pre-Yosemite # Refuse to run on pre-El Capitan
if [[ "${HOMEBREW_MACOS_VERSION_NUMERIC}" -lt "101000" ]] if [[ "${HOMEBREW_MACOS_VERSION_NUMERIC}" -lt "101100" ]]
then then
printf "ERROR: Your version of macOS (%s) is too old to run Homebrew!\\n" "${HOMEBREW_MACOS_VERSION}" >&2 printf "ERROR: Your version of macOS (%s) is too old to run Homebrew!\\n" "${HOMEBREW_MACOS_VERSION}" >&2
if [[ "${HOMEBREW_MACOS_VERSION_NUMERIC}" -lt "100700" ]] if [[ "${HOMEBREW_MACOS_VERSION_NUMERIC}" -lt "100700" ]]

View File

@ -153,14 +153,14 @@ module Cask
# @api public # @api public
sig { returns(T.self_type) } sig { returns(T.self_type) }
def before_colon def before_colon
odeprecated "Cask::DSL::Version#before_colon", "Cask::DSL::Version#csv" odisabled "Cask::DSL::Version#before_colon", "Cask::DSL::Version#csv"
version { split(":", 2).first } version { split(":", 2).first }
end end
# @api public # @api public
sig { returns(T.self_type) } sig { returns(T.self_type) }
def after_colon def after_colon
odeprecated "Cask::DSL::Version#after_colon", "Cask::DSL::Version#csv" odisabled "Cask::DSL::Version#after_colon", "Cask::DSL::Version#csv"
version { split(":", 2).second } version { split(":", 2).second }
end end

View File

@ -43,9 +43,6 @@ module Cask
print_stderr: false) print_stderr: false)
case api_check.exit_status case api_check.exit_status
when 5
odebug "This feature requires the macOS 10.10 SDK or higher."
:no_quarantine
when 2 when 2
odebug "Quarantine is available." odebug "Quarantine is available."
:quarantine_available :quarantine_available

View File

@ -10,13 +10,6 @@ struct SwiftErr: TextOutputStream {
} }
} }
// Make sure the user is on macOS 10.10 or newer
guard #available(macOS 10.10, *) else {
print("Homebrew Quarantine: user must be on macOS 10.10 or newer.", to: &SwiftErr.stream)
exit(5)
}
// TODO: tell which arguments have to be provided // TODO: tell which arguments have to be provided
guard CommandLine.arguments.count >= 4 else { guard CommandLine.arguments.count >= 4 else {
exit(2) exit(2)

View File

@ -6,7 +6,7 @@ module Cask
extend Enumerable extend Enumerable
def self.each(&block) def self.each(&block)
odeprecated "`Enumerable` methods on `Cask::Cask`", odisabled "`Enumerable` methods on `Cask::Cask`",
"`Cask::Cask.all` (but avoid looping over all casks, it's slow and insecure)" "`Cask::Cask.all` (but avoid looping over all casks, it's slow and insecure)"
return to_enum unless block return to_enum unless block

View File

@ -5,7 +5,7 @@ class Formula
extend Enumerable extend Enumerable
def self.each(&_block) def self.each(&_block)
odeprecated "`Enumerable` methods on `Formula`", odisabled "`Enumerable` methods on `Formula`",
"`Formula.all` (but avoid looping over all formulae, it's slow and insecure)" "`Formula.all` (but avoid looping over all formulae, it's slow and insecure)"
files.each do |file| files.each do |file|

View File

@ -306,12 +306,6 @@ module Homebrew
tap = CoreTap.instance tap = CoreTap.instance
end end
if f.bottle_disabled?
ofail "Formula has disabled bottle: #{f.full_name}"
puts f.bottle_disable_reason
return
end
return ofail "Formula has no stable version: #{f.full_name}" unless f.stable return ofail "Formula has no stable version: #{f.full_name}" unless f.stable
bottle_tag, rebuild = if local_bottle_json bottle_tag, rebuild = if local_bottle_json
@ -332,7 +326,7 @@ module Homebrew
else else
ohai "Determining #{f.full_name} bottle rebuild..." ohai "Determining #{f.full_name} bottle rebuild..."
FormulaVersions.new(f).formula_at_revision("origin/HEAD") do |upstream_f| FormulaVersions.new(f).formula_at_revision("origin/HEAD") do |upstream_f|
if f.pkg_version == upstream_f.pkg_version && !upstream_f.bottle_unneeded? if f.pkg_version == upstream_f.pkg_version
upstream_f.bottle_specification.rebuild + 1 upstream_f.bottle_specification.rebuild + 1
else else
0 0

View File

@ -24,7 +24,6 @@ module Homebrew
description: "Print what would be done rather than doing it." description: "Print what would be done rather than doing it."
switch "--write-only", switch "--write-only",
description: "Make the expected file modifications without taking any Git actions." description: "Make the expected file modifications without taking any Git actions."
switch "--write", hidden: true
switch "--commit", switch "--commit",
depends_on: "--write-only", depends_on: "--write-only",
description: "When passed with `--write-only`, generate a new commit after writing changes "\ description: "When passed with `--write-only`, generate a new commit after writing changes "\
@ -62,8 +61,6 @@ module Homebrew
def bump_cask_pr def bump_cask_pr
args = bump_cask_pr_args.parse args = bump_cask_pr_args.parse
odisabled "`brew bump-cask-pr --write`", "`brew bump-cask-pr --write-only`" if args.write?
# This will be run by `brew style` later so run it first to not start # This will be run by `brew style` later so run it first to not start
# spamming during normal output. # spamming during normal output.
Homebrew.install_bundler_gems! Homebrew.install_bundler_gems!

View File

@ -100,7 +100,7 @@ module Homebrew
def bump_formula_pr def bump_formula_pr
args = bump_formula_pr_args.parse args = bump_formula_pr_args.parse
odeprecated "`brew bump-formula-pr --write`", "`brew bump-formula-pr --write-only`" if args.write? odisabled "`brew bump-formula-pr --write`", "`brew bump-formula-pr --write-only`" if args.write?
if args.revision.present? && args.tag.nil? && args.version.nil? if args.revision.present? && args.tag.nil? && args.version.nil?
raise UsageError, "`--revision` must be passed with either `--tag` or `--version`!" raise UsageError, "`--revision` must be passed with either `--tag` or `--version`!"

View File

@ -312,7 +312,7 @@ module Homebrew
return false if labels.include?("CI-syntax-only") || labels.include?("CI-no-bottles") return false if labels.include?("CI-syntax-only") || labels.include?("CI-no-bottles")
changed_packages(tap, original_commit).any? do |f| changed_packages(tap, original_commit).any? do |f|
!f.instance_of?(Cask::Cask) && !f.bottle_unneeded? && !f.bottle_disabled? !f.instance_of?(Cask::Cask)
end end
end end

View File

@ -90,7 +90,7 @@ module Homebrew
def pr_upload def pr_upload
args = pr_upload_args.parse args = pr_upload_args.parse
odeprecated "`brew pr-upload --github-org`", "`brew pr-upload` without `--github-org`" if args.github_org odisabled "`brew pr-upload --github-org`", "`brew pr-upload` without `--github-org`" if args.github_org
json_files = Dir["*.bottle.json"] json_files = Dir["*.bottle.json"]
odie "No bottle JSON files found in the current working directory" if json_files.blank? odie "No bottle JSON files found in the current working directory" if json_files.blank?

View File

@ -147,7 +147,6 @@ module Homebrew
formulae.each do |f| formulae.each do |f|
next if f.bottle_specification.tag?(@bottle_tag) next if f.bottle_specification.tag?(@bottle_tag)
next if f.bottle_unneeded?
unbottled_formulae += 1 unbottled_formulae += 1
end end
@ -200,23 +199,13 @@ module Homebrew
end end
end end
if f.bottle_unneeded? || f.bottle_disabled?
reason = if f.bottle_unneeded?
"unneeded"
else
"disabled"
end
puts "#{Tty.bold}#{Tty.red}#{name}#{Tty.reset}: bottle #{reason}" if any_named_args
next
end
if f.bottle_specification.tag?(@bottle_tag, no_older_versions: true) if f.bottle_specification.tag?(@bottle_tag, no_older_versions: true)
puts "#{Tty.bold}#{Tty.green}#{name}#{Tty.reset}: already bottled" if any_named_args puts "#{Tty.bold}#{Tty.green}#{name}#{Tty.reset}: already bottled" if any_named_args
next next
end end
deps = Array(deps_hash[f.name]).reject do |dep| deps = Array(deps_hash[f.name]).reject do |dep|
dep.bottle_specification.tag?(@bottle_tag, no_older_versions: true) || dep.bottle_unneeded? dep.bottle_specification.tag?(@bottle_tag, no_older_versions: true)
end end
if deps.blank? if deps.blank?

View File

@ -1048,8 +1048,6 @@ module Homebrew
"There's no working version of `xattr` on this system." "There's no working version of `xattr` on this system."
when :no_swift when :no_swift
"Swift is not available on this system." "Swift is not available on this system."
when :no_quarantine
"This feature requires the macOS 10.10 SDK or higher."
else else
"Unknown support status" "Unknown support status"
end end

View File

@ -357,9 +357,6 @@ class Formula
end end
delegate [ # rubocop:disable Layout/HashAlignment delegate [ # rubocop:disable Layout/HashAlignment
:bottle_unneeded?,
:bottle_disabled?,
:bottle_disable_reason,
:bottle_defined?, :bottle_defined?,
:bottle_tag?, :bottle_tag?,
:bottled?, :bottled?,
@ -1948,7 +1945,6 @@ class Formula
"bottle" => {}, "bottle" => {},
"keg_only" => keg_only?, "keg_only" => keg_only?,
"keg_only_reason" => keg_only_reason&.to_hash, "keg_only_reason" => keg_only_reason&.to_hash,
"bottle_disabled" => bottle_disabled?,
"options" => [], "options" => [],
"build_dependencies" => dependencies.select(&:build?) "build_dependencies" => dependencies.select(&:build?)
.map(&:name) .map(&:name)

View File

@ -3,9 +3,6 @@
# This file provides definitions for Forwardable#delegate, which is currently not supported by Sorbet. # This file provides definitions for Forwardable#delegate, which is currently not supported by Sorbet.
class Formula class Formula
def bottle_unneeded?; end
def bottle_disabled?; end
def bottle_disable_reason; end
def bottle_defined?; end def bottle_defined?; end
def bottle_tag?(tag = nil); end def bottle_tag?(tag = nil); end
def bottled?(tag = nil); end def bottled?(tag = nil); end

View File

@ -481,27 +481,11 @@ module Homebrew
return unless @new_formula_inclusive return unless @new_formula_inclusive
return unless @core_tap return unless @core_tap
return if formula.bottle_disabled?
return unless formula.bottle_defined? return unless formula.bottle_defined?
new_formula_problem "New formulae in homebrew/core should not have a `bottle do` block" new_formula_problem "New formulae in homebrew/core should not have a `bottle do` block"
end end
def audit_bottle_disabled
return unless formula.bottle_disabled?
if !formula.bottle_disable_reason.valid?
problem "Unrecognized bottle modifier"
elsif @core_tap
if formula.bottle_unneeded?
problem "Formulae in homebrew/core should not use `bottle :unneeded`"
else
problem "Formulae in homebrew/core should not use `bottle :disabled`"
end
end
end
def audit_github_repository_archived def audit_github_repository_archived
return if formula.deprecated? || formula.disabled? return if formula.deprecated? || formula.disabled?

View File

@ -134,9 +134,7 @@ class FormulaInstaller
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def build_bottle? def build_bottle?
return false unless @build_bottle @build_bottle.present?
!formula.bottle_disabled?
end end
sig { params(output_warning: T::Boolean).returns(T::Boolean) } sig { params(output_warning: T::Boolean).returns(T::Boolean) }
@ -146,7 +144,6 @@ class FormulaInstaller
return false if build_from_source? || build_bottle? || interactive? return false if build_from_source? || build_bottle? || interactive?
return false if @cc return false if @cc
return false unless options.empty? return false unless options.empty?
return false if formula.bottle_disabled?
unless formula.pour_bottle? unless formula.pour_bottle?
if output_warning && formula.pour_bottle_check_unsatisfied_reason if output_warning && formula.pour_bottle_check_unsatisfied_reason
@ -249,8 +246,7 @@ class FormulaInstaller
end end
if Homebrew.default_prefix? && if Homebrew.default_prefix? &&
!build_from_source? && !build_bottle? && !formula.head? && !build_from_source? && !build_bottle? && !formula.head? && formula.tap&.core_tap? &&
formula.tap&.core_tap? && !formula.bottle_unneeded? &&
# Integration tests override homebrew-core locations # Integration tests override homebrew-core locations
ENV["HOMEBREW_TEST_TMPDIR"].nil? && ENV["HOMEBREW_TEST_TMPDIR"].nil? &&
!pour_bottle? !pour_bottle?
@ -373,9 +369,7 @@ class FormulaInstaller
lock lock
start_time = Time.now start_time = Time.now
if !formula.bottle_unneeded? && !pour_bottle? && DevelopmentTools.installed? Homebrew::Install.perform_build_from_source_checks if !pour_bottle? && DevelopmentTools.installed?
Homebrew::Install.perform_build_from_source_checks
end
# Warn if a more recent version of this formula is available in the tap. # Warn if a more recent version of this formula is available in the tap.
begin begin
@ -388,7 +382,7 @@ class FormulaInstaller
check_conflicts check_conflicts
raise UnbottledError, [formula] if !pour_bottle? && !formula.bottle_unneeded? && !DevelopmentTools.installed? raise UnbottledError, [formula] if !pour_bottle? && !DevelopmentTools.installed?
unless ignore_deps? unless ignore_deps?
deps = compute_dependencies(use_cache: false) deps = compute_dependencies(use_cache: false)
@ -520,7 +514,7 @@ class FormulaInstaller
deps.map(&:first).map(&:to_formula).reject do |dep_f| deps.map(&:first).map(&:to_formula).reject do |dep_f|
next false unless dep_f.pour_bottle? next false unless dep_f.pour_bottle?
dep_f.bottle_unneeded? || dep_f.bottled? dep_f.bottled?
end end
end end

View File

@ -75,29 +75,4 @@ class KegOnlyReason
end end
end end
# Used to annotate formulae that don't require compiling or cannot build a bottle.
class BottleDisableReason
SUPPORTED_TYPES = [:unneeded, :disable].freeze
def initialize(type, reason)
@type = type
@reason = reason
odisabled "bottle :#{@type}" if valid?
end
def unneeded?
@type == :unneeded
end
def valid?
SUPPORTED_TYPES.include? @type
end
def to_s
return "This formula doesn't require compiling." if unneeded?
@reason
end
end
require "extend/os/formula_support" require "extend/os/formula_support"

View File

@ -21,6 +21,8 @@ module OS
high_sierra: "10.13", high_sierra: "10.13",
sierra: "10.12", sierra: "10.12",
el_capitan: "10.11", el_capitan: "10.11",
# TODO: remove after 3.5.0 has been shipped and this is implicitly
# odisabled and we've cleaned up all tap references.
yosemite: "10.10", yosemite: "10.10",
}.freeze }.freeze

View File

@ -30,8 +30,6 @@ module OS
when "10.13" then "10.1" when "10.13" then "10.1"
when "10.12" then "9.2" when "10.12" then "9.2"
when "10.11" then "8.2.1" when "10.11" then "8.2.1"
when "10.10" then "7.2.1"
when "10.9" then "6.2"
else else
raise "macOS '#{MacOS.version}' is invalid" unless OS::Mac.version.prerelease? raise "macOS '#{MacOS.version}' is invalid" unless OS::Mac.version.prerelease?
@ -343,9 +341,7 @@ module OS
when "10.14" then "1100.0.33.17" when "10.14" then "1100.0.33.17"
when "10.13" then "1000.10.44.2" when "10.13" then "1000.10.44.2"
when "10.12" then "900.0.39.2" when "10.12" then "900.0.39.2"
when "10.11" then "800.0.42.1" else "800.0.42.1"
when "10.10" then "700.1.81"
else "600.0.57"
end end
end end

View File

@ -27,7 +27,7 @@ class SoftwareSpec
attr_reader :name, :full_name, :owner, :build, :resources, :patches, :options, :deprecated_flags, attr_reader :name, :full_name, :owner, :build, :resources, :patches, :options, :deprecated_flags,
:deprecated_options, :dependency_collector, :bottle_specification, :compiler_failures, :deprecated_options, :dependency_collector, :bottle_specification, :compiler_failures,
:uses_from_macos_elements, :bottle_disable_reason :uses_from_macos_elements
def_delegators :@resource, :stage, :fetch, :verify_download_integrity, :source_modified_time, :download_name, def_delegators :@resource, :stage, :fetch, :verify_download_integrity, :source_modified_time, :download_name,
:cached_download, :clear_cache, :checksum, :mirrors, :specs, :using, :version, :mirror, :cached_download, :clear_cache, :checksum, :mirrors, :specs, :using, :version, :mirror,
@ -48,7 +48,6 @@ class SoftwareSpec
@build = BuildOptions.new(Options.create(@flags), options) @build = BuildOptions.new(Options.create(@flags), options)
@compiler_failures = [] @compiler_failures = []
@uses_from_macos_elements = [] @uses_from_macos_elements = []
@bottle_disable_reason = nil
end end
def owner=(owner) def owner=(owner)
@ -79,17 +78,6 @@ class SoftwareSpec
dependency_collector.add(@resource) dependency_collector.add(@resource)
end end
def bottle_unneeded?
return false unless @bottle_disable_reason
@bottle_disable_reason.unneeded?
end
sig { returns(T::Boolean) }
def bottle_disabled?
@bottle_disable_reason ? true : false
end
def bottle_defined? def bottle_defined?
!bottle_specification.collector.tags.empty? !bottle_specification.collector.tags.empty?
end end
@ -103,13 +91,9 @@ class SoftwareSpec
(tag.present? || bottle_specification.compatible_locations? || owner.force_bottle) (tag.present? || bottle_specification.compatible_locations? || owner.force_bottle)
end end
def bottle(disable_type = nil, disable_reason = nil, &block) def bottle(&block)
if disable_type
@bottle_disable_reason = BottleDisableReason.new(disable_type, disable_reason)
else
bottle_specification.instance_eval(&block) bottle_specification.instance_eval(&block)
end end
end
def resource_defined?(name) def resource_defined?(name)
resources.key?(name) resources.key?(name)

View File

@ -11,9 +11,6 @@ require "test/support/fixtures/testball_bottle"
require "test/support/fixtures/failball" require "test/support/fixtures/failball"
describe FormulaInstaller do describe FormulaInstaller do
define_negated_matcher :need_bottle, :be_bottle_unneeded
alias_matcher :have_disabled_bottle, :be_bottle_disabled
matcher :be_poured_from_bottle do matcher :be_poured_from_bottle do
match(&:poured_from_bottle) match(&:poured_from_bottle)
end end
@ -74,22 +71,6 @@ describe FormulaInstaller do
end end
end end
specify "Formula installation with unneeded bottle" do
allow(DevelopmentTools).to receive(:installed?).and_return(false)
formula = Testball.new
allow(formula).to receive(:bottle_unneeded?).and_return(true)
allow(formula).to receive(:bottle_disabled?).and_return(true)
expect(formula).not_to be_bottled
expect(formula).not_to need_bottle
expect(formula).to have_disabled_bottle
temporary_install(formula) do |f|
expect(f).to be_latest_version_installed
end
end
specify "Formula is not poured from bottle when compiler specified" do specify "Formula is not poured from bottle when compiler specified" do
temporary_install(TestballBottle.new, cc: "clang") do |f| temporary_install(TestballBottle.new, cc: "clang") do |f|
tab = Tab.for_formula(f) tab = Tab.for_formula(f)

View File

@ -85,7 +85,6 @@ describe OS::Mac::Version do
specify "#pretty_name" do specify "#pretty_name" do
expect(described_class.new("10.11").pretty_name).to eq("El Capitan") expect(described_class.new("10.11").pretty_name).to eq("El Capitan")
expect(described_class.new("10.14").pretty_name).to eq("Mojave") expect(described_class.new("10.14").pretty_name).to eq("Mojave")
expect(described_class.new("10.10").pretty_name).to eq("Yosemite")
end end
specify "#requires_nehalem_cpu?" do specify "#requires_nehalem_cpu?" do

View File

@ -7,7 +7,7 @@ cask "with-depends-on-macos-comparison" do
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip" url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
homepage "https://brew.sh/with-depends-on-macos-comparison" homepage "https://brew.sh/with-depends-on-macos-comparison"
depends_on macos: ">= :yosemite" depends_on macos: ">= :el_capitan"
app "Caffeine.app" app "Caffeine.app"
end end

View File

@ -49,7 +49,7 @@ if MacOS.version <= :mojave # symbolic name
if MacOS.version <= "10.14" # version string if MacOS.version <= "10.14" # version string
``` ```
The available symbols for macOS versions are: `:yosemite`, `:el_capitan`, `:sierra`, `:high_sierra`, `:mojave`, `:catalina` and `:big_sur`. The corresponding numeric version strings should be given as major releases containing a single dot. The available symbols for macOS versions are: `:el_capitan`, `:sierra`, `:high_sierra`, `:mojave`, `:catalina` and `:big_sur`. The corresponding numeric version strings should be given as major releases containing a single dot.
Note that in the official Homebrew Cask repositories only the symbolic names are allowed. The numeric comparison may only be used for third-party taps. Note that in the official Homebrew Cask repositories only the symbolic names are allowed. The numeric comparison may only be used for third-party taps.
@ -173,6 +173,7 @@ caveats
Note that every stanza that has additional parameters (`:symbols` after a `,`) shall have them on separate lines, one per line, in alphabetical order. An exception is `target:` which typically consists of short lines. Note that every stanza that has additional parameters (`:symbols` after a `,`) shall have them on separate lines, one per line, in alphabetical order. An exception is `target:` which typically consists of short lines.
## Stanzas ## Stanzas
### Required Stanzas ### Required Stanzas
Each of the following stanzas is required for every Cask. Each of the following stanzas is required for every Cask.
@ -234,7 +235,6 @@ Each Cask must declare one or more *artifacts* (i.e. something to install).
| `container type:` | no | Symbol to override container-type autodetect. May be one of: `:air`, `:bz2`, `:cab`, `:dmg`, `:generic_unar`, `:gzip`, `:otf`, `:pkg`, `:rar`, `:seven_zip`, `:sit`, `:tar`, `:ttf`, `:xar`, `:zip`, `:naked`. (Example: [parse.rb](https://github.com/Homebrew/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/parse.rb#L11)) | `container type:` | no | Symbol to override container-type autodetect. May be one of: `:air`, `:bz2`, `:cab`, `:dmg`, `:generic_unar`, `:gzip`, `:otf`, `:pkg`, `:rar`, `:seven_zip`, `:sit`, `:tar`, `:ttf`, `:xar`, `:zip`, `:naked`. (Example: [parse.rb](https://github.com/Homebrew/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/parse.rb#L11))
| `auto_updates` | no | `true`. Assert the Cask artifacts auto-update. Use if `Check for Updates…` or similar is present in app menu, but not if it only opens a webpage and does not do the download and installation for you. | `auto_updates` | no | `true`. Assert the Cask artifacts auto-update. Use if `Check for Updates…` or similar is present in app menu, but not if it only opens a webpage and does not do the download and installation for you.
## Stanza descriptions ## Stanza descriptions
### Stanza: `app` ### Stanza: `app`
@ -406,7 +406,7 @@ end
`conflicts_with` is used to declare conflicts that keep a Cask from installing or working correctly. `conflicts_with` is used to declare conflicts that keep a Cask from installing or working correctly.
#### conflicts_with cask: #### conflicts_with cask
The value should be another Cask token. The value should be another Cask token.
@ -416,7 +416,7 @@ Example use: [`wireshark`](https://github.com/Homebrew/homebrew-cask/blob/903493
conflicts_with cask: "wireshark-chmodbpf" conflicts_with cask: "wireshark-chmodbpf"
``` ```
#### conflicts_with formula: #### conflicts_with formula
Note: `conflicts_with formula:` is a stub and is not yet functional. Note: `conflicts_with formula:` is a stub and is not yet functional.
@ -433,7 +433,7 @@ conflicts_with formula: "macvim"
`depends_on` is used to declare dependencies and requirements for a Cask. `depends_on` is used to declare dependencies and requirements for a Cask.
`depends_on` is not consulted until `install` is attempted. `depends_on` is not consulted until `install` is attempted.
#### depends_on cask: #### depends_on cask
The value should be another Cask token, needed by the current Cask. The value should be another Cask token, needed by the current Cask.
@ -443,7 +443,7 @@ Example use: [`cellery`](https://github.com/Homebrew/homebrew-cask/blob/4002df8f
depends_on cask: "osxfuse" depends_on cask: "osxfuse"
``` ```
#### depends_on formula: #### depends_on formula
The value should name a Homebrew Formula needed by the Cask. The value should name a Homebrew Formula needed by the Cask.
@ -453,7 +453,7 @@ Example use: some distributions are contained in archive formats such as `7z` wh
depends_on formula: "unar" depends_on formula: "unar"
``` ```
#### depends_on macos: #### depends_on macos
##### Requiring an Exact macOS Release ##### Requiring an Exact macOS Release
@ -463,7 +463,6 @@ The available values for macOS releases are:
| symbol | corresponding release | symbol | corresponding release
| -------------------|---------------------- | -------------------|----------------------
| `:yosemite` | `10.10`
| `:el_capitan` | `10.11` | `:el_capitan` | `10.11`
| `:sierra` | `10.12` | `:sierra` | `10.12`
| `:high_sierra` | `10.13` | `:high_sierra` | `10.13`
@ -492,7 +491,7 @@ depends_on macos: ">= :big_sur"
A comparison expression cannot be combined with any other form of `depends_on macos:`. A comparison expression cannot be combined with any other form of `depends_on macos:`.
#### depends_on arch: #### depends_on arch
The value for `depends_on arch:` may be a symbol or an array of symbols, listing the hardware compatibility requirements for a Cask. The requirement is satisfied at install time if any one of multiple `arch:` value matches the users hardware. The value for `depends_on arch:` may be a symbol or an array of symbols, listing the hardware compatibility requirements for a Cask. The requirement is satisfied at install time if any one of multiple `arch:` value matches the users hardware.
@ -531,57 +530,56 @@ depends_on arch: :arm64
#### Dos and Don'ts #### Dos and Don'ts
- **Do** start with an uppercase letter. * **Do** start with an uppercase letter.
```diff ```diff
- desc "sound and music editor" - desc "sound and music editor"
+ desc "Sound and music editor" + desc "Sound and music editor"
``` ```
- **Do** be brief, i.e. use less than 80 characters. * **Do** be brief, i.e. use less than 80 characters.
```diff ```diff
- desc "Sound and music editor which comes with effects, instruments, sounds and all kinds of creative features" - desc "Sound and music editor which comes with effects, instruments, sounds and all kinds of creative features"
+ desc "Sound and music editor" + desc "Sound and music editor"
``` ```
- **Do** describe what the software does or is: * **Do** describe what the software does or is:
```diff ```diff
- desc "Development of musical ideas made easy" - desc "Development of musical ideas made easy"
+ desc "Sound and music editor" + desc "Sound and music editor"
``` ```
- **Do not** include the platform. Casks only work on macOS, so this is redundant information. * **Do not** include the platform. Casks only work on macOS, so this is redundant information.
```diff ```diff
- desc "Sound and music editor for macOS" - desc "Sound and music editor for macOS"
+ desc "Sound and music editor" + desc "Sound and music editor"
``` ```
- **Do not** include the Casks [name](#stanza-name). * **Do not** include the Casks [name](#stanza-name).
```diff ```diff
- desc "Ableton Live is a sound and music editor" - desc "Ableton Live is a sound and music editor"
+ desc "Sound and music editor" + desc "Sound and music editor"
``` ```
- **Do not** include the vendor. This should be added to the Casks [name](#stanza-name) instead. * **Do not** include the vendor. This should be added to the Casks [name](#stanza-name) instead.
```diff ```diff
- desc "Sound and music editor made by Ableton" - desc "Sound and music editor made by Ableton"
+ desc "Sound and music editor" + desc "Sound and music editor"
``` ```
- **Do not** add user pronouns. * **Do not** add user pronouns.
```diff ```diff
- desc "Edit your music files" - desc "Edit your music files"
+ desc "Sound and music editor" + desc "Sound and music editor"
``` ```
- **Do not** use empty marketing jargon. * **Do not** use empty marketing jargon.
```diff ```diff
- desc "Beautiful and powerful modern sound and music editor" - desc "Beautiful and powerful modern sound and music editor"
@ -613,7 +611,7 @@ This stanza must always be accompanied by [`uninstall`](#stanza-uninstall).
The `installer` stanza takes a series of key-value pairs, the first key of which must be `manual:` or `script:`. The `installer` stanza takes a series of key-value pairs, the first key of which must be `manual:` or `script:`.
#### installer manual: #### installer manual
`installer manual:` takes a single string value, describing a GUI installer which must be run by the user at a later time. The path may be absolute, or relative to the Cask. Example (from [nutstore.rb](https://github.com/Homebrew/homebrew-cask/blob/249ec31048591308e63e50f79dae01d2f933cccf/Casks/nutstore.rb#L9)): `installer manual:` takes a single string value, describing a GUI installer which must be run by the user at a later time. The path may be absolute, or relative to the Cask. Example (from [nutstore.rb](https://github.com/Homebrew/homebrew-cask/blob/249ec31048591308e63e50f79dae01d2f933cccf/Casks/nutstore.rb#L9)):
@ -621,7 +619,7 @@ The `installer` stanza takes a series of key-value pairs, the first key of which
installer manual: "Nutstore Installer.app" installer manual: "Nutstore Installer.app"
``` ```
#### installer script: #### installer script
`installer script:` introduces a series of key-value pairs describing a command which will automate completion of the install. **It should never be used for interactive installations.** The form is similar to `uninstall script:`: `installer script:` introduces a series of key-value pairs describing a command which will automate completion of the install. **It should never be used for interactive installations.** The form is similar to `uninstall script:`:
@ -692,7 +690,6 @@ homepage "https://example.org/#{language}"
Examples: [Firefox](https://github.com/Homebrew/homebrew-cask/blob/306b8fbd9502036f1ca742f70c569d8677b62403/Casks/firefox.rb#L4L74), [Battle.net](https://github.com/Homebrew/homebrew-cask/blob/306b8fbd9502036f1ca742f70c569d8677b62403/Casks/battle-net.rb#L5L17) Examples: [Firefox](https://github.com/Homebrew/homebrew-cask/blob/306b8fbd9502036f1ca742f70c569d8677b62403/Casks/firefox.rb#L4L74), [Battle.net](https://github.com/Homebrew/homebrew-cask/blob/306b8fbd9502036f1ca742f70c569d8677b62403/Casks/battle-net.rb#L5L17)
#### Installation #### Installation
To install a cask in a specific language, you can pass the `--language=` option to `brew install`: To install a cask in a specific language, you can pass the `--language=` option to `brew install`:
@ -735,7 +732,6 @@ livecheck do
end end
``` ```
The `header_match` strategy will try parsing a version from the filename (in the `Content-Disposition` header) and the final URL (in the `Location` header). If that doesn't work, a `regex` can be specified, e.g.: The `header_match` strategy will try parsing a version from the filename (in the `Content-Disposition` header) and the final URL (in the `Location` header). If that doesn't work, a `regex` can be specified, e.g.:
```ruby ```ruby
@ -807,7 +803,7 @@ pkg "AlinofTimer.pkg", allow_untrusted: true
Running the macOS command: Running the macOS command:
```bash ```bash
$ installer -showChoicesXML -pkg '/path/to/my.pkg' installer -showChoicesXML -pkg '/path/to/my.pkg'
``` ```
will output an XML which you can use to extract the `choices:` values, as well as their equivalents to the GUI options. will output an XML which you can use to extract the `choices:` values, as well as their equivalents to the GUI options.
@ -815,6 +811,7 @@ will output an XML which you can use to extract the `choices:` values, as well a
See [this pull request for wireshark-chmodbpf](https://github.com/Homebrew/homebrew-cask/pull/26997) and [this one for wine-staging](https://github.com/Homebrew/homebrew-cask/pull/27937) for some examples of the procedure. See [this pull request for wireshark-chmodbpf](https://github.com/Homebrew/homebrew-cask/pull/26997) and [this one for wine-staging](https://github.com/Homebrew/homebrew-cask/pull/27937) for some examples of the procedure.
Example ([wireshark-chmodbpf.rb](https://github.com/Homebrew/homebrew-cask/blob/f95b8a8306b91fe9da7908b842f4a5fa80f7afe0/Casks/wireshark-chmodbpf.rb#L9-L26)): Example ([wireshark-chmodbpf.rb](https://github.com/Homebrew/homebrew-cask/blob/f95b8a8306b91fe9da7908b842f4a5fa80f7afe0/Casks/wireshark-chmodbpf.rb#L9-L26)):
```ruby ```ruby
pkg "Wireshark #{version} Intel 64.pkg", pkg "Wireshark #{version} Intel 64.pkg",
choices: [ choices: [
@ -837,6 +834,7 @@ pkg "Wireshark #{version} Intel 64.pkg",
``` ```
Example ([wine-staging.rb](https://github.com/Homebrew/homebrew-cask/blob/51b65f6a5a25a7f79af4d372e1a0bf1dc3849251/Casks/wine-staging.rb#L11-L18)): Example ([wine-staging.rb](https://github.com/Homebrew/homebrew-cask/blob/51b65f6a5a25a7f79af4d372e1a0bf1dc3849251/Casks/wine-staging.rb#L11-L18)):
```ruby ```ruby
pkg "winehq-staging-#{version}.pkg", pkg "winehq-staging-#{version}.pkg",
choices: [ choices: [
@ -855,7 +853,7 @@ pkg "winehq-staging-#{version}.pkg",
The `sha256` value is usually calculated by the command: The `sha256` value is usually calculated by the command:
```bash ```bash
$ shasum --algorithm 256 <file> shasum --algorithm 256 <file>
``` ```
#### Special Value `:no_check` #### Special Value `:no_check`
@ -886,7 +884,7 @@ The value of `suite` is never an `.app` bundle, but a plain directory.
`pkgutil:` is the easiest and most useful `uninstall` directive. See [Uninstall Key pkgutil:](#uninstall-key-pkgutil). `pkgutil:` is the easiest and most useful `uninstall` directive. See [Uninstall Key pkgutil:](#uninstall-key-pkgutil).
#### `uninstall` Is Required for Casks That Install a pkg or installer manual: #### `uninstall` Is Required for Casks That Install a pkg or installer manual
For most Casks, uninstall actions are determined automatically, and an explicit `uninstall` stanza is not needed. However, a Cask which uses the `pkg` or `installer manual:` stanzas will **not** know how to uninstall correctly unless an `uninstall` stanza is given. For most Casks, uninstall actions are determined automatically, and an explicit `uninstall` stanza is not needed. However, a Cask which uses the `pkg` or `installer manual:` stanzas will **not** know how to uninstall correctly unless an `uninstall` stanza is given.
@ -907,11 +905,11 @@ Since `pkg` installers can do arbitrary things, different techniques are needed
* [`login_item:`](#uninstall-key-login_item) (string or array) - names of login items to remove * [`login_item:`](#uninstall-key-login_item) (string or array) - names of login items to remove
* [`kext:`](#uninstall-key-kext) (string or array) - bundle ids of kexts to unload from the system * [`kext:`](#uninstall-key-kext) (string or array) - bundle ids of kexts to unload from the system
* [`script:`](#uninstall-key-script) (string or hash) - relative path to an uninstall script to be run via sudo; use hash if args are needed * [`script:`](#uninstall-key-script) (string or hash) - relative path to an uninstall script to be run via sudo; use hash if args are needed
- `executable:` - relative path to an uninstall script to be run via sudo (required for hash form) * `executable:` - relative path to an uninstall script to be run via sudo (required for hash form)
- `args:` - array of arguments to the uninstall script * `args:` - array of arguments to the uninstall script
- `input:` - array of lines of input to be sent to `stdin` of the script * `input:` - array of lines of input to be sent to `stdin` of the script
- `must_succeed:` - set to `false` if the script is allowed to fail * `must_succeed:` - set to `false` if the script is allowed to fail
- `sudo:` - set to `true` if the script needs `sudo` * `sudo:` - set to `true` if the script needs `sudo`
* [`pkgutil:`](#uninstall-key-pkgutil) (string, regexp or array of strings and regexps) - strings or regexps matching bundle ids of packages to uninstall using `pkgutil` * [`pkgutil:`](#uninstall-key-pkgutil) (string, regexp or array of strings and regexps) - strings or regexps matching bundle ids of packages to uninstall using `pkgutil`
* [`delete:`](#uninstall-key-delete) (string or array) - single-quoted, absolute paths of files or directory trees to remove. `delete:` should only be used as a last resort. `pkgutil:` is strongly preferred. * [`delete:`](#uninstall-key-delete) (string or array) - single-quoted, absolute paths of files or directory trees to remove. `delete:` should only be used as a last resort. `pkgutil:` is strongly preferred.
* `rmdir:` (string or array) - single-quoted, absolute paths of directories to remove if empty. Works recursively. * `rmdir:` (string or array) - single-quoted, absolute paths of directories to remove if empty. Works recursively.
@ -930,13 +928,13 @@ This is the most useful uninstall key. `pkgutil:` is often sufficient to complet
IDs for the most recently-installed packages can be listed using the command: IDs for the most recently-installed packages can be listed using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_recent_pkg_ids" "$(brew --repository homebrew/cask)/developer/bin/list_recent_pkg_ids"
``` ```
`pkgutil:` also accepts a regular expression match against multiple package IDs. The regular expressions are somewhat nonstandard. To test a `pkgutil:` regular expression against currently-installed packages, use the command: `pkgutil:` also accepts a regular expression match against multiple package IDs. The regular expressions are somewhat nonstandard. To test a `pkgutil:` regular expression against currently-installed packages, use the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_pkg_ids_by_regexp" <regular-expression> "$(brew --repository homebrew/cask)/developer/bin/list_pkg_ids_by_regexp" <regular-expression>
``` ```
#### List Files Associated With a pkg Id #### List Files Associated With a pkg Id
@ -944,7 +942,7 @@ $ "$(brew --repository homebrew/cask)/developer/bin/list_pkg_ids_by_regexp" <reg
Once you know the ID for an installed package, (above), you can list all files on your system associated with that package ID using the macOS command: Once you know the ID for an installed package, (above), you can list all files on your system associated with that package ID using the macOS command:
```bash ```bash
$ pkgutil --files <package.id.goes.here> pkgutil --files <package.id.goes.here>
``` ```
Listing the associated files can help you assess whether the package included any `launchctl` jobs or kernel extensions (kexts). Listing the associated files can help you assess whether the package included any `launchctl` jobs or kernel extensions (kexts).
@ -954,13 +952,13 @@ Listing the associated files can help you assess whether the package included an
IDs for currently loaded `launchctl` jobs can be listed using the command: IDs for currently loaded `launchctl` jobs can be listed using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_loaded_launchjob_ids" "$(brew --repository homebrew/cask)/developer/bin/list_loaded_launchjob_ids"
``` ```
IDs for all installed `launchctl` jobs can be listed using the command: IDs for all installed `launchctl` jobs can be listed using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_installed_launchjob_ids" "$(brew --repository homebrew/cask)/developer/bin/list_installed_launchjob_ids"
``` ```
#### `uninstall` Key `quit:` #### `uninstall` Key `quit:`
@ -968,13 +966,13 @@ $ "$(brew --repository homebrew/cask)/developer/bin/list_installed_launchjob_ids
Bundle IDs for currently running Applications can be listed using the command: Bundle IDs for currently running Applications can be listed using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_running_app_ids" "$(brew --repository homebrew/cask)/developer/bin/list_running_app_ids"
``` ```
Bundle IDs inside an Application bundle on disk can be listed using the command: Bundle IDs inside an Application bundle on disk can be listed using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_ids_in_app" '/path/to/application.app' "$(brew --repository homebrew/cask)/developer/bin/list_ids_in_app" '/path/to/application.app'
``` ```
#### `uninstall` Key `signal:` #### `uninstall` Key `signal:`
@ -1010,7 +1008,7 @@ Unlike `quit:` directives, Unix signals originate from the current user, not fro
Login items associated with an Application bundle on disk can be listed using the command: Login items associated with an Application bundle on disk can be listed using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_login_items_for_app" '/path/to/application.app' "$(brew --repository homebrew/cask)/developer/bin/list_login_items_for_app" '/path/to/application.app'
``` ```
Note that you will likely need to have opened the app at least once for any login items to be present. Note that you will likely need to have opened the app at least once for any login items to be present.
@ -1020,13 +1018,13 @@ Note that you will likely need to have opened the app at least once for any logi
IDs for currently loaded kernel extensions can be listed using the command: IDs for currently loaded kernel extensions can be listed using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_loaded_kext_ids" "$(brew --repository homebrew/cask)/developer/bin/list_loaded_kext_ids"
``` ```
IDs inside a kext bundle you have located on disk can be listed using the command: IDs inside a kext bundle you have located on disk can be listed using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_id_in_kext" '/path/to/name.kext' "$(brew --repository homebrew/cask)/developer/bin/list_id_in_kext" '/path/to/name.kext'
``` ```
#### `uninstall` Key `script:` #### `uninstall` Key `script:`
@ -1065,19 +1063,19 @@ Advanced users may wish to work with a `pkg` file manually, without having the p
A list of files which may be installed from a `pkg` can be extracted using the command: A list of files which may be installed from a `pkg` can be extracted using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_payload_in_pkg" '/path/to/my.pkg' "$(brew --repository homebrew/cask)/developer/bin/list_payload_in_pkg" '/path/to/my.pkg'
``` ```
Candidate application names helpful for determining the name of a Cask may be extracted from a `pkg` file using the command: Candidate application names helpful for determining the name of a Cask may be extracted from a `pkg` file using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_apps_in_pkg" '/path/to/my.pkg' "$(brew --repository homebrew/cask)/developer/bin/list_apps_in_pkg" '/path/to/my.pkg'
``` ```
Candidate package IDs which may be useful in a `pkgutil:` key may be extracted from a `pkg` file using the command: Candidate package IDs which may be useful in a `pkgutil:` key may be extracted from a `pkg` file using the command:
```bash ```bash
$ "$(brew --repository homebrew/cask)/developer/bin/list_ids_in_pkg" '/path/to/my.pkg' "$(brew --repository homebrew/cask)/developer/bin/list_ids_in_pkg" '/path/to/my.pkg'
``` ```
A fully manual method for finding bundle ids in a package file follows: A fully manual method for finding bundle ids in a package file follows:
@ -1127,7 +1125,7 @@ The parameter doesnt mean you should trust the source blindly, but we only ap
Web browsers may obscure the direct `url` download location for a variety of reasons. Homebrew Cask supplies a script which can read extended file attributes to extract the actual source URL for most files downloaded by a browser on macOS. The script usually emits multiple candidate URLs; you may have to test each of them: Web browsers may obscure the direct `url` download location for a variety of reasons. Homebrew Cask supplies a script which can read extended file attributes to extract the actual source URL for most files downloaded by a browser on macOS. The script usually emits multiple candidate URLs; you may have to test each of them:
```bash ```bash
$ $(brew --repository homebrew/cask)/developer/bin/list_url_attributes_on_file <file> $(brew --repository homebrew/cask)/developer/bin/list_url_attributes_on_file <file>
``` ```
#### Subversion URLs #### Subversion URLs
@ -1182,7 +1180,7 @@ However, this typically involves an HTTP round trip to a landing site, which may
##### Writing the Block ##### Writing the Block
Similar to the `preflight`, `postflight`, `uninstall_preflight`, and `uninstall_postflight` blocks, the `url` stanza offers an optional _block syntax_: Similar to the `preflight`, `postflight`, `uninstall_preflight`, and `uninstall_postflight` blocks, the `url` stanza offers an optional *block syntax*:
```rb ```rb
url "https://handbrake.fr/nightly.php" do |page| url "https://handbrake.fr/nightly.php" do |page|
@ -1278,7 +1276,7 @@ Finally, there is `csv` that returns an array of comma-separated values. `csv`,
The `zap` stanza describes a more complete uninstallation of files associated with a Cask. The `zap` procedures will never be performed by default, but only if the user uses `--zap` on `uninstall`: The `zap` stanza describes a more complete uninstallation of files associated with a Cask. The `zap` procedures will never be performed by default, but only if the user uses `--zap` on `uninstall`:
```bash ```bash
$ brew uninstall --zap firefox brew uninstall --zap firefox
``` ```
`zap` stanzas may remove: `zap` stanzas may remove:
@ -1313,8 +1311,6 @@ Manual creation can be facilitated with:
* An uninstaller tool such as [AppCleaner](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/appcleaner.rb). * An uninstaller tool such as [AppCleaner](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/appcleaner.rb).
* Inspecting the usual suspects, i.e. `/Library/{'Application Support',LaunchAgents,LaunchDaemons,Frameworks,Logs,Preferences,PrivilegedHelperTools}` and `~/Library/{'Application Support',Caches,Containers,LaunchAgents,Logs,Preferences,'Saved Application State'}`. * Inspecting the usual suspects, i.e. `/Library/{'Application Support',LaunchAgents,LaunchDaemons,Frameworks,Logs,Preferences,PrivilegedHelperTools}` and `~/Library/{'Application Support',Caches,Containers,LaunchAgents,Logs,Preferences,'Saved Application State'}`.
--- ---
## Token reference ## Token reference
@ -1378,12 +1374,12 @@ Details of software names and brands will inevitably be lost in the conversion t
* If the vendor provides an English localization string, that is preferred. Here are the places it may be found, in order of preference: * If the vendor provides an English localization string, that is preferred. Here are the places it may be found, in order of preference:
- `CFBundleDisplayName` in the main `Info.plist` file of the app bundle * `CFBundleDisplayName` in the main `Info.plist` file of the app bundle
- `CFBundleName` in the main `Info.plist` file of the app bundle * `CFBundleName` in the main `Info.plist` file of the app bundle
- `CFBundleDisplayName` in `InfoPlist.strings` of an `en.lproj` localization directory * `CFBundleDisplayName` in `InfoPlist.strings` of an `en.lproj` localization directory
- `CFBundleName` in `InfoPlist.strings` of an `en.lproj` localization directory * `CFBundleName` in `InfoPlist.strings` of an `en.lproj` localization directory
- `CFBundleDisplayName` in `InfoPlist.strings` of an `English.lproj` localization directory * `CFBundleDisplayName` in `InfoPlist.strings` of an `English.lproj` localization directory
- `CFBundleName` in `InfoPlist.strings` of an `English.lproj` localization directory * `CFBundleName` in `InfoPlist.strings` of an `English.lproj` localization directory
* When there is no vendor localization string, romanize the name by transliteration or decomposition. * When there is no vendor localization string, romanize the name by transliteration or decomposition.

View File

@ -73,7 +73,7 @@ Uninstallation is documented in the [FAQ](FAQ.md).
<a name="1"><sup>1</sup></a> For 32-bit or PPC support see [Tigerbrew](https://github.com/mistydemeo/tigerbrew). <a name="1"><sup>1</sup></a> For 32-bit or PPC support see [Tigerbrew](https://github.com/mistydemeo/tigerbrew).
<a name="2"><sup>2</sup></a> 10.15 or higher is recommended, while 10.1010.14 are supported on a best-effort basis. For 10.410.6 see [Tigerbrew](https://github.com/mistydemeo/tigerbrew). <a name="2"><sup>2</sup></a> 10.15 or higher is recommended, while 10.1110.14 are supported on a best-effort basis. For 10.410.6 see [Tigerbrew](https://github.com/mistydemeo/tigerbrew).
<a name="3"><sup>3</sup></a> Most formulae require a compiler. A handful require a full Xcode installation. You can install Xcode, the CLT, or both; Homebrew supports all three configurations. Downloading Xcode may require an Apple Developer account on older versions of Mac OS X. Sign up for free at [Apple's website](https://developer.apple.com/register/index.action). <a name="3"><sup>3</sup></a> Most formulae require a compiler. A handful require a full Xcode installation. You can install Xcode, the CLT, or both; Homebrew supports all three configurations. Downloading Xcode may require an Apple Developer account on older versions of Mac OS X. Sign up for free at [Apple's website](https://developer.apple.com/register/index.action).