Merge pull request #12469 from XuehaiPan/ensure-installed

utils: add method `ensure_formula_installed!`
This commit is contained in:
Mike McQuaid 2021-11-23 17:33:37 +00:00 committed by GitHub
commit 7c4247eec9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 108 additions and 115 deletions

View File

@ -18,7 +18,7 @@ module Homebrew
def update_preinstall_header(args:) def update_preinstall_header(args:)
@update_preinstall_header ||= begin @update_preinstall_header ||= begin
ohai_stdout_or_stderr "Auto-updated Homebrew!" if args.preinstall? ohai "Auto-updated Homebrew!" if args.preinstall?
true true
end end
end end
@ -40,12 +40,20 @@ module Homebrew
end end
def update_report 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 args = update_report_args.parse
# Run `brew update` (again) if we've got a linuxbrew-core CoreTap # Run `brew update` (again) if we've got a linuxbrew-core CoreTap
if CoreTap.instance.installed? && CoreTap.instance.linuxbrew_core? && if CoreTap.instance.installed? && CoreTap.instance.linuxbrew_core? &&
ENV["HOMEBREW_LINUXBREW_CORE_MIGRATION"].blank? 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"] if ENV["HOMEBREW_CORE_DEFAULT_GIT_REMOTE"] != ENV["HOMEBREW_CORE_GIT_REMOTE"]
opoo <<~EOS opoo <<~EOS
@ -85,8 +93,8 @@ module Homebrew
print "\a" print "\a"
# Use an extra newline and bold to avoid this being missed. # Use an extra newline and bold to avoid this being missed.
ohai_stdout_or_stderr "Homebrew has enabled anonymous aggregate formula and cask analytics." ohai "Homebrew has enabled anonymous aggregate formula and cask analytics."
puts_stdout_or_stderr <<~EOS puts <<~EOS
#{Tty.bold}Read the analytics documentation (and how to opt-out) here: #{Tty.bold}Read the analytics documentation (and how to opt-out) here:
#{Formatter.url("https://docs.brew.sh/Analytics")}#{Tty.reset} #{Formatter.url("https://docs.brew.sh/Analytics")}#{Tty.reset}
No analytics have been recorded yet (nor will be during this `brew` run). No analytics have been recorded yet (nor will be during this `brew` run).
@ -98,8 +106,8 @@ module Homebrew
end end
if Settings.read("donationmessage") != "true" && !args.quiet? if Settings.read("donationmessage") != "true" && !args.quiet?
ohai_stdout_or_stderr "Homebrew is run entirely by unpaid volunteers. Please consider donating:" ohai "Homebrew is run entirely by unpaid volunteers. Please consider donating:"
puts_stdout_or_stderr " #{Formatter.url("https://github.com/Homebrew/brew#donations")}\n" puts " #{Formatter.url("https://github.com/Homebrew/brew#donations")}\n"
# Consider the message possibly missed if not a TTY. # Consider the message possibly missed if not a TTY.
Settings.write "donationmessage", true if $stdout.tty? Settings.write "donationmessage", true if $stdout.tty?
@ -116,8 +124,7 @@ module Homebrew
if initial_revision != current_revision if initial_revision != current_revision
update_preinstall_header args: args update_preinstall_header args: args
puts_stdout_or_stderr \ puts "Updated Homebrew from #{shorten_revision(initial_revision)} to #{shorten_revision(current_revision)}."
"Updated Homebrew from #{shorten_revision(initial_revision)} to #{shorten_revision(current_revision)}."
updated = true updated = true
old_tag = Settings.read "latesttag" old_tag = Settings.read "latesttag"
@ -141,7 +148,7 @@ module Homebrew
if ENV["HOMEBREW_MIGRATE_LINUXBREW_FORMULAE"].present? && tap.core_tap? && if ENV["HOMEBREW_MIGRATE_LINUXBREW_FORMULAE"].present? && tap.core_tap? &&
Settings.read("linuxbrewmigrated") != "true" 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| LINUXBREW_CORE_MIGRATION_LIST.each do |name|
begin begin
@ -175,14 +182,13 @@ module Homebrew
unless updated_taps.empty? unless updated_taps.empty?
update_preinstall_header args: args update_preinstall_header args: args
puts_stdout_or_stderr \ puts "Updated #{updated_taps.count} #{"tap".pluralize(updated_taps.count)} (#{updated_taps.to_sentence})."
"Updated #{updated_taps.count} #{"tap".pluralize(updated_taps.count)} (#{updated_taps.to_sentence})."
updated = true updated = true
end end
if updated if updated
if hub.empty? if hub.empty?
puts_stdout_or_stderr "No changes to formulae." unless args.quiet? puts "No changes to formulae." unless args.quiet?
else else
hub.dump(updated_formula_report: !args.preinstall?) unless args.quiet? hub.dump(updated_formula_report: !args.preinstall?) unless args.quiet?
hub.reporters.each(&:migrate_tap_migration) hub.reporters.each(&:migrate_tap_migration)
@ -209,8 +215,8 @@ module Homebrew
msg += "#{Tty.bold}#{outdated_casks}#{Tty.reset} outdated #{"cask".pluralize(outdated_casks)}" msg += "#{Tty.bold}#{outdated_casks}#{Tty.reset} outdated #{"cask".pluralize(outdated_casks)}"
end end
if msg.present? if msg.present?
puts_stdout_or_stderr puts
puts_stdout_or_stderr <<~EOS puts <<~EOS
You have #{msg} installed. You have #{msg} installed.
You can upgrade #{update_pronoun} with #{Tty.bold}brew upgrade#{Tty.reset} You can upgrade #{update_pronoun} with #{Tty.bold}brew upgrade#{Tty.reset}
or list #{update_pronoun} with #{Tty.bold}brew outdated#{Tty.reset}. or list #{update_pronoun} with #{Tty.bold}brew outdated#{Tty.reset}.
@ -218,9 +224,9 @@ module Homebrew
end end
end 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"] 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 end
Commands.rebuild_commands_completion_list Commands.rebuild_commands_completion_list
@ -242,17 +248,17 @@ module Homebrew
return if new_repository_version.blank? return if new_repository_version.blank?
puts_stdout_or_stderr puts
ohai_stdout_or_stderr "Homebrew was updated to version #{new_repository_version}" ohai "Homebrew was updated to version #{new_repository_version}"
if new_repository_version.split(".").last == "0" if new_repository_version.split(".").last == "0"
Settings.write "latesttag", new_repository_version Settings.write "latesttag", new_repository_version
puts_stdout_or_stderr <<~EOS puts <<~EOS
More detailed release notes are available on the Homebrew Blog: More detailed release notes are available on the Homebrew Blog:
#{Formatter.url("https://brew.sh/blog/#{new_repository_version}")} #{Formatter.url("https://brew.sh/blog/#{new_repository_version}")}
EOS EOS
elsif !args.quiet? elsif !args.quiet?
Settings.write "latesttag", new_repository_version Settings.write "latesttag", new_repository_version
puts_stdout_or_stderr <<~EOS puts <<~EOS
The changelog can be found at: The changelog can be found at:
#{Formatter.url("https://github.com/Homebrew/brew/releases/tag/#{new_repository_version}")} #{Formatter.url("https://github.com/Homebrew/brew/releases/tag/#{new_repository_version}")}
EOS EOS
@ -442,13 +448,13 @@ class Reporter
new_tap = Tap.fetch(new_tap_name) new_tap = Tap.fetch(new_tap_name)
new_tap.install unless new_tap.installed? 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: To uninstall the cask, run:
brew uninstall --cask --force #{name} brew uninstall --cask --force #{name}
EOS EOS
next if (HOMEBREW_CELLAR/new_name.split("/").last).directory? 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 system HOMEBREW_BREW_FILE, "install", new_full_name
begin begin
unless Formulary.factory(new_full_name).keg_only? 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. # For formulae migrated to cask: Auto-install cask or provide install instructions.
if new_tap_name.start_with?("homebrew/cask") if new_tap_name.start_with?("homebrew/cask")
if new_tap.installed? && (HOMEBREW_PREFIX/"Caskroom").directory? if new_tap.installed? && (HOMEBREW_PREFIX/"Caskroom").directory?
ohai_stdout_or_stderr "#{name} has been moved to Homebrew Cask." ohai "#{name} has been moved to Homebrew Cask."
ohai_stdout_or_stderr "brew unlink #{name}" ohai "brew unlink #{name}"
system HOMEBREW_BREW_FILE, "unlink", name system HOMEBREW_BREW_FILE, "unlink", name
ohai_stdout_or_stderr "brew cleanup" ohai "brew cleanup"
system HOMEBREW_BREW_FILE, "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 system HOMEBREW_BREW_FILE, "install", "--cask", new_name
ohai <<~EOS ohai <<~EOS
#{name} has been moved to Homebrew Cask. #{name} has been moved to Homebrew Cask.
@ -483,7 +489,7 @@ class Reporter
brew uninstall --force #{name} brew uninstall --force #{name}
EOS EOS
else 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: To uninstall the formula and install the cask, run:
brew uninstall --force #{name} brew uninstall --force #{name}
brew tap #{new_tap_name} brew tap #{new_tap_name}
@ -570,10 +576,7 @@ class ReporterHub
dump_formula_report :M, "Updated Formulae" dump_formula_report :M, "Updated Formulae"
else else
updated = select_formula(:M).count updated = select_formula(:M).count
if updated.positive? ohai "Updated Formulae", "Updated #{updated} #{"formula".pluralize(updated)}." if updated.positive?
ohai_stdout_or_stderr "Updated Formulae",
"Updated #{updated} #{"formula".pluralize(updated)}."
end
end end
dump_formula_report :R, "Renamed Formulae" dump_formula_report :R, "Renamed Formulae"
dump_formula_report :D, "Deleted Formulae" dump_formula_report :D, "Deleted Formulae"
@ -582,10 +585,7 @@ class ReporterHub
dump_formula_report :MC, "Updated Casks" dump_formula_report :MC, "Updated Casks"
else else
updated = select_formula(:MC).count updated = select_formula(:MC).count
if updated.positive? ohai "Updated Casks", "Updated #{updated} #{"cask".pluralize(updated)}." if updated.positive?
ohai_stdout_or_stderr "Updated Casks",
"Updated #{updated} #{"cask".pluralize(updated)}."
end
end end
dump_formula_report :DC, "Deleted Casks" dump_formula_report :DC, "Deleted Casks"
end end

