Separate formula conflicts from requirements

Closes Homebrew/homebrew#20357.
This commit is contained in:
Jack Nagel 2013-06-09 13:44:59 -05:00
parent 33cae6ac42
commit 8b9a3a560f
8 changed files with 58 additions and 41 deletions

View File

@ -174,11 +174,11 @@ class FormulaAuditor
end
def audit_conflicts
f.conflicts.each do |req|
f.conflicts.each do |c|
begin
Formula.factory req.formula
Formula.factory(c.name)
rescue FormulaUnavailableError
problem "Can't find conflicting formula \"#{req.formula}\"."
problem "Can't find conflicting formula #{c.name.inspect}."
end
end
end

View File

@ -102,7 +102,7 @@ module Homebrew extend self
puts
end
conflicts = f.conflicts.map(&:formula).sort!
conflicts = f.conflicts.map(&:name).sort!
puts "Conflicts with: #{conflicts*', '}" unless conflicts.empty?
if f.rack.directory?

View File

@ -115,6 +115,38 @@ class UnsatisfiedRequirements < Homebrew::InstallationError
end
end
class FormulaConflictError < Homebrew::InstallationError
attr_reader :f, :conflicts
def initialize(f, conflicts)
@f = f
@conflicts = conflicts
super f, message
end
def conflict_message(conflict)
message = []
message << " #{conflict.name}"
message << ": because #{conflict.reason}" if conflict.reason
message.join
end
def message
message = []
message << "Cannot install #{f.name} because conflicting formulae are installed.\n"
message.concat conflicts.map { |c| conflict_message(c) } << ""
message << <<-EOS.undent
Please `brew unlink #{conflicts.map(&:name)*' '}` before continuing.
Unlinking removes a formula's symlinks from #{HOMEBREW_PREFIX}. You can
link the formula again after the install finishes. You can --force this
install, but the build may fail or cause obscure side-effects in the
resulting software.
EOS
message.join("\n")
end
end
class BuildError < Homebrew::InstallationError
attr_reader :exit_status, :command, :env

View File

@ -491,7 +491,7 @@ class Formula
end
def conflicts
requirements.grep(ConflictRequirement)
self.class.conflicts
end
# Returns a list of Dependency objects in an installable order, which
@ -764,8 +764,12 @@ class Formula
@plist_manual = options[:manual]
end
def conflicts_with formula, opts={}
dependencies.add ConflictRequirement.new(formula, name, opts)
def conflicts
@conflicts ||= []
end
def conflicts_with name, opts={}
conflicts << FormulaConflict.new(name, opts[:because])
end
def skip_clean *paths

View File

@ -78,6 +78,8 @@ class FormulaInstaller
EOS
end
check_conflicts
unless ignore_deps
perform_readline_hack
check_requirements
@ -121,6 +123,17 @@ class FormulaInstaller
end
end
def check_conflicts
return if ARGV.force?
conflicts = f.conflicts.reject do |c|
keg = Formula.factory(c.name).prefix
not keg.directory? && Keg.new(keg).linked?
end
raise FormulaConflictError.new(f, conflicts) unless conflicts.empty?
end
def check_requirements
unsatisfied = ARGV.filter_for_dependencies do
f.recursive_requirements do |dependent, req|

View File

@ -2,6 +2,8 @@ require 'download_strategy'
require 'checksum'
require 'version'
FormulaConflict = Struct.new(:name, :reason)
class SoftwareSpec
attr_reader :checksum, :mirrors, :specs
attr_reader :using # for auditing

View File

@ -1,5 +1,4 @@
require 'requirement'
require 'requirements/conflict_requirement'
require 'requirements/language_module_dependency'
require 'requirements/x11_dependency'
require 'requirements/mpi_dependency'

View File

@ -1,33 +0,0 @@
require 'requirement'
# This requirement added by the `conflicts_with` DSL method.
class ConflictRequirement < Requirement
attr_reader :formula
# The user can chose to force installation even in the face of conflicts.
fatal !ARGV.force?
def initialize formula, name, opts={}
@formula = formula
@name = name
@opts = opts
super([formula])
end
def message
message = "#{@name.downcase} cannot be installed alongside #{@formula}.\n"
message << "This is because #{@opts[:because]}\n" if @opts[:because]
message << <<-EOS.undent unless ARGV.force?
Please `brew unlink #{@formula}` before continuing. Unlinking removes
the formula's symlinks from #{HOMEBREW_PREFIX}. You can link the
formula again after the install finishes. You can --force this install
but the build may fail or cause obscure side-effects in the end-binary.
EOS
message
end
satisfy :build_env => false do
keg = Formula.factory(@formula).prefix
not keg.exist? && Keg.new(keg).linked?
end
end