2020-11-24 15:46:47 +01:00
|
|
|
# typed: true
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
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"
|
2016-04-25 17:57:51 +01:00
|
|
|
require "utils/bottles"
|
2020-03-27 13:04:10 +00:00
|
|
|
require "utils/shebang"
|
2016-09-05 14:45:35 +10:00
|
|
|
require "utils/shell"
|
2015-08-03 13:09:07 +01:00
|
|
|
require "build_environment"
|
|
|
|
require "build_options"
|
|
|
|
require "formulary"
|
|
|
|
require "software_spec"
|
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
|
|
|
#
|
|
|
|
# <pre>class Wget < Formula
|
|
|
|
# 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
|
|
|
|
# end</pre>
|
2023-02-21 00:25:02 +00:00
|
|
|
class Formula
|
2012-03-06 19:23:51 -06:00
|
|
|
include FileUtils
|
2013-07-11 21:55:02 -05:00
|
|
|
include Utils::Inreplace
|
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
|
2020-08-02 06:05:53 +02:00
|
|
|
extend Predicable
|
2023-03-21 19:05:41 -07:00
|
|
|
extend APIHashable
|
2010-07-04 14:17:03 -07:00
|
|
|
|
2014-12-06 11:26:43 +00:00
|
|
|
# The name of this {Formula}.
|
|
|
|
# e.g. `this-formula`
|
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`
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T.any(NilClass, Pathname, String)) }
|
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}.
|
|
|
|
# For core formula it's the same as {#name}.
|
|
|
|
# e.g. `homebrew/tap-name/this-formula`
|
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}.
|
|
|
|
# For core formula it's the same as {#alias_name}.
|
|
|
|
# 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}.
|
2016-04-05 13:19:16 +08:00
|
|
|
# e.g. `/usr/local/Library/Taps/homebrew/homebrew-core/Formula/this-formula.rb`
|
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.
|
2015-12-06 22:16:08 +08:00
|
|
|
# @private
|
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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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.
|
|
|
|
# @see #stable
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
|
|
|
# @private
|
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`.
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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.
|
|
|
|
# @private
|
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.
|
|
|
|
# @private
|
2023-07-24 14:01:53 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2020-11-06 11:25:31 +00:00
|
|
|
attr_accessor :force_bottle
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# @private
|
2023-07-24 14:12:47 -07:00
|
|
|
sig {
|
|
|
|
params(name: String, path: Pathname, spec: Symbol, alias_path: T.any(NilClass, Pathname, String),
|
|
|
|
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
|
|
|
|
|
2012-03-09 10:18:12 -08:00
|
|
|
@name = name
|
2023-04-18 00:22:13 +01:00
|
|
|
@unresolved_path = path
|
|
|
|
@path = path.resolved_path
|
2016-09-05 01:11:36 +01:00
|
|
|
@alias_path = alias_path
|
2019-02-19 13:11:32 +00:00
|
|
|
@alias_name = (File.basename(alias_path) if alias_path)
|
2014-03-05 20:12:51 -06:00
|
|
|
@revision = self.class.revision || 0
|
2016-08-11 09:54:47 +02:00
|
|
|
@version_scheme = self.class.version_scheme || 0
|
2013-04-13 17:40:12 -05:00
|
|
|
|
2020-07-26 07:24:14 +02:00
|
|
|
@force_bottle = force_bottle
|
|
|
|
|
2023-04-18 00:22:13 +01:00
|
|
|
@tap = tap
|
|
|
|
@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
|
|
|
|
|
2016-09-24 17:59:14 +02:00
|
|
|
@full_name = full_name_with_optional_tap(name)
|
|
|
|
@full_alias_name = full_name_with_optional_tap(@alias_name)
|
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
|
|
|
|
2014-06-19 21:35:47 -05:00
|
|
|
@active_spec = determine_active_spec(spec)
|
2015-07-28 15:10:40 +08:00
|
|
|
@active_spec_sym = if head?
|
|
|
|
:head
|
|
|
|
else
|
|
|
|
:stable
|
|
|
|
end
|
2014-12-26 16:08:12 -05:00
|
|
|
validate_attributes!
|
2014-08-11 17:48:30 -05:00
|
|
|
@build = active_spec.build
|
2013-03-11 16:41:08 +01:00
|
|
|
@pin = FormulaPin.new(self)
|
2016-09-15 16:01:18 +01:00
|
|
|
@follow_installed_alias = true
|
2017-01-06 08:50:35 +00:00
|
|
|
@prefix_returns_versioned_prefix = false
|
2023-04-27 04:09:28 +01:00
|
|
|
@oldname_locks = []
|
2012-04-05 21:09:24 -05:00
|
|
|
end
|
|
|
|
|
2015-07-30 16:25:21 +08:00
|
|
|
# @private
|
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
|
|
|
|
|
|
|
|
# @private
|
|
|
|
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
|
|
|
|
|
2016-09-15 16:01:18 +01:00
|
|
|
# Allow full name logic to be re-used between names, aliases,
|
|
|
|
# and installed aliases.
|
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
|
|
|
|
|
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)
|
2016-09-23 22:02:23 +02: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
|
|
|
|
|
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
|
2015-08-03 13:09:07 +01:00
|
|
|
spec || raise(FormulaSpecificationError, "formulae require at least a URL")
|
2013-04-13 17:40:12 -05:00
|
|
|
end
|
|
|
|
|
2014-12-26 16:08:12 -05:00
|
|
|
def validate_attributes!
|
2021-01-07 13:49:05 -08:00
|
|
|
raise FormulaValidationError.new(full_name, :name, name) if name.blank? || name.match?(/\s/)
|
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
|
2021-01-07 13:49:05 -08:00
|
|
|
return if val.present? && !val.match?(/\s/)
|
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.
|
|
|
|
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)
|
2020-11-16 22:18:56 +01:00
|
|
|
return unless path&.match?(%r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases}o)
|
2017-03-30 19:39:26 +01:00
|
|
|
return unless File.symlink?(path)
|
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
|
|
|
|
File.basename(installed_alias_path) if installed_alias_path
|
|
|
|
end
|
|
|
|
|
|
|
|
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.
|
2016-09-05 22:13:55 +01:00
|
|
|
def specified_path
|
2021-09-22 02:08:18 +01:00
|
|
|
default_specified_path = Pathname(alias_path) if alias_path.present?
|
2023-04-18 00:22:13 +01:00
|
|
|
default_specified_path ||= @unresolved_path
|
2021-09-12 02:09:11 -04:00
|
|
|
|
2021-09-21 00:42:40 -04:00
|
|
|
return default_specified_path if default_specified_path.presence&.exist?
|
|
|
|
return local_bottle_path if local_bottle_path.presence&.exist?
|
2021-09-12 02:09:11 -04:00
|
|
|
|
|
|
|
default_specified_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.
|
|
|
|
def specified_name
|
|
|
|
alias_name || name
|
|
|
|
end
|
|
|
|
|
|
|
|
# The name (including tap) specified to find this formula.
|
|
|
|
def full_specified_name
|
|
|
|
full_alias_name || full_name
|
|
|
|
end
|
|
|
|
|
|
|
|
# The name specified to install this formula.
|
|
|
|
def installed_specified_name
|
|
|
|
installed_alias_name || name
|
|
|
|
end
|
|
|
|
|
|
|
|
# The name (including tap) specified to install this formula.
|
|
|
|
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?
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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?
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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?
|
|
|
|
# @private
|
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
|
|
|
|
|
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}.
|
|
|
|
# @private
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(T.nilable(Bottle)) }
|
2014-03-10 14:56:02 -05:00
|
|
|
def bottle
|
2021-04-15 18:06:54 +01:00
|
|
|
@bottle ||= Bottle.new(self, bottle_specification) 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.
|
|
|
|
# @private
|
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"
|
|
|
|
|
|
|
|
# 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
|
|
|
|
2023-05-15 13:58:33 +02:00
|
|
|
# Whether this formula was loaded using the formulae.brew.sh API
|
|
|
|
# @!method loaded_from_api?
|
|
|
|
# @private
|
|
|
|
# @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
|
|
|
|
|
2022-08-23 12:42:02 +01:00
|
|
|
# Returns any `@`-versioned formulae names for any formula (including versioned formulae).
|
|
|
|
sig { returns(T::Array[String]) }
|
|
|
|
def versioned_formulae_names
|
2023-07-05 16:28:44 +01:00
|
|
|
versioned_names = if tap
|
2022-08-25 15:05:49 +01:00
|
|
|
name_prefix = "#{name.gsub(/(@[\d.]+)?$/, "")}@"
|
2023-07-24 14:01:53 -07:00
|
|
|
T.must(tap).formula_names.select do |name|
|
2023-07-05 16:28:44 +01:00
|
|
|
name.start_with?(name_prefix)
|
2022-08-25 15:05:49 +01:00
|
|
|
end
|
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-07-24 14:01:53 -07:00
|
|
|
else
|
|
|
|
raise "Either tap or path is required to list versioned formulae"
|
2023-07-05 16:28:44 +01:00
|
|
|
end.sort
|
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
|
2022-08-25 11:04:37 +01:00
|
|
|
versioned_formulae_names.map do |name|
|
2022-08-23 12:42:02 +01:00
|
|
|
Formula[name]
|
2019-10-13 10:03:26 +01:00
|
|
|
rescue FormulaUnavailableError
|
|
|
|
nil
|
2020-02-26 15:59:50 +00:00
|
|
|
end.compact.sort_by(&:version).reverse
|
2018-05-12 14:35:50 -04:00
|
|
|
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.
|
|
|
|
# <pre>resource("additional_files").stage { bin.install "my/extra/tool" }</pre>
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!method resource
|
2017-06-26 07:30:28 +02:00
|
|
|
delegate resource: :active_spec
|
2013-08-06 19:52:58 -07:00
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# An old name for the formula.
|
2023-04-27 04:09:28 +01:00
|
|
|
# @deprecated Use #{#oldnames} instead.
|
2023-07-24 06:55:41 -07:00
|
|
|
sig { returns(T.nilable(String)) }
|
2015-08-09 14:46:07 +03:00
|
|
|
def oldname
|
2023-07-06 16:47:09 +01:00
|
|
|
odeprecated "Formula#oldname", "Formula#oldnames"
|
2023-04-27 04:09:28 +01:00
|
|
|
@oldname ||= oldnames.first
|
|
|
|
end
|
|
|
|
|
|
|
|
# Old names for the formula.
|
2023-07-24 06:55:41 -07:00
|
|
|
sig { returns(T::Array[String]) }
|
2023-04-27 04:09:28 +01:00
|
|
|
def oldnames
|
|
|
|
@oldnames ||= if tap
|
2023-07-24 14:01:53 -07:00
|
|
|
T.must(tap).formula_renames
|
|
|
|
.flat_map { |old_name, new_name| (new_name == name) ? old_name : [] }
|
2023-04-27 04:09:28 +01:00
|
|
|
else
|
|
|
|
[]
|
2015-08-09 14:46:07 +03:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-11-05 17:17:03 -05:00
|
|
|
# All aliases for the formula.
|
2023-07-24 06:55:41 -07:00
|
|
|
sig { returns(T::Array[String]) }
|
2015-10-07 18:51:02 +08:00
|
|
|
def aliases
|
2015-12-06 22:16:08 +08:00
|
|
|
@aliases ||= if tap
|
2023-07-24 14:01:53 -07:00
|
|
|
T.must(tap).alias_reverse_table[full_name].to_a.map do |a|
|
2018-09-17 19:44:12 +02:00
|
|
|
a.split("/").last
|
2017-07-21 17:20:12 +01:00
|
|
|
end
|
2015-10-07 18:51:02 +08:00
|
|
|
else
|
|
|
|
[]
|
|
|
|
end
|
|
|
|
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}.
|
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
|
|
|
|
|
2019-09-17 18:10:02 -04:00
|
|
|
# Dependencies provided by macOS for the currently active {SoftwareSpec}.
|
|
|
|
delegate uses_from_macos_elements: :active_spec
|
|
|
|
|
2021-09-14 09:48:17 +01:00
|
|
|
# Dependency names provided by macOS for the currently active {SoftwareSpec}.
|
|
|
|
delegate uses_from_macos_names: :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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2015-07-30 16:01:36 +08:00
|
|
|
def any_version_installed?
|
2015-11-29 15:22:22 +08:00
|
|
|
installed_prefixes.any? { |keg| (keg/Tab::FILENAME).file? }
|
2015-07-30 16:01:36 +08:00
|
|
|
end
|
|
|
|
|
2015-07-21 21:57:14 +08:00
|
|
|
# @private
|
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.
|
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
|
|
|
|
|
2016-07-22 12:58:24 +03:00
|
|
|
def latest_head_version
|
2016-07-13 10:11:59 +03:00
|
|
|
head_versions = installed_prefixes.map do |pn|
|
|
|
|
pn_pkgversion = PkgVersion.parse(pn.basename.to_s)
|
|
|
|
pn_pkgversion if pn_pkgversion.head?
|
|
|
|
end.compact
|
|
|
|
|
2016-07-22 12:58:24 +03:00
|
|
|
head_versions.max_by do |pn_pkgversion|
|
2016-07-13 10:11:59 +03:00
|
|
|
[Tab.for_keg(prefix(pn_pkgversion)).source_modified_time, pn_pkgversion.revision]
|
|
|
|
end
|
2016-07-22 12:58:24 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
def latest_head_prefix
|
|
|
|
head_version = latest_head_version
|
|
|
|
prefix(head_version) if head_version
|
|
|
|
end
|
|
|
|
|
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}
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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)
|
|
|
|
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.
|
2016-12-31 16:38:05 +00:00
|
|
|
# This directory points to {#opt_prefix} if it exists and if #{prefix} is not
|
|
|
|
# called from within the same formula's {#install} or {#post_install} methods.
|
|
|
|
# Otherwise, return the full path to the formula's versioned cellar.
|
2023-03-07 23:42:00 +00:00
|
|
|
def prefix(version = pkg_version)
|
|
|
|
versioned_prefix = versioned_prefix(version)
|
|
|
|
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?
|
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.
|
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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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.
|
2015-11-29 15:13:56 +08:00
|
|
|
# @private
|
|
|
|
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.
|
2015-11-29 15:13:56 +08:00
|
|
|
# @private
|
|
|
|
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
|
|
|
#
|
2018-10-18 21:42:43 -04:00
|
|
|
# Need to install into the {.bin} but the makefile doesn't `mkdir -p prefix/bin`?
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>bin.mkpath</pre>
|
|
|
|
#
|
|
|
|
# No `make install` available?
|
|
|
|
# <pre>bin.install "binary1"</pre>
|
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.
|
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
|
|
|
#
|
|
|
|
# No `make install` available?
|
|
|
|
# <pre>include.install "example.h"</pre>
|
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.
|
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
|
|
|
#
|
|
|
|
# No `make install` available?
|
|
|
|
# <pre>lib.install "example.dylib"</pre>
|
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}.
|
2021-01-09 13:34:17 +11:00
|
|
|
# <pre>libexec.install "foo.jar"
|
|
|
|
# bin.write_jar_script libexec/"foo.jar", "foo"
|
|
|
|
# </pre>
|
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}.
|
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
|
|
|
#
|
|
|
|
# No `make install` available?
|
|
|
|
# <pre>man1.install "example.1"</pre>
|
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.
|
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
|
|
|
#
|
|
|
|
# No `make install` available?
|
|
|
|
# <pre>man3.install "man.3"</pre>
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
|
|
#
|
|
|
|
# Need a custom directory?
|
|
|
|
# <pre>(share/"concept").mkpath</pre>
|
|
|
|
#
|
|
|
|
# Installing something into another custom directory?
|
|
|
|
# <pre>(share/"concept2").install "ducks.txt"</pre>
|
|
|
|
#
|
2020-11-05 17:17:03 -05:00
|
|
|
# Install `./example_code/simple/ones` to `share/demos`:
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>(share/"demos").install "example_code/simple/ones"</pre>
|
|
|
|
#
|
2020-11-05 17:17:03 -05:00
|
|
|
# Install `./example_code/simple/ones` to `share/demos/examples`:
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>(share/"demos").install "example_code/simple/ones" => "examples"</pre>
|
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
|
|
|
#
|
|
|
|
# No `make install` available?
|
|
|
|
# <pre>pkgshare.install "examples"</pre>
|
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.
|
|
|
|
#
|
2020-11-05 17:17:03 -05:00
|
|
|
# To install an Emacs mode included with a software package:
|
2015-10-31 21:45:40 -07:00
|
|
|
# <pre>elisp.install "contrib/emacs/example-mode.el"</pre>
|
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`.
|
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`.
|
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.
|
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.
|
|
|
|
# e.g. `$HOMEBREW_PREFIX/etc/openssl@1.1`
|
|
|
|
# Anything using `pkgetc.install` will not overwrite other files on
|
|
|
|
# e.g. upgrades but will write a new file named `*.default`.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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.
|
2016-05-27 01:53:08 -04:00
|
|
|
def with_logging(log_type)
|
|
|
|
old_log_type = @active_log_type
|
|
|
|
@active_log_type = log_type
|
|
|
|
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.
|
2018-10-18 21:42:43 -04:00
|
|
|
# @see https://www.unix.com/man-page/all/5/plist/ Apple's plist(5) man page
|
2017-10-15 02:28:32 +02:00
|
|
|
# <pre>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
|
2016-09-17 15:17:27 +01:00
|
|
|
# end</pre>
|
2022-11-06 13:52:53 +01:00
|
|
|
#
|
2021-10-23 21:32:38 -04:00
|
|
|
# @deprecated Please use {Homebrew::Service} instead.
|
2015-08-03 13:09:07 +01:00
|
|
|
def plist
|
|
|
|
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
|
|
|
|
|
2015-12-06 22:18:16 +00:00
|
|
|
# The generated launchd {.plist} file path.
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { returns(Pathname) }
|
2015-08-03 13:09:07 +01:00
|
|
|
def plist_path
|
2023-07-06 16:47:09 +01:00
|
|
|
odisabled "formula.plist_path", "formula.launchd_service_path"
|
2022-11-06 13:52:53 +01:00
|
|
|
launchd_service_path
|
|
|
|
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.
|
|
|
|
def service
|
2023-03-17 23:24:37 -07:00
|
|
|
@service ||= Homebrew::Service.new(self, &self.class.service)
|
2021-04-08 10:06:45 +02:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate plist_manual: :"self.class"
|
2015-08-03 13:09:07 +01:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate plist_startup: :"self.class"
|
2011-12-30 23:56:52 -06:00
|
|
|
|
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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>args << "--with-readline=#{Formula["readline"].opt_prefix}" if build.with? "readline"</pre>
|
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
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
2016-01-09 11:06:17 +00:00
|
|
|
# @private
|
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
|
|
|
# @private
|
|
|
|
sig { returns(T::Boolean) }
|
|
|
|
def post_install_defined?
|
|
|
|
method(:post_install).owner != Formula
|
|
|
|
end
|
|
|
|
|
|
|
|
# @private
|
|
|
|
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
|
|
|
|
|
2016-05-27 01:53:08 -04:00
|
|
|
# @private
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { void }
|
2016-05-27 01:53:08 -04:00
|
|
|
def run_post_install
|
2017-01-06 08:50:35 +00:00
|
|
|
@prefix_returns_versioned_prefix = true
|
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
|
|
|
|
@prefix_returns_versioned_prefix = false
|
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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# @return [String]
|
|
|
|
# <pre>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
|
|
|
|
# end</pre>
|
|
|
|
#
|
|
|
|
# <pre>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
|
|
|
|
# end</pre>
|
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
|
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
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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)
|
|
|
|
return true if path.extname == ".la" && 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
|
2009-11-23 10:07:23 -08:00
|
|
|
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
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2015-08-23 16:35:51 +08:00
|
|
|
def link_overwrite?(path)
|
|
|
|
# Don't overwrite files not created by Homebrew.
|
2023-04-18 15:06:50 -07:00
|
|
|
return false if path.stat.uid != HOMEBREW_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
|
2015-12-06 22:16:08 +08:00
|
|
|
tab_tap = Tab.for_keg(keg).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
|
2015-09-28 22:47:53 +01:00
|
|
|
rescue TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError
|
|
|
|
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
|
|
|
|
self.class.link_overwrite_paths.any? do |p|
|
|
|
|
p == to_check ||
|
2020-08-19 17:12:32 +01:00
|
|
|
to_check.start_with?("#{p.chomp("/")}/") ||
|
2016-09-20 22:03:08 +02:00
|
|
|
to_check =~ /^#{Regexp.escape(p).gsub('\*', ".*?")}$/
|
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"
|
|
|
|
|
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"
|
|
|
|
|
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
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
|
|
|
|
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.
|
2014-12-26 20:24:12 +00:00
|
|
|
# @private
|
2022-07-26 12:15:53 +01:00
|
|
|
def brew(fetch: true, keep_tmp: false, debug_symbols: false, interactive: false)
|
2017-01-06 08:50:35 +00:00
|
|
|
@prefix_returns_versioned_prefix = true
|
2020-05-12 12:37:54 +01:00
|
|
|
active_spec.fetch if fetch
|
2022-07-31 19:59:25 +01:00
|
|
|
stage(interactive: interactive, debug_symbols: 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
|
|
|
|
CMakeOutput.log
|
|
|
|
CMakeError.log
|
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
|
2017-01-06 08:50:35 +00:00
|
|
|
@prefix_returns_versioned_prefix = false
|
2009-07-24 15:10:01 +01:00
|
|
|
end
|
2009-08-10 16:48:30 +01:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2013-01-23 00:26:25 -06:00
|
|
|
def lock
|
2013-02-09 18:19:50 -06:00
|
|
|
@lock = FormulaLock.new(name)
|
|
|
|
@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
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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-04-27 04:09:28 +01:00
|
|
|
# @private
|
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
|
|
|
|
|
2015-11-27 15:11:00 +00:00
|
|
|
# @private
|
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?
|
|
|
|
|
|
|
|
tab = Tab.for_keg(keg)
|
2022-06-15 16:32:14 -04:00
|
|
|
next if version_scheme > tab.version_scheme && pkg_version != version
|
|
|
|
next if version_scheme == tab.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 ||
|
2020-11-13 17:21:51 +01:00
|
|
|
((head_version = latest_head_version) && !head_version_outdated?(head_version, fetch_head: fetch_head))
|
2019-11-06 11:49:31 +00:00
|
|
|
[]
|
|
|
|
else
|
|
|
|
all_kegs += old_installed_formulae.flat_map(&:installed_kegs)
|
|
|
|
all_kegs.sort_by(&:version)
|
|
|
|
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
|
|
|
|
|
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.
|
|
|
|
def latest_formula
|
|
|
|
installed_alias_target_changed? ? current_installed_alias_target : self
|
|
|
|
end
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2015-11-27 15:11:00 +00:00
|
|
|
# @private
|
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)
|
|
|
|
!outdated_kegs(fetch_head: fetch_head).empty?
|
2015-11-27 15:11:00 +00:00
|
|
|
rescue Migrator::MigrationNeededError
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate pinnable?: :@pin
|
2013-05-21 22:41:21 -05:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate pinned?: :@pin
|
2013-05-21 22:41:21 -05:00
|
|
|
|
2015-11-16 19:23:48 +08:00
|
|
|
# @private
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate pinned_version: :@pin
|
2015-11-16 19:23:48 +08:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate pin: :@pin
|
2013-05-21 22:41:21 -05:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate unpin: :@pin
|
2013-05-21 22:41:21 -05:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2010-09-11 20:22:54 +01:00
|
|
|
def hash
|
|
|
|
name.hash
|
|
|
|
end
|
2014-07-03 14:54:14 -05:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2014-07-03 14:54:14 -05:00
|
|
|
def <=>(other)
|
2016-09-20 22:03:08 +02:00
|
|
|
return unless other.is_a?(Formula)
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2014-07-03 14:54:14 -05:00
|
|
|
name <=> other.name
|
2010-09-11 20:22:54 +01:00
|
|
|
end
|
2014-07-03 14:54:14 -05:00
|
|
|
|
2020-07-09 15:03:49 +01:00
|
|
|
# @private
|
|
|
|
def possible_names
|
2023-04-27 04:09:28 +01:00
|
|
|
[name, *oldnames, *aliases].compact
|
2020-07-09 15:03:49 +01:00
|
|
|
end
|
|
|
|
|
2010-09-11 20:22:54 +01:00
|
|
|
def to_s
|
|
|
|
name
|
|
|
|
end
|
2014-07-01 15:13:29 -05:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
|
|
|
2020-12-17 23:49:19 +01:00
|
|
|
# Standard parameters for configure builds.
|
2021-01-09 13:34:17 +11:00
|
|
|
sig { returns(T::Array[String]) }
|
2020-12-17 23:49:19 +01:00
|
|
|
def std_configure_args
|
|
|
|
["--disable-debug", "--disable-dependency-tracking", "--prefix=#{prefix}", "--libdir=#{lib}"]
|
|
|
|
end
|
|
|
|
|
2020-06-22 13:24:41 +02:00
|
|
|
# Standard parameters for cargo builds.
|
2021-08-10 11:55:00 +08:00
|
|
|
sig { params(root: T.any(String, Pathname), path: String).returns(T::Array[T.any(String, Pathname)]) }
|
2021-07-19 21:26:52 -04:00
|
|
|
def std_cargo_args(root: prefix, path: ".")
|
|
|
|
["--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.
|
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")
|
2016-09-22 01:37:28 -07:00
|
|
|
args = %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
|
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
|
|
|
]
|
2016-09-22 01:37:28 -07:00
|
|
|
|
|
|
|
# Avoid false positives for clock_gettime support on 10.11.
|
|
|
|
# CMake cache entries for other weak symbols may be added here as needed.
|
2019-02-19 13:11:32 +00:00
|
|
|
args << "-DHAVE_CLOCK_GETTIME:INTERNAL=0" if MacOS.version == "10.11" && MacOS::Xcode.version >= "8.0"
|
2016-09-22 01:37:28 -07:00
|
|
|
|
2020-03-09 22:40:02 +00:00
|
|
|
# Ensure CMake is using the same SDK we are using.
|
2020-04-07 16:45:03 +01:00
|
|
|
args << "-DCMAKE_OSX_SYSROOT=#{MacOS.sdk_for_formula(self).path}" if MacOS.sdk_root_needed?
|
2020-03-09 22:40:02 +00:00
|
|
|
|
2016-09-22 01:37:28 -07:00
|
|
|
args
|
2009-08-21 20:20:44 +01:00
|
|
|
end
|
|
|
|
|
2020-01-15 12:33:55 +01:00
|
|
|
# Standard parameters for Go builds.
|
2021-11-15 14:33:46 -05:00
|
|
|
sig {
|
|
|
|
params(output: T.any(String, Pathname),
|
|
|
|
ldflags: T.nilable(T.any(String, T::Array[String]))).returns(T::Array[String])
|
|
|
|
}
|
2021-10-28 15:25:44 -04:00
|
|
|
def std_go_args(output: bin/name, ldflags: nil)
|
|
|
|
args = ["-trimpath", "-o=#{output}"]
|
2021-11-15 14:33:46 -05:00
|
|
|
args += ["-ldflags=#{Array(ldflags).join(" ")}"] if ldflags
|
2021-03-23 16:39:01 +00:00
|
|
|
args
|
2020-01-15 12:33:55 +01:00
|
|
|
end
|
|
|
|
|
2020-01-29 15:41:13 +01:00
|
|
|
# Standard parameters for cabal-v2 builds.
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(T::Array[String]) }
|
2020-01-29 15:41:13 +01:00
|
|
|
def std_cabal_v2_args
|
2020-11-24 15:46:47 +01:00
|
|
|
env = T.cast(ENV, T.any(Stdenv, Superenv))
|
|
|
|
|
2020-01-29 15:41:13 +01:00
|
|
|
# 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.
|
2020-11-24 15:46:47 +01:00
|
|
|
["--jobs=#{env.make_jobs}", "--max-backjumps=100000", "--install-method=copy", "--installdir=#{bin}"]
|
2020-01-29 15:41:13 +01:00
|
|
|
end
|
|
|
|
|
2020-04-15 12:19:02 +02:00
|
|
|
# Standard parameters for meson builds.
|
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
|
|
|
|
|
2023-07-17 20:48:40 -07:00
|
|
|
# Standard parameters for pip builds.
|
|
|
|
sig {
|
|
|
|
params(prefix: T.any(String, Pathname, FalseClass),
|
|
|
|
build_isolation: T::Boolean).returns(T::Array[String])
|
|
|
|
}
|
|
|
|
def std_pip_args(prefix: self.prefix, build_isolation: false)
|
|
|
|
args = ["--verbose", "--no-deps", "--no-binary=:all:", "--ignore-installed",
|
|
|
|
"--use-feature=no-binary-enable-wheel-cache"]
|
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
|
|
|
|
|
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.
|
|
|
|
#
|
|
|
|
# <pre>
|
|
|
|
# shared_library("foo") #=> foo.dylib
|
|
|
|
# shared_library("foo", 1) #=> foo.1.dylib
|
|
|
|
# shared_library("foo", "*") #=> foo.2.dylib, foo.1.dylib, foo.dylib
|
|
|
|
# shared_library("*") #=> foo.dylib, bar.dylib
|
|
|
|
# </pre>
|
|
|
|
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.
|
|
|
|
#
|
|
|
|
# <pre>
|
|
|
|
# rpath #=> "@loader_path/../lib"
|
|
|
|
# rpath(target: frameworks) #=> "@loader_path/../Frameworks"
|
|
|
|
# rpath(source: libexec/"bin") #=> "@loader_path/../../lib"
|
|
|
|
# </pre>
|
|
|
|
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
|
|
|
|
|
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}.
|
2021-07-22 00:43:46 +08:00
|
|
|
sig { params(targets: T.nilable(T.any(Pathname, String))).void }
|
|
|
|
def deuniversalize_machos(*targets)
|
2021-08-17 22:47:08 +08:00
|
|
|
targets = nil if targets.blank?
|
2021-08-17 22:32:52 +08:00
|
|
|
targets ||= any_installed_keg.mach_o_files.select do |file|
|
|
|
|
file.arch == :universal && file.archs.include?(Hardware::CPU.arch)
|
2021-07-22 00:43:46 +08:00
|
|
|
end
|
|
|
|
|
2021-07-25 11:29:33 +08:00
|
|
|
targets.each { |t| extract_macho_slice_from(Pathname.new(t), Hardware::CPU.arch) }
|
2021-07-24 19:39:47 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# @private
|
|
|
|
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
|
|
|
|
2022-07-31 21:01:42 +02:00
|
|
|
# Generate shell completions for a formula for bash, zsh, and fish, using the formula's executable.
|
2022-07-11 15:35:48 +02:00
|
|
|
#
|
2022-08-11 18:12:08 +02:00
|
|
|
# @param commands [Pathname, String] the path to the executable and any passed subcommand(s)
|
|
|
|
# to use for generating the completion scripts.
|
2022-07-11 15:35:48 +02:00
|
|
|
# @param base_name [String] the base name of the generated completion script. Defaults to the formula name.
|
|
|
|
# @param shells [Array<Symbol>] the shells to generate completion scripts for. Defaults to `[:bash, :zsh, :fish]`.
|
2022-08-10 15:14:06 +02:00
|
|
|
# @param shell_parameter_format [String, Symbol] specify how `shells` should each be passed
|
2022-11-15 12:32:05 -08:00
|
|
|
# to the `executable`. Takes either a String representing a prefix, or one of [:flag, :arg, :none, :click].
|
2022-07-31 21:01:42 +02:00
|
|
|
# Defaults to plainly passing the shell.
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
|
|
|
# @example Using default values for optional arguments
|
|
|
|
# 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")
|
|
|
|
#
|
|
|
|
# @example Selecting shells and using a different base_name
|
|
|
|
# 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")
|
|
|
|
#
|
|
|
|
# @example Using predefined shell_parameter_format :flag
|
|
|
|
# generate_completions_from_executable(bin/"foo", "completions", shell_parameter_format: :flag, shells: [:bash])
|
|
|
|
# translates to
|
|
|
|
#
|
|
|
|
# (bash_completion/"foo").write Utils.safe_popen_read({ "SHELL" => "bash" }, bin/"foo", "completions", "--bash")
|
|
|
|
#
|
|
|
|
# @example Using predefined shell_parameter_format :arg
|
|
|
|
# generate_completions_from_executable(bin/"foo", "completions", shell_parameter_format: :arg, shells: [:bash])
|
|
|
|
# translates to
|
|
|
|
#
|
2022-08-10 18:00:44 +02:00
|
|
|
# (bash_completion/"foo").write Utils.safe_popen_read({ "SHELL" => "bash" }, bin/"foo",
|
|
|
|
# "completions", "--shell=bash")
|
2022-08-10 15:40:54 +02:00
|
|
|
#
|
|
|
|
# @example Using predefined shell_parameter_format :none
|
|
|
|
# generate_completions_from_executable(bin/"foo", "completions", shell_parameter_format: :none, shells: [:bash])
|
|
|
|
# translates to
|
|
|
|
#
|
|
|
|
# (bash_completion/"foo").write Utils.safe_popen_read({ "SHELL" => "bash" }, bin/"foo", "completions")
|
|
|
|
#
|
2022-11-15 12:32:05 -08:00
|
|
|
# @example Using predefined shell_parameter_format :click
|
|
|
|
# generate_completions_from_executable(bin/"foo", shell_parameter_format: :click, shells: [:zsh])
|
|
|
|
# translates to
|
|
|
|
#
|
|
|
|
# (zsh_completion/"_foo").write Utils.safe_popen_read({ "SHELL" => "zsh", "_FOO_COMPLETE" => "zsh_source" },
|
|
|
|
# bin/"foo")
|
|
|
|
#
|
2022-08-10 15:40:54 +02:00
|
|
|
# @example Using custom shell_parameter_format
|
2022-08-10 18:00:44 +02:00
|
|
|
# generate_completions_from_executable(bin/"foo", "completions", shell_parameter_format: "--selected-shell=",
|
|
|
|
# shells: [:bash])
|
2022-08-10 15:40:54 +02:00
|
|
|
# translates to
|
|
|
|
#
|
2022-08-10 18:00:44 +02:00
|
|
|
# (bash_completion/"foo").write Utils.safe_popen_read({ "SHELL" => "bash" }, bin/"foo",
|
|
|
|
# "completions", "--selected-shell=bash")
|
2022-07-11 15:21:57 +02:00
|
|
|
sig {
|
2022-08-11 18:12:08 +02:00
|
|
|
params(commands: T.any(Pathname, String), base_name: String, shells: T::Array[Symbol],
|
2022-07-31 21:01:42 +02:00
|
|
|
shell_parameter_format: T.nilable(T.any(Symbol, String))).void
|
2022-07-11 15:21:57 +02:00
|
|
|
}
|
2022-08-11 18:12:08 +02:00
|
|
|
def generate_completions_from_executable(*commands,
|
2022-08-10 15:11:06 +02:00
|
|
|
base_name: name,
|
2022-07-24 22:54:28 +02:00
|
|
|
shells: [:bash, :zsh, :fish],
|
2022-07-24 23:03:28 +02:00
|
|
|
shell_parameter_format: nil)
|
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
|
|
|
|
prog_name = File.basename(commands.first.to_s).upcase.tr("-", "_")
|
|
|
|
popen_read_env["_#{prog_name}_COMPLETE"] = "#{shell}_source"
|
|
|
|
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
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2015-05-08 19:54:29 +08:00
|
|
|
def self.tap_names
|
2016-03-06 14:50:33 +08:00
|
|
|
@tap_names ||= Tap.reject(&:core_tap?).flat_map(&:formula_names).sort
|
2015-05-08 19:54:29 +08:00
|
|
|
end
|
|
|
|
|
2015-08-01 00:02:19 +08:00
|
|
|
# an array of all tap {Formula} files
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2015-08-01 00:02:19 +08:00
|
|
|
def self.tap_files
|
2016-03-06 14:50:33 +08:00
|
|
|
@tap_files ||= Tap.reject(&:core_tap?).flat_map(&:formula_files)
|
2015-08-01 00:02:19 +08:00
|
|
|
end
|
|
|
|
|
2014-12-26 20:24:12 +00:00
|
|
|
# an array of all {Formula} names
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2010-03-09 02:18:08 +00:00
|
|
|
def self.names
|
2018-09-17 19:44:12 +02:00
|
|
|
@names ||= (core_names + tap_names.map { |name| name.split("/").last }).uniq.sort
|
2015-05-08 19:54:29 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# an array of all {Formula} names, which the tap formulae have the fully-qualified name
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2015-05-08 19:54:29 +08:00
|
|
|
def self.full_names
|
2015-06-20 14:46:24 +08:00
|
|
|
@full_names ||= core_names + tap_names
|
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
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2022-01-03 14:59:10 +00:00
|
|
|
def self.all
|
2023-02-07 19:25:51 +01:00
|
|
|
# TODO: ideally avoid using ARGV by moving to e.g. CLI::Parser
|
|
|
|
if ARGV.exclude?("--eval-all") && !Homebrew::EnvConfig.eval_all?
|
2023-07-06 16:47:09 +01:00
|
|
|
odisabled "Formula#all without --eval-all or HOMEBREW_EVAL_ALL"
|
2023-02-07 19:25:51 +01:00
|
|
|
end
|
2022-03-08 19:24:55 +00:00
|
|
|
|
2023-06-28 15:27:20 +01:00
|
|
|
(core_names + tap_files).map do |name_or_file|
|
|
|
|
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
|
|
|
|
end.compact
|
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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
|
|
|
|
2015-08-13 20:35:22 +08:00
|
|
|
# An array of all installed {Formula}
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
|
|
|
|
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}
|
|
|
|
# @private
|
|
|
|
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
|
|
|
|
# @private
|
|
|
|
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
|
|
|
|
# @private
|
|
|
|
def self.tap_aliases
|
2016-03-06 14:50:33 +08:00
|
|
|
@tap_aliases ||= Tap.reject(&:core_tap?).flat_map(&:aliases).sort
|
2015-09-12 19:14:38 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# an array of all aliases
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2010-03-09 02:18:08 +00:00
|
|
|
def self.aliases
|
2018-09-17 19:44:12 +02:00
|
|
|
@aliases ||= (core_aliases + tap_aliases.map { |name| name.split("/").last }).uniq.sort
|
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
|
2015-09-13 17:23:17 +08:00
|
|
|
# @private
|
|
|
|
def self.alias_full_names
|
|
|
|
@alias_full_names ||= core_aliases + tap_aliases
|
2009-11-16 15:35:58 -08:00
|
|
|
end
|
2009-08-21 20:20:44 +01:00
|
|
|
|
2015-10-07 17:54:20 +08:00
|
|
|
# a table mapping core alias to formula name
|
|
|
|
# @private
|
|
|
|
def self.core_alias_table
|
2016-03-07 18:04:25 +08:00
|
|
|
CoreTap.instance.alias_table
|
2015-10-07 17:54:20 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# a table mapping core formula name to aliases
|
|
|
|
# @private
|
|
|
|
def self.core_alias_reverse_table
|
2016-03-07 18:04:25 +08:00
|
|
|
CoreTap.instance.alias_reverse_table
|
2015-10-07 17:54:20 +08:00
|
|
|
end
|
|
|
|
|
2021-06-19 00:14:33 +01:00
|
|
|
# Returns a list of approximately matching formula names, but not the complete match
|
|
|
|
# @private
|
|
|
|
def self.fuzzy_search(name)
|
|
|
|
@spell_checker ||= DidYouMean::SpellChecker.new(dictionary: Set.new(names + full_names).to_a)
|
|
|
|
@spell_checker.correct(name)
|
|
|
|
end
|
|
|
|
|
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
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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.
|
|
|
|
# @private
|
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
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
|
|
|
|
2023-02-06 13:06:11 +00:00
|
|
|
# @private
|
|
|
|
def tap_git_head
|
|
|
|
tap&.git_head
|
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate env: :"self.class"
|
2012-09-14 07:54:14 -07:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-07-16 01:48:25 +01:00
|
|
|
delegate conflicts: :"self.class"
|
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
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
|
|
|
Dependency.expand(self, cache_key: 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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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
|
|
|
|
Requirement.expand(self, cache_key: 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`.
|
2018-04-25 11:44:29 +01:00
|
|
|
# @private
|
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
|
|
|
|
|
|
|
|
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`.
|
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.
|
|
|
|
# @private
|
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)
|
2019-11-05 20:34:06 +00:00
|
|
|
tab_deps.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
|
2018-06-01 19:22:33 +01:00
|
|
|
end.compact
|
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.
|
2018-04-25 11:44:29 +01:00
|
|
|
# @private
|
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(
|
2018-07-16 16:46:39 +01:00
|
|
|
read_from_tab: read_from_tab,
|
2018-11-02 17:18:07 +00:00
|
|
|
undeclared: undeclared,
|
2018-07-16 16:46:39 +01:00
|
|
|
).map do |d|
|
2019-10-13 10:03:26 +01:00
|
|
|
d.to_formula
|
|
|
|
rescue FormulaUnavailableError
|
|
|
|
nil
|
2018-07-16 16:46:39 +01:00
|
|
|
end.compact
|
2018-03-12 09:20:24 +00:00
|
|
|
end
|
|
|
|
|
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.
|
2016-10-05 20:56:07 +01:00
|
|
|
def missing_dependencies(hide: nil)
|
|
|
|
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
|
|
|
# @private
|
|
|
|
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
|
|
|
|
|
|
|
|
# @private
|
|
|
|
sig { returns(T.nilable(Checksum)) }
|
|
|
|
def ruby_source_checksum
|
|
|
|
Checksum.new(Digest::SHA256.file(path).hexdigest) if path.exist?
|
|
|
|
end
|
|
|
|
|
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|
|
|
|
|
{
|
|
|
|
dependable: dependable,
|
|
|
|
# Now find the list of specs each dependency was a part of.
|
|
|
|
specs: dependables.map { |spec, spec_deps| spec if spec_deps&.include?(dependable) }.compact,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
private :merge_spec_dependables
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2012-08-15 22:08:40 -05:00
|
|
|
def to_hash
|
2023-06-19 06:07:53 +01:00
|
|
|
# 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
|
|
|
|
dependencies.transform_values! { |deps| deps&.reject(&:implicit?) } # Remove all implicit deps from all lists
|
|
|
|
requirements = self.class.spec_syms.to_h do |sym|
|
|
|
|
[sym, send(sym)&.requirements]
|
|
|
|
end
|
2018-03-21 12:38:47 +00:00
|
|
|
|
2012-08-15 22:08:40 -05:00
|
|
|
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
|
|
|
"oldname" => oldnames.first, # deprecated
|
|
|
|
"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,
|
2018-05-12 10:42:07 -04:00
|
|
|
"bottle" => !bottle_specification.checksums.empty?,
|
2012-08-15 22:08:40 -05:00
|
|
|
},
|
2020-02-02 17:11:29 +01:00
|
|
|
"urls" => {},
|
2018-11-02 17:18:07 +00:00
|
|
|
"revision" => revision,
|
|
|
|
"version_scheme" => version_scheme,
|
|
|
|
"bottle" => {},
|
|
|
|
"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" => [],
|
2018-11-02 17:18:07 +00:00
|
|
|
"requirements" => [],
|
|
|
|
"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,
|
2023-07-18 10:59:27 +01:00
|
|
|
"caveats" => caveats&.gsub(HOMEBREW_PREFIX, HOMEBREW_PREFIX_PLACEHOLDER)
|
|
|
|
&.gsub(HOMEBREW_CELLAR, HOMEBREW_CELLAR_PLACEHOLDER),
|
2018-11-02 17:18:07 +00:00
|
|
|
"installed" => [],
|
|
|
|
"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,
|
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,
|
2023-06-22 03:06:45 +01:00
|
|
|
"post_install_defined" => post_install_defined?,
|
2023-04-13 23:33:31 -07:00
|
|
|
"service" => (service.serialize 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
|
|
|
}
|
|
|
|
|
2020-09-03 10:34:22 +01:00
|
|
|
if stable
|
2023-07-24 14:01:53 -07:00
|
|
|
stable_spec = T.must(stable)
|
2020-09-03 10:34:22 +01:00
|
|
|
hsh["urls"]["stable"] = {
|
2023-07-24 14:01:53 -07:00
|
|
|
"url" => stable_spec.url,
|
|
|
|
"tag" => stable_spec.specs[:tag],
|
|
|
|
"revision" => stable_spec.specs[:revision],
|
|
|
|
"checksum" => stable_spec.checksum&.to_s,
|
2020-05-13 00:37:37 -04:00
|
|
|
}
|
|
|
|
|
2021-02-10 10:36:40 +00:00
|
|
|
hsh["bottle"]["stable"] = bottle_hash if bottle_defined?
|
2015-09-13 12:59:13 +08:00
|
|
|
end
|
|
|
|
|
2023-02-06 13:04:16 +00:00
|
|
|
if head
|
|
|
|
hsh["urls"]["head"] = {
|
2023-07-24 14:01:53 -07:00
|
|
|
"url" => T.must(head).url,
|
|
|
|
"branch" => T.must(head).specs[:branch],
|
2023-02-06 13:04:16 +00:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2018-05-12 10:42:07 -04:00
|
|
|
hsh["options"] = options.map do |opt|
|
|
|
|
{ "option" => opt.flag, "description" => opt.description }
|
|
|
|
end
|
|
|
|
|
2023-06-19 06:07:53 +01:00
|
|
|
dependencies.each do |spec_sym, spec_deps|
|
|
|
|
next if spec_deps.nil?
|
|
|
|
|
|
|
|
dep_hash = if spec_sym == :stable
|
|
|
|
hsh
|
|
|
|
else
|
|
|
|
next if spec_deps == dependencies[:stable]
|
|
|
|
|
|
|
|
hsh["#{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
|
|
|
|
|
|
|
|
hsh["requirements"] = merge_spec_dependables(requirements).map do |data|
|
|
|
|
req = data[:dependable]
|
2023-02-14 02:31:12 +00:00
|
|
|
req_name = req.name.dup
|
|
|
|
req_name.prepend("maximum_") if req.try(:comparator) == "<="
|
2018-05-12 10:42:07 -04:00
|
|
|
{
|
2023-02-14 02:31:12 +00:00
|
|
|
"name" => req_name,
|
2018-11-02 17:18:07 +00:00
|
|
|
"cask" => req.cask,
|
2018-05-12 10:42:07 -04:00
|
|
|
"download" => req.download,
|
2020-11-01 11:57:00 -05:00
|
|
|
"version" => req.try(:version) || req.try(:arch),
|
2020-03-02 16:29:49 -05:00
|
|
|
"contexts" => req.tags,
|
2023-06-19 06:07:53 +01:00
|
|
|
"specs" => data[:specs],
|
2018-05-12 10:42:07 -04:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2020-07-16 01:48:25 +01:00
|
|
|
hsh["installed"] = installed_kegs.sort_by(&:version).map do |keg|
|
2015-11-29 15:22:22 +08:00
|
|
|
tab = Tab.for_keg keg
|
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
|
|
|
|
|
2022-07-21 13:04:56 +02:00
|
|
|
# @private
|
2022-07-21 16:41:15 +02:00
|
|
|
def to_hash_with_variations
|
2023-02-13 05:07:01 +00:00
|
|
|
hash = to_hash
|
|
|
|
|
|
|
|
# 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?
|
2023-02-13 05:07:01 +00:00
|
|
|
json_formula = Homebrew::API::Formula.all_formulae[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-05-09 02:15:28 +02:00
|
|
|
os_versions = [*MacOSVersion::SYMBOLS.keys, :linux]
|
2022-07-21 13:04:56 +02:00
|
|
|
|
2023-06-19 03:47:50 +01:00
|
|
|
if path.exist? && (self.class.on_system_blocks_exist? || @on_system_blocks_exist)
|
2023-05-13 22:35:08 +02:00
|
|
|
formula_contents = path.read
|
|
|
|
os_versions.product(OnSystem::ARCH_OPTIONS).each do |os, arch|
|
|
|
|
bottle_tag = Utils::Bottles::Tag.new(system: os, arch: arch)
|
|
|
|
next unless bottle_tag.valid_combination?
|
|
|
|
|
|
|
|
Homebrew::SimulateSystem.with os: os, arch: arch do
|
|
|
|
variations_namespace = Formulary.class_s("Variations#{bottle_tag.to_sym.capitalize}")
|
|
|
|
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,
|
|
|
|
alias_path: alias_path, force_bottle: force_bottle)
|
|
|
|
|
|
|
|
variations_formula.to_hash.each do |key, value|
|
|
|
|
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
|
|
|
|
|
|
|
|
hash["variations"] = variations
|
|
|
|
hash
|
|
|
|
end
|
|
|
|
|
2021-02-10 10:36:40 +00:00
|
|
|
# Returns the bottle information for a formula
|
|
|
|
def bottle_hash
|
2023-07-24 14:01:53 -07:00
|
|
|
bottle_spec = T.must(stable).bottle_specification
|
2021-02-10 10:36:40 +00:00
|
|
|
hash = {
|
|
|
|
"rebuild" => bottle_spec.rebuild,
|
|
|
|
"root_url" => bottle_spec.root_url,
|
|
|
|
"files" => {},
|
|
|
|
}
|
2021-09-16 18:56:47 +01:00
|
|
|
bottle_spec.collector.each_tag do |tag|
|
|
|
|
tag_spec = bottle_spec.collector.specification_for(tag)
|
|
|
|
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-04-09 14:01:18 +01:00
|
|
|
|
2021-09-16 18:56:47 +01:00
|
|
|
checksum = tag_spec.checksum.hexdigest
|
|
|
|
filename = Bottle::Filename.create(self, tag, bottle_spec.rebuild)
|
2021-04-15 18:06:54 +01:00
|
|
|
path, = Utils::Bottles.path_resolved_basename(bottle_spec.root_url, name, checksum, filename)
|
2021-04-09 14:01:18 +01:00
|
|
|
url = "#{bottle_spec.root_url}/#{path}"
|
|
|
|
|
2021-09-16 18:56:47 +01:00
|
|
|
hash["files"][tag.to_sym] = {
|
2021-04-09 14:01:18 +01:00
|
|
|
"cellar" => os_cellar,
|
|
|
|
"url" => url,
|
|
|
|
"sha256" => checksum,
|
2021-02-10 10:36:40 +00:00
|
|
|
}
|
|
|
|
end
|
|
|
|
hash
|
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-08-02 14:32:31 +02:00
|
|
|
def fetch(verify_download_integrity: true)
|
|
|
|
active_spec.fetch(verify_download_integrity: verify_download_integrity)
|
2013-06-05 09:47:08 -07:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2023-03-07 23:48:52 +00:00
|
|
|
def verify_download_integrity(filename)
|
|
|
|
active_spec.verify_download_integrity(filename)
|
2013-06-05 09:47:08 -07:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-08-02 14:32:31 +02:00
|
|
|
def run_test(keep_tmp: false)
|
2017-01-06 08:50:35 +00:00
|
|
|
@prefix_returns_versioned_prefix = true
|
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
|
2016-04-10 22:53:56 -04:00
|
|
|
@testpath = staging.tmpdir
|
2017-10-29 14:44:43 +00:00
|
|
|
test_env[:HOME] = @testpath
|
2015-10-17 10:05:41 -07:00
|
|
|
setup_home @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
|
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
|
2017-01-06 08:50:35 +00:00
|
|
|
@prefix_returns_versioned_prefix = false
|
2020-08-02 06:05:53 +02:00
|
|
|
@testpath = nil
|
2013-06-05 09:47:08 -07:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(T::Boolean) }
|
2013-06-05 09:47:08 -07:00
|
|
|
def test_defined?
|
2014-08-16 17:44:22 -05:00
|
|
|
false
|
2013-06-05 09:47:08 -07:00
|
|
|
end
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
2017-10-07 00:31:28 +02:00
|
|
|
def test; end
|
2014-09-18 14:16:07 -05:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>def install
|
|
|
|
# system "./configure", "--prefix=#{prefix}"
|
|
|
|
# system "make", "install"
|
|
|
|
# end</pre>
|
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}.
|
|
|
|
#
|
|
|
|
# `inreplace` supports regular expressions:
|
|
|
|
# <pre>inreplace "somefile.cfg", /look[for]what?/, "replace by #{bin}/tool"</pre>
|
|
|
|
#
|
|
|
|
# `inreplace` supports blocks:
|
|
|
|
# <pre>inreplace "Makefile" do |s|
|
|
|
|
# s.gsub! "/usr/local", HOMEBREW_PREFIX.to_s
|
|
|
|
# end
|
|
|
|
# </pre>
|
|
|
|
#
|
|
|
|
# @see Utils::Inreplace.inreplace
|
|
|
|
# @api public
|
2023-07-21 19:48:28 -07:00
|
|
|
sig {
|
|
|
|
params(
|
|
|
|
paths: T.any(T::Array[T.untyped], String, Pathname),
|
2023-07-23 15:23:45 +08:00
|
|
|
before: T.nilable(T.any(Pathname, Regexp, String)),
|
2023-07-21 19:48:28 -07:00
|
|
|
after: T.nilable(T.any(Pathname, String, Symbol)),
|
|
|
|
audit_result: T::Boolean,
|
|
|
|
).void
|
|
|
|
}
|
2022-07-30 19:10:40 +02:00
|
|
|
def inreplace(paths, before = nil, after = nil, audit_result = true) # rubocop:disable Style/OptionalBooleanParameter
|
|
|
|
super(paths, before, after, audit_result)
|
2022-10-07 21:00:46 +01:00
|
|
|
rescue Utils::Inreplace::Error => e
|
|
|
|
onoe e.to_s
|
2023-07-21 20:09:00 -07:00
|
|
|
args = paths.is_a?(Array) ? paths : [paths]
|
|
|
|
raise BuildError.new(self, "inreplace", args, {})
|
2022-07-30 19:10:40 +02:00
|
|
|
end
|
|
|
|
|
2014-12-12 22:27:34 -05:00
|
|
|
protected
|
|
|
|
|
2015-10-17 10:05:41 -07:00
|
|
|
def setup_home(home)
|
|
|
|
# keep Homebrew's site-packages in sys.path when using system Python
|
2015-04-08 12:56:32 -07:00
|
|
|
user_site_packages = home/"Library/Python/2.7/lib/python/site-packages"
|
|
|
|
user_site_packages.mkpath
|
2018-07-11 15:17:40 +02:00
|
|
|
(user_site_packages/"homebrew.pth").write <<~PYTHON
|
2015-04-08 12:56:32 -07:00
|
|
|
import site; site.addsitedir("#{HOMEBREW_PREFIX}/lib/python2.7/site-packages")
|
2016-01-27 08:39:32 -08:00
|
|
|
import sys, os; sys.path = (os.environ["PYTHONPATH"].split(os.pathsep) if "PYTHONPATH" in os.environ else []) + ["#{HOMEBREW_PREFIX}/lib/python2.7/site-packages"] + sys.path
|
2018-07-11 15:17:40 +02:00
|
|
|
PYTHON
|
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.
|
|
|
|
# @private
|
|
|
|
def declared_runtime_dependencies
|
|
|
|
recursive_dependencies do |_, dependency|
|
|
|
|
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.
|
|
|
|
# @private
|
|
|
|
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.
|
|
|
|
# <pre>system "./bootstrap.sh", "--arg1", "--prefix=#{prefix}"</pre>
|
|
|
|
#
|
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}:
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>system "cmake", ".", *std_cmake_args</pre>
|
|
|
|
#
|
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:
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>args = ["--with-option1", "--with-option2"]
|
2020-11-03 16:36:48 -05:00
|
|
|
# args << "--without-gcc" if ENV.compiler == :clang
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# # Most software still uses `configure` and `make`.
|
2020-11-05 17:17:03 -05:00
|
|
|
# # Check with `./configure --help` for what our options are.
|
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)
|
|
|
|
#
|
2020-11-03 16:36:48 -05:00
|
|
|
# # If there is a "make install" available, please use it!
|
2015-08-29 10:56:24 +01:00
|
|
|
# system "make", "install"</pre>
|
2020-11-28 22:59:14 +11:00
|
|
|
sig { params(cmd: T.any(String, Pathname), args: T.any(String, Pathname, Integer)).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"
|
|
|
|
pretty_args -= %w[--disable-dependency-tracking --disable-debug --disable-silent-rules]
|
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
|
|
|
|
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
|
|
|
|
2013-10-27 07:05:13 +01:00
|
|
|
@exec_count ||= 0
|
|
|
|
@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
|
|
|
|
2020-11-24 15:46:47 +01:00
|
|
|
Process.wait(T.must(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
|
|
|
|
2015-12-29 12:57:48 +01:00
|
|
|
# @private
|
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)
|
2021-05-28 10:00:36 -04:00
|
|
|
head, stable = installed_kegs.partition { |k| k.version.head? }
|
2021-05-28 11:34:36 -04:00
|
|
|
# Remove newest head and stable kegs
|
2021-06-01 03:25:26 -04:00
|
|
|
head - [Keg.new(head_prefix)] + stable.sort_by(&: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|
|
|
|
|
tab = Tab.for_keg(keg)
|
|
|
|
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
|
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.
|
2020-08-19 17:12:32 +01:00
|
|
|
def mktemp(prefix = name, opts = {}, &block)
|
|
|
|
Mktemp.new(prefix, opts).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.
|
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.
|
2020-11-24 15:46:47 +01:00
|
|
|
sig { params(args: T.any(String, Pathname)).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
|
|
|
|
T.unsafe(self).system("xcodebuild", *args)
|
|
|
|
ensure
|
|
|
|
ENV.update(removed)
|
|
|
|
end
|
2018-07-14 18:13:23 +01:00
|
|
|
end
|
|
|
|
|
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
|
|
|
|
|
|
|
|
sig { returns(Hash) }
|
|
|
|
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
|
|
|
|
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.
|
|
|
|
# @private
|
2023-03-07 23:42:00 +00:00
|
|
|
def versioned_prefix(version)
|
|
|
|
rack/version
|
2017-01-06 08:50:35 +00:00
|
|
|
end
|
|
|
|
|
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" }
|
2020-11-24 15:46:47 +01:00
|
|
|
env = T.cast(ENV, T.any(Stdenv, Superenv))
|
|
|
|
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.
|
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",
|
|
|
|
CURL_HOME: ENV.fetch("CURL_HOME") { Dir.home },
|
|
|
|
PYTHONDONTWRITEBYTECODE: "1",
|
2020-07-16 01:48:25 +01:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2022-07-31 19:59:25 +01:00
|
|
|
def stage(interactive: false, debug_symbols: false)
|
|
|
|
active_spec.stage(debug_symbols: debug_symbols) do |staging|
|
2016-01-14 19:00:06 +08:00
|
|
|
@source_modified_time = active_spec.source_modified_time
|
2012-02-24 12:50:21 -08:00
|
|
|
@buildpath = Pathname.pwd
|
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
|
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
|
|
|
|
@buildpath = nil
|
|
|
|
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
|
2022-07-21 15:32:51 +02:00
|
|
|
extend Predicable
|
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.
|
|
|
|
def inherited(child)
|
|
|
|
super
|
|
|
|
child.instance_eval do
|
|
|
|
# Ensure this is synced with `freeze`
|
|
|
|
@stable = SoftwareSpec.new(flags: build_flags)
|
|
|
|
@head = HeadSoftwareSpec.new(flags: build_flags)
|
|
|
|
@livecheck = Livecheck.new(self)
|
|
|
|
@conflicts = []
|
|
|
|
@skip_clean_paths = Set.new
|
|
|
|
@link_overwrite_paths = Set.new
|
|
|
|
@allowed_missing_libraries = Set.new
|
2023-05-15 13:58:33 +02:00
|
|
|
@loaded_from_api = false
|
2022-08-24 23:53:35 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-10-07 00:31:28 +02:00
|
|
|
def method_added(method)
|
2020-08-19 17:12:32 +01:00
|
|
|
super
|
|
|
|
|
2017-10-07 00:31:28 +02:00
|
|
|
case method
|
|
|
|
when :brew
|
|
|
|
raise "You cannot override Formula#brew in class #{name}"
|
|
|
|
when :test
|
|
|
|
define_method(:test_defined?) { true }
|
|
|
|
end
|
2013-01-07 17:34:56 -06:00
|
|
|
end
|
2009-09-28 14:06:53 -07:00
|
|
|
|
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
|
|
|
|
@allowed_missing_libraries.freeze
|
|
|
|
super
|
|
|
|
end
|
|
|
|
|
2022-09-10 20:28:21 -04:00
|
|
|
# Whether this formula was loaded using the formulae.brew.sh API
|
|
|
|
# @private
|
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`).
|
|
|
|
# @private
|
|
|
|
attr_predicate :on_system_blocks_exist?
|
|
|
|
|
2014-12-06 11:26:43 +00:00
|
|
|
# The reason for why this software is not linked (by default) to
|
|
|
|
# {::HOMEBREW_PREFIX}.
|
2014-12-26 20:24:12 +00:00
|
|
|
# @private
|
2014-08-19 17:14:02 -05:00
|
|
|
attr_reader :keg_only_reason
|
2014-12-06 11:26:43 +00:00
|
|
|
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!attribute [w] desc
|
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
|
|
|
#
|
|
|
|
# <pre>desc "Example formula"</pre>
|
2015-05-19 13:06:06 -04:00
|
|
|
attr_rw :desc
|
|
|
|
|
2020-11-05 15:19:56 -05:00
|
|
|
# @!attribute [w] license
|
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`.
|
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.
|
|
|
|
# Add `+` to an identifier to indicate that the formulae can be
|
|
|
|
# licensed under later versions of the same license.
|
2020-08-24 01:54:28 -04:00
|
|
|
# @see https://docs.brew.sh/License-Guidelines Homebrew License Guidelines
|
2020-08-18 10:58:32 -04:00
|
|
|
# @see https://spdx.github.io/spdx-spec/appendix-IV-SPDX-license-expressions/ SPDX license expression guide
|
2020-06-24 18:32:53 +08:00
|
|
|
# <pre>license "BSD-2-Clause"</pre>
|
2020-08-18 10:58:32 -04:00
|
|
|
# <pre>license "EPL-1.0+"</pre>
|
|
|
|
# <pre>license any_of: ["MIT", "GPL-2.0-only"]</pre>
|
|
|
|
# <pre>license all_of: ["MIT", "GPL-2.0-only"]</pre>
|
|
|
|
# <pre>license "GPL-2.0-only" => { with: "LLVM-exception" }</pre>
|
2020-08-04 10:47:41 +01:00
|
|
|
# <pre>license :public_domain</pre>
|
2020-08-24 01:54:28 -04:00
|
|
|
# <pre>license any_of: [
|
|
|
|
# "MIT",
|
|
|
|
# :public_domain,
|
|
|
|
# all_of: ["0BSD", "Zlib", "Artistic-1.0+"],
|
|
|
|
# "Apache-2.0" => { with: "LLVM-exception" },
|
|
|
|
# ]</pre>
|
2020-08-20 10:26:37 -04:00
|
|
|
def license(args = nil)
|
|
|
|
if args.nil?
|
|
|
|
@licenses
|
|
|
|
else
|
|
|
|
@licenses = args
|
|
|
|
end
|
|
|
|
end
|
2020-07-09 13:01:10 +08:00
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @!attribute [w] homepage
|
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
|
|
|
#
|
|
|
|
# <pre>homepage "https://www.example.com"</pre>
|
2014-12-06 11:26:43 +00:00
|
|
|
attr_rw :homepage
|
|
|
|
|
2020-03-16 01:37:49 +05:30
|
|
|
# Whether a livecheck specification is defined or not.
|
|
|
|
# It returns true when a livecheck block is present in the {Formula} and
|
|
|
|
# false otherwise, and is used by livecheck.
|
2023-07-23 21:05:02 -07:00
|
|
|
sig { returns(T::Boolean) }
|
2020-03-16 01:37:49 +05:30
|
|
|
def livecheckable?
|
|
|
|
@livecheckable == true
|
|
|
|
end
|
|
|
|
|
2020-12-11 23:14:50 +01:00
|
|
|
# Whether a service specification is defined or not.
|
|
|
|
# It returns true when a service block is present in the {Formula} and
|
|
|
|
# false otherwise, and is used by service.
|
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
|
|
|
|
|
2014-12-06 11:26:43 +00:00
|
|
|
# The `:startup` attribute set by {.plist_options}.
|
2014-12-26 20:24:12 +00:00
|
|
|
# @private
|
|
|
|
attr_reader :plist_startup
|
2014-12-06 11:26:43 +00:00
|
|
|
|
|
|
|
# The `:manual` attribute set by {.plist_options}.
|
2014-12-26 20:24:12 +00:00
|
|
|
# @private
|
|
|
|
attr_reader :plist_manual
|
2014-12-06 11:26:43 +00:00
|
|
|
|
2022-08-24 23:53:35 +01:00
|
|
|
# @private
|
|
|
|
attr_reader :conflicts
|
|
|
|
|
|
|
|
# @private
|
|
|
|
attr_reader :skip_clean_paths
|
|
|
|
|
|
|
|
# @private
|
|
|
|
attr_reader :link_overwrite_paths
|
|
|
|
|
|
|
|
# @private
|
|
|
|
attr_reader :allowed_missing_libraries
|
|
|
|
|
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.
|
|
|
|
# @private
|
|
|
|
attr_accessor :pour_bottle_check_unsatisfied_reason
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @!attribute [w] revision
|
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
|
|
|
#
|
|
|
|
# <pre>revision 1</pre>
|
2014-12-06 11:26:43 +00:00
|
|
|
attr_rw :revision
|
2009-10-17 14:35:24 +02:00
|
|
|
|
2016-08-11 09:54:47 +02:00
|
|
|
# @!attribute [w] version_scheme
|
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.
|
|
|
|
#
|
|
|
|
# <pre>version_scheme 1</pre>
|
|
|
|
attr_rw :version_scheme
|
|
|
|
|
2023-06-19 06:07:53 +01:00
|
|
|
# @private
|
|
|
|
def spec_syms
|
|
|
|
[:stable, :head].freeze
|
|
|
|
end
|
|
|
|
|
2020-09-03 10:34:22 +01:00
|
|
|
# A list of the {.stable} and {.head} {SoftwareSpec}s.
|
2014-12-26 20:24:12 +00:00
|
|
|
# @private
|
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
|
|
|
|
|
2015-01-04 14:25:59 -05:00
|
|
|
# @!attribute [w] url
|
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
|
|
|
#
|
|
|
|
# <pre>url "https://packed.sources.and.we.prefer.https.example.com/archive-1.2.3.tar.bz2"</pre>
|
2017-02-19 13:21:55 -08:00
|
|
|
# <pre>url "https://some.dont.provide.archives.example.com",
|
2020-11-03 16:36:48 -05:00
|
|
|
# using: :git,
|
|
|
|
# tag: "1.2.3",
|
|
|
|
# revision: "db8e4de5b2d6653f66aea53094624468caad15d2"</pre>
|
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
|
|
|
#
|
|
|
|
# <pre>version "1.2-final"</pre>
|
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
|
|
|
#
|
|
|
|
# <pre>mirror "https://in.case.the.host.is.down.example.com"
|
|
|
|
# mirror "https://in.case.the.mirror.is.down.example.com</pre>
|
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
|
|
|
#
|
|
|
|
# <pre>sha256 "2a2ba417eebaadcb4418ee7b12fe2998f26d6e6f7fda7983412ff66a741ab6f7"</pre>
|
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
|
|
|
# @!attribute [w] bottle
|
|
|
|
# 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
|
|
|
#
|
|
|
|
# <pre>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"
|
2015-08-29 10:56:24 +01:00
|
|
|
# end</pre>
|
2015-09-14 19:51:04 +08:00
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# Homebrew maintainers aim to bottle all formulae that require compilation.
|
2015-10-19 17:09:13 +01:00
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# Formulae that can be installed without compilation should be tagged with:
|
2015-09-14 19:51:04 +08:00
|
|
|
# <pre>bottle :unneeded</pre>
|
|
|
|
#
|
2021-01-09 13:34:17 +11:00
|
|
|
# Formulae which should not be bottled should be tagged with:
|
2015-09-14 19:51:04 +08:00
|
|
|
# <pre>bottle :disable, "reasons"</pre>
|
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
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# @private
|
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`.
|
2020-07-26 07:24:14 +02:00
|
|
|
# @private
|
|
|
|
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
|
|
|
#
|
|
|
|
# <pre>stable do
|
|
|
|
# url "https://example.com/foo-1.0.tar.gz"
|
|
|
|
# sha256 "2a2ba417eebaadcb4418ee7b12fe2998f26d6e6f7fda7983412ff66a741ab6f7"
|
|
|
|
#
|
|
|
|
# depends_on "libxml2"
|
|
|
|
# depends_on "libffi"
|
|
|
|
# end</pre>
|
2015-08-03 13:09:07 +01:00
|
|
|
def stable(&block)
|
2020-11-16 22:18:56 +01:00
|
|
|
return @stable unless block
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2013-09-12 19:43:22 -05:00
|
|
|
@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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>head "https://we.prefer.https.over.git.example.com/.git"</pre>
|
2020-11-03 16:36:48 -05:00
|
|
|
# <pre>head "https://example.com/.git", branch: "name_of_branch"</pre>
|
2015-08-29 10:56:24 +01:00
|
|
|
# or (if autodetect fails):
|
2020-11-03 16:36:48 -05:00
|
|
|
# <pre>head "https://hg.is.awesome.but.git.has.won.example.com/", using: :hg</pre>
|
2015-08-03 13:09:07 +01:00
|
|
|
def head(val = nil, specs = {}, &block)
|
2020-11-16 22:18:56 +01:00
|
|
|
if block
|
2013-09-13 11:13:12 -05:00
|
|
|
@head.instance_eval(&block)
|
|
|
|
elsif val
|
|
|
|
@head.url(val, specs)
|
|
|
|
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.
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>resource "additional_files" do
|
|
|
|
# url "https://example.com/additional-stuff.tar.gz"
|
|
|
|
# sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2"
|
|
|
|
# end</pre>
|
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
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def go_resource(name, &block)
|
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).
|
|
|
|
#
|
|
|
|
# `:build` means this dependency is only needed during build.
|
|
|
|
# <pre>depends_on "cmake" => :build</pre>
|
|
|
|
#
|
|
|
|
# `:test` means this dependency is only needed during testing.
|
|
|
|
# <pre>depends_on "node" => :test</pre>
|
|
|
|
#
|
|
|
|
# `:recommended` dependencies are built by default.
|
|
|
|
# But a `--without-...` option is generated to opt-out.
|
|
|
|
# <pre>depends_on "readline" => :recommended</pre>
|
|
|
|
#
|
|
|
|
# `:optional` dependencies are NOT built by default unless the
|
|
|
|
# auto-generated `--with-...` option is passed.
|
|
|
|
# <pre>depends_on "glib" => :optional</pre>
|
|
|
|
#
|
|
|
|
# If you need to specify that another formula has to be built with/out
|
|
|
|
# certain options (note, no `--` needed before the option):
|
|
|
|
# <pre>depends_on "zeromq" => "with-pgm"
|
2015-08-29 10:56:24 +01:00
|
|
|
# depends_on "qt" => ["with-qtdbus", "developer"] # Multiple options.</pre>
|
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`.
|
2021-01-09 13:34:17 +11:00
|
|
|
# <pre>depends_on "boost" => [:optional, "with-c++11"]</pre>
|
|
|
|
#
|
|
|
|
# If a dependency is only needed in certain cases:
|
|
|
|
# <pre>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.
|
2021-01-09 13:34:17 +11:00
|
|
|
# </pre>
|
|
|
|
#
|
|
|
|
# It is possible to only depend on something if
|
|
|
|
# `build.with?` or `build.without? "another_formula"`:
|
|
|
|
# <pre>depends_on "postgresql" if build.without? "sqlite"</pre>
|
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}.
|
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).
|
|
|
|
# <pre>option "with-spam", "The description goes here without a dot at the end"</pre>
|
2020-11-05 17:17:03 -05:00
|
|
|
# <pre>option "with-qt", "Text here overwrites what's autogenerated by 'depends_on "qt" => :optional'"</pre>
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>option :universal</pre>
|
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`).
|
|
|
|
# <pre>deprecated_option "enable-debug" => "with-debug"</pre>
|
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.
|
|
|
|
# <pre>patch do
|
|
|
|
# url "https://example.com/example_patch.diff"
|
|
|
|
# sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2"
|
|
|
|
# end</pre>
|
|
|
|
#
|
|
|
|
# A strip level of `-p1` is assumed. It can be overridden using a symbol
|
|
|
|
# argument:
|
|
|
|
# <pre>patch :p0 do
|
|
|
|
# url "https://example.com/example_patch.diff"
|
|
|
|
# sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2"
|
|
|
|
# end</pre>
|
|
|
|
#
|
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.
|
|
|
|
# <pre>stable do
|
|
|
|
# patch do
|
|
|
|
# url "https://example.com/example_patch.diff"
|
|
|
|
# sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2"
|
|
|
|
# end
|
|
|
|
# end</pre>
|
|
|
|
#
|
|
|
|
# Embedded (`__END__`) patches are declared like so:
|
|
|
|
# <pre>patch :DATA
|
|
|
|
# patch :p0, :DATA</pre>
|
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
# <pre>patch :p0, "..."</pre>
|
2020-11-03 12:39:26 -05:00
|
|
|
# @see https://docs.brew.sh/Formula-Cookbook#patches Patches
|
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
|
|
|
|
|
2015-08-29 10:56:24 +01:00
|
|
|
# Defines launchd plist handling.
|
|
|
|
#
|
|
|
|
# Does your plist need to be loaded at startup?
|
2020-11-03 16:36:48 -05:00
|
|
|
# <pre>plist_options startup: true</pre>
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# Or only when necessary or desired by the user?
|
2020-11-03 16:36:48 -05:00
|
|
|
# <pre>plist_options manual: "foo"</pre>
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
|
|
|
# Or perhaps you'd like to give the user a choice? Ooh fancy.
|
2020-11-03 16:36:48 -05:00
|
|
|
# <pre>plist_options startup: true, manual: "foo start"</pre>
|
2022-11-06 13:52:53 +01:00
|
|
|
#
|
2021-10-23 21:32:38 -04:00
|
|
|
# @deprecated Please use {Homebrew::Service.require_root} instead.
|
2015-08-03 13:09:07 +01:00
|
|
|
def plist_options(options)
|
2023-07-06 16:47:09 +01:00
|
|
|
odisabled "plist_options", "service.require_root"
|
2012-11-25 15:06:41 +00:00
|
|
|
@plist_startup = options[:startup]
|
|
|
|
@plist_manual = options[:manual]
|
|
|
|
end
|
2012-07-30 11:32:56 -07:00
|
|
|
|
2020-11-03 16:36:48 -05:00
|
|
|
# One or more formulae that conflict with this one and why.
|
|
|
|
# <pre>conflicts_with "imagemagick", because: "both install `convert` binaries"</pre>
|
2015-08-03 13:09:07 +01:00
|
|
|
def conflicts_with(*names)
|
2016-09-20 22:03:08 +02:00
|
|
|
opts = names.last.is_a?(Hash) ? names.pop : {}
|
2013-08-29 19:03:34 -05:00
|
|
|
names.each { |name| 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.
|
|
|
|
# Preserve cleaned paths with:
|
|
|
|
# <pre>skip_clean "bin/foo", "lib/bar"</pre>
|
|
|
|
# Keep .la files with:
|
|
|
|
# <pre>skip_clean :la</pre>
|
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
|
2013-12-22 13:43:00 -06:00
|
|
|
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
|
|
|
|
# will add the necessary includes, libraries, and other paths while
|
|
|
|
# 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.
|
2016-09-18 19:57:19 +01:00
|
|
|
# <pre>keg_only :provided_by_macos</pre>
|
2021-01-09 13:34:17 +11:00
|
|
|
# <pre>keg_only :versioned_formulae</pre>
|
2015-08-29 10:56:24 +01:00
|
|
|
# <pre>keg_only "because I want it so"</pre>
|
2015-08-03 13:09:07 +01:00
|
|
|
def keg_only(reason, explanation = "")
|
2014-08-08 01:34:45 -05:00
|
|
|
@keg_only_reason = KegOnlyReason.new(reason, explanation)
|
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.
|
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.
|
2013-09-28 12:21:16 -07:00
|
|
|
# For Apple compilers, this should be in the format:
|
2016-05-22 09:40:08 +01:00
|
|
|
# <pre>fails_with :clang do
|
2015-08-29 10:56:24 +01:00
|
|
|
# build 600
|
|
|
|
# cause "multiple configure and compile errors"
|
|
|
|
# end</pre>
|
|
|
|
#
|
2013-09-28 12:21:16 -07: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
|
|
|
#
|
2019-01-08 19:13:46 +00:00
|
|
|
# <pre>fails_with :gcc => '7' do
|
|
|
|
# version '7.1'
|
2015-08-29 10:56:24 +01:00
|
|
|
# end</pre>
|
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`.
|
|
|
|
#
|
|
|
|
# @see #fails_with
|
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
|
|
|
# @return [Boolean]
|
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
#
|
2020-11-03 12:39:26 -05:00
|
|
|
# @see https://docs.brew.sh/Formula-Cookbook#add-a-test-to-the-formula Tests
|
2015-08-29 10:56:24 +01:00
|
|
|
#
|
2017-10-15 02:28:32 +02:00
|
|
|
# <pre>(testpath/"test.file").write <<~EOS
|
2015-08-29 10:56:24 +01:00
|
|
|
# writing some test file, if you need to
|
|
|
|
# EOS
|
|
|
|
# assert_equal "OK", shell_output("test_command test.file").strip</pre>
|
|
|
|
#
|
|
|
|
# Need complete control over stdin, stdout?
|
|
|
|
# <pre>require "open3"
|
|
|
|
# Open3.popen3("#{bin}/example", "argument") do |stdin, stdout, _|
|
|
|
|
# stdin.write("some text")
|
|
|
|
# stdin.close
|
|
|
|
# assert_equal "result", stdout.read
|
|
|
|
# end</pre>
|
|
|
|
#
|
|
|
|
# The test will fail if it returns false, or if an exception is raised.
|
|
|
|
# Failed assertions and failed `system` commands will raise exceptions.
|
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
|
|
|
|
2020-03-16 01:37:49 +05:30
|
|
|
# @!attribute [w] livecheck
|
2021-01-09 13:34:17 +11:00
|
|
|
# {Livecheck} can be used to check for newer versions of the software.
|
2020-03-16 01:37:49 +05:30
|
|
|
# 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.
|
|
|
|
#
|
|
|
|
# <pre>livecheck do
|
|
|
|
# skip "Not maintained"
|
|
|
|
# url "https://example.com/foo/releases"
|
|
|
|
# regex /foo-(\d+(?:\.\d+)+)\.tar/
|
|
|
|
# end</pre>
|
|
|
|
def livecheck(&block)
|
2020-11-16 22:18:56 +01:00
|
|
|
return @livecheck unless block
|
2020-03-16 01:37:49 +05:30
|
|
|
|
|
|
|
@livecheckable = true
|
|
|
|
@livecheck.instance_eval(&block)
|
|
|
|
end
|
|
|
|
|
2020-12-11 23:14:50 +01:00
|
|
|
# @!attribute [w] service
|
|
|
|
# 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
|
|
|
#
|
|
|
|
# <pre>service do
|
|
|
|
# run [opt_bin/"foo"]
|
|
|
|
# end</pre>
|
|
|
|
def service(&block)
|
2021-04-08 10:06:45 +02:00
|
|
|
return @service_block unless block
|
2020-12-11 23:14:50 +01:00
|
|
|
|
2021-04-08 10:06:45 +02:00
|
|
|
@service_block = block
|
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.
|
|
|
|
#
|
|
|
|
# For example, if the bottle requires the Xcode CLT to be installed a
|
|
|
|
# {Formula} would declare:
|
|
|
|
# <pre>pour_bottle? do
|
|
|
|
# reason "The bottle needs the Xcode CLT to be installed."
|
|
|
|
# satisfy { MacOS::CLT.installed? }
|
|
|
|
# end</pre>
|
|
|
|
#
|
|
|
|
# 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:
|
2021-05-20 11:29:33 -04:00
|
|
|
# <pre>pour_bottle? only_if: :clt_installed</pre>
|
2021-05-20 11:24:08 -04:00
|
|
|
def pour_bottle?(only_if: nil, &block)
|
2016-01-09 11:06:17 +00:00
|
|
|
@pour_bottle_check = PourBottleCheck.new(self)
|
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)
|
|
|
|
reason(+<<~EOS)
|
2021-05-15 14:05:50 -04:00
|
|
|
The bottle needs the Apple Command Line Tools to be installed.
|
|
|
|
You can install them, if desired, with:
|
|
|
|
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)
|
|
|
|
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
|
|
|
|
|
2016-01-09 11:06:17 +00:00
|
|
|
@pour_bottle_check.instance_eval(&block)
|
|
|
|
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.
|
2020-08-28 22:49:26 -04:00
|
|
|
# <pre>deprecate! date: "2020-08-27", because: :unmaintained</pre>
|
2020-11-03 16:36:48 -05:00
|
|
|
# <pre>deprecate! date: "2020-08-27", because: "has been replaced by foo"</pre>
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see https://docs.brew.sh/Deprecating-Disabling-and-Removing-Formulae
|
|
|
|
# @see DeprecateDisable::DEPRECATE_DISABLE_REASONS
|
2021-06-17 11:34:31 +01:00
|
|
|
def deprecate!(date:, because:)
|
|
|
|
@deprecation_date = Date.parse(date)
|
|
|
|
return if @deprecation_date > Date.today
|
2020-08-27 16:40:12 -04:00
|
|
|
|
2021-06-17 11:34:31 +01:00
|
|
|
@deprecation_reason = because
|
2020-04-01 13:42:52 +01:00
|
|
|
@deprecated = true
|
|
|
|
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.
|
|
|
|
# @return Date
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .deprecate!
|
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}.
|
2020-11-05 15:19:56 -05:00
|
|
|
# @return [nil] if no reason was provided or the formula is not deprecated.
|
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
|
|
|
attr_reader :deprecation_reason
|
|
|
|
|
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.
|
2020-08-28 22:49:26 -04:00
|
|
|
# <pre>disable! date: "2020-08-27", because: :does_not_build</pre>
|
|
|
|
# <pre>disable! date: "2020-08-27", because: "has been replaced by foo"</pre>
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see https://docs.brew.sh/Deprecating-Disabling-and-Removing-Formulae
|
|
|
|
# @see DeprecateDisable::DEPRECATE_DISABLE_REASONS
|
2021-06-17 11:34:31 +01:00
|
|
|
def disable!(date:, because:)
|
|
|
|
@disable_date = Date.parse(date)
|
2020-12-23 02:58:14 -05:00
|
|
|
|
2021-06-17 11:34:31 +01:00
|
|
|
if @disable_date > Date.today
|
|
|
|
@deprecation_reason = because
|
2020-04-29 09:34:40 +01:00
|
|
|
@deprecated = true
|
|
|
|
return
|
|
|
|
end
|
2020-04-01 13:42:52 +01:00
|
|
|
|
2021-06-17 11:34:31 +01:00
|
|
|
@disable_reason = because
|
2020-04-01 13:42:52 +01:00
|
|
|
@disabled = true
|
|
|
|
end
|
|
|
|
|
|
|
|
# Whether this {Formula} is disabled (i.e. cannot be installed).
|
|
|
|
# Defaults to false.
|
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.
|
|
|
|
# @return Date
|
2021-01-09 13:34:17 +11:00
|
|
|
# @see .disable!
|
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.
|
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
|
|
|
attr_reader :disable_reason
|
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# Permit overwriting certain files while linking.
|
|
|
|
#
|
|
|
|
# Sometimes we accidentally install files outside prefix. Once we fix that,
|
|
|
|
# users will get a link conflict error. Overwrite those files with:
|
|
|
|
# <pre>link_overwrite "bin/foo", "lib/bar"</pre>
|
|
|
|
# <pre>link_overwrite "share/man/man1/baz-*"</pre>
|
2015-08-23 16:35:51 +08:00
|
|
|
def link_overwrite(*paths)
|
|
|
|
paths.flatten!
|
|
|
|
link_overwrite_paths.merge(paths)
|
|
|
|
end
|
|
|
|
|
2021-01-09 13:34:17 +11:00
|
|
|
# Permit links to certain libraries that don't exist. Available on Linux only.
|
2022-07-23 02:58:50 +02:00
|
|
|
def ignore_missing_libraries(*libs)
|
2023-07-06 16:47:09 +01:00
|
|
|
odisabled "ignore_missing_libraries"
|
2022-07-28 09:18:16 -04:00
|
|
|
unless Homebrew::SimulateSystem.simulating_or_running_on_linux?
|
2022-07-23 02:58:50 +02:00
|
|
|
raise FormulaSpecificationError, "#{__method__} is available on Linux only"
|
|
|
|
end
|
|
|
|
|
|
|
|
libraries = libs.flatten
|
|
|
|
if libraries.any? { |x| !x.is_a?(String) && !x.is_a?(Regexp) }
|
|
|
|
raise FormulaSpecificationError, "#{__method__} can handle Strings and Regular Expressions only"
|
|
|
|
end
|
2022-07-22 18:44:40 +02:00
|
|
|
|
2022-07-23 02:58:50 +02:00
|
|
|
allowed_missing_libraries.merge(libraries)
|
2020-07-21 12:50:22 +00: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"
|