2025-02-16 22:20:37 -08:00
|
|
|
# typed: strict
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2023-12-28 11:45:18 -08:00
|
|
|
require "attrable"
|
2018-04-25 10:25:00 -04:00
|
|
|
require "cache_store"
|
2021-06-19 00:14:33 +01:00
|
|
|
require "did_you_mean"
|
2015-08-03 13:09:07 +01:00
|
|
|
require "formula_support"
|
2017-05-22 03:23:50 +02:00
|
|
|
require "lock_file"
|
2015-08-03 13:09:07 +01:00
|
|
|
require "formula_pin"
|
|
|
|
require "hardware"
|
2024-07-14 08:49:39 -04:00
|
|
|
require "utils"
|
2016-04-25 17:57:51 +01:00
|
|
|
require "utils/bottles"
|
2024-07-15 10:09:12 -04:00
|
|
|
require "utils/gzip"
|
2024-07-15 21:37:31 -07:00
|
|
|
require "utils/inreplace"
|
2020-03-27 13:04:10 +00:00
|
|
|
require "utils/shebang"
|
2016-09-05 14:45:35 +10:00
|
|
|
require "utils/shell"
|
2024-07-15 09:50:14 -04:00
|
|
|
require "utils/git_repository"
|
2015-08-03 13:09:07 +01:00
|
|
|
require "build_environment"
|
|
|
|
require "build_options"
|
|
|
|
require "formulary"
|
|
|
|
require "software_spec"
|
2025-02-04 16:27:39 +00:00
|
|
|
require "bottle"
|
|
|
|
require "pour_bottle_check"
|
|
|
|
require "head_software_spec"
|
|
|
|
require "bottle_specification"
|
2020-03-16 01:37:49 +05:30
|
|
|
require "livecheck"
|
2020-12-11 23:14:50 +01:00
|
|
|
require "service"
|
2015-08-03 13:09:07 +01:00
|
|
|
require "install_renamed"
|
|
|
|
require "pkg_version"
|
2015-08-23 16:35:51 +08:00
|
|
|
require "keg"
|
2015-11-27 17:58:16 +00:00
|
|
|
require "migrator"
|
2018-03-01 17:34:18 +00:00
|
|
|
require "linkage_checker"
|
2017-04-22 16:31:19 +01:00
|
|
|
require "extend/ENV"
|
2021-02-01 12:47:20 +00:00
|
|
|
require "language/java"
|
2018-01-17 10:43:14 +00:00
|
|
|
require "language/python"
|
2018-03-25 12:43:56 +01:00
|
|
|
require "tab"
|
2018-07-13 14:42:49 +01:00
|
|
|
require "mktemp"
|
2019-11-14 23:31:40 +00:00
|
|
|
require "find"
|
2020-09-11 17:16:03 +01:00
|
|
|
require "utils/spdx"
|
2022-06-23 17:18:58 -04:00
|
|
|
require "extend/on_system"
|
2021-08-06 02:30:44 -04:00
|
|
|
require "api"
|
2023-03-21 19:05:41 -07:00
|
|
|
require "extend/api_hashable"
|
2012-04-05 21:09:24 -05:00
|
|
|
|
2014-12-06 11:26:43 +00:00
|
|
|
# A formula provides instructions and metadata for Homebrew to install a piece
|
|
|
|
# of software. Every Homebrew formula is a {Formula}.
|
|
|
|
# All subclasses of {Formula} (and all Ruby classes) have to be named
|
|
|
|
# `UpperCase` and `not-use-dashes`.
|
|
|
|
# A formula specified in `this-formula.rb` should have a class named
|
|
|
|
# `ThisFormula`. Homebrew does enforce that the name of the file and the class
|
|
|
|
# correspond.
|
|
|
|
# Make sure you check with `brew search` that the name is free!
|
|
|
|
# @abstract
|
2015-08-29 10:56:24 +01:00
|
|
|
# @see SharedEnvExtension
|
|
|
|
# @see Pathname
|
2018-10-18 21:42:43 -04:00
|
|
|
# @see https://www.rubydoc.info/stdlib/fileutils FileUtils
|
2018-02-22 19:46:58 +00:00
|
|
|
# @see https://docs.brew.sh/Formula-Cookbook Formula Cookbook
|
2020-11-03 12:39:26 -05:00
|
|
|
# @see https://rubystyle.guide Ruby Style Guide
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# class Wget < Formula
|
2015-08-29 10:56:24 +01:00
|
|
|
# homepage "https://www.gnu.org/software/wget/"
|
|
|
|
# url "https://ftp.gnu.org/gnu/wget/wget-1.15.tar.gz"
|
|
|
|
# sha256 "52126be8cf1bddd7536886e74c053ad7d0ed2aa89b4b630f76785bac21695fcd"
|
|
|
|
#
|
|
|
|
# def install
|
|
|
|
# system "./configure", "--prefix=#{prefix}"
|
|
|
|
# system "make", "install"
|
|
|
|
# end
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2023-02-21 00:25:02 +00:00
|
|
|
class Formula
|
2012-03-06 19:23:51 -06:00
|
|
|
include FileUtils
|
2020-03-27 13:04:10 +00:00
|
|
|
include Utils::Shebang
|
2016-09-05 14:45:35 +10:00
|
|
|
include Utils::Shell
|
2020-08-02 14:32:31 +02:00
|
|
|
include Context
|
2022-06-29 17:48:21 -04:00
|
|
|
include OnSystem::MacOSAndLinux
|
2022-12-21 05:27:23 -05:00
|
|
|
include Homebrew::Livecheck::Constants
|
2017-06-26 07:30:28 +02:00
|
|
|
extend Forwardable
|
2019-11-05 20:34:06 +00:00
|
|
|
extend Cachable
|
2023-12-28 11:45:18 -08:00
|
|
|
extend Attrable
|
2023-03-21 19:05:41 -07:00
|
|
|
extend APIHashable
|
2024-11-21 18:10:20 -08:00
|
|
|
extend T::Helpers
|
|
|
|
|
|
|
|
abstract!
|
2010-07-04 14:17:03 -07:00
|
|
|
|
2024-04-13 00:23:00 -04:00
|
|
|
SUPPORTED_NETWORK_ACCESS_PHASES = [:build, :test, :postinstall].freeze
|
|
|
|
private_constant :SUPPORTED_NETWORK_ACCESS_PHASES
|
2024-03-06 01:00:39 +01:00
|
|
|
DEFAULT_NETWORK_ACCESS_ALLOWED = true
|
2024-04-13 00:23:00 -04:00
|
|
|
private_constant :DEFAULT_NETWORK_ACCESS_ALLOWED
|
|
|
|
|
2014-12-06 11:26:43 +00:00
|
|
|
# The name of this {Formula}.
|
|
|
|
# e.g. `this-formula`
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(String) }
|
2014-12-06 11:26:43 +00:00
|
|
|
attr_reader :name
|
|
|
|
|
2016-09-15 16:01:18 +01:00
|
|
|
# The path to the alias that was used to identify this {Formula}.
|
|
|
|
# e.g. `/usr/local/Library/Taps/homebrew/homebrew-core/Aliases/another-name-for-this-formula`
|
2024-02-16 21:27:02 +01:00
|
|
|
sig { returns(T.nilable(Pathname)) }
|
2016-09-05 01:11:36 +01:00
|
|
|
attr_reader :alias_path
|
2016-09-03 21:10:44 +01:00
|
|
|
|
2016-09-15 16:01:18 +01:00
|
|
|
# The name of the alias that was used to identify this {Formula}.
|
|
|
|
# e.g. `another-name-for-this-formula`
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.nilable(String)) }
|
2016-09-15 16:01:18 +01:00
|
|
|
attr_reader :alias_name
|
|
|
|
|
2015-05-27 20:30:43 +08:00
|
|
|
# The fully-qualified name of this {Formula}.
|
2023-09-08 14:46:15 -04:00
|
|
|
# For core formulae it's the same as {#name}.
|
2015-05-27 20:30:43 +08:00
|
|
|
# e.g. `homebrew/tap-name/this-formula`
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(String) }
|
2015-05-27 20:30:43 +08:00
|
|
|
attr_reader :full_name
|
|
|
|
|
2016-09-15 16:01:18 +01:00
|
|
|
# The fully-qualified alias referring to this {Formula}.
|
2023-09-08 14:46:15 -04:00
|
|
|
# For core formulae it's the same as {#alias_name}.
|
2016-09-15 16:01:18 +01:00
|
|
|
# e.g. `homebrew/tap-name/another-name-for-this-formula`
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.nilable(String)) }
|
2016-09-15 16:01:18 +01:00
|
|
|
attr_reader :full_alias_name
|
|
|
|
|
2014-12-06 11:26:43 +00:00
|
|
|
# The full path to this {Formula}.
|
2023-09-09 09:02:21 -04:00
|
|
|
# e.g. `/usr/local/Library/Taps/homebrew/homebrew-core/Formula/t/this-formula.rb`
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(Pathname) }
|
2014-12-06 11:26:43 +00:00
|
|
|
attr_reader :path
|
|
|
|
|
2015-12-06 22:16:08 +08:00
|
|
|
# The {Tap} instance associated with this {Formula}.
|
2020-11-05 17:17:03 -05:00
|
|
|
# If it's `nil`, then this formula is loaded from a path or URL.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.nilable(Tap)) }
|
2015-12-06 22:16:08 +08:00
|
|
|
attr_reader :tap
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# The stable (and default) {SoftwareSpec} for this {Formula}.
|
2014-12-26 16:07:32 -05:00
|
|
|
# This contains all the attributes (e.g. URL, checksum) that apply to the
|
|
|
|
# stable version of this formula.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.nilable(SoftwareSpec)) }
|
2014-12-06 11:26:43 +00:00
|
|
|
attr_reader :stable
|
|
|
|
|
|
|
|
# The HEAD {SoftwareSpec} for this {Formula}.
|
2020-11-05 17:17:03 -05:00
|
|
|
# Installed when using `brew install --HEAD`.
|
2014-12-06 11:26:43 +00:00
|
|
|
# This is always installed with the version `HEAD` and taken from the latest
|
|
|
|
# commit in the version control system.
|
|
|
|
# `nil` if there is no HEAD version.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
2014-12-06 11:26:43 +00:00
|
|
|
# @see #stable
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.nilable(SoftwareSpec)) }
|
2014-12-06 11:26:43 +00:00
|
|
|
attr_reader :head
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# The currently active {SoftwareSpec}.
|
2015-01-04 15:33:25 -05:00
|
|
|
# @see #determine_active_spec
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(SoftwareSpec) }
|
2014-12-06 11:26:43 +00:00
|
|
|
attr_reader :active_spec
|
2020-05-12 08:32:27 +01:00
|
|
|
|
2015-01-04 15:33:25 -05:00
|
|
|
protected :active_spec
|
2014-12-06 11:26:43 +00:00
|
|
|
|
2015-07-28 15:10:40 +08:00
|
|
|
# A symbol to indicate currently active {SoftwareSpec}.
|
2020-09-03 10:34:22 +01:00
|
|
|
# It's either :stable or :head
|
2015-07-28 15:10:40 +08:00
|
|
|
# @see #active_spec
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(Symbol) }
|
2015-07-28 15:10:40 +08:00
|
|
|
attr_reader :active_spec_sym
|
|
|
|
|
2016-01-14 19:00:06 +08:00
|
|
|
# most recent modified time for source files
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.nilable(Time)) }
|
2016-01-14 19:00:06 +08:00
|
|
|
attr_reader :source_modified_time
|
|
|
|
|
2014-12-06 11:26:43 +00:00
|
|
|
# Used for creating new Homebrew versions of software without new upstream
|
|
|
|
# versions.
|
2018-10-18 21:42:43 -04:00
|
|
|
# @see .revision=
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(Integer) }
|
2014-12-06 11:26:43 +00:00
|
|
|
attr_reader :revision
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Used to change version schemes for packages.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @see .version_scheme=
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(Integer) }
|
2016-08-11 09:54:47 +02:00
|
|
|
attr_reader :version_scheme
|
|
|
|
|
2014-12-06 11:26:43 +00:00
|
|
|
# The current working directory during builds.
|
|
|
|
# Will only be non-`nil` inside {#install}.
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.nilable(Pathname)) }
|
2014-12-06 11:26:43 +00:00
|
|
|
attr_reader :buildpath
|
|
|
|
|
|
|
|
# The current working directory during tests.
|
2018-10-18 21:42:43 -04:00
|
|
|
# Will only be non-`nil` inside {.test}.
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.nilable(Pathname)) }
|
2014-12-06 11:26:43 +00:00
|
|
|
attr_reader :testpath
|
|
|
|
|
|
|
|
# When installing a bottle (binary package) from a local path this will be
|
|
|
|
# set to the full path to the bottle tarball. If not, it will be `nil`.
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.nilable(Pathname)) }
|
2013-09-25 18:51:30 -05:00
|
|
|
attr_accessor :local_bottle_path
|
2014-12-06 11:26:43 +00:00
|
|
|
|
2016-05-27 01:53:08 -04:00
|
|
|
# When performing a build, test, or other loggable action, indicates which
|
|
|
|
# log file location to use.
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.nilable(String)) }
|
2016-05-27 01:53:08 -04:00
|
|
|
attr_reader :active_log_type
|
|
|
|
|
2023-07-24 14:01:53 -07:00
|
|
|
# The {BuildOptions} or {Tab} for this {Formula}. Lists the arguments passed
|
|
|
|
# and any {.option}s in the {Formula}. Note that these may differ at
|
|
|
|
# different times during the installation of a {Formula}. This is annoying
|
|
|
|
# but the result of state that we're trying to eliminate.
|
|
|
|
sig { returns(T.any(BuildOptions, Tab)) }
|
2021-03-19 03:21:27 +00:00
|
|
|
attr_reader :build
|
2013-09-25 18:51:30 -05:00
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Whether this formula should be considered outdated
|
2016-09-15 16:01:18 +01:00
|
|
|
# if the target of the alias it was installed with has since changed.
|
|
|
|
# Defaults to true.
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2016-09-15 16:01:18 +01:00
|
|
|
attr_accessor :follow_installed_alias
|
2020-05-12 08:32:27 +01:00
|
|
|
|
2016-09-23 18:13:48 +02:00
|
|
|
alias follow_installed_alias? follow_installed_alias
|
2016-09-15 16:01:18 +01:00
|
|
|
|
2020-11-06 11:25:31 +00:00
|
|
|
# Whether or not to force the use of a bottle.
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2020-11-06 11:25:31 +00:00
|
|
|
attr_accessor :force_bottle
|
|
|
|
|
2023-07-24 14:12:47 -07:00
|
|
|
sig {
|
2024-02-16 21:27:02 +01:00
|
|
|
params(name: String, path: Pathname, spec: Symbol, alias_path: T.nilable(Pathname),
|
2023-07-24 14:12:47 -07:00
|
|
|
tap: T.nilable(Tap), force_bottle: T::Boolean).void
|
|
|
|
}
|
2023-04-18 00:22:13 +01:00
|
|
|
def initialize(name, path, spec, alias_path: nil, tap: nil, force_bottle: false)
|
2022-08-24 23:51:29 +01:00
|
|
|
# Only allow instances of subclasses. The base class does not hold any spec information (URLs etc).
|
|
|
|
raise "Do not call `Formula.new' directly without a subclass." unless self.class < Formula
|
|
|
|
|
2022-08-24 23:53:35 +01:00
|
|
|
# Stop any subsequent modification of a formula's definition.
|
|
|
|
# Changes do not propagate to existing instances of formulae.
|
|
|
|
# Now that we have an instance, it's too late to make any changes to the class-level definition.
|
|
|
|
self.class.freeze
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@name = T.let(name, String)
|
|
|
|
@unresolved_path = T.let(path, Pathname)
|
|
|
|
@path = T.let(path.resolved_path, Pathname)
|
|
|
|
@alias_path = T.let(alias_path, T.nilable(Pathname))
|
|
|
|
@alias_name = T.let((File.basename(alias_path) if alias_path), T.nilable(String))
|
|
|
|
@revision = T.let(self.class.revision || 0, Integer)
|
|
|
|
@version_scheme = T.let(self.class.version_scheme || 0, Integer)
|
|
|
|
@head = T.let(nil, T.nilable(SoftwareSpec))
|
|
|
|
@stable = T.let(nil, T.nilable(SoftwareSpec))
|
2013-04-13 17:40:12 -05:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@force_bottle = T.let(force_bottle, T::Boolean)
|
2020-07-26 07:24:14 +02:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@tap = T.let(tap, T.nilable(Tap))
|
2023-04-18 00:22:13 +01:00
|
|
|
@tap ||= if path == Formulary.core_path(name)
|
2016-09-15 16:01:18 +01:00
|
|
|
CoreTap.instance
|
2018-03-29 22:05:02 +02:00
|
|
|
else
|
|
|
|
Tap.from_path(path)
|
2015-05-27 20:30:43 +08:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@full_name = T.let(T.must(full_name_with_optional_tap(name)), String)
|
|
|
|
@full_alias_name = T.let(full_name_with_optional_tap(@alias_name), T.nilable(String))
|
2016-09-15 16:01:18 +01:00
|
|
|
|
2023-06-19 06:07:53 +01:00
|
|
|
self.class.spec_syms.each do |sym|
|
|
|
|
spec_eval sym
|
|
|
|
end
|
2012-04-05 21:09:24 -05:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@active_spec = T.let(determine_active_spec(spec), SoftwareSpec)
|
|
|
|
@active_spec_sym = T.let(head? ? :head : :stable, Symbol)
|
2014-12-26 16:08:12 -05:00
|
|
|
validate_attributes!
|
2025-02-16 22:20:37 -08:00
|
|
|
@build = T.let(active_spec.build, T.any(BuildOptions, Tab))
|
|
|
|
@pin = T.let(FormulaPin.new(self), FormulaPin)
|
|
|
|
@follow_installed_alias = T.let(true, T::Boolean)
|
|
|
|
@prefix_returns_versioned_prefix = T.let(false, T.nilable(T::Boolean))
|
|
|
|
@oldname_locks = T.let([], T::Array[FormulaLock])
|
|
|
|
@on_system_blocks_exist = T.let(false, T::Boolean)
|
2012-04-05 21:09:24 -05:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(spec_sym: Symbol).void }
|
2016-09-24 17:59:14 +02:00
|
|
|
def active_spec=(spec_sym)
|
2015-07-30 16:25:21 +08:00
|
|
|
spec = send(spec_sym)
|
|
|
|
raise FormulaSpecificationError, "#{spec_sym} spec is not available for #{full_name}" unless spec
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2021-03-19 03:21:27 +00:00
|
|
|
old_spec_sym = @active_spec_sym
|
2015-07-30 16:25:21 +08:00
|
|
|
@active_spec = spec
|
|
|
|
@active_spec_sym = spec_sym
|
|
|
|
validate_attributes!
|
|
|
|
@build = active_spec.build
|
2021-03-19 03:21:27 +00:00
|
|
|
|
|
|
|
return if spec_sym == old_spec_sym
|
|
|
|
|
|
|
|
Dependency.clear_cache
|
|
|
|
Requirement.clear_cache
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(build_options: T.any(BuildOptions, Tab)).void }
|
2021-03-19 03:21:27 +00:00
|
|
|
def build=(build_options)
|
|
|
|
old_options = @build
|
|
|
|
@build = build_options
|
|
|
|
|
|
|
|
return if old_options.used_options == build_options.used_options &&
|
|
|
|
old_options.unused_options == build_options.unused_options
|
|
|
|
|
|
|
|
Dependency.clear_cache
|
|
|
|
Requirement.clear_cache
|
2015-07-30 16:25:21 +08:00
|
|
|
end
|
|
|
|
|
2014-12-06 11:27:17 +00:00
|
|
|
private
|
|
|
|
|
2024-06-10 09:31:53 +01:00
|
|
|
# Allow full name logic to be re-used between names, aliases and installed aliases.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(name: T.nilable(String)).returns(T.nilable(String)) }
|
2016-09-24 17:59:14 +02:00
|
|
|
def full_name_with_optional_tap(name)
|
2016-09-15 16:01:18 +01:00
|
|
|
if name.nil? || @tap.nil? || @tap.core_tap?
|
|
|
|
name
|
|
|
|
else
|
|
|
|
"#{@tap}/#{name}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(name: T.any(String, Symbol)).void }
|
2016-09-24 17:59:14 +02:00
|
|
|
def spec_eval(name)
|
2021-10-26 15:03:29 +01:00
|
|
|
spec = self.class.send(name).dup
|
2016-09-23 22:02:23 +02:00
|
|
|
return unless spec.url
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-09-23 22:02:23 +02:00
|
|
|
spec.owner = self
|
2022-08-25 11:04:37 +01:00
|
|
|
add_global_deps_to_spec(spec)
|
2023-12-18 09:34:01 -08:00
|
|
|
instance_variable_set(:"@#{name}", spec)
|
2013-04-13 17:40:12 -05:00
|
|
|
end
|
|
|
|
|
2022-08-25 11:04:37 +01:00
|
|
|
sig { params(spec: SoftwareSpec).void }
|
|
|
|
def add_global_deps_to_spec(spec); end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(requested: T.any(String, Symbol)).returns(SoftwareSpec) }
|
2014-06-19 21:35:47 -05:00
|
|
|
def determine_active_spec(requested)
|
2020-09-03 10:34:22 +01:00
|
|
|
spec = send(requested) || stable || head
|
2024-09-11 10:45:28 -04:00
|
|
|
spec || raise(FormulaSpecificationError, "#{full_name}: formula requires at least a URL")
|
2013-04-13 17:40:12 -05:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { void }
|
2014-12-26 16:08:12 -05:00
|
|
|
def validate_attributes!
|
2024-01-01 17:46:48 +00:00
|
|
|
if name.blank? || name.match?(/\s/) || !Utils.safe_filename?(name)
|
|
|
|
raise FormulaValidationError.new(full_name, :name, name)
|
|
|
|
end
|
2014-12-26 16:08:12 -05:00
|
|
|
|
2014-12-26 16:07:32 -05:00
|
|
|
url = active_spec.url
|
2021-01-07 13:49:05 -08:00
|
|
|
raise FormulaValidationError.new(full_name, :url, url) if url.blank? || url.match?(/\s/)
|
2014-12-26 16:08:12 -05:00
|
|
|
|
|
|
|
val = version.respond_to?(:to_str) ? version.to_str : version
|
2024-01-01 17:46:48 +00:00
|
|
|
return if val.present? && !val.match?(/\s/) && Utils.safe_filename?(val)
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-09-23 22:02:23 +02:00
|
|
|
raise FormulaValidationError.new(full_name, :version, val)
|
2013-04-13 17:40:12 -05:00
|
|
|
end
|
|
|
|
|
2014-12-06 11:27:17 +00:00
|
|
|
public
|
|
|
|
|
2017-03-30 19:39:26 +01:00
|
|
|
# The alias path that was used to install this formula, if it exists.
|
2018-10-18 21:42:43 -04:00
|
|
|
# Can differ from {#alias_path}, which is the alias used to find the formula,
|
2016-09-14 23:18:55 +01:00
|
|
|
# and is specified to this instance.
|
2024-02-16 21:27:02 +01:00
|
|
|
sig { returns(T.nilable(Pathname)) }
|
2016-09-14 23:18:55 +01:00
|
|
|
def installed_alias_path
|
2023-07-24 22:08:17 -07:00
|
|
|
build_tab = build
|
|
|
|
path = build_tab.source["path"] if build_tab.is_a?(Tab)
|
2024-02-16 21:27:02 +01:00
|
|
|
|
2020-11-16 22:18:56 +01:00
|
|
|
return unless path&.match?(%r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases}o)
|
2024-02-16 21:27:02 +01:00
|
|
|
|
|
|
|
path = Pathname(path)
|
|
|
|
return unless path.symlink?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2017-03-30 19:39:26 +01:00
|
|
|
path
|
2016-09-14 23:18:55 +01:00
|
|
|
end
|
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(T.nilable(String)) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def installed_alias_name
|
2024-02-16 21:27:02 +01:00
|
|
|
installed_alias_path&.basename&.to_s
|
2016-09-15 16:01:18 +01:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(String)) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def full_installed_alias_name
|
2016-09-24 17:59:14 +02:00
|
|
|
full_name_with_optional_tap(installed_alias_name)
|
2016-09-15 16:01:18 +01:00
|
|
|
end
|
|
|
|
|
2016-09-14 23:18:55 +01:00
|
|
|
# The path that was specified to find this formula.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(Pathname)) }
|
2016-09-05 22:13:55 +01:00
|
|
|
def specified_path
|
2024-07-03 13:41:52 -04:00
|
|
|
return Homebrew::API::Formula.cached_json_file_path if loaded_from_api?
|
2024-02-16 21:27:02 +01:00
|
|
|
return alias_path if alias_path&.exist?
|
2023-12-01 17:00:15 +00:00
|
|
|
|
|
|
|
return @unresolved_path if @unresolved_path.exist?
|
2021-09-12 02:09:11 -04:00
|
|
|
|
2021-09-21 00:42:40 -04:00
|
|
|
return local_bottle_path if local_bottle_path.presence&.exist?
|
2021-09-12 02:09:11 -04:00
|
|
|
|
2024-02-16 21:27:02 +01:00
|
|
|
alias_path || @unresolved_path
|
2016-09-05 22:13:55 +01:00
|
|
|
end
|
|
|
|
|
2016-09-15 16:01:18 +01:00
|
|
|
# The name specified to find this formula.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(String) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def specified_name
|
|
|
|
alias_name || name
|
|
|
|
end
|
|
|
|
|
|
|
|
# The name (including tap) specified to find this formula.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(String) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def full_specified_name
|
|
|
|
full_alias_name || full_name
|
|
|
|
end
|
|
|
|
|
|
|
|
# The name specified to install this formula.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(String) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def installed_specified_name
|
|
|
|
installed_alias_name || name
|
|
|
|
end
|
|
|
|
|
|
|
|
# The name (including tap) specified to install this formula.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(String) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def full_installed_specified_name
|
|
|
|
full_installed_alias_name || full_name
|
|
|
|
end
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# Is the currently active {SoftwareSpec} a {#stable} build?
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2014-10-29 23:32:38 -05:00
|
|
|
def stable?
|
|
|
|
active_spec == stable
|
|
|
|
end
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# Is the currently active {SoftwareSpec} a {#head} build?
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2014-10-29 23:32:38 -05:00
|
|
|
def head?
|
|
|
|
active_spec == head
|
|
|
|
end
|
|
|
|
|
2020-09-09 13:27:12 +05:30
|
|
|
# Is this formula HEAD-only?
|
2023-07-24 06:55:41 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2020-09-09 13:27:12 +05:30
|
|
|
def head_only?
|
2023-07-24 06:55:41 -07:00
|
|
|
!!head && !stable
|
2020-09-09 13:27:12 +05:30
|
|
|
end
|
|
|
|
|
2024-04-13 00:23:00 -04:00
|
|
|
# Stop RuboCop from erroneously indenting hash target
|
2019-11-28 15:10:50 +00:00
|
|
|
delegate [ # rubocop:disable Layout/HashAlignment
|
2017-06-26 07:30:28 +02:00
|
|
|
:bottle_defined?,
|
2020-12-09 13:53:10 +00:00
|
|
|
:bottle_tag?,
|
2017-06-26 07:30:28 +02:00
|
|
|
:bottled?,
|
|
|
|
:bottle_specification,
|
2018-10-01 10:19:55 +02:00
|
|
|
:downloader,
|
2018-11-02 17:27:24 +00:00
|
|
|
] => :active_spec
|
2015-01-20 22:25:24 -05:00
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# The Bottle object for the currently active {SoftwareSpec}.
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(T.nilable(Bottle)) }
|
2014-03-10 14:56:02 -05:00
|
|
|
def bottle
|
2025-02-16 22:20:37 -08:00
|
|
|
@bottle ||= T.let(Bottle.new(self, bottle_specification), T.nilable(Bottle)) if bottled?
|
2014-03-10 14:56:02 -05:00
|
|
|
end
|
|
|
|
|
2021-07-10 21:17:33 +02:00
|
|
|
# The Bottle object for given tag.
|
2023-04-14 15:33:40 +02:00
|
|
|
sig { params(tag: T.nilable(Utils::Bottles::Tag)).returns(T.nilable(Bottle)) }
|
2021-07-10 21:17:33 +02:00
|
|
|
def bottle_for_tag(tag = nil)
|
2021-08-26 14:36:49 -07:00
|
|
|
Bottle.new(self, bottle_specification, tag) if bottled?(tag)
|
2021-07-10 21:17:33 +02:00
|
|
|
end
|
|
|
|
|
2015-05-19 13:06:06 -04:00
|
|
|
# The description of the software.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method desc
|
2018-10-18 21:42:43 -04:00
|
|
|
# @see .desc=
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate desc: :"self.class"
|
2015-05-19 13:06:06 -04:00
|
|
|
|
2020-06-10 12:29:25 -04:00
|
|
|
# The SPDX ID of the software license.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method license
|
2020-07-16 01:48:25 +01:00
|
|
|
# @see .license=
|
2020-06-10 12:29:25 -04:00
|
|
|
delegate license: :"self.class"
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# The homepage for the software.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method homepage
|
2018-10-18 21:42:43 -04:00
|
|
|
# @see .homepage=
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate homepage: :"self.class"
|
2014-08-08 10:53:00 -05:00
|
|
|
|
2020-03-16 01:37:49 +05:30
|
|
|
# The livecheck specification for the software.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method livecheck
|
2020-03-16 01:37:49 +05:30
|
|
|
# @see .livecheck=
|
|
|
|
delegate livecheck: :"self.class"
|
|
|
|
|
livecheck: clarify livecheckable language
Formulae, casks, and resources have a `#livecheckable?` method that
indicates whether they contain a `livecheck` block. This is intended
to be read as "has a livecheckable?", not "is livecheckable?" (as
livecheck can find versions for some packages/resources without a
`livecheck` block). Unfortunately, correct understanding of this
method's behavior [outside of documentation] relies on historical
knowledge that few people possess, so this is often confusing to
anyone who hasn't been working on livecheck since 2020.
In the olden days, a "livecheckable" was a Ruby file containing a
`livecheck` block (originally a hash) with a filename that
corresponded to a related formula. The `livecheck` blocks in
livecheckable files were integrated into their respective formulae in
August 2020, so [first-party] livecheckables ceased to exist at that
time. From that point forward, we simply referred to these as
`livecheck` blocks.
With that in mind, this clarifies the situation by replacing
"livecheckable" language. This includes renaming `#livecheckable?` to
`#livecheck_defined?`, replacing usage of "livecheckable" as a noun
with "`livecheck` block", replacing "livecheckable" as a boolean with
"livecheck_defined", and replacing incorrect usage of "livecheckable"
as an adjective with "checkable".
2024-11-27 18:20:56 -05:00
|
|
|
# Is a livecheck specification defined for the software?
|
|
|
|
# @!method livecheck_defined?
|
|
|
|
# @see .livecheck_defined?
|
|
|
|
delegate livecheck_defined?: :"self.class"
|
|
|
|
|
2020-03-16 01:37:49 +05:30
|
|
|
# Is a livecheck specification defined for the software?
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method livecheckable?
|
2020-03-16 01:37:49 +05:30
|
|
|
# @see .livecheckable?
|
|
|
|
delegate livecheckable?: :"self.class"
|
|
|
|
|
2020-12-11 23:14:50 +01:00
|
|
|
# Is a service specification defined for the software?
|
|
|
|
# @!method service?
|
|
|
|
# @see .service?
|
|
|
|
delegate service?: :"self.class"
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# The version for the currently active {SoftwareSpec}.
|
|
|
|
# The version is autodetected from the URL and/or tag so only needs to be
|
|
|
|
# declared if it cannot be autodetected correctly.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method version
|
2014-12-26 20:24:12 +00:00
|
|
|
# @see .version
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate version: :active_spec
|
2014-12-26 20:24:12 +00:00
|
|
|
|
2024-04-13 00:23:00 -04:00
|
|
|
# Stop RuboCop from erroneously indenting hash target
|
|
|
|
delegate [ # rubocop:disable Layout/HashAlignment
|
|
|
|
:allow_network_access!,
|
|
|
|
:deny_network_access!,
|
|
|
|
:network_access_allowed?,
|
|
|
|
] => :"self.class"
|
|
|
|
|
2023-05-15 13:58:33 +02:00
|
|
|
# Whether this formula was loaded using the formulae.brew.sh API
|
|
|
|
# @!method loaded_from_api?
|
|
|
|
# @see .loaded_from_api?
|
|
|
|
delegate loaded_from_api?: :"self.class"
|
|
|
|
|
2023-07-24 06:55:41 -07:00
|
|
|
sig { void }
|
2016-07-13 10:11:59 +03:00
|
|
|
def update_head_version
|
|
|
|
return unless head?
|
2023-07-24 14:01:53 -07:00
|
|
|
|
|
|
|
head_spec = T.must(head)
|
|
|
|
return unless head_spec.downloader.is_a?(VCSDownloadStrategy)
|
|
|
|
return unless head_spec.downloader.cached_location.exist?
|
2016-07-13 10:11:59 +03:00
|
|
|
|
2018-06-01 16:43:11 +01:00
|
|
|
path = if ENV["HOMEBREW_ENV"]
|
2022-06-15 05:40:43 +01:00
|
|
|
ENV.fetch("PATH")
|
2018-06-01 16:43:11 +01:00
|
|
|
else
|
2022-06-15 05:40:43 +01:00
|
|
|
PATH.new(ORIGINAL_PATHS)
|
2018-06-01 16:43:11 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
with_env(PATH: path) do
|
2023-07-24 14:01:53 -07:00
|
|
|
head_spec.version.update_commit(head_spec.downloader.last_commit)
|
2018-06-01 16:43:11 +01:00
|
|
|
end
|
2016-07-13 10:11:59 +03:00
|
|
|
end
|
|
|
|
|
2015-07-30 15:53:03 +08:00
|
|
|
# The {PkgVersion} for this formula with {version} and {#revision} information.
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(PkgVersion) }
|
2015-07-30 15:53:03 +08:00
|
|
|
def pkg_version
|
|
|
|
PkgVersion.new(version, revision)
|
|
|
|
end
|
|
|
|
|
2017-01-17 10:43:43 +00:00
|
|
|
# If this is a `@`-versioned formula.
|
2022-08-23 12:42:02 +01:00
|
|
|
sig { returns(T::Boolean) }
|
2017-01-17 10:43:43 +00:00
|
|
|
def versioned_formula?
|
|
|
|
name.include?("@")
|
|
|
|
end
|
|
|
|
|
2023-09-14 21:25:52 -07:00
|
|
|
# Returns any other `@`-versioned formulae names for any formula (including versioned formulae).
|
2022-08-23 12:42:02 +01:00
|
|
|
sig { returns(T::Array[String]) }
|
|
|
|
def versioned_formulae_names
|
2023-07-05 16:28:44 +01:00
|
|
|
versioned_names = if tap
|
2023-09-14 21:25:52 -07:00
|
|
|
name_prefix = name.gsub(/(@[\d.]+)?$/, "")
|
|
|
|
T.must(tap).prefix_to_versioned_formulae_names.fetch(name_prefix, [])
|
2023-07-05 16:28:44 +01:00
|
|
|
elsif path.exist?
|
2022-08-25 15:05:49 +01:00
|
|
|
Pathname.glob(path.to_s.gsub(/(@[\d.]+)?\.rb$/, "@*.rb"))
|
2023-07-05 16:28:44 +01:00
|
|
|
.map { |path| path.basename(".rb").to_s }
|
2023-09-14 21:25:52 -07:00
|
|
|
.sort
|
2023-07-24 14:01:53 -07:00
|
|
|
else
|
|
|
|
raise "Either tap or path is required to list versioned formulae"
|
2023-09-14 21:25:52 -07:00
|
|
|
end
|
2022-08-25 15:05:49 +01:00
|
|
|
|
2023-07-05 16:28:44 +01:00
|
|
|
versioned_names.reject do |versioned_name|
|
|
|
|
versioned_name == name
|
|
|
|
end
|
2022-08-23 12:42:02 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# Returns any `@`-versioned Formula objects for any Formula (including versioned formulae).
|
|
|
|
sig { returns(T::Array[Formula]) }
|
|
|
|
def versioned_formulae
|
2024-02-22 23:29:55 +00:00
|
|
|
versioned_formulae_names.filter_map do |name|
|
2022-08-23 12:42:02 +01:00
|
|
|
Formula[name]
|
2019-10-13 10:03:26 +01:00
|
|
|
rescue FormulaUnavailableError
|
|
|
|
nil
|
2024-02-22 23:29:55 +00:00
|
|
|
end.sort_by(&:version).reverse
|
2018-05-12 14:35:50 -04:00
|
|
|
end
|
|
|
|
|
2024-03-03 01:55:56 -05:00
|
|
|
# Whether this {Formula} is version-synced with other formulae.
|
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
def synced_with_other_formulae?
|
|
|
|
return false if @tap.nil?
|
|
|
|
|
|
|
|
@tap.synced_versions_formulae.any? { |synced_formulae| synced_formulae.include?(name) }
|
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# A named {Resource} for the currently active {SoftwareSpec}.
|
2015-08-29 10:56:24 +01:00
|
|
|
# Additional downloads can be defined as {#resource}s.
|
|
|
|
# {Resource#stage} will create a temporary directory and yield to a block.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# resource("additional_files").stage { bin.install "my/extra/tool" }
|
|
|
|
# ```
|
2024-05-03 21:47:49 +02:00
|
|
|
#
|
|
|
|
# FIXME: This should not actually take a block. All resources should be defined
|
|
|
|
# at the top-level using {Formula.resource} instead
|
|
|
|
# (see https://github.com/Homebrew/brew/issues/17203#issuecomment-2093654431).
|
|
|
|
#
|
|
|
|
# @api public
|
|
|
|
sig {
|
|
|
|
params(name: String, klass: T.class_of(Resource), block: T.nilable(T.proc.bind(Resource).void))
|
|
|
|
.returns(T.nilable(Resource))
|
|
|
|
}
|
2024-09-05 17:19:07 +02:00
|
|
|
def resource(name = T.unsafe(nil), klass = T.unsafe(nil), &block)
|
|
|
|
if klass.nil?
|
|
|
|
active_spec.resource(*name, &block)
|
|
|
|
else
|
2024-09-05 17:20:20 +02:00
|
|
|
active_spec.resource(name, klass, &block)
|
2024-09-05 17:19:07 +02:00
|
|
|
end
|
|
|
|
end
|
2013-08-06 19:52:58 -07:00
|
|
|
|
2023-04-27 04:09:28 +01:00
|
|
|
# Old names for the formula.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2023-07-24 06:55:41 -07:00
|
|
|
sig { returns(T::Array[String]) }
|
2023-04-27 04:09:28 +01:00
|
|
|
def oldnames
|
2025-02-16 22:20:37 -08:00
|
|
|
@oldnames ||= T.let(
|
|
|
|
if (tap = self.tap)
|
|
|
|
Tap.tap_migration_oldnames(tap, name) + tap.formula_reverse_renames.fetch(name, [])
|
|
|
|
else
|
|
|
|
[]
|
|
|
|
end, T.nilable(T::Array[String])
|
|
|
|
)
|
2015-08-09 14:46:07 +03:00
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# All aliases for the formula.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2023-07-24 06:55:41 -07:00
|
|
|
sig { returns(T::Array[String]) }
|
2015-10-07 18:51:02 +08:00
|
|
|
def aliases
|
2025-02-16 22:20:37 -08:00
|
|
|
@aliases ||= T.let(
|
|
|
|
if (tap = self.tap)
|
|
|
|
tap.alias_reverse_table.fetch(full_name, []).map { _1.split("/").fetch(-1) }
|
|
|
|
else
|
|
|
|
[]
|
|
|
|
end, T.nilable(T::Array[String])
|
|
|
|
)
|
2015-10-07 18:51:02 +08:00
|
|
|
end
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# The {Resource}s for the currently active {SoftwareSpec}.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method resources
|
2017-06-26 07:30:28 +02:00
|
|
|
def_delegator :"active_spec.resources", :values, :resources
|
2013-08-06 19:52:58 -07:00
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# The {Dependency}s for the currently active {SoftwareSpec}.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate deps: :active_spec
|
2013-09-21 19:27:24 -05:00
|
|
|
|
2023-06-19 06:03:31 +01:00
|
|
|
# The declared {Dependency}s for the currently active {SoftwareSpec} (i.e. including those provided by macOS)
|
|
|
|
delegate declared_deps: :active_spec
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# The {Requirement}s for the currently active {SoftwareSpec}.
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate requirements: :active_spec
|
2013-09-21 19:27:24 -05:00
|
|
|
|
2014-12-26 16:07:32 -05:00
|
|
|
# The cached download for the currently active {SoftwareSpec}.
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate cached_download: :active_spec
|
2014-02-21 00:41:07 -05:00
|
|
|
|
2014-12-26 16:07:32 -05:00
|
|
|
# Deletes the download for the currently active {SoftwareSpec}.
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate clear_cache: :active_spec
|
2014-02-21 00:41:07 -05:00
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# The list of patches for the currently active {SoftwareSpec}.
|
2017-06-26 07:30:28 +02:00
|
|
|
def_delegator :active_spec, :patches, :patchlist
|
2014-03-13 19:51:23 -05:00
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# The options for the currently active {SoftwareSpec}.
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate options: :active_spec
|
2014-08-10 21:45:24 -05:00
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# The deprecated options for the currently active {SoftwareSpec}.
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate deprecated_options: :active_spec
|
2014-10-16 13:01:05 +01:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# The deprecated option flags for the currently active {SoftwareSpec}.
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate deprecated_flags: :active_spec
|
2014-12-27 14:26:56 -05:00
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# If a named option is defined for the currently active {SoftwareSpec}.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method option_defined?
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate option_defined?: :active_spec
|
2014-07-31 19:37:39 -05:00
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# All the {.fails_with} for the currently active {SoftwareSpec}.
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate compiler_failures: :active_spec
|
2014-08-19 17:14:02 -05:00
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# If this {Formula} is installed.
|
2020-08-21 12:10:44 -07:00
|
|
|
# This is actually just a check for if the {#latest_installed_prefix} directory
|
2014-12-26 20:24:12 +00:00
|
|
|
# exists and is not empty.
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2019-12-03 11:42:09 +00:00
|
|
|
def latest_version_installed?
|
2022-06-15 16:32:14 -04:00
|
|
|
(dir = latest_installed_prefix).directory? && !dir.children.empty?
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
|
|
|
|
2015-07-30 16:01:36 +08:00
|
|
|
# If at least one version of {Formula} is installed.
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2015-07-30 16:01:36 +08:00
|
|
|
def any_version_installed?
|
2024-06-22 13:31:50 -04:00
|
|
|
installed_prefixes.any? { |keg| (keg/AbstractTab::FILENAME).file? }
|
2015-07-30 16:01:36 +08:00
|
|
|
end
|
|
|
|
|
2016-09-15 18:28:42 +01:00
|
|
|
# The link status symlink directory for this {Formula}.
|
2015-01-04 14:25:59 -05:00
|
|
|
# You probably want {#opt_prefix} instead.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(Pathname) }
|
2012-01-14 20:03:30 -06:00
|
|
|
def linked_keg
|
2020-07-09 15:03:49 +01:00
|
|
|
linked_keg = possible_names.map { |name| HOMEBREW_LINKED_KEGS/name }
|
|
|
|
.find(&:directory?)
|
|
|
|
return linked_keg if linked_keg.present?
|
|
|
|
|
2016-09-15 18:28:42 +01:00
|
|
|
HOMEBREW_LINKED_KEGS/name
|
2012-01-14 20:03:30 -06:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(PkgVersion)) }
|
2016-07-22 12:58:24 +03:00
|
|
|
def latest_head_version
|
2024-02-22 23:29:55 +00:00
|
|
|
head_versions = installed_prefixes.filter_map do |pn|
|
2016-07-13 10:11:59 +03:00
|
|
|
pn_pkgversion = PkgVersion.parse(pn.basename.to_s)
|
|
|
|
pn_pkgversion if pn_pkgversion.head?
|
2024-02-22 23:29:55 +00:00
|
|
|
end
|
2016-07-13 10:11:59 +03:00
|
|
|
|
2016-07-22 12:58:24 +03:00
|
|
|
head_versions.max_by do |pn_pkgversion|
|
2024-04-28 03:23:21 +02:00
|
|
|
[Keg.new(prefix(pn_pkgversion)).tab.source_modified_time, pn_pkgversion.revision]
|
2016-07-13 10:11:59 +03:00
|
|
|
end
|
2016-07-22 12:58:24 +03:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(Pathname)) }
|
2016-07-22 12:58:24 +03:00
|
|
|
def latest_head_prefix
|
|
|
|
head_version = latest_head_version
|
|
|
|
prefix(head_version) if head_version
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(version: PkgVersion, fetch_head: T::Boolean).returns(T::Boolean) }
|
2019-11-06 11:49:31 +00:00
|
|
|
def head_version_outdated?(version, fetch_head: false)
|
2016-07-22 12:58:24 +03:00
|
|
|
tab = Tab.for_keg(prefix(version))
|
|
|
|
|
2016-08-11 10:00:39 +02:00
|
|
|
return true if tab.version_scheme < version_scheme
|
2023-07-24 14:01:53 -07:00
|
|
|
return true if stable && tab.stable_version && tab.stable_version < T.must(stable).version
|
2019-11-06 11:49:31 +00:00
|
|
|
return false unless fetch_head
|
|
|
|
return false unless head&.downloader.is_a?(VCSDownloadStrategy)
|
2016-07-22 12:58:24 +03:00
|
|
|
|
2023-07-24 14:01:53 -07:00
|
|
|
downloader = T.must(head).downloader
|
2020-08-02 14:32:31 +02:00
|
|
|
|
|
|
|
with_context quiet: true do
|
|
|
|
downloader.commit_outdated?(version.version.commit)
|
|
|
|
end
|
2016-07-13 10:11:59 +03:00
|
|
|
end
|
|
|
|
|
2020-09-03 10:34:22 +01:00
|
|
|
# The latest prefix for this formula. Checks for {#head} and then {#stable}'s {#prefix}
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(Pathname) }
|
2020-08-21 12:10:44 -07:00
|
|
|
def latest_installed_prefix
|
2016-07-22 12:40:16 +03:00
|
|
|
if head && (head_version = latest_head_version) && !head_version_outdated?(head_version)
|
2025-02-16 22:20:37 -08:00
|
|
|
T.must(latest_head_prefix)
|
2023-07-24 14:01:53 -07:00
|
|
|
elsif stable && (stable_prefix = prefix(PkgVersion.new(T.must(stable).version, revision))).directory?
|
2015-07-30 15:58:20 +08:00
|
|
|
stable_prefix
|
2010-09-24 11:55:21 -05:00
|
|
|
else
|
|
|
|
prefix
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-03-05 20:51:37 -08:00
|
|
|
# The directory in the cellar that the formula is installed to.
|
2023-09-09 09:02:21 -04:00
|
|
|
# This directory points to {#opt_prefix} if it exists and if {#prefix} is not
|
2016-12-31 16:38:05 +00:00
|
|
|
# called from within the same formula's {#install} or {#post_install} methods.
|
|
|
|
# Otherwise, return the full path to the formula's versioned cellar.
|
2024-12-05 14:01:37 +00:00
|
|
|
sig { params(version: T.any(String, PkgVersion)).returns(Pathname) }
|
2023-03-07 23:42:00 +00:00
|
|
|
def prefix(version = pkg_version)
|
|
|
|
versioned_prefix = versioned_prefix(version)
|
2024-12-05 14:01:37 +00:00
|
|
|
version = PkgVersion.parse(version) if version.is_a?(String)
|
2023-03-07 23:42:00 +00:00
|
|
|
if !@prefix_returns_versioned_prefix && version == pkg_version &&
|
2017-01-06 08:50:35 +00:00
|
|
|
versioned_prefix.directory? && Keg.new(versioned_prefix).optlinked?
|
2016-12-31 16:38:05 +00:00
|
|
|
opt_prefix
|
|
|
|
else
|
2017-01-06 08:50:35 +00:00
|
|
|
versioned_prefix
|
2016-12-31 16:38:05 +00:00
|
|
|
end
|
2010-02-19 21:55:17 -08:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
2016-11-01 03:53:20 +03:00
|
|
|
# Is the formula linked?
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2016-11-01 03:53:20 +03:00
|
|
|
def linked?
|
|
|
|
linked_keg.symlink?
|
|
|
|
end
|
|
|
|
|
2018-10-18 21:42:43 -04:00
|
|
|
# Is the formula linked to `opt`?
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2016-11-01 03:53:20 +03:00
|
|
|
def optlinked?
|
|
|
|
opt_prefix.symlink?
|
|
|
|
end
|
|
|
|
|
2018-10-18 21:42:43 -04:00
|
|
|
# If a formula's linked keg points to the prefix.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(version: T.any(String, PkgVersion)).returns(T::Boolean) }
|
2023-03-07 23:42:00 +00:00
|
|
|
def prefix_linked?(version = pkg_version)
|
2016-11-01 03:53:20 +03:00
|
|
|
return false unless linked?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2023-03-07 23:42:00 +00:00
|
|
|
linked_keg.resolved_path == versioned_prefix(version)
|
2016-11-01 03:53:20 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
# {PkgVersion} of the linked keg for the formula.
|
2021-01-09 13:34:17 +11:00
|
|
|
sig { returns(T.nilable(PkgVersion)) }
|
2016-11-01 03:53:20 +03:00
|
|
|
def linked_version
|
|
|
|
return unless linked?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-11-01 03:53:20 +03:00
|
|
|
Keg.for(linked_keg).version
|
|
|
|
end
|
|
|
|
|
2014-03-05 20:51:37 -08:00
|
|
|
# The parent of the prefix; the named directory in the cellar containing all
|
2020-11-05 17:17:03 -05:00
|
|
|
# installed versions of this software.
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def rack
|
2020-10-20 12:03:48 +02:00
|
|
|
HOMEBREW_CELLAR/name
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2010-02-19 21:55:17 -08:00
|
|
|
|
2016-09-14 23:18:55 +01:00
|
|
|
# All currently installed prefix directories.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[Pathname]) }
|
2015-11-29 15:13:56 +08:00
|
|
|
def installed_prefixes
|
2020-07-09 15:03:49 +01:00
|
|
|
possible_names.map { |name| HOMEBREW_CELLAR/name }
|
|
|
|
.select(&:directory?)
|
|
|
|
.flat_map(&:subdirs)
|
|
|
|
.sort_by(&:basename)
|
2015-11-29 15:13:56 +08:00
|
|
|
end
|
|
|
|
|
2016-09-14 23:18:55 +01:00
|
|
|
# All currently installed kegs.
|
2024-04-28 03:23:21 +02:00
|
|
|
sig { returns(T::Array[Keg]) }
|
2015-11-29 15:13:56 +08:00
|
|
|
def installed_kegs
|
|
|
|
installed_prefixes.map { |dir| Keg.new(dir) }
|
|
|
|
end
|
|
|
|
|
2015-04-12 21:49:01 -07:00
|
|
|
# The directory where the formula's binaries should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Examples
|
|
|
|
#
|
2018-10-18 21:42:43 -04:00
|
|
|
# Need to install into the {.bin} but the makefile doesn't `mkdir -p prefix/bin`?
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# bin.mkpath
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# No `make install` available?
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# bin.install "binary1"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def bin
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"bin"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's documentation should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def doc
|
2017-06-01 16:06:51 +02:00
|
|
|
share/"doc"/name
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's headers should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
2015-08-29 10:56:24 +01:00
|
|
|
# No `make install` available?
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# include.install "example.h"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def include
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"include"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's info files should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def info
|
2017-06-01 16:06:51 +02:00
|
|
|
share/"info"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's libraries should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
2015-08-29 10:56:24 +01:00
|
|
|
# No `make install` available?
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# lib.install "example.dylib"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def lib
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"lib"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's binaries should be installed.
|
|
|
|
# This is not symlinked into `HOMEBREW_PREFIX`.
|
2021-01-09 13:34:17 +11:00
|
|
|
# It is commonly used to install files that we do not wish to be
|
2018-10-18 21:42:43 -04:00
|
|
|
# symlinked into `HOMEBREW_PREFIX` from one of the other directories and
|
2015-04-12 21:49:01 -07:00
|
|
|
# instead manually create symlinks or wrapper scripts into e.g. {#bin}.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# libexec.install "foo.jar"
|
2021-01-09 13:34:17 +11:00
|
|
|
# bin.write_jar_script libexec/"foo.jar", "foo"
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def libexec
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"libexec"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The root directory where the formula's manual pages should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2018-10-18 21:42:43 -04:00
|
|
|
# Often one of the more specific `man` functions should be used instead,
|
2020-11-05 17:17:03 -05:00
|
|
|
# e.g. {#man1}.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def man
|
2017-06-01 16:06:51 +02:00
|
|
|
share/"man"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's man1 pages should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
2015-08-29 10:56:24 +01:00
|
|
|
# No `make install` available?
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# man1.install "example.1"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def man1
|
2017-06-01 16:06:51 +02:00
|
|
|
man/"man1"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's man2 pages should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def man2
|
2017-06-01 16:06:51 +02:00
|
|
|
man/"man2"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's man3 pages should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
2015-08-29 10:56:24 +01:00
|
|
|
# No `make install` available?
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# man3.install "man.3"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def man3
|
2017-06-01 16:06:51 +02:00
|
|
|
man/"man3"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's man4 pages should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def man4
|
2017-06-01 16:06:51 +02:00
|
|
|
man/"man4"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's man5 pages should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def man5
|
2017-06-01 16:06:51 +02:00
|
|
|
man/"man5"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's man6 pages should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def man6
|
2017-06-01 16:06:51 +02:00
|
|
|
man/"man6"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's man7 pages should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def man7
|
2017-06-01 16:06:51 +02:00
|
|
|
man/"man7"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's man8 pages should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def man8
|
2017-06-01 16:06:51 +02:00
|
|
|
man/"man8"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's `sbin` binaries should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
|
|
|
# Generally we try to migrate these to {#bin} instead.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def sbin
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"sbin"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's shared files should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Examples
|
|
|
|
#
|
2015-08-29 10:56:24 +01:00
|
|
|
# Need a custom directory?
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# (share/"concept").mkpath
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# Installing something into another custom directory?
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# (share/"concept2").install "ducks.txt"
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2020-11-05 17:17:03 -05:00
|
|
|
# Install `./example_code/simple/ones` to `share/demos`:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# (share/"demos").install "example_code/simple/ones"
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2020-11-05 17:17:03 -05:00
|
|
|
# Install `./example_code/simple/ones` to `share/demos/examples`:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# (share/"demos").install "example_code/simple/ones" => "examples"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def share
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"share"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2009-10-02 15:55:34 +01:00
|
|
|
|
2015-07-03 10:03:00 -07:00
|
|
|
# The directory where the formula's shared files should be installed,
|
|
|
|
# with the name of the formula appended to avoid linking conflicts.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
2015-08-29 10:56:24 +01:00
|
|
|
# No `make install` available?
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# pkgshare.install "examples"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def pkgshare
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"share"/name
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-07-03 10:03:00 -07:00
|
|
|
|
2015-10-31 21:45:40 -07:00
|
|
|
# The directory where Emacs Lisp files should be installed, with the
|
|
|
|
# formula name appended to avoid linking conflicts.
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
2020-11-05 17:17:03 -05:00
|
|
|
# To install an Emacs mode included with a software package:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# elisp.install "contrib/emacs/example-mode.el"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-10-31 21:45:40 -07:00
|
|
|
def elisp
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"share/emacs/site-lisp"/name
|
2015-10-31 21:45:40 -07:00
|
|
|
end
|
|
|
|
|
2015-04-12 21:49:01 -07:00
|
|
|
# The directory where the formula's Frameworks should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
|
|
|
# This is not symlinked into `HOMEBREW_PREFIX`.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def frameworks
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"Frameworks"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
|
|
|
# The directory where the formula's kernel extensions should be installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
|
|
|
# This is not symlinked into `HOMEBREW_PREFIX`.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def kext_prefix
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"Library/Extensions"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2013-04-21 10:44:24 +02:00
|
|
|
|
2015-04-12 21:49:01 -07:00
|
|
|
# The directory where the formula's configuration files should be installed.
|
|
|
|
# Anything using `etc.install` will not overwrite other files on e.g. upgrades
|
|
|
|
# but will write a new file named `*.default`.
|
2018-10-18 21:42:43 -04:00
|
|
|
# This directory is not inside the `HOMEBREW_CELLAR` so it persists
|
2015-04-12 21:49:01 -07:00
|
|
|
# across upgrades.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def etc
|
2017-06-01 16:06:51 +02:00
|
|
|
(HOMEBREW_PREFIX/"etc").extend(InstallRenamed)
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2013-10-06 22:04:46 +01:00
|
|
|
|
2020-05-05 08:34:07 +01:00
|
|
|
# A subdirectory of `etc` with the formula name suffixed.
|
2025-01-27 15:12:50 +00:00
|
|
|
# e.g. `$HOMEBREW_PREFIX/etc/openssl@1.1`
|
2020-05-05 08:34:07 +01:00
|
|
|
# Anything using `pkgetc.install` will not overwrite other files on
|
|
|
|
# e.g. upgrades but will write a new file named `*.default`.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2020-05-05 08:34:07 +01:00
|
|
|
def pkgetc
|
|
|
|
(HOMEBREW_PREFIX/"etc"/name).extend(InstallRenamed)
|
|
|
|
end
|
|
|
|
|
2015-04-12 21:49:01 -07:00
|
|
|
# The directory where the formula's variable files should be installed.
|
2018-10-18 21:42:43 -04:00
|
|
|
# This directory is not inside the `HOMEBREW_CELLAR` so it persists
|
2015-04-12 21:49:01 -07:00
|
|
|
# across upgrades.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def var
|
2017-06-01 16:06:51 +02:00
|
|
|
HOMEBREW_PREFIX/"var"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2010-04-06 13:13:50 -07:00
|
|
|
|
2020-07-29 17:31:11 -04:00
|
|
|
# The directory where the formula's zsh function files should be
|
2016-12-08 07:20:40 -06:00
|
|
|
# installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2016-12-08 07:20:40 -06:00
|
|
|
def zsh_function
|
2017-06-01 16:06:51 +02:00
|
|
|
share/"zsh/site-functions"
|
2016-12-08 07:20:40 -06:00
|
|
|
end
|
|
|
|
|
2016-12-03 11:36:49 -06:00
|
|
|
# The directory where the formula's fish function files should be
|
|
|
|
# installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2016-12-03 11:36:49 -06:00
|
|
|
def fish_function
|
2017-06-01 16:06:51 +02:00
|
|
|
share/"fish/vendor_functions.d"
|
2016-12-03 11:36:49 -06:00
|
|
|
end
|
|
|
|
|
2015-04-12 21:49:01 -07:00
|
|
|
# The directory where the formula's Bash completion files should be
|
|
|
|
# installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def bash_completion
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/"etc/bash_completion.d"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-04-12 21:49:01 -07:00
|
|
|
|
2020-07-29 17:31:11 -04:00
|
|
|
# The directory where the formula's zsh completion files should be
|
2015-04-12 21:49:01 -07:00
|
|
|
# installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def zsh_completion
|
2017-06-01 16:06:51 +02:00
|
|
|
share/"zsh/site-functions"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2015-05-17 01:12:12 +02:00
|
|
|
|
|
|
|
# The directory where the formula's fish completion files should be
|
|
|
|
# installed.
|
|
|
|
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
|
|
|
|
# `brew link` for formulae that are not keg-only.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def fish_completion
|
2017-06-01 16:06:51 +02:00
|
|
|
share/"fish/vendor_completions.d"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2013-01-27 22:34:26 +00:00
|
|
|
|
2015-04-12 21:49:01 -07:00
|
|
|
# The directory used for as the prefix for {#etc} and {#var} files on
|
|
|
|
# installation so, despite not being in `HOMEBREW_CELLAR`, they are installed
|
|
|
|
# there after pouring a bottle.
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def bottle_prefix
|
2017-06-01 16:06:51 +02:00
|
|
|
prefix/".bottle"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2013-10-05 20:29:19 +01:00
|
|
|
|
2016-05-27 01:53:08 -04:00
|
|
|
# The directory where the formula's installation or test logs will be written.
|
2023-07-23 18:42:06 -07:00
|
|
|
sig { returns(Pathname) }
|
2015-04-25 22:07:06 -04:00
|
|
|
def logs
|
2017-06-01 16:06:51 +02:00
|
|
|
HOMEBREW_LOGS + name
|
2015-04-25 22:07:06 -04:00
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# The prefix, if any, to use in filenames for logging current activity.
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(String) }
|
2016-05-27 01:53:08 -04:00
|
|
|
def active_log_prefix
|
|
|
|
if active_log_type
|
|
|
|
"#{active_log_type}."
|
|
|
|
else
|
|
|
|
""
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Runs a block with the given log type in effect for its duration.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(log_type: String, _block: T.proc.void).void }
|
|
|
|
def with_logging(log_type, &_block)
|
2016-05-27 01:53:08 -04:00
|
|
|
old_log_type = @active_log_type
|
2025-02-16 22:20:37 -08:00
|
|
|
@active_log_type = T.let(log_type, T.nilable(String))
|
2016-05-27 01:53:08 -04:00
|
|
|
yield
|
|
|
|
ensure
|
|
|
|
@active_log_type = old_log_type
|
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# This method can be overridden to provide a plist.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# def plist; <<~EOS
|
2020-11-03 16:36:48 -05:00
|
|
|
# <?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
# <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
|
|
# <plist version="1.0">
|
|
|
|
# <dict>
|
|
|
|
# <key>Label</key>
|
|
|
|
# <string>#{plist_name}</string>
|
|
|
|
# <key>ProgramArguments</key>
|
|
|
|
# <array>
|
|
|
|
# <string>#{opt_bin}/example</string>
|
|
|
|
# <string>--do-this</string>
|
|
|
|
# </array>
|
|
|
|
# <key>RunAtLoad</key>
|
|
|
|
# <true/>
|
|
|
|
# <key>KeepAlive</key>
|
|
|
|
# <true/>
|
|
|
|
# <key>StandardErrorPath</key>
|
|
|
|
# <string>/dev/null</string>
|
|
|
|
# <key>StandardOutPath</key>
|
|
|
|
# <string>/dev/null</string>
|
|
|
|
# </dict>
|
|
|
|
# </plist>
|
|
|
|
# EOS
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2022-11-06 13:52:53 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# @see https://www.unix.com/man-page/all/5/plist/ <code>plist(5)</code> man page
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(NilClass) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def plist
|
2024-09-24 10:15:34 +01:00
|
|
|
odisabled "`Formula#plist`", "`Homebrew::Service`"
|
2015-08-03 13:09:07 +01:00
|
|
|
nil
|
|
|
|
end
|
2015-08-29 10:56:24 +01:00
|
|
|
|
2015-12-06 22:18:16 +00:00
|
|
|
# The generated launchd {.plist} service name.
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(String) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def plist_name
|
2023-04-13 23:33:31 -07:00
|
|
|
service.plist_name
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
|
|
|
|
2021-05-04 16:22:28 +02:00
|
|
|
# The generated service name.
|
|
|
|
sig { returns(String) }
|
|
|
|
def service_name
|
2023-04-13 23:33:31 -07:00
|
|
|
service.service_name
|
2021-05-04 16:22:28 +02:00
|
|
|
end
|
|
|
|
|
2021-10-23 21:32:38 -04:00
|
|
|
# The generated launchd {.service} file path.
|
2022-11-06 13:52:53 +01:00
|
|
|
sig { returns(Pathname) }
|
|
|
|
def launchd_service_path
|
2021-07-26 09:08:26 +02:00
|
|
|
opt_prefix/"#{plist_name}.plist"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
|
|
|
|
2021-05-04 16:22:28 +02:00
|
|
|
# The generated systemd {.service} file path.
|
|
|
|
sig { returns(Pathname) }
|
|
|
|
def systemd_service_path
|
2021-07-26 09:08:26 +02:00
|
|
|
opt_prefix/"#{service_name}.service"
|
2021-05-04 16:22:28 +02:00
|
|
|
end
|
|
|
|
|
2021-11-20 15:14:50 +01:00
|
|
|
# The generated systemd {.timer} file path.
|
|
|
|
sig { returns(Pathname) }
|
|
|
|
def systemd_timer_path
|
|
|
|
opt_prefix/"#{service_name}.timer"
|
|
|
|
end
|
|
|
|
|
2021-04-08 10:06:45 +02:00
|
|
|
# The service specification of the software.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(Homebrew::Service) }
|
2021-04-08 10:06:45 +02:00
|
|
|
def service
|
2025-02-16 22:20:37 -08:00
|
|
|
@service ||= T.let(Homebrew::Service.new(self, &self.class.service), T.nilable(Homebrew::Service))
|
2021-04-08 10:06:45 +02:00
|
|
|
end
|
|
|
|
|
2014-03-05 20:51:37 -08:00
|
|
|
# A stable path for this formula, when installed. Contains the formula name
|
|
|
|
# but no version number. Only the active version will be linked here if
|
|
|
|
# multiple versions are installed.
|
|
|
|
#
|
2018-10-18 21:42:43 -04:00
|
|
|
# This is the preferred way to refer to a formula in plists or from another
|
2014-03-05 20:51:37 -08:00
|
|
|
# formula, as the path is stable even when the software is updated.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# args << "--with-readline=#{Formula["readline"].opt_prefix}" if build.with? "readline"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(Pathname) }
|
2013-04-15 15:00:57 -05:00
|
|
|
def opt_prefix
|
2020-10-20 12:03:48 +02:00
|
|
|
HOMEBREW_PREFIX/"opt"/name
|
2013-04-15 15:00:57 -05:00
|
|
|
end
|
2012-08-10 16:33:22 -04:00
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Same as {#bin}, but relative to {#opt_prefix} instead of {#prefix}.
|
|
|
|
#
|
|
|
|
# @api public
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def opt_bin
|
2017-06-01 16:06:51 +02:00
|
|
|
opt_prefix/"bin"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Same as {#include}, but relative to {#opt_prefix} instead of {#prefix}.
|
|
|
|
#
|
|
|
|
# @api public
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def opt_include
|
2017-06-01 16:06:51 +02:00
|
|
|
opt_prefix/"include"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Same as {#lib}, but relative to {#opt_prefix} instead of {#prefix}.
|
|
|
|
#
|
|
|
|
# @api public
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def opt_lib
|
2017-06-01 16:06:51 +02:00
|
|
|
opt_prefix/"lib"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Same as {#libexec}, but relative to {#opt_prefix} instead of {#prefix}.
|
|
|
|
#
|
|
|
|
# @api public
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def opt_libexec
|
2017-06-01 16:06:51 +02:00
|
|
|
opt_prefix/"libexec"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Same as {#sbin}, but relative to {#opt_prefix} instead of {#prefix}.
|
|
|
|
#
|
|
|
|
# @api public
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def opt_sbin
|
2017-06-01 16:06:51 +02:00
|
|
|
opt_prefix/"sbin"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Same as {#share}, but relative to {#opt_prefix} instead of {#prefix}.
|
|
|
|
#
|
|
|
|
# @api public
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def opt_share
|
2017-06-01 16:06:51 +02:00
|
|
|
opt_prefix/"share"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Same as {#pkgshare}, but relative to {#opt_prefix} instead of {#prefix}.
|
|
|
|
#
|
|
|
|
# @api public
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def opt_pkgshare
|
2017-06-01 16:06:51 +02:00
|
|
|
opt_prefix/"share"/name
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Same as {#elisp}, but relative to {#opt_prefix} instead of {#prefix}.
|
|
|
|
#
|
|
|
|
# @api public
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(Pathname) }
|
2015-10-31 21:45:40 -07:00
|
|
|
def opt_elisp
|
2017-06-01 16:06:51 +02:00
|
|
|
opt_prefix/"share/emacs/site-lisp"/name
|
2015-10-31 21:45:40 -07:00
|
|
|
end
|
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Same as {#frameworks}, but relative to {#opt_prefix} instead of {#prefix}.
|
|
|
|
#
|
|
|
|
# @api public
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def opt_frameworks
|
2017-06-01 16:06:51 +02:00
|
|
|
opt_prefix/"Frameworks"
|
2015-08-03 13:09:07 +01:00
|
|
|
end
|
2014-03-05 21:01:24 -08:00
|
|
|
|
2016-05-06 12:02:13 -07:00
|
|
|
# Indicates that this formula supports bottles. (Not necessarily that one
|
|
|
|
# should be used in the current installation run.)
|
2013-01-27 19:22:56 +00:00
|
|
|
# Can be overridden to selectively disable bottles from formulae.
|
|
|
|
# Defaults to true so overridden version does not have to check if bottles
|
|
|
|
# are supported.
|
2020-11-05 17:17:03 -05:00
|
|
|
# Replaced by {.pour_bottle?}'s `satisfy` method if it is specified.
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(T::Boolean) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def pour_bottle?
|
|
|
|
true
|
|
|
|
end
|
2013-01-27 19:22:56 +00:00
|
|
|
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate pour_bottle_check_unsatisfied_reason: :"self.class"
|
2016-01-09 11:06:17 +00:00
|
|
|
|
2013-04-01 20:33:12 +01:00
|
|
|
# Can be overridden to run commands on both source and bottle installation.
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { overridable.void }
|
2013-04-01 20:33:12 +01:00
|
|
|
def post_install; end
|
|
|
|
|
2023-06-22 03:06:45 +01:00
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
def post_install_defined?
|
|
|
|
method(:post_install).owner != Formula
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { void }
|
|
|
|
def install_etc_var
|
|
|
|
etc_var_dirs = [bottle_prefix/"etc", bottle_prefix/"var"]
|
|
|
|
Find.find(*etc_var_dirs.select(&:directory?)) do |path|
|
|
|
|
path = Pathname.new(path)
|
|
|
|
path.extend(InstallRenamed)
|
|
|
|
path.cp_path_sub(bottle_prefix, HOMEBREW_PREFIX)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { void }
|
2016-05-27 01:53:08 -04:00
|
|
|
def run_post_install
|
2025-02-16 22:20:37 -08:00
|
|
|
@prefix_returns_versioned_prefix = T.let(true, T.nilable(T::Boolean))
|
2016-05-27 01:53:08 -04:00
|
|
|
build = self.build
|
2017-04-22 16:31:19 +01:00
|
|
|
|
2020-11-24 15:46:47 +01:00
|
|
|
begin
|
|
|
|
self.build = Tab.for_formula(self)
|
2017-07-15 17:26:51 -07:00
|
|
|
|
2020-11-24 15:46:47 +01:00
|
|
|
new_env = {
|
|
|
|
TMPDIR: HOMEBREW_TEMP,
|
|
|
|
TEMP: HOMEBREW_TEMP,
|
|
|
|
TMP: HOMEBREW_TEMP,
|
|
|
|
_JAVA_OPTIONS: "-Djava.io.tmpdir=#{HOMEBREW_TEMP}",
|
|
|
|
HOMEBREW_PATH: nil,
|
2022-06-15 05:40:43 +01:00
|
|
|
PATH: PATH.new(ORIGINAL_PATHS),
|
2020-11-24 15:46:47 +01:00
|
|
|
}
|
2017-07-15 17:26:51 -07:00
|
|
|
|
2020-11-24 15:46:47 +01:00
|
|
|
with_env(new_env) do
|
|
|
|
ENV.clear_sensitive_environment!
|
2020-12-18 12:35:06 -08:00
|
|
|
ENV.activate_extensions!
|
2017-07-15 17:26:51 -07:00
|
|
|
|
2020-11-24 15:46:47 +01:00
|
|
|
with_logging("post_install") do
|
|
|
|
post_install
|
|
|
|
end
|
2017-07-15 17:26:51 -07:00
|
|
|
end
|
2020-11-24 15:46:47 +01:00
|
|
|
ensure
|
|
|
|
self.build = build
|
2025-02-16 22:20:37 -08:00
|
|
|
@prefix_returns_versioned_prefix = T.let(false, T.nilable(T::Boolean))
|
2016-05-27 01:53:08 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Warn the user about any Homebrew-specific issues or quirks for this package.
|
2019-06-20 11:08:02 +01:00
|
|
|
# These should not contain setup instructions that would apply to installation
|
|
|
|
# through a different package manager on a different OS.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# def caveats
|
2017-10-15 02:28:32 +02:00
|
|
|
# <<~EOS
|
2019-06-20 11:08:02 +01:00
|
|
|
# Are optional. Something the user must be warned about?
|
2015-08-29 10:56:24 +01:00
|
|
|
# EOS
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# def caveats
|
2017-10-15 02:28:32 +02:00
|
|
|
# s = <<~EOS
|
2018-10-18 21:42:43 -04:00
|
|
|
# Print some important notice to the user when `brew info [formula]` is
|
2015-08-29 10:56:24 +01:00
|
|
|
# called or when brewing a formula.
|
|
|
|
# This is optional. You can use all the vars like #{version} here.
|
|
|
|
# EOS
|
2019-01-26 17:13:14 +00:00
|
|
|
# s += "Some issue only on older systems" if MacOS.version < :el_capitan
|
2015-08-29 10:56:24 +01:00
|
|
|
# s
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { overridable.returns(T.nilable(String)) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def caveats
|
|
|
|
nil
|
|
|
|
end
|
2009-09-28 14:06:53 -07:00
|
|
|
|
2018-10-18 21:42:43 -04:00
|
|
|
# Rarely, you don't want your library symlinked into the main prefix.
|
|
|
|
# See `gettext.rb` for an example.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @see .keg_only
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2010-07-18 10:38:45 -07:00
|
|
|
def keg_only?
|
2017-07-07 09:23:31 +01:00
|
|
|
return false unless keg_only_reason
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2020-04-11 14:15:42 +01:00
|
|
|
keg_only_reason.applicable?
|
2012-08-09 02:00:58 -05:00
|
|
|
end
|
|
|
|
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate keg_only_reason: :"self.class"
|
2009-08-10 16:48:30 +01:00
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .skip_clean
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { params(path: Pathname).returns(T::Boolean) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def skip_clean?(path)
|
2025-02-16 22:20:37 -08:00
|
|
|
return true if path.extname == ".la" && T.must(self.class.skip_clean_paths).include?(:la)
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2009-09-28 14:06:53 -07:00
|
|
|
to_check = path.relative_path_from(prefix).to_s
|
2025-02-16 22:20:37 -08:00
|
|
|
T.must(self.class.skip_clean_paths).include? to_check
|
2009-09-28 14:06:53 -07:00
|
|
|
end
|
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .link_overwrite
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(path: Pathname).returns(T::Boolean) }
|
2015-08-23 16:35:51 +08:00
|
|
|
def link_overwrite?(path)
|
|
|
|
# Don't overwrite files not created by Homebrew.
|
2025-01-07 17:40:18 +00:00
|
|
|
return false if path.stat.uid != HOMEBREW_ORIGINAL_BREW_FILE.stat.uid
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2015-09-28 22:47:53 +01:00
|
|
|
# Don't overwrite files belong to other keg except when that
|
|
|
|
# keg's formula is deleted.
|
2015-08-23 16:35:51 +08:00
|
|
|
begin
|
2015-09-28 22:47:53 +01:00
|
|
|
keg = Keg.for(path)
|
2020-05-05 08:34:07 +01:00
|
|
|
rescue NotAKegError, Errno::ENOENT
|
2015-08-23 16:35:51 +08:00
|
|
|
# file doesn't belong to any keg.
|
|
|
|
else
|
2024-04-28 03:23:21 +02:00
|
|
|
tab_tap = keg.tab.tap
|
2018-09-02 16:15:09 +01:00
|
|
|
# this keg doesn't below to any core/tap formula, most likely coming from a DIY install.
|
|
|
|
return false if tab_tap.nil?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2015-09-28 22:47:53 +01:00
|
|
|
begin
|
2020-07-05 22:24:03 +02:00
|
|
|
f = Formulary.factory(keg.name)
|
2020-05-05 08:34:07 +01:00
|
|
|
rescue FormulaUnavailableError
|
2020-06-06 19:12:12 +01:00
|
|
|
# formula for this keg is deleted, so defer to allowlist
|
2024-02-16 21:27:02 +01:00
|
|
|
rescue TapFormulaAmbiguityError
|
2015-09-28 22:47:53 +01:00
|
|
|
return false # this keg belongs to another formula
|
|
|
|
else
|
2020-07-06 09:23:04 +01:00
|
|
|
# this keg belongs to another unrelated formula
|
2020-07-09 15:03:49 +01:00
|
|
|
return false unless f.possible_names.include?(keg.name)
|
2015-09-28 22:47:53 +01:00
|
|
|
end
|
2015-08-23 16:35:51 +08:00
|
|
|
end
|
|
|
|
to_check = path.relative_path_from(HOMEBREW_PREFIX).to_s
|
2025-02-16 22:20:37 -08:00
|
|
|
T.must(self.class.link_overwrite_paths).any? do |p|
|
|
|
|
p.to_s == to_check ||
|
|
|
|
to_check.start_with?("#{p.to_s.chomp("/")}/") ||
|
|
|
|
/^#{Regexp.escape(p.to_s).gsub('\*', ".*?")}$/.match?(to_check)
|
2015-08-23 16:35:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-01 13:42:52 +01:00
|
|
|
# Whether this {Formula} is deprecated (i.e. warns on installation).
|
|
|
|
# Defaults to false.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method deprecated?
|
2020-04-01 13:42:52 +01:00
|
|
|
# @return [Boolean]
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .deprecate!
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate deprecated?: :"self.class"
|
2020-04-01 13:42:52 +01:00
|
|
|
|
2020-12-23 02:58:14 -05:00
|
|
|
# The date that this {Formula} was or becomes deprecated.
|
|
|
|
# Returns `nil` if no date is specified.
|
|
|
|
# @!method deprecation_date
|
|
|
|
# @return Date
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .deprecate!
|
2020-12-23 02:58:14 -05:00
|
|
|
delegate deprecation_date: :"self.class"
|
|
|
|
|
2020-08-27 10:42:57 -04:00
|
|
|
# The reason this {Formula} is deprecated.
|
|
|
|
# Returns `nil` if no reason is specified or the formula is not deprecated.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method deprecation_reason
|
2020-08-28 22:49:26 -04:00
|
|
|
# @return [String, Symbol]
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .deprecate!
|
2020-08-27 10:42:57 -04:00
|
|
|
delegate deprecation_reason: :"self.class"
|
|
|
|
|
2024-11-07 15:50:03 -05:00
|
|
|
# The replacement for this deprecated {Formula}.
|
|
|
|
# Returns `nil` if no replacement is specified or the formula is not deprecated.
|
|
|
|
# @!method deprecation_replacement
|
|
|
|
# @return [String]
|
|
|
|
# @see .deprecate!
|
|
|
|
delegate deprecation_replacement: :"self.class"
|
|
|
|
|
2020-04-01 13:42:52 +01:00
|
|
|
# Whether this {Formula} is disabled (i.e. cannot be installed).
|
|
|
|
# Defaults to false.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method disabled?
|
2020-04-01 13:42:52 +01:00
|
|
|
# @return [Boolean]
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .disable!
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate disabled?: :"self.class"
|
2020-04-01 13:42:52 +01:00
|
|
|
|
2020-12-23 02:58:14 -05:00
|
|
|
# The date that this {Formula} was or becomes disabled.
|
|
|
|
# Returns `nil` if no date is specified.
|
|
|
|
# @!method disable_date
|
|
|
|
# @return Date
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .disable!
|
2020-12-23 02:58:14 -05:00
|
|
|
delegate disable_date: :"self.class"
|
|
|
|
|
2020-08-27 10:42:57 -04:00
|
|
|
# The reason this {Formula} is disabled.
|
|
|
|
# Returns `nil` if no reason is specified or the formula is not disabled.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method disable_reason
|
2020-08-28 22:49:26 -04:00
|
|
|
# @return [String, Symbol]
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .disable!
|
2020-08-27 10:42:57 -04:00
|
|
|
delegate disable_reason: :"self.class"
|
|
|
|
|
2024-11-07 15:50:03 -05:00
|
|
|
# The replacement for this disabled {Formula}.
|
|
|
|
# Returns `nil` if no replacement is specified or the formula is not disabled.
|
|
|
|
# @!method disable_replacement
|
|
|
|
# @return [String]
|
|
|
|
# @see .disable!
|
|
|
|
delegate disable_replacement: :"self.class"
|
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(T::Boolean) }
|
2014-07-06 15:51:43 -05:00
|
|
|
def skip_cxxstdlib_check?
|
2014-08-16 02:05:13 -05:00
|
|
|
false
|
2014-07-06 15:51:43 -05:00
|
|
|
end
|
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(T::Boolean) }
|
2014-08-16 01:33:41 -05:00
|
|
|
def require_universal_deps?
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { void }
|
2014-12-26 17:44:44 -05:00
|
|
|
def patch
|
2016-09-23 22:02:23 +02:00
|
|
|
return if patchlist.empty?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-09-23 22:02:23 +02:00
|
|
|
ohai "Patching"
|
|
|
|
patchlist.each(&:apply)
|
2014-12-26 17:44:44 -05:00
|
|
|
end
|
|
|
|
|
formula: don't include DATA patches in initial Git repo
Currently, existing DATA patches are subsumed into the initial Git repo
created by `brew install --git`, which makes creating a new DATA
patch after more fixes a tedious and error-prone process.
This PR delays DATA patch processing till after the Git repo is
created, so a `git diff` at the end creates a correct and consolidated
DATA patch block ready for insertion/replacement, or even migration
to a proper remote patch URL.
The difference is clearly seen in `gromgit/fuse/dislocker-mac`,
which has both remote and DATA patches.
Before:
```
% brew install -sig dislocker-mac
==> Fetching gromgit/fuse/dislocker-mac
==> Downloading https://github.com/Aorimn/dislocker/commit/2cfbba2c8cc07e529622ba134d0a6982815d2b30.patch?full_index=1
Already downloaded: /Volumes/aho/Library/Caches/Homebrew/downloads/37276859cbebc1711941278db00cd8b25b98d69e15e31e33915a98d01a13febc--2cfbba2c8cc07e529622ba134d0a6982815d2b30.patch
==> Downloading https://github.com/Aorimn/dislocker/archive/refs/tags/v0.7.3.tar.gz
Already downloaded: /Volumes/aho/Library/Caches/Homebrew/downloads/b1ba1098c95535574936051eca45cc472955a5a024b81cc72e1c3b006e1950b3--dislocker-0.7.3.tar.gz
==> Installing dislocker-mac from gromgit/fuse
==> Patching
==> Applying 2cfbba2c8cc07e529622ba134d0a6982815d2b30.patch
Initialized empty Git repository in /private/tmp/dislocker-mac-20250215-35534-8qlxtp/dislocker-0.7.3/.git/
==> Entering interactive mode...
Type `exit` to return and finalize the installation.
Install to this prefix: /opt/homebrew/Cellar/dislocker-mac/0.7.3_2
This directory is now a Git repository. Make your changes and then use:
git diff | pbcopy
to copy the diff to the clipboard.
% git diff
```
After:
```
% brew install -sig dislocker-mac
==> Fetching gromgit/fuse/dislocker-mac
==> Downloading https://github.com/Aorimn/dislocker/commit/2cfbba2c8cc07e529622ba134d0a6982815d2b30.patch?full_index=1
Already downloaded: /Volumes/aho/Library/Caches/Homebrew/downloads/37276859cbebc1711941278db00cd8b25b98d69e15e31e33915a98d01a13febc--2cfbba2c8cc07e529622ba134d0a6982815d2b30.patch
==> Downloading https://github.com/Aorimn/dislocker/archive/refs/tags/v0.7.3.tar.gz
Already downloaded: /Volumes/aho/Library/Caches/Homebrew/downloads/b1ba1098c95535574936051eca45cc472955a5a024b81cc72e1c3b006e1950b3--dislocker-0.7.3.tar.gz
==> Installing dislocker-mac from gromgit/fuse
==> Applying non-DATA patches
==> Applying 2cfbba2c8cc07e529622ba134d0a6982815d2b30.patch
Initialized empty Git repository in /private/tmp/dislocker-mac-20250215-32462-zh1akh/dislocker-0.7.3/.git/
==> Applying DATA patches
==> Entering interactive mode...
Type `exit` to return and finalize the installation.
Install to this prefix: /opt/homebrew/Cellar/dislocker-mac/0.7.3_2
This directory is now a Git repository. Make your changes and then use:
git diff | pbcopy
to copy the diff to the clipboard.
% git diff
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bd854d2..9ab137d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -92,7 +92,7 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
# Don't use `-read_only_relocs' here as it seems to only work for 32 bits
# binaries
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-bind_at_load")
- set (FUSE_LIB osxfuse_i64)
+ set (FUSE_LIB fuse)
else()
# Useless warnings when used within Darwin
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion")
diff --git a/src/dislocker-fuse.c b/src/dislocker-fuse.c
index f93523f..3dd106c 100644
--- a/src/dislocker-fuse.c
+++ b/src/dislocker-fuse.c
@@ -33,11 +33,7 @@
-#ifdef __DARWIN
-# include <osxfuse/fuse.h>
-#else
-# include <fuse.h>
-#endif /* __DARWIN */
+#include <fuse.h>
/** NTFS virtual partition's name */
```
2025-02-15 20:15:53 +08:00
|
|
|
sig { params(is_data: T::Boolean).void }
|
|
|
|
def selective_patch(is_data: false)
|
|
|
|
patches = patchlist.select { |p| p.is_a?(DATAPatch) == is_data }
|
|
|
|
return if patches.empty?
|
|
|
|
|
|
|
|
patchtype = if is_data
|
|
|
|
"DATA"
|
|
|
|
else
|
|
|
|
"non-DATA"
|
|
|
|
end
|
|
|
|
ohai "Applying #{patchtype} patches"
|
|
|
|
patches.each(&:apply)
|
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Yields |self,staging| with current working directory set to the uncompressed tarball
|
|
|
|
# where staging is a {Mktemp} staging context.
|
2024-11-21 18:10:20 -08:00
|
|
|
sig(:final) {
|
|
|
|
params(fetch: T::Boolean, keep_tmp: T::Boolean, debug_symbols: T::Boolean, interactive: T::Boolean,
|
|
|
|
_blk: T.proc.params(arg0: Formula, arg1: Mktemp).void).void
|
|
|
|
}
|
|
|
|
def brew(fetch: true, keep_tmp: false, debug_symbols: false, interactive: false, &_blk)
|
2025-02-16 22:20:37 -08:00
|
|
|
@prefix_returns_versioned_prefix = T.let(true, T.nilable(T::Boolean))
|
2020-05-12 12:37:54 +01:00
|
|
|
active_spec.fetch if fetch
|
2024-03-07 16:20:20 +00:00
|
|
|
stage(interactive:, debug_symbols:) do |staging|
|
2022-07-26 12:15:53 +01:00
|
|
|
staging.retain! if keep_tmp || debug_symbols
|
2020-05-13 11:49:17 +01:00
|
|
|
|
|
|
|
prepare_patches
|
2020-08-02 14:32:31 +02:00
|
|
|
fetch_patches if fetch
|
2014-12-26 17:44:44 -05:00
|
|
|
|
2009-08-10 16:48:30 +01:00
|
|
|
begin
|
2016-04-10 22:53:56 -04:00
|
|
|
yield self, staging
|
2018-09-02 20:14:54 +01:00
|
|
|
rescue
|
2020-08-02 14:32:31 +02:00
|
|
|
staging.retain! if interactive || debug?
|
2016-04-10 22:53:56 -04:00
|
|
|
raise
|
2014-08-29 22:31:55 -05:00
|
|
|
ensure
|
formula: capture logs more comprehensively
Currently, we copy `config.log` and `CMakeCache.txt` from the root of
the source tree into the the logs generated by the build. This has three
shortcomings:
1. These files are not necessarily found where we look. This is often
the case with a CMake build, but can occur with an Autotools build
as well (e.g. GCC, or any other out-of-tree build).
2. There may be several of these files scattered throughout the build
tree. This occurs, for example, when the build itself invokes
`configure` or `cmake` as part of the build process.
3. We don't copy `CMakeOutput.log` or `CMakeError.log`, which are
usually more informative about what happened during the CMake
invocation. It is not sufficient to add them to the array of log
files that we copy because these are never found at the source root,
even when building in-tree.
Let's rectify this by copying all instances of these files that can be
found in the source tree. Since there will inevitably be duplicate file
names, we also store them in the log directory using the same relative
paths from the source root. [1] This has the added benefit of providing
context for these log files.
[1] For example, if `CMakeOutput.log` can be found in `build/CMakeFiles`
relative to the source root, then that will also be where it will be
stored in the log directory.
2021-06-24 19:12:40 +01:00
|
|
|
%w[
|
|
|
|
config.log
|
|
|
|
CMakeCache.txt
|
2024-09-11 14:57:16 +08:00
|
|
|
CMakeConfigureLog.yaml
|
2022-01-18 17:42:40 +08:00
|
|
|
meson-log.txt
|
formula: capture logs more comprehensively
Currently, we copy `config.log` and `CMakeCache.txt` from the root of
the source tree into the the logs generated by the build. This has three
shortcomings:
1. These files are not necessarily found where we look. This is often
the case with a CMake build, but can occur with an Autotools build
as well (e.g. GCC, or any other out-of-tree build).
2. There may be several of these files scattered throughout the build
tree. This occurs, for example, when the build itself invokes
`configure` or `cmake` as part of the build process.
3. We don't copy `CMakeOutput.log` or `CMakeError.log`, which are
usually more informative about what happened during the CMake
invocation. It is not sufficient to add them to the array of log
files that we copy because these are never found at the source root,
even when building in-tree.
Let's rectify this by copying all instances of these files that can be
found in the source tree. Since there will inevitably be duplicate file
names, we also store them in the log directory using the same relative
paths from the source root. [1] This has the added benefit of providing
context for these log files.
[1] For example, if `CMakeOutput.log` can be found in `build/CMakeFiles`
relative to the source root, then that will also be where it will be
stored in the log directory.
2021-06-24 19:12:40 +01:00
|
|
|
].each do |logfile|
|
|
|
|
Dir["**/#{logfile}"].each do |logpath|
|
|
|
|
destdir = logs/File.dirname(logpath)
|
|
|
|
mkdir_p destdir
|
|
|
|
cp logpath, destdir
|
|
|
|
end
|
|
|
|
end
|
2009-08-10 16:48:30 +01:00
|
|
|
end
|
|
|
|
end
|
2016-12-31 16:38:05 +00:00
|
|
|
ensure
|
2025-02-16 22:20:37 -08:00
|
|
|
@prefix_returns_versioned_prefix = T.let(false, T.nilable(T::Boolean))
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
2009-08-10 16:48:30 +01:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2013-01-23 00:26:25 -06:00
|
|
|
def lock
|
2025-02-16 22:20:37 -08:00
|
|
|
@lock = T.let(FormulaLock.new(name), T.nilable(FormulaLock))
|
|
|
|
T.must(@lock).lock
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2023-04-27 04:09:28 +01:00
|
|
|
oldnames.each do |oldname|
|
|
|
|
next unless (oldname_rack = HOMEBREW_CELLAR/oldname).exist?
|
|
|
|
next if oldname_rack.resolved_path != rack
|
|
|
|
|
|
|
|
oldname_lock = FormulaLock.new(oldname)
|
|
|
|
oldname_lock.lock
|
|
|
|
@oldname_locks << oldname_lock
|
|
|
|
end
|
2013-01-23 00:26:25 -06:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[FormulaLock]) }
|
2013-01-23 00:26:25 -06:00
|
|
|
def unlock
|
2017-09-24 19:24:46 +01:00
|
|
|
@lock&.unlock
|
2023-04-27 04:09:28 +01:00
|
|
|
@oldname_locks.each(&:unlock)
|
2013-01-23 00:26:25 -06:00
|
|
|
end
|
|
|
|
|
2023-07-24 06:55:41 -07:00
|
|
|
sig { returns(T::Array[String]) }
|
2023-04-27 04:09:28 +01:00
|
|
|
def oldnames_to_migrate
|
|
|
|
oldnames.select do |oldname|
|
|
|
|
old_rack = HOMEBREW_CELLAR/oldname
|
|
|
|
next false unless old_rack.directory?
|
|
|
|
next false if old_rack.subdirs.empty?
|
2016-07-01 18:02:31 +03:00
|
|
|
|
2023-04-27 04:09:28 +01:00
|
|
|
tap == Tab.for_keg(old_rack.subdirs.min).tap
|
|
|
|
end
|
|
|
|
end
|
2016-07-01 18:02:31 +03:00
|
|
|
|
2023-07-24 06:55:41 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2023-04-27 04:09:28 +01:00
|
|
|
def migration_needed?
|
|
|
|
!oldnames_to_migrate.empty? && !rack.exist?
|
2016-06-27 13:08:19 +03:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(fetch_head: T::Boolean).returns(T::Array[Keg]) }
|
2019-11-06 11:49:31 +00:00
|
|
|
def outdated_kegs(fetch_head: false)
|
2023-04-27 04:09:28 +01:00
|
|
|
raise Migrator::MigrationNeededError.new(oldnames_to_migrate.first, name) if migration_needed?
|
2019-11-06 11:49:31 +00:00
|
|
|
|
2020-08-02 13:43:32 +01:00
|
|
|
cache_key = "#{full_name}-#{fetch_head}"
|
2019-11-06 11:49:31 +00:00
|
|
|
Formula.cache[:outdated_kegs] ||= {}
|
|
|
|
Formula.cache[:outdated_kegs][cache_key] ||= begin
|
|
|
|
all_kegs = []
|
2020-11-24 15:46:47 +01:00
|
|
|
current_version = T.let(false, T::Boolean)
|
2019-11-06 11:49:31 +00:00
|
|
|
|
|
|
|
installed_kegs.each do |keg|
|
|
|
|
all_kegs << keg
|
|
|
|
version = keg.version
|
|
|
|
next if version.head?
|
|
|
|
|
2024-03-29 23:07:38 +00:00
|
|
|
next if version_scheme > keg.version_scheme && pkg_version != version
|
|
|
|
next if version_scheme == keg.version_scheme && pkg_version > version
|
2019-11-06 11:49:31 +00:00
|
|
|
|
|
|
|
# don't consider this keg current if there's a newer formula available
|
|
|
|
next if follow_installed_alias? && new_formula_available?
|
|
|
|
|
|
|
|
# this keg is the current version of the formula, so it's not outdated
|
|
|
|
current_version = true
|
|
|
|
break
|
|
|
|
end
|
2016-09-15 16:01:18 +01:00
|
|
|
|
2020-11-13 10:07:02 -05:00
|
|
|
if current_version ||
|
2024-03-07 16:20:20 +00:00
|
|
|
((head_version = latest_head_version) && !head_version_outdated?(head_version, fetch_head:))
|
2019-11-06 11:49:31 +00:00
|
|
|
[]
|
|
|
|
else
|
|
|
|
all_kegs += old_installed_formulae.flat_map(&:installed_kegs)
|
2024-03-31 16:53:15 -07:00
|
|
|
all_kegs.sort_by(&:scheme_and_version)
|
2019-11-06 11:49:31 +00:00
|
|
|
end
|
2015-11-27 15:11:00 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2016-09-19 01:53:48 +01:00
|
|
|
def new_formula_available?
|
2019-12-03 11:42:09 +00:00
|
|
|
installed_alias_target_changed? && !latest_formula.latest_version_installed?
|
2016-09-19 01:53:48 +01:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(Formula)) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def current_installed_alias_target
|
2023-07-24 06:55:41 -07:00
|
|
|
Formulary.factory(T.must(installed_alias_name)) if installed_alias_path
|
2016-09-15 16:01:18 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# Has the target of the alias used to install this formula changed?
|
|
|
|
# Returns false if the formula wasn't installed with an alias.
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def installed_alias_target_changed?
|
2016-09-18 19:43:54 +01:00
|
|
|
target = current_installed_alias_target
|
2017-09-24 20:12:58 +01:00
|
|
|
return false unless target
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2017-09-24 20:12:58 +01:00
|
|
|
target.name != name
|
2016-09-15 16:01:18 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# Is this formula the target of an alias used to install an old formula?
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def supersedes_an_installed_formula?
|
|
|
|
old_installed_formulae.any?
|
|
|
|
end
|
|
|
|
|
|
|
|
# Has the alias used to install the formula changed, or are different
|
|
|
|
# formulae already installed with this alias?
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def alias_changed?
|
|
|
|
installed_alias_target_changed? || supersedes_an_installed_formula?
|
|
|
|
end
|
|
|
|
|
|
|
|
# If the alias has changed value, return the new formula.
|
|
|
|
# Otherwise, return self.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(Formula) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def latest_formula
|
2025-02-16 22:20:37 -08:00
|
|
|
installed_alias_target_changed? ? T.must(current_installed_alias_target) : self
|
2016-09-15 16:01:18 +01:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[Formula]) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def old_installed_formulae
|
2016-09-18 23:59:55 +01:00
|
|
|
# If this formula isn't the current target of the alias,
|
|
|
|
# it doesn't make sense to say that other formulae are older versions of it
|
|
|
|
# because we don't know which came first.
|
|
|
|
return [] if alias_path.nil? || installed_alias_target_changed?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-10-20 01:50:59 +03:00
|
|
|
self.class.installed_with_alias_path(alias_path).reject { |f| f.name == name }
|
2016-09-15 16:01:18 +01:00
|
|
|
end
|
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Check whether the installed formula is outdated.
|
|
|
|
#
|
|
|
|
# @api internal
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { params(fetch_head: T::Boolean).returns(T::Boolean) }
|
2019-11-06 11:49:31 +00:00
|
|
|
def outdated?(fetch_head: false)
|
2024-03-07 16:20:20 +00:00
|
|
|
!outdated_kegs(fetch_head:).empty?
|
2015-11-27 15:11:00 +00:00
|
|
|
rescue Migrator::MigrationNeededError
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate pinnable?: :@pin
|
2013-05-21 22:41:21 -05:00
|
|
|
|
2024-04-26 20:55:51 +02:00
|
|
|
# !attr[r] pinned?
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api internal
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate pinned?: :@pin
|
2013-05-21 22:41:21 -05:00
|
|
|
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate pinned_version: :@pin
|
2015-11-16 19:23:48 +08:00
|
|
|
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate pin: :@pin
|
2013-05-21 22:41:21 -05:00
|
|
|
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate unpin: :@pin
|
2013-05-21 22:41:21 -05:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(other: T.untyped).returns(T::Boolean) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def ==(other)
|
2021-10-26 15:03:29 +01:00
|
|
|
self.class == other.class &&
|
2014-06-19 21:35:46 -05:00
|
|
|
name == other.name &&
|
2021-10-26 15:03:29 +01:00
|
|
|
active_spec_sym == other.active_spec_sym
|
2010-09-11 20:22:54 +01:00
|
|
|
end
|
2016-09-23 18:13:48 +02:00
|
|
|
alias eql? ==
|
2013-10-04 21:19:15 -05:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(Integer) }
|
2010-09-11 20:22:54 +01:00
|
|
|
def hash
|
|
|
|
name.hash
|
|
|
|
end
|
2014-07-03 14:54:14 -05:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(other: BasicObject).returns(T.nilable(Integer)) }
|
2014-07-03 14:54:14 -05:00
|
|
|
def <=>(other)
|
2025-02-16 22:20:37 -08:00
|
|
|
case other
|
|
|
|
when Formula then name <=> other.name
|
|
|
|
end
|
2010-09-11 20:22:54 +01:00
|
|
|
end
|
2014-07-03 14:54:14 -05:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2020-07-09 15:03:49 +01:00
|
|
|
def possible_names
|
2023-04-27 04:09:28 +01:00
|
|
|
[name, *oldnames, *aliases].compact
|
2020-07-09 15:03:49 +01:00
|
|
|
end
|
|
|
|
|
2024-04-26 14:04:55 +02:00
|
|
|
# @api public
|
|
|
|
sig { returns(String) }
|
|
|
|
def to_s = name
|
2014-07-01 15:13:29 -05:00
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(String) }
|
2013-03-20 22:23:36 -05:00
|
|
|
def inspect
|
2015-07-28 15:10:40 +08:00
|
|
|
"#<Formula #{name} (#{active_spec_sym}) #{path}>"
|
2013-03-20 22:23:36 -05:00
|
|
|
end
|
2010-09-11 20:22:54 +01:00
|
|
|
|
2024-07-17 17:32:37 -07:00
|
|
|
# Standard parameters for cabal-v2 builds.
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2024-07-17 17:32:37 -07:00
|
|
|
sig { returns(T::Array[String]) }
|
|
|
|
def std_cabal_v2_args
|
|
|
|
# cabal-install's dependency-resolution backtracking strategy can
|
|
|
|
# easily need more than the default 2,000 maximum number of
|
|
|
|
# "backjumps," since Hackage is a fast-moving, rolling-release
|
|
|
|
# target. The highest known needed value by a formula was 43,478
|
|
|
|
# for git-annex, so 100,000 should be enough to avoid most
|
|
|
|
# gratuitous backjumps build failures.
|
|
|
|
["--jobs=#{ENV.make_jobs}", "--max-backjumps=100000", "--install-method=copy", "--installdir=#{bin}"]
|
2020-12-17 23:49:19 +01:00
|
|
|
end
|
|
|
|
|
2020-06-22 13:24:41 +02:00
|
|
|
# Standard parameters for cargo builds.
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-25 20:20:22 -07:00
|
|
|
sig {
|
|
|
|
params(root: T.any(String, Pathname), path: T.any(String, Pathname)).returns(T::Array[String])
|
|
|
|
}
|
2021-07-19 21:26:52 -04:00
|
|
|
def std_cargo_args(root: prefix, path: ".")
|
2024-09-12 02:16:01 +08:00
|
|
|
["--jobs", ENV.make_jobs.to_s, "--locked", "--root=#{root}", "--path=#{path}"]
|
2020-06-22 13:24:41 +02:00
|
|
|
end
|
|
|
|
|
2010-09-22 08:05:58 -07:00
|
|
|
# Standard parameters for CMake builds.
|
2021-01-09 13:34:17 +11:00
|
|
|
#
|
2018-10-18 21:42:43 -04:00
|
|
|
# Setting `CMAKE_FIND_FRAMEWORK` to "LAST" tells CMake to search for our
|
2012-05-29 16:58:32 -07:00
|
|
|
# libraries before trying to utilize Frameworks, many of which will be from
|
|
|
|
# 3rd party installs.
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2021-08-10 11:55:00 +08:00
|
|
|
sig {
|
|
|
|
params(
|
|
|
|
install_prefix: T.any(String, Pathname),
|
2023-07-23 01:52:58 +08:00
|
|
|
install_libdir: T.any(String, Pathname),
|
2021-08-10 11:55:00 +08:00
|
|
|
find_framework: String,
|
|
|
|
).returns(T::Array[String])
|
|
|
|
}
|
|
|
|
def std_cmake_args(install_prefix: prefix, install_libdir: "lib", find_framework: "LAST")
|
2023-11-15 19:52:21 +00:00
|
|
|
%W[
|
2021-08-10 11:55:00 +08:00
|
|
|
-DCMAKE_INSTALL_PREFIX=#{install_prefix}
|
|
|
|
-DCMAKE_INSTALL_LIBDIR=#{install_libdir}
|
2015-03-03 15:24:51 +00:00
|
|
|
-DCMAKE_BUILD_TYPE=Release
|
2021-08-10 11:55:00 +08:00
|
|
|
-DCMAKE_FIND_FRAMEWORK=#{find_framework}
|
2013-09-05 22:54:32 -07:00
|
|
|
-DCMAKE_VERBOSE_MAKEFILE=ON
|
2024-05-15 19:53:26 -04:00
|
|
|
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=#{HOMEBREW_LIBRARY_PATH}/cmake/trap_fetchcontent_provider.cmake
|
2012-05-29 16:58:32 -07:00
|
|
|
-Wno-dev
|
2021-04-15 23:07:18 +01:00
|
|
|
-DBUILD_TESTING=OFF
|
2012-05-29 16:58:32 -07:00
|
|
|
]
|
2009-08-21 20:20:44 +01:00
|
|
|
end
|
|
|
|
|
2024-07-17 17:32:37 -07:00
|
|
|
# Standard parameters for configure builds.
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2024-07-17 17:32:37 -07:00
|
|
|
sig {
|
|
|
|
params(
|
|
|
|
prefix: T.any(String, Pathname),
|
|
|
|
libdir: T.any(String, Pathname),
|
|
|
|
).returns(T::Array[String])
|
|
|
|
}
|
|
|
|
def std_configure_args(prefix: self.prefix, libdir: "lib")
|
|
|
|
libdir = Pathname(libdir).expand_path(prefix)
|
|
|
|
["--disable-debug", "--disable-dependency-tracking", "--prefix=#{prefix}", "--libdir=#{libdir}"]
|
|
|
|
end
|
|
|
|
|
2020-01-15 12:33:55 +01:00
|
|
|
# Standard parameters for Go builds.
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2021-11-15 14:33:46 -05:00
|
|
|
sig {
|
2024-10-23 19:15:41 +02:00
|
|
|
params(
|
|
|
|
output: T.any(String, Pathname),
|
|
|
|
ldflags: T.nilable(T.any(String, T::Array[String])),
|
|
|
|
gcflags: T.nilable(T.any(String, T::Array[String])),
|
|
|
|
).returns(T::Array[String])
|
2021-11-15 14:33:46 -05:00
|
|
|
}
|
2024-10-23 19:15:41 +02:00
|
|
|
def std_go_args(output: bin/name, ldflags: nil, gcflags: nil)
|
2021-10-28 15:25:44 -04:00
|
|
|
args = ["-trimpath", "-o=#{output}"]
|
2021-11-15 14:33:46 -05:00
|
|
|
args += ["-ldflags=#{Array(ldflags).join(" ")}"] if ldflags
|
2024-10-23 19:15:41 +02:00
|
|
|
args += ["-gcflags=#{Array(gcflags).join(" ")}"] if gcflags
|
2021-03-23 16:39:01 +00:00
|
|
|
args
|
2020-01-15 12:33:55 +01:00
|
|
|
end
|
|
|
|
|
2020-04-15 12:19:02 +02:00
|
|
|
# Standard parameters for meson builds.
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(T::Array[String]) }
|
2020-04-15 12:19:02 +02:00
|
|
|
def std_meson_args
|
2020-09-08 14:58:20 +01:00
|
|
|
["--prefix=#{prefix}", "--libdir=#{lib}", "--buildtype=release", "--wrap-mode=nofallback"]
|
2020-04-15 12:19:02 +02:00
|
|
|
end
|
|
|
|
|
2024-07-15 23:36:52 -07:00
|
|
|
# Standard parameters for npm builds.
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(prefix: T.any(NilClass, String, Pathname)).returns(T::Array[String]) }
|
2024-07-15 23:36:52 -07:00
|
|
|
def std_npm_args(prefix: libexec)
|
|
|
|
require "language/node"
|
|
|
|
|
|
|
|
return Language::Node.std_npm_install_args(Pathname(prefix)) if prefix
|
|
|
|
|
|
|
|
Language::Node.local_npm_install_args
|
|
|
|
end
|
|
|
|
|
2023-07-17 20:48:40 -07:00
|
|
|
# Standard parameters for pip builds.
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2023-07-17 20:48:40 -07:00
|
|
|
sig {
|
2025-02-16 22:20:37 -08:00
|
|
|
params(prefix: T.any(FalseClass, String, Pathname),
|
2023-07-17 20:48:40 -07:00
|
|
|
build_isolation: T::Boolean).returns(T::Array[String])
|
|
|
|
}
|
|
|
|
def std_pip_args(prefix: self.prefix, build_isolation: false)
|
2023-08-25 17:23:30 -07:00
|
|
|
args = ["--verbose", "--no-deps", "--no-binary=:all:", "--ignore-installed", "--no-compile"]
|
2023-07-23 20:35:44 -07:00
|
|
|
args << "--prefix=#{prefix}" if prefix
|
2023-07-17 20:48:40 -07:00
|
|
|
args << "--no-build-isolation" unless build_isolation
|
|
|
|
args
|
|
|
|
end
|
|
|
|
|
2025-02-21 14:53:34 +01:00
|
|
|
# Standard parameters for zig builds.
|
|
|
|
#
|
|
|
|
# @api public
|
|
|
|
sig {
|
|
|
|
params(prefix: T.any(String, Pathname),
|
2025-02-21 17:07:29 +01:00
|
|
|
release_mode: Symbol).returns(T::Array[String])
|
2025-02-21 14:53:34 +01:00
|
|
|
}
|
2025-02-21 17:07:29 +01:00
|
|
|
def std_zig_args(prefix: self.prefix, release_mode: :fast)
|
|
|
|
raise ArgumentError, "Invalid Zig release mode: #{release_mode}" if [:safe, :fast, :small].exclude?(release_mode)
|
|
|
|
|
|
|
|
release_mode_downcased = release_mode.to_s.downcase
|
|
|
|
release_mode_capitalized = release_mode.to_s.capitalize
|
2025-02-21 16:49:11 +01:00
|
|
|
[
|
|
|
|
"--prefix", prefix.to_s,
|
|
|
|
"--release=#{release_mode_downcased}",
|
|
|
|
"-Doptimize=Release#{release_mode_capitalized}",
|
2025-02-21 17:07:29 +01:00
|
|
|
"--summary", "all"
|
2025-02-21 16:49:11 +01:00
|
|
|
]
|
2025-02-21 14:53:34 +01:00
|
|
|
end
|
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# Shared library names according to platform conventions.
|
|
|
|
#
|
|
|
|
# Optionally specify a `version` to restrict the shared library to a specific
|
|
|
|
# version. The special string "*" matches any version.
|
|
|
|
#
|
|
|
|
# If `name` is specified as "*", match any shared library of any version.
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# shared_library("foo") #=> foo.dylib
|
2021-01-09 13:34:17 +11:00
|
|
|
# shared_library("foo", 1) #=> foo.1.dylib
|
|
|
|
# shared_library("foo", "*") #=> foo.2.dylib, foo.1.dylib, foo.dylib
|
|
|
|
# shared_library("*") #=> foo.dylib, bar.dylib
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2021-01-09 13:34:17 +11:00
|
|
|
sig { params(name: String, version: T.nilable(T.any(String, Integer))).returns(String) }
|
2020-06-16 18:25:13 +02:00
|
|
|
def shared_library(name, version = nil)
|
2020-12-24 08:18:32 -08:00
|
|
|
return "*.dylib" if name == "*" && (version.blank? || version == "*")
|
|
|
|
|
|
|
|
infix = if version == "*"
|
|
|
|
"{,.*}"
|
|
|
|
elsif version.present?
|
|
|
|
".#{version}"
|
|
|
|
end
|
|
|
|
"#{name}#{infix}.dylib"
|
2020-06-16 18:25:13 +02:00
|
|
|
end
|
|
|
|
|
2021-04-19 09:23:33 +01:00
|
|
|
# Executable/Library RPATH according to platform conventions.
|
2022-08-19 17:32:43 +08:00
|
|
|
#
|
|
|
|
# Optionally specify a `source` or `target` depending on the location
|
|
|
|
# of the file containing the RPATH command and where its target is located.
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# rpath #=> "@loader_path/../lib"
|
2022-08-19 17:32:43 +08:00
|
|
|
# rpath(target: frameworks) #=> "@loader_path/../Frameworks"
|
|
|
|
# rpath(source: libexec/"bin") #=> "@loader_path/../../lib"
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2022-08-19 17:32:43 +08:00
|
|
|
sig { params(source: Pathname, target: Pathname).returns(String) }
|
|
|
|
def rpath(source: bin, target: lib)
|
2022-10-08 00:15:37 +08:00
|
|
|
unless target.to_s.start_with?(HOMEBREW_PREFIX)
|
2022-10-08 11:43:43 +08:00
|
|
|
raise "rpath `target` should only be used for paths inside HOMEBREW_PREFIX!"
|
2022-10-08 00:15:37 +08:00
|
|
|
end
|
|
|
|
|
2022-08-19 17:32:43 +08:00
|
|
|
"#{loader_path}/#{target.relative_path_from(source)}"
|
|
|
|
end
|
|
|
|
|
2024-10-16 11:54:21 -04:00
|
|
|
# Linker variable for the directory containing the program or shared object.
|
|
|
|
#
|
|
|
|
# @api public
|
2021-04-19 09:23:33 +01:00
|
|
|
sig { returns(String) }
|
2022-08-19 17:32:43 +08:00
|
|
|
def loader_path
|
|
|
|
"@loader_path"
|
2021-04-19 09:23:33 +01:00
|
|
|
end
|
|
|
|
|
2021-07-06 12:26:03 +01:00
|
|
|
# Creates a new `Time` object for use in the formula as the build time.
|
|
|
|
#
|
|
|
|
# @see https://www.rubydoc.info/stdlib/time/Time Time
|
|
|
|
sig { returns(Time) }
|
|
|
|
def time
|
|
|
|
if ENV["SOURCE_DATE_EPOCH"].present?
|
|
|
|
Time.at(ENV["SOURCE_DATE_EPOCH"].to_i).utc
|
|
|
|
else
|
|
|
|
Time.now.utc
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-07-24 19:39:47 +08:00
|
|
|
# Replaces a universal binary with its native slice.
|
|
|
|
#
|
|
|
|
# If called with no parameters, does this with all compatible
|
|
|
|
# universal binaries in a {Formula}'s {Keg}.
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
2024-12-10 09:24:27 -05:00
|
|
|
# Raises an error if no universal binaries are found to deuniversalize.
|
|
|
|
#
|
2024-10-16 11:54:21 -04:00
|
|
|
# @api public
|
2021-07-22 00:43:46 +08:00
|
|
|
sig { params(targets: T.nilable(T.any(Pathname, String))).void }
|
|
|
|
def deuniversalize_machos(*targets)
|
2024-04-28 03:23:21 +02:00
|
|
|
if targets.none?
|
|
|
|
targets = any_installed_keg&.mach_o_files&.select do |file|
|
|
|
|
file.arch == :universal && file.archs.include?(Hardware::CPU.arch)
|
|
|
|
end
|
2021-07-22 00:43:46 +08:00
|
|
|
end
|
|
|
|
|
2024-12-10 09:24:27 -05:00
|
|
|
raise "No universal binaries found to deuniversalize" if targets.blank?
|
|
|
|
|
2024-04-28 03:23:21 +02:00
|
|
|
targets&.each do |target|
|
|
|
|
extract_macho_slice_from(Pathname(target), Hardware::CPU.arch)
|
|
|
|
end
|
2021-07-24 19:39:47 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
sig { params(file: Pathname, arch: T.nilable(Symbol)).void }
|
2021-07-25 11:29:33 +08:00
|
|
|
def extract_macho_slice_from(file, arch = Hardware::CPU.arch)
|
2021-07-24 19:39:47 +08:00
|
|
|
odebug "Extracting #{arch} slice from #{file}"
|
|
|
|
file.ensure_writable do
|
|
|
|
macho = MachO::FatFile.new(file)
|
2021-07-22 00:43:46 +08:00
|
|
|
native_slice = macho.extract(Hardware::CPU.arch)
|
2021-07-24 19:39:47 +08:00
|
|
|
native_slice.write file
|
2021-07-25 23:21:26 +08:00
|
|
|
MachO.codesign! file if Hardware::CPU.arm?
|
2021-07-24 19:39:47 +08:00
|
|
|
rescue MachO::MachOBinaryError
|
|
|
|
onoe "#{file} is not a universal binary"
|
|
|
|
raise
|
|
|
|
rescue NoMethodError
|
|
|
|
onoe "#{file} does not contain an #{arch} slice"
|
|
|
|
raise
|
2021-07-22 00:43:46 +08:00
|
|
|
end
|
|
|
|
end
|
2021-08-18 11:51:08 +08:00
|
|
|
private :extract_macho_slice_from
|
2021-07-22 00:43:46 +08:00
|
|
|
|
2024-04-26 20:55:51 +02:00
|
|
|
# Generate shell completions for a formula for `bash`, `zsh` and `fish`, using the formula's executable.
|
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# Using default values for optional arguments.
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# generate_completions_from_executable(bin/"foo", "completions")
|
|
|
|
#
|
|
|
|
# # translates to
|
|
|
|
# (bash_completion/"foo").write Utils.safe_popen_read({ "SHELL" => "bash" }, bin/"foo", "completions", "bash")
|
|
|
|
# (zsh_completion/"_foo").write Utils.safe_popen_read({ "SHELL" => "zsh" }, bin/"foo", "completions", "zsh")
|
|
|
|
# (fish_completion/"foo.fish").write Utils.safe_popen_read({ "SHELL" => "fish" }, bin/"foo",
|
|
|
|
# "completions", "fish")
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# Selecting shells and using a different `base_name`.
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# generate_completions_from_executable(bin/"foo", "completions", shells: [:bash, :zsh], base_name: "bar")
|
|
|
|
#
|
|
|
|
# # translates to
|
|
|
|
# (bash_completion/"bar").write Utils.safe_popen_read({ "SHELL" => "bash" }, bin/"foo", "completions", "bash")
|
|
|
|
# (zsh_completion/"_bar").write Utils.safe_popen_read({ "SHELL" => "zsh" }, bin/"foo", "completions", "zsh")
|
|
|
|
# ```
|
2022-07-11 15:35:48 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# Using predefined `shell_parameter_format :flag`.
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# generate_completions_from_executable(bin/"foo", "completions", shell_parameter_format: :flag, shells: [:bash])
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# # translates to
|
|
|
|
# (bash_completion/"foo").write Utils.safe_popen_read({ "SHELL" => "bash" }, bin/"foo", "completions", "--bash")
|
|
|
|
# ```
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# Using predefined `shell_parameter_format :arg`.
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# generate_completions_from_executable(bin/"foo", "completions", shell_parameter_format: :arg, shells: [:bash])
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# # translates to
|
|
|
|
# (bash_completion/"foo").write Utils.safe_popen_read({ "SHELL" => "bash" }, bin/"foo",
|
|
|
|
# "completions", "--shell=bash")
|
|
|
|
# ```
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# Using predefined `shell_parameter_format :none`.
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# generate_completions_from_executable(bin/"foo", "completions", shell_parameter_format: :none, shells: [:bash])
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# # translates to
|
|
|
|
# (bash_completion/"foo").write Utils.safe_popen_read({ "SHELL" => "bash" }, bin/"foo", "completions")
|
|
|
|
# ```
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# Using predefined `shell_parameter_format :click`.
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# generate_completions_from_executable(bin/"foo", shell_parameter_format: :click, shells: [:zsh])
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# # translates to
|
|
|
|
# (zsh_completion/"_foo").write Utils.safe_popen_read({ "SHELL" => "zsh", "_FOO_COMPLETE" => "zsh_source" },
|
|
|
|
# bin/"foo")
|
|
|
|
# ```
|
2022-11-15 12:32:05 -08:00
|
|
|
#
|
2024-12-17 07:52:45 +09:00
|
|
|
# Using predefined `shell_parameter_format :clap`.
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# generate_completions_from_executable(bin/"foo", shell_parameter_format: :clap, shells: [:zsh])
|
|
|
|
#
|
|
|
|
# # translates to
|
|
|
|
# (zsh_completion/"_foo").write Utils.safe_popen_read({ "SHELL" => "zsh", "COMPLETE" => "zsh" }, bin/"foo")
|
|
|
|
# ```
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# Using custom `shell_parameter_format`.
|
2022-11-15 12:32:05 -08:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# generate_completions_from_executable(bin/"foo", "completions", shell_parameter_format: "--selected-shell=",
|
|
|
|
# shells: [:bash])
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# # translates to
|
|
|
|
# (bash_completion/"foo").write Utils.safe_popen_read({ "SHELL" => "bash" }, bin/"foo",
|
|
|
|
# "completions", "--selected-shell=bash")
|
|
|
|
# ```
|
|
|
|
#
|
2024-10-16 11:54:21 -04:00
|
|
|
# @api public
|
|
|
|
# @param commands
|
2024-04-26 20:55:51 +02:00
|
|
|
# the path to the executable and any passed subcommand(s) to use for generating the completion scripts.
|
2024-10-16 11:54:21 -04:00
|
|
|
# @param base_name
|
2024-12-15 11:09:05 -05:00
|
|
|
# the base name of the generated completion script. Defaults to the name of the executable if installed
|
|
|
|
# within formula's bin or sbin. Otherwise falls back to the formula name.
|
2024-10-16 11:54:21 -04:00
|
|
|
# @param shells
|
2024-04-26 20:55:51 +02:00
|
|
|
# the shells to generate completion scripts for. Defaults to `[:bash, :zsh, :fish]`.
|
2024-10-16 11:54:21 -04:00
|
|
|
# @param shell_parameter_format
|
2024-04-26 20:55:51 +02:00
|
|
|
# specify how `shells` should each be passed to the `executable`. Takes either a String representing a
|
2024-12-17 07:52:45 +09:00
|
|
|
# prefix, or one of `[:flag, :arg, :none, :click, :clap]`. Defaults to plainly passing the shell.
|
2022-07-11 15:21:57 +02:00
|
|
|
sig {
|
2024-04-26 20:55:51 +02:00
|
|
|
params(
|
2024-12-15 11:09:05 -05:00
|
|
|
commands: T.any(Pathname, String),
|
|
|
|
base_name: T.nilable(String),
|
|
|
|
shells: T::Array[Symbol],
|
|
|
|
shell_parameter_format: T.nilable(T.any(Symbol, String)),
|
2024-04-26 20:55:51 +02:00
|
|
|
).void
|
2022-07-11 15:21:57 +02:00
|
|
|
}
|
2022-08-11 18:12:08 +02:00
|
|
|
def generate_completions_from_executable(*commands,
|
2024-12-15 11:09:05 -05:00
|
|
|
base_name: nil,
|
2022-07-24 22:54:28 +02:00
|
|
|
shells: [:bash, :zsh, :fish],
|
2022-07-24 23:03:28 +02:00
|
|
|
shell_parameter_format: nil)
|
2024-12-15 11:09:05 -05:00
|
|
|
executable = commands.first.to_s
|
|
|
|
base_name ||= File.basename(executable) if executable.start_with?(bin.to_s, sbin.to_s)
|
|
|
|
base_name ||= name
|
|
|
|
|
2022-07-10 15:24:14 +02:00
|
|
|
completion_script_path_map = {
|
2022-07-10 15:45:07 +02:00
|
|
|
bash: bash_completion/base_name,
|
|
|
|
zsh: zsh_completion/"_#{base_name}",
|
|
|
|
fish: fish_completion/"#{base_name}.fish",
|
2022-07-10 15:24:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
shells.each do |shell|
|
2022-11-15 12:32:05 -08:00
|
|
|
popen_read_env = { "SHELL" => shell.to_s }
|
2022-07-10 15:24:14 +02:00
|
|
|
script_path = completion_script_path_map[shell]
|
2022-07-24 23:03:28 +02:00
|
|
|
shell_parameter = if shell_parameter_format.nil?
|
2022-07-13 14:11:17 +02:00
|
|
|
shell.to_s
|
2022-07-24 23:03:28 +02:00
|
|
|
elsif shell_parameter_format == :flag
|
2022-07-13 14:11:17 +02:00
|
|
|
"--#{shell}"
|
2022-07-24 23:03:28 +02:00
|
|
|
elsif shell_parameter_format == :arg
|
|
|
|
"--shell=#{shell}"
|
|
|
|
elsif shell_parameter_format == :none
|
2022-09-02 15:40:24 +02:00
|
|
|
nil
|
2022-11-15 12:32:05 -08:00
|
|
|
elsif shell_parameter_format == :click
|
2024-12-15 11:09:05 -05:00
|
|
|
prog_name = File.basename(executable).upcase.tr("-", "_")
|
2022-11-15 12:32:05 -08:00
|
|
|
popen_read_env["_#{prog_name}_COMPLETE"] = "#{shell}_source"
|
|
|
|
nil
|
2024-12-17 07:52:45 +09:00
|
|
|
elsif shell_parameter_format == :clap
|
|
|
|
popen_read_env["COMPLETE"] = shell.to_s
|
|
|
|
nil
|
2022-07-13 14:11:17 +02:00
|
|
|
else
|
2022-07-24 23:03:28 +02:00
|
|
|
"#{shell_parameter_format}#{shell}"
|
2022-07-13 14:11:17 +02:00
|
|
|
end
|
|
|
|
|
2022-08-11 21:32:03 +02:00
|
|
|
popen_read_args = %w[]
|
|
|
|
popen_read_args << commands
|
2022-09-02 22:26:58 +02:00
|
|
|
popen_read_args << shell_parameter if shell_parameter.present?
|
2022-08-11 21:32:03 +02:00
|
|
|
popen_read_args.flatten!
|
|
|
|
|
2022-12-19 20:09:23 -08:00
|
|
|
popen_read_options = {}
|
|
|
|
popen_read_options[:err] = :err unless ENV["HOMEBREW_STDERR"]
|
|
|
|
|
2022-07-10 15:24:14 +02:00
|
|
|
script_path.dirname.mkpath
|
2022-12-19 20:09:23 -08:00
|
|
|
script_path.write Utils.safe_popen_read(popen_read_env, *popen_read_args, **popen_read_options)
|
2022-07-10 15:24:14 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-05-08 19:54:29 +08:00
|
|
|
# an array of all core {Formula} names
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2015-05-08 19:54:29 +08:00
|
|
|
def self.core_names
|
2016-03-07 18:04:25 +08:00
|
|
|
CoreTap.instance.formula_names
|
2015-05-08 19:54:29 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# an array of all tap {Formula} names
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2015-05-08 19:54:29 +08:00
|
|
|
def self.tap_names
|
2025-02-16 22:20:37 -08:00
|
|
|
@tap_names ||= T.let(Tap.reject(&:core_tap?).flat_map(&:formula_names).sort, T.nilable(T::Array[String]))
|
2015-05-08 19:54:29 +08:00
|
|
|
end
|
|
|
|
|
2015-08-01 00:02:19 +08:00
|
|
|
# an array of all tap {Formula} files
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[Pathname]) }
|
2015-08-01 00:02:19 +08:00
|
|
|
def self.tap_files
|
2025-02-16 22:20:37 -08:00
|
|
|
@tap_files ||= T.let(Tap.reject(&:core_tap?).flat_map(&:formula_files), T.nilable(T::Array[Pathname]))
|
2015-08-01 00:02:19 +08:00
|
|
|
end
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# an array of all {Formula} names
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2010-03-09 02:18:08 +00:00
|
|
|
def self.names
|
2025-02-16 22:20:37 -08:00
|
|
|
@names ||= T.let((core_names + tap_names.map do |name|
|
|
|
|
name.split("/").fetch(-1)
|
|
|
|
end).uniq.sort, T.nilable(T::Array[String]))
|
2015-05-08 19:54:29 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# an array of all {Formula} names, which the tap formulae have the fully-qualified name
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2015-05-08 19:54:29 +08:00
|
|
|
def self.full_names
|
2025-02-16 22:20:37 -08:00
|
|
|
@full_names ||= T.let(core_names + tap_names, T.nilable(T::Array[String]))
|
2010-03-09 02:18:08 +00:00
|
|
|
end
|
|
|
|
|
2022-01-03 14:59:10 +00:00
|
|
|
# an array of all {Formula}
|
2022-03-08 19:24:55 +00:00
|
|
|
# this should only be used when users specify `--all` to a command
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(eval_all: T::Boolean).returns(T::Array[Formula]) }
|
2023-09-02 19:35:22 +09:00
|
|
|
def self.all(eval_all: false)
|
2023-12-07 22:58:54 +00:00
|
|
|
if !eval_all && !Homebrew::EnvConfig.eval_all?
|
2024-02-04 15:19:29 +01:00
|
|
|
raise ArgumentError, "Formula#all without `--eval-all` or HOMEBREW_EVAL_ALL"
|
2023-12-07 22:58:54 +00:00
|
|
|
end
|
2022-03-08 19:24:55 +00:00
|
|
|
|
2024-02-22 23:29:55 +00:00
|
|
|
(core_names + tap_files).filter_map do |name_or_file|
|
2023-06-28 15:27:20 +01:00
|
|
|
Formulary.factory(name_or_file)
|
2020-09-03 19:34:25 +02:00
|
|
|
rescue FormulaUnavailableError, FormulaUnreadableError => e
|
|
|
|
# Don't let one broken formula break commands. But do complain.
|
2023-06-28 15:27:20 +01:00
|
|
|
onoe "Failed to import: #{name_or_file}"
|
2020-09-03 19:34:25 +02:00
|
|
|
$stderr.puts e
|
2022-01-03 14:59:10 +00:00
|
|
|
|
|
|
|
nil
|
2024-02-22 23:29:55 +00:00
|
|
|
end
|
2010-09-11 20:22:54 +01:00
|
|
|
end
|
2012-08-10 16:05:30 -04:00
|
|
|
|
2015-08-13 20:35:22 +08:00
|
|
|
# An array of all racks currently installed.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[Pathname]) }
|
2015-08-13 20:35:22 +08:00
|
|
|
def self.racks
|
2020-10-29 08:31:04 +00:00
|
|
|
Formula.cache[:racks] ||= if HOMEBREW_CELLAR.directory?
|
2015-11-11 14:14:58 +08:00
|
|
|
HOMEBREW_CELLAR.subdirs.reject do |rack|
|
2018-01-19 15:07:04 -08:00
|
|
|
rack.symlink? || rack.basename.to_s.start_with?(".") || rack.subdirs.empty?
|
2015-11-11 14:14:58 +08:00
|
|
|
end
|
2015-06-20 14:46:24 +08:00
|
|
|
else
|
|
|
|
[]
|
|
|
|
end
|
2012-08-10 16:05:30 -04:00
|
|
|
end
|
|
|
|
|
2023-12-13 13:54:37 +00:00
|
|
|
# An array of all currently installed formula names.
|
|
|
|
sig { returns(T::Array[String]) }
|
|
|
|
def self.installed_formula_names
|
2023-12-14 02:52:30 +00:00
|
|
|
racks.map { |rack| rack.basename.to_s }
|
2023-12-13 13:54:37 +00:00
|
|
|
end
|
|
|
|
|
2015-08-13 20:35:22 +08:00
|
|
|
# An array of all installed {Formula}
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[Formula]) }
|
2015-08-13 20:35:22 +08:00
|
|
|
def self.installed
|
2020-10-29 08:31:04 +00:00
|
|
|
Formula.cache[:installed] ||= racks.flat_map do |rack|
|
2019-10-13 10:03:26 +01:00
|
|
|
Formulary.from_rack(rack)
|
|
|
|
rescue
|
|
|
|
[]
|
2017-10-07 00:31:28 +02:00
|
|
|
end.uniq(&:name)
|
2015-08-13 20:35:22 +08:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(alias_path: T.nilable(Pathname)).returns(T::Array[Formula]) }
|
2016-09-15 16:01:18 +01:00
|
|
|
def self.installed_with_alias_path(alias_path)
|
|
|
|
return [] if alias_path.nil?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-09-15 16:01:18 +01:00
|
|
|
installed.select { |f| f.installed_alias_path == alias_path }
|
|
|
|
end
|
|
|
|
|
2015-09-27 15:57:37 +08:00
|
|
|
# an array of all alias files of core {Formula}
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[Pathname]) }
|
2015-09-27 15:57:37 +08:00
|
|
|
def self.core_alias_files
|
2016-03-07 18:04:25 +08:00
|
|
|
CoreTap.instance.alias_files
|
2015-09-27 15:57:37 +08:00
|
|
|
end
|
|
|
|
|
2015-09-12 19:14:38 +08:00
|
|
|
# an array of all core aliases
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2015-09-12 19:14:38 +08:00
|
|
|
def self.core_aliases
|
2016-03-07 18:04:25 +08:00
|
|
|
CoreTap.instance.aliases
|
2015-09-12 19:14:38 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# an array of all tap aliases
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2015-09-12 19:14:38 +08:00
|
|
|
def self.tap_aliases
|
2025-02-16 22:20:37 -08:00
|
|
|
@tap_aliases ||= T.let(Tap.reject(&:core_tap?).flat_map(&:aliases).sort, T.nilable(T::Array[String]))
|
2015-09-12 19:14:38 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# an array of all aliases
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2010-03-09 02:18:08 +00:00
|
|
|
def self.aliases
|
2025-02-16 22:20:37 -08:00
|
|
|
@aliases ||= T.let((core_aliases + tap_aliases.map do |name|
|
|
|
|
name.split("/").fetch(-1)
|
|
|
|
end).uniq.sort, T.nilable(T::Array[String]))
|
2015-09-13 17:23:17 +08:00
|
|
|
end
|
|
|
|
|
2022-03-23 00:03:11 -04:00
|
|
|
# an array of all aliases as fully-qualified names
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2015-09-13 17:23:17 +08:00
|
|
|
def self.alias_full_names
|
2025-02-16 22:20:37 -08:00
|
|
|
@alias_full_names ||= T.let(core_aliases + tap_aliases, T.nilable(T::Array[String]))
|
2009-11-16 15:35:58 -08:00
|
|
|
end
|
2009-08-21 20:20:44 +01:00
|
|
|
|
2021-06-19 00:14:33 +01:00
|
|
|
# Returns a list of approximately matching formula names, but not the complete match
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(name: String).returns(T::Array[String]) }
|
2021-06-19 00:14:33 +01:00
|
|
|
def self.fuzzy_search(name)
|
2025-02-16 22:20:37 -08:00
|
|
|
@spell_checker ||= T.let(DidYouMean::SpellChecker.new(dictionary: Set.new(names + full_names).to_a),
|
|
|
|
T.nilable(DidYouMean::SpellChecker))
|
|
|
|
T.cast(@spell_checker.correct(name), T::Array[String])
|
2021-06-19 00:14:33 +01:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(name: T.any(Pathname, String)).returns(Formula) }
|
2014-02-24 20:25:16 -08:00
|
|
|
def self.[](name)
|
|
|
|
Formulary.factory(name)
|
|
|
|
end
|
|
|
|
|
2015-12-06 22:16:08 +08:00
|
|
|
# True if this formula is provided by Homebrew itself
|
2023-07-24 06:55:41 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2015-12-06 22:16:08 +08:00
|
|
|
def core_formula?
|
2023-07-24 06:55:41 -07:00
|
|
|
!!tap&.core_tap?
|
2013-10-29 15:46:10 -04:00
|
|
|
end
|
|
|
|
|
2015-12-06 22:16:08 +08:00
|
|
|
# True if this formula is provided by external Tap
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2015-12-06 22:16:08 +08:00
|
|
|
def tap?
|
2017-09-24 20:12:58 +01:00
|
|
|
return false unless tap
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2023-07-24 14:01:53 -07:00
|
|
|
!T.must(tap).core_tap?
|
2012-03-16 12:29:47 +00:00
|
|
|
end
|
|
|
|
|
2023-03-27 19:35:28 -07:00
|
|
|
# True if this formula can be installed on this platform
|
|
|
|
# Redefined in extend/os.
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2023-03-27 19:35:28 -07:00
|
|
|
def valid_platform?
|
|
|
|
requirements.none?(MacOSRequirement) && requirements.none?(LinuxRequirement)
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(options: T::Hash[Symbol, String]).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def print_tap_action(options = {})
|
2016-09-23 22:02:23 +02:00
|
|
|
return unless tap?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-09-23 22:02:23 +02:00
|
|
|
verb = options[:verb] || "Installing"
|
|
|
|
ohai "#{verb} #{name} from #{tap}"
|
2014-10-19 13:54:00 +01:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(String)) }
|
2023-02-06 13:06:11 +00:00
|
|
|
def tap_git_head
|
|
|
|
tap&.git_head
|
2024-07-15 13:47:21 -04:00
|
|
|
rescue TapUnavailableError
|
|
|
|
nil
|
2023-02-06 13:06:11 +00:00
|
|
|
end
|
|
|
|
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate env: :"self.class"
|
2012-09-14 07:54:14 -07:00
|
|
|
|
2024-04-26 20:55:51 +02:00
|
|
|
# !attr[r] conflicts
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api internal
|
2024-04-26 20:55:51 +02:00
|
|
|
sig { returns(T::Array[FormulaConflict]) }
|
2025-02-16 22:20:37 -08:00
|
|
|
def conflicts = T.must(self.class.conflicts)
|
2012-08-07 14:22:20 -05:00
|
|
|
|
2013-01-23 00:26:26 -06:00
|
|
|
# Returns a list of Dependency objects in an installable order, which
|
|
|
|
# means if a depends on b then b will be ordered before a in this list
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(block: T.nilable(T.proc.params(arg0: Formula, arg1: Dependency).void)).returns(T::Array[Dependency]) }
|
2013-01-23 00:26:26 -06:00
|
|
|
def recursive_dependencies(&block)
|
2021-03-19 03:21:27 +00:00
|
|
|
cache_key = "Formula#recursive_dependencies" unless block
|
2024-03-07 16:20:20 +00:00
|
|
|
Dependency.expand(self, cache_key:, &block)
|
2010-01-13 09:00:24 +00:00
|
|
|
end
|
|
|
|
|
2013-01-23 00:26:24 -06:00
|
|
|
# The full set of Requirements for this formula's dependency tree.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(block: T.nilable(T.proc.params(arg0: Formula, arg1: Requirement).void)).returns(Requirements) }
|
2013-01-30 17:55:04 -06:00
|
|
|
def recursive_requirements(&block)
|
2021-03-19 03:21:27 +00:00
|
|
|
cache_key = "Formula#recursive_requirements" unless block
|
2024-03-07 16:20:20 +00:00
|
|
|
Requirement.expand(self, cache_key:, &block)
|
2012-08-14 21:45:08 -05:00
|
|
|
end
|
|
|
|
|
2018-04-25 11:44:29 +01:00
|
|
|
# Returns a Keg for the opt_prefix or installed_prefix if they exist.
|
2020-11-05 17:17:03 -05:00
|
|
|
# If not, return `nil`.
|
2024-04-28 03:23:21 +02:00
|
|
|
sig { returns(T.nilable(Keg)) }
|
2020-08-31 10:58:36 -07:00
|
|
|
def any_installed_keg
|
|
|
|
Formula.cache[:any_installed_keg] ||= {}
|
|
|
|
Formula.cache[:any_installed_keg][full_name] ||= if (installed_prefix = any_installed_prefix)
|
|
|
|
Keg.new(installed_prefix)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-04-22 21:05:48 +02:00
|
|
|
# Get the path of any installed prefix.
|
|
|
|
#
|
|
|
|
# @api internal
|
|
|
|
sig { returns(T.nilable(Pathname)) }
|
2020-08-31 10:58:36 -07:00
|
|
|
def any_installed_prefix
|
|
|
|
if optlinked? && opt_prefix.exist?
|
|
|
|
opt_prefix
|
2020-07-09 23:04:15 +01:00
|
|
|
elsif (latest_installed_prefix = installed_prefixes.last)
|
2020-08-31 10:58:36 -07:00
|
|
|
latest_installed_prefix
|
2018-04-25 11:44:29 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# Returns the {PkgVersion} for this formula if it is installed.
|
|
|
|
# If not, return `nil`.
|
2025-02-19 14:51:36 -05:00
|
|
|
sig { returns(T.nilable(PkgVersion)) }
|
2020-08-31 10:59:27 -07:00
|
|
|
def any_installed_version
|
|
|
|
any_installed_keg&.version
|
|
|
|
end
|
|
|
|
|
2016-09-19 20:53:39 +01:00
|
|
|
# Returns a list of Dependency objects that are required at runtime.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api internal
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(read_from_tab: T::Boolean, undeclared: T::Boolean).returns(T::Array[Dependency]) }
|
2018-07-05 20:29:19 +01:00
|
|
|
def runtime_dependencies(read_from_tab: true, undeclared: true)
|
2019-11-05 20:34:06 +00:00
|
|
|
deps = if read_from_tab && undeclared &&
|
2020-08-31 10:58:36 -07:00
|
|
|
(tab_deps = any_installed_keg&.runtime_dependencies)
|
2024-02-22 23:29:55 +00:00
|
|
|
tab_deps.filter_map do |d|
|
2018-06-01 19:53:26 +01:00
|
|
|
full_name = d["full_name"]
|
|
|
|
next unless full_name
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2018-06-01 19:53:26 +01:00
|
|
|
Dependency.new full_name
|
2024-02-22 23:29:55 +00:00
|
|
|
end
|
2018-03-12 09:20:24 +00:00
|
|
|
end
|
2019-12-10 16:56:10 +00:00
|
|
|
begin
|
|
|
|
deps ||= declared_runtime_dependencies unless undeclared
|
|
|
|
deps ||= (declared_runtime_dependencies | undeclared_runtime_dependencies)
|
|
|
|
rescue FormulaUnavailableError
|
2020-07-29 17:31:11 -04:00
|
|
|
onoe "Could not get runtime dependencies from #{path}!"
|
2019-12-10 16:56:10 +00:00
|
|
|
deps ||= []
|
|
|
|
end
|
2019-11-05 20:34:06 +00:00
|
|
|
deps
|
2018-03-12 09:20:24 +00:00
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Returns a list of {Formula} objects that are required at runtime.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(read_from_tab: T::Boolean, undeclared: T::Boolean).returns(T::Array[Formula]) }
|
2018-07-16 16:46:39 +01:00
|
|
|
def runtime_formula_dependencies(read_from_tab: true, undeclared: true)
|
2020-08-02 13:43:32 +01:00
|
|
|
cache_key = "#{full_name}-#{read_from_tab}-#{undeclared}"
|
2019-11-05 20:34:06 +00:00
|
|
|
|
|
|
|
Formula.cache[:runtime_formula_dependencies] ||= {}
|
|
|
|
Formula.cache[:runtime_formula_dependencies][cache_key] ||= runtime_dependencies(
|
2024-03-07 16:20:20 +00:00
|
|
|
read_from_tab:,
|
|
|
|
undeclared:,
|
2024-02-22 23:29:55 +00:00
|
|
|
).filter_map do |d|
|
2019-10-13 10:03:26 +01:00
|
|
|
d.to_formula
|
|
|
|
rescue FormulaUnavailableError
|
|
|
|
nil
|
2024-02-22 23:29:55 +00:00
|
|
|
end
|
2018-03-12 09:20:24 +00:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[Formula]) }
|
2019-11-05 20:34:24 +00:00
|
|
|
def runtime_installed_formula_dependents
|
2020-08-31 10:58:36 -07:00
|
|
|
# `any_installed_keg` and `runtime_dependencies` `select`s ensure
|
2019-11-05 20:34:24 +00:00
|
|
|
# that we don't end up with something `Formula#runtime_dependencies` can't
|
|
|
|
# read from a `Tab`.
|
2022-08-18 15:14:44 -07:00
|
|
|
Formula.cache[:runtime_installed_formula_dependents] ||= {}
|
2020-08-02 13:43:32 +01:00
|
|
|
Formula.cache[:runtime_installed_formula_dependents][full_name] ||= Formula.installed
|
2020-08-31 10:58:36 -07:00
|
|
|
.select(&:any_installed_keg)
|
2020-08-02 13:43:32 +01:00
|
|
|
.select(&:runtime_dependencies)
|
|
|
|
.select do |f|
|
2019-11-05 20:34:24 +00:00
|
|
|
f.runtime_formula_dependencies.any? do |dep|
|
|
|
|
full_name == dep.full_name
|
|
|
|
rescue
|
|
|
|
name == dep.name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-10-05 20:56:07 +01:00
|
|
|
# Returns a list of formulae depended on by this formula that aren't
|
2020-11-05 17:17:03 -05:00
|
|
|
# installed.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(hide: T::Array[String]).returns(T::Array[Formula]) }
|
|
|
|
def missing_dependencies(hide: [])
|
2018-07-16 16:46:39 +01:00
|
|
|
runtime_formula_dependencies.select do |f|
|
|
|
|
hide.include?(f.name) || f.installed_prefixes.empty?
|
2016-10-05 20:56:07 +01:00
|
|
|
end
|
2018-07-17 14:59:50 +01:00
|
|
|
# If we're still getting unavailable formulae at this stage the best we can
|
|
|
|
# do is just return no results.
|
|
|
|
rescue FormulaUnavailableError
|
|
|
|
[]
|
2016-10-05 20:56:07 +01:00
|
|
|
end
|
|
|
|
|
2023-04-18 00:22:13 +01:00
|
|
|
sig { returns(T.nilable(String)) }
|
|
|
|
def ruby_source_path
|
2023-07-24 14:01:53 -07:00
|
|
|
path.relative_path_from(T.must(tap).path).to_s if tap && path.exist?
|
2023-04-18 00:22:13 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
sig { returns(T.nilable(Checksum)) }
|
|
|
|
def ruby_source_checksum
|
|
|
|
Checksum.new(Digest::SHA256.file(path).hexdigest) if path.exist?
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(dependables: T::Hash[Symbol, T.untyped]).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
2023-06-19 06:07:53 +01:00
|
|
|
def merge_spec_dependables(dependables)
|
|
|
|
# We have a hash of specs names (stable/head) to dependency lists.
|
|
|
|
# Merge all of the dependency lists together, removing any duplicates.
|
|
|
|
all_dependables = [].union(*dependables.values.map(&:to_a))
|
|
|
|
|
|
|
|
all_dependables.map do |dependable|
|
|
|
|
{
|
2024-03-07 16:20:20 +00:00
|
|
|
dependable:,
|
2023-06-19 06:07:53 +01:00
|
|
|
# Now find the list of specs each dependency was a part of.
|
2024-02-22 23:29:55 +00:00
|
|
|
specs: dependables.filter_map { |spec, spec_deps| spec if spec_deps&.include?(dependable) },
|
2023-06-19 06:07:53 +01:00
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
private :merge_spec_dependables
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Hash[String, T.untyped]) }
|
2012-08-15 22:08:40 -05:00
|
|
|
def to_hash
|
|
|
|
hsh = {
|
2018-11-02 17:18:07 +00:00
|
|
|
"name" => name,
|
|
|
|
"full_name" => full_name,
|
2021-02-07 19:00:07 +01:00
|
|
|
"tap" => tap&.name,
|
2023-04-27 04:09:28 +01:00
|
|
|
"oldnames" => oldnames,
|
2018-11-02 17:18:07 +00:00
|
|
|
"aliases" => aliases.sort,
|
|
|
|
"versioned_formulae" => versioned_formulae.map(&:name),
|
|
|
|
"desc" => desc,
|
2020-09-11 13:10:42 +01:00
|
|
|
"license" => SPDX.license_expression_to_string(license),
|
2018-11-02 17:18:07 +00:00
|
|
|
"homepage" => homepage,
|
|
|
|
"versions" => {
|
2017-11-02 07:26:00 -07:00
|
|
|
"stable" => stable&.version&.to_s,
|
2018-11-02 17:18:07 +00:00
|
|
|
"head" => head&.version&.to_s,
|
2023-09-28 14:07:25 +01:00
|
|
|
"bottle" => bottle_defined?,
|
2012-08-15 22:08:40 -05:00
|
|
|
},
|
2024-02-03 13:21:32 -08:00
|
|
|
"urls" => urls_hash,
|
2018-11-02 17:18:07 +00:00
|
|
|
"revision" => revision,
|
|
|
|
"version_scheme" => version_scheme,
|
|
|
|
"bottle" => {},
|
2023-12-07 18:05:36 +00:00
|
|
|
"pour_bottle_only_if" => self.class.pour_bottle_only_if&.to_s,
|
2018-11-02 17:18:07 +00:00
|
|
|
"keg_only" => keg_only?,
|
2021-12-11 23:30:06 +00:00
|
|
|
"keg_only_reason" => keg_only_reason&.to_hash,
|
2018-11-02 17:18:07 +00:00
|
|
|
"options" => [],
|
2023-06-19 06:07:53 +01:00
|
|
|
"build_dependencies" => [],
|
|
|
|
"dependencies" => [],
|
|
|
|
"test_dependencies" => [],
|
|
|
|
"recommended_dependencies" => [],
|
|
|
|
"optional_dependencies" => [],
|
|
|
|
"uses_from_macos" => [],
|
|
|
|
"uses_from_macos_bounds" => [],
|
2024-02-03 13:21:32 -08:00
|
|
|
"requirements" => serialized_requirements,
|
2018-11-02 17:18:07 +00:00
|
|
|
"conflicts_with" => conflicts.map(&:name),
|
2023-02-20 16:08:38 +00:00
|
|
|
"conflicts_with_reasons" => conflicts.map(&:reason),
|
|
|
|
"link_overwrite" => self.class.link_overwrite_paths.to_a,
|
2024-02-03 13:21:32 -08:00
|
|
|
"caveats" => caveats_with_placeholders,
|
2024-03-29 23:07:38 +00:00
|
|
|
"installed" => T.let([], T::Array[T::Hash[String, T.untyped]]),
|
2018-11-02 17:18:07 +00:00
|
|
|
"linked_keg" => linked_version&.to_s,
|
|
|
|
"pinned" => pinned?,
|
|
|
|
"outdated" => outdated?,
|
2020-08-01 02:51:09 +01:00
|
|
|
"deprecated" => deprecated?,
|
2020-12-23 09:56:46 -05:00
|
|
|
"deprecation_date" => deprecation_date,
|
|
|
|
"deprecation_reason" => deprecation_reason,
|
2024-11-07 15:50:03 -05:00
|
|
|
"deprecation_replacement" => deprecation_replacement,
|
2020-08-01 02:51:09 +01:00
|
|
|
"disabled" => disabled?,
|
2020-12-23 09:56:46 -05:00
|
|
|
"disable_date" => disable_date,
|
|
|
|
"disable_reason" => disable_reason,
|
2024-11-07 15:50:03 -05:00
|
|
|
"disable_replacement" => disable_replacement,
|
2023-06-22 03:06:45 +01:00
|
|
|
"post_install_defined" => post_install_defined?,
|
2024-02-03 13:21:32 -08:00
|
|
|
"service" => (service.to_hash if service?),
|
2023-02-06 13:06:11 +00:00
|
|
|
"tap_git_head" => tap_git_head,
|
2023-04-18 00:22:13 +01:00
|
|
|
"ruby_source_path" => ruby_source_path,
|
2023-02-19 02:03:59 +00:00
|
|
|
"ruby_source_checksum" => {},
|
2012-08-15 22:08:40 -05:00
|
|
|
}
|
|
|
|
|
2024-01-27 12:33:17 -08:00
|
|
|
hsh["bottle"]["stable"] = bottle_hash if stable && bottle_defined?
|
2023-02-06 13:04:16 +00:00
|
|
|
|
2018-05-12 10:42:07 -04:00
|
|
|
hsh["options"] = options.map do |opt|
|
|
|
|
{ "option" => opt.flag, "description" => opt.description }
|
|
|
|
end
|
|
|
|
|
2024-02-03 13:21:32 -08:00
|
|
|
hsh.merge!(dependencies_hash)
|
2018-05-12 10:42:07 -04:00
|
|
|
|
2024-03-31 16:53:15 -07:00
|
|
|
hsh["installed"] = installed_kegs.sort_by(&:scheme_and_version).map do |keg|
|
2024-04-28 03:23:21 +02:00
|
|
|
tab = keg.tab
|
2020-07-16 01:48:25 +01:00
|
|
|
{
|
2018-11-02 17:18:07 +00:00
|
|
|
"version" => keg.version.to_s,
|
|
|
|
"used_options" => tab.used_options.as_flags,
|
|
|
|
"built_as_bottle" => tab.built_as_bottle,
|
|
|
|
"poured_from_bottle" => tab.poured_from_bottle,
|
2022-10-03 09:47:56 -07:00
|
|
|
"time" => tab.time,
|
2018-11-02 17:18:07 +00:00
|
|
|
"runtime_dependencies" => tab.runtime_dependencies,
|
2017-01-09 21:06:38 +00:00
|
|
|
"installed_as_dependency" => tab.installed_as_dependency,
|
2018-11-02 17:18:07 +00:00
|
|
|
"installed_on_request" => tab.installed_on_request,
|
2015-11-29 15:22:22 +08:00
|
|
|
}
|
2012-08-15 22:08:40 -05:00
|
|
|
end
|
|
|
|
|
2023-04-18 00:22:13 +01:00
|
|
|
if (source_checksum = ruby_source_checksum)
|
2023-02-19 02:03:59 +00:00
|
|
|
hsh["ruby_source_checksum"] = {
|
2023-04-18 00:22:13 +01:00
|
|
|
"sha256" => source_checksum.hexdigest,
|
2023-02-19 02:03:59 +00:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2012-08-15 22:08:40 -05:00
|
|
|
hsh
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Hash[String, T.untyped]) }
|
2025-02-05 23:36:57 -08:00
|
|
|
def to_hash_with_variations
|
|
|
|
hash = to_hash
|
2023-02-13 05:07:01 +00:00
|
|
|
|
|
|
|
# Take from API, merging in local install status.
|
2023-05-15 13:58:33 +02:00
|
|
|
if loaded_from_api? && !Homebrew::EnvConfig.no_install_from_api?
|
2024-02-16 21:27:02 +01:00
|
|
|
json_formula = Homebrew::API::Formula.all_formulae.fetch(name).dup
|
2023-05-05 01:26:59 +02:00
|
|
|
return json_formula.merge(
|
|
|
|
hash.slice("name", "installed", "linked_keg", "pinned", "outdated"),
|
|
|
|
)
|
2023-02-10 12:07:36 -05:00
|
|
|
end
|
|
|
|
|
2022-07-21 13:04:56 +02:00
|
|
|
variations = {}
|
|
|
|
|
2023-09-28 14:05:09 +01:00
|
|
|
if path.exist? && on_system_blocks_exist?
|
2023-05-13 22:35:08 +02:00
|
|
|
formula_contents = path.read
|
2023-09-19 21:33:13 -07:00
|
|
|
OnSystem::ALL_OS_ARCH_COMBINATIONS.each do |os, arch|
|
2024-03-07 16:20:20 +00:00
|
|
|
bottle_tag = Utils::Bottles::Tag.new(system: os, arch:)
|
2023-05-13 22:35:08 +02:00
|
|
|
next unless bottle_tag.valid_combination?
|
|
|
|
|
2024-03-07 16:20:20 +00:00
|
|
|
Homebrew::SimulateSystem.with(os:, arch:) do
|
2025-02-05 23:36:57 -08:00
|
|
|
variations_namespace = Formulary.class_s("Variations#{bottle_tag.to_sym.capitalize}")
|
2023-05-13 22:35:08 +02:00
|
|
|
variations_formula_class = Formulary.load_formula(name, path, formula_contents, variations_namespace,
|
|
|
|
flags: self.class.build_flags, ignore_errors: true)
|
|
|
|
variations_formula = variations_formula_class.new(name, path, :stable,
|
2024-03-07 16:20:20 +00:00
|
|
|
alias_path:, force_bottle:)
|
2023-05-13 22:35:08 +02:00
|
|
|
|
2025-02-05 23:36:57 -08:00
|
|
|
variations_formula.to_hash.each do |key, value|
|
2023-05-13 22:35:08 +02:00
|
|
|
next if value.to_s == hash[key].to_s
|
|
|
|
|
|
|
|
variations[bottle_tag.to_sym] ||= {}
|
|
|
|
variations[bottle_tag.to_sym][key] = value
|
2022-07-21 13:04:56 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-02-05 23:36:57 -08:00
|
|
|
hash["variations"] = variations
|
2022-07-21 13:04:56 +02:00
|
|
|
hash
|
|
|
|
end
|
|
|
|
|
2023-09-08 14:46:15 -04:00
|
|
|
# Returns the bottle information for a formula.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Hash[String, T.untyped]) }
|
2025-02-05 23:36:57 -08:00
|
|
|
def bottle_hash
|
2024-01-27 12:33:17 -08:00
|
|
|
hash = {}
|
2024-05-20 09:41:29 +01:00
|
|
|
stable_spec = stable
|
|
|
|
return hash unless stable_spec
|
|
|
|
return hash unless bottle_defined?
|
|
|
|
|
|
|
|
bottle_spec = stable_spec.bottle_specification
|
|
|
|
|
2025-02-05 23:36:57 -08:00
|
|
|
hash["rebuild"] = bottle_spec.rebuild
|
|
|
|
hash["root_url"] = bottle_spec.root_url
|
2024-01-27 12:33:17 -08:00
|
|
|
hash["files"] = {}
|
|
|
|
|
2021-09-16 18:56:47 +01:00
|
|
|
bottle_spec.collector.each_tag do |tag|
|
2023-09-28 14:07:25 +01:00
|
|
|
tag_spec = bottle_spec.collector.specification_for(tag, no_older_versions: true)
|
2021-09-16 18:56:47 +01:00
|
|
|
os_cellar = tag_spec.cellar
|
2021-08-13 13:49:52 +01:00
|
|
|
os_cellar = os_cellar.inspect if os_cellar.is_a?(Symbol)
|
2021-09-16 18:56:47 +01:00
|
|
|
checksum = tag_spec.checksum.hexdigest
|
2024-01-27 12:33:17 -08:00
|
|
|
|
|
|
|
file_hash = {}
|
|
|
|
file_hash["cellar"] = os_cellar
|
2025-02-05 23:36:57 -08:00
|
|
|
filename = Bottle::Filename.create(self, tag, bottle_spec.rebuild)
|
|
|
|
path, = Utils::Bottles.path_resolved_basename(bottle_spec.root_url, name, checksum, filename)
|
|
|
|
file_hash["url"] = "#{bottle_spec.root_url}/#{path}"
|
2024-01-27 12:33:17 -08:00
|
|
|
file_hash["sha256"] = checksum
|
|
|
|
|
|
|
|
hash["files"][tag.to_sym] = file_hash
|
|
|
|
end
|
|
|
|
hash
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Hash[String, T::Hash[String, T.untyped]]) }
|
2024-01-27 12:33:17 -08:00
|
|
|
def urls_hash
|
|
|
|
hash = {}
|
|
|
|
|
|
|
|
if stable
|
|
|
|
stable_spec = T.must(stable)
|
|
|
|
hash["stable"] = {
|
|
|
|
"url" => stable_spec.url,
|
|
|
|
"tag" => stable_spec.specs[:tag],
|
|
|
|
"revision" => stable_spec.specs[:revision],
|
|
|
|
"using" => (stable_spec.using if stable_spec.using.is_a?(Symbol)),
|
|
|
|
"checksum" => stable_spec.checksum&.to_s,
|
2021-02-10 10:36:40 +00:00
|
|
|
}
|
|
|
|
end
|
2024-01-27 12:33:17 -08:00
|
|
|
|
|
|
|
if head
|
|
|
|
hash["head"] = {
|
|
|
|
"url" => T.must(head).url,
|
|
|
|
"branch" => T.must(head).specs[:branch],
|
|
|
|
"using" => (T.must(head).using if T.must(head).using.is_a?(Symbol)),
|
2021-02-10 10:36:40 +00:00
|
|
|
}
|
|
|
|
end
|
2024-01-27 12:33:17 -08:00
|
|
|
|
2021-02-10 10:36:40 +00:00
|
|
|
hash
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[T::Hash[String, T.untyped]]) }
|
2024-01-27 13:01:14 -08:00
|
|
|
def serialized_requirements
|
|
|
|
requirements = self.class.spec_syms.to_h do |sym|
|
|
|
|
[sym, send(sym)&.requirements]
|
|
|
|
end
|
|
|
|
|
|
|
|
merge_spec_dependables(requirements).map do |data|
|
|
|
|
req = data[:dependable]
|
|
|
|
req_name = req.name.dup
|
|
|
|
req_name.prepend("maximum_") if req.respond_to?(:comparator) && req.comparator == "<="
|
|
|
|
req_version = if req.respond_to?(:version)
|
|
|
|
req.version
|
|
|
|
elsif req.respond_to?(:arch)
|
|
|
|
req.arch
|
|
|
|
end
|
|
|
|
{
|
|
|
|
"name" => req_name,
|
|
|
|
"cask" => req.cask,
|
|
|
|
"download" => req.download,
|
|
|
|
"version" => req_version,
|
|
|
|
"contexts" => req.tags,
|
|
|
|
"specs" => data[:specs],
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(String)) }
|
2024-01-30 23:00:29 -08:00
|
|
|
def caveats_with_placeholders
|
|
|
|
caveats&.gsub(HOMEBREW_PREFIX, HOMEBREW_PREFIX_PLACEHOLDER)
|
|
|
|
&.gsub(HOMEBREW_CELLAR, HOMEBREW_CELLAR_PLACEHOLDER)
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Hash[String, T.untyped]) }
|
2024-01-27 13:27:07 -08:00
|
|
|
def dependencies_hash
|
|
|
|
# Create a hash of spec names (stable/head) to the list of dependencies under each
|
|
|
|
dependencies = self.class.spec_syms.to_h do |sym|
|
|
|
|
[sym, send(sym)&.declared_deps]
|
|
|
|
end
|
2024-04-30 23:12:07 -07:00
|
|
|
|
|
|
|
# Implicit dependencies are only needed when installing from source
|
|
|
|
# since they are only used to download and unpack source files.
|
|
|
|
# @see DependencyCollector
|
|
|
|
dependencies.transform_values! { |deps| deps&.reject(&:implicit?) }
|
2024-01-27 13:27:07 -08:00
|
|
|
|
|
|
|
hash = {}
|
|
|
|
|
|
|
|
dependencies.each do |spec_sym, spec_deps|
|
|
|
|
next if spec_deps.nil?
|
|
|
|
|
|
|
|
dep_hash = if spec_sym == :stable
|
|
|
|
hash
|
|
|
|
else
|
|
|
|
next if spec_deps == dependencies[:stable]
|
|
|
|
|
|
|
|
hash["#{spec_sym}_dependencies"] ||= {}
|
|
|
|
end
|
|
|
|
|
|
|
|
dep_hash["build_dependencies"] = spec_deps.select(&:build?)
|
|
|
|
.reject(&:uses_from_macos?)
|
|
|
|
.map(&:name)
|
|
|
|
.uniq
|
|
|
|
dep_hash["dependencies"] = spec_deps.reject(&:optional?)
|
|
|
|
.reject(&:recommended?)
|
|
|
|
.reject(&:build?)
|
|
|
|
.reject(&:test?)
|
|
|
|
.reject(&:uses_from_macos?)
|
|
|
|
.map(&:name)
|
|
|
|
.uniq
|
|
|
|
dep_hash["test_dependencies"] = spec_deps.select(&:test?)
|
|
|
|
.reject(&:uses_from_macos?)
|
|
|
|
.map(&:name)
|
|
|
|
.uniq
|
|
|
|
dep_hash["recommended_dependencies"] = spec_deps.select(&:recommended?)
|
|
|
|
.reject(&:uses_from_macos?)
|
|
|
|
.map(&:name)
|
|
|
|
.uniq
|
|
|
|
dep_hash["optional_dependencies"] = spec_deps.select(&:optional?)
|
|
|
|
.reject(&:uses_from_macos?)
|
|
|
|
.map(&:name)
|
|
|
|
.uniq
|
|
|
|
|
|
|
|
uses_from_macos_deps = spec_deps.select(&:uses_from_macos?).uniq
|
|
|
|
dep_hash["uses_from_macos"] = uses_from_macos_deps.map do |dep|
|
|
|
|
if dep.tags.length >= 2
|
|
|
|
{ dep.name => dep.tags }
|
|
|
|
elsif dep.tags.present?
|
|
|
|
{ dep.name => dep.tags.first }
|
|
|
|
else
|
|
|
|
dep.name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
dep_hash["uses_from_macos_bounds"] = uses_from_macos_deps.map(&:bounds)
|
|
|
|
end
|
|
|
|
|
2021-02-10 10:36:40 +00:00
|
|
|
hash
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(spec_symbol: Symbol).returns(T.nilable(T::Hash[String, T.untyped])) }
|
2024-04-30 23:12:07 -07:00
|
|
|
def internal_dependencies_hash(spec_symbol)
|
|
|
|
raise ArgumentError, "Unsupported spec: #{spec_symbol}" unless [:stable, :head].include?(spec_symbol)
|
|
|
|
return unless (spec = public_send(spec_symbol))
|
|
|
|
|
|
|
|
spec.declared_deps.each_with_object({}) do |dep, dep_hash|
|
|
|
|
# Implicit dependencies are only needed when installing from source
|
|
|
|
# since they are only used to download and unpack source files.
|
|
|
|
# @see DependencyCollector
|
|
|
|
next if dep.implicit?
|
2024-03-17 13:55:57 -07:00
|
|
|
|
2024-04-30 23:12:07 -07:00
|
|
|
metadata_hash = {}
|
|
|
|
metadata_hash[:tags] = dep.tags if dep.tags.present?
|
|
|
|
metadata_hash[:uses_from_macos] = dep.bounds.presence if dep.uses_from_macos?
|
2024-03-17 13:55:57 -07:00
|
|
|
|
2024-04-30 23:12:07 -07:00
|
|
|
dep_hash[dep.name] = metadata_hash.presence
|
2024-03-17 13:55:57 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(T::Boolean)) }
|
2023-09-28 14:05:09 +01:00
|
|
|
def on_system_blocks_exist?
|
|
|
|
self.class.on_system_blocks_exist? || @on_system_blocks_exist
|
|
|
|
end
|
|
|
|
|
2024-07-14 11:42:22 -04:00
|
|
|
sig {
|
|
|
|
params(
|
|
|
|
verify_download_integrity: T::Boolean,
|
|
|
|
timeout: T.nilable(T.any(Integer, Float)),
|
|
|
|
quiet: T::Boolean,
|
|
|
|
).returns(Pathname)
|
|
|
|
}
|
|
|
|
def fetch(verify_download_integrity: true, timeout: nil, quiet: false)
|
2024-09-24 10:15:34 +01:00
|
|
|
odeprecated "Formula#fetch", "Resource#fetch on Formula#resource"
|
2024-07-14 11:42:22 -04:00
|
|
|
active_spec.fetch(verify_download_integrity:, timeout:, quiet:)
|
2013-06-05 09:47:08 -07:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(filename: T.any(Pathname, String)).void }
|
2023-03-07 23:48:52 +00:00
|
|
|
def verify_download_integrity(filename)
|
2024-09-24 10:15:34 +01:00
|
|
|
odeprecated "Formula#verify_download_integrity", "Resource#verify_download_integrity on Formula#resource"
|
2023-03-07 23:48:52 +00:00
|
|
|
active_spec.verify_download_integrity(filename)
|
2013-06-05 09:47:08 -07:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(keep_tmp: T::Boolean).returns(T.untyped) }
|
2020-08-02 14:32:31 +02:00
|
|
|
def run_test(keep_tmp: false)
|
2025-02-16 22:20:37 -08:00
|
|
|
@prefix_returns_versioned_prefix = T.let(true, T.nilable(T::Boolean))
|
2017-10-29 14:44:43 +00:00
|
|
|
|
|
|
|
test_env = {
|
2018-11-02 17:18:07 +00:00
|
|
|
TMPDIR: HOMEBREW_TEMP,
|
|
|
|
TEMP: HOMEBREW_TEMP,
|
|
|
|
TMP: HOMEBREW_TEMP,
|
|
|
|
TERM: "dumb",
|
2022-06-15 05:40:43 +01:00
|
|
|
PATH: PATH.new(ENV.fetch("PATH"), HOMEBREW_PREFIX/"bin"),
|
2017-10-29 14:44:43 +00:00
|
|
|
HOMEBREW_PATH: nil,
|
2020-07-16 01:48:25 +01:00
|
|
|
}.merge(common_stage_test_env)
|
2020-07-21 14:59:29 +01:00
|
|
|
test_env[:_JAVA_OPTIONS] += " -Djava.io.tmpdir=#{HOMEBREW_TEMP}"
|
2017-04-22 16:31:19 +01:00
|
|
|
|
|
|
|
ENV.clear_sensitive_environment!
|
2020-08-23 06:32:26 +02:00
|
|
|
Utils::Git.set_name_email!
|
2017-04-22 16:31:19 +01:00
|
|
|
|
2018-07-14 15:41:16 +01:00
|
|
|
mktemp("#{name}-test") do |staging|
|
2020-07-23 02:58:12 +02:00
|
|
|
staging.retain! if keep_tmp
|
2025-02-16 22:20:37 -08:00
|
|
|
@testpath = T.let(staging.tmpdir, T.nilable(Pathname))
|
2017-10-29 14:44:43 +00:00
|
|
|
test_env[:HOME] = @testpath
|
2025-02-16 22:20:37 -08:00
|
|
|
setup_home T.must(@testpath)
|
2016-04-10 22:53:56 -04:00
|
|
|
begin
|
2016-05-27 01:53:08 -04:00
|
|
|
with_logging("test") do
|
2017-10-29 14:44:43 +00:00
|
|
|
with_env(test_env) do
|
|
|
|
test
|
|
|
|
end
|
2016-05-27 01:53:08 -04:00
|
|
|
end
|
2025-01-12 16:56:48 +00:00
|
|
|
# Handle all possible exceptions running formula tests.
|
2017-10-07 00:31:28 +02:00
|
|
|
rescue Exception # rubocop:disable Lint/RescueException
|
2020-08-02 14:32:31 +02:00
|
|
|
staging.retain! if debug?
|
2016-04-10 22:53:56 -04:00
|
|
|
raise
|
|
|
|
end
|
2013-06-05 09:47:08 -07:00
|
|
|
end
|
2014-09-18 14:16:07 -05:00
|
|
|
ensure
|
2025-02-16 22:20:37 -08:00
|
|
|
@prefix_returns_versioned_prefix = T.let(false, T.nilable(T::Boolean))
|
|
|
|
@testpath = T.let(nil, T.nilable(Pathname))
|
2013-06-05 09:47:08 -07:00
|
|
|
end
|
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(T::Boolean) }
|
2013-06-05 09:47:08 -07:00
|
|
|
def test_defined?
|
2024-11-22 18:06:49 -08:00
|
|
|
method(:test).owner != Formula
|
2013-06-05 09:47:08 -07:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(T::Boolean)) }
|
2017-10-07 00:31:28 +02:00
|
|
|
def test; end
|
2014-09-18 14:16:07 -05:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(file: T.any(Pathname, String)).returns(Pathname) }
|
2014-10-19 01:14:32 -05:00
|
|
|
def test_fixtures(file)
|
2017-06-01 16:06:51 +02:00
|
|
|
HOMEBREW_LIBRARY_PATH/"test/support/fixtures"/file
|
2014-10-19 01:14:32 -05:00
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# This method is overridden in {Formula} subclasses to provide the
|
|
|
|
# installation instructions. The sources (from {.url}) are downloaded,
|
|
|
|
# hash-checked and then Homebrew changes into a temporary directory where the
|
|
|
|
# archive is unpacked or repository cloned.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# def install
|
2015-08-29 10:56:24 +01:00
|
|
|
# system "./configure", "--prefix=#{prefix}"
|
|
|
|
# system "make", "install"
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { void }
|
2017-10-07 00:31:28 +02:00
|
|
|
def install; end
|
2014-12-06 11:27:03 +00:00
|
|
|
|
2022-08-07 15:55:37 +02:00
|
|
|
# Sometimes we have to change a bit before we install. Mostly we
|
|
|
|
# prefer a patch, but if you need the {Formula#prefix prefix} of
|
|
|
|
# this formula in the patch you have to resort to `inreplace`,
|
|
|
|
# because in the patch you don't have access to any variables
|
|
|
|
# defined by the formula, as only `HOMEBREW_PREFIX` is available
|
|
|
|
# in the {DATAPatch embedded patch}.
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Examples
|
|
|
|
#
|
2022-08-07 15:55:37 +02:00
|
|
|
# `inreplace` supports regular expressions:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# inreplace "somefile.cfg", /look[for]what?/, "replace by #{bin}/tool"
|
|
|
|
# ```
|
2022-08-07 15:55:37 +02:00
|
|
|
#
|
|
|
|
# `inreplace` supports blocks:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# inreplace "Makefile" do |s|
|
2022-08-07 15:55:37 +02:00
|
|
|
# s.gsub! "/usr/local", HOMEBREW_PREFIX.to_s
|
|
|
|
# end
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```
|
2022-08-07 15:55:37 +02:00
|
|
|
#
|
|
|
|
# @see Utils::Inreplace.inreplace
|
|
|
|
# @api public
|
2023-07-21 19:48:28 -07:00
|
|
|
sig {
|
|
|
|
params(
|
2024-08-31 12:29:43 +08:00
|
|
|
paths: T.any(T::Enumerable[T.any(String, Pathname)], String, Pathname),
|
|
|
|
before: T.nilable(T.any(Pathname, Regexp, String)),
|
|
|
|
after: T.nilable(T.any(Pathname, String, Symbol)),
|
|
|
|
old_audit_result: T.nilable(T::Boolean),
|
|
|
|
audit_result: T::Boolean,
|
2024-11-26 13:45:50 -05:00
|
|
|
global: T::Boolean,
|
2024-08-31 12:29:43 +08:00
|
|
|
block: T.nilable(T.proc.params(s: StringInreplaceExtension).void),
|
2023-07-21 19:48:28 -07:00
|
|
|
).void
|
|
|
|
}
|
2024-11-26 13:45:50 -05:00
|
|
|
def inreplace(paths, before = nil, after = nil, old_audit_result = nil, audit_result: true, global: true, &block)
|
2024-09-02 16:02:35 +08:00
|
|
|
# NOTE: must check for `#nil?` and not `#blank?`, or else `old_audit_result = false` will not call `odeprecated`.
|
2024-08-31 12:29:43 +08:00
|
|
|
unless old_audit_result.nil?
|
2024-09-24 10:15:34 +01:00
|
|
|
odeprecated "inreplace(paths, before, after, #{old_audit_result})",
|
|
|
|
"inreplace(paths, before, after, audit_result: #{old_audit_result})"
|
2024-08-31 12:29:43 +08:00
|
|
|
audit_result = old_audit_result
|
|
|
|
end
|
2024-11-26 13:45:50 -05:00
|
|
|
Utils::Inreplace.inreplace(paths, before, after, audit_result:, global:, &block)
|
2022-10-07 21:00:46 +01:00
|
|
|
rescue Utils::Inreplace::Error => e
|
|
|
|
onoe e.to_s
|
2023-07-31 11:31:35 -07:00
|
|
|
raise BuildError.new(self, "inreplace", Array(paths), {})
|
2022-07-30 19:10:40 +02:00
|
|
|
end
|
|
|
|
|
2014-12-12 22:27:34 -05:00
|
|
|
protected
|
|
|
|
|
2024-03-14 02:04:20 -04:00
|
|
|
sig { params(home: Pathname).void }
|
2015-10-17 10:05:41 -07:00
|
|
|
def setup_home(home)
|
2021-03-27 16:15:45 +00:00
|
|
|
# Don't let bazel write to tmp directories we don't control or clean.
|
|
|
|
(home/".bazelrc").write "startup --output_user_root=#{home}/_bazel"
|
2015-04-08 12:56:32 -07:00
|
|
|
end
|
|
|
|
|
2018-07-16 16:46:39 +01:00
|
|
|
# Returns a list of Dependency objects that are declared in the formula.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[Dependency]) }
|
2018-07-16 16:46:39 +01:00
|
|
|
def declared_runtime_dependencies
|
2023-09-15 03:08:22 +01:00
|
|
|
cache_key = "Formula#declared_runtime_dependencies" unless build.any_args_or_options?
|
2024-03-07 16:20:20 +00:00
|
|
|
Dependency.expand(self, cache_key:) do |_, dependency|
|
2018-07-16 16:46:39 +01:00
|
|
|
Dependency.prune if dependency.build?
|
|
|
|
next if dependency.required?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2018-07-16 16:46:39 +01:00
|
|
|
if build.any_args_or_options?
|
|
|
|
Dependency.prune if build.without?(dependency)
|
|
|
|
elsif !dependency.recommended?
|
|
|
|
Dependency.prune
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Returns a list of Dependency objects that are not declared in the formula
|
|
|
|
# but the formula links to.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[Dependency]) }
|
2018-07-16 16:46:39 +01:00
|
|
|
def undeclared_runtime_dependencies
|
2020-08-31 10:58:36 -07:00
|
|
|
keg = any_installed_keg
|
2018-07-16 16:46:39 +01:00
|
|
|
return [] unless keg
|
|
|
|
|
2020-07-07 11:29:33 +01:00
|
|
|
CacheStoreDatabase.use(:linkage) do |db|
|
2018-07-16 16:46:39 +01:00
|
|
|
linkage_checker = LinkageChecker.new(keg, self, cache_db: db)
|
|
|
|
linkage_checker.undeclared_deps.map { |n| Dependency.new(n) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
public
|
|
|
|
|
|
|
|
# To call out to the system, we use the `system` method and we prefer
|
|
|
|
# you give the args separately as in the line below, otherwise a subshell
|
|
|
|
# has to be opened first.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# system "./bootstrap.sh", "--arg1", "--prefix=#{prefix}"
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# For CMake and other build systems we have some necessary defaults in e.g.
|
|
|
|
# {#std_cmake_args}:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# system "cmake", ".", *std_cmake_args
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2020-11-05 17:17:03 -05:00
|
|
|
# If the arguments given to `configure` (or `make` or `cmake`) are depending
|
2015-08-29 10:56:24 +01:00
|
|
|
# on options defined above, we usually make a list first and then
|
2020-11-05 17:17:03 -05:00
|
|
|
# use the `args << if <condition>` to append each:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# args = ["--with-option1", "--with-option2"]
|
2020-11-03 16:36:48 -05:00
|
|
|
# args << "--without-gcc" if ENV.compiler == :clang
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# Most software still uses `configure` and `make`.
|
|
|
|
# Check with `./configure --help` for what our options are.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
2015-08-29 10:56:24 +01:00
|
|
|
# system "./configure", "--disable-debug", "--disable-dependency-tracking",
|
|
|
|
# "--disable-silent-rules", "--prefix=#{prefix}",
|
|
|
|
# *args # our custom arg list (needs `*` to unpack)
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# If there is a "make install" available, please use it!
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# system "make", "install"
|
|
|
|
# ```
|
2024-10-16 11:54:21 -04:00
|
|
|
#
|
|
|
|
# @api public
|
2023-09-13 13:23:35 -04:00
|
|
|
sig { params(cmd: T.any(String, Pathname), args: T.any(String, Integer, Pathname, Symbol)).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def system(cmd, *args)
|
2020-04-05 15:44:50 +01:00
|
|
|
verbose_using_dots = Homebrew::EnvConfig.verbose_using_dots?
|
2015-09-23 15:40:27 +08:00
|
|
|
|
2011-07-30 11:03:27 +01:00
|
|
|
# remove "boring" arguments so that the important ones are more likely to
|
|
|
|
# be shown considering that we trim long ohai lines to the terminal width
|
|
|
|
pretty_args = args.dup
|
2020-08-02 06:05:53 +02:00
|
|
|
unless verbose?
|
2020-02-17 14:42:43 +11:00
|
|
|
case cmd
|
|
|
|
when "./configure"
|
2023-07-29 22:55:58 -07:00
|
|
|
pretty_args -= std_configure_args
|
|
|
|
when "cabal"
|
|
|
|
pretty_args -= std_cabal_v2_args
|
2020-06-22 13:24:41 +02:00
|
|
|
when "cargo"
|
|
|
|
pretty_args -= std_cargo_args
|
2020-02-17 14:42:43 +11:00
|
|
|
when "cmake"
|
|
|
|
pretty_args -= std_cmake_args
|
|
|
|
when "go"
|
|
|
|
pretty_args -= std_go_args
|
2023-07-29 22:55:58 -07:00
|
|
|
when "meson"
|
|
|
|
pretty_args -= std_meson_args
|
2025-02-21 14:53:34 +01:00
|
|
|
when "zig"
|
|
|
|
pretty_args -= std_zig_args
|
2023-07-29 22:55:58 -07:00
|
|
|
when %r{(^|/)(pip|python)(?:[23](?:\.\d{1,2})?)?$}
|
|
|
|
pretty_args -= std_pip_args
|
2020-02-17 14:42:43 +11:00
|
|
|
end
|
2012-08-31 08:09:35 -04:00
|
|
|
end
|
2014-12-08 12:57:40 -05:00
|
|
|
pretty_args.each_index do |i|
|
2019-02-19 13:11:32 +00:00
|
|
|
pretty_args[i] = "import setuptools..." if pretty_args[i].to_s.start_with? "import setuptools"
|
2014-12-08 12:57:40 -05:00
|
|
|
end
|
2017-06-01 16:06:51 +02:00
|
|
|
ohai "#{cmd} #{pretty_args * " "}".strip
|
2009-11-06 17:09:14 +00:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@exec_count ||= T.let(0, T.nilable(Integer))
|
2013-10-27 07:05:13 +01:00
|
|
|
@exec_count += 1
|
2019-10-03 08:50:45 +02:00
|
|
|
logfn = format("#{logs}/#{active_log_prefix}%02<exec_count>d.%<cmd_base>s",
|
2018-09-02 20:14:54 +01:00
|
|
|
exec_count: @exec_count,
|
2020-11-30 16:27:49 +01:00
|
|
|
cmd_base: File.basename(cmd).split.first)
|
2015-04-25 22:07:06 -04:00
|
|
|
logs.mkpath
|
2013-10-27 07:05:13 +01:00
|
|
|
|
2014-12-30 23:52:07 -05:00
|
|
|
File.open(logfn, "w") do |log|
|
2014-09-05 15:36:08 -05:00
|
|
|
log.puts Time.now, "", cmd, args, ""
|
|
|
|
log.flush
|
2014-09-05 15:13:52 -05:00
|
|
|
|
2020-08-02 06:05:53 +02:00
|
|
|
if verbose?
|
2014-09-05 15:36:08 -05:00
|
|
|
rd, wr = IO.pipe
|
|
|
|
begin
|
|
|
|
pid = fork do
|
|
|
|
rd.close
|
|
|
|
log.close
|
|
|
|
exec_cmd(cmd, args, wr, logfn)
|
|
|
|
end
|
|
|
|
wr.close
|
|
|
|
|
2015-09-23 15:40:27 +08:00
|
|
|
if verbose_using_dots
|
|
|
|
last_dot = Time.at(0)
|
2021-02-12 18:33:37 +05:30
|
|
|
while (buf = rd.gets)
|
2015-09-23 15:40:27 +08:00
|
|
|
log.puts buf
|
|
|
|
# make sure dots printed with interval of at least 1 min.
|
2023-04-18 15:06:50 -07:00
|
|
|
next if (Time.now - last_dot) <= 60
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-09-17 15:17:27 +01:00
|
|
|
print "."
|
|
|
|
$stdout.flush
|
|
|
|
last_dot = Time.now
|
2015-09-23 15:40:27 +08:00
|
|
|
end
|
|
|
|
puts
|
|
|
|
else
|
2021-02-12 18:33:37 +05:30
|
|
|
while (buf = rd.gets)
|
2015-09-23 15:40:27 +08:00
|
|
|
log.puts buf
|
|
|
|
puts buf
|
|
|
|
end
|
2014-09-05 15:36:08 -05:00
|
|
|
end
|
|
|
|
ensure
|
2014-09-05 16:56:07 -05:00
|
|
|
rd.close
|
2014-09-05 15:13:53 -05:00
|
|
|
end
|
2014-09-05 15:36:08 -05:00
|
|
|
else
|
2020-11-24 15:46:47 +01:00
|
|
|
pid = fork do
|
|
|
|
exec_cmd(cmd, args, log, logfn)
|
|
|
|
end
|
2014-09-05 15:13:53 -05:00
|
|
|
end
|
2013-09-07 10:22:58 -05:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
Process.wait(pid)
|
2013-09-07 10:22:58 -05:00
|
|
|
|
2014-09-05 15:36:08 -05:00
|
|
|
$stdout.flush
|
2013-11-29 21:05:20 -06:00
|
|
|
|
2017-06-10 20:12:55 +03:00
|
|
|
unless $CHILD_STATUS.success?
|
2023-03-13 00:59:08 +01:00
|
|
|
log_lines = Homebrew::EnvConfig.fail_log_lines
|
2015-09-21 15:10:23 +01:00
|
|
|
|
2014-09-05 15:36:08 -05:00
|
|
|
log.flush
|
2020-08-02 06:05:53 +02:00
|
|
|
if !verbose? || verbose_using_dots
|
2015-09-21 15:10:23 +01:00
|
|
|
puts "Last #{log_lines} lines from #{logfn}:"
|
2023-03-13 00:59:08 +01:00
|
|
|
Kernel.system "/usr/bin/tail", "-n", log_lines.to_s, logfn
|
2015-09-21 15:10:23 +01:00
|
|
|
end
|
2014-09-05 15:36:08 -05:00
|
|
|
log.puts
|
2014-12-30 23:47:07 -05:00
|
|
|
|
2016-05-08 21:41:51 +02:00
|
|
|
require "system_config"
|
2015-11-13 16:43:43 +01:00
|
|
|
require "build_environment"
|
2014-12-30 23:47:07 -05:00
|
|
|
|
|
|
|
env = ENV.to_hash
|
|
|
|
|
2016-05-08 21:41:51 +02:00
|
|
|
SystemConfig.dump_verbose_config(log)
|
2014-12-30 23:47:07 -05:00
|
|
|
log.puts
|
2020-08-14 02:26:29 +02:00
|
|
|
BuildEnvironment.dump env, log
|
2014-12-30 23:47:07 -05:00
|
|
|
|
|
|
|
raise BuildError.new(self, cmd, args, env)
|
2014-09-05 15:36:08 -05:00
|
|
|
end
|
2012-09-11 20:59:59 -04:00
|
|
|
end
|
2009-08-10 16:48:30 +01:00
|
|
|
end
|
2009-07-24 15:10:01 +01:00
|
|
|
|
2025-01-23 14:29:48 +00:00
|
|
|
sig { params(quiet: T::Boolean).returns(T::Array[Keg]) }
|
2019-01-28 16:08:23 +00:00
|
|
|
def eligible_kegs_for_cleanup(quiet: false)
|
2015-12-29 12:57:48 +01:00
|
|
|
eligible_for_cleanup = []
|
2019-12-03 11:42:09 +00:00
|
|
|
if latest_version_installed?
|
2021-06-01 03:25:26 -04:00
|
|
|
eligible_kegs = if head? && (head_prefix = latest_head_prefix)
|
2024-04-28 03:23:21 +02:00
|
|
|
head, stable = installed_kegs.partition { |keg| keg.version.head? }
|
|
|
|
|
|
|
|
# Remove newest head and stable kegs.
|
|
|
|
head - [Keg.new(head_prefix)] + T.must(stable.sort_by(&:scheme_and_version).slice(0...-1))
|
2016-07-16 15:31:03 +03:00
|
|
|
else
|
2017-01-30 17:16:23 +08:00
|
|
|
installed_kegs.select do |keg|
|
2024-04-28 03:23:21 +02:00
|
|
|
tab = keg.tab
|
2017-01-30 17:16:23 +08:00
|
|
|
if version_scheme > tab.version_scheme
|
|
|
|
true
|
|
|
|
elsif version_scheme == tab.version_scheme
|
|
|
|
pkg_version > keg.version
|
|
|
|
else
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end
|
2016-07-16 15:31:03 +03:00
|
|
|
end
|
|
|
|
|
2016-08-05 22:01:32 +08:00
|
|
|
unless eligible_kegs.empty?
|
2015-12-29 12:57:48 +01:00
|
|
|
eligible_kegs.each do |keg|
|
|
|
|
if keg.linked?
|
2019-01-28 16:08:23 +00:00
|
|
|
opoo "Skipping (old) #{keg} due to it being linked" unless quiet
|
2016-09-01 17:31:28 +03:00
|
|
|
elsif pinned? && keg == Keg.new(@pin.path.resolved_path)
|
2019-01-28 16:08:23 +00:00
|
|
|
opoo "Skipping (old) #{keg} due to it being pinned" unless quiet
|
2025-01-23 14:29:48 +00:00
|
|
|
elsif (keepme = keg/".keepme") && keepme.exist? && keepme.readable? &&
|
|
|
|
(keepme_refs = keepme.readlines.map(&:strip).select { |ref| Pathname(ref).exist? }.presence)
|
|
|
|
opoo "Skipping #{keg} as it needed by #{keepme_refs.join(", ")}" unless quiet
|
2015-12-29 12:57:48 +01:00
|
|
|
else
|
|
|
|
eligible_for_cleanup << keg
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-08-05 22:01:32 +08:00
|
|
|
elsif !installed_prefixes.empty? && !pinned?
|
2015-12-29 12:57:48 +01:00
|
|
|
# If the cellar only has one version installed, don't complain
|
|
|
|
# that we can't tell which one to keep. Don't complain at all if the
|
|
|
|
# only installed version is a pinned formula.
|
2019-02-19 13:11:32 +00:00
|
|
|
opoo "Skipping #{full_name}: most recent version #{pkg_version} not installed" unless quiet
|
2015-12-29 12:57:48 +01:00
|
|
|
end
|
|
|
|
eligible_for_cleanup
|
|
|
|
end
|
|
|
|
|
2018-07-14 15:41:16 +01:00
|
|
|
# Create a temporary directory then yield. When the block returns,
|
2018-10-18 21:42:43 -04:00
|
|
|
# recursively delete the temporary directory. Passing `opts[:retain]`
|
2018-07-14 15:41:16 +01:00
|
|
|
# or calling `do |staging| ... staging.retain!` in the block will skip
|
|
|
|
# the deletion and retain the temporary directory's contents.
|
2024-10-13 18:48:01 -04:00
|
|
|
sig {
|
|
|
|
params(
|
|
|
|
prefix: String,
|
|
|
|
retain: T::Boolean,
|
|
|
|
retain_in_cache: T::Boolean,
|
|
|
|
block: T.proc.params(arg0: Mktemp).void,
|
|
|
|
).void
|
|
|
|
}
|
|
|
|
def mktemp(prefix = name, retain: false, retain_in_cache: false, &block)
|
|
|
|
Mktemp.new(prefix, retain:, retain_in_cache:).run(&block)
|
2018-07-14 15:41:16 +01:00
|
|
|
end
|
|
|
|
|
2018-07-14 18:13:23 +01:00
|
|
|
# A version of `FileUtils.mkdir` that also changes to that folder in
|
|
|
|
# a block.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(name: T.any(String, Pathname), block: T.nilable(T.proc.void)).returns(T.untyped) }
|
2020-08-19 17:12:32 +01:00
|
|
|
def mkdir(name, &block)
|
2018-07-14 18:13:23 +01:00
|
|
|
result = FileUtils.mkdir_p(name)
|
2020-11-16 22:18:56 +01:00
|
|
|
return result unless block
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2020-08-19 17:12:32 +01:00
|
|
|
FileUtils.chdir(name, &block)
|
2018-07-14 18:13:23 +01:00
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Runs `xcodebuild` without Homebrew's compiler environment variables set.
|
2023-09-13 13:23:35 -04:00
|
|
|
sig { params(args: T.any(String, Integer, Pathname, Symbol)).void }
|
2018-07-14 18:13:23 +01:00
|
|
|
def xcodebuild(*args)
|
|
|
|
removed = ENV.remove_cc_etc
|
2020-11-24 15:46:47 +01:00
|
|
|
|
|
|
|
begin
|
2024-08-18 16:28:17 -07:00
|
|
|
self.system("xcodebuild", *args)
|
2020-11-24 15:46:47 +01:00
|
|
|
ensure
|
|
|
|
ENV.update(removed)
|
|
|
|
end
|
2018-07-14 18:13:23 +01:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { void }
|
2020-08-02 14:32:31 +02:00
|
|
|
def fetch_patches
|
|
|
|
patchlist.select(&:external?).each(&:fetch)
|
2020-05-12 12:37:54 +01:00
|
|
|
end
|
|
|
|
|
2021-03-31 20:55:35 +01:00
|
|
|
sig { void }
|
|
|
|
def fetch_bottle_tab
|
|
|
|
return unless bottled?
|
|
|
|
|
|
|
|
T.must(bottle).fetch_tab
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Hash[String, T.untyped]) }
|
2021-03-31 20:55:35 +01:00
|
|
|
def bottle_tab_attributes
|
|
|
|
return {} unless bottled?
|
|
|
|
|
|
|
|
T.must(bottle).tab_attributes
|
|
|
|
end
|
|
|
|
|
2013-04-07 00:49:56 -05:00
|
|
|
private
|
2012-03-04 16:48:00 -08:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { void }
|
2020-05-13 11:49:17 +01:00
|
|
|
def prepare_patches
|
|
|
|
patchlist.grep(DATAPatch) { |p| p.path = path }
|
|
|
|
end
|
|
|
|
|
2017-01-06 08:50:35 +00:00
|
|
|
# Returns the prefix for a given formula version number.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(version: T.any(String, Pathname, PkgVersion)).returns(Pathname) }
|
2023-03-07 23:42:00 +00:00
|
|
|
def versioned_prefix(version)
|
2025-02-16 22:20:37 -08:00
|
|
|
rack/version.to_s
|
2017-01-06 08:50:35 +00:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig {
|
|
|
|
params(
|
|
|
|
cmd: T.any(String, Pathname),
|
|
|
|
args: T::Array[T.any(String, Integer, Pathname, Symbol)],
|
|
|
|
out: IO,
|
|
|
|
logfn: T.nilable(String),
|
|
|
|
).void
|
|
|
|
}
|
2014-09-05 15:13:52 -05:00
|
|
|
def exec_cmd(cmd, args, out, logfn)
|
2015-08-03 13:09:07 +01:00
|
|
|
ENV["HOMEBREW_CC_LOG_PATH"] = logfn
|
2014-09-05 15:13:52 -05:00
|
|
|
|
2016-09-23 11:01:40 +02:00
|
|
|
ENV.remove_cc_etc if cmd.to_s.start_with? "xcodebuild"
|
2014-09-05 15:13:52 -05:00
|
|
|
|
|
|
|
# Turn on argument filtering in the superenv compiler wrapper.
|
|
|
|
# We should probably have a better mechanism for this than adding
|
|
|
|
# special cases to this method.
|
2014-12-10 00:29:11 -08:00
|
|
|
if cmd == "python"
|
|
|
|
setup_py_in_args = %w[setup.py build.py].include?(args.first)
|
2014-12-12 15:16:24 -08:00
|
|
|
setuptools_shim_in_args = args.any? { |a| a.to_s.start_with? "import setuptools" }
|
2024-05-31 15:49:12 -07:00
|
|
|
ENV.refurbish_args if setup_py_in_args || setuptools_shim_in_args
|
2014-09-05 15:13:52 -05:00
|
|
|
end
|
|
|
|
|
2014-09-05 15:13:52 -05:00
|
|
|
$stdout.reopen(out)
|
|
|
|
$stderr.reopen(out)
|
2014-09-07 20:41:18 -05:00
|
|
|
out.close
|
2018-09-02 20:14:54 +01:00
|
|
|
args.map!(&:to_s)
|
2016-09-17 15:17:27 +01:00
|
|
|
begin
|
2023-04-03 17:34:39 -07:00
|
|
|
Kernel.exec(cmd, *args)
|
2016-09-17 15:17:27 +01:00
|
|
|
rescue
|
|
|
|
nil
|
|
|
|
end
|
2014-09-05 15:13:52 -05:00
|
|
|
puts "Failed to execute: #{cmd}"
|
|
|
|
exit! 1 # never gets here unless exec threw or failed
|
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Common environment variables used at both build and test time.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Hash[Symbol, String]) }
|
2020-07-16 01:48:25 +01:00
|
|
|
def common_stage_test_env
|
|
|
|
{
|
2023-01-07 15:22:06 +00:00
|
|
|
_JAVA_OPTIONS: "-Duser.home=#{HOMEBREW_CACHE}/java_cache",
|
|
|
|
GOCACHE: "#{HOMEBREW_CACHE}/go_cache",
|
|
|
|
GOPATH: "#{HOMEBREW_CACHE}/go_mod_cache",
|
|
|
|
CARGO_HOME: "#{HOMEBREW_CACHE}/cargo_cache",
|
2023-11-22 13:11:53 -08:00
|
|
|
PIP_CACHE_DIR: "#{HOMEBREW_CACHE}/pip_cache",
|
2023-01-07 15:22:06 +00:00
|
|
|
CURL_HOME: ENV.fetch("CURL_HOME") { Dir.home },
|
|
|
|
PYTHONDONTWRITEBYTECODE: "1",
|
2020-07-16 01:48:25 +01:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(interactive: T::Boolean, debug_symbols: T::Boolean, _block: T.proc.params(arg0: Mktemp).void).void }
|
|
|
|
def stage(interactive: false, debug_symbols: false, &_block)
|
2024-03-07 16:20:20 +00:00
|
|
|
active_spec.stage(debug_symbols:) do |staging|
|
2025-02-16 22:20:37 -08:00
|
|
|
@source_modified_time = T.let(active_spec.source_modified_time, T.nilable(Time))
|
|
|
|
@buildpath = T.let(Pathname.pwd, T.nilable(Pathname))
|
2023-07-24 14:01:53 -07:00
|
|
|
env_home = T.must(buildpath)/".brew_home"
|
2015-06-05 22:35:08 +01:00
|
|
|
mkdir_p env_home
|
|
|
|
|
2017-10-29 14:44:43 +00:00
|
|
|
stage_env = {
|
|
|
|
HOMEBREW_PATH: nil,
|
|
|
|
}
|
2017-04-22 16:31:19 +01:00
|
|
|
|
2020-07-23 02:58:12 +02:00
|
|
|
unless interactive
|
2017-10-29 14:44:43 +00:00
|
|
|
stage_env[:HOME] = env_home
|
2020-07-16 01:48:25 +01:00
|
|
|
stage_env.merge!(common_stage_test_env)
|
2017-05-09 20:00:11 +01:00
|
|
|
end
|
2017-04-22 16:31:19 +01:00
|
|
|
|
2015-10-17 10:05:41 -07:00
|
|
|
setup_home env_home
|
2024-04-23 18:33:35 -07:00
|
|
|
# Don't dirty the git tree for git clones.
|
|
|
|
(env_home/".gitignore").write "*"
|
2015-06-05 22:35:08 +01:00
|
|
|
|
2017-04-22 16:31:19 +01:00
|
|
|
ENV.clear_sensitive_environment!
|
|
|
|
|
2015-06-05 22:35:08 +01:00
|
|
|
begin
|
2017-10-29 14:44:43 +00:00
|
|
|
with_env(stage_env) do
|
|
|
|
yield staging
|
|
|
|
end
|
2015-06-05 22:35:08 +01:00
|
|
|
ensure
|
2025-02-16 22:20:37 -08:00
|
|
|
@buildpath = T.let(nil, T.nilable(Pathname))
|
2015-06-05 22:35:08 +01:00
|
|
|
end
|
2009-07-31 11:05:23 -07:00
|
|
|
end
|
|
|
|
end
|
2010-07-04 14:17:03 -07:00
|
|
|
|
2017-10-07 00:31:28 +02:00
|
|
|
# The methods below define the formula DSL.
|
|
|
|
class << self
|
2023-12-28 11:45:18 -08:00
|
|
|
extend Attrable
|
2023-04-24 19:14:04 -07:00
|
|
|
|
2017-10-07 00:31:28 +02:00
|
|
|
include BuildEnvironment::DSL
|
2022-06-29 17:48:21 -04:00
|
|
|
include OnSystem::MacOSAndLinux
|
2014-08-10 21:45:23 -05:00
|
|
|
|
2022-08-24 23:53:35 +01:00
|
|
|
# Initialise instance variables for each subclass. These need to be initialised before the class is frozen,
|
|
|
|
# and some DSL may never be called so it can't be done lazily.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(child: T::Class[Formula]).void }
|
2022-08-24 23:53:35 +01:00
|
|
|
def inherited(child)
|
|
|
|
super
|
|
|
|
child.instance_eval do
|
|
|
|
# Ensure this is synced with `freeze`
|
2025-02-16 22:20:37 -08:00
|
|
|
@stable = T.let(SoftwareSpec.new(flags: build_flags), T.nilable(SoftwareSpec))
|
|
|
|
@head = T.let(HeadSoftwareSpec.new(flags: build_flags), T.nilable(HeadSoftwareSpec))
|
|
|
|
@livecheck = T.let(Livecheck.new(self), T.nilable(Livecheck))
|
|
|
|
@conflicts = T.let([], T.nilable(T::Array[FormulaConflict]))
|
|
|
|
@skip_clean_paths = T.let(Set.new, T.nilable(T::Set[T.any(String, Symbol)]))
|
|
|
|
@link_overwrite_paths = T.let(Set.new, T.nilable(T::Set[String]))
|
|
|
|
@loaded_from_api = T.let(false, T.nilable(T::Boolean))
|
|
|
|
@network_access_allowed = T.let(SUPPORTED_NETWORK_ACCESS_PHASES.to_h do |phase|
|
2024-04-13 00:23:00 -04:00
|
|
|
[phase, DEFAULT_NETWORK_ACCESS_ALLOWED]
|
2025-02-16 22:20:37 -08:00
|
|
|
end, T.nilable(T::Hash[Symbol, T::Boolean]))
|
2022-08-24 23:53:35 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.self_type) }
|
2022-08-24 23:53:35 +01:00
|
|
|
def freeze
|
|
|
|
specs.each(&:freeze)
|
|
|
|
@livecheck.freeze
|
|
|
|
@conflicts.freeze
|
|
|
|
@skip_clean_paths.freeze
|
|
|
|
@link_overwrite_paths.freeze
|
|
|
|
super
|
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Hash[Symbol, T::Boolean]) }
|
|
|
|
def network_access_allowed = T.must(@network_access_allowed)
|
|
|
|
|
2022-09-10 20:28:21 -04:00
|
|
|
# Whether this formula was loaded using the formulae.brew.sh API
|
2023-05-15 13:58:33 +02:00
|
|
|
attr_predicate :loaded_from_api?
|
2022-09-10 20:28:21 -04:00
|
|
|
|
2022-07-21 15:32:51 +02:00
|
|
|
# Whether this formula contains OS/arch-specific blocks
|
|
|
|
# (e.g. `on_macos`, `on_arm`, `on_monterey :or_older`, `on_system :linux, macos: :big_sur_or_newer`).
|
|
|
|
attr_predicate :on_system_blocks_exist?
|
|
|
|
|
2024-03-06 01:00:39 +01:00
|
|
|
# The reason for why this software is not linked (by default) to {::HOMEBREW_PREFIX}.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(KegOnlyReason)) }
|
2014-08-19 17:14:02 -05:00
|
|
|
attr_reader :keg_only_reason
|
2014-12-06 11:26:43 +00:00
|
|
|
|
2015-05-19 13:06:06 -04:00
|
|
|
# A one-line description of the software. Used by users to get an overview
|
|
|
|
# of the software and Homebrew maintainers.
|
|
|
|
# Shows when running `brew info`.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# desc "Example formula"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-23 13:41:23 -08:00
|
|
|
sig { params(val: String).returns(T.nilable(String)) }
|
|
|
|
def desc(val = T.unsafe(nil))
|
2025-02-23 13:18:49 -08:00
|
|
|
val.nil? ? @desc : @desc = T.let(val, T.nilable(String))
|
|
|
|
end
|
2015-05-19 13:06:06 -04:00
|
|
|
|
2020-06-10 12:29:25 -04:00
|
|
|
# The SPDX ID of the open-source license that the formula uses.
|
|
|
|
# Shows when running `brew info`.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
2020-08-24 01:54:28 -04:00
|
|
|
# Use `:any_of`, `:all_of` or `:with` to describe complex license expressions.
|
|
|
|
# `:any_of` should be used when the user can choose which license to use.
|
|
|
|
# `:all_of` should be used when the user must use all licenses.
|
2020-08-18 10:58:32 -04:00
|
|
|
# `:with` should be used to specify a valid SPDX exception.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
2020-08-18 10:58:32 -04:00
|
|
|
# Add `+` to an identifier to indicate that the formulae can be
|
|
|
|
# licensed under later versions of the same license.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# license "BSD-2-Clause"
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# license "EPL-1.0+"
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# license any_of: ["MIT", "GPL-2.0-only"]
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# license all_of: ["MIT", "GPL-2.0-only"]
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# license "GPL-2.0-only" => { with: "LLVM-exception" }
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# license :public_domain
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# license any_of: [
|
2020-08-24 01:54:28 -04:00
|
|
|
# "MIT",
|
|
|
|
# :public_domain,
|
|
|
|
# all_of: ["0BSD", "Zlib", "Artistic-1.0+"],
|
|
|
|
# "Apache-2.0" => { with: "LLVM-exception" },
|
2024-04-26 20:55:51 +02:00
|
|
|
# ]
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# @!attribute [w] license
|
|
|
|
# @see https://docs.brew.sh/License-Guidelines Homebrew License Guidelines
|
2024-09-06 19:44:58 +08:00
|
|
|
# @see https://spdx.github.io/spdx-spec/latest/annexes/spdx-license-expressions/ SPDX license expression guide
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig {
|
|
|
|
params(args: T.any(NilClass, String, Symbol, T::Hash[T.any(String, Symbol), T.anything]))
|
|
|
|
.returns(T.any(NilClass, String, Symbol, T::Hash[T.any(String, Symbol), T.anything]))
|
|
|
|
}
|
2020-08-20 10:26:37 -04:00
|
|
|
def license(args = nil)
|
|
|
|
if args.nil?
|
|
|
|
@licenses
|
|
|
|
else
|
2025-02-16 22:20:37 -08:00
|
|
|
@licenses = T.let(args, T.any(NilClass, String, Symbol, T::Hash[T.any(String, Symbol), T.anything]))
|
2020-08-20 10:26:37 -04:00
|
|
|
end
|
|
|
|
end
|
2020-07-09 13:01:10 +08:00
|
|
|
|
2024-04-13 00:23:00 -04:00
|
|
|
# The phases for which network access is allowed. By default, network
|
|
|
|
# access is allowed for all phases. Valid phases are `:build`, `:test`,
|
|
|
|
# and `:postinstall`. When no argument is passed, network access will be
|
|
|
|
# allowed for all phases.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# allow_network_access!
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# allow_network_access! :build
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# allow_network_access! [:build, :test]
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# @!attribute [w] allow_network_access!
|
2024-04-13 00:23:00 -04:00
|
|
|
sig { params(phases: T.any(Symbol, T::Array[Symbol])).void }
|
|
|
|
def allow_network_access!(phases = [])
|
|
|
|
phases_array = Array(phases)
|
|
|
|
if phases_array.empty?
|
2025-02-16 22:20:37 -08:00
|
|
|
network_access_allowed.each_key { |phase| network_access_allowed[phase] = true }
|
2024-04-13 00:23:00 -04:00
|
|
|
else
|
|
|
|
phases_array.each do |phase|
|
|
|
|
raise ArgumentError, "Unknown phase: #{phase}" unless SUPPORTED_NETWORK_ACCESS_PHASES.include?(phase)
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
network_access_allowed[phase] = true
|
2024-04-13 00:23:00 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# The phases for which network access is denied. By default, network
|
|
|
|
# access is allowed for all phases. Valid phases are `:build`, `:test`,
|
|
|
|
# and `:postinstall`. When no argument is passed, network access will be
|
|
|
|
# denied for all phases.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# deny_network_access!
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# deny_network_access! :build
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# deny_network_access! [:build, :test]
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# @!attribute [w] deny_network_access!
|
2024-04-13 00:23:00 -04:00
|
|
|
sig { params(phases: T.any(Symbol, T::Array[Symbol])).void }
|
|
|
|
def deny_network_access!(phases = [])
|
|
|
|
phases_array = Array(phases)
|
|
|
|
if phases_array.empty?
|
2025-02-16 22:20:37 -08:00
|
|
|
network_access_allowed.each_key { |phase| network_access_allowed[phase] = false }
|
2024-04-13 00:23:00 -04:00
|
|
|
else
|
|
|
|
phases_array.each do |phase|
|
|
|
|
raise ArgumentError, "Unknown phase: #{phase}" unless SUPPORTED_NETWORK_ACCESS_PHASES.include?(phase)
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
network_access_allowed[phase] = false
|
2024-04-13 00:23:00 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Whether the specified phase should be forced offline.
|
|
|
|
sig { params(phase: Symbol).returns(T::Boolean) }
|
|
|
|
def network_access_allowed?(phase)
|
|
|
|
raise ArgumentError, "Unknown phase: #{phase}" unless SUPPORTED_NETWORK_ACCESS_PHASES.include?(phase)
|
|
|
|
|
|
|
|
env_var = Homebrew::EnvConfig.send(:"formula_#{phase}_network")
|
2025-02-16 22:20:37 -08:00
|
|
|
env_var.nil? ? network_access_allowed[phase] : env_var == "allow"
|
2024-04-13 00:23:00 -04:00
|
|
|
end
|
|
|
|
|
2014-12-06 11:26:43 +00:00
|
|
|
# The homepage for the software. Used by users to get more information
|
|
|
|
# about the software and Homebrew maintainers as a point of contact for
|
|
|
|
# e.g. submitting patches.
|
2014-12-26 20:24:12 +00:00
|
|
|
# Can be opened with running `brew home`.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# homepage "https://www.example.com"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-23 13:41:23 -08:00
|
|
|
sig { params(val: String).returns(T.nilable(String)) }
|
|
|
|
def homepage(val = T.unsafe(nil))
|
2025-02-23 13:18:49 -08:00
|
|
|
val.nil? ? @homepage : @homepage = T.let(val, T.nilable(String))
|
|
|
|
end
|
2014-12-06 11:26:43 +00:00
|
|
|
|
2024-04-26 20:55:51 +02:00
|
|
|
# Checks whether a `livecheck` specification is defined or not.
|
|
|
|
#
|
|
|
|
# It returns `true` when a `livecheck` block is present in the {Formula}
|
|
|
|
# and `false` otherwise.
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
livecheck: clarify livecheckable language
Formulae, casks, and resources have a `#livecheckable?` method that
indicates whether they contain a `livecheck` block. This is intended
to be read as "has a livecheckable?", not "is livecheckable?" (as
livecheck can find versions for some packages/resources without a
`livecheck` block). Unfortunately, correct understanding of this
method's behavior [outside of documentation] relies on historical
knowledge that few people possess, so this is often confusing to
anyone who hasn't been working on livecheck since 2020.
In the olden days, a "livecheckable" was a Ruby file containing a
`livecheck` block (originally a hash) with a filename that
corresponded to a related formula. The `livecheck` blocks in
livecheckable files were integrated into their respective formulae in
August 2020, so [first-party] livecheckables ceased to exist at that
time. From that point forward, we simply referred to these as
`livecheck` blocks.
With that in mind, this clarifies the situation by replacing
"livecheckable" language. This includes renaming `#livecheckable?` to
`#livecheck_defined?`, replacing usage of "livecheckable" as a noun
with "`livecheck` block", replacing "livecheckable" as a boolean with
"livecheck_defined", and replacing incorrect usage of "livecheckable"
as an adjective with "checkable".
2024-11-27 18:20:56 -05:00
|
|
|
def livecheck_defined?
|
|
|
|
@livecheck_defined == true
|
|
|
|
end
|
|
|
|
|
|
|
|
# Checks whether a `livecheck` specification is defined or not. This is a
|
|
|
|
# legacy alias for `#livecheck_defined?`.
|
|
|
|
#
|
|
|
|
# It returns `true` when a `livecheck` block is present in the {Formula}
|
|
|
|
# and `false` otherwise.
|
|
|
|
sig { returns(T::Boolean) }
|
2020-03-16 01:37:49 +05:30
|
|
|
def livecheckable?
|
livecheck: clarify livecheckable language
Formulae, casks, and resources have a `#livecheckable?` method that
indicates whether they contain a `livecheck` block. This is intended
to be read as "has a livecheckable?", not "is livecheckable?" (as
livecheck can find versions for some packages/resources without a
`livecheck` block). Unfortunately, correct understanding of this
method's behavior [outside of documentation] relies on historical
knowledge that few people possess, so this is often confusing to
anyone who hasn't been working on livecheck since 2020.
In the olden days, a "livecheckable" was a Ruby file containing a
`livecheck` block (originally a hash) with a filename that
corresponded to a related formula. The `livecheck` blocks in
livecheckable files were integrated into their respective formulae in
August 2020, so [first-party] livecheckables ceased to exist at that
time. From that point forward, we simply referred to these as
`livecheck` blocks.
With that in mind, this clarifies the situation by replacing
"livecheckable" language. This includes renaming `#livecheckable?` to
`#livecheck_defined?`, replacing usage of "livecheckable" as a noun
with "`livecheck` block", replacing "livecheckable" as a boolean with
"livecheck_defined", and replacing incorrect usage of "livecheckable"
as an adjective with "checkable".
2024-11-27 18:20:56 -05:00
|
|
|
# odeprecated "`livecheckable?`", "`livecheck_defined?`"
|
|
|
|
@livecheck_defined == true
|
2020-03-16 01:37:49 +05:30
|
|
|
end
|
|
|
|
|
2024-04-26 20:55:51 +02:00
|
|
|
# Checks whether a service specification is defined or not.
|
|
|
|
#
|
|
|
|
# It returns `true` when a service block is present in the {Formula}
|
|
|
|
# and `false` otherwise.
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2020-12-11 23:14:50 +01:00
|
|
|
def service?
|
2021-04-08 10:06:45 +02:00
|
|
|
@service_block.present?
|
2020-12-11 23:14:50 +01:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(T::Array[FormulaConflict])) }
|
2024-04-26 20:55:51 +02:00
|
|
|
attr_reader :conflicts
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(T::Set[T.any(String, Symbol)])) }
|
|
|
|
attr_reader :skip_clean_paths
|
|
|
|
|
|
|
|
sig { returns(T.nilable(T::Set[String])) }
|
|
|
|
attr_reader :link_overwrite_paths
|
|
|
|
|
|
|
|
sig { returns(T.nilable(Symbol)) }
|
|
|
|
attr_reader :pour_bottle_only_if
|
2022-08-24 23:53:35 +01:00
|
|
|
|
2016-01-09 11:06:17 +00:00
|
|
|
# If `pour_bottle?` returns `false` the user-visible reason to display for
|
|
|
|
# why they cannot use the bottle.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(String)) }
|
2016-01-09 11:06:17 +00:00
|
|
|
attr_accessor :pour_bottle_check_unsatisfied_reason
|
|
|
|
|
2014-12-06 11:26:43 +00:00
|
|
|
# Used for creating new Homebrew versions of software without new upstream
|
2020-11-05 17:17:03 -05:00
|
|
|
# versions. For example, if we bump the major version of a library that this
|
2014-12-06 11:26:43 +00:00
|
|
|
# {Formula} {.depends_on} then we may need to update the `revision` of this
|
|
|
|
# {Formula} to install a new version linked against the new library version.
|
|
|
|
# `0` if unset.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# revision 1
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-23 13:41:23 -08:00
|
|
|
sig { params(val: Integer).returns(T.nilable(Integer)) }
|
|
|
|
def revision(val = T.unsafe(nil))
|
2025-02-23 13:18:49 -08:00
|
|
|
val.nil? ? @revision : @revision = T.let(val, T.nilable(Integer))
|
|
|
|
end
|
2009-10-17 14:35:24 +02:00
|
|
|
|
2018-10-18 21:42:43 -04:00
|
|
|
# Used for creating new Homebrew version schemes. For example, if we want
|
2016-08-11 09:54:47 +02:00
|
|
|
# to change version scheme from one to another, then we may need to update
|
2020-11-05 17:17:03 -05:00
|
|
|
# `version_scheme` of this {Formula} to be able to use new version scheme,
|
2018-10-18 21:42:43 -04:00
|
|
|
# e.g. to move from 20151020 scheme to 1.0.0 we need to increment
|
2016-08-11 10:00:39 +02:00
|
|
|
# `version_scheme`. Without this, the prior scheme will always equate to a
|
|
|
|
# higher version.
|
2016-08-11 09:54:47 +02:00
|
|
|
# `0` if unset.
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# version_scheme 1
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-23 13:41:23 -08:00
|
|
|
sig { params(val: Integer).returns(T.nilable(Integer)) }
|
|
|
|
def version_scheme(val = T.unsafe(nil))
|
2025-02-23 13:18:49 -08:00
|
|
|
val.nil? ? @version_scheme : @version_scheme = T.let(val, T.nilable(Integer))
|
|
|
|
end
|
2016-08-11 09:54:47 +02:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[Symbol]) }
|
2023-06-19 06:07:53 +01:00
|
|
|
def spec_syms
|
|
|
|
[:stable, :head].freeze
|
|
|
|
end
|
|
|
|
|
2020-09-03 10:34:22 +01:00
|
|
|
# A list of the {.stable} and {.head} {SoftwareSpec}s.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[SoftwareSpec]) }
|
2013-09-17 21:25:39 -05:00
|
|
|
def specs
|
2023-06-19 06:07:53 +01:00
|
|
|
spec_syms.map do |sym|
|
|
|
|
send(sym)
|
|
|
|
end.freeze
|
2013-09-17 21:25:39 -05:00
|
|
|
end
|
|
|
|
|
2018-10-18 21:42:43 -04:00
|
|
|
# The URL used to download the source for the {.stable} version of the formula.
|
2014-12-26 20:24:12 +00:00
|
|
|
# We prefer `https` for security and proxy reasons.
|
2022-11-06 22:50:07 -05:00
|
|
|
# If not inferable, specify the download strategy with `using: ...`.
|
2018-10-18 21:42:43 -04:00
|
|
|
#
|
|
|
|
# - `:git`, `:hg`, `:svn`, `:bzr`, `:fossil`, `:cvs`,
|
2020-11-03 16:36:48 -05:00
|
|
|
# - `:curl` (normal file download, will also extract)
|
2018-10-18 21:42:43 -04:00
|
|
|
# - `:nounzip` (without extracting)
|
|
|
|
# - `:post` (download via an HTTP POST)
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# url "https://packed.sources.and.we.prefer.https.example.com/archive-1.2.3.tar.bz2"
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# url "https://some.dont.provide.archives.example.com",
|
2020-11-03 16:36:48 -05:00
|
|
|
# using: :git,
|
|
|
|
# tag: "1.2.3",
|
2024-04-26 20:55:51 +02:00
|
|
|
# revision: "db8e4de5b2d6653f66aea53094624468caad15d2"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# @!attribute [w] url
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(val: String, specs: T::Hash[Symbol, T.any(String, Symbol)]).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def url(val, specs = {})
|
Eagerly initialize formula specs
Declarations of dependencies, options, and resources in the DSL only
apply to specs that have already been initialized. For example, given
this snippet:
url ...
sha1 ...
depends_on 'foo'
devel do
url ...
sha1 ...
end
The dependency 'foo' will be recorded for the stable spec, but not the
devel spec, since it was not initialized prior to the call to
depends_on.
While it is considered best practice to declare all specs (stable,
devel, head, and bottle) prior to other declarations, there is nothing
that enforces this ordering, so when it happens it can be confusing and
hard to debug.
To prevent this, we can initialize all specs up front. This comes with
a performance penalty for commands that load all formulae into memory,
but that is probably outweighed by what we gain in correctness.
Fixes Homebrew/homebrew#23425.
2013-10-22 13:07:08 -05:00
|
|
|
stable.url(val, specs)
|
2012-07-30 11:32:56 -07:00
|
|
|
end
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# @!attribute [w] version
|
2018-10-18 21:42:43 -04:00
|
|
|
# The version string for the {.stable} version of the formula.
|
2014-12-26 20:24:12 +00:00
|
|
|
# The version is autodetected from the URL and/or tag so only needs to be
|
|
|
|
# declared if it cannot be autodetected correctly.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# version "1.2-final"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(val: T.nilable(String)).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def version(val = nil)
|
Eagerly initialize formula specs
Declarations of dependencies, options, and resources in the DSL only
apply to specs that have already been initialized. For example, given
this snippet:
url ...
sha1 ...
depends_on 'foo'
devel do
url ...
sha1 ...
end
The dependency 'foo' will be recorded for the stable spec, but not the
devel spec, since it was not initialized prior to the call to
depends_on.
While it is considered best practice to declare all specs (stable,
devel, head, and bottle) prior to other declarations, there is nothing
that enforces this ordering, so when it happens it can be confusing and
hard to debug.
To prevent this, we can initialize all specs up front. This comes with
a performance penalty for commands that load all formulae into memory,
but that is probably outweighed by what we gain in correctness.
Fixes Homebrew/homebrew#23425.
2013-10-22 13:07:08 -05:00
|
|
|
stable.version(val)
|
2013-09-22 16:04:25 -05:00
|
|
|
end
|
|
|
|
|
2015-01-04 14:25:59 -05:00
|
|
|
# @!attribute [w] mirror
|
2018-10-18 21:42:43 -04:00
|
|
|
# Additional URLs for the {.stable} version of the formula.
|
2014-12-26 20:24:12 +00:00
|
|
|
# These are only used if the {.url} fails to download. It's optional and
|
|
|
|
# there can be more than one. Generally we add them when the main {.url}
|
|
|
|
# is unreliable. If {.url} is really unreliable then we may swap the
|
|
|
|
# {.mirror} and {.url}.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# mirror "https://in.case.the.host.is.down.example.com"
|
|
|
|
# mirror "https://in.case.the.mirror.is.down.example.com
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(val: String).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def mirror(val)
|
Eagerly initialize formula specs
Declarations of dependencies, options, and resources in the DSL only
apply to specs that have already been initialized. For example, given
this snippet:
url ...
sha1 ...
depends_on 'foo'
devel do
url ...
sha1 ...
end
The dependency 'foo' will be recorded for the stable spec, but not the
devel spec, since it was not initialized prior to the call to
depends_on.
While it is considered best practice to declare all specs (stable,
devel, head, and bottle) prior to other declarations, there is nothing
that enforces this ordering, so when it happens it can be confusing and
hard to debug.
To prevent this, we can initialize all specs up front. This comes with
a performance penalty for commands that load all formulae into memory,
but that is probably outweighed by what we gain in correctness.
Fixes Homebrew/homebrew#23425.
2013-10-22 13:07:08 -05:00
|
|
|
stable.mirror(val)
|
2013-09-22 16:04:25 -05:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @!attribute [w] sha256
|
2014-12-26 20:24:12 +00:00
|
|
|
# @scope class
|
2018-10-18 21:42:43 -04:00
|
|
|
# To verify the cached download's integrity and security we verify the
|
2020-11-05 17:17:03 -05:00
|
|
|
# SHA-256 hash matches what we've declared in the {Formula}. To quickly fill
|
2014-12-26 20:24:12 +00:00
|
|
|
# this value you can leave it blank and run `brew fetch --force` and it'll
|
|
|
|
# tell you the currently valid value.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# sha256 "2a2ba417eebaadcb4418ee7b12fe2998f26d6e6f7fda7983412ff66a741ab6f7"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(val: String).void }
|
2021-01-07 08:33:57 +01:00
|
|
|
def sha256(val)
|
|
|
|
stable.sha256(val)
|
2013-09-22 16:04:25 -05:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# Adds a {.bottle} {SoftwareSpec}.
|
|
|
|
# This provides a pre-built binary package built by the Homebrew maintainers for you.
|
2015-10-19 17:09:13 +01:00
|
|
|
# It will be installed automatically if there is a binary package for your platform
|
|
|
|
# and you haven't passed or previously used any options on this formula.
|
|
|
|
#
|
2015-08-29 10:56:24 +01:00
|
|
|
# If you maintain your own repository, you can add your own bottle links.
|
2020-11-03 12:39:26 -05:00
|
|
|
# @see https://docs.brew.sh/Bottles Bottles
|
2017-07-31 19:24:33 -07:00
|
|
|
# You can ignore this block entirely if submitting to Homebrew/homebrew-core.
|
|
|
|
# It'll be handled for you by the Brew Test Bot.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# bottle do
|
2020-11-05 17:17:03 -05:00
|
|
|
# root_url "https://example.com" # Optional root to calculate bottle URLs.
|
|
|
|
# rebuild 1 # Marks the old bottle as outdated without bumping the version/revision of the formula.
|
2021-02-06 14:27:03 -05:00
|
|
|
# # Optionally specify the HOMEBREW_CELLAR in which the bottles were built.
|
|
|
|
# sha256 cellar: "/brew/Cellar", catalina: "ef65c759c5097a36323fa9c77756468649e8d1980a3a4e05695c05e39568967c"
|
|
|
|
# sha256 cellar: :any, mojave: "28f4090610946a4eb207df102d841de23ced0d06ba31cb79e040d883906dcd4f"
|
|
|
|
# sha256 high_sierra: "91dd0caca9bd3f38c439d5a7b6f68440c4274945615fae035ff0a369264b8a2f"
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2015-09-14 19:51:04 +08:00
|
|
|
#
|
2024-03-07 10:01:56 -05:00
|
|
|
# Homebrew maintainers aim to bottle all formulae.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2022-08-31 19:47:19 +01:00
|
|
|
sig { params(block: T.proc.bind(BottleSpecification).void).void }
|
|
|
|
def bottle(&block)
|
|
|
|
stable.bottle(&block)
|
2014-03-10 14:56:02 -05:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(String) }
|
2013-09-22 16:04:25 -05:00
|
|
|
def build
|
Eagerly initialize formula specs
Declarations of dependencies, options, and resources in the DSL only
apply to specs that have already been initialized. For example, given
this snippet:
url ...
sha1 ...
depends_on 'foo'
devel do
url ...
sha1 ...
end
The dependency 'foo' will be recorded for the stable spec, but not the
devel spec, since it was not initialized prior to the call to
depends_on.
While it is considered best practice to declare all specs (stable,
devel, head, and bottle) prior to other declarations, there is nothing
that enforces this ordering, so when it happens it can be confusing and
hard to debug.
To prevent this, we can initialize all specs up front. This comes with
a performance penalty for commands that load all formulae into memory,
but that is probably outweighed by what we gain in correctness.
Fixes Homebrew/homebrew#23425.
2013-10-22 13:07:08 -05:00
|
|
|
stable.build
|
2009-10-17 14:35:24 +02:00
|
|
|
end
|
2009-09-28 14:06:53 -07:00
|
|
|
|
2020-07-30 10:10:42 +02:00
|
|
|
# Get the `BUILD_FLAGS` from the formula's namespace set in `Formulary::load_formula`.
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T::Array[String]) }
|
2020-07-26 07:24:14 +02:00
|
|
|
def build_flags
|
2020-11-24 15:46:47 +01:00
|
|
|
namespace = T.must(to_s.split("::")[0..-2]).join("::")
|
2020-07-30 10:10:42 +02:00
|
|
|
return [] if namespace.empty?
|
2020-07-26 07:24:14 +02:00
|
|
|
|
2020-07-30 10:10:42 +02:00
|
|
|
mod = const_get(namespace)
|
2020-07-26 07:24:14 +02:00
|
|
|
mod.const_get(:BUILD_FLAGS)
|
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @!attribute [w] stable
|
2018-10-18 21:42:43 -04:00
|
|
|
# Allows adding {.depends_on} and {Patch}es just to the {.stable} {SoftwareSpec}.
|
2015-08-29 10:56:24 +01:00
|
|
|
# This is required instead of using a conditional.
|
2022-11-06 22:50:07 -05:00
|
|
|
# It is preferable to also pull the {url} and {sha256= sha256} into the block if one is added.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# stable do
|
2015-08-29 10:56:24 +01:00
|
|
|
# url "https://example.com/foo-1.0.tar.gz"
|
|
|
|
# sha256 "2a2ba417eebaadcb4418ee7b12fe2998f26d6e6f7fda7983412ff66a741ab6f7"
|
|
|
|
#
|
|
|
|
# depends_on "libxml2"
|
|
|
|
# depends_on "libffi"
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(block: T.nilable(T.proc.returns(SoftwareSpec))).returns(T.untyped) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def stable(&block)
|
2025-02-16 22:20:37 -08:00
|
|
|
return T.must(@stable) unless block
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
T.must(@stable).instance_eval(&block)
|
2012-01-22 22:32:15 -06:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @!attribute [w] head
|
|
|
|
# Adds a {.head} {SoftwareSpec}.
|
|
|
|
# This can be installed by passing the `--HEAD` option to allow
|
|
|
|
# installing software directly from a branch of a version-control repository.
|
|
|
|
# If called as a method this provides just the {url} for the {SoftwareSpec}.
|
2018-10-18 21:42:43 -04:00
|
|
|
# If a block is provided you can also add {.depends_on} and {Patch}es just to the {.head} {SoftwareSpec}.
|
2015-08-29 10:56:24 +01:00
|
|
|
# The download strategies (e.g. `:using =>`) are the same as for {url}.
|
2020-11-03 16:36:48 -05:00
|
|
|
# `master` is the default branch and doesn't need stating with a `branch:` parameter.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# head "https://we.prefer.https.over.git.example.com/.git"
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# head "https://example.com/.git", branch: "name_of_branch"
|
|
|
|
# ```
|
|
|
|
#
|
2015-08-29 10:56:24 +01:00
|
|
|
# or (if autodetect fails):
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# head "https://hg.is.awesome.but.git.has.won.example.com/", using: :hg
|
|
|
|
# ```
|
2025-02-16 22:20:37 -08:00
|
|
|
sig {
|
|
|
|
params(val: T.nilable(String), specs: T::Hash[Symbol, T.untyped], block: T.nilable(T.proc.void))
|
|
|
|
.returns(T.untyped)
|
|
|
|
}
|
2015-08-03 13:09:07 +01:00
|
|
|
def head(val = nil, specs = {}, &block)
|
2020-11-16 22:18:56 +01:00
|
|
|
if block
|
2025-02-16 22:20:37 -08:00
|
|
|
T.must(@head).instance_eval(&block)
|
2013-09-13 11:13:12 -05:00
|
|
|
elsif val
|
2025-02-16 22:20:37 -08:00
|
|
|
T.must(@head).url(val, specs)
|
2013-09-13 11:13:12 -05:00
|
|
|
else
|
|
|
|
@head
|
|
|
|
end
|
2012-04-05 21:09:24 -05:00
|
|
|
end
|
2012-03-18 20:37:10 +13:00
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Additional downloads can be defined as {resource}s and accessed in the
|
2020-06-10 09:06:36 +01:00
|
|
|
# install method. Resources can also be defined inside a {.stable} or
|
2018-10-18 21:42:43 -04:00
|
|
|
# {.head} block. This mechanism replaces ad-hoc "subformula" classes.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# resource "additional_files" do
|
2015-08-29 10:56:24 +01:00
|
|
|
# url "https://example.com/additional-stuff.tar.gz"
|
|
|
|
# sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2"
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2024-05-03 21:47:49 +02:00
|
|
|
sig { params(name: String, klass: T.class_of(Resource), block: T.nilable(T.proc.bind(Resource).void)).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def resource(name, klass = Resource, &block)
|
2013-09-17 21:25:40 -05:00
|
|
|
specs.each do |spec|
|
2014-06-02 23:32:42 -07:00
|
|
|
spec.resource(name, klass, &block) unless spec.resource_defined?(name)
|
2013-09-17 21:25:40 -05:00
|
|
|
end
|
2013-08-06 19:52:58 -07:00
|
|
|
end
|
|
|
|
|
2024-04-26 20:55:51 +02:00
|
|
|
# Specify a Go resource.
|
|
|
|
#
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(name: String, block: T.nilable(T.proc.void)).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def go_resource(name, &block)
|
2024-09-24 10:15:34 +01:00
|
|
|
odisabled "`Formula.go_resource`", "Go modules"
|
2015-04-02 21:43:28 -07:00
|
|
|
specs.each { |spec| spec.go_resource(name, &block) }
|
2014-06-02 23:32:42 -07:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# The dependencies for this formula. Use strings for the names of other
|
2021-01-09 13:34:17 +11:00
|
|
|
# formulae. Homebrew provides some `:special` {Requirement}s for stuff
|
|
|
|
# that needs extra handling (often changing some ENV vars or
|
|
|
|
# deciding whether to use the system provided version).
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Examples
|
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# `:build` means this dependency is only needed during build.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# depends_on "cmake" => :build
|
|
|
|
# ```
|
2021-01-09 13:34:17 +11:00
|
|
|
#
|
|
|
|
# `:test` means this dependency is only needed during testing.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# depends_on "node" => :test
|
|
|
|
# ```
|
2021-01-09 13:34:17 +11:00
|
|
|
#
|
|
|
|
# `:recommended` dependencies are built by default.
|
|
|
|
# But a `--without-...` option is generated to opt-out.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# depends_on "readline" => :recommended
|
|
|
|
# ```
|
2021-01-09 13:34:17 +11:00
|
|
|
#
|
|
|
|
# `:optional` dependencies are NOT built by default unless the
|
|
|
|
# auto-generated `--with-...` option is passed.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# depends_on "glib" => :optional
|
|
|
|
# ```
|
2021-01-09 13:34:17 +11:00
|
|
|
#
|
|
|
|
# If you need to specify that another formula has to be built with/out
|
|
|
|
# certain options (note, no `--` needed before the option):
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# depends_on "zeromq" => "with-pgm"
|
|
|
|
# depends_on "qt" => ["with-qtdbus", "developer"] # Multiple options.
|
|
|
|
# ```
|
2021-01-09 13:34:17 +11:00
|
|
|
#
|
2023-02-10 23:15:40 -05:00
|
|
|
# Optional and enforce that "boost" is built using `--with-c++11`.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# depends_on "boost" => [:optional, "with-c++11"]
|
|
|
|
# ```
|
2021-01-09 13:34:17 +11:00
|
|
|
#
|
|
|
|
# If a dependency is only needed in certain cases:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# depends_on "sqlite" if MacOS.version >= :catalina
|
2020-11-03 16:36:48 -05:00
|
|
|
# depends_on xcode: :build # If the formula really needs full Xcode to compile.
|
|
|
|
# depends_on macos: :mojave # Needs at least macOS Mojave (10.14) to run.
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```
|
2021-01-09 13:34:17 +11:00
|
|
|
#
|
|
|
|
# It is possible to only depend on something if
|
|
|
|
# `build.with?` or `build.without? "another_formula"`:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# depends_on "postgresql" if build.without? "sqlite"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(dep: T.any(String, Symbol, T::Hash[String, T.untyped])).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def depends_on(dep)
|
2013-09-21 19:27:24 -05:00
|
|
|
specs.each { |spec| spec.depends_on(dep) }
|
2009-09-18 19:16:39 +01:00
|
|
|
end
|
2009-09-28 14:06:53 -07:00
|
|
|
|
2020-04-07 21:23:12 +02:00
|
|
|
# Indicates use of dependencies provided by macOS.
|
2021-10-23 21:32:38 -04:00
|
|
|
# On macOS this is a no-op (as we use the provided system libraries) unless
|
|
|
|
# `:since` specifies a minimum macOS version.
|
2020-11-05 17:17:03 -05:00
|
|
|
# On Linux this will act as {.depends_on}.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2024-02-12 23:45:03 +01:00
|
|
|
sig {
|
|
|
|
params(
|
2024-02-13 00:42:54 +01:00
|
|
|
dep: T.any(String, T::Hash[T.any(String, Symbol), T.any(Symbol, T::Array[Symbol])]),
|
|
|
|
bounds: T::Hash[Symbol, Symbol],
|
2024-02-12 23:45:03 +01:00
|
|
|
).void
|
|
|
|
}
|
2020-04-28 14:17:54 +01:00
|
|
|
def uses_from_macos(dep, bounds = {})
|
|
|
|
specs.each { |spec| spec.uses_from_macos(dep, bounds) }
|
2019-05-22 14:08:55 -03:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @!attribute [w] option
|
|
|
|
# Options can be used as arguments to `brew install`.
|
|
|
|
# To switch features on/off: `"with-something"` or `"with-otherthing"`.
|
2020-11-05 17:17:03 -05:00
|
|
|
# To use other software: `"with-other-software"` or `"without-foo"`.
|
2018-10-18 21:42:43 -04:00
|
|
|
# Note that for {.depends_on} that are `:optional` or `:recommended`, options
|
2015-08-29 10:56:24 +01:00
|
|
|
# are generated automatically.
|
|
|
|
#
|
|
|
|
# There are also some special options:
|
2018-10-18 21:42:43 -04:00
|
|
|
#
|
2015-08-29 10:56:24 +01:00
|
|
|
# - `:universal`: build a universal binary/library (e.g. on newer Intel Macs
|
|
|
|
# this means a combined x86_64/x86 binary/library).
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# option "with-spam", "The description goes here without a dot at the end"
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# option "with-qt", "Text here overwrites what's autogenerated by 'depends_on "qt" => :optional'"
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# option :universal
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(name: String, description: String).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def option(name, description = "")
|
2013-09-21 19:27:24 -05:00
|
|
|
specs.each { |spec| spec.option(name, description) }
|
2012-07-30 11:32:56 -07:00
|
|
|
end
|
2012-11-25 15:06:41 +00:00
|
|
|
|
2015-12-06 22:18:16 +00:00
|
|
|
# @!attribute [w] deprecated_option
|
|
|
|
# Deprecated options are used to rename options and migrate users who used
|
|
|
|
# them to newer ones. They are mostly used for migrating non-`with` options
|
|
|
|
# (e.g. `enable-debug`) to `with` options (e.g. `with-debug`).
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# deprecated_option "enable-debug" => "with-debug"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(hash: T::Hash[String, String]).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def deprecated_option(hash)
|
2014-10-16 13:01:05 +01:00
|
|
|
specs.each { |spec| spec.deprecated_option(hash) }
|
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# External patches can be declared using resource-style blocks.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# patch do
|
2015-08-29 10:56:24 +01:00
|
|
|
# url "https://example.com/example_patch.diff"
|
|
|
|
# sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2"
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# A strip level of `-p1` is assumed. It can be overridden using a symbol
|
|
|
|
# argument:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# patch :p0 do
|
2015-08-29 10:56:24 +01:00
|
|
|
# url "https://example.com/example_patch.diff"
|
|
|
|
# sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2"
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2020-06-10 09:06:36 +01:00
|
|
|
# Patches can be declared in stable and head blocks. This form is
|
2015-08-29 10:56:24 +01:00
|
|
|
# preferred over using conditionals.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# stable do
|
2015-08-29 10:56:24 +01:00
|
|
|
# patch do
|
|
|
|
# url "https://example.com/example_patch.diff"
|
|
|
|
# sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2"
|
|
|
|
# end
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# Embedded (`__END__`) patches are declared like so:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# patch :DATA
|
|
|
|
# patch :p0, :DATA
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# Patches can also be embedded by passing a string. This makes it possible
|
|
|
|
# to provide multiple embedded patches while making only some of them
|
|
|
|
# conditional.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# patch :p0, "..."
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# @see https://docs.brew.sh/Formula-Cookbook#patches Patches
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig {
|
|
|
|
params(strip: T.any(String, Symbol), src: T.any(NilClass, String, Symbol), block: T.nilable(T.proc.void)).void
|
|
|
|
}
|
2015-08-03 13:09:07 +01:00
|
|
|
def patch(strip = :p1, src = nil, &block)
|
2014-07-29 16:06:07 -05:00
|
|
|
specs.each { |spec| spec.patch(strip, src, &block) }
|
2014-03-13 19:51:23 -05:00
|
|
|
end
|
|
|
|
|
2020-11-03 16:36:48 -05:00
|
|
|
# One or more formulae that conflict with this one and why.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# conflicts_with "imagemagick", because: "both install `convert` binaries"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(names: T.untyped).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def conflicts_with(*names)
|
2025-02-16 22:20:37 -08:00
|
|
|
opts = T.let(names.last.is_a?(Hash) ? names.pop : {}, T::Hash[Symbol, T.untyped])
|
|
|
|
names.each { |name| T.must(conflicts) << FormulaConflict.new(name, opts[:because]) }
|
2012-07-28 13:02:46 -03:00
|
|
|
end
|
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# Skip cleaning paths in a formula.
|
|
|
|
#
|
|
|
|
# Sometimes the formula {Cleaner cleaner} breaks things.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# Preserve cleaned paths with:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# skip_clean "bin/foo", "lib/bar"
|
|
|
|
# ```
|
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# Keep .la files with:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# skip_clean :la
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(paths: T.any(String, Symbol)).returns(T::Set[T.any(String, Symbol)]) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def skip_clean(*paths)
|
2013-06-20 16:18:01 -05:00
|
|
|
paths.flatten!
|
2014-02-23 12:09:28 -08:00
|
|
|
# Specifying :all is deprecated and will become an error
|
2025-02-16 22:20:37 -08:00
|
|
|
T.must(skip_clean_paths).merge(paths)
|
2009-09-28 14:06:53 -07:00
|
|
|
end
|
2010-07-04 14:17:03 -07:00
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# Software that will not be symlinked into the `brew --prefix` and will
|
|
|
|
# only live in its Cellar. Other formulae can depend on it and Homebrew
|
2024-04-26 20:55:51 +02:00
|
|
|
# will add the necessary includes, libraries and other paths while
|
2021-01-09 13:34:17 +11:00
|
|
|
# building that other formula.
|
|
|
|
#
|
|
|
|
# Keg-only formulae are not in your PATH and are not seen by compilers
|
|
|
|
# if you build your own software outside of Homebrew. This way, we
|
|
|
|
# don't shadow software provided by macOS.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# keg_only :provided_by_macos
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# keg_only :versioned_formulae
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# keg_only "because I want it so"
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(reason: T.any(String, Symbol), explanation: String).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def keg_only(reason, explanation = "")
|
2025-02-16 22:20:37 -08:00
|
|
|
@keg_only_reason = T.let(KegOnlyReason.new(reason, explanation), T.nilable(KegOnlyReason))
|
2010-07-18 10:38:45 -07:00
|
|
|
end
|
2011-03-21 14:23:28 -07:00
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# Pass `:skip` to this method to disable post-install stdlib checking.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(check_type: Symbol).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def cxxstdlib_check(check_type)
|
2014-08-16 02:05:13 -05:00
|
|
|
define_method(:skip_cxxstdlib_check?) { true } if check_type == :skip
|
2014-04-21 18:50:22 +01:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# Marks the {Formula} as failing with a particular compiler so it will fall back to others.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
2013-09-28 12:21:16 -07:00
|
|
|
# For Apple compilers, this should be in the format:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# fails_with :clang do
|
2015-08-29 10:56:24 +01:00
|
|
|
# build 600
|
|
|
|
# cause "multiple configure and compile errors"
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# The block may be omitted and if present, the build may be omitted;
|
2020-06-06 21:10:16 +01:00
|
|
|
# if so, then the compiler will not be allowed for *all* versions.
|
2013-09-28 12:21:16 -07:00
|
|
|
#
|
|
|
|
# `major_version` should be the major release number only, for instance
|
2019-01-08 19:13:46 +00:00
|
|
|
# '7' for the GCC 7 series (7.0, 7.1, etc.).
|
2020-06-06 21:10:16 +01:00
|
|
|
# If `version` or the block is omitted, then the compiler will
|
|
|
|
# not be allowed for all compilers in that series.
|
2013-09-28 12:21:16 -07:00
|
|
|
#
|
2019-01-08 19:13:46 +00:00
|
|
|
# For example, if a bug is only triggered on GCC 7.1 but is not
|
|
|
|
# encountered on 7.2:
|
2014-01-04 12:49:48 +00:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# fails_with :gcc => '7' do
|
2019-01-08 19:13:46 +00:00
|
|
|
# version '7.1'
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(compiler: T.any(Symbol, T::Hash[Symbol, String]), block: T.proc.void).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def fails_with(compiler, &block)
|
2014-08-19 17:14:02 -05:00
|
|
|
specs.each { |spec| spec.fails_with(compiler, &block) }
|
2011-03-21 14:23:28 -07:00
|
|
|
end
|
2012-11-01 14:40:59 -05:00
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# Marks the {Formula} as needing a certain standard, so Homebrew
|
|
|
|
# will fall back to other compilers if the default compiler
|
|
|
|
# does not implement that standard.
|
|
|
|
#
|
|
|
|
# We generally prefer to {.depends_on} a desired compiler and to
|
|
|
|
# explicitly use that compiler in a formula's {#install} block,
|
|
|
|
# rather than implicitly finding a suitable compiler with `needs`.
|
|
|
|
#
|
2023-09-09 09:02:21 -04:00
|
|
|
# @see .fails_with
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(standards: String).void }
|
2015-08-03 13:09:07 +01:00
|
|
|
def needs(*standards)
|
2014-08-19 17:14:02 -05:00
|
|
|
specs.each { |spec| spec.needs(*standards) }
|
2014-04-04 21:16:09 -07:00
|
|
|
end
|
|
|
|
|
2018-10-18 21:42:43 -04:00
|
|
|
# A test is required for new formulae and makes us happy.
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# The block will create, run in and delete a temporary directory.
|
|
|
|
#
|
2020-06-30 16:41:20 +02:00
|
|
|
# We want tests that don't require any user input
|
|
|
|
# and test the basic functionality of the application.
|
2020-11-05 17:17:03 -05:00
|
|
|
# For example, `foo build-foo input.foo` is a good test
|
|
|
|
# and `foo --version` or `foo --help` are bad tests.
|
2020-06-30 16:41:20 +02:00
|
|
|
# However, a bad test is better than no test at all.
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Examples
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ```ruby
|
|
|
|
# (testpath/"test.file").write <<~EOS
|
2015-08-29 10:56:24 +01:00
|
|
|
# writing some test file, if you need to
|
|
|
|
# EOS
|
2024-04-26 20:55:51 +02:00
|
|
|
# assert_equal "OK", shell_output("test_command test.file").strip
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# Need complete control over stdin, stdout?
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# require "open3"
|
2015-08-29 10:56:24 +01:00
|
|
|
# Open3.popen3("#{bin}/example", "argument") do |stdin, stdout, _|
|
|
|
|
# stdin.write("some text")
|
|
|
|
# stdin.close
|
|
|
|
# assert_equal "result", stdout.read
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# The test will fail if it returns false, or if an exception is raised.
|
|
|
|
# Failed assertions and failed `system` commands will raise exceptions.
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# @see https://docs.brew.sh/Formula-Cookbook#add-a-test-to-the-formula Tests
|
|
|
|
# @return [Boolean]
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(block: T.proc.returns(T.untyped)).returns(T.untyped) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def test(&block)
|
2014-09-18 14:16:07 -05:00
|
|
|
define_method(:test, &block)
|
2012-11-01 14:40:59 -05:00
|
|
|
end
|
2015-08-23 16:35:51 +08:00
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# {Livecheck} can be used to check for newer versions of the software.
|
2024-12-02 10:06:14 -05:00
|
|
|
# This method evaluates the DSL specified in the `livecheck` block of the
|
2021-01-09 13:34:17 +11:00
|
|
|
# {Formula} (if it exists) and sets the instance variables of a {Livecheck}
|
2020-11-05 17:17:03 -05:00
|
|
|
# object accordingly. This is used by `brew livecheck` to check for newer
|
2020-03-16 01:37:49 +05:30
|
|
|
# versions of the software.
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# livecheck do
|
2020-03-16 01:37:49 +05:30
|
|
|
# skip "Not maintained"
|
|
|
|
# url "https://example.com/foo/releases"
|
|
|
|
# regex /foo-(\d+(?:\.\d+)+)\.tar/
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# @!attribute [w] livecheck
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(block: T.nilable(T.proc.bind(Livecheck).returns(T.untyped))).returns(T.untyped) }
|
2020-03-16 01:37:49 +05:30
|
|
|
def livecheck(&block)
|
2020-11-16 22:18:56 +01:00
|
|
|
return @livecheck unless block
|
2020-03-16 01:37:49 +05:30
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@livecheck_defined = T.let(true, T.nilable(T::Boolean))
|
2020-03-16 01:37:49 +05:30
|
|
|
@livecheck.instance_eval(&block)
|
|
|
|
end
|
|
|
|
|
2020-12-11 23:14:50 +01:00
|
|
|
# Service can be used to define services.
|
|
|
|
# This method evaluates the DSL specified in the service block of the
|
|
|
|
# {Formula} (if it exists) and sets the instance variables of a Service
|
2022-11-06 13:52:53 +01:00
|
|
|
# object accordingly. This is used by `brew install` to generate a service file.
|
2020-12-11 23:14:50 +01:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Example
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# service do
|
2020-12-11 23:14:50 +01:00
|
|
|
# run [opt_bin/"foo"]
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# @!attribute [w] service
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig {
|
|
|
|
params(block: T.nilable(T.proc.returns(T.untyped)))
|
|
|
|
.returns(T.nilable(T.proc.returns(T.untyped)))
|
|
|
|
}
|
2020-12-11 23:14:50 +01:00
|
|
|
def service(&block)
|
2021-04-08 10:06:45 +02:00
|
|
|
return @service_block unless block
|
2020-12-11 23:14:50 +01:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@service_block = T.let(block, T.nilable(T.proc.returns(T.untyped)))
|
2020-12-11 23:14:50 +01:00
|
|
|
end
|
|
|
|
|
2016-01-09 11:06:17 +00:00
|
|
|
# Defines whether the {Formula}'s bottle can be used on the given Homebrew
|
|
|
|
# installation.
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# If the bottle requires the Xcode CLT to be installed a
|
2016-01-09 11:06:17 +00:00
|
|
|
# {Formula} would declare:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# pour_bottle? do
|
2016-01-09 11:06:17 +00:00
|
|
|
# reason "The bottle needs the Xcode CLT to be installed."
|
|
|
|
# satisfy { MacOS::CLT.installed? }
|
2024-04-26 20:55:51 +02:00
|
|
|
# end
|
|
|
|
# ```
|
2016-01-09 11:06:17 +00:00
|
|
|
#
|
|
|
|
# If `satisfy` returns `false` then a bottle will not be used and instead
|
|
|
|
# the {Formula} will be built from source and `reason` will be printed.
|
2021-05-15 14:05:50 -04:00
|
|
|
#
|
|
|
|
# Alternatively, a preset reason can be passed as a symbol:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# pour_bottle? only_if: :clt_installed
|
|
|
|
# ```
|
2024-04-22 21:05:48 +02:00
|
|
|
#
|
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig {
|
|
|
|
params(
|
|
|
|
only_if: T.nilable(Symbol),
|
|
|
|
block: T.nilable(T.proc.params(arg0: T.untyped).returns(T.any(T::Boolean, Symbol))),
|
|
|
|
).returns(T.any(T::Boolean, Symbol))
|
|
|
|
}
|
2021-05-20 11:24:08 -04:00
|
|
|
def pour_bottle?(only_if: nil, &block)
|
2025-02-16 22:20:37 -08:00
|
|
|
@pour_bottle_check = T.let(PourBottleCheck.new(self), T.nilable(PourBottleCheck))
|
|
|
|
@pour_bottle_only_if = T.let(only_if, T.nilable(Symbol))
|
2021-05-15 14:05:50 -04:00
|
|
|
|
2021-05-20 11:24:08 -04:00
|
|
|
if only_if.present? && block.present?
|
|
|
|
raise ArgumentError, "Do not pass both a preset condition and a block to `pour_bottle?`"
|
2021-05-17 15:33:09 -04:00
|
|
|
end
|
|
|
|
|
2021-05-20 11:24:08 -04:00
|
|
|
block ||= case only_if
|
|
|
|
when :clt_installed
|
2021-05-17 15:33:09 -04:00
|
|
|
lambda do |_|
|
2021-12-21 20:43:57 +08:00
|
|
|
on_macos do
|
2023-07-24 22:08:17 -07:00
|
|
|
T.bind(self, PourBottleCheck)
|
2025-02-09 20:16:16 +03:00
|
|
|
reason(+<<~EOS)
|
2024-12-21 19:39:04 +08:00
|
|
|
The bottle needs the Xcode Command Line Tools to be installed at /Library/Developer/CommandLineTools.
|
|
|
|
Development tools provided by Xcode.app are not sufficient.
|
|
|
|
|
|
|
|
You can install the Xcode Command Line Tools, if desired, with:
|
2021-05-15 14:05:50 -04:00
|
|
|
xcode-select --install
|
|
|
|
EOS
|
2023-07-24 22:08:17 -07:00
|
|
|
satisfy { MacOS::CLT.installed? }
|
2021-05-15 14:05:50 -04:00
|
|
|
end
|
|
|
|
end
|
2021-07-19 20:02:29 +08:00
|
|
|
when :default_prefix
|
|
|
|
lambda do |_|
|
2023-07-24 22:08:17 -07:00
|
|
|
T.bind(self, PourBottleCheck)
|
2024-09-04 10:05:50 -07:00
|
|
|
reason(<<~EOS)
|
2022-10-06 10:01:02 +01:00
|
|
|
The bottle (and many others) needs to be installed into #{Homebrew::DEFAULT_PREFIX}.
|
2021-07-20 09:07:09 +08:00
|
|
|
EOS
|
2023-07-24 22:08:17 -07:00
|
|
|
satisfy { HOMEBREW_PREFIX.to_s == Homebrew::DEFAULT_PREFIX }
|
2021-07-19 20:02:29 +08:00
|
|
|
end
|
2021-05-17 15:33:09 -04:00
|
|
|
else
|
2021-05-20 11:24:08 -04:00
|
|
|
raise ArgumentError, "Invalid preset `pour_bottle?` condition" if only_if.present?
|
2021-05-15 14:05:50 -04:00
|
|
|
end
|
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@pour_bottle_check.instance_eval(&T.unsafe(block))
|
2016-01-09 11:06:17 +00:00
|
|
|
end
|
|
|
|
|
2021-06-17 11:34:31 +01:00
|
|
|
# Deprecates a {Formula} (on the given date) so a warning is
|
2020-04-29 09:34:40 +01:00
|
|
|
# shown on each installation. If the date has not yet passed the formula
|
|
|
|
# will not be deprecated.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# deprecate! date: "2020-08-27", because: :unmaintained
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# deprecate! date: "2020-08-27", because: "has been replaced by foo"
|
|
|
|
# ```
|
|
|
|
#
|
2024-11-07 15:50:03 -05:00
|
|
|
# ```ruby
|
|
|
|
# deprecate! date: "2020-08-27", because: "has been replaced by foo", replacement: "foo"
|
|
|
|
# ```
|
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see https://docs.brew.sh/Deprecating-Disabling-and-Removing-Formulae
|
2023-12-03 21:59:03 -05:00
|
|
|
# @see DeprecateDisable::FORMULA_DEPRECATE_DISABLE_REASONS
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(date: String, because: T.any(NilClass, String, Symbol), replacement: T.nilable(String)).void }
|
2024-11-07 15:50:03 -05:00
|
|
|
def deprecate!(date:, because:, replacement: nil)
|
2025-02-16 22:20:37 -08:00
|
|
|
@deprecation_date = T.let(Date.parse(date), T.nilable(Date))
|
|
|
|
return if T.must(@deprecation_date) > Date.today
|
2020-08-27 16:40:12 -04:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@deprecation_reason = T.let(because, T.any(NilClass, String, Symbol))
|
|
|
|
@deprecation_replacement = T.let(replacement, T.nilable(String))
|
|
|
|
T.must(@deprecated = T.let(true, T.nilable(T::Boolean)))
|
2020-04-01 13:42:52 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# Whether this {Formula} is deprecated (i.e. warns on installation).
|
|
|
|
# Defaults to false.
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .deprecate!
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2020-04-01 13:42:52 +01:00
|
|
|
def deprecated?
|
|
|
|
@deprecated == true
|
|
|
|
end
|
|
|
|
|
2020-12-23 02:58:14 -05:00
|
|
|
# The date that this {Formula} was or becomes deprecated.
|
|
|
|
# Returns `nil` if no date is specified.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .deprecate!
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(Date)) }
|
2020-12-23 02:58:14 -05:00
|
|
|
attr_reader :deprecation_date
|
|
|
|
|
2020-08-27 10:42:57 -04:00
|
|
|
# The reason for deprecation of a {Formula}.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
2020-11-05 15:19:56 -05:00
|
|
|
# @return [nil] if no reason was provided or the formula is not deprecated.
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .deprecate!
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.any(NilClass, String, Symbol)) }
|
2020-08-27 10:42:57 -04:00
|
|
|
attr_reader :deprecation_reason
|
|
|
|
|
2024-11-07 15:50:03 -05:00
|
|
|
# The replacement for a deprecated {Formula}.
|
|
|
|
#
|
|
|
|
# @return [nil] if no replacement was provided or the formula is not deprecated.
|
|
|
|
# @see .deprecate!
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(String)) }
|
2024-11-07 15:50:03 -05:00
|
|
|
attr_reader :deprecation_replacement
|
|
|
|
|
2021-06-17 11:34:31 +01:00
|
|
|
# Disables a {Formula} (on the given date) so it cannot be
|
2020-04-29 09:34:40 +01:00
|
|
|
# installed. If the date has not yet passed the formula
|
|
|
|
# will be deprecated instead of disabled.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# disable! date: "2020-08-27", because: :does_not_build
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# disable! date: "2020-08-27", because: "has been replaced by foo"
|
|
|
|
# ```
|
|
|
|
#
|
2024-11-07 15:50:03 -05:00
|
|
|
# ```ruby
|
|
|
|
# disable! date: "2020-08-27", because: "has been replaced by foo", replacement: "foo"
|
|
|
|
# ```
|
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see https://docs.brew.sh/Deprecating-Disabling-and-Removing-Formulae
|
2023-12-03 21:59:03 -05:00
|
|
|
# @see DeprecateDisable::FORMULA_DEPRECATE_DISABLE_REASONS
|
2024-04-22 21:05:48 +02:00
|
|
|
# @api public
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(date: String, because: T.any(NilClass, String, Symbol), replacement: T.nilable(String)).void }
|
2024-11-07 15:50:03 -05:00
|
|
|
def disable!(date:, because:, replacement: nil)
|
2025-02-16 22:20:37 -08:00
|
|
|
@disable_date = T.let(Date.parse(date), T.nilable(Date))
|
2020-12-23 02:58:14 -05:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
if T.must(@disable_date) > Date.today
|
|
|
|
@deprecation_reason = T.let(because, T.any(NilClass, String, Symbol))
|
|
|
|
@deprecation_replacement = T.let(replacement, T.nilable(String))
|
|
|
|
@deprecated = T.let(true, T.nilable(T::Boolean))
|
2020-04-29 09:34:40 +01:00
|
|
|
return
|
|
|
|
end
|
2020-04-01 13:42:52 +01:00
|
|
|
|
2025-02-16 22:20:37 -08:00
|
|
|
@disable_reason = T.let(because, T.nilable(T.any(String, Symbol)))
|
|
|
|
@disable_replacement = T.let(replacement, T.nilable(String))
|
|
|
|
@disabled = T.let(true, T.nilable(T::Boolean))
|
2020-04-01 13:42:52 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
# Whether this {Formula} is disabled (i.e. cannot be installed).
|
|
|
|
# Defaults to false.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .disable!
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2020-04-01 13:42:52 +01:00
|
|
|
def disabled?
|
|
|
|
@disabled == true
|
|
|
|
end
|
|
|
|
|
2020-12-23 02:58:14 -05:00
|
|
|
# The date that this {Formula} was or becomes disabled.
|
|
|
|
# Returns `nil` if no date is specified.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .disable!
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(Date)) }
|
2020-12-23 02:58:14 -05:00
|
|
|
attr_reader :disable_date
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# The reason this {Formula} is disabled.
|
2020-08-27 10:42:57 -04:00
|
|
|
# Returns `nil` if no reason was provided or the formula is not disabled.
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .disable!
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.any(NilClass, String, Symbol)) }
|
2020-08-27 10:42:57 -04:00
|
|
|
attr_reader :disable_reason
|
|
|
|
|
2024-11-07 15:50:03 -05:00
|
|
|
# The replacement for a disabled {Formula}.
|
|
|
|
# Returns `nil` if no reason was provided or the formula is not disabled.
|
|
|
|
#
|
|
|
|
# @see .disable!
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { returns(T.nilable(String)) }
|
2024-11-07 15:50:03 -05:00
|
|
|
attr_reader :disable_replacement
|
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# Permit overwriting certain files while linking.
|
|
|
|
#
|
2024-04-26 20:55:51 +02:00
|
|
|
# ### Examples
|
|
|
|
#
|
|
|
|
# Sometimes we accidentally install files outside the prefix. Once we fix that,
|
2021-01-09 13:34:17 +11:00
|
|
|
# users will get a link conflict error. Overwrite those files with:
|
2024-04-26 20:55:51 +02:00
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# link_overwrite "bin/foo", "lib/bar"
|
|
|
|
# ```
|
|
|
|
#
|
|
|
|
# ```ruby
|
|
|
|
# link_overwrite "share/man/man1/baz-*"
|
|
|
|
# ```
|
2025-02-16 22:20:37 -08:00
|
|
|
sig { params(paths: String).returns(T::Set[String]) }
|
2015-08-23 16:35:51 +08:00
|
|
|
def link_overwrite(*paths)
|
|
|
|
paths.flatten!
|
2025-02-16 22:20:37 -08:00
|
|
|
T.must(link_overwrite_paths).merge(paths)
|
2015-08-23 16:35:51 +08:00
|
|
|
end
|
2009-09-28 14:06:53 -07:00
|
|
|
end
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
2020-04-07 21:23:12 +02:00
|
|
|
|
|
|
|
require "extend/os/formula"
|