From 8b9a3a560f93b1a1f42dcae83240ffddb6763be0 Mon Sep 17 00:00:00 2001 From: Jack Nagel Date: Sun, 9 Jun 2013 13:44:59 -0500 Subject: [PATCH] Separate formula conflicts from requirements Closes Homebrew/homebrew#20357. --- Library/Homebrew/cmd/audit.rb | 6 ++-- Library/Homebrew/cmd/info.rb | 2 +- Library/Homebrew/exceptions.rb | 32 ++++++++++++++++++ Library/Homebrew/formula.rb | 10 ++++-- Library/Homebrew/formula_installer.rb | 13 ++++++++ Library/Homebrew/formula_support.rb | 2 ++ Library/Homebrew/requirements.rb | 1 - .../requirements/conflict_requirement.rb | 33 ------------------- 8 files changed, 58 insertions(+), 41 deletions(-) delete mode 100644 Library/Homebrew/requirements/conflict_requirement.rb diff --git a/Library/Homebrew/cmd/audit.rb b/Library/Homebrew/cmd/audit.rb index 3027580652..5bb9c2df0f 100644 --- a/Library/Homebrew/cmd/audit.rb +++ b/Library/Homebrew/cmd/audit.rb @@ -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 diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index 7abe9ec673..67a009877f 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -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? diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index 9c812ce349..71ce3eccdc 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -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 diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 402c4500b6..51b02eab03 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -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 diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index aca76b492c..4537e31d1f 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -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| diff --git a/Library/Homebrew/formula_support.rb b/Library/Homebrew/formula_support.rb index 114e46de4f..e7e2231fd9 100644 --- a/Library/Homebrew/formula_support.rb +++ b/Library/Homebrew/formula_support.rb @@ -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 diff --git a/Library/Homebrew/requirements.rb b/Library/Homebrew/requirements.rb index c1c7fff7a1..0aafc0a8ca 100644 --- a/Library/Homebrew/requirements.rb +++ b/Library/Homebrew/requirements.rb @@ -1,5 +1,4 @@ require 'requirement' -require 'requirements/conflict_requirement' require 'requirements/language_module_dependency' require 'requirements/x11_dependency' require 'requirements/mpi_dependency' diff --git a/Library/Homebrew/requirements/conflict_requirement.rb b/Library/Homebrew/requirements/conflict_requirement.rb deleted file mode 100644 index 286396735c..0000000000 --- a/Library/Homebrew/requirements/conflict_requirement.rb +++ /dev/null @@ -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