Merge pull request #19714 from Homebrew/bundle-sim-services-2

Reland "bundle: handle simultaneous exec --services better"
This commit is contained in:
Bo Anderson 2025-04-07 15:46:39 +00:00 committed by GitHub
commit 25214f1f39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 15 additions and 4 deletions

View File

@ -179,6 +179,7 @@ module Homebrew
params( params(
entries: T::Array[Homebrew::Bundle::Dsl::Entry], entries: T::Array[Homebrew::Bundle::Dsl::Entry],
_block: T.proc.params( _block: T.proc.params(
entry: Homebrew::Bundle::Dsl::Entry,
info: T::Hash[String, T.anything], info: T::Hash[String, T.anything],
service_file: Pathname, service_file: Pathname,
conflicting_services: T::Array[T::Hash[String, T.anything]], conflicting_services: T::Array[T::Hash[String, T.anything]],
@ -195,6 +196,8 @@ module Homebrew
[entry, formula] [entry, formula]
end.to_h end.to_h
return if entries_formulae.empty?
conflicts = entries_formulae.to_h do |entry, formula| conflicts = entries_formulae.to_h do |entry, formula|
[ [
entry, entry,
@ -245,15 +248,20 @@ module Homebrew
raise "Failed to get service info for #{entry.name}" if info.nil? raise "Failed to get service info for #{entry.name}" if info.nil?
yield info, service_file, conflicting_services yield entry, info, service_file, conflicting_services
end end
end end
sig { params(entries: T::Array[Homebrew::Bundle::Dsl::Entry], _block: T.nilable(T.proc.void)).void } sig { params(entries: T::Array[Homebrew::Bundle::Dsl::Entry], _block: T.nilable(T.proc.void)).void }
private_class_method def self.run_services(entries, &_block) private_class_method def self.run_services(entries, &_block)
entries_to_stop = []
services_to_restart = [] services_to_restart = []
map_service_info(entries) do |info, service_file, conflicting_services| map_service_info(entries) do |entry, info, service_file, conflicting_services|
# Don't restart if already running this version
loaded_file = Pathname.new(info["loaded_file"].to_s)
next if info["running"] && loaded_file&.file? && loaded_file&.realpath == service_file.realpath
if info["running"] && !Bundle::BrewServices.stop(info["name"], keep: true) if info["running"] && !Bundle::BrewServices.stop(info["name"], keep: true)
opoo "Failed to stop #{info["name"]} service" opoo "Failed to stop #{info["name"]} service"
end end
@ -269,6 +277,8 @@ module Homebrew
unless Bundle::BrewServices.run(info["name"], file: service_file) unless Bundle::BrewServices.run(info["name"], file: service_file)
opoo "Failed to start #{info["name"]} service" opoo "Failed to start #{info["name"]} service"
end end
entries_to_stop << entry
end end
return unless block_given? return unless block_given?
@ -277,7 +287,7 @@ module Homebrew
yield yield
ensure ensure
# Do a full re-evaluation of services instead state has changed # Do a full re-evaluation of services instead state has changed
stop_services(entries) stop_services(entries_to_stop)
services_to_restart.each do |service| services_to_restart.each do |service|
next if Bundle::BrewServices.run(service) next if Bundle::BrewServices.run(service)
@ -289,7 +299,7 @@ module Homebrew
sig { params(entries: T::Array[Homebrew::Bundle::Dsl::Entry]).void } sig { params(entries: T::Array[Homebrew::Bundle::Dsl::Entry]).void }
private_class_method def self.stop_services(entries) private_class_method def self.stop_services(entries)
map_service_info(entries) do |info, _, _| map_service_info(entries) do |_, info, _, _|
next unless info["loaded"] next unless info["loaded"]
# Try avoid services not started by `brew bundle services` # Try avoid services not started by `brew bundle services`

View File

@ -185,6 +185,7 @@ RSpec.describe Homebrew::Bundle::Commands::Exec do
allow(pkgconf).to receive(:any_version_installed?).and_return(false) allow(pkgconf).to receive(:any_version_installed?).and_return(false)
allow_any_instance_of(Pathname).to receive(:file?).and_return(true) allow_any_instance_of(Pathname).to receive(:file?).and_return(true)
allow_any_instance_of(Pathname).to receive(:realpath) { |path| path }
allow(described_class).to receive(:exit!).and_return(nil) allow(described_class).to receive(:exit!).and_return(nil)
end end