View File

@ -108,10 +108,7 @@ module Homebrew
def ensure_relocation_formulae_installed! def ensure_relocation_formulae_installed!
Keg.relocation_formulae.each do |f| Keg.relocation_formulae.each do |f|
next if Formula[f].latest_version_installed? ensure_formula_installed!(f, latest: true)
ohai "Installing #{f}..."
safe_system HOMEBREW_BREW_FILE, "install", f
end end
end end
@ -263,10 +260,7 @@ module Homebrew
return default_tar_args return default_tar_args
end end
unless gnu_tar.any_version_installed? ensure_formula_installed!(gnu_tar, reason: "bottling")
ohai "Installing `gnu-tar` for bottling..."
safe_system HOMEBREW_BREW_FILE, "install", "--formula", gnu_tar.full_name
end
["#{gnu_tar.opt_bin}/gtar", gnutar_args].freeze ["#{gnu_tar.opt_bin}/gtar", gnutar_args].freeze
end end

View File

@ -59,8 +59,7 @@ module Homebrew
unless Utils::Curl.curl_supports_tls13? unless Utils::Curl.curl_supports_tls13?
begin begin
unless Pathname.new(ENV["HOMEBREW_BREWED_CURL_PATH"]).exist? unless Pathname.new(ENV["HOMEBREW_BREWED_CURL_PATH"]).exist?
ohai "Installing `curl` for Repology queries..." ensure_formula_installed!("curl", reason: "Repology queries")
safe_system HOMEBREW_BREW_FILE, "install", "--formula", Formula["curl"].full_name
end end
rescue FormulaUnavailableError rescue FormulaUnavailableError
opoo "A `curl` with TLS 1.3 support is required for Repology queries." opoo "A `curl` with TLS 1.3 support is required for Repology queries."

