2020-10-10 14:16:11 +02:00
|
|
|
# typed: false
|
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.
|
2016-04-19 08:11:17 +02:00
|
|
|
class UsageError < RuntimeError
|
2020-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
2016-04-19 08:11:17 +02:00
|
|
|
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
|
|
|
|
2020-07-03 18:24:52 -04:00
|
|
|
class MultipleVersionsInstalledError < RuntimeError; end
|
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.
|
|
|
|
#
|
|
|
|
# @api private
|
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
|
2020-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
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
|
|
|
|
end
|
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(String) }
|
2020-09-25 21:13:26 +02:00
|
|
|
def to_s
|
|
|
|
"No available formula or cask with the name \"#{name}\"."
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Raised when a formula is not available.
|
|
|
|
class FormulaUnavailableError < FormulaOrCaskUnavailableError
|
2020-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
2020-09-25 21:13:26 +02:00
|
|
|
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
|
2020-10-20 12:03:48 +02:00
|
|
|
"No available formula with the name \"#{name}\"#{dependent_s}."
|
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.
|
|
|
|
#
|
|
|
|
# @api private
|
2017-04-18 08:43:39 +01:00
|
|
|
module FormulaClassUnavailableErrorModule
|
2020-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
2020-07-07 11:29:33 +01:00
|
|
|
attr_reader :path, :class_name, :class_list
|
2016-04-16 20:57:03 +02:00
|
|
|
|
|
|
|
def to_s
|
|
|
|
s = super
|
|
|
|
s += "\nIn formula file: #{path}"
|
|
|
|
s += "\nExpected 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.
|
|
|
|
#
|
|
|
|
# @api private
|
2017-04-18 08:43:39 +01:00
|
|
|
module FormulaUnreadableErrorModule
|
2020-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
|
|
|
def to_s
|
2017-04-18 08:43:39 +01:00
|
|
|
s = super
|
|
|
|
s += "\nPlease 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
|
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
|
|
|
|
attr_reader :name, :paths, :formulae
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def initialize(name, paths)
|
2015-05-08 19:16:06 +08:00
|
|
|
@name = name
|
|
|
|
@paths = paths
|
|
|
|
@formulae = paths.map do |path|
|
2018-03-29 22:05:02 +02:00
|
|
|
"#{Tap.from_path(path).name}/#{path.basename(".rb")}"
|
2015-05-08 19:16:06 +08:00
|
|
|
end
|
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
super <<~EOS
|
2015-05-08 19:16:06 +08:00
|
|
|
Formulae found in multiple taps: #{formulae.map { |f| "\n * #{f}" }.join}
|
|
|
|
|
2019-04-08 12:47:15 -04:00
|
|
|
Please use the fully-qualified name (e.g. #{formulae.first}) to refer to the formula.
|
2015-05-08 19:16:06 +08:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-08-14 05:28:26 +02:00
|
|
|
# Raised when a formula's old name in a specific tap is found in multiple taps.
|
2015-08-09 15:08:12 +03:00
|
|
|
class TapFormulaWithOldnameAmbiguityError < RuntimeError
|
|
|
|
attr_reader :name, :possible_tap_newname_formulae, :taps
|
|
|
|
|
|
|
|
def initialize(name, possible_tap_newname_formulae)
|
|
|
|
@name = name
|
|
|
|
@possible_tap_newname_formulae = possible_tap_newname_formulae
|
|
|
|
|
|
|
|
@taps = possible_tap_newname_formulae.map do |newname|
|
|
|
|
newname =~ HOMEBREW_TAP_FORMULA_REGEX
|
2017-06-10 20:23:20 +03:00
|
|
|
"#{Regexp.last_match(1)}/#{Regexp.last_match(2)}"
|
2015-08-09 15:08:12 +03:00
|
|
|
end
|
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
super <<~EOS
|
2015-08-22 13:15:33 +08:00
|
|
|
Formulae with '#{name}' old name found in multiple taps: #{taps.map { |t| "\n * #{t}" }.join}
|
2015-08-09 15:08:12 +03:00
|
|
|
|
2019-04-08 12:47:15 -04:00
|
|
|
Please use the fully-qualified name (e.g. #{taps.first}/#{name}) to refer to the formula or use its new name.
|
2015-08-09 15:08:12 +03: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
|
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
super <<~EOS
|
2015-06-13 14:32:10 +08:00
|
|
|
No available tap #{name}.
|
|
|
|
EOS
|
|
|
|
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
|
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
super <<~EOS
|
2016-04-04 03:18:55 -07:00
|
|
|
Tap #{name} remote mismatch.
|
|
|
|
#{expected_remote} != #{actual_remote}
|
|
|
|
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
|
|
|
|
|
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
|
2020-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
2014-09-14 01:10:20 -05:00
|
|
|
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
|
|
|
|
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.
|
|
|
|
|
|
|
|
If you are using a non-standard Python depedency, please add `:using => "python@x.y"` to
|
|
|
|
`virtualenv_install_with_resources` to resolve the issue manually.
|
|
|
|
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
|
2016-08-05 00:20:20 -07:00
|
|
|
The version of python to use with the virtualenv in the `#{formula.full_name}` formula
|
2020-02-10 22:54:11 +01:00
|
|
|
cannot be guessed automatically. If the simultaneous use of multiple pythons
|
|
|
|
is intentional, please add `:using => "python@x.y"` to
|
2016-08-05 00:20:20 -07:00
|
|
|
`virtualenv_install_with_resources` to resolve the ambiguity manually.
|
|
|
|
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
|
|
|
|
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
|
2018-11-07 11:58:05 +01:00
|
|
|
pretty_args = Array(args).map { |arg| arg.to_s.gsub " ", "\\ " }.join(" ")
|
|
|
|
super "Failed executing: #{cmd} #{pretty_args}".strip
|
2010-09-11 20:22:54 +01:00
|
|
|
end
|
2012-03-07 11:11:05 +00:00
|
|
|
|
2012-10-31 11:26:45 -04:00
|
|
|
def issues
|
2014-02-08 16:04:53 -05:00
|
|
|
@issues ||= fetch_issues
|
|
|
|
end
|
|
|
|
|
|
|
|
def fetch_issues
|
2020-06-14 20:49:52 -04:00
|
|
|
GitHub.issues_for_formula(formula.name, tap: formula.tap, state: "open")
|
2014-02-08 16:04:53 -05:00
|
|
|
rescue GitHub::RateLimitExceededError => e
|
|
|
|
opoo e.message
|
|
|
|
[]
|
2012-10-31 11:26:45 -04:00
|
|
|
end
|
|
|
|
|
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
|
|
|
|
2016-11-24 08:54:24 +00:00
|
|
|
if formula.tap && defined?(OS::ISSUES_URL)
|
2016-11-05 15:39:25 -04:00
|
|
|
if formula.tap.official?
|
|
|
|
puts Formatter.error(Formatter.url(OS::ISSUES_URL), label: "READ THIS")
|
|
|
|
elsif issues_url = formula.tap.issues_url
|
2017-10-15 02:28:32 +02:00
|
|
|
puts <<~EOS
|
2016-11-05 15:39:25 -04:00
|
|
|
If reporting this issue please do so at (not Homebrew/brew or 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
|
2016-11-05 15:39:25 -04:00
|
|
|
If reporting this issue please do so to (not Homebrew/brew or 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
|
2016-11-05 15:39:25 -04:00
|
|
|
Do not report this issue to Homebrew/brew or Homebrew/core!
|
|
|
|
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
|
|
|
|
The following #{"formula".pluralize(formulae.count)} cannot be installed from #{"bottle".pluralize(formulae.count)} and must be
|
|
|
|
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
|
|
|
|
|
2018-10-18 21:42:43 -04: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.
|
2019-10-11 09:02:41 +01: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
|
|
|
|
2018-10-18 21:42:43 -04:00
|
|
|
# Raised in {Resource#fetch}.
|
2014-02-18 15:08:03 -05:00
|
|
|
class DownloadError < RuntimeError
|
2014-12-29 22:51:55 -05:00
|
|
|
def initialize(resource, cause)
|
2017-10-15 02:28:32 +02:00
|
|
|
super <<~EOS
|
2014-02-18 15:08:03 -05:00
|
|
|
Failed to download resource #{resource.download_name.inspect}
|
2014-12-29 22:51:55 -05:00
|
|
|
#{cause.message}
|
2018-06-06 23:34:19 -04:00
|
|
|
EOS
|
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
|
|
|
|
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-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
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
|
|
|
|
2018-08-17 22:42:37 -04:00
|
|
|
exitstatus = if status.respond_to?(:exitstatus)
|
|
|
|
status.exitstatus
|
|
|
|
else
|
|
|
|
status
|
|
|
|
end
|
|
|
|
|
2019-06-28 14:50:38 +08:00
|
|
|
redacted_cmd = redact_secrets(cmd.shelljoin.gsub('\=', "="), secrets)
|
|
|
|
s = +"Failure while executing; `#{redacted_cmd}` exited with #{exitstatus}."
|
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
|
2014-02-18 13:27:35 -05:00
|
|
|
attr_reader :expected, :hash_type
|
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
|
2012-06-26 00:51:02 -05:00
|
|
|
@hash_type = expected.hash_type.to_s.upcase
|
2012-06-18 19:58:35 -05:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
super <<~EOS
|
2012-06-26 00:51:02 -05:00
|
|
|
#{@hash_type} 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
|
|
|
|
2020-08-14 05:28:26 +02:00
|
|
|
# Raised when a macOS version is unsupported.
|
2020-06-10 10:06:46 +01:00
|
|
|
class MacOSVersionError < RuntimeError
|
|
|
|
attr_reader :version
|
|
|
|
|
|
|
|
def initialize(version)
|
|
|
|
@version = version
|
|
|
|
super "unknown or unsupported macOS version: #{version.inspect}"
|
|
|
|
end
|
|
|
|
end
|