brew/Library/Homebrew/formula.rb

1342 lines
35 KiB
Ruby
Raw Normal View History

require "formula_support"
require "formula_lock"
require "formula_pin"
require "hardware"
require "bottles"
require "build_environment"
require "build_options"
require "formulary"
require "software_spec"
require "install_renamed"
require "pkg_version"
require "tap"
require "formula_renames"
2012-04-05 21:09:24 -05: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
class Formula
include FileUtils
include Utils::Inreplace
extend Enumerable
# The name of this {Formula}.
# e.g. `this-formula`
attr_reader :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`
attr_reader :full_name
# The full path to this {Formula}.
# e.g. `/usr/local/Library/Formula/this-formula.rb`
attr_reader :path
# 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.
attr_reader :stable
# The development {SoftwareSpec} for this {Formula}.
# Installed when using `brew install --devel`
# `nil` if there is no development version.
# @see #stable
attr_reader :devel
# The HEAD {SoftwareSpec} for this {Formula}.
# Installed when using `brew install --HEAD`
# 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
attr_reader :head
# The currently active {SoftwareSpec}.
2015-01-04 15:33:25 -05:00
# @see #determine_active_spec
attr_reader :active_spec
2015-01-04 15:33:25 -05:00
protected :active_spec
2015-07-28 15:10:40 +08:00
# A symbol to indicate currently active {SoftwareSpec}.
# It's either :stable, :devel or :head
# @see #active_spec
attr_reader :active_spec_sym
# Used for creating new Homebrew versions of software without new upstream
# versions.
# @see .revision
attr_reader :revision
# The current working directory during builds.
# Will only be non-`nil` inside {#install}.
attr_reader :buildpath
# The current working directory during tests.
# Will only be non-`nil` inside {#test}.
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`.
attr_accessor :local_bottle_path
# The {BuildOptions} for this {Formula}. Lists the arguments passed and any
# {#options} 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.
2014-08-11 17:48:30 -05:00
attr_accessor :build
# @private
def initialize(name, path, spec)
@name = name
2014-02-21 20:07:41 -05:00
@path = path
@revision = self.class.revision || 0
2015-05-27 20:30:43 +08:00
if path.to_s =~ HOMEBREW_TAP_PATH_REGEX
@full_name = "#{$1}/#{$2.gsub(/^homebrew-/, "")}/#{name}"
else
@full_name = name
end
set_spec :stable
set_spec :devel
set_spec :head
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
elsif devel?
:devel
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
@pin = FormulaPin.new(self)
2012-04-05 21:09:24 -05:00
end
2015-07-30 16:25:21 +08:00
# @private
def set_active_spec(spec_sym)
spec = send(spec_sym)
raise FormulaSpecificationError, "#{spec_sym} spec is not available for #{full_name}" unless spec
@active_spec = spec
@active_spec_sym = spec_sym
validate_attributes!
@build = active_spec.build
end
private
def set_spec(name)
spec = self.class.send(name)
if spec.url
spec.owner = self
instance_variable_set("@#{name}", spec)
end
end
2014-06-19 21:35:47 -05:00
def determine_active_spec(requested)
spec = send(requested) || stable || devel || head
spec || raise(FormulaSpecificationError, "formulae require at least a URL")
end
2014-12-26 16:08:12 -05:00
def validate_attributes!
if name.nil? || name.empty? || name =~ /\s/
raise FormulaValidationError.new(:name, name)
end
2014-12-26 16:07:32 -05:00
url = active_spec.url
2014-12-26 16:08:12 -05:00
if url.nil? || url.empty? || url =~ /\s/
raise FormulaValidationError.new(:url, url)
end
val = version.respond_to?(:to_str) ? version.to_str : version
if val.nil? || val.empty? || val =~ /\s/
raise FormulaValidationError.new(:version, val)
end
end
public
# Is the currently active {SoftwareSpec} a {#stable} build?
def stable?
active_spec == stable
end
# Is the currently active {SoftwareSpec} a {#devel} build?
def devel?
active_spec == devel
end
# Is the currently active {SoftwareSpec} a {#head} build?
def head?
active_spec == head
end
# @private
def bottled?
active_spec.bottled?
end
# @private
def bottle_specification
active_spec.bottle_specification
end
# The Bottle object for the currently active {SoftwareSpec}.
# @private
def bottle
Bottle.new(self, bottle_specification) if bottled?
end
2015-05-19 13:06:06 -04:00
# The description of the software.
# @see .desc
def desc
self.class.desc
end
# The homepage for the software.
# @see .homepage
def homepage
self.class.homepage
end
# 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.
# @see .version
def version
active_spec.version
end
# The {PkgVersion} for this formula with {version} and {#revision} information.
def pkg_version
PkgVersion.new(version, revision)
end
# A named Resource for the currently active {SoftwareSpec}.
def resource(name)
2013-09-17 21:25:39 -05:00
active_spec.resource(name)
end
# An old name for the formula
def oldname
@oldname ||= if core_formula?
if FORMULA_RENAMES && FORMULA_RENAMES.value?(name)
FORMULA_RENAMES.to_a.rassoc(name).first
end
elsif tap?
user, repo = tap.split("/")
formula_renames = Tap.new(user, repo.sub("homebrew-", "")).formula_renames
if formula_renames.value?(name)
formula_renames.to_a.rassoc(name).first
end
end
end
# The {Resource}s for the currently active {SoftwareSpec}.
def resources
2013-09-17 21:25:39 -05:00
active_spec.resources.values
end
# The {Dependency}s for the currently active {SoftwareSpec}.
2013-09-21 19:27:24 -05:00
def deps
active_spec.deps
end
# The {Requirement}s for the currently active {SoftwareSpec}.
2013-09-21 19:27:24 -05:00
def requirements
active_spec.requirements
end
2014-12-26 16:07:32 -05:00
# The cached download for the currently active {SoftwareSpec}.
2014-02-21 00:41:07 -05:00
def cached_download
2014-02-21 00:41:07 -05:00
active_spec.cached_download
2014-02-21 00:41:07 -05:00
end
2014-12-26 16:07:32 -05:00
# Deletes the download for the currently active {SoftwareSpec}.
2014-02-21 00:41:07 -05:00
def clear_cache
2014-02-21 00:41:07 -05:00
active_spec.clear_cache
2014-02-21 00:41:07 -05:00
end
# The list of patches for the currently active {SoftwareSpec}.
2014-03-13 19:51:23 -05:00
def patchlist
active_spec.patches
end
# The options for the currently active {SoftwareSpec}.
def options
active_spec.options
end
# The deprecated options for the currently active {SoftwareSpec}.
def deprecated_options
active_spec.deprecated_options
end
2014-12-27 14:26:56 -05:00
def deprecated_flags
active_spec.deprecated_flags
end
# If a named option is defined for the currently active {SoftwareSpec}.
2014-07-31 19:37:39 -05:00
def option_defined?(name)
active_spec.option_defined?(name)
end
# All the {.fails_with} for the currently active {SoftwareSpec}.
def compiler_failures
active_spec.compiler_failures
end
# If this {Formula} is installed.
# This is actually just a check for if the {#installed_prefix} directory
# exists and is not empty.
def installed?
(dir = installed_prefix).directory? && dir.children.length > 0
end
# If at least one version of {Formula} is installed.
def any_version_installed?
require "tab"
rack.directory? && rack.subdirs.any? { |keg| (keg/Tab::FILENAME).file? }
end
# @private
# The `LinkedKegs` directory for this {Formula}.
2015-01-04 14:25:59 -05:00
# You probably want {#opt_prefix} instead.
def linked_keg
2013-04-15 15:00:57 -05:00
Pathname.new("#{HOMEBREW_LIBRARY}/LinkedKegs/#{name}")
end
2015-01-04 14:25:59 -05:00
# The latest prefix for this formula. Checks for {#head}, then {#devel}
# and then {#stable}'s {#prefix}
def installed_prefix
if head && (head_prefix = prefix(PkgVersion.new(head.version, revision))).directory?
head_prefix
elsif devel && (devel_prefix = prefix(PkgVersion.new(devel.version, revision))).directory?
2012-04-05 21:09:24 -05:00
devel_prefix
elsif stable && (stable_prefix = prefix(PkgVersion.new(stable.version, revision))).directory?
stable_prefix
else
prefix
end
end
# The currently installed version for this formula. Will raise an exception
# if the formula is not installed.
def installed_version
require "keg"
Keg.new(installed_prefix).version
end
2014-03-05 20:51:37 -08:00
# The directory in the cellar that the formula is installed to.
# This directory contains the formula's name and version.
def prefix(v = pkg_version)
Pathname.new("#{HOMEBREW_CELLAR}/#{name}/#{v}")
end
2014-03-05 20:51:37 -08:00
# The parent of the prefix; the named directory in the cellar containing all
# installed versions of this software
def rack
prefix.parent
end
# 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.
def bin
prefix+"bin"
end
# 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.
def doc
share+"doc"+name
end
# 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.
def include
prefix+"include"
end
# 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.
def info
share+"info"
end
# 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.
def lib
prefix+"lib"
end
# The directory where the formula's binaries should be installed.
# This is not symlinked into `HOMEBREW_PREFIX`.
# It is also commonly used to install files that we do not wish to be
# symlinked into HOMEBREW_PREFIX from one of the other directories and
# instead manually create symlinks or wrapper scripts into e.g. {#bin}.
def libexec
prefix+"libexec"
end
# 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.
# Often one of the more specific `man` functions should be used instead
# e.g. {#man1}
def man
share+"man"
end
# 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.
def man1
man+"man1"
end
# 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.
def man2
man+"man2"
end
# 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.
def man3
man+"man3"
end
# 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.
def man4
man+"man4"
end
# 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.
def man5
man+"man5"
end
# 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.
def man6
man+"man6"
end
# 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.
def man7
man+"man7"
end
# 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.
def man8
man+"man8"
end
# 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.
def sbin
prefix+"sbin"
end
# 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.
def share
prefix+"share"
end
# 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.
def pkgshare
prefix+"share"+name
end
# 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`.
def frameworks
prefix+"Frameworks"
end
# 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`.
def kext_prefix
prefix+"Library/Extensions"
end
# 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`.
# This directory is not inside the `HOMEBREW_CELLAR` so it is persisted
# across upgrades.
def etc
(HOMEBREW_PREFIX+"etc").extend(InstallRenamed)
end
# The directory where the formula's variable files should be installed.
# This directory is not inside the `HOMEBREW_CELLAR` so it is persisted
# across upgrades.
def var
HOMEBREW_PREFIX+"var"
end
# 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.
def bash_completion
prefix+"etc/bash_completion.d"
end
# The directory where the formula's ZSH completion files should be
# installed.
# This is symlinked into `HOMEBREW_PREFIX` after installation or with
# `brew link` for formulae that are not keg-only.
def zsh_completion
share+"zsh/site-functions"
end
# 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.
def fish_completion
share+"fish/vendor_completions.d"
end
# 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.
def bottle_prefix
prefix+".bottle"
end
2013-10-05 20:29:19 +01:00
2015-04-25 22:07:06 -04:00
def logs
HOMEBREW_LOGS+name
end
2012-09-08 12:18:52 -07:00
# override this to provide a plist
def plist
nil
end
alias_method :startup_plist, :plist
# plist name, i.e. the name of the launchd service
def plist_name
"homebrew.mxcl."+name
end
def plist_path
prefix+(plist_name+".plist")
end
def plist_manual
self.class.plist_manual
end
def plist_startup
self.class.plist_startup
end
2014-03-05 20:51:37 -08:00
# A stable path for this formula, when installed. Contains the formula name
# but no version number. Only the active version will be linked here if
# multiple versions are installed.
#
# This is the prefered way to refer a formula in plists or from another
# formula, as the path is stable even when the software is updated.
2013-04-15 15:00:57 -05:00
def opt_prefix
Pathname.new("#{HOMEBREW_PREFIX}/opt/#{name}")
end
def opt_bin
opt_prefix+"bin"
end
def opt_include
opt_prefix+"include"
end
def opt_lib
opt_prefix+"lib"
end
def opt_libexec
opt_prefix+"libexec"
end
def opt_sbin
opt_prefix+"sbin"
end
def opt_share
opt_prefix+"share"
end
def opt_pkgshare
opt_prefix+"share"+name
end
def opt_frameworks
opt_prefix+"Frameworks"
end
2014-03-05 21:01:24 -08: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.
def pour_bottle?
true
end
# Can be overridden to run commands on both source and bottle installation.
def post_install; end
def post_install_defined?
method(:post_install).owner == self.class
end
# @private
def run_post_install
build, self.build = self.build, Tab.for_formula(self)
post_install
ensure
self.build = build
end
# tell the user about any caveats regarding this package, return a string
def caveats
nil
end
# rarely, you don't want your library symlinked into the main prefix
# see gettext.rb for an example
2010-07-18 10:38:45 -07:00
def keg_only?
keg_only_reason && keg_only_reason.valid?
end
def keg_only_reason
self.class.keg_only_reason
2010-07-18 10:38:45 -07:00
end
2014-02-23 12:21:43 -08:00
# sometimes the formula cleaner breaks things
# skip cleaning paths in a formula with a class method like this:
# skip_clean "bin/foo", "lib/bar"
2014-02-23 12:21:43 -08:00
# keep .la files with:
2014-02-23 12:09:28 -08:00
# skip_clean :la
def skip_clean?(path)
return true if path.extname == ".la" && self.class.skip_clean_paths.include?(:la)
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
end
def skip_cxxstdlib_check?
false
end
def require_universal_deps?
false
end
def patch
unless patchlist.empty?
ohai "Patching"
patchlist.each(&:apply)
end
end
# yields self with current working directory set to the uncompressed tarball
# @private
def brew
stage do
prepare_patches
begin
yield self
ensure
2015-04-25 22:07:06 -04:00
cp Dir["config.log", "CMakeCache.txt"], logs
end
end
end
def lock
2013-02-09 18:19:50 -06:00
@lock = FormulaLock.new(name)
@lock.lock
end
def unlock
2013-02-09 18:19:50 -06:00
@lock.unlock unless @lock.nil?
end
def pinnable?
@pin.pinnable?
end
def pinned?
@pin.pinned?
end
def pin
@pin.pin
end
def unpin
@pin.unpin
end
def ==(other)
instance_of?(other.class) &&
name == other.name &&
active_spec == other.active_spec
end
alias_method :eql?, :==
def hash
name.hash
end
def <=>(other)
return unless Formula === other
name <=> other.name
end
def to_s
name
end
2014-07-01 15:13:29 -05:00
def inspect
2015-07-28 15:10:40 +08:00
"#<Formula #{name} (#{active_spec_sym}) #{path}>"
end
def file_modified?
return false unless which("git")
path.parent.cd do
diff = Utils.popen_read("git", "diff", "origin/master", "--", "#{path}")
!diff.empty? && $?.exitstatus == 0
end
end
2010-09-22 08:05:58 -07:00
# Standard parameters for CMake builds.
# Setting CMAKE_FIND_FRAMEWORK to "LAST" tells CMake to search for our
# libraries before trying to utilize Frameworks, many of which will be from
# 3rd party installs.
2010-09-22 08:05:58 -07:00
# Note: there isn't a std_autotools variant because autotools is a lot
# less consistent and the standard parameters are more memorable.
def std_cmake_args
%W[
-DCMAKE_C_FLAGS_RELEASE=
-DCMAKE_CXX_FLAGS_RELEASE=
-DCMAKE_INSTALL_PREFIX=#{prefix}
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_FIND_FRAMEWORK=LAST
-DCMAKE_VERBOSE_MAKEFILE=ON
-Wno-dev
]
end
# an array of all core {Formula} names
def self.core_names
@core_names ||= Dir["#{HOMEBREW_LIBRARY}/Formula/*.rb"].map { |f| File.basename f, ".rb" }.sort
end
# an array of all core {Formula} files
def self.core_files
@core_files ||= Pathname.glob("#{HOMEBREW_LIBRARY}/Formula/*.rb")
end
# an array of all tap {Formula} names
def self.tap_names
2015-08-06 17:12:35 +08:00
@tap_names ||= Tap.flat_map(&:formula_names).sort
end
# an array of all tap {Formula} files
def self.tap_files
2015-08-06 17:12:35 +08:00
@tap_files ||= Tap.flat_map(&:formula_files)
end
# an array of all {Formula} names
def self.names
@names ||= (core_names + tap_names.map { |name| name.split("/")[-1] }).sort.uniq
end
# an array of all {Formula} files
def self.files
@files ||= core_files + tap_files
end
# an array of all {Formula} names, which the tap formulae have the fully-qualified name
def self.full_names
@full_names ||= core_names + tap_names
end
def self.each
files.each do |file|
2013-04-14 23:29:15 -05:00
begin
yield Formulary.factory(file)
rescue StandardError => e
# Don't let one broken formula break commands. But do complain.
onoe "Failed to import: #{file}"
puts e
next
2010-07-18 14:07:40 -07:00
end
end
end
2012-08-10 16:05:30 -04:00
# An array of all installed {Formula}
2012-08-10 16:05:30 -04:00
def self.installed
@installed ||= if HOMEBREW_CELLAR.directory?
HOMEBREW_CELLAR.subdirs.map do |rack|
begin
Formulary.from_rack(rack)
rescue FormulaUnavailableError, TapFormulaAmbiguityError
end
end.compact
else
[]
end
2012-08-10 16:05:30 -04:00
end
def self.aliases
Dir["#{HOMEBREW_LIBRARY}/Aliases/*"].map { |f| File.basename f }.sort
end
def self.[](name)
Formulary.factory(name)
end
2013-10-29 15:46:10 -04:00
def tap?
2014-04-06 00:31:07 -05:00
HOMEBREW_TAP_DIR_REGEX === path
2013-10-29 15:46:10 -04:00
end
def tap
2014-04-06 00:31:07 -05:00
if path.to_s =~ HOMEBREW_TAP_DIR_REGEX
"#{$1}/#{$2}"
elsif core_formula?
2013-12-14 18:15:59 +00:00
"Homebrew/homebrew"
end
end
def print_tap_action(options = {})
if tap?
verb = options[:verb] || "Installing"
ohai "#{verb} #{name} from #{tap}"
end
end
# True if this formula is provided by Homebrew itself
def core_formula?
path == Formulary.core_path(name)
end
def env
2014-07-07 21:32:35 -05:00
self.class.env
end
def conflicts
self.class.conflicts
end
# 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
def recursive_dependencies(&block)
Dependency.expand(self, &block)
end
# The full set of Requirements for this formula's dependency tree.
def recursive_requirements(&block)
Requirement.expand(self, &block)
end
def to_hash
hsh = {
"name" => name,
2015-05-27 20:30:43 +08:00
"full_name" => full_name,
2015-05-19 13:06:06 -04:00
"desc" => desc,
"homepage" => homepage,
"oldname" => oldname,
"versions" => {
"stable" => (stable.version.to_s if stable),
"bottle" => bottle ? true : false,
"devel" => (devel.version.to_s if devel),
"head" => (head.version.to_s if head)
},
"revision" => revision,
"installed" => [],
"linked_keg" => (linked_keg.resolved_path.basename.to_s if linked_keg.exist?),
"keg_only" => keg_only?,
"dependencies" => deps.map(&:name).uniq,
"conflicts_with" => conflicts.map(&:name),
"caveats" => caveats
}
hsh["requirements"] = requirements.map do |req|
{
"name" => req.name,
"default_formula" => req.default_formula,
"cask" => req.cask,
"download" => req.download
}
end
hsh["options"] = options.map do |opt|
2014-03-28 20:42:55 -05:00
{ "option" => opt.flag, "description" => opt.description }
end
if rack.directory?
rack.subdirs.each do |keg_path|
keg = Keg.new keg_path
tab = Tab.for_keg keg_path
hsh["installed"] << {
"version" => keg.version.to_s,
2014-08-14 01:00:23 -05:00
"used_options" => tab.used_options.as_flags,
"built_as_bottle" => tab.built_bottle,
"poured_from_bottle" => tab.poured_from_bottle
}
end
hsh["installed"] = hsh["installed"].sort_by { |i| Version.new(i["version"]) }
end
hsh
end
def fetch
active_spec.fetch
end
def verify_download_integrity(fn)
active_spec.verify_download_integrity(fn)
end
2014-09-18 14:16:07 -05:00
def run_test
old_home = ENV["HOME"]
build, self.build = self.build, Tab.for_formula(self)
mktemp do
@testpath = Pathname.pwd
ENV["HOME"] = @testpath
setup_test_home @testpath
2014-09-18 14:16:07 -05:00
test
end
2014-09-18 14:16:07 -05:00
ensure
@testpath = nil
self.build = build
ENV["HOME"] = old_home
end
def test_defined?
false
end
2014-09-18 14:16:07 -05:00
def test
end
def test_fixtures(file)
HOMEBREW_LIBRARY.join("Homebrew", "test", "fixtures", file)
end
def install
end
protected
def setup_test_home(home)
# keep Homebrew's site-packages in sys.path when testing with system Python
user_site_packages = home/"Library/Python/2.7/lib/python/site-packages"
user_site_packages.mkpath
(user_site_packages/"homebrew.pth").write <<-EOS.undent
import site; site.addsitedir("#{HOMEBREW_PREFIX}/lib/python2.7/site-packages")
import sys; sys.path.insert(0, "#{HOMEBREW_PREFIX}/lib/python2.7/site-packages")
EOS
end
# Pretty titles the command and buffers stdout/stderr
# Throws if there's an error
def system(cmd, *args)
verbose = ARGV.verbose?
# 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
if cmd == "./configure" && !verbose
pretty_args.delete "--disable-dependency-tracking"
pretty_args.delete "--disable-debug"
end
pretty_args.each_index do |i|
if pretty_args[i].to_s.start_with? "import setuptools"
pretty_args[i] = "import setuptools..."
end
end
ohai "#{cmd} #{pretty_args*" "}".strip
@exec_count ||= 0
@exec_count += 1
logfn = "#{logs}/%02d.%s" % [@exec_count, File.basename(cmd).split(" ").first]
2015-04-25 22:07:06 -04:00
logs.mkpath
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:36:08 -05:00
if verbose
rd, wr = IO.pipe
begin
pid = fork do
rd.close
log.close
exec_cmd(cmd, args, wr, logfn)
end
wr.close
while buf = rd.gets
log.puts buf
puts buf
end
ensure
rd.close
end
2014-09-05 15:36:08 -05:00
else
pid = fork { exec_cmd(cmd, args, log, logfn) }
end
2014-09-05 15:36:08 -05:00
Process.wait(pid)
2014-09-05 15:36:08 -05:00
$stdout.flush
2014-09-05 15:36:08 -05:00
unless $?.success?
log.flush
Kernel.system "/usr/bin/tail", "-n", "5", logfn unless verbose
log.puts
2014-12-30 23:47:07 -05:00
require "cmd/config"
require "cmd/--env"
env = ENV.to_hash
2014-12-30 23:33:50 -05:00
Homebrew.dump_verbose_config(log)
2014-12-30 23:47:07 -05:00
log.puts
Homebrew.dump_build_env(env, log)
raise BuildError.new(self, cmd, args, env)
2014-09-05 15:36:08 -05:00
end
end
end
private
def exec_cmd(cmd, args, out, logfn)
ENV["HOMEBREW_CC_LOG_PATH"] = logfn
# TODO: system "xcodebuild" is deprecated, this should be removed soon.
if cmd.to_s.start_with? "xcodebuild"
ENV.remove_cc_etc
end
# 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.
if cmd == "python"
setup_py_in_args = %w[setup.py build.py].include?(args.first)
setuptools_shim_in_args = args.any? { |a| a.to_s.start_with? "import setuptools" }
if setup_py_in_args || setuptools_shim_in_args
ENV.refurbish_args
end
end
$stdout.reopen(out)
$stderr.reopen(out)
out.close
args.collect!(&:to_s)
exec(cmd, *args) rescue nil
puts "Failed to execute: #{cmd}"
exit! 1 # never gets here unless exec threw or failed
end
def stage
active_spec.stage do
2012-02-24 12:50:21 -08:00
@buildpath = Pathname.pwd
env_home = buildpath/".brew_home"
mkdir_p env_home
old_home, ENV["HOME"] = ENV["HOME"], env_home
begin
yield
ensure
@buildpath = nil
ENV["HOME"] = old_home
end
end
end
def prepare_patches
active_spec.add_legacy_patches(patches) if respond_to?(:patches)
2015-01-22 17:03:54 -05:00
patchlist.grep(DATAPatch) { |p| p.path = path }
2015-01-22 17:03:54 -05:00
patchlist.select(&:external?).each do |patch|
patch.verify_download_integrity(patch.fetch)
end
end
def self.method_added(method)
2013-01-07 17:34:56 -06:00
case method
when :brew
2013-06-06 16:36:12 -07:00
raise "You cannot override Formula#brew in class #{name}"
2013-01-07 17:34:56 -06:00
when :test
define_method(:test_defined?) { true }
when :options
instance = allocate
specs.each do |spec|
instance.options.each do |opt, desc|
spec.option(opt[/^--(.+)$/, 1], desc)
end
end
remove_method(:options)
2013-01-07 17:34:56 -06:00
end
2009-07-31 14:17:56 +01:00
end
# The methods below define the formula DSL.
class << self
2014-06-22 15:00:15 -05:00
include BuildEnvironmentDSL
# The reason for why this software is not linked (by default) to
# {::HOMEBREW_PREFIX}.
# @private
attr_reader :keg_only_reason
2015-05-19 13:06:06 -04:00
# @!attribute [w]
# 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`.
attr_rw :desc
# @!attribute [w]
# 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.
# Can be opened with running `brew home`.
attr_rw :homepage
# The `:startup` attribute set by {.plist_options}.
# @private
attr_reader :plist_startup
# The `:manual` attribute set by {.plist_options}.
# @private
attr_reader :plist_manual
# @!attribute [w]
# Used for creating new Homebrew versions of software without new upstream
# versions. For example, if we bump the major version of a library this
# {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.
attr_rw :revision
# A list of the {.stable}, {.devel} and {.head} {SoftwareSpec}s.
# @private
2013-09-17 21:25:39 -05:00
def specs
@specs ||= [stable, devel, head].freeze
2013-09-17 21:25:39 -05:00
end
# @!attribute [w] url
# The URL used to download the source for the {#stable} version of the formula.
# We prefer `https` for security and proxy reasons.
def url(val, specs = {})
stable.url(val, specs)
end
# @!attribute [w] version
# The version string for the {#stable} version of the formula.
# The version is autodetected from the URL and/or tag so only needs to be
# declared if it cannot be autodetected correctly.
def version(val = nil)
stable.version(val)
end
# @!attribute [w] mirror
# Additional URLs for the {#stable} version of the formula.
# 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}.
def mirror(val)
stable.mirror(val)
end
# @!attribute [w] sha1
# @scope class
# To verify the {#cached_download}'s integrity and security we verify the
# SHA-1 hash matches what we've declared in the {Formula}. To quickly fill
# this value you can leave it blank and run `brew fetch --force` and it'll
# tell you the currently valid value.
# @!attribute [w] sha256
# @scope class
# Similar to {.sha1} but using a SHA-256 hash instead.
Checksum::TYPES.each do |type|
define_method(type) { |val| stable.send(type, val) }
end
def bottle(*, &block)
stable.bottle(&block)
end
def build
stable.build
end
def stable(&block)
@stable ||= SoftwareSpec.new
2012-04-05 21:09:24 -05:00
return @stable unless block_given?
@stable.instance_eval(&block)
end
def devel(&block)
@devel ||= SoftwareSpec.new
2012-04-05 21:09:24 -05:00
return @devel unless block_given?
@devel.instance_eval(&block)
end
def head(val = nil, specs = {}, &block)
@head ||= HeadSoftwareSpec.new
2013-09-13 11:13:12 -05:00
if block_given?
@head.instance_eval(&block)
elsif val
@head.url(val, specs)
else
@head
end
2012-04-05 21:09:24 -05:00
end
# Define a named resource using a {SoftwareSpec} style block
def resource(name, klass = Resource, &block)
specs.each do |spec|
spec.resource(name, klass, &block) unless spec.resource_defined?(name)
end
end
def go_resource(name, &block)
specs.each { |spec| spec.go_resource(name, &block) }
end
def depends_on(dep)
2013-09-21 19:27:24 -05:00
specs.each { |spec| spec.depends_on(dep) }
end
def option(name, description = "")
2013-09-21 19:27:24 -05:00
specs.each { |spec| spec.option(name, description) }
end
def deprecated_option(hash)
specs.each { |spec| spec.deprecated_option(hash) }
end
def patch(strip = :p1, src = nil, &block)
specs.each { |spec| spec.patch(strip, src, &block) }
end
def plist_options(options)
@plist_startup = options[:startup]
@plist_manual = options[:manual]
end
def conflicts
@conflicts ||= []
end
def conflicts_with(*names)
opts = Hash === names.last ? names.pop : {}
names.each { |name| conflicts << FormulaConflict.new(name, opts[:because]) }
end
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
skip_clean_paths.merge(paths)
end
def skip_clean_paths
2013-06-20 16:25:58 -05:00
@skip_clean_paths ||= Set.new
end
def keg_only(reason, explanation = "")
@keg_only_reason = KegOnlyReason.new(reason, explanation)
2010-07-18 10:38:45 -07:00
end
# Pass :skip to this method to disable post-install stdlib checking
def cxxstdlib_check(check_type)
define_method(:skip_cxxstdlib_check?) { true } if check_type == :skip
end
# For Apple compilers, this should be in the format:
# fails_with compiler do
# cause "An explanation for why the build doesn't work."
# build "The Apple build number for the newest incompatible release."
# end
#
# The block may be omitted, and if present the build may be omitted;
# if so, then the compiler will be blacklisted for *all* versions.
#
# For GNU GCC compilers, this should be in the format:
# fails_with compiler => major_version do
# cause
# version "The official release number for the latest incompatible
# version, for instance 4.8.1"
# end
2014-01-04 12:49:48 +00:00
#
# `major_version` should be the major release number only, for instance
# '4.8' for the GCC 4.8 series (4.8.0, 4.8.1, etc.).
# If `version` or the block is omitted, then the compiler will be
# blacklisted for all compilers in that series.
#
# For example, if a bug is only triggered on GCC 4.8.1 but is not
# encountered on 4.8.2:
2014-01-04 12:49:48 +00:00
#
# fails_with :gcc => '4.8' do
# version '4.8.1'
# end
def fails_with(compiler, &block)
specs.each { |spec| spec.fails_with(compiler, &block) }
end
def needs(*standards)
specs.each { |spec| spec.needs(*standards) }
end
def test(&block)
2014-09-18 14:16:07 -05:00
define_method(:test, &block)
end
end
end