2020-10-10 14:16:11 +02:00
|
|
|
# typed: true
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-06-05 23:19:18 -04:00
|
|
|
require "diagnostic"
|
|
|
|
require "fileutils"
|
|
|
|
require "hardware"
|
|
|
|
require "development_tools"
|
2021-06-15 10:11:40 -04:00
|
|
|
require "upgrade"
|
2018-06-05 23:19:18 -04:00
|
|
|
|
|
|
|
module Homebrew
|
2020-08-17 18:39:55 +02:00
|
|
|
# Helper module for performing (pre-)install checks.
|
|
|
|
#
|
|
|
|
# @api private
|
2018-06-05 23:19:18 -04:00
|
|
|
module Install
|
2020-07-27 11:37:07 +02:00
|
|
|
module_function
|
|
|
|
|
2020-08-17 18:39:55 +02:00
|
|
|
def perform_preinstall_checks(all_fatal: false, cc: nil)
|
2020-11-12 17:06:47 +00:00
|
|
|
check_prefix
|
2020-08-17 18:39:55 +02:00
|
|
|
check_cpu
|
|
|
|
attempt_directory_creation
|
|
|
|
check_cc_argv(cc)
|
2020-09-11 12:05:22 +01:00
|
|
|
Diagnostic.checks(:supported_configuration_checks, fatal: all_fatal)
|
|
|
|
Diagnostic.checks(:fatal_preinstall_checks)
|
2020-08-17 18:39:55 +02:00
|
|
|
end
|
|
|
|
alias generic_perform_preinstall_checks perform_preinstall_checks
|
|
|
|
module_function :generic_perform_preinstall_checks
|
|
|
|
|
|
|
|
def perform_build_from_source_checks(all_fatal: false)
|
2020-09-11 12:05:22 +01:00
|
|
|
Diagnostic.checks(:fatal_build_from_source_checks)
|
|
|
|
Diagnostic.checks(:build_from_source_checks, fatal: all_fatal)
|
2020-08-17 18:39:55 +02:00
|
|
|
end
|
|
|
|
|
2020-11-12 17:06:47 +00:00
|
|
|
def check_prefix
|
2020-12-22 08:41:49 +00:00
|
|
|
if (Hardware::CPU.intel? || Hardware::CPU.in_rosetta2?) &&
|
|
|
|
HOMEBREW_PREFIX.to_s == HOMEBREW_MACOS_ARM_DEFAULT_PREFIX
|
2021-01-13 21:16:36 -07:00
|
|
|
if Hardware::CPU.in_rosetta2?
|
|
|
|
odie <<~EOS
|
2021-01-25 10:39:29 -07:00
|
|
|
Cannot install under Rosetta 2 in ARM default prefix (#{HOMEBREW_PREFIX})!
|
2021-01-26 10:21:55 +00:00
|
|
|
To rerun under ARM use:
|
2021-01-14 14:26:41 -07:00
|
|
|
arch -arm64 brew install ...
|
2021-01-25 10:39:29 -07:00
|
|
|
To install under x86_64, install Homebrew into #{HOMEBREW_DEFAULT_PREFIX}.
|
2021-01-13 21:16:36 -07:00
|
|
|
EOS
|
2020-12-22 11:28:45 +00:00
|
|
|
else
|
2021-01-14 14:26:41 -07:00
|
|
|
odie "Cannot install on Intel processor in ARM default prefix (#{HOMEBREW_PREFIX})!"
|
2020-12-22 08:41:49 +00:00
|
|
|
end
|
2020-11-12 18:58:03 +00:00
|
|
|
elsif Hardware::CPU.arm? && HOMEBREW_PREFIX.to_s == HOMEBREW_DEFAULT_PREFIX
|
2020-11-12 19:14:46 +00:00
|
|
|
odie <<~EOS
|
|
|
|
Cannot install in Homebrew on ARM processor in Intel default prefix (#{HOMEBREW_PREFIX})!
|
|
|
|
Please create a new installation in #{HOMEBREW_MACOS_ARM_DEFAULT_PREFIX} using one of the
|
|
|
|
"Alternative Installs" from:
|
|
|
|
#{Formatter.url("https://docs.brew.sh/Installation")}
|
|
|
|
You can migrate your previously installed formula list with:
|
|
|
|
brew bundle dump
|
|
|
|
EOS
|
2020-11-12 17:06:47 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-08 19:13:46 +00:00
|
|
|
def check_cpu
|
2020-11-12 17:06:47 +00:00
|
|
|
return unless Hardware::CPU.ppc?
|
|
|
|
|
|
|
|
odie <<~EOS
|
|
|
|
Sorry, Homebrew does not support your computer's CPU architecture!
|
|
|
|
For PowerPC Mac (PPC32/PPC64BE) support, see:
|
|
|
|
#{Formatter.url("https://github.com/mistydemeo/tigerbrew")}
|
|
|
|
EOS
|
2018-06-05 23:19:18 -04:00
|
|
|
end
|
2020-08-17 18:39:55 +02:00
|
|
|
private_class_method :check_cpu
|
2018-06-05 23:19:18 -04:00
|
|
|
|
2018-09-06 18:38:43 +01:00
|
|
|
def attempt_directory_creation
|
2018-09-25 22:03:29 +01:00
|
|
|
Keg::MUST_EXIST_DIRECTORIES.each do |dir|
|
2019-10-13 10:03:26 +01:00
|
|
|
FileUtils.mkdir_p(dir) unless dir.exist?
|
2019-09-17 11:06:48 +02:00
|
|
|
|
2019-10-13 10:03:26 +01:00
|
|
|
# Create these files to ensure that these directories aren't removed
|
|
|
|
# by the Catalina installer.
|
|
|
|
# (https://github.com/Homebrew/brew/issues/6263)
|
|
|
|
keep_file = dir/".keepme"
|
|
|
|
FileUtils.touch(keep_file) unless keep_file.exist?
|
|
|
|
rescue
|
|
|
|
nil
|
2018-06-05 23:19:18 -04:00
|
|
|
end
|
|
|
|
end
|
2020-08-17 18:39:55 +02:00
|
|
|
private_class_method :attempt_directory_creation
|
2018-06-05 23:19:18 -04:00
|
|
|
|
2020-07-27 11:37:07 +02:00
|
|
|
def check_cc_argv(cc)
|
|
|
|
return unless cc
|
2019-01-21 19:23:31 +00:00
|
|
|
|
|
|
|
@checks ||= Diagnostic::Checks.new
|
|
|
|
opoo <<~EOS
|
2020-07-25 21:33:48 +02:00
|
|
|
You passed `--cc=#{cc}`.
|
2019-01-21 19:23:31 +00:00
|
|
|
#{@checks.please_create_pull_requests}
|
|
|
|
EOS
|
2018-09-06 18:38:43 +01:00
|
|
|
end
|
2020-08-17 18:39:55 +02:00
|
|
|
private_class_method :check_cc_argv
|
2021-06-10 10:50:05 -04:00
|
|
|
|
|
|
|
def install_formula?(
|
|
|
|
f,
|
|
|
|
head: false,
|
|
|
|
fetch_head: false,
|
|
|
|
only_dependencies: false,
|
|
|
|
force: false,
|
|
|
|
quiet: false
|
|
|
|
)
|
|
|
|
# head-only without --HEAD is an error
|
|
|
|
if !head && f.stable.nil?
|
|
|
|
odie <<~EOS
|
|
|
|
#{f.full_name} is a head-only formula.
|
|
|
|
To install it, run:
|
|
|
|
brew install --HEAD #{f.full_name}
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
|
|
|
# --HEAD, fail with no head defined
|
|
|
|
odie "No head is defined for #{f.full_name}" if head && f.head.nil?
|
|
|
|
|
|
|
|
installed_head_version = f.latest_head_version
|
|
|
|
if installed_head_version &&
|
|
|
|
!f.head_version_outdated?(installed_head_version, fetch_head: fetch_head)
|
|
|
|
new_head_installed = true
|
|
|
|
end
|
|
|
|
prefix_installed = f.prefix.exist? && !f.prefix.children.empty?
|
|
|
|
|
2021-06-10 11:39:20 -04:00
|
|
|
if f.keg_only? && f.any_version_installed? && f.optlinked? && !force
|
2021-06-10 10:50:05 -04:00
|
|
|
# keg-only install is only possible when no other version is
|
|
|
|
# linked to opt, because installing without any warnings can break
|
|
|
|
# dependencies. Therefore before performing other checks we need to be
|
|
|
|
# sure --force flag is passed.
|
|
|
|
if f.outdated?
|
2022-01-13 23:57:51 +08:00
|
|
|
if !Homebrew::EnvConfig.no_install_upgrade? && !f.pinned?
|
2021-11-25 09:10:59 +00:00
|
|
|
puts "#{f.name} #{f.linked_version} is already installed but outdated (so it will be upgraded)."
|
|
|
|
return true
|
|
|
|
end
|
2021-06-14 11:16:20 -04:00
|
|
|
|
2022-01-14 00:19:14 +08:00
|
|
|
unpin_cmd_if_needed = ("brew unpin #{f.full_name} && " if f.pinned?)
|
2021-06-10 10:50:05 -04:00
|
|
|
optlinked_version = Keg.for(f.opt_prefix).version
|
|
|
|
onoe <<~EOS
|
|
|
|
#{f.full_name} #{optlinked_version} is already installed.
|
|
|
|
To upgrade to #{f.version}, run:
|
2022-01-14 00:09:51 +08:00
|
|
|
#{unpin_cmd_if_needed}brew upgrade #{f.full_name}
|
2021-06-10 10:50:05 -04:00
|
|
|
EOS
|
|
|
|
elsif only_dependencies
|
|
|
|
return true
|
2021-06-10 11:39:20 -04:00
|
|
|
elsif !quiet
|
2021-06-10 10:50:05 -04:00
|
|
|
opoo <<~EOS
|
|
|
|
#{f.full_name} #{f.pkg_version} is already installed and up-to-date.
|
|
|
|
To reinstall #{f.pkg_version}, run:
|
|
|
|
brew reinstall #{f.name}
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
elsif (head && new_head_installed) || prefix_installed
|
|
|
|
# After we're sure that --force flag is passed for linked to opt
|
|
|
|
# keg-only we need to be sure that the version we're attempting to
|
|
|
|
# install is not already installed.
|
|
|
|
|
|
|
|
installed_version = if head
|
|
|
|
f.latest_head_version
|
|
|
|
else
|
|
|
|
f.pkg_version
|
|
|
|
end
|
|
|
|
|
|
|
|
msg = "#{f.full_name} #{installed_version} is already installed"
|
|
|
|
linked_not_equals_installed = f.linked_version != installed_version
|
|
|
|
if f.linked? && linked_not_equals_installed
|
|
|
|
msg = if quiet
|
|
|
|
nil
|
|
|
|
else
|
|
|
|
<<~EOS
|
|
|
|
#{msg}.
|
|
|
|
The currently linked version is: #{f.linked_version}
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
elsif !f.linked? || f.keg_only?
|
|
|
|
msg = <<~EOS
|
|
|
|
#{msg}, it's just not linked.
|
|
|
|
To link this version, run:
|
|
|
|
brew link #{f}
|
|
|
|
EOS
|
|
|
|
elsif only_dependencies
|
|
|
|
msg = nil
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
msg = if quiet
|
|
|
|
nil
|
|
|
|
else
|
|
|
|
<<~EOS
|
|
|
|
#{msg} and up-to-date.
|
|
|
|
To reinstall #{f.pkg_version}, run:
|
|
|
|
brew reinstall #{f.name}
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
end
|
|
|
|
opoo msg if msg
|
|
|
|
elsif !f.any_version_installed? && (old_formula = f.old_installed_formulae.first)
|
|
|
|
msg = "#{old_formula.full_name} #{old_formula.any_installed_version} already installed"
|
|
|
|
msg = if !old_formula.linked? && !old_formula.keg_only?
|
|
|
|
<<~EOS
|
|
|
|
#{msg}, it's just not linked.
|
|
|
|
To link this version, run:
|
|
|
|
brew link #{old_formula.full_name}
|
|
|
|
EOS
|
|
|
|
elsif quiet
|
|
|
|
nil
|
|
|
|
else
|
|
|
|
"#{msg}."
|
|
|
|
end
|
|
|
|
opoo msg if msg
|
2021-06-10 11:39:20 -04:00
|
|
|
elsif f.migration_needed? && !force
|
2021-06-10 10:50:05 -04:00
|
|
|
# Check if the formula we try to install is the same as installed
|
|
|
|
# but not migrated one. If --force is passed then install anyway.
|
|
|
|
opoo <<~EOS
|
|
|
|
#{f.oldname} is already installed, it's just not migrated.
|
|
|
|
To migrate this formula, run:
|
|
|
|
brew migrate #{f}
|
|
|
|
Or to force-install it, run:
|
|
|
|
brew install #{f} --force
|
|
|
|
EOS
|
2021-09-10 06:06:02 -07:00
|
|
|
elsif f.linked?
|
|
|
|
message = "#{f.name} #{f.linked_version} is already installed"
|
|
|
|
if f.outdated? && !head
|
2022-01-13 23:57:51 +08:00
|
|
|
if !Homebrew::EnvConfig.no_install_upgrade? && !f.pinned?
|
2021-11-25 09:10:59 +00:00
|
|
|
puts "#{message} but outdated (so it will be upgraded)."
|
2021-09-10 08:31:53 -07:00
|
|
|
return true
|
|
|
|
end
|
2021-09-10 06:06:02 -07:00
|
|
|
|
2022-01-14 00:19:14 +08:00
|
|
|
unpin_cmd_if_needed = ("brew unpin #{f.full_name} && " if f.pinned?)
|
2021-09-10 06:06:02 -07:00
|
|
|
onoe <<~EOS
|
|
|
|
#{message}
|
|
|
|
To upgrade to #{f.pkg_version}, run:
|
2022-01-14 00:09:51 +08:00
|
|
|
#{unpin_cmd_if_needed}brew upgrade #{f.full_name}
|
2021-09-10 06:06:02 -07:00
|
|
|
EOS
|
|
|
|
elsif only_dependencies
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
onoe <<~EOS
|
|
|
|
#{message}
|
|
|
|
To install #{f.pkg_version}, first run:
|
|
|
|
brew unlink #{f.name}
|
|
|
|
EOS
|
|
|
|
end
|
2021-06-10 10:50:05 -04:00
|
|
|
else
|
|
|
|
# If none of the above is true and the formula is linked, then
|
|
|
|
# FormulaInstaller will handle this case.
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
# Even if we don't install this formula mark it as no longer just
|
|
|
|
# installed as a dependency.
|
|
|
|
return false unless f.opt_prefix.directory?
|
|
|
|
|
|
|
|
keg = Keg.new(f.opt_prefix.resolved_path)
|
|
|
|
tab = Tab.for_keg(keg)
|
|
|
|
unless tab.installed_on_request
|
|
|
|
tab.installed_on_request = true
|
|
|
|
tab.write
|
|
|
|
end
|
|
|
|
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
2021-09-01 22:27:34 -07:00
|
|
|
def install_formulae(
|
|
|
|
formulae_to_install,
|
2021-06-10 10:50:05 -04:00
|
|
|
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,
|
2022-07-26 12:15:53 +01:00
|
|
|
debug_symbols: false,
|
2021-06-10 10:50:05 -04:00
|
|
|
force: false,
|
2022-01-10 10:05:44 -06:00
|
|
|
overwrite: false,
|
2021-06-10 10:50:05 -04:00
|
|
|
debug: false,
|
|
|
|
quiet: false,
|
2022-08-16 20:59:01 +09:00
|
|
|
verbose: false,
|
|
|
|
dry_run: false
|
2021-06-10 10:50:05 -04:00
|
|
|
)
|
2021-09-01 22:27:34 -07:00
|
|
|
formula_installers = formulae_to_install.map do |f|
|
2022-08-17 22:14:20 +09:00
|
|
|
Migrator.migrate_if_needed(f, force: force, dry_run: dry_run)
|
2021-09-01 22:27:34 -07:00
|
|
|
build_options = f.build
|
|
|
|
|
|
|
|
fi = FormulaInstaller.new(
|
|
|
|
f,
|
|
|
|
options: build_options.used_options,
|
|
|
|
build_bottle: build_bottle,
|
|
|
|
force_bottle: force_bottle,
|
|
|
|
bottle_arch: bottle_arch,
|
|
|
|
ignore_deps: ignore_deps,
|
|
|
|
only_deps: only_deps,
|
|
|
|
include_test_formulae: include_test_formulae,
|
|
|
|
build_from_source_formulae: build_from_source_formulae,
|
|
|
|
cc: cc,
|
|
|
|
git: git,
|
|
|
|
interactive: interactive,
|
|
|
|
keep_tmp: keep_tmp,
|
2022-07-26 12:15:53 +01:00
|
|
|
debug_symbols: debug_symbols,
|
2021-09-01 22:27:34 -07:00
|
|
|
force: force,
|
2022-01-10 10:05:44 -06:00
|
|
|
overwrite: overwrite,
|
2021-09-01 22:27:34 -07:00
|
|
|
debug: debug,
|
|
|
|
quiet: quiet,
|
|
|
|
verbose: verbose,
|
|
|
|
)
|
|
|
|
|
|
|
|
begin
|
2022-08-17 22:14:20 +09:00
|
|
|
unless dry_run
|
|
|
|
fi.prelude
|
|
|
|
fi.fetch
|
|
|
|
end
|
2021-09-01 22:27:34 -07:00
|
|
|
fi
|
2021-09-10 06:01:37 -07:00
|
|
|
rescue CannotInstallFormulaError => e
|
|
|
|
ofail e.message
|
2021-09-14 03:37:40 +01:00
|
|
|
nil
|
2021-09-01 22:27:34 -07:00
|
|
|
rescue UnsatisfiedRequirements, DownloadError, ChecksumMismatchError => e
|
|
|
|
ofail "#{f}: #{e}"
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
end.compact
|
|
|
|
|
2022-08-17 22:14:20 +09:00
|
|
|
if dry_run
|
2022-08-27 22:29:07 +09:00
|
|
|
if (formulae_name_to_install = formulae_to_install.map(&:name))
|
|
|
|
plural = "formula".pluralize(formulae_name_to_install.count)
|
2022-08-18 00:16:11 +09:00
|
|
|
ohai "Would install #{formulae_name_to_install.count} #{plural}:"
|
2022-08-17 22:14:20 +09:00
|
|
|
puts formulae_name_to_install.join(" ")
|
2022-08-19 21:43:57 +09:00
|
|
|
|
|
|
|
formula_installers.each do |fi|
|
|
|
|
f = fi.formula
|
|
|
|
print_dry_run_dependencies(f, fi.compute_dependencies)
|
|
|
|
end
|
2022-08-17 22:14:20 +09:00
|
|
|
end
|
2022-08-19 21:43:57 +09:00
|
|
|
return
|
2022-08-17 22:14:20 +09:00
|
|
|
end
|
|
|
|
|
2021-09-01 22:27:34 -07:00
|
|
|
formula_installers.each do |fi|
|
2021-09-10 06:06:02 -07:00
|
|
|
install_formula(fi)
|
2021-09-01 22:27:34 -07:00
|
|
|
Cleanup.install_formula_clean!(fi.formula)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-09-10 06:06:02 -07:00
|
|
|
def install_formula(formula_installer)
|
2021-09-01 22:27:34 -07:00
|
|
|
f = formula_installer.formula
|
|
|
|
|
2021-09-10 08:31:53 -07:00
|
|
|
upgrade = f.linked? && f.outdated? && !f.head? && !Homebrew::EnvConfig.no_install_upgrade?
|
2021-06-15 10:11:40 -04:00
|
|
|
|
2021-09-10 08:31:53 -07:00
|
|
|
Upgrade.install_formula(formula_installer, upgrade: upgrade)
|
2021-06-10 10:50:05 -04:00
|
|
|
end
|
2021-09-01 22:27:34 -07:00
|
|
|
private_class_method :install_formula
|
2022-08-17 22:14:20 +09:00
|
|
|
|
|
|
|
def print_dry_run_dependencies(formula, dependencies)
|
2022-08-19 21:43:57 +09:00
|
|
|
return if dependencies.empty?
|
2022-08-17 22:14:20 +09:00
|
|
|
|
|
|
|
plural = "dependency".pluralize(dependencies.count)
|
|
|
|
ohai "Would install #{dependencies.count} #{plural} for #{formula.name}:"
|
2022-08-18 00:16:11 +09:00
|
|
|
formula_names = dependencies.map(&:first).map(&:to_formula).map(&:name)
|
2022-08-17 22:14:20 +09:00
|
|
|
puts formula_names.join(" ")
|
|
|
|
end
|
|
|
|
|
|
|
|
private_class_method :print_dry_run_dependencies
|
2018-06-05 23:19:18 -04:00
|
|
|
end
|
|
|
|
end
|
2018-09-28 14:01:09 -07:00
|
|
|
|
|
|
|
require "extend/os/install"
|