View File

@ -31,18 +31,14 @@ module Homebrew
cd HOMEBREW_REPOSITORY cd HOMEBREW_REPOSITORY
pager = if Homebrew::EnvConfig.bat? pager = if Homebrew::EnvConfig.bat?
require "formula" ENV["BAT_CONFIG_PATH"] = Homebrew::EnvConfig.bat_config_path
ensure_formula_installed!(
unless Formula["bat"].any_version_installed? "bat",
reason: "displaying <formula>/<cask> source",
# The user might want to capture the output of `brew cat ...` # The user might want to capture the output of `brew cat ...`
# Redirect stdout to stderr # Redirect stdout to stderr
redirect_stdout($stderr) do output_to_stderr: true,
ohai "Installing `bat` for displaying <formula>/<cask> source..." ).opt_bin/"bat"
safe_system HOMEBREW_BREW_FILE, "install", "bat"
end
end
ENV["BAT_CONFIG_PATH"] = Homebrew::EnvConfig.bat_config_path
Formula["bat"].opt_bin/"bat"
else else
"cat" "cat"
end end

View File

@ -48,11 +48,9 @@ module Homebrew
def run_buildpulse def run_buildpulse
require "formula" require "formula"
unless Formula["buildpulse-test-reporter"].any_version_installed? with_env(HOMEBREW_NO_AUTO_UPDATE: "1", HOMEBREW_NO_BOOTSNAP: "1") do
ohai "Installing `buildpulse-test-reporter` for reporting test flakiness..." ensure_formula_installed!("buildpulse-test-reporter",
with_env(HOMEBREW_NO_AUTO_UPDATE: "1", HOMEBREW_NO_BOOTSNAP: "1") do reason: "reporting test flakiness")
safe_system HOMEBREW_BREW_FILE, "install", "buildpulse-test-reporter"
end
end end
ENV["BUILDPULSE_ACCESS_KEY_ID"] = ENV["HOMEBREW_BUILDPULSE_ACCESS_KEY_ID"] ENV["BUILDPULSE_ACCESS_KEY_ID"] = ENV["HOMEBREW_BUILDPULSE_ACCESS_KEY_ID"]

