services: try multiple domains when stopping

This commit is contained in:
Bo Anderson 2025-05-01 06:29:37 +01:00
parent d8b96a4385
commit ae58b3ef21
No known key found for this signature in database
4 changed files with 46 additions and 13 deletions

View File

@ -196,18 +196,31 @@ module Homebrew
System::Systemctl.quiet_run(*systemctl_args, "disable", "--now", service.service_name)
end
elsif System.launchctl?
quiet_system System.launchctl, "bootout", "#{System.domain_target}/#{service.service_name}"
unless no_wait
time_slept = 0
sleep_time = 1
max_wait = T.must(max_wait)
while ($CHILD_STATUS.to_i == 9216 || service.loaded?) && (max_wait.zero? || time_slept < max_wait)
sleep(sleep_time)
time_slept += sleep_time
quiet_system System.launchctl, "bootout", "#{System.domain_target}/#{service.service_name}"
dont_wait_statuses = [
Errno::ESRCH::Errno,
System::LAUNCHCTL_DOMAIN_ACTION_NOT_SUPPORTED,
]
System.candidate_domain_targets.each do |domain_target|
break unless service.loaded?
quiet_system System.launchctl, "bootout", "#{domain_target}/#{service.service_name}"
unless no_wait
time_slept = 0
sleep_time = 1
max_wait = T.must(max_wait)
exit_status = $CHILD_STATUS.exitstatus
while dont_wait_statuses.exclude?(exit_status) &&
(exit_status == Errno::EINPROGRESS::Errno || service.loaded?) &&
(max_wait.zero? || time_slept < max_wait)
sleep(sleep_time)
time_slept += sleep_time
quiet_system System.launchctl, "bootout", "#{domain_target}/#{service.service_name}"
exit_status = $CHILD_STATUS.exitstatus
end
end
service.reset_cache!
quiet_system System.launchctl, "stop", "#{domain_target}/#{service.service_name}" if service.pid?
end
quiet_system System.launchctl, "stop", "#{System.domain_target}/#{service.service_name}" if service.pid?
end
unless keep
@ -216,7 +229,7 @@ module Homebrew
System::Systemctl.run(*systemctl_args, "daemon-reload") if System.systemctl?
end
if service.pid? || service.loaded?
if service.loaded? || service.pid?
opoo "Unable to stop `#{service.name}` (label: #{service.service_name})"
else
ohai "Successfully stopped `#{service.name}` (label: #{service.service_name})"
@ -237,7 +250,12 @@ module Homebrew
if System.systemctl?
System::Systemctl.quiet_run("stop", service.service_name)
elsif System.launchctl?
quiet_system System.launchctl, "stop", "#{System.domain_target}/#{service.service_name}"
System.candidate_domain_targets.each do |domain_target|
break unless service.pid?
quiet_system System.launchctl, "stop", "#{domain_target}/#{service.service_name}"
service.reset_cache!
end
end
if service.pid?

View File

@ -113,12 +113,17 @@ module Homebrew
false
end
sig { void }
def reset_cache!
@status_output_success_type = nil
end
# Returns `true` if the service is loaded, else false.
# TODO: this should either be T::Boolean or renamed to `loaded`
sig { params(cached: T::Boolean).returns(T.nilable(T::Boolean)) }
def loaded?(cached: false)
if System.launchctl?
@status_output_success_type = nil unless cached
reset_cache! unless cached
_, status_success, = status_output_success_type
status_success
elsif System.systemctl?

View File

@ -6,6 +6,8 @@ require_relative "system/systemctl"
module Homebrew
module Services
module System
LAUNCHCTL_DOMAIN_ACTION_NOT_SUPPORTED = T.let(125, Integer)
# Path to launchctl binary.
sig { returns(T.nilable(Pathname)) }
def self.launchctl
@ -98,6 +100,13 @@ module Homebrew
"gui/#{Process.uid}"
end
end
sig { returns(T::Array[String]) }
def self.candidate_domain_targets
candidates = [domain_target]
candidates += ["user/#{Process.euid}", "gui/#{Process.uid}"] unless root?
candidates.uniq
end
end
end
end

View File

@ -74,6 +74,7 @@ RSpec.describe Homebrew::Services::Cli do
keep_alive?: false,
)
allow(service).to receive(:service_name)
allow(service).to receive(:reset_cache!)
allow(Homebrew::Services::FormulaWrapper).to receive(:from).and_return(service)
allow(services_cli).to receive(:running).and_return(["example_service"])
expect do