Separate formula conflicts from requirements
Closes Homebrew/homebrew#20357.
This commit is contained in:
		
							parent
							
								
									33cae6ac42
								
							
						
					
					
						commit
						8b9a3a560f
					
				@ -174,11 +174,11 @@ class FormulaAuditor
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def audit_conflicts
 | 
					  def audit_conflicts
 | 
				
			||||||
    f.conflicts.each do |req|
 | 
					    f.conflicts.each do |c|
 | 
				
			||||||
      begin
 | 
					      begin
 | 
				
			||||||
        Formula.factory req.formula
 | 
					        Formula.factory(c.name)
 | 
				
			||||||
      rescue FormulaUnavailableError
 | 
					      rescue FormulaUnavailableError
 | 
				
			||||||
        problem "Can't find conflicting formula \"#{req.formula}\"."
 | 
					        problem "Can't find conflicting formula #{c.name.inspect}."
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
				
			|||||||
@ -102,7 +102,7 @@ module Homebrew extend self
 | 
				
			|||||||
      puts
 | 
					      puts
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    conflicts = f.conflicts.map(&:formula).sort!
 | 
					    conflicts = f.conflicts.map(&:name).sort!
 | 
				
			||||||
    puts "Conflicts with: #{conflicts*', '}" unless conflicts.empty?
 | 
					    puts "Conflicts with: #{conflicts*', '}" unless conflicts.empty?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if f.rack.directory?
 | 
					    if f.rack.directory?
 | 
				
			||||||
 | 
				
			|||||||
@ -115,6 +115,38 @@ class UnsatisfiedRequirements < Homebrew::InstallationError
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
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
 | 
					class BuildError < Homebrew::InstallationError
 | 
				
			||||||
  attr_reader :exit_status, :command, :env
 | 
					  attr_reader :exit_status, :command, :env
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -491,7 +491,7 @@ class Formula
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def conflicts
 | 
					  def conflicts
 | 
				
			||||||
    requirements.grep(ConflictRequirement)
 | 
					    self.class.conflicts
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Returns a list of Dependency objects in an installable order, which
 | 
					  # Returns a list of Dependency objects in an installable order, which
 | 
				
			||||||
@ -764,8 +764,12 @@ class Formula
 | 
				
			|||||||
      @plist_manual = options[:manual]
 | 
					      @plist_manual = options[:manual]
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def conflicts_with formula, opts={}
 | 
					    def conflicts
 | 
				
			||||||
      dependencies.add ConflictRequirement.new(formula, name, opts)
 | 
					      @conflicts ||= []
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def conflicts_with name, opts={}
 | 
				
			||||||
 | 
					      conflicts << FormulaConflict.new(name, opts[:because])
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def skip_clean *paths
 | 
					    def skip_clean *paths
 | 
				
			||||||
 | 
				
			|||||||
@ -78,6 +78,8 @@ class FormulaInstaller
 | 
				
			|||||||
      EOS
 | 
					      EOS
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    check_conflicts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unless ignore_deps
 | 
					    unless ignore_deps
 | 
				
			||||||
      perform_readline_hack
 | 
					      perform_readline_hack
 | 
				
			||||||
      check_requirements
 | 
					      check_requirements
 | 
				
			||||||
@ -121,6 +123,17 @@ class FormulaInstaller
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
  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
 | 
					  def check_requirements
 | 
				
			||||||
    unsatisfied = ARGV.filter_for_dependencies do
 | 
					    unsatisfied = ARGV.filter_for_dependencies do
 | 
				
			||||||
      f.recursive_requirements do |dependent, req|
 | 
					      f.recursive_requirements do |dependent, req|
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,8 @@ require 'download_strategy'
 | 
				
			|||||||
require 'checksum'
 | 
					require 'checksum'
 | 
				
			||||||
require 'version'
 | 
					require 'version'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FormulaConflict = Struct.new(:name, :reason)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SoftwareSpec
 | 
					class SoftwareSpec
 | 
				
			||||||
  attr_reader :checksum, :mirrors, :specs
 | 
					  attr_reader :checksum, :mirrors, :specs
 | 
				
			||||||
  attr_reader :using # for auditing
 | 
					  attr_reader :using # for auditing
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
require 'requirement'
 | 
					require 'requirement'
 | 
				
			||||||
require 'requirements/conflict_requirement'
 | 
					 | 
				
			||||||
require 'requirements/language_module_dependency'
 | 
					require 'requirements/language_module_dependency'
 | 
				
			||||||
require 'requirements/x11_dependency'
 | 
					require 'requirements/x11_dependency'
 | 
				
			||||||
require 'requirements/mpi_dependency'
 | 
					require 'requirements/mpi_dependency'
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user