View File

@ -48,16 +48,7 @@ class GitHubPackages
raise UsageError, "HOMEBREW_GITHUB_PACKAGES_USER is unset." if user.blank? raise UsageError, "HOMEBREW_GITHUB_PACKAGES_USER is unset." if user.blank?
raise UsageError, "HOMEBREW_GITHUB_PACKAGES_TOKEN is unset." if token.blank? raise UsageError, "HOMEBREW_GITHUB_PACKAGES_TOKEN is unset." if token.blank?
skopeo = [ skopeo = ensure_executable!("skopeo", reason: "upload")
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
require "json_schemer" require "json_schemer"

View File

@ -277,32 +277,13 @@ module Homebrew
end end
def shellcheck def shellcheck
# Always use the latest brewed shellcheck ensure_formula_installed!("shellcheck", latest: true,
unless Formula["shellcheck"].latest_version_installed? reason: "shell style checks").opt_bin/"shellcheck"
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"
end end
def shfmt def shfmt
# Always use the latest brewed shfmt ensure_formula_installed!("shfmt", latest: true,
unless Formula["shfmt"].latest_version_installed? reason: "formatting shell scripts")
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
HOMEBREW_LIBRARY/"Homebrew/utils/shfmt.sh" HOMEBREW_LIBRARY/"Homebrew/utils/shfmt.sh"
end end

View File

@ -184,7 +184,7 @@ describe Utils::Git do
unless ENV["HOMEBREW_TEST_GENERIC_OS"] unless ENV["HOMEBREW_TEST_GENERIC_OS"]
it "installs git" do it "installs git" do
expect(described_class).to receive(:available?).and_return(false) 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) expect(described_class).to receive(:available?).and_return(true)
described_class.ensure_installed! described_class.ensure_installed!

View File

@ -112,24 +112,6 @@ module Kernel
puts sput puts sput
end 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) def odebug(title, *sput, always_display: false)
debug = if respond_to?(:debug) debug = if respond_to?(:debug)
debug? debug?
@ -454,6 +436,60 @@ module Kernel
out.close out.close
end 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 def paths
@paths ||= PATH.new(ENV["HOMEBREW_PATH"]).map do |p| @paths ||= PATH.new(ENV["HOMEBREW_PATH"]).map do |p|
File.expand_path(p).chomp("/") File.expand_path(p).chomp("/")

View File

@ -94,13 +94,11 @@ module Utils
# we cannot install brewed git if homebrew/core is unavailable. # we cannot install brewed git if homebrew/core is unavailable.
if CoreTap.instance.installed? if CoreTap.instance.installed?
begin begin
oh1 "Installing #{Formatter.identifier("git")}"
# Otherwise `git` will be installed from source in tests that need it. This is slow # 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. # 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"] 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 clear_available_cache
rescue rescue
raise "Git is unavailable" raise "Git is unavailable"