diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 04375fcbe7425..7a7fc8b8ef222 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -218,8 +218,12 @@ def verify_deps_exist raise end - def check_install_sanity + def check_installation_already_attempted raise FormulaInstallationAlreadyAttemptedError, formula if self.class.attempted.include?(formula) + end + + def check_install_sanity + check_installation_already_attempted if force_bottle? && !pour_bottle? raise CannotInstallFormulaError, "--force-bottle passed but #{formula.full_name} has no bottle!" diff --git a/Library/Homebrew/install.rb b/Library/Homebrew/install.rb index 52e630ab00652..5c563b4e46015 100644 --- a/Library/Homebrew/install.rb +++ b/Library/Homebrew/install.rb @@ -209,6 +209,28 @@ def install_formula?( Or to force-install it, run: brew install #{f} --force EOS + elsif f.linked? + message = "#{f.name} #{f.linked_version} is already installed" + if f.outdated? && !head + unless Homebrew::EnvConfig.no_install_upgrade? + puts "#{message} but outdated" + return true + end + + onoe <<~EOS + #{message} + To upgrade to #{f.pkg_version}, run: + brew upgrade #{f.full_name} + EOS + elsif only_dependencies + return true + else + onoe <<~EOS + #{message} + To install #{f.pkg_version}, first run: + brew unlink #{f.name} + EOS + end else # If none of the above is true and the formula is linked, then # FormulaInstaller will handle this case. @@ -272,8 +294,11 @@ def install_formulae( ) begin + fi.prelude fi.fetch fi + rescue CannotInstallFormulaError => e + ofail e.message rescue UnsatisfiedRequirements, DownloadError, ChecksumMismatchError => e ofail "#{f}: #{e}" nil @@ -281,60 +306,21 @@ def install_formulae( end.compact formula_installers.each do |fi| - install_formula(fi, only_deps: only_deps) + install_formula(fi) Cleanup.install_formula_clean!(fi.formula) end end - def install_formula(formula_installer, only_deps: false) + def install_formula(formula_installer) f = formula_installer.formula - formula_installer.prelude + formula_installer.check_installation_already_attempted f.print_tap_action - if f.linked_keg.directory? - if Homebrew::EnvConfig.no_install_upgrade? - message = <<~EOS - #{f.name} #{f.linked_version} is already installed - EOS - message += if f.outdated? && !f.head? - <<~EOS - To upgrade to #{f.pkg_version}, run: - brew upgrade #{f.full_name} - EOS - else - <<~EOS - To install #{f.pkg_version}, first run: - brew unlink #{f.name} - EOS - end - raise CannotInstallFormulaError, message unless only_deps - elsif f.outdated? && !f.head? - puts "#{f.name} #{f.linked_version} is installed but outdated" - kegs = Upgrade.outdated_kegs(f) - linked_kegs = kegs.select(&:linked?) - Upgrade.print_upgrade_message(f, formula_installer.options) - end - end + upgrade = f.linked? && f.outdated? && !f.head? && !Homebrew::EnvConfig.no_install_upgrade? - kegs.each(&:unlink) if kegs.present? - - formula_installer.install - formula_installer.finish - rescue FormulaInstallationAlreadyAttemptedError - # We already attempted to install f as part of the dependency tree of - # another formula. In that case, don't generate an error, just move on. - nil - rescue CannotInstallFormulaError => e - ofail e.message - ensure - # Re-link kegs if upgrade fails - begin - linked_kegs.each(&:link) if linked_kegs.present? && !f.latest_version_installed? - rescue - nil - end + Upgrade.install_formula(formula_installer, upgrade: upgrade) end private_class_method :install_formula end diff --git a/Library/Homebrew/upgrade.rb b/Library/Homebrew/upgrade.rb index b90bdfb6dc9e8..dd9071f170bff 100644 --- a/Library/Homebrew/upgrade.rb +++ b/Library/Homebrew/upgrade.rb @@ -58,8 +58,13 @@ def upgrade_formulae( quiet: quiet, verbose: verbose, ) - fi.fetch unless dry_run + unless dry_run + fi.prelude + fi.fetch + end fi + rescue CannotInstallFormulaError => e + ofail e rescue UnsatisfiedRequirements, DownloadError => e ofail "#{formula}: #{e}" nil @@ -159,22 +164,35 @@ def create_formula_installer( def upgrade_formula(formula_installer, dry_run: false, verbose: false) formula = formula_installer.formula - kegs = outdated_kegs(formula) - linked_kegs = kegs.select(&:linked?) - if dry_run print_dry_run_dependencies(formula, formula_installer.compute_dependencies) return end - formula_installer.prelude + formula_installer.check_installation_already_attempted + + install_formula(formula_installer, upgrade: true) + rescue BuildError => e + e.dump(verbose: verbose) + puts + Homebrew.failed = true + end + private_class_method :upgrade_formula + + def install_formula(formula_installer, upgrade:) + formula = formula_installer.formula - print_upgrade_message(formula, formula_installer.options) + if upgrade + print_upgrade_message(formula, formula_installer.options) + + kegs = outdated_kegs(formula) + linked_kegs = kegs.select(&:linked?) + end # first we unlink the currently active keg for this formula otherwise it is # possible for the existing build to interfere with the build we are about to # do! Seriously, it happens! - kegs.each(&:unlink) + kegs.each(&:unlink) if kegs.present? formula_installer.install formula_installer.finish @@ -182,21 +200,14 @@ def upgrade_formula(formula_installer, dry_run: false, verbose: false) # We already attempted to upgrade f as part of the dependency tree of # another formula. In that case, don't generate an error, just move on. nil - rescue CannotInstallFormulaError => e - ofail e - rescue BuildError => e - e.dump(verbose: verbose) - puts - Homebrew.failed = true ensure # restore previous installation state if build failed begin - linked_kegs.each(&:link) unless formula.latest_version_installed? + linked_kegs.each(&:link) if linked_kegs.present? && !f.latest_version_installed? rescue nil end end - private_class_method :upgrade_formula def check_broken_dependents(installed_formulae) CacheStoreDatabase.use(:linkage) do |db|