diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index ee695c1b43..60c272ac9e 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -310,9 +310,7 @@ module Homebrew Install.perform_preinstall_checks_once Install.check_cc_argv(args.cc) - Install.ask_formulae(installed_formulae, args: args) if args.ask? - - Install.install_formulae( + formulae_installer = Install.formula_installers( installed_formulae, installed_on_request: !args.as_dependency?, installed_as_dependency: args.as_dependency?, @@ -338,9 +336,10 @@ module Homebrew skip_link: args.skip_link?, ) - Upgrade.check_installed_dependents( + dependants = Upgrade.dependants( installed_formulae, flags: args.flags_only, + ask: args.ask?, installed_on_request: !args.as_dependency?, force_bottle: args.force_bottle?, build_from_source_formulae: args.build_from_source_formulae, @@ -354,6 +353,28 @@ module Homebrew dry_run: args.dry_run?, ) + # Main block: if asking the user is enabled, show dependency and size information. + Install.ask_formulae(formulae_installer, dependants, args: args) if args.ask? + + Install.install_formulae(formulae_installer, + dry_run: args.dry_run?, + verbose: args.verbose?) + + Upgrade.upgrade_dependents( + dependants, installed_formulae, + flags: args.flags_only, + dry_run: args.dry_run?, + force_bottle: args.force_bottle?, + build_from_source_formulae: args.build_from_source_formulae, + interactive: args.interactive?, + keep_tmp: args.keep_tmp?, + debug_symbols: args.debug_symbols?, + force: args.force?, + debug: args.debug?, + quiet: args.quiet?, + verbose: args.verbose? + ) + Cleanup.periodic_clean!(dry_run: args.dry_run?) Homebrew.messages.display_messages(display_times: args.display_times?) diff --git a/Library/Homebrew/cmd/reinstall.rb b/Library/Homebrew/cmd/reinstall.rb index f6361ec689..e0dd7182dc 100644 --- a/Library/Homebrew/cmd/reinstall.rb +++ b/Library/Homebrew/cmd/reinstall.rb @@ -130,16 +130,13 @@ module Homebrew unless formulae.empty? Install.perform_preinstall_checks_once - # If asking the user is enabled, show dependency and size information. - Install.ask_formulae(formulae, args: args) if args.ask? - - formulae.each do |formula| + install_context = formulae.map do |formula| if formula.pinned? onoe "#{formula.full_name} is pinned. You must unpin it to reinstall." next end Migrator.migrate_if_needed(formula, force: args.force?) - Homebrew::Reinstall.reinstall_formula( + Homebrew::Reinstall.build_install_context( formula, flags: args.flags_only, force_bottle: args.force_bottle?, @@ -153,12 +150,12 @@ module Homebrew verbose: args.verbose?, git: args.git?, ) - Cleanup.install_formula_clean!(formula) end - Upgrade.check_installed_dependents( + dependants = Upgrade.dependants( formulae, flags: args.flags_only, + ask: args.ask?, force_bottle: args.force_bottle?, build_from_source_formulae: args.build_from_source_formulae, interactive: args.interactive?, @@ -169,6 +166,43 @@ module Homebrew quiet: args.quiet?, verbose: args.verbose?, ) + + formulae_installer = install_context.map(&:formula_installer) + + # Main block: if asking the user is enabled, show dependency and size information. + Install.ask_formulae(formulae_installer, dependants, args: args) if args.ask? + + install_context.each do |f| + Homebrew::Reinstall.reinstall_formula( + f, + flags: args.flags_only, + force_bottle: args.force_bottle?, + build_from_source_formulae: args.build_from_source_formulae, + interactive: args.interactive?, + keep_tmp: args.keep_tmp?, + debug_symbols: args.debug_symbols?, + force: args.force?, + debug: args.debug?, + quiet: args.quiet?, + verbose: args.verbose?, + git: args.git?, + ) + Cleanup.install_formula_clean!(f.formula) + end + + Upgrade.upgrade_dependents( + dependants, formulae, + flags: args.flags_only, + force_bottle: args.force_bottle?, + build_from_source_formulae: args.build_from_source_formulae, + interactive: args.interactive?, + keep_tmp: args.keep_tmp?, + debug_symbols: args.debug_symbols?, + force: args.force?, + debug: args.debug?, + quiet: args.quiet?, + verbose: args.verbose? + ) end if casks.any? diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index d1880ea4bd..aa23543312 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -220,10 +220,7 @@ module Homebrew Install.perform_preinstall_checks_once - # Main block: if asking the user is enabled, show dependency and size information. - Install.ask_formulae(formulae_to_install, args: args) if args.ask? - - Upgrade.upgrade_formulae( + formulae_installer = Upgrade.formula_installers( formulae_to_install, flags: args.flags_only, dry_run: args.dry_run?, @@ -239,10 +236,33 @@ module Homebrew verbose: args.verbose?, ) - Upgrade.check_installed_dependents( + dependants = Upgrade.dependants( formulae_to_install, flags: args.flags_only, dry_run: args.dry_run?, + ask: args.ask?, + force_bottle: args.force_bottle?, + build_from_source_formulae: args.build_from_source_formulae, + interactive: args.interactive?, + keep_tmp: args.keep_tmp?, + debug_symbols: args.debug_symbols?, + force: args.force?, + debug: args.debug?, + quiet: args.quiet?, + verbose: args.verbose?, + ) + + # Main block: if asking the user is enabled, show dependency and size information. + Install.ask_formulae(formulae_installer, dependants, args: args) if args.ask? + + Upgrade.upgrade_formulae(formulae_installer, + dry_run: args.dry_run?, + verbose: args.verbose?) + + Upgrade.upgrade_dependents( + dependants, formulae_to_install, + flags: args.flags_only, + dry_run: args.dry_run?, force_bottle: args.force_bottle?, build_from_source_formulae: args.build_from_source_formulae, interactive: args.interactive?, @@ -251,7 +271,7 @@ module Homebrew force: args.force?, debug: args.debug?, quiet: args.quiet?, - verbose: args.verbose?, + verbose: args.verbose? ) true diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 7b20a26dfc..ac85783f92 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -3207,11 +3207,11 @@ class Formula patchlist.select(&:external?).each(&:fetch) end - sig { void } - def fetch_bottle_tab + sig { params(quiet: T::Boolean).void } + def fetch_bottle_tab(quiet: false) return unless bottled? - T.must(bottle).fetch_tab + T.must(bottle).fetch_tab(quiet: quiet) end sig { returns(T::Hash[String, T.untyped]) } diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 691abffc19..241863355f 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -1356,12 +1356,12 @@ on_request: installed_on_request?, options:) end end - sig { void } - def fetch_bottle_tab + sig { params(quiet: T::Boolean).void } + def fetch_bottle_tab(quiet: false) return if @fetch_bottle_tab begin - formula.fetch_bottle_tab + formula.fetch_bottle_tab(quiet: quiet) @bottle_tab_runtime_dependencies = formula.bottle_tab_attributes .fetch("runtime_dependencies", []).then { |deps| deps || [] } .each_with_object({}) { |dep, h| h[dep["full_name"]] = dep } diff --git a/Library/Homebrew/install.rb b/Library/Homebrew/install.rb index 7c614bcab1..48b9acb362 100644 --- a/Library/Homebrew/install.rb +++ b/Library/Homebrew/install.rb @@ -231,7 +231,7 @@ module Homebrew false end - def install_formulae( + def formula_installers( formulae_to_install, installed_on_request: true, installed_as_dependency: false, @@ -256,11 +256,11 @@ module Homebrew skip_post_install: false, skip_link: false ) - formula_installers = formulae_to_install.filter_map do |formula| + formulae_to_install.filter_map do |formula| Migrator.migrate_if_needed(formula, force:, dry_run:) build_options = formula.build - formula_installer = FormulaInstaller.new( + FormulaInstaller.new( formula, options: build_options.used_options, installed_on_request:, @@ -285,24 +285,36 @@ module Homebrew skip_post_install:, skip_link:, ) - - begin - unless dry_run - formula_installer.prelude - formula_installer.fetch - end - formula_installer - rescue CannotInstallFormulaError => e - ofail e.message - nil - rescue UnsatisfiedRequirements, DownloadError, ChecksumMismatchError => e - ofail "#{formula}: #{e}" - nil - end end + end + def install_formulae( + formula_installers, + installed_on_request: true, + installed_as_dependency: false, + build_bottle: false, + force_bottle: false, + bottle_arch: nil, + ignore_deps: false, + only_deps: false, + include_test_formulae: [], + build_from_source_formulae: [], + cc: nil, + git: false, + interactive: false, + keep_tmp: false, + debug_symbols: false, + force: false, + overwrite: false, + debug: false, + quiet: false, + verbose: false, + dry_run: false, + skip_post_install: false, + skip_link: false + ) if dry_run - if (formulae_name_to_install = formulae_to_install.map(&:name)) + if (formulae_name_to_install = formula_installers.map(&:name)) ohai "Would install #{Utils.pluralize("formula", formulae_name_to_install.count, plural: "e", include_count: true)}:" puts formulae_name_to_install.join(" ") @@ -315,6 +327,18 @@ module Homebrew end formula_installers.each do |fi| + begin + unless dry_run + fi.prelude + fi.fetch + end + rescue CannotInstallFormulaError => e + ofail e.message + next + rescue UnsatisfiedRequirements, DownloadError, ChecksumMismatchError => e + ofail "#{formula}: #{e}" + next + end install_formula(fi) Cleanup.install_formula_clean!(fi.formula) end @@ -330,16 +354,17 @@ module Homebrew end # If asking the user is enabled, show dependency and size information. - def ask_formulae(formulae, args:) - return if formulae.empty? + def ask_formulae(formulae_installer, dependants, args:) + return if formulae_installer.empty? + + formulae = collect_dependencies(formulae_installer, dependants) ohai "Looking for bottles..." - sized_formulae = compute_sized_formulae(formulae, args: args) - sizes = compute_total_sizes(sized_formulae, debug: args.debug?) + sizes = compute_total_sizes(formulae, debug: args.debug?) - puts "#{::Utils.pluralize("Formula", sized_formulae.count, plural: "e")} \ -(#{sized_formulae.count}): #{sized_formulae.join(", ")}\n\n" + puts "#{::Utils.pluralize("Formula", formulae.count, plural: "e")} \ +(#{formulae.count}): #{formulae.join(", ")}\n\n" puts "Download Size: #{disk_usage_readable(sizes[:download])}" puts "Install Size: #{disk_usage_readable(sizes[:installed])}" puts "Net Install Size: #{disk_usage_readable(sizes[:net])}" if sizes[:net] != 0 @@ -411,41 +436,6 @@ module Homebrew end end - # Build a unique list of formulae to size by including: - # 1. The original formulae to install. - # 2. Their outdated dependents (subject to pruning criteria). - # 3. Optionally, any installed formula that depends on one of these and is outdated. - def compute_sized_formulae(formulae, args:) - sized_formulae = formulae.flat_map do |formula| - # Always include the formula itself. - formula_list = [formula] - - deps = args.build_from_source? ? formula.deps.build : formula.deps.required - - outdated_dependents = deps.map(&:to_formula).reject(&:pinned?).select do |dep| - dep.installed_kegs.empty? || (dep.bottled? && dep.outdated?) - end - deps.map(&:to_formula).each do |f| - outdated_dependents.concat(f.recursive_dependencies.map(&:to_formula).reject(&:pinned?).select do |dep| - dep.installed_kegs.empty? || (dep.bottled? && dep.outdated?) - end) - end - formula_list.concat(outdated_dependents) - - formula_list - end - - # Add any installed formula that depends on one of the sized formulae and is outdated. - unless Homebrew::EnvConfig.no_installed_dependents_check? - sized_formulae.concat(Formula.installed.select do |installed_formula| - installed_formula.bottled? && installed_formula.outdated? && - installed_formula.deps.required.map(&:to_formula).intersect?(sized_formulae) - end) - end - - sized_formulae.uniq(&:to_s).compact - end - # Compute the total sizes (download, installed, and net) for the given formulae. def compute_total_sizes(sized_formulae, debug: false) total_download_size = 0 @@ -471,6 +461,16 @@ module Homebrew installed: total_installed_size, net: total_net_size } end + + def collect_dependencies(formulae_installer, dependants) + formulae_dependencies = formulae_installer.flat_map do |f| + [f.formula, f.compute_dependencies.flatten.filter do |c| + c.is_a? Dependency + end.flat_map(&:to_formula)] + end.flatten.uniq + formulae_dependencies.concat(dependants.upgradeable) if dependants&.upgradeable + formulae_dependencies + end end end end diff --git a/Library/Homebrew/reinstall.rb b/Library/Homebrew/reinstall.rb index b8260b1116..4d5ff2485c 100644 --- a/Library/Homebrew/reinstall.rb +++ b/Library/Homebrew/reinstall.rb @@ -7,7 +7,9 @@ require "messages" module Homebrew module Reinstall - def self.reinstall_formula( + # struct to keep context of the current installer, keg, formula and option + InstallationContext = Struct.new(:formula_installer, :keg, :formula, :options) + def self.build_install_context( formula, flags:, force_bottle: false, @@ -61,16 +63,38 @@ module Homebrew verbose:, }.compact, ) - fi.prelude - fi.fetch + InstallationContext.new(fi, keg, formula, options) + end + + def self.reinstall_formula( + install_context, + flags:, + force_bottle: false, + build_from_source_formulae: [], + interactive: false, + keep_tmp: false, + debug_symbols: false, + force: false, + debug: false, + quiet: false, + verbose: false, + git: false + ) + formula_installer = install_context.formula_installer + keg = install_context.keg + formula = install_context.formula + options = install_context.options + link_keg = keg.linked? + formula_installer.prelude + formula_installer.fetch oh1 "Reinstalling #{Formatter.identifier(formula.full_name)} #{options.to_a.join " "}" - fi.install - fi.finish + formula_installer.install + formula_installer.finish rescue FormulaInstallationAlreadyAttemptedError nil - # Any other exceptions we want to restore the previous keg and report the error. + # Any other exceptions we want to restore the previous keg and report the error. rescue Exception # rubocop:disable Lint/RescueException ignore_interrupts { restore_backup(keg, link_keg, verbose:) } raise diff --git a/Library/Homebrew/test/cmd/install_spec.rb b/Library/Homebrew/test/cmd/install_spec.rb index ef74f06cc3..1e8d70948d 100644 --- a/Library/Homebrew/test/cmd/install_spec.rb +++ b/Library/Homebrew/test/cmd/install_spec.rb @@ -95,34 +95,4 @@ RSpec.describe Homebrew::Cmd::InstallCmd do expect(HOMEBREW_CELLAR/"testball1/0.1/bin/test").to be_a_file end - - it "installs with asking for user prompts with installed dependent checks", :integration_test do - setup_test_formula "testball1", <<~RUBY - depends_on "testball5" - # should work as its not building but test doesnt pass if dependant - # depends_on "build" => :build - depends_on "installed" - RUBY - setup_test_formula "installed" - setup_test_formula "testball5", <<~RUBY - depends_on "testball4" - RUBY - setup_test_formula "testball4", "" - setup_test_formula "hiop" - setup_test_formula "build" - - # Mock `Formula#any_version_installed?` by creating the tab in a plausible keg directory - keg_dir = HOMEBREW_CELLAR/"installed"/"1.0" - keg_dir.mkpath - touch keg_dir/AbstractTab::FILENAME - - expect do - brew "install", "--ask", "testball1" - end.to output(/.*Formulae\s*\(3\):\s*testball1\s*,?\s*testball5\s*,?\s*testball4.*/).to_stdout - .and not_to_output.to_stderr - - expect(HOMEBREW_CELLAR/"testball1/0.1/bin/test").to be_a_file - expect(HOMEBREW_CELLAR/"testball4/0.1/bin/testball4").to be_a_file - expect(HOMEBREW_CELLAR/"testball5/0.1/bin/testball5").to be_a_file - end end diff --git a/Library/Homebrew/test/cmd/upgrade_spec.rb b/Library/Homebrew/test/cmd/upgrade_spec.rb index 59918aaf02..cc82c242c4 100644 --- a/Library/Homebrew/test/cmd/upgrade_spec.rb +++ b/Library/Homebrew/test/cmd/upgrade_spec.rb @@ -28,48 +28,4 @@ RSpec.describe Homebrew::Cmd::UpgradeCmd do expect(HOMEBREW_CELLAR/"testball/0.1").to be_a_directory expect(HOMEBREW_CELLAR/"testball/0.0.1").not_to exist end - - it "upgrades with asking for user prompts with dependants checks", :integration_test do - setup_test_formula "testball", <<~RUBY - depends_on "testball5" - # should work as its not building but test doesnt pass if dependant - # depends_on "build" => :build - depends_on "installed" - RUBY - setup_test_formula "installed" - setup_test_formula "testball5", <<~RUBY - depends_on "testball4" - RUBY - setup_test_formula "testball4" - setup_test_formula "hiop" - setup_test_formula "build" - - (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath - (HOMEBREW_CELLAR/"testball5/0.0.1/foo").mkpath - (HOMEBREW_CELLAR/"testball4/0.0.1/foo").mkpath - - keg_dir = HOMEBREW_CELLAR/"installed"/"1.0" - keg_dir.mkpath - touch keg_dir/AbstractTab::FILENAME - - regex = / - Formulae\s*\(3\):\s* - (testball|testball5|testball4) - \s*,\s* - ((?!\1)testball|testball5|testball4) - \s*,\s* - ((?!\1|\2)testball|testball5|testball4) - /x - expect do - brew "upgrade", "--ask" - end.to output(regex) - .to_stdout.and not_to_output.to_stderr - - expect(HOMEBREW_CELLAR/"testball/0.1").to be_a_directory - expect(HOMEBREW_CELLAR/"testball/0.0.1").not_to exist - expect(HOMEBREW_CELLAR/"testball5/0.1").to be_a_directory - expect(HOMEBREW_CELLAR/"testball5/0.0.1").not_to exist - expect(HOMEBREW_CELLAR/"testball4/0.1").to be_a_directory - expect(HOMEBREW_CELLAR/"testball4/0.0.1").not_to exist - end end diff --git a/Library/Homebrew/test/support/fixtures/tarballs/testball4-0.1-linux.tbz b/Library/Homebrew/test/support/fixtures/tarballs/testball4-0.1-linux.tbz deleted file mode 100644 index 72957a4c13..0000000000 Binary files a/Library/Homebrew/test/support/fixtures/tarballs/testball4-0.1-linux.tbz and /dev/null differ diff --git a/Library/Homebrew/test/support/fixtures/tarballs/testball4-0.1.tbz b/Library/Homebrew/test/support/fixtures/tarballs/testball4-0.1.tbz deleted file mode 100644 index c7c57aee5f..0000000000 Binary files a/Library/Homebrew/test/support/fixtures/tarballs/testball4-0.1.tbz and /dev/null differ diff --git a/Library/Homebrew/test/support/fixtures/tarballs/testball5-0.1-linux.tbz b/Library/Homebrew/test/support/fixtures/tarballs/testball5-0.1-linux.tbz deleted file mode 100644 index 4d35e20d2b..0000000000 Binary files a/Library/Homebrew/test/support/fixtures/tarballs/testball5-0.1-linux.tbz and /dev/null differ diff --git a/Library/Homebrew/test/support/fixtures/tarballs/testball5-0.1.tbz b/Library/Homebrew/test/support/fixtures/tarballs/testball5-0.1.tbz deleted file mode 100644 index 06def51fbd..0000000000 Binary files a/Library/Homebrew/test/support/fixtures/tarballs/testball5-0.1.tbz and /dev/null differ diff --git a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb index e402974813..6c24f3635e 100644 --- a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb +++ b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb @@ -135,21 +135,13 @@ RSpec.shared_context "integration test" do # rubocop:disable RSpec/ContextWordin bottle_block: nil, tab_attributes: nil) case name when /^testball/ - case name - when "testball4", "testball5" - prefix = name - program_name = name - when "testball2" - prefix = name - program_name = "test" + # Use a different tarball for testball2 to avoid lock errors when writing concurrency tests + prefix = (name == "testball2") ? "testball2" : "testball" + tarball = if OS.linux? + TEST_FIXTURE_DIR/"tarballs/#{prefix}-0.1-linux.tbz" else - prefix = "testball" - program_name = "test" + TEST_FIXTURE_DIR/"tarballs/#{prefix}-0.1.tbz" end - - tarball_name = "#{prefix}-0.1#{"-linux" if OS.linux?}.tbz" - tarball = TEST_FIXTURE_DIR / "tarballs/#{tarball_name}" - content = <<~RUBY desc "Some test" homepage "https://brew.sh/#{name}" @@ -159,12 +151,12 @@ RSpec.shared_context "integration test" do # rubocop:disable RSpec/ContextWordin option "with-foo", "Build with foo" #{bottle_block} def install - (prefix/"foo"/"#{program_name}").write("#{program_name}") if build.with? "foo" + (prefix/"foo"/"test").write("test") if build.with? "foo" prefix.install Dir["*"] - (buildpath/"#{program_name}.c").write \ - "#include \\nint main(){printf(\\"#{program_name}\\");return 0;}" + (buildpath/"test.c").write \ + "#include \\nint main(){printf(\\"test\\");return 0;}" bin.mkpath - system ENV.cc, "#{program_name}.c", "-o", bin/"#{program_name}" + system ENV.cc, "test.c", "-o", bin/"test" end #{content} diff --git a/Library/Homebrew/upgrade.rb b/Library/Homebrew/upgrade.rb index 112893aac1..fa7bcf7c1f 100644 --- a/Library/Homebrew/upgrade.rb +++ b/Library/Homebrew/upgrade.rb @@ -11,7 +11,9 @@ require "utils/topological_hash" module Homebrew # Helper functions for upgrading formulae. module Upgrade - def self.upgrade_formulae( + Dependents = Struct.new(:upgradeable, :pinned, :skipped) + + def self.formula_installers( formulae_to_install, flags:, dry_run: false, @@ -48,7 +50,7 @@ module Homebrew raise CyclicDependencyError, dependency_graph.strongly_connected_components if Homebrew::EnvConfig.developer? end - formula_installers = formulae_to_install.filter_map do |formula| + formulae_to_install.filter_map do |formula| Migrator.migrate_if_needed(formula, force:, dry_run:) begin fi = create_formula_installer( @@ -65,18 +67,19 @@ module Homebrew quiet:, verbose:, ) - unless dry_run - fi.prelude + fi.fetch_bottle_tab(quiet: !debug) + all_runtime_deps_installed = fi.bottle_tab_runtime_dependencies.presence&.all? do |dependency, hash| + minimum_version = Version.new(hash["version"]) if hash["version"].present? + Dependency.new(dependency).installed?(minimum_version:, minimum_revision: hash["revision"]) + end + + if !dry_run && dependents && all_runtime_deps_installed # Don't need to install this bottle if all of the runtime # dependencies have the same or newer version already installed. - next if dependents && fi.bottle_tab_runtime_dependencies.presence&.all? do |dependency, hash| - minimum_version = Version.new(hash["version"]) if hash["version"].present? - Dependency.new(dependency).installed?(minimum_version:, minimum_revision: hash["revision"]) - end - - fi.fetch + next end + fi rescue CannotInstallFormulaError => e ofail e @@ -86,6 +89,19 @@ module Homebrew nil end end + end + + def self.upgrade_formulae(formula_installers, dry_run: false, verbose: false) + unless dry_run + formula_installers.each do |fi| + fi.prelude + fi.fetch + rescue CannotInstallFormulaError => e + ofail e + rescue UnsatisfiedRequirements, DownloadError => e + ofail "#{fi.formula.full_name}: #{e}" + end + end formula_installers.each do |fi| upgrade_formula(fi, dry_run:, verbose:) @@ -250,10 +266,11 @@ module Homebrew @puts_no_installed_dependents_check_disable_message_if_not_already = true end - def self.check_installed_dependents( + def self.dependants( formulae, flags:, dry_run: false, + ask: false, installed_on_request: false, force_bottle: false, build_from_source_formulae: [], @@ -274,35 +291,26 @@ module Homebrew end return end + formulae_to_install = formulae.dup + formulae_to_install.reject! { |f| f.core_formula? && f.versioned_formula? } + return if formulae_to_install.empty? - installed_formulae = (dry_run ? formulae : FormulaInstaller.installed.to_a).dup - installed_formulae.reject! { |f| f.core_formula? && f.versioned_formula? } - return if installed_formulae.empty? - - already_broken_dependents = check_broken_dependents(installed_formulae) + already_broken_dependents = check_broken_dependents(formulae_to_install) # TODO: this should be refactored to use FormulaInstaller new logic outdated_dependents = - installed_formulae.flat_map(&:runtime_installed_formula_dependents) - .uniq - .select(&:outdated?) + formulae_to_install.flat_map(&:runtime_installed_formula_dependents) + .uniq + .select(&:outdated?) # Ensure we never attempt a source build for outdated dependents of upgraded formulae. outdated_dependents, skipped_dependents = outdated_dependents.partition do |dependent| dependent.bottled? && dependent.deps.map(&:to_formula).all?(&:bottled?) end - if skipped_dependents.present? - opoo <<~EOS - The following dependents of upgraded formulae are outdated but will not - be upgraded because they are not bottled: - #{skipped_dependents * "\n "} - EOS - end - return if outdated_dependents.blank? && already_broken_dependents.blank? - outdated_dependents -= installed_formulae if dry_run + outdated_dependents -= formulae_to_install if dry_run upgradeable_dependents = outdated_dependents.reject(&:pinned?) @@ -311,24 +319,52 @@ module Homebrew outdated_dependents.select(&:pinned?) .sort { |a, b| depends_on(a, b) } - if pinned_dependents.present? - plural = Utils.pluralize("dependent", pinned_dependents.count) - opoo "Not upgrading #{pinned_dependents.count} pinned #{plural}:" - puts(pinned_dependents.map do |f| + Dependents.new(upgradeable_dependents, pinned_dependents, skipped_dependents) + end + + def self.upgrade_dependents(deps, formulae, + flags:, + dry_run: false, + installed_on_request: false, + force_bottle: false, + build_from_source_formulae: [], + interactive: false, + keep_tmp: false, + debug_symbols: false, + force: false, + debug: false, + quiet: false, + verbose: false) + return if deps.blank? + + upgradeable = deps.upgradeable + pinned = deps.pinned + skipped = deps.skipped + if pinned.present? + plural = Utils.pluralize("dependent", pinned.count) + opoo "Not upgrading #{pinned.count} pinned #{plural}:" + puts(pinned.map do |f| "#{f.full_specified_name} #{f.pkg_version}" end.join(", ")) end - + if skipped.present? + opoo <<~EOS + The following dependents of upgraded formulae are outdated but will not + be upgraded because they are not bottled: + #{skipped * "\n "} + EOS + end # Print the upgradable dependents. - if upgradeable_dependents.blank? + if upgradeable.blank? ohai "No outdated dependents to upgrade!" unless dry_run else + installed_formulae = (dry_run ? formulae : FormulaInstaller.installed.to_a).dup formula_plural = Utils.pluralize("formula", installed_formulae.count, plural: "e") upgrade_verb = dry_run ? "Would upgrade" : "Upgrading" - ohai "#{upgrade_verb} #{Utils.pluralize("dependent", upgradeable_dependents.count, + ohai "#{upgrade_verb} #{Utils.pluralize("dependent", upgradeable.count, include_count: true)} of upgraded #{formula_plural}:" Upgrade.puts_no_installed_dependents_check_disable_message_if_not_already! - formulae_upgrades = upgradeable_dependents.map do |f| + formulae_upgrades = upgradeable.map do |f| name = f.full_specified_name if f.optlinked? "#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}" @@ -340,8 +376,8 @@ module Homebrew end unless dry_run - upgrade_formulae( - upgradeable_dependents, + dependent_installers = formula_installers( + upgradeable, flags:, force_bottle:, build_from_source_formulae:, @@ -354,6 +390,9 @@ module Homebrew quiet:, verbose:, ) + puts "here", dependent_installers + puts "here", upgradeable + upgrade_formulae(dependent_installers, dry_run: dry_run, verbose: verbose) end # Update installed formulae after upgrading @@ -409,7 +448,7 @@ module Homebrew return if dry_run reinstallable_broken_dependents.each do |formula| - Reinstall.reinstall_formula( + formula_installer = Reinstall.build_install_context( formula, flags:, force_bottle:, @@ -422,6 +461,19 @@ module Homebrew quiet:, verbose:, ) + Reinstall.reinstall_formula( + formula_installer, + flags:, + force_bottle:, + build_from_source_formulae:, + interactive:, + keep_tmp:, + debug_symbols:, + force:, + debug:, + quiet:, + verbose:, + ) rescue FormulaInstallationAlreadyAttemptedError # We already attempted to reinstall f as part of the dependency tree of # another formula. In that case, don't generate an error, just move on.