diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index 0c9a9199a6..fff584325c 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -18,7 +18,7 @@ module Homebrew def update_preinstall_header(args:) @update_preinstall_header ||= begin - ohai_stdout_or_stderr "Auto-updated Homebrew!" if args.preinstall? + ohai "Auto-updated Homebrew!" if args.preinstall? true end end @@ -40,12 +40,20 @@ module Homebrew end def update_report + return output_update_report if $stdout.tty? + + redirect_stdout($stderr) do + output_update_report + end + end + + def output_update_report args = update_report_args.parse # Run `brew update` (again) if we've got a linuxbrew-core CoreTap if CoreTap.instance.installed? && CoreTap.instance.linuxbrew_core? && ENV["HOMEBREW_LINUXBREW_CORE_MIGRATION"].blank? - ohai_stdout_or_stderr "Re-running `brew update` for linuxbrew-core migration" + ohai "Re-running `brew update` for linuxbrew-core migration" if ENV["HOMEBREW_CORE_DEFAULT_GIT_REMOTE"] != ENV["HOMEBREW_CORE_GIT_REMOTE"] opoo <<~EOS @@ -85,8 +93,8 @@ module Homebrew print "\a" # Use an extra newline and bold to avoid this being missed. - ohai_stdout_or_stderr "Homebrew has enabled anonymous aggregate formula and cask analytics." - puts_stdout_or_stderr <<~EOS + ohai "Homebrew has enabled anonymous aggregate formula and cask analytics." + puts <<~EOS #{Tty.bold}Read the analytics documentation (and how to opt-out) here: #{Formatter.url("https://docs.brew.sh/Analytics")}#{Tty.reset} No analytics have been recorded yet (nor will be during this `brew` run). @@ -98,8 +106,8 @@ module Homebrew end if Settings.read("donationmessage") != "true" && !args.quiet? - ohai_stdout_or_stderr "Homebrew is run entirely by unpaid volunteers. Please consider donating:" - puts_stdout_or_stderr " #{Formatter.url("https://github.com/Homebrew/brew#donations")}\n" + ohai "Homebrew is run entirely by unpaid volunteers. Please consider donating:" + puts " #{Formatter.url("https://github.com/Homebrew/brew#donations")}\n" # Consider the message possibly missed if not a TTY. Settings.write "donationmessage", true if $stdout.tty? @@ -116,8 +124,7 @@ module Homebrew if initial_revision != current_revision update_preinstall_header args: args - puts_stdout_or_stderr \ - "Updated Homebrew from #{shorten_revision(initial_revision)} to #{shorten_revision(current_revision)}." + puts "Updated Homebrew from #{shorten_revision(initial_revision)} to #{shorten_revision(current_revision)}." updated = true old_tag = Settings.read "latesttag" @@ -141,7 +148,7 @@ module Homebrew if ENV["HOMEBREW_MIGRATE_LINUXBREW_FORMULAE"].present? && tap.core_tap? && Settings.read("linuxbrewmigrated") != "true" - ohai_stdout_or_stderr "Migrating formulae from linuxbrew-core to homebrew-core" + ohai "Migrating formulae from linuxbrew-core to homebrew-core" LINUXBREW_CORE_MIGRATION_LIST.each do |name| begin @@ -175,14 +182,13 @@ module Homebrew unless updated_taps.empty? update_preinstall_header args: args - puts_stdout_or_stderr \ - "Updated #{updated_taps.count} #{"tap".pluralize(updated_taps.count)} (#{updated_taps.to_sentence})." + puts "Updated #{updated_taps.count} #{"tap".pluralize(updated_taps.count)} (#{updated_taps.to_sentence})." updated = true end if updated if hub.empty? - puts_stdout_or_stderr "No changes to formulae." unless args.quiet? + puts "No changes to formulae." unless args.quiet? else hub.dump(updated_formula_report: !args.preinstall?) unless args.quiet? hub.reporters.each(&:migrate_tap_migration) @@ -209,8 +215,8 @@ module Homebrew msg += "#{Tty.bold}#{outdated_casks}#{Tty.reset} outdated #{"cask".pluralize(outdated_casks)}" end if msg.present? - puts_stdout_or_stderr - puts_stdout_or_stderr <<~EOS + puts + puts <<~EOS You have #{msg} installed. You can upgrade #{update_pronoun} with #{Tty.bold}brew upgrade#{Tty.reset} or list #{update_pronoun} with #{Tty.bold}brew outdated#{Tty.reset}. @@ -218,9 +224,9 @@ module Homebrew end end end - puts_stdout_or_stderr if args.preinstall? + puts if args.preinstall? elsif !args.preinstall? && !ENV["HOMEBREW_UPDATE_FAILED"] && !ENV["HOMEBREW_MIGRATE_LINUXBREW_FORMULAE"] - puts_stdout_or_stderr "Already up-to-date." unless args.quiet? + puts "Already up-to-date." unless args.quiet? end Commands.rebuild_commands_completion_list @@ -242,17 +248,17 @@ module Homebrew return if new_repository_version.blank? - puts_stdout_or_stderr - ohai_stdout_or_stderr "Homebrew was updated to version #{new_repository_version}" + puts + ohai "Homebrew was updated to version #{new_repository_version}" if new_repository_version.split(".").last == "0" Settings.write "latesttag", new_repository_version - puts_stdout_or_stderr <<~EOS + puts <<~EOS More detailed release notes are available on the Homebrew Blog: #{Formatter.url("https://brew.sh/blog/#{new_repository_version}")} EOS elsif !args.quiet? Settings.write "latesttag", new_repository_version - puts_stdout_or_stderr <<~EOS + puts <<~EOS The changelog can be found at: #{Formatter.url("https://github.com/Homebrew/brew/releases/tag/#{new_repository_version}")} EOS @@ -442,13 +448,13 @@ class Reporter new_tap = Tap.fetch(new_tap_name) new_tap.install unless new_tap.installed? - ohai_stdout_or_stderr "#{name} has been moved to Homebrew.", <<~EOS + ohai "#{name} has been moved to Homebrew.", <<~EOS To uninstall the cask, run: brew uninstall --cask --force #{name} EOS next if (HOMEBREW_CELLAR/new_name.split("/").last).directory? - ohai_stdout_or_stderr "Installing #{new_name}..." + ohai "Installing #{new_name}..." system HOMEBREW_BREW_FILE, "install", new_full_name begin unless Formulary.factory(new_full_name).keg_only? @@ -469,12 +475,12 @@ class Reporter # For formulae migrated to cask: Auto-install cask or provide install instructions. if new_tap_name.start_with?("homebrew/cask") if new_tap.installed? && (HOMEBREW_PREFIX/"Caskroom").directory? - ohai_stdout_or_stderr "#{name} has been moved to Homebrew Cask." - ohai_stdout_or_stderr "brew unlink #{name}" + ohai "#{name} has been moved to Homebrew Cask." + ohai "brew unlink #{name}" system HOMEBREW_BREW_FILE, "unlink", name - ohai_stdout_or_stderr "brew cleanup" + ohai "brew cleanup" system HOMEBREW_BREW_FILE, "cleanup" - ohai_stdout_or_stderr "brew install --cask #{new_name}" + ohai "brew install --cask #{new_name}" system HOMEBREW_BREW_FILE, "install", "--cask", new_name ohai <<~EOS #{name} has been moved to Homebrew Cask. @@ -483,7 +489,7 @@ class Reporter brew uninstall --force #{name} EOS else - ohai_stdout_or_stderr "#{name} has been moved to Homebrew Cask.", <<~EOS + ohai "#{name} has been moved to Homebrew Cask.", <<~EOS To uninstall the formula and install the cask, run: brew uninstall --force #{name} brew tap #{new_tap_name} @@ -570,10 +576,7 @@ class ReporterHub dump_formula_report :M, "Updated Formulae" else updated = select_formula(:M).count - if updated.positive? - ohai_stdout_or_stderr "Updated Formulae", - "Updated #{updated} #{"formula".pluralize(updated)}." - end + ohai "Updated Formulae", "Updated #{updated} #{"formula".pluralize(updated)}." if updated.positive? end dump_formula_report :R, "Renamed Formulae" dump_formula_report :D, "Deleted Formulae" @@ -582,10 +585,7 @@ class ReporterHub dump_formula_report :MC, "Updated Casks" else updated = select_formula(:MC).count - if updated.positive? - ohai_stdout_or_stderr "Updated Casks", - "Updated #{updated} #{"cask".pluralize(updated)}." - end + ohai "Updated Casks", "Updated #{updated} #{"cask".pluralize(updated)}." if updated.positive? end dump_formula_report :DC, "Deleted Casks" end diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index 756df0a4ee..12a67c19dc 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -108,10 +108,7 @@ module Homebrew def ensure_relocation_formulae_installed! Keg.relocation_formulae.each do |f| - next if Formula[f].latest_version_installed? - - ohai "Installing #{f}..." - safe_system HOMEBREW_BREW_FILE, "install", f + ensure_formula_installed!(f, latest: true) end end @@ -263,10 +260,7 @@ module Homebrew return default_tar_args end - unless gnu_tar.any_version_installed? - ohai "Installing `gnu-tar` for bottling..." - safe_system HOMEBREW_BREW_FILE, "install", "--formula", gnu_tar.full_name - end + ensure_formula_installed!(gnu_tar, reason: "bottling") ["#{gnu_tar.opt_bin}/gtar", gnutar_args].freeze end diff --git a/Library/Homebrew/dev-cmd/bump.rb b/Library/Homebrew/dev-cmd/bump.rb index 381b777a9f..97f079c32d 100644 --- a/Library/Homebrew/dev-cmd/bump.rb +++ b/Library/Homebrew/dev-cmd/bump.rb @@ -59,8 +59,7 @@ module Homebrew unless Utils::Curl.curl_supports_tls13? begin unless Pathname.new(ENV["HOMEBREW_BREWED_CURL_PATH"]).exist? - ohai "Installing `curl` for Repology queries..." - safe_system HOMEBREW_BREW_FILE, "install", "--formula", Formula["curl"].full_name + ensure_formula_installed!("curl", reason: "Repology queries") end rescue FormulaUnavailableError opoo "A `curl` with TLS 1.3 support is required for Repology queries." diff --git a/Library/Homebrew/dev-cmd/cat.rb b/Library/Homebrew/dev-cmd/cat.rb index c3a8e0ebf8..43d937c62e 100644 --- a/Library/Homebrew/dev-cmd/cat.rb +++ b/Library/Homebrew/dev-cmd/cat.rb @@ -31,18 +31,14 @@ module Homebrew cd HOMEBREW_REPOSITORY pager = if Homebrew::EnvConfig.bat? - require "formula" - - unless Formula["bat"].any_version_installed? + ENV["BAT_CONFIG_PATH"] = Homebrew::EnvConfig.bat_config_path + ensure_formula_installed!( + "bat", + reason: "displaying / source", # The user might want to capture the output of `brew cat ...` # Redirect stdout to stderr - redirect_stdout($stderr) do - ohai "Installing `bat` for displaying / source..." - safe_system HOMEBREW_BREW_FILE, "install", "bat" - end - end - ENV["BAT_CONFIG_PATH"] = Homebrew::EnvConfig.bat_config_path - Formula["bat"].opt_bin/"bat" + output_to_stderr: true, + ).opt_bin/"bat" else "cat" end diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb index 010c7c2f78..7acdf6153a 100644 --- a/Library/Homebrew/dev-cmd/tests.rb +++ b/Library/Homebrew/dev-cmd/tests.rb @@ -48,11 +48,9 @@ module Homebrew def run_buildpulse require "formula" - unless Formula["buildpulse-test-reporter"].any_version_installed? - ohai "Installing `buildpulse-test-reporter` for reporting test flakiness..." - with_env(HOMEBREW_NO_AUTO_UPDATE: "1", HOMEBREW_NO_BOOTSNAP: "1") do - safe_system HOMEBREW_BREW_FILE, "install", "buildpulse-test-reporter" - end + with_env(HOMEBREW_NO_AUTO_UPDATE: "1", HOMEBREW_NO_BOOTSNAP: "1") do + ensure_formula_installed!("buildpulse-test-reporter", + reason: "reporting test flakiness") end ENV["BUILDPULSE_ACCESS_KEY_ID"] = ENV["HOMEBREW_BUILDPULSE_ACCESS_KEY_ID"] diff --git a/Library/Homebrew/github_packages.rb b/Library/Homebrew/github_packages.rb index 4f91d8de9c..d37f4ee048 100644 --- a/Library/Homebrew/github_packages.rb +++ b/Library/Homebrew/github_packages.rb @@ -48,16 +48,7 @@ class GitHubPackages raise UsageError, "HOMEBREW_GITHUB_PACKAGES_USER is unset." if user.blank? raise UsageError, "HOMEBREW_GITHUB_PACKAGES_TOKEN is unset." if token.blank? - skopeo = [ - which("skopeo"), - which("skopeo", ENV["HOMEBREW_PATH"]), - HOMEBREW_PREFIX/"bin/skopeo", - ].compact.first - unless skopeo.exist? - ohai "Installing `skopeo` for upload..." - safe_system HOMEBREW_BREW_FILE, "install", "--formula", "skopeo" - skopeo = Formula["skopeo"].opt_bin/"skopeo" - end + skopeo = ensure_executable!("skopeo", reason: "upload") require "json_schemer" diff --git a/Library/Homebrew/style.rb b/Library/Homebrew/style.rb index 82236000d6..9e3d5bab9a 100644 --- a/Library/Homebrew/style.rb +++ b/Library/Homebrew/style.rb @@ -277,32 +277,13 @@ module Homebrew end def shellcheck - # Always use the latest brewed shellcheck - unless Formula["shellcheck"].latest_version_installed? - if Formula["shellcheck"].any_version_installed? - ohai "Upgrading `shellcheck` for shell style checks..." - safe_system HOMEBREW_BREW_FILE, "upgrade", "shellcheck" - else - ohai "Installing `shellcheck` for shell style checks..." - safe_system HOMEBREW_BREW_FILE, "install", "shellcheck" - end - end - - Formula["shellcheck"].opt_bin/"shellcheck" + ensure_formula_installed!("shellcheck", latest: true, + reason: "shell style checks").opt_bin/"shellcheck" end def shfmt - # Always use the latest brewed shfmt - unless Formula["shfmt"].latest_version_installed? - if Formula["shfmt"].any_version_installed? - ohai "Upgrading `shfmt` to format shell scripts..." - safe_system HOMEBREW_BREW_FILE, "upgrade", "shfmt" - else - ohai "Installing `shfmt` to format shell scripts..." - safe_system HOMEBREW_BREW_FILE, "install", "shfmt" - end - end - + ensure_formula_installed!("shfmt", latest: true, + reason: "formatting shell scripts") HOMEBREW_LIBRARY/"Homebrew/utils/shfmt.sh" end diff --git a/Library/Homebrew/test/utils/git_spec.rb b/Library/Homebrew/test/utils/git_spec.rb index 8b8d1ae6d7..20bc7fddab 100644 --- a/Library/Homebrew/test/utils/git_spec.rb +++ b/Library/Homebrew/test/utils/git_spec.rb @@ -184,7 +184,7 @@ describe Utils::Git do unless ENV["HOMEBREW_TEST_GENERIC_OS"] it "installs git" do expect(described_class).to receive(:available?).and_return(false) - expect(described_class).to receive(:safe_system).with(HOMEBREW_BREW_FILE, "install", "git").and_return(true) + expect(described_class).to receive(:ensure_formula_installed!).with("git") expect(described_class).to receive(:available?).and_return(true) described_class.ensure_installed! diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index ee6d16dfda..efa4abe7fa 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -112,24 +112,6 @@ module Kernel puts sput end - def ohai_stdout_or_stderr(message, *sput) - if $stdout.tty? - ohai(message, *sput) - else - $stderr.puts(ohai_title(message)) - $stderr.puts(sput) - end - end - - def puts_stdout_or_stderr(*message) - message = "\n" if message.empty? - if $stdout.tty? - puts(message) - else - $stderr.puts(message) - end - end - def odebug(title, *sput, always_display: false) debug = if respond_to?(:debug) debug? @@ -454,6 +436,60 @@ module Kernel out.close end + # Ensure the given formula is installed + # This is useful for installing a utility formula (e.g. `shellcheck` for `brew style`) + def ensure_formula_installed!(formula_or_name, reason: "", latest: false, + output_to_stderr: true, quiet: false) + if output_to_stderr || quiet + file = if quiet + File::NULL + else + $stderr + end + # Call this method itself with redirected stdout + redirect_stdout(file) do + return ensure_formula_installed!(formula_or_name, latest: latest, + reason: reason, output_to_stderr: false) + end + end + + require "formula" + + formula = if formula_or_name.is_a?(Formula) + formula_or_name + else + Formula[formula_or_name] + end + + reason = " for #{reason}" if reason.present? + + unless formula.any_version_installed? + ohai "Installing `#{formula.name}`#{reason}..." + safe_system HOMEBREW_BREW_FILE, "install", "--formula", formula.full_name + end + + if latest && !formula.latest_version_installed? + ohai "Upgrading `#{formula.name}`#{reason}..." + safe_system HOMEBREW_BREW_FILE, "upgrade", "--formula", formula.full_name + end + + formula + end + + # Ensure the given executable is exist otherwise install the brewed version + def ensure_executable!(name, formula_name = nil, reason: "") + formula_name ||= name + + executable = [ + which(name), + which(name, ENV["HOMEBREW_PATH"]), + HOMEBREW_PREFIX/"bin/#{name}", + ].compact.first + return executable if executable.exist? + + ensure_formula_installed!(formula_name, reason: reason).opt_bin/name + end + def paths @paths ||= PATH.new(ENV["HOMEBREW_PATH"]).map do |p| File.expand_path(p).chomp("/") diff --git a/Library/Homebrew/utils/git.rb b/Library/Homebrew/utils/git.rb index 17176baf3a..8fbe90de34 100644 --- a/Library/Homebrew/utils/git.rb +++ b/Library/Homebrew/utils/git.rb @@ -94,13 +94,11 @@ module Utils # we cannot install brewed git if homebrew/core is unavailable. if CoreTap.instance.installed? begin - oh1 "Installing #{Formatter.identifier("git")}" - # Otherwise `git` will be installed from source in tests that need it. This is slow # and will also likely fail due to `OS::Linux` and `OS::Mac` being undefined. raise "Refusing to install Git on a generic OS." if ENV["HOMEBREW_TEST_GENERIC_OS"] - safe_system HOMEBREW_BREW_FILE, "install", "git" + ensure_formula_installed!("git") clear_available_cache rescue raise "Git is unavailable"