2023-03-02 18:21:53 -08:00
# typed: true
2019-04-19 15:38:03 +09:00
# frozen_string_literal: true
2018-07-16 23:17:16 +02:00
require " shellwords "
2019-06-28 14:50:38 +08:00
require " utils "
2018-07-16 23:17:16 +02:00
2020-08-14 05:28:26 +02:00
# Raised when a command is used wrong.
2024-04-22 21:05:48 +02:00
#
# @api internal
2016-04-19 08:11:17 +02:00
class UsageError < RuntimeError
attr_reader :reason
def initialize ( reason = nil )
2020-08-19 17:12:32 +01:00
super
2016-04-19 08:11:17 +02:00
@reason = reason
end
2020-10-20 12:03:48 +02:00
sig { returns ( String ) }
2016-04-19 08:11:17 +02:00
def to_s
s = " Invalid usage "
s += " : #{ reason } " if reason
s
end
end
2020-08-14 05:28:26 +02:00
# Raised when a command expects a formula and none was specified.
2016-04-19 08:11:17 +02:00
class FormulaUnspecifiedError < UsageError
def initialize
2020-03-04 19:26:09 +00:00
super " this command requires a formula argument "
2016-04-19 08:11:17 +02:00
end
end
2020-10-08 11:12:17 +02:00
# Raised when a command expects a formula or cask and none was specified.
class FormulaOrCaskUnspecifiedError < UsageError
def initialize
super " this command requires a formula or cask argument "
end
end
2020-08-14 05:28:26 +02:00
# Raised when a command expects a keg and none was specified.
2016-04-19 08:11:17 +02:00
class KegUnspecifiedError < UsageError
def initialize
2020-03-04 19:26:09 +00:00
super " this command requires a keg argument "
2016-04-19 08:11:17 +02:00
end
end
2010-09-11 20:22:54 +01:00
2021-12-02 15:53:09 +00:00
class UnsupportedInstallationMethod < RuntimeError ; end
2020-07-03 18:24:52 -04:00
class MultipleVersionsInstalledError < RuntimeError ; end
2010-11-12 20:59:53 -08:00
2024-04-23 19:10:33 +02:00
# Raised when a path is not a keg.
#
# @api internal
2010-11-12 20:59:53 -08:00
class NotAKegError < RuntimeError ; end
2020-08-14 05:28:26 +02:00
# Raised when a keg doesn't exist.
2011-03-12 23:06:45 -08:00
class NoSuchKegError < RuntimeError
2013-02-17 22:52:39 -06:00
attr_reader :name
2010-11-12 20:59:53 -08:00
2015-08-03 13:09:07 +01:00
def initialize ( name )
2010-11-12 20:59:53 -08:00
@name = name
super " No such keg: #{ HOMEBREW_CELLAR } / #{ name } "
end
2010-09-11 20:22:54 +01:00
end
2020-08-14 05:28:26 +02:00
# Raised when an invalid attribute is used in a formula.
2013-04-13 17:40:12 -05:00
class FormulaValidationError < StandardError
2015-10-14 14:42:34 +02:00
attr_reader :attr , :formula
2013-04-13 17:40:12 -05:00
2015-10-14 14:42:34 +02:00
def initialize ( formula , attr , value )
2013-04-13 17:40:12 -05:00
@attr = attr
2015-10-14 14:42:34 +02:00
@formula = formula
super " invalid attribute for formula ' #{ formula } ': #{ attr } ( #{ value . inspect } ) "
2013-04-13 17:40:12 -05:00
end
end
2013-08-06 21:48:05 -07:00
class FormulaSpecificationError < StandardError ; end
2013-04-27 14:44:48 -05:00
2020-08-14 05:28:26 +02:00
# Raised when a deprecated method is used.
2016-12-10 13:04:14 +00:00
class MethodDeprecatedError < StandardError
attr_accessor :issues_url
end
2016-07-29 14:59:09 -06:00
2020-09-25 21:13:26 +02:00
# Raised when neither a formula nor a cask with the given name is available.
class FormulaOrCaskUnavailableError < RuntimeError
2013-02-17 22:52:39 -06:00
attr_reader :name
2012-03-16 11:55:30 +00:00
2015-08-03 13:09:07 +01:00
def initialize ( name )
2020-09-25 21:13:26 +02:00
super ( )
2020-08-19 17:12:32 +01:00
2014-02-28 15:58:20 -06:00
@name = name
2023-06-19 03:57:52 +01:00
# Store the state of these envs at the time the exception is thrown.
# This is so we do the fuzzy search for "did you mean" etc under that same mode,
# in case the list of formulae are different.
@without_api = Homebrew :: EnvConfig . no_install_from_api?
@auto_without_api = Homebrew :: EnvConfig . automatically_set_no_install_from_api?
2014-02-28 15:58:20 -06:00
end
2021-06-19 00:18:51 +01:00
sig { returns ( String ) }
def did_you_mean
2022-06-02 05:54:42 +01:00
require " formula "
2023-06-19 03:57:52 +01:00
similar_formula_names = Homebrew . with_no_api_env_if_needed ( @without_api ) { Formula . fuzzy_search ( name ) }
2021-06-19 00:18:51 +01:00
return " " if similar_formula_names . blank?
" Did you mean #{ similar_formula_names . to_sentence two_words_connector : " or " , last_word_connector : " or " } ? "
end
2020-10-20 12:03:48 +02:00
sig { returns ( String ) }
2020-09-25 21:13:26 +02:00
def to_s
2023-06-19 03:57:52 +01:00
s = " No available formula or cask with the name \" #{ name } \" . #{ did_you_mean } " . strip
if @auto_without_api && ! CoreTap . instance . installed?
s += " \n A full git tap clone is required to use this command on core packages. "
end
s
2020-09-25 21:13:26 +02:00
end
end
2021-03-11 21:09:42 +05:30
# Raised when a formula or cask in a specific tap is not available.
class TapFormulaOrCaskUnavailableError < FormulaOrCaskUnavailableError
attr_reader :tap
def initialize ( tap , name )
super " #{ tap } / #{ name } "
@tap = tap
end
sig { returns ( String ) }
def to_s
s = super
s += " \n Please tap it and then try again: brew tap #{ tap } " unless tap . installed?
s
end
end
2020-09-25 21:13:26 +02:00
# Raised when a formula is not available.
2024-04-22 21:05:48 +02:00
#
# @api internal
2020-09-25 21:13:26 +02:00
class FormulaUnavailableError < FormulaOrCaskUnavailableError
attr_accessor :dependent
2020-10-20 12:03:48 +02:00
sig { returns ( T . nilable ( String ) ) }
2012-03-16 11:55:30 +00:00
def dependent_s
2020-10-20 12:03:48 +02:00
" (dependency of #{ dependent } ) " if dependent && dependent != name
2012-03-16 11:55:30 +00:00
end
2020-10-20 12:03:48 +02:00
sig { returns ( String ) }
2012-03-16 11:55:30 +00:00
def to_s
2021-06-19 00:18:51 +01:00
" No available formula with the name \" #{ name } \" #{ dependent_s } . #{ did_you_mean } " . strip
2012-03-16 11:55:30 +00:00
end
2014-02-28 15:58:20 -06:00
end
2020-08-14 05:28:26 +02:00
# Shared methods for formula class errors.
2017-04-18 08:43:39 +01:00
module FormulaClassUnavailableErrorModule
2020-07-07 11:29:33 +01:00
attr_reader :path , :class_name , :class_list
2016-04-16 20:57:03 +02:00
2024-04-26 14:04:55 +02:00
sig { returns ( String ) }
2016-04-16 20:57:03 +02:00
def to_s
s = super
s += " \n In formula file: #{ path } "
s += " \n Expected to find class #{ class_name } , but #{ class_list_s } . "
s
end
private
2020-10-20 12:03:48 +02:00
sig { returns ( String ) }
2016-04-16 20:57:03 +02:00
def class_list_s
formula_class_list = class_list . select { | klass | klass < Formula }
if class_list . empty?
" found no classes "
elsif formula_class_list . empty?
" only found: #{ format_list ( class_list ) } (not derived from Formula!) "
else
" only found: #{ format_list ( formula_class_list ) } "
end
end
def format_list ( class_list )
2018-09-17 19:44:12 +02:00
class_list . map { | klass | klass . name . split ( " :: " ) . last } . join ( " , " )
2016-04-16 20:57:03 +02:00
end
end
2020-08-14 05:28:26 +02:00
# Raised when a formula does not contain a formula class.
2017-04-18 08:43:39 +01:00
class FormulaClassUnavailableError < FormulaUnavailableError
include FormulaClassUnavailableErrorModule
def initialize ( name , path , class_name , class_list )
@path = path
@class_name = class_name
@class_list = class_list
super name
end
end
2020-08-14 05:28:26 +02:00
# Shared methods for formula unreadable errors.
2017-04-18 08:43:39 +01:00
module FormulaUnreadableErrorModule
2017-02-01 18:30:55 +00:00
attr_reader :formula_error
2020-10-20 12:03:48 +02:00
sig { returns ( String ) }
2017-04-18 08:43:39 +01:00
def to_s
" #{ name } : " + formula_error . to_s
end
end
2020-08-14 05:28:26 +02:00
# Raised when a formula is unreadable.
2017-04-18 08:43:39 +01:00
class FormulaUnreadableError < FormulaUnavailableError
include FormulaUnreadableErrorModule
2017-02-01 18:30:55 +00:00
def initialize ( name , error )
super ( name )
@formula_error = error
2021-09-17 00:06:42 +01:00
set_backtrace ( error . backtrace )
2017-02-01 18:30:55 +00:00
end
2017-04-18 08:43:39 +01:00
end
2020-08-14 05:28:26 +02:00
# Raised when a formula in a specific tap is unavailable.
2017-04-18 08:43:39 +01:00
class TapFormulaUnavailableError < FormulaUnavailableError
attr_reader :tap , :user , :repo
def initialize ( tap , name )
@tap = tap
@user = tap . user
@repo = tap . repo
super " #{ tap } / #{ name } "
end
2017-02-01 18:30:55 +00:00
2024-04-26 14:04:55 +02:00
sig { returns ( String ) }
2017-02-01 18:30:55 +00:00
def to_s
2017-04-18 08:43:39 +01:00
s = super
s += " \n Please tap it and then try again: brew tap #{ tap } " unless tap . installed?
s
end
end
2020-08-14 05:28:26 +02:00
# Raised when a formula in a specific tap does not contain a formula class.
2017-04-18 08:43:39 +01:00
class TapFormulaClassUnavailableError < TapFormulaUnavailableError
include FormulaClassUnavailableErrorModule
attr_reader :tap
def initialize ( tap , name , path , class_name , class_list )
@path = path
@class_name = class_name
@class_list = class_list
super tap , name
end
end
2020-08-14 05:28:26 +02:00
# Raised when a formula in a specific tap is unreadable.
2017-04-18 08:43:39 +01:00
class TapFormulaUnreadableError < TapFormulaUnavailableError
include FormulaUnreadableErrorModule
def initialize ( tap , name , error )
super ( tap , name )
@formula_error = error
2021-09-17 00:06:42 +01:00
set_backtrace ( error . backtrace )
2017-02-01 18:30:55 +00:00
end
end
2020-11-05 17:17:03 -05:00
# Raised when a formula with the same name is found in multiple taps.
2015-05-08 19:16:06 +08:00
class TapFormulaAmbiguityError < RuntimeError
2024-02-16 21:27:02 +01:00
attr_reader :name , :taps , :loaders
2015-05-08 19:16:06 +08:00
2024-02-16 21:27:02 +01:00
def initialize ( name , loaders )
2015-05-08 19:16:06 +08:00
@name = name
2024-02-16 21:27:02 +01:00
@loaders = loaders
@taps = loaders . map ( & :tap )
2024-02-08 12:14:26 +01:00
2024-02-16 21:27:02 +01:00
formulae = taps . map { | tap | " #{ tap } / #{ name } " }
formula_list = formulae . map { | f | " \n * #{ f } " } . join
2015-05-08 19:16:06 +08:00
2017-10-15 02:28:32 +02:00
super << ~ EOS
2024-02-16 21:27:02 +01:00
Formulae found in multiple taps : #{formula_list}
2015-05-08 19:16:06 +08:00
2024-02-16 21:27:02 +01:00
Please use the fully - qualified name ( e . g . #{formulae.first}) to refer to a specific formula.
2015-05-08 19:16:06 +08:00
EOS
end
end
2020-08-14 05:28:26 +02:00
# Raised when a tap is unavailable.
2015-06-13 14:32:10 +08:00
class TapUnavailableError < RuntimeError
attr_reader :name
2015-08-03 13:09:07 +01:00
def initialize ( name )
2015-06-13 14:32:10 +08:00
@name = name
2023-07-31 20:26:29 -04:00
message = " No available tap #{ name } . \n "
if [ CoreTap . instance . name , CoreCaskTap . instance . name ] . include? ( name )
command = " brew tap --force #{ name } "
message += << ~ EOS
Run #{Formatter.identifier(command)} to tap #{name}!
EOS
else
command = " brew tap-new #{ name } "
message += << ~ EOS
Run #{Formatter.identifier(command)} to create a new #{name} tap!
EOS
end
super message . freeze
2015-06-13 14:32:10 +08:00
end
end
2020-08-14 05:28:26 +02:00
# Raised when a tap's remote does not match the actual remote.
2016-04-04 03:18:55 -07:00
class TapRemoteMismatchError < RuntimeError
2020-07-07 11:29:33 +01:00
attr_reader :name , :expected_remote , :actual_remote
2016-04-04 03:18:55 -07:00
def initialize ( name , expected_remote , actual_remote )
@name = name
@expected_remote = expected_remote
@actual_remote = actual_remote
2021-10-11 17:00:43 +08:00
super message
end
def message
<< ~ EOS
2016-04-04 03:18:55 -07:00
Tap #{name} remote mismatch.
#{expected_remote} != #{actual_remote}
EOS
end
end
2023-02-10 23:15:40 -05:00
# Raised when the remote of homebrew/core does not match HOMEBREW_CORE_GIT_REMOTE.
2021-10-11 17:00:43 +08:00
class TapCoreRemoteMismatchError < TapRemoteMismatchError
def message
<< ~ EOS
2023-07-17 10:33:48 -04:00
Tap #{name} remote does not match HOMEBREW_CORE_GIT_REMOTE.
2021-10-11 17:00:43 +08:00
#{expected_remote} != #{actual_remote}
Please set HOMEBREW_CORE_GIT_REMOTE = " #{ actual_remote } " and run ` brew update ` instead .
EOS
end
end
2020-08-14 05:28:26 +02:00
# Raised when a tap is already installed.
2015-11-07 16:01:05 +08:00
class TapAlreadyTappedError < RuntimeError
attr_reader :name
def initialize ( name )
@name = name
2017-10-15 02:28:32 +02:00
super << ~ EOS
2015-11-07 16:01:05 +08:00
Tap #{name} already tapped.
EOS
end
end
2021-10-11 17:00:43 +08:00
# Raised when run `brew tap --custom-remote` without a remote URL.
class TapNoCustomRemoteError < RuntimeError
attr_reader :name
def initialize ( name )
@name = name
super << ~ EOS
Tap #{name} with option `--custom-remote` but without a remote URL.
EOS
end
end
2020-08-14 05:28:26 +02:00
# Raised when another Homebrew operation is already in progress.
2013-01-23 00:26:25 -06:00
class OperationInProgressError < RuntimeError
2015-08-03 13:09:07 +01:00
def initialize ( name )
2017-10-15 02:28:32 +02:00
message = << ~ EOS
2013-01-23 00:26:25 -06:00
Operation already in progress for #{name}
Another active Homebrew process is already using #{name}.
Please wait for it to finish or terminate it to continue .
2018-06-06 23:34:19 -04:00
EOS
2013-01-23 00:26:25 -06:00
super message
end
end
2013-08-06 21:48:05 -07:00
class CannotInstallFormulaError < RuntimeError ; end
2010-09-11 20:22:54 +01:00
2020-08-14 05:28:26 +02:00
# Raised when a formula installation was already attempted.
2014-09-14 01:10:20 -05:00
class FormulaInstallationAlreadyAttemptedError < RuntimeError
2014-09-12 21:28:25 -05:00
def initialize ( formula )
2015-05-27 22:16:48 +08:00
super " Formula installation already attempted: #{ formula . full_name } "
2010-09-11 20:22:54 +01:00
end
end
2020-08-14 05:28:26 +02:00
# Raised when there are unsatisfied requirements.
2014-09-14 01:10:20 -05:00
class UnsatisfiedRequirements < RuntimeError
def initialize ( reqs )
if reqs . length == 1
super " An unsatisfied requirement failed this build. "
else
2015-07-26 00:48:50 -04:00
super " Unsatisfied requirements failed this build. "
2014-09-14 01:10:20 -05:00
end
2010-09-11 20:22:54 +01:00
end
end
2020-08-14 05:28:26 +02:00
# Raised when a formula conflicts with another one.
2014-09-14 01:10:20 -05:00
class FormulaConflictError < RuntimeError
attr_reader :formula , :conflicts
2013-06-09 13:44:59 -05:00
2014-09-12 21:27:00 -05:00
def initialize ( formula , conflicts )
@formula = formula
2014-09-14 01:10:20 -05:00
@conflicts = conflicts
super message
2013-06-09 13:44:59 -05:00
end
def conflict_message ( conflict )
message = [ ]
message << " #{ conflict . name } "
message << " : because #{ conflict . reason } " if conflict . reason
message . join
end
2020-10-20 12:03:48 +02:00
sig { returns ( String ) }
2013-06-09 13:44:59 -05:00
def message
message = [ ]
2017-05-27 10:15:37 +01:00
message << " Cannot install #{ formula . full_name } because conflicting formulae are installed. "
2013-06-09 13:44:59 -05:00
message . concat conflicts . map { | c | conflict_message ( c ) } << " "
2017-10-15 02:28:32 +02:00
message << << ~ EOS
2017-06-01 16:06:51 +02:00
Please ` brew unlink #{ conflicts . map ( & :name ) * " " } ` before continuing .
2013-06-09 13:44:59 -05:00
Unlinking removes a formula ' s symlinks from #{HOMEBREW_PREFIX}. You can
2024-02-04 15:19:29 +01:00
link the formula again after the install finishes . You can ` --force ` this
2019-04-08 12:47:15 -04:00
install , but the build may fail or cause obscure side effects in the
2013-06-09 13:44:59 -05:00
resulting software .
2018-06-06 23:34:19 -04:00
EOS
2013-06-09 13:44:59 -05:00
message . join ( " \n " )
end
end
2020-08-14 05:28:26 +02:00
# Raise when the Python version cannot be detected automatically.
2020-07-09 15:43:05 +01:00
class FormulaUnknownPythonError < RuntimeError
def initialize ( formula )
super << ~ EOS
The version of Python to use with the virtualenv in the ` #{ formula . full_name } ` formula
cannot be guessed automatically because a recognised Python dependency could not be found .
2021-01-24 21:55:35 -05:00
If you are using a non - standard Python dependency , please add ` :using => "python@x.y" `
to 'virtualenv_install_with_resources' to resolve the issue manually .
2020-07-09 15:43:05 +01:00
EOS
end
end
2020-08-14 05:28:26 +02:00
# Raise when two Python versions are detected simultaneously.
2016-08-05 00:20:20 -07:00
class FormulaAmbiguousPythonError < RuntimeError
def initialize ( formula )
2017-10-15 02:28:32 +02:00
super << ~ EOS
2021-01-24 21:55:35 -05:00
The version of Python to use with the virtualenv in the ` #{ formula . full_name } ` formula
cannot be guessed automatically .
If the simultaneous use of multiple Pythons is intentional , please add ` :using => "python@x.y" `
to 'virtualenv_install_with_resources' to resolve the ambiguity manually .
2016-08-05 00:20:20 -07:00
EOS
end
end
2020-08-14 05:28:26 +02:00
# Raised when an error occurs during a formula build.
2014-09-14 01:10:20 -05:00
class BuildError < RuntimeError
2018-08-17 22:42:37 -04:00
attr_reader :cmd , :args , :env
attr_accessor :formula , :options
2010-09-11 20:22:54 +01:00
2022-08-11 09:35:02 +02:00
sig {
params (
formula : T . nilable ( Formula ) ,
cmd : T . any ( String , Pathname ) ,
2023-09-13 13:23:35 -04:00
args : T :: Array [ T . any ( String , Integer , Pathname , Symbol ) ] ,
2022-08-11 09:35:02 +02:00
env : T :: Hash [ String , T . untyped ] ,
) . void
}
2014-09-13 19:47:30 -05:00
def initialize ( formula , cmd , args , env )
2014-09-14 01:10:20 -05:00
@formula = formula
2018-08-17 22:42:37 -04:00
@cmd = cmd
@args = args
2014-09-13 19:47:30 -05:00
@env = env
2022-05-20 01:41:26 +01:00
pretty_args = Array ( args ) . map { | arg | arg . to_s . gsub ( / [ \\ ] / , " \\ \\ \\ 0 " ) } . join ( " " )
2018-11-07 11:58:05 +01:00
super " Failed executing: #{ cmd } #{ pretty_args } " . strip
2010-09-11 20:22:54 +01:00
end
2012-03-07 11:11:05 +00:00
2022-08-11 09:35:02 +02:00
sig { returns ( T :: Array [ T . untyped ] ) }
2012-10-31 11:26:45 -04:00
def issues
2014-02-08 16:04:53 -05:00
@issues || = fetch_issues
end
2022-08-11 09:35:02 +02:00
sig { returns ( T :: Array [ T . untyped ] ) }
2014-02-08 16:04:53 -05:00
def fetch_issues
2023-07-08 22:15:58 +01:00
GitHub . issues_for_formula ( formula . name , tap : formula . tap , state : " open " , type : " issue " )
2024-04-29 11:44:21 -07:00
rescue GitHub :: API :: Error = > e
opoo " Unable to query GitHub for recent issues on the tap \n #{ e . message } "
2014-02-08 16:04:53 -05:00
[ ]
2012-10-31 11:26:45 -04:00
end
2022-08-11 09:35:02 +02:00
sig { params ( verbose : T :: Boolean ) . void }
2020-08-02 02:52:24 +02:00
def dump ( verbose : false )
2016-11-05 15:39:25 -04:00
puts
2020-08-02 02:52:24 +02:00
if verbose
2016-05-08 21:41:51 +02:00
require " system_config "
2015-11-13 16:43:43 +01:00
require " build_environment "
2013-06-23 16:15:11 -07:00
2015-03-03 21:11:00 -05:00
ohai " Formula "
puts " Tap: #{ formula . tap } " if formula . tap?
puts " Path: #{ formula . path } "
2012-09-27 15:39:16 -04:00
ohai " Configuration "
2016-05-08 21:41:51 +02:00
SystemConfig . dump_verbose_config
2012-09-27 15:39:16 -04:00
ohai " ENV "
2020-08-14 02:26:29 +02:00
BuildEnvironment . dump env
2012-10-31 11:26:45 -04:00
puts
2015-05-27 22:16:48 +08:00
onoe " #{ formula . full_name } #{ formula . version } did not build "
2015-04-25 22:07:06 -04:00
unless ( logs = Dir [ " #{ formula . logs } /* " ] ) . empty?
2013-10-27 17:17:09 +01:00
puts " Logs: "
2015-08-03 13:09:07 +01:00
puts logs . map { | fn | " #{ fn } " } . join ( " \n " )
2012-10-31 11:26:45 -04:00
end
2012-09-27 15:39:16 -04:00
end
2016-11-05 15:39:25 -04:00
2023-02-02 14:49:33 +00:00
if formula . tap && ! OS . unsupported_configuration?
2016-11-05 15:39:25 -04:00
if formula . tap . official?
puts Formatter . error ( Formatter . url ( OS :: ISSUES_URL ) , label : " READ THIS " )
2021-02-12 18:33:37 +05:30
elsif ( issues_url = formula . tap . issues_url )
2017-10-15 02:28:32 +02:00
puts << ~ EOS
2023-02-10 23:15:40 -05:00
If reporting this issue please do so at ( not Homebrew / brew or Homebrew / homebrew - core ) :
2019-04-01 16:02:13 -04:00
#{Formatter.url(issues_url)}
2016-11-05 15:39:25 -04:00
EOS
else
2017-10-15 02:28:32 +02:00
puts << ~ EOS
2023-02-10 23:15:40 -05:00
If reporting this issue please do so to ( not Homebrew / brew or Homebrew / homebrew - core ) :
2019-04-01 16:02:13 -04:00
#{formula.tap}
2016-11-05 15:39:25 -04:00
EOS
end
else
2017-10-15 02:28:32 +02:00
puts << ~ EOS
2023-02-10 23:15:40 -05:00
Do not report this issue to Homebrew / brew or Homebrew / homebrew - core!
2016-11-05 15:39:25 -04:00
EOS
end
2012-08-13 09:50:15 -04:00
puts
2016-11-05 15:39:25 -04:00
2019-03-18 14:30:58 +00:00
if issues . present?
2012-10-31 11:26:45 -04:00
puts " These open issues may also help: "
2015-08-03 13:09:07 +01:00
puts issues . map { | i | " #{ i [ " title " ] } #{ i [ " html_url " ] } " } . join ( " \n " )
2012-10-31 11:26:45 -04:00
end
2015-06-16 20:02:10 -04:00
2016-01-04 23:14:58 +01:00
require " diagnostic "
2016-11-05 10:40:07 -04:00
checks = Homebrew :: Diagnostic :: Checks . new
checks . build_error_checks . each do | check |
2016-11-05 15:39:25 -04:00
out = checks . send ( check )
2016-11-05 10:40:07 -04:00
next if out . nil?
2018-09-17 02:45:00 +02:00
2016-11-05 15:39:25 -04:00
puts
2016-11-05 10:40:07 -04:00
ofail out
end
2012-03-07 11:11:05 +00:00
end
2013-05-20 19:35:07 -05:00
end
2020-12-11 16:57:47 +00:00
# Raised if the formula or its dependencies are not bottled and are being
# installed in a situation where a bottle is required.
class UnbottledError < RuntimeError
2015-06-29 14:09:57 -04:00
def initialize ( formulae )
2020-12-11 16:57:47 +00:00
msg = + << ~ EOS
2023-02-27 20:16:34 -08:00
The following #{Utils.pluralize("formula", formulae.count, plural: "e")} cannot be installed from #{Utils.pluralize("bottle", formulae.count)} and must be
2020-12-11 16:57:47 +00:00
built from source .
2018-09-17 20:11:11 +02:00
#{formulae.to_sentence}
2015-06-29 14:09:57 -04:00
EOS
2020-12-11 16:57:47 +00:00
msg += " #{ DevelopmentTools . installation_instructions } \n " unless DevelopmentTools . installed?
msg . freeze
super ( msg )
2015-06-29 14:09:57 -04:00
end
end
2024-04-26 20:55:51 +02:00
# Raised by `Homebrew.install`, `Homebrew.reinstall` and `Homebrew.upgrade`
2015-06-29 14:09:57 -04:00
# if the user passes any flags/environment that would case a bottle-only
2018-10-18 21:42:43 -04:00
# installation on a system without build tools to fail.
2015-06-29 14:09:57 -04:00
class BuildFlagsError < RuntimeError
2018-01-28 22:44:03 +00:00
def initialize ( flags , bottled : true )
2015-06-29 14:09:57 -04:00
if flags . length > 1
flag_text = " flags "
require_text = " require "
else
flag_text = " flag "
require_text = " requires "
end
2019-10-11 09:02:41 +01:00
bottle_text = if bottled
<< ~ EOS
Alternatively , remove the #{flag_text} to attempt bottle installation.
EOS
end
message = << ~ EOS
2015-06-29 14:09:57 -04:00
The following #{flag_text}:
2015-08-22 13:15:33 +08:00
#{flags.join(", ")}
2015-06-29 14:09:57 -04:00
#{require_text} building tools, but none are installed.
2021-08-09 02:21:45 +09:00
#{DevelopmentTools.installation_instructions} #{bottle_text}
2015-06-29 14:09:57 -04:00
EOS
2018-01-28 22:44:03 +00:00
super message
2015-06-29 14:09:57 -04:00
end
end
2018-10-18 21:42:43 -04:00
# Raised by {CompilerSelector} if the formula fails with all of
# the compilers available on the user's system.
2014-09-14 01:10:20 -05:00
class CompilerSelectionError < RuntimeError
def initialize ( formula )
2017-10-15 02:28:32 +02:00
super << ~ EOS
2016-07-16 21:03:36 +01:00
#{formula.full_name} cannot be built with any available compilers.
#{DevelopmentTools.custom_installation_instructions}
EOS
2013-05-20 19:35:07 -05:00
end
2010-09-11 20:22:54 +01:00
end
2011-09-14 12:18:35 -07:00
2023-04-18 00:22:13 +01:00
# Raised in {Downloadable#fetch}.
2014-02-18 15:08:03 -05:00
class DownloadError < RuntimeError
2023-04-18 00:22:13 +01:00
attr_reader :cause
def initialize ( downloadable , cause )
2017-10-15 02:28:32 +02:00
super << ~ EOS
2023-04-18 00:22:13 +01:00
Failed to download resource #{downloadable.download_name.inspect}
2014-12-29 22:51:55 -05:00
#{cause.message}
2018-06-06 23:34:19 -04:00
EOS
2023-04-18 00:22:13 +01:00
@cause = cause
2014-12-29 22:51:55 -05:00
set_backtrace ( cause . backtrace )
2014-02-18 15:08:03 -05:00
end
end
2018-10-18 21:42:43 -04:00
# Raised in {CurlDownloadStrategy#fetch}.
2014-12-29 22:52:53 -05:00
class CurlDownloadStrategyError < RuntimeError
def initialize ( url )
case url
2015-08-03 13:09:07 +01:00
when %r{ ^file://(.+) }
2017-06-10 20:23:20 +03:00
super " File does not exist: #{ Regexp . last_match ( 1 ) } "
2014-12-29 22:52:53 -05:00
else
super " Download failed: #{ url } "
end
end
end
2011-09-14 12:18:35 -07:00
2021-07-26 12:39:25 +02:00
# Raised in {HomebrewCurlDownloadStrategy#fetch}.
class HomebrewCurlDownloadStrategyError < CurlDownloadStrategyError
def initialize ( url )
super " Homebrew-installed `curl` is not installed for: #{ url } "
end
end
2020-07-16 02:52:28 +01:00
# Raised by {Kernel#safe_system} in `utils.rb`.
2014-09-18 20:32:50 -05:00
class ErrorDuringExecution < RuntimeError
2020-07-07 11:29:33 +01:00
attr_reader :cmd , :status , :output
2018-07-30 10:11:00 +02:00
2019-06-28 14:50:38 +08:00
def initialize ( cmd , status : , output : nil , secrets : [ ] )
2018-08-17 22:42:37 -04:00
@cmd = cmd
2018-07-30 10:11:00 +02:00
@status = status
2018-08-17 22:42:37 -04:00
@output = output
2018-07-30 10:11:00 +02:00
2021-02-23 21:30:36 +00:00
raise ArgumentError , " Status cannot be nil. " if status . nil?
2020-12-17 15:45:50 +01:00
exitstatus = case status
when Integer
2018-08-17 22:42:37 -04:00
status
2021-02-23 21:30:36 +00:00
when Hash
status [ " exitstatus " ]
else
status . exitstatus
end
termsig = case status
when Integer
nil
when Hash
status [ " termsig " ]
2020-12-17 15:45:50 +01:00
else
2021-02-23 21:30:36 +00:00
status . termsig
2018-08-17 22:42:37 -04:00
end
2019-06-28 14:50:38 +08:00
redacted_cmd = redact_secrets ( cmd . shelljoin . gsub ( '\=' , " = " ) , secrets )
2020-12-17 15:45:50 +01:00
reason = if exitstatus
" exited with #{ exitstatus } "
2021-02-23 21:30:36 +00:00
elsif termsig
" was terminated by uncaught signal #{ Signal . signame ( termsig ) } "
2020-12-17 15:45:50 +01:00
else
2020-12-28 09:04:08 +00:00
raise ArgumentError , " Status neither has `exitstatus` nor `termsig`. "
2020-12-17 15:45:50 +01:00
end
s = + " Failure while executing; ` #{ redacted_cmd } ` #{ reason } . "
2018-07-16 23:17:16 +02:00
2020-07-13 22:48:53 +10:00
if Array ( output ) . present?
2019-01-02 10:12:12 -08:00
format_output_line = lambda do | type_line |
type , line = * type_line
2018-07-19 13:31:40 +02:00
if type == :stderr
Formatter . error ( line )
else
line
end
end
2018-07-16 23:17:16 +02:00
2018-07-19 13:31:40 +02:00
s << " Here's the output: \n "
s << output . map ( & format_output_line ) . join
s << " \n " unless s . end_with? ( " \n " )
2018-07-16 23:17:16 +02:00
end
2019-04-20 14:07:29 +09:00
super s . freeze
2014-09-18 20:32:50 -05:00
end
2019-03-29 21:06:39 +01:00
2020-10-20 12:03:48 +02:00
sig { returns ( String ) }
2019-03-29 21:06:39 +01:00
def stderr
2020-07-13 22:48:53 +10:00
Array ( output ) . select { | type , | type == :stderr } . map ( & :last ) . join
2019-03-29 21:06:39 +01:00
end
2014-09-18 20:32:50 -05:00
end
2012-06-18 19:58:35 -05:00
2018-10-18 21:42:43 -04:00
# Raised by {Pathname#verify_checksum} when "expected" is nil or empty.
2013-08-06 21:48:05 -07:00
class ChecksumMissingError < ArgumentError ; end
2012-06-18 19:58:35 -05:00
2018-10-18 21:42:43 -04:00
# Raised by {Pathname#verify_checksum} when verification fails.
2012-06-18 19:58:35 -05:00
class ChecksumMismatchError < RuntimeError
2021-01-07 08:33:57 +01:00
attr_reader :expected
2012-06-18 19:58:35 -05:00
2020-11-19 19:44:23 +01:00
def initialize ( path , expected , actual )
2012-06-18 19:58:35 -05:00
@expected = expected
2017-10-15 02:28:32 +02:00
super << ~ EOS
2021-01-07 08:33:57 +01:00
SHA256 mismatch
2020-11-19 19:44:23 +01:00
Expected : #{Formatter.success(expected.to_s)}
Actual : #{Formatter.error(actual.to_s)}
File : #{path}
2014-02-18 13:27:35 -05:00
To retry an incomplete download , remove the file above .
2018-06-06 23:34:19 -04:00
EOS
2012-06-18 19:58:35 -05:00
end
end
2013-08-06 19:52:58 -07:00
2020-08-14 05:28:26 +02:00
# Raised when a resource is missing.
2013-08-06 19:52:58 -07:00
class ResourceMissingError < ArgumentError
2014-09-12 21:19:25 -05:00
def initialize ( formula , resource )
2015-05-27 22:16:48 +08:00
super " #{ formula . full_name } does not define resource #{ resource . inspect } "
2013-08-06 19:52:58 -07:00
end
end
2020-08-14 05:28:26 +02:00
# Raised when a resource is specified multiple times.
2013-08-06 19:52:58 -07:00
class DuplicateResourceError < ArgumentError
2014-09-12 21:19:25 -05:00
def initialize ( resource )
super " Resource #{ resource . inspect } is defined more than once "
2013-08-06 19:52:58 -07:00
end
end
2015-07-23 14:09:32 +08:00
2018-10-18 21:42:43 -04:00
# Raised when a single patch file is not found and apply hasn't been specified.
2016-09-17 15:17:27 +01:00
class MissingApplyError < RuntimeError ; end
2016-01-25 08:21:57 -08:00
2020-08-14 05:28:26 +02:00
# Raised when a bottle does not contain a formula file.
2017-09-19 12:22:32 -07:00
class BottleFormulaUnavailableError < RuntimeError
def initialize ( bottle_path , formula_path )
2017-10-15 02:28:32 +02:00
super << ~ EOS
2017-09-19 12:22:32 -07:00
This bottle does not contain the formula file :
#{bottle_path}
#{formula_path}
2015-07-23 14:09:32 +08:00
EOS
end
end
2018-08-17 22:42:37 -04:00
# Raised when a child process sends us an exception over its error pipe.
class ChildProcessError < RuntimeError
2020-07-07 11:29:33 +01:00
attr_reader :inner , :inner_class
2018-08-17 22:42:37 -04:00
def initialize ( inner )
@inner = inner
@inner_class = Object . const_get inner [ " json_class " ]
super << ~ EOS
2018-10-05 12:04:19 -07:00
An exception occurred within a child process :
2018-08-17 22:42:37 -04:00
#{inner_class}: #{inner["m"]}
EOS
# Clobber our real (but irrelevant) backtrace with that of the inner exception.
set_backtrace inner [ " b " ]
end
end
2020-06-10 10:06:46 +01:00
2021-04-29 17:48:09 +01:00
# Raised when `detected_perl_shebang` etc cannot detect the shebang.
class ShebangDetectionError < RuntimeError
def initialize ( type , reason )
super " Cannot detect #{ type } shebang: #{ reason } . "
end
end
2021-09-12 07:56:37 -07:00
# Raised when one or more formulae have cyclic dependencies.
class CyclicDependencyError < RuntimeError
def initialize ( strongly_connected_components )
super << ~ EOS
The following packages contain cyclic dependencies :
#{strongly_connected_components.select { |packages| packages.count > 1 }.map(&:to_sentence).join("\n ")}
EOS
end
end