Skip to content
Snippets Groups Projects
Unverified Commit aaf6ccfb authored by Markus Reiter's avatar Markus Reiter Committed by GitHub
Browse files

Merge pull request #8461 from reitermarkus/document-upgrade

Refactor and document `Upgrade`.
parents 75962590 4937e4bb
No related branches found
No related tags found
No related merge requests found
...@@ -263,7 +263,7 @@ module Homebrew ...@@ -263,7 +263,7 @@ module Homebrew
Cleanup.install_formula_clean!(f) Cleanup.install_formula_clean!(f)
end end
check_installed_dependents(args: args) Upgrade.check_installed_dependents(args: args)
Homebrew.messages.display_messages(display_times: args.display_times?) Homebrew.messages.display_messages(display_times: args.display_times?)
rescue FormulaUnreadableError, FormulaClassUnavailableError, rescue FormulaUnreadableError, FormulaClassUnavailableError,
......
...@@ -72,7 +72,7 @@ module Homebrew ...@@ -72,7 +72,7 @@ module Homebrew
Cleanup.install_formula_clean!(f) Cleanup.install_formula_clean!(f)
end end
check_installed_dependents(args: args) Upgrade.check_installed_dependents(args: args)
Homebrew.messages.display_messages(display_times: args.display_times?) Homebrew.messages.display_messages(display_times: args.display_times?)
......
...@@ -137,9 +137,9 @@ module Homebrew ...@@ -137,9 +137,9 @@ module Homebrew
puts formulae_upgrades.join("\n") puts formulae_upgrades.join("\n")
end end
upgrade_formulae(formulae_to_install, args: args) Upgrade.upgrade_formulae(formulae_to_install, args: args)
check_installed_dependents(args: args) Upgrade.check_installed_dependents(args: args)
Homebrew.messages.display_messages(display_times: args.display_times?) Homebrew.messages.display_messages(display_times: args.display_times?)
end end
......
...@@ -7,219 +7,99 @@ require "messages" ...@@ -7,219 +7,99 @@ require "messages"
require "cleanup" require "cleanup"
module Homebrew module Homebrew
module_function # Helper functions for upgrading formulae.
#
def upgrade_formulae(formulae_to_install, args:) # @api private
return if formulae_to_install.empty? module Upgrade
return if args.dry_run? module_function
# Sort keg-only before non-keg-only formulae to avoid any needless conflicts def upgrade_formulae(formulae_to_install, args:)
# with outdated, non-keg-only versions of formulae being upgraded. return if formulae_to_install.empty?
formulae_to_install.sort! do |a, b| return if args.dry_run?
if !a.keg_only? && b.keg_only?
1 # Sort keg-only before non-keg-only formulae to avoid any needless conflicts
elsif a.keg_only? && !b.keg_only? # with outdated, non-keg-only versions of formulae being upgraded.
-1 formulae_to_install.sort! do |a, b|
else if !a.keg_only? && b.keg_only?
0 1
elsif a.keg_only? && !b.keg_only?
-1
else
0
end
end end
end
formulae_to_install.each do |f| formulae_to_install.each do |f|
Migrator.migrate_if_needed(f, force: args.force?) Migrator.migrate_if_needed(f, force: args.force?)
begin begin
upgrade_formula(f, args: args) upgrade_formula(f, args: args)
Cleanup.install_formula_clean!(f) Cleanup.install_formula_clean!(f)
rescue UnsatisfiedRequirements => e rescue UnsatisfiedRequirements => e
Homebrew.failed = true Homebrew.failed = true
onoe "#{f}: #{e}" onoe "#{f}: #{e}"
end
end end
end end
end
def upgrade_formula(f, args:)
return if args.dry_run?
if f.opt_prefix.directory?
keg = Keg.new(f.opt_prefix.resolved_path)
keg_had_linked_opt = true
keg_was_linked = keg.linked?
end
formulae_maybe_with_kegs = [f] + f.old_installed_formulae def upgrade_formula(f, args:)
outdated_kegs = formulae_maybe_with_kegs return if args.dry_run?
.map(&:linked_keg)
.select(&:directory?)
.map { |k| Keg.new(k.resolved_path) }
linked_kegs = outdated_kegs.select(&:linked?)
if f.opt_prefix.directory?
keg = Keg.new(f.opt_prefix.resolved_path)
tab = Tab.for_keg(keg)
end
build_options = BuildOptions.new(Options.create(args.flags_only), f.options)
options = build_options.used_options
options |= f.build.used_options
options &= f.options
fi = FormulaInstaller.new(f, force_bottle: args.force_bottle?,
build_from_source_formulae: args.build_from_source_formulae,
debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?)
fi.options = options
fi.force = args.force?
fi.keep_tmp = args.keep_tmp?
fi.build_bottle = args.build_bottle?
fi.installed_on_request = args.named.present?
fi.link_keg ||= keg_was_linked if keg_had_linked_opt
if tab
fi.build_bottle ||= tab.built_bottle?
fi.installed_as_dependency = tab.installed_as_dependency
fi.installed_on_request ||= tab.installed_on_request
end
upgrade_version = if f.optlinked? if f.opt_prefix.directory?
"#{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}" keg = Keg.new(f.opt_prefix.resolved_path)
else keg_had_linked_opt = true
"-> #{f.pkg_version}" keg_was_linked = keg.linked?
end end
oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}"
fi.prelude
fi.fetch
# first we unlink the currently active keg for this formula otherwise it is
# possible for the existing build to interfere with the build we are about to
# do! Seriously, it happens!
outdated_kegs.each(&:unlink)
fi.install
fi.finish
rescue FormulaInstallationAlreadyAttemptedError
# We already attempted to upgrade f as part of the dependency tree of
# another formula. In that case, don't generate an error, just move on.
nil
rescue CannotInstallFormulaError => e
ofail e
rescue BuildError => e
e.dump(verbose: args.verbose?)
puts
Homebrew.failed = true
rescue DownloadError => e
ofail e
ensure
# restore previous installation state if build failed
begin
linked_kegs.each(&:link) unless f.latest_version_installed?
rescue
nil
end
end
def check_installed_dependents(args:)
installed_formulae = FormulaInstaller.installed.to_a
return if installed_formulae.empty?
outdated_dependents =
installed_formulae.flat_map(&:runtime_installed_formula_dependents)
.select(&:outdated?)
return if outdated_dependents.blank?
outdated_dependents -= installed_formulae if args.dry_run?
upgradeable_dependents =
outdated_dependents.reject(&:pinned?)
.sort { |a, b| depends_on(a, b) }
pinned_dependents =
outdated_dependents.select(&:pinned?)
.sort { |a, b| depends_on(a, b) }
if pinned_dependents.present? formulae_maybe_with_kegs = [f] + f.old_installed_formulae
plural = "dependent".pluralize(pinned_dependents.count) outdated_kegs = formulae_maybe_with_kegs.map(&:linked_keg)
ohai "Not upgrading #{pinned_dependents.count} pinned #{plural}:" .select(&:directory?)
puts(pinned_dependents.map do |f| .map { |k| Keg.new(k.resolved_path) }
"#{f.full_specified_name} #{f.pkg_version}" linked_kegs = outdated_kegs.select(&:linked?)
end.join(", "))
end
# Print the upgradable dependents. if f.opt_prefix.directory?
if upgradeable_dependents.blank? keg = Keg.new(f.opt_prefix.resolved_path)
ohai "No outdated dependents to upgrade!" unless args.dry_run? tab = Tab.for_keg(keg)
else
plural = "dependent".pluralize(upgradeable_dependents.count)
verb = args.dry_run? ? "Would upgrade" : "Upgrading"
ohai "#{verb} #{upgradeable_dependents.count} #{plural}:"
formulae_upgrades = upgradeable_dependents.map do |f|
name = f.full_specified_name
if f.optlinked?
"#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
else
"#{name} #{f.pkg_version}"
end
end end
puts formulae_upgrades.join(", ")
end
upgrade_formulae(upgradeable_dependents, args: args) build_options = BuildOptions.new(Options.create(args.flags_only), f.options)
options = build_options.used_options
# Assess the dependents tree again now we've upgraded. options |= f.build.used_options
oh1 "Checking for dependents of upgraded formulae..." unless args.dry_run? options &= f.options
broken_dependents = CacheStoreDatabase.use(:linkage) do |db|
installed_formulae.flat_map(&:runtime_installed_formula_dependents) fi = FormulaInstaller.new(f, force_bottle: args.force_bottle?,
.select do |f| build_from_source_formulae: args.build_from_source_formulae,
keg = f.opt_or_installed_prefix_keg debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?)
next unless keg fi.options = options
fi.force = args.force?
fi.keep_tmp = args.keep_tmp?
fi.build_bottle = args.build_bottle?
fi.installed_on_request = args.named.present?
fi.link_keg ||= keg_was_linked if keg_had_linked_opt
if tab
fi.build_bottle ||= tab.built_bottle?
fi.installed_as_dependency = tab.installed_as_dependency
fi.installed_on_request ||= tab.installed_on_request
end
LinkageChecker.new(keg, cache_db: db) upgrade_version = if f.optlinked?
.broken_library_linkage? "#{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
end.compact
end
if broken_dependents.blank?
if args.dry_run?
ohai "No currently broken dependents found!"
opoo "If they are broken by the upgrade they will also be upgraded or reinstalled."
else else
ohai "No broken dependents found!" "-> #{f.pkg_version}"
end end
return oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}"
end
reinstallable_broken_dependents = fi.prelude
broken_dependents.reject(&:outdated?) fi.fetch
.reject(&:pinned?)
.sort { |a, b| depends_on(a, b) }
outdated_pinned_broken_dependents =
broken_dependents.select(&:outdated?)
.select(&:pinned?)
.sort { |a, b| depends_on(a, b) }
# Print the pinned dependents.
if outdated_pinned_broken_dependents.present?
count = outdated_pinned_broken_dependents.count
plural = "dependent".pluralize(outdated_pinned_broken_dependents.count)
onoe "Not reinstalling #{count} broken and outdated, but pinned #{plural}:"
$stderr.puts(outdated_pinned_broken_dependents.map do |f|
"#{f.full_specified_name} #{f.pkg_version}"
end.join(", "))
end
# Print the broken dependents.
if reinstallable_broken_dependents.blank?
ohai "No broken dependents to reinstall!"
else
count = reinstallable_broken_dependents.count
plural = "dependent".pluralize(reinstallable_broken_dependents.count)
ohai "Reinstalling #{count} broken #{plural} from source:"
puts reinstallable_broken_dependents.map(&:full_specified_name)
.join(", ")
end
return if args.dry_run? # first we unlink the currently active keg for this formula otherwise it is
# possible for the existing build to interfere with the build we are about to
# do! Seriously, it happens!
outdated_kegs.each(&:unlink)
reinstallable_broken_dependents.each do |f| fi.install
reinstall_formula(f, build_from_source: true, args: args) fi.finish
rescue FormulaInstallationAlreadyAttemptedError rescue FormulaInstallationAlreadyAttemptedError
# We already attempted to reinstall f as part of the dependency tree of # We already attempted to upgrade 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.
nil nil
rescue CannotInstallFormulaError => e rescue CannotInstallFormulaError => e
...@@ -230,17 +110,142 @@ module Homebrew ...@@ -230,17 +110,142 @@ module Homebrew
Homebrew.failed = true Homebrew.failed = true
rescue DownloadError => e rescue DownloadError => e
ofail e ofail e
ensure
# restore previous installation state if build failed
begin
linked_kegs.each(&:link) unless f.latest_version_installed?
rescue
nil
end
end end
end private_class_method :upgrade_formula
def check_installed_dependents(args:)
installed_formulae = FormulaInstaller.installed.to_a
return if installed_formulae.empty?
outdated_dependents =
installed_formulae.flat_map(&:runtime_installed_formula_dependents)
.select(&:outdated?)
return if outdated_dependents.blank?
outdated_dependents -= installed_formulae if args.dry_run?
upgradeable_dependents =
outdated_dependents.reject(&:pinned?)
.sort { |a, b| depends_on(a, b) }
pinned_dependents =
outdated_dependents.select(&:pinned?)
.sort { |a, b| depends_on(a, b) }
if pinned_dependents.present?
plural = "dependent".pluralize(pinned_dependents.count)
ohai "Not upgrading #{pinned_dependents.count} pinned #{plural}:"
puts(pinned_dependents.map do |f|
"#{f.full_specified_name} #{f.pkg_version}"
end.join(", "))
end
# @private # Print the upgradable dependents.
def depends_on(a, b) if upgradeable_dependents.blank?
if a.opt_or_installed_prefix_keg ohai "No outdated dependents to upgrade!" unless args.dry_run?
&.runtime_dependencies else
&.any? { |d| d["full_name"] == b.full_name } plural = "dependent".pluralize(upgradeable_dependents.count)
1 verb = args.dry_run? ? "Would upgrade" : "Upgrading"
else ohai "#{verb} #{upgradeable_dependents.count} #{plural}:"
a <=> b formulae_upgrades = upgradeable_dependents.map do |f|
name = f.full_specified_name
if f.optlinked?
"#{name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}"
else
"#{name} #{f.pkg_version}"
end
end
puts formulae_upgrades.join(", ")
end
upgrade_formulae(upgradeable_dependents, args: args)
# Assess the dependents tree again now we've upgraded.
oh1 "Checking for dependents of upgraded formulae..." unless args.dry_run?
broken_dependents = CacheStoreDatabase.use(:linkage) do |db|
installed_formulae.flat_map(&:runtime_installed_formula_dependents)
.select do |f|
keg = f.opt_or_installed_prefix_keg
next unless keg
LinkageChecker.new(keg, cache_db: db)
.broken_library_linkage?
end.compact
end
if broken_dependents.blank?
if args.dry_run?
ohai "No currently broken dependents found!"
opoo "If they are broken by the upgrade they will also be upgraded or reinstalled."
else
ohai "No broken dependents found!"
end
return
end
reinstallable_broken_dependents =
broken_dependents.reject(&:outdated?)
.reject(&:pinned?)
.sort { |a, b| depends_on(a, b) }
outdated_pinned_broken_dependents =
broken_dependents.select(&:outdated?)
.select(&:pinned?)
.sort { |a, b| depends_on(a, b) }
# Print the pinned dependents.
if outdated_pinned_broken_dependents.present?
count = outdated_pinned_broken_dependents.count
plural = "dependent".pluralize(outdated_pinned_broken_dependents.count)
onoe "Not reinstalling #{count} broken and outdated, but pinned #{plural}:"
$stderr.puts(outdated_pinned_broken_dependents.map do |f|
"#{f.full_specified_name} #{f.pkg_version}"
end.join(", "))
end
# Print the broken dependents.
if reinstallable_broken_dependents.blank?
ohai "No broken dependents to reinstall!"
else
count = reinstallable_broken_dependents.count
plural = "dependent".pluralize(reinstallable_broken_dependents.count)
ohai "Reinstalling #{count} broken #{plural} from source:"
puts reinstallable_broken_dependents.map(&:full_specified_name)
.join(", ")
end
return if args.dry_run?
reinstallable_broken_dependents.each do |f|
reinstall_formula(f, build_from_source: true, args: args)
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.
nil
rescue CannotInstallFormulaError => e
ofail e
rescue BuildError => e
e.dump(verbose: args.verbose?)
puts
Homebrew.failed = true
rescue DownloadError => e
ofail e
end
end
def depends_on(a, b)
if a.opt_or_installed_prefix_keg
&.runtime_dependencies
&.any? { |d| d["full_name"] == b.full_name }
1
else
a <=> b
end
end end
private_class_method :depends_on
end end
end end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment