mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Merge pull request #20033 from tyuwags/master
Refine ask‐option dependency resolution and strengthen tests
This commit is contained in:
commit
b87d2887fe
@ -310,9 +310,7 @@ module Homebrew
|
|||||||
Install.perform_preinstall_checks_once
|
Install.perform_preinstall_checks_once
|
||||||
Install.check_cc_argv(args.cc)
|
Install.check_cc_argv(args.cc)
|
||||||
|
|
||||||
Install.ask_formulae(installed_formulae, args: args) if args.ask?
|
formulae_installer = Install.formula_installers(
|
||||||
|
|
||||||
Install.install_formulae(
|
|
||||||
installed_formulae,
|
installed_formulae,
|
||||||
installed_on_request: !args.as_dependency?,
|
installed_on_request: !args.as_dependency?,
|
||||||
installed_as_dependency: args.as_dependency?,
|
installed_as_dependency: args.as_dependency?,
|
||||||
@ -338,9 +336,10 @@ module Homebrew
|
|||||||
skip_link: args.skip_link?,
|
skip_link: args.skip_link?,
|
||||||
)
|
)
|
||||||
|
|
||||||
Upgrade.check_installed_dependents(
|
dependants = Upgrade.dependants(
|
||||||
installed_formulae,
|
installed_formulae,
|
||||||
flags: args.flags_only,
|
flags: args.flags_only,
|
||||||
|
ask: args.ask?,
|
||||||
installed_on_request: !args.as_dependency?,
|
installed_on_request: !args.as_dependency?,
|
||||||
force_bottle: args.force_bottle?,
|
force_bottle: args.force_bottle?,
|
||||||
build_from_source_formulae: args.build_from_source_formulae,
|
build_from_source_formulae: args.build_from_source_formulae,
|
||||||
@ -354,6 +353,28 @@ module Homebrew
|
|||||||
dry_run: args.dry_run?,
|
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?)
|
Cleanup.periodic_clean!(dry_run: args.dry_run?)
|
||||||
|
|
||||||
Homebrew.messages.display_messages(display_times: args.display_times?)
|
Homebrew.messages.display_messages(display_times: args.display_times?)
|
||||||
|
@ -130,16 +130,13 @@ module Homebrew
|
|||||||
unless formulae.empty?
|
unless formulae.empty?
|
||||||
Install.perform_preinstall_checks_once
|
Install.perform_preinstall_checks_once
|
||||||
|
|
||||||
# If asking the user is enabled, show dependency and size information.
|
install_context = formulae.map do |formula|
|
||||||
Install.ask_formulae(formulae, args: args) if args.ask?
|
|
||||||
|
|
||||||
formulae.each do |formula|
|
|
||||||
if formula.pinned?
|
if formula.pinned?
|
||||||
onoe "#{formula.full_name} is pinned. You must unpin it to reinstall."
|
onoe "#{formula.full_name} is pinned. You must unpin it to reinstall."
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
Migrator.migrate_if_needed(formula, force: args.force?)
|
Migrator.migrate_if_needed(formula, force: args.force?)
|
||||||
Homebrew::Reinstall.reinstall_formula(
|
Homebrew::Reinstall.build_install_context(
|
||||||
formula,
|
formula,
|
||||||
flags: args.flags_only,
|
flags: args.flags_only,
|
||||||
force_bottle: args.force_bottle?,
|
force_bottle: args.force_bottle?,
|
||||||
@ -153,12 +150,32 @@ module Homebrew
|
|||||||
verbose: args.verbose?,
|
verbose: args.verbose?,
|
||||||
git: args.git?,
|
git: args.git?,
|
||||||
)
|
)
|
||||||
Cleanup.install_formula_clean!(formula)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Upgrade.check_installed_dependents(
|
dependants = Upgrade.dependants(
|
||||||
formulae,
|
formulae,
|
||||||
flags: args.flags_only,
|
flags: args.flags_only,
|
||||||
|
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?,
|
||||||
|
)
|
||||||
|
|
||||||
|
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?,
|
force_bottle: args.force_bottle?,
|
||||||
build_from_source_formulae: args.build_from_source_formulae,
|
build_from_source_formulae: args.build_from_source_formulae,
|
||||||
interactive: args.interactive?,
|
interactive: args.interactive?,
|
||||||
@ -168,6 +185,23 @@ module Homebrew
|
|||||||
debug: args.debug?,
|
debug: args.debug?,
|
||||||
quiet: args.quiet?,
|
quiet: args.quiet?,
|
||||||
verbose: args.verbose?,
|
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
|
end
|
||||||
|
|
||||||
|
@ -220,10 +220,7 @@ module Homebrew
|
|||||||
|
|
||||||
Install.perform_preinstall_checks_once
|
Install.perform_preinstall_checks_once
|
||||||
|
|
||||||
# Main block: if asking the user is enabled, show dependency and size information.
|
formulae_installer = Upgrade.formula_installers(
|
||||||
Install.ask_formulae(formulae_to_install, args: args) if args.ask?
|
|
||||||
|
|
||||||
Upgrade.upgrade_formulae(
|
|
||||||
formulae_to_install,
|
formulae_to_install,
|
||||||
flags: args.flags_only,
|
flags: args.flags_only,
|
||||||
dry_run: args.dry_run?,
|
dry_run: args.dry_run?,
|
||||||
@ -239,10 +236,33 @@ module Homebrew
|
|||||||
verbose: args.verbose?,
|
verbose: args.verbose?,
|
||||||
)
|
)
|
||||||
|
|
||||||
Upgrade.check_installed_dependents(
|
dependants = Upgrade.dependants(
|
||||||
formulae_to_install,
|
formulae_to_install,
|
||||||
flags: args.flags_only,
|
flags: args.flags_only,
|
||||||
dry_run: args.dry_run?,
|
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?,
|
force_bottle: args.force_bottle?,
|
||||||
build_from_source_formulae: args.build_from_source_formulae,
|
build_from_source_formulae: args.build_from_source_formulae,
|
||||||
interactive: args.interactive?,
|
interactive: args.interactive?,
|
||||||
@ -251,7 +271,7 @@ module Homebrew
|
|||||||
force: args.force?,
|
force: args.force?,
|
||||||
debug: args.debug?,
|
debug: args.debug?,
|
||||||
quiet: args.quiet?,
|
quiet: args.quiet?,
|
||||||
verbose: args.verbose?,
|
verbose: args.verbose?
|
||||||
)
|
)
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -3207,11 +3207,11 @@ class Formula
|
|||||||
patchlist.select(&:external?).each(&:fetch)
|
patchlist.select(&:external?).each(&:fetch)
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { void }
|
sig { params(quiet: T::Boolean).void }
|
||||||
def fetch_bottle_tab
|
def fetch_bottle_tab(quiet: false)
|
||||||
return unless bottled?
|
return unless bottled?
|
||||||
|
|
||||||
T.must(bottle).fetch_tab
|
T.must(bottle).fetch_tab(quiet: quiet)
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { returns(T::Hash[String, T.untyped]) }
|
sig { returns(T::Hash[String, T.untyped]) }
|
||||||
|
@ -1356,12 +1356,12 @@ on_request: installed_on_request?, options:)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
sig { void }
|
sig { params(quiet: T::Boolean).void }
|
||||||
def fetch_bottle_tab
|
def fetch_bottle_tab(quiet: false)
|
||||||
return if @fetch_bottle_tab
|
return if @fetch_bottle_tab
|
||||||
|
|
||||||
begin
|
begin
|
||||||
formula.fetch_bottle_tab
|
formula.fetch_bottle_tab(quiet: quiet)
|
||||||
@bottle_tab_runtime_dependencies = formula.bottle_tab_attributes
|
@bottle_tab_runtime_dependencies = formula.bottle_tab_attributes
|
||||||
.fetch("runtime_dependencies", []).then { |deps| deps || [] }
|
.fetch("runtime_dependencies", []).then { |deps| deps || [] }
|
||||||
.each_with_object({}) { |dep, h| h[dep["full_name"]] = dep }
|
.each_with_object({}) { |dep, h| h[dep["full_name"]] = dep }
|
||||||
|
@ -231,7 +231,7 @@ module Homebrew
|
|||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def install_formulae(
|
def formula_installers(
|
||||||
formulae_to_install,
|
formulae_to_install,
|
||||||
installed_on_request: true,
|
installed_on_request: true,
|
||||||
installed_as_dependency: false,
|
installed_as_dependency: false,
|
||||||
@ -256,11 +256,11 @@ module Homebrew
|
|||||||
skip_post_install: false,
|
skip_post_install: false,
|
||||||
skip_link: 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:)
|
Migrator.migrate_if_needed(formula, force:, dry_run:)
|
||||||
build_options = formula.build
|
build_options = formula.build
|
||||||
|
|
||||||
formula_installer = FormulaInstaller.new(
|
FormulaInstaller.new(
|
||||||
formula,
|
formula,
|
||||||
options: build_options.used_options,
|
options: build_options.used_options,
|
||||||
installed_on_request:,
|
installed_on_request:,
|
||||||
@ -285,24 +285,36 @@ module Homebrew
|
|||||||
skip_post_install:,
|
skip_post_install:,
|
||||||
skip_link:,
|
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
|
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 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,
|
ohai "Would install #{Utils.pluralize("formula", formulae_name_to_install.count,
|
||||||
plural: "e", include_count: true)}:"
|
plural: "e", include_count: true)}:"
|
||||||
puts formulae_name_to_install.join(" ")
|
puts formulae_name_to_install.join(" ")
|
||||||
@ -315,6 +327,18 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
formula_installers.each do |fi|
|
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)
|
install_formula(fi)
|
||||||
Cleanup.install_formula_clean!(fi.formula)
|
Cleanup.install_formula_clean!(fi.formula)
|
||||||
end
|
end
|
||||||
@ -330,16 +354,17 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
# If asking the user is enabled, show dependency and size information.
|
# If asking the user is enabled, show dependency and size information.
|
||||||
def ask_formulae(formulae, args:)
|
def ask_formulae(formulae_installer, dependants, args:)
|
||||||
return if formulae.empty?
|
return if formulae_installer.empty?
|
||||||
|
|
||||||
|
formulae = collect_dependencies(formulae_installer, dependants)
|
||||||
|
|
||||||
ohai "Looking for bottles..."
|
ohai "Looking for bottles..."
|
||||||
|
|
||||||
sized_formulae = compute_sized_formulae(formulae, args: args)
|
sizes = compute_total_sizes(formulae, debug: args.debug?)
|
||||||
sizes = compute_total_sizes(sized_formulae, debug: args.debug?)
|
|
||||||
|
|
||||||
puts "#{::Utils.pluralize("Formula", sized_formulae.count, plural: "e")} \
|
puts "#{::Utils.pluralize("Formula", formulae.count, plural: "e")} \
|
||||||
(#{sized_formulae.count}): #{sized_formulae.join(", ")}\n\n"
|
(#{formulae.count}): #{formulae.join(", ")}\n\n"
|
||||||
puts "Download Size: #{disk_usage_readable(sizes[:download])}"
|
puts "Download Size: #{disk_usage_readable(sizes[:download])}"
|
||||||
puts "Install Size: #{disk_usage_readable(sizes[:installed])}"
|
puts "Install Size: #{disk_usage_readable(sizes[:installed])}"
|
||||||
puts "Net Install Size: #{disk_usage_readable(sizes[:net])}" if sizes[:net] != 0
|
puts "Net Install Size: #{disk_usage_readable(sizes[:net])}" if sizes[:net] != 0
|
||||||
@ -411,41 +436,6 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
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.
|
# Compute the total sizes (download, installed, and net) for the given formulae.
|
||||||
def compute_total_sizes(sized_formulae, debug: false)
|
def compute_total_sizes(sized_formulae, debug: false)
|
||||||
total_download_size = 0
|
total_download_size = 0
|
||||||
@ -471,6 +461,16 @@ module Homebrew
|
|||||||
installed: total_installed_size,
|
installed: total_installed_size,
|
||||||
net: total_net_size }
|
net: total_net_size }
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
@ -7,7 +7,9 @@ require "messages"
|
|||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
module Reinstall
|
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,
|
formula,
|
||||||
flags:,
|
flags:,
|
||||||
force_bottle: false,
|
force_bottle: false,
|
||||||
@ -61,13 +63,35 @@ module Homebrew
|
|||||||
verbose:,
|
verbose:,
|
||||||
}.compact,
|
}.compact,
|
||||||
)
|
)
|
||||||
fi.prelude
|
InstallationContext.new(fi, keg, formula, options)
|
||||||
fi.fetch
|
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 " "}"
|
oh1 "Reinstalling #{Formatter.identifier(formula.full_name)} #{options.to_a.join " "}"
|
||||||
|
|
||||||
fi.install
|
formula_installer.install
|
||||||
fi.finish
|
formula_installer.finish
|
||||||
rescue FormulaInstallationAlreadyAttemptedError
|
rescue FormulaInstallationAlreadyAttemptedError
|
||||||
nil
|
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.
|
||||||
|
@ -95,34 +95,4 @@ RSpec.describe Homebrew::Cmd::InstallCmd do
|
|||||||
|
|
||||||
expect(HOMEBREW_CELLAR/"testball1/0.1/bin/test").to be_a_file
|
expect(HOMEBREW_CELLAR/"testball1/0.1/bin/test").to be_a_file
|
||||||
end
|
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
|
end
|
||||||
|
@ -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.1").to be_a_directory
|
||||||
expect(HOMEBREW_CELLAR/"testball/0.0.1").not_to exist
|
expect(HOMEBREW_CELLAR/"testball/0.0.1").not_to exist
|
||||||
end
|
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
|
end
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -135,21 +135,13 @@ RSpec.shared_context "integration test" do # rubocop:disable RSpec/ContextWordin
|
|||||||
bottle_block: nil, tab_attributes: nil)
|
bottle_block: nil, tab_attributes: nil)
|
||||||
case name
|
case name
|
||||||
when /^testball/
|
when /^testball/
|
||||||
case name
|
# Use a different tarball for testball2 to avoid lock errors when writing concurrency tests
|
||||||
when "testball4", "testball5"
|
prefix = (name == "testball2") ? "testball2" : "testball"
|
||||||
prefix = name
|
tarball = if OS.linux?
|
||||||
program_name = name
|
TEST_FIXTURE_DIR/"tarballs/#{prefix}-0.1-linux.tbz"
|
||||||
when "testball2"
|
|
||||||
prefix = name
|
|
||||||
program_name = "test"
|
|
||||||
else
|
else
|
||||||
prefix = "testball"
|
TEST_FIXTURE_DIR/"tarballs/#{prefix}-0.1.tbz"
|
||||||
program_name = "test"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
tarball_name = "#{prefix}-0.1#{"-linux" if OS.linux?}.tbz"
|
|
||||||
tarball = TEST_FIXTURE_DIR / "tarballs/#{tarball_name}"
|
|
||||||
|
|
||||||
content = <<~RUBY
|
content = <<~RUBY
|
||||||
desc "Some test"
|
desc "Some test"
|
||||||
homepage "https://brew.sh/#{name}"
|
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"
|
option "with-foo", "Build with foo"
|
||||||
#{bottle_block}
|
#{bottle_block}
|
||||||
def install
|
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["*"]
|
prefix.install Dir["*"]
|
||||||
(buildpath/"#{program_name}.c").write \
|
(buildpath/"test.c").write \
|
||||||
"#include <stdio.h>\\nint main(){printf(\\"#{program_name}\\");return 0;}"
|
"#include <stdio.h>\\nint main(){printf(\\"test\\");return 0;}"
|
||||||
bin.mkpath
|
bin.mkpath
|
||||||
system ENV.cc, "#{program_name}.c", "-o", bin/"#{program_name}"
|
system ENV.cc, "test.c", "-o", bin/"test"
|
||||||
end
|
end
|
||||||
|
|
||||||
#{content}
|
#{content}
|
||||||
|
@ -11,7 +11,9 @@ require "utils/topological_hash"
|
|||||||
module Homebrew
|
module Homebrew
|
||||||
# Helper functions for upgrading formulae.
|
# Helper functions for upgrading formulae.
|
||||||
module Upgrade
|
module Upgrade
|
||||||
def self.upgrade_formulae(
|
Dependents = Struct.new(:upgradeable, :pinned, :skipped)
|
||||||
|
|
||||||
|
def self.formula_installers(
|
||||||
formulae_to_install,
|
formulae_to_install,
|
||||||
flags:,
|
flags:,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
@ -48,7 +50,7 @@ module Homebrew
|
|||||||
raise CyclicDependencyError, dependency_graph.strongly_connected_components if Homebrew::EnvConfig.developer?
|
raise CyclicDependencyError, dependency_graph.strongly_connected_components if Homebrew::EnvConfig.developer?
|
||||||
end
|
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:)
|
Migrator.migrate_if_needed(formula, force:, dry_run:)
|
||||||
begin
|
begin
|
||||||
fi = create_formula_installer(
|
fi = create_formula_installer(
|
||||||
@ -65,18 +67,19 @@ module Homebrew
|
|||||||
quiet:,
|
quiet:,
|
||||||
verbose:,
|
verbose:,
|
||||||
)
|
)
|
||||||
unless dry_run
|
fi.fetch_bottle_tab(quiet: !debug)
|
||||||
fi.prelude
|
|
||||||
|
|
||||||
# Don't need to install this bottle if all of the runtime
|
all_runtime_deps_installed = fi.bottle_tab_runtime_dependencies.presence&.all? do |dependency, hash|
|
||||||
# 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?
|
minimum_version = Version.new(hash["version"]) if hash["version"].present?
|
||||||
Dependency.new(dependency).installed?(minimum_version:, minimum_revision: hash["revision"])
|
Dependency.new(dependency).installed?(minimum_version:, minimum_revision: hash["revision"])
|
||||||
end
|
end
|
||||||
|
|
||||||
fi.fetch
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
fi
|
fi
|
||||||
rescue CannotInstallFormulaError => e
|
rescue CannotInstallFormulaError => e
|
||||||
ofail e
|
ofail e
|
||||||
@ -86,6 +89,19 @@ module Homebrew
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
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|
|
formula_installers.each do |fi|
|
||||||
upgrade_formula(fi, dry_run:, verbose:)
|
upgrade_formula(fi, dry_run:, verbose:)
|
||||||
@ -250,10 +266,11 @@ module Homebrew
|
|||||||
@puts_no_installed_dependents_check_disable_message_if_not_already = true
|
@puts_no_installed_dependents_check_disable_message_if_not_already = true
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.check_installed_dependents(
|
def self.dependants(
|
||||||
formulae,
|
formulae,
|
||||||
flags:,
|
flags:,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
|
ask: false,
|
||||||
installed_on_request: false,
|
installed_on_request: false,
|
||||||
force_bottle: false,
|
force_bottle: false,
|
||||||
build_from_source_formulae: [],
|
build_from_source_formulae: [],
|
||||||
@ -274,16 +291,15 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
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
|
already_broken_dependents = check_broken_dependents(formulae_to_install)
|
||||||
installed_formulae.reject! { |f| f.core_formula? && f.versioned_formula? }
|
|
||||||
return if installed_formulae.empty?
|
|
||||||
|
|
||||||
already_broken_dependents = check_broken_dependents(installed_formulae)
|
|
||||||
|
|
||||||
# TODO: this should be refactored to use FormulaInstaller new logic
|
# TODO: this should be refactored to use FormulaInstaller new logic
|
||||||
outdated_dependents =
|
outdated_dependents =
|
||||||
installed_formulae.flat_map(&:runtime_installed_formula_dependents)
|
formulae_to_install.flat_map(&:runtime_installed_formula_dependents)
|
||||||
.uniq
|
.uniq
|
||||||
.select(&:outdated?)
|
.select(&:outdated?)
|
||||||
|
|
||||||
@ -292,17 +308,9 @@ module Homebrew
|
|||||||
dependent.bottled? && dependent.deps.map(&:to_formula).all?(&:bottled?)
|
dependent.bottled? && dependent.deps.map(&:to_formula).all?(&:bottled?)
|
||||||
end
|
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?
|
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 =
|
upgradeable_dependents =
|
||||||
outdated_dependents.reject(&:pinned?)
|
outdated_dependents.reject(&:pinned?)
|
||||||
@ -311,24 +319,52 @@ module Homebrew
|
|||||||
outdated_dependents.select(&:pinned?)
|
outdated_dependents.select(&:pinned?)
|
||||||
.sort { |a, b| depends_on(a, b) }
|
.sort { |a, b| depends_on(a, b) }
|
||||||
|
|
||||||
if pinned_dependents.present?
|
Dependents.new(upgradeable_dependents, pinned_dependents, skipped_dependents)
|
||||||
plural = Utils.pluralize("dependent", pinned_dependents.count)
|
end
|
||||||
opoo "Not upgrading #{pinned_dependents.count} pinned #{plural}:"
|
|
||||||
puts(pinned_dependents.map do |f|
|
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}"
|
"#{f.full_specified_name} #{f.pkg_version}"
|
||||||
end.join(", "))
|
end.join(", "))
|
||||||
end
|
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.
|
# Print the upgradable dependents.
|
||||||
if upgradeable_dependents.blank?
|
if upgradeable.blank?
|
||||||
ohai "No outdated dependents to upgrade!" unless dry_run
|
ohai "No outdated dependents to upgrade!" unless dry_run
|
||||||
else
|
else
|
||||||
|
installed_formulae = (dry_run ? formulae : FormulaInstaller.installed.to_a).dup
|
||||||
formula_plural = Utils.pluralize("formula", installed_formulae.count, plural: "e")
|
formula_plural = Utils.pluralize("formula", installed_formulae.count, plural: "e")
|
||||||
upgrade_verb = dry_run ? "Would upgrade" : "Upgrading"
|
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}:"
|
include_count: true)} of upgraded #{formula_plural}:"
|
||||||
Upgrade.puts_no_installed_dependents_check_disable_message_if_not_already!
|
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
|
name = f.full_specified_name
|
||||||
if f.optlinked?
|
if f.optlinked?
|
||||||
"#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
|
"#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
|
||||||
@ -340,8 +376,8 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
unless dry_run
|
unless dry_run
|
||||||
upgrade_formulae(
|
dependent_installers = formula_installers(
|
||||||
upgradeable_dependents,
|
upgradeable,
|
||||||
flags:,
|
flags:,
|
||||||
force_bottle:,
|
force_bottle:,
|
||||||
build_from_source_formulae:,
|
build_from_source_formulae:,
|
||||||
@ -354,6 +390,9 @@ module Homebrew
|
|||||||
quiet:,
|
quiet:,
|
||||||
verbose:,
|
verbose:,
|
||||||
)
|
)
|
||||||
|
puts "here", dependent_installers
|
||||||
|
puts "here", upgradeable
|
||||||
|
upgrade_formulae(dependent_installers, dry_run: dry_run, verbose: verbose)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Update installed formulae after upgrading
|
# Update installed formulae after upgrading
|
||||||
@ -409,7 +448,7 @@ module Homebrew
|
|||||||
return if dry_run
|
return if dry_run
|
||||||
|
|
||||||
reinstallable_broken_dependents.each do |formula|
|
reinstallable_broken_dependents.each do |formula|
|
||||||
Reinstall.reinstall_formula(
|
formula_installer = Reinstall.build_install_context(
|
||||||
formula,
|
formula,
|
||||||
flags:,
|
flags:,
|
||||||
force_bottle:,
|
force_bottle:,
|
||||||
@ -422,6 +461,19 @@ module Homebrew
|
|||||||
quiet:,
|
quiet:,
|
||||||
verbose:,
|
verbose:,
|
||||||
)
|
)
|
||||||
|
Reinstall.reinstall_formula(
|
||||||
|
formula_installer,
|
||||||
|
flags:,
|
||||||
|
force_bottle:,
|
||||||
|
build_from_source_formulae:,
|
||||||
|
interactive:,
|
||||||
|
keep_tmp:,
|
||||||
|
debug_symbols:,
|
||||||
|
force:,
|
||||||
|
debug:,
|
||||||
|
quiet:,
|
||||||
|
verbose:,
|
||||||
|
)
|
||||||
rescue FormulaInstallationAlreadyAttemptedError
|
rescue FormulaInstallationAlreadyAttemptedError
|
||||||
# We already attempted to reinstall f as part of the dependency tree of
|
# 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.
|
# another formula. In that case, don't generate an error, just move on.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user