mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Merge pull request #19552 from Homebrew/bundle-services
Add `brew bundle exec --services`
This commit is contained in:
commit
2603401bcb
@ -113,12 +113,15 @@ module Homebrew
|
|||||||
|
|
||||||
def service_change_state!(verbose:)
|
def service_change_state!(verbose:)
|
||||||
require "bundle/brew_services"
|
require "bundle/brew_services"
|
||||||
|
|
||||||
|
file = Bundle::BrewServices.versioned_service_file(@name)
|
||||||
|
|
||||||
if restart_service_needed?
|
if restart_service_needed?
|
||||||
puts "Restarting #{@name} service." if verbose
|
puts "Restarting #{@name} service." if verbose
|
||||||
BrewServices.restart(@full_name, verbose:)
|
BrewServices.restart(@full_name, file:, verbose:)
|
||||||
elsif start_service_needed?
|
elsif start_service_needed?
|
||||||
puts "Starting #{@name} service." if verbose
|
puts "Starting #{@name} service." if verbose
|
||||||
BrewServices.start(@full_name, verbose:)
|
BrewServices.start(@full_name, file:, verbose:)
|
||||||
else
|
else
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
@ -1,43 +1,58 @@
|
|||||||
# typed: true # rubocop:todo Sorbet/StrictSigil
|
# typed: true # rubocop:todo Sorbet/StrictSigil
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "services/system"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
module Bundle
|
module Bundle
|
||||||
module BrewServices
|
module BrewServices
|
||||||
module_function
|
def self.reset!
|
||||||
|
|
||||||
def reset!
|
|
||||||
@started_services = nil
|
@started_services = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def stop(name, verbose: false)
|
def self.stop(name, keep: false, verbose: false)
|
||||||
return true unless started?(name)
|
return true unless started?(name)
|
||||||
|
|
||||||
return unless Bundle.brew("services", "stop", name, verbose:)
|
args = ["services", "stop", name]
|
||||||
|
args << "--keep" if keep
|
||||||
|
return unless Bundle.brew(*args, verbose:)
|
||||||
|
|
||||||
started_services.delete(name)
|
started_services.delete(name)
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def start(name, verbose: false)
|
def self.start(name, file: nil, verbose: false)
|
||||||
return unless Bundle.brew("services", "start", name, verbose:)
|
args = ["services", "start", name]
|
||||||
|
args << "--file=#{file}" if file
|
||||||
|
return unless Bundle.brew(*args, verbose:)
|
||||||
|
|
||||||
started_services << name
|
started_services << name
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def restart(name, verbose: false)
|
def self.run(name, file: nil, verbose: false)
|
||||||
return unless Bundle.brew("services", "restart", name, verbose:)
|
args = ["services", "run", name]
|
||||||
|
args << "--file=#{file}" if file
|
||||||
|
return unless Bundle.brew(*args, verbose:)
|
||||||
|
|
||||||
started_services << name
|
started_services << name
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def started?(name)
|
def self.restart(name, file: nil, verbose: false)
|
||||||
|
args = ["services", "restart", name]
|
||||||
|
args << "--file=#{file}" if file
|
||||||
|
return unless Bundle.brew(*args, verbose:)
|
||||||
|
|
||||||
|
started_services << name
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.started?(name)
|
||||||
started_services.include? name
|
started_services.include? name
|
||||||
end
|
end
|
||||||
|
|
||||||
def started_services
|
def self.started_services
|
||||||
@started_services ||= begin
|
@started_services ||= begin
|
||||||
states_to_skip = %w[stopped none]
|
states_to_skip = %w[stopped none]
|
||||||
Utils.safe_popen_read(HOMEBREW_BREW_FILE, "services", "list").lines.filter_map do |line|
|
Utils.safe_popen_read(HOMEBREW_BREW_FILE, "services", "list").lines.filter_map do |line|
|
||||||
@ -48,6 +63,23 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.versioned_service_file(name)
|
||||||
|
env_version = Bundle.formula_versions_from_env[name]
|
||||||
|
return if env_version.nil?
|
||||||
|
|
||||||
|
formula = Formula[name]
|
||||||
|
prefix = formula.rack/env_version
|
||||||
|
return unless prefix.directory?
|
||||||
|
|
||||||
|
service_file = if Homebrew::Services::System.launchctl?
|
||||||
|
prefix/"#{formula.plist_name}.plist"
|
||||||
|
else
|
||||||
|
prefix/"#{formula.service_name}.service"
|
||||||
|
end
|
||||||
|
|
||||||
|
service_file if service_file.file?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -47,7 +47,7 @@ module Homebrew
|
|||||||
|
|
||||||
PATH_LIKE_ENV_REGEX = /.+#{File::PATH_SEPARATOR}/
|
PATH_LIKE_ENV_REGEX = /.+#{File::PATH_SEPARATOR}/
|
||||||
|
|
||||||
def self.run(*args, global: false, file: nil, subcommand: "")
|
def self.run(*args, global: false, file: nil, subcommand: "", services: false)
|
||||||
# Cleanup Homebrew's global environment
|
# Cleanup Homebrew's global environment
|
||||||
HOMEBREW_ENV_CLEANUP.each { |key| ENV.delete(key) }
|
HOMEBREW_ENV_CLEANUP.each { |key| ENV.delete(key) }
|
||||||
|
|
||||||
@ -157,9 +157,137 @@ module Homebrew
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if services
|
||||||
|
require "bundle/brew_services"
|
||||||
|
|
||||||
|
exit_code = 0
|
||||||
|
run_services(@dsl.entries) do
|
||||||
|
Kernel.system(*args)
|
||||||
|
exit_code = $CHILD_STATUS.exitstatus
|
||||||
|
end
|
||||||
|
exit!(exit_code)
|
||||||
|
else
|
||||||
exec(*args)
|
exec(*args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig {
|
||||||
|
params(
|
||||||
|
entries: T::Array[Homebrew::Bundle::Dsl::Entry],
|
||||||
|
_block: T.proc.params(
|
||||||
|
info: T::Hash[String, T.anything],
|
||||||
|
service_file: Pathname,
|
||||||
|
conflicting_services: T::Array[T::Hash[String, T.anything]],
|
||||||
|
).void,
|
||||||
|
).void
|
||||||
|
}
|
||||||
|
private_class_method def self.map_service_info(entries, &_block)
|
||||||
|
entries_formulae = entries.filter_map do |entry|
|
||||||
|
next if entry.type != :brew
|
||||||
|
|
||||||
|
formula = Formula[entry.name]
|
||||||
|
next unless formula.any_version_installed?
|
||||||
|
|
||||||
|
[entry, formula]
|
||||||
|
end.to_h
|
||||||
|
|
||||||
|
# The formula + everything that could possible conflict with the service
|
||||||
|
names_to_query = entries_formulae.flat_map do |entry, formula|
|
||||||
|
[
|
||||||
|
formula.name,
|
||||||
|
*formula.versioned_formulae_names,
|
||||||
|
*formula.conflicts.map(&:name),
|
||||||
|
*entry.options[:conflicts_with],
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
# We parse from a command invocation so that brew wrappers can invoke special actions
|
||||||
|
# for the elevated nature of `brew services`
|
||||||
|
services_info = JSON.parse(
|
||||||
|
Utils.safe_popen_read(HOMEBREW_BREW_FILE, "services", "info", "--json", *names_to_query),
|
||||||
|
)
|
||||||
|
|
||||||
|
entries_formulae.filter_map do |entry, formula|
|
||||||
|
service_file = Bundle::BrewServices.versioned_service_file(entry.name)
|
||||||
|
|
||||||
|
unless service_file&.file?
|
||||||
|
prefix = formula.any_installed_prefix
|
||||||
|
next if prefix.nil?
|
||||||
|
|
||||||
|
service_file = if Homebrew::Services::System.launchctl?
|
||||||
|
prefix/"#{formula.plist_name}.plist"
|
||||||
|
else
|
||||||
|
prefix/"#{formula.service_name}.service"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
next unless service_file.file?
|
||||||
|
|
||||||
|
info = services_info.find { |candidate| candidate["name"] == formula.name }
|
||||||
|
conflicting_services = services_info.select do |candidate|
|
||||||
|
next unless candidate["running"]
|
||||||
|
|
||||||
|
formula.versioned_formulae_names.include?(candidate["name"])
|
||||||
|
end
|
||||||
|
|
||||||
|
raise "Failed to get service info for #{entry.name}" if info.nil?
|
||||||
|
|
||||||
|
yield info, service_file, conflicting_services
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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)
|
||||||
|
services_to_restart = []
|
||||||
|
|
||||||
|
map_service_info(entries) do |info, service_file, conflicting_services|
|
||||||
|
if info["running"] && !Bundle::BrewServices.stop(info["name"], keep: true)
|
||||||
|
opoo "Failed to stop #{info["name"]} service"
|
||||||
|
end
|
||||||
|
|
||||||
|
conflicting_services.each do |conflict|
|
||||||
|
if Bundle::BrewServices.stop(conflict["name"], keep: true)
|
||||||
|
services_to_restart << conflict["name"] if conflict["registered"]
|
||||||
|
else
|
||||||
|
opoo "Failed to stop #{conflict["name"]} service"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unless Bundle::BrewServices.run(info["name"], file: service_file)
|
||||||
|
opoo "Failed to start #{info["name"]} service"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return unless block_given?
|
||||||
|
|
||||||
|
begin
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
# Do a full re-evaluation of services instead state has changed
|
||||||
|
stop_services(entries)
|
||||||
|
|
||||||
|
services_to_restart.each do |service|
|
||||||
|
next if Bundle::BrewServices.run(service)
|
||||||
|
|
||||||
|
opoo "Failed to restart #{service} service"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sig { params(entries: T::Array[Homebrew::Bundle::Dsl::Entry]).void }
|
||||||
|
private_class_method def self.stop_services(entries)
|
||||||
|
map_service_info(entries) do |info, _, _|
|
||||||
|
next unless info["loaded"]
|
||||||
|
|
||||||
|
# Try avoid services not started by `brew bundle services`
|
||||||
|
next if Homebrew::Services::System.launchctl? && info["registered"]
|
||||||
|
|
||||||
|
if info["running"] && !Bundle::BrewServices.stop(info["name"], keep: true)
|
||||||
|
opoo "Failed to stop #{info["name"]} service"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -83,6 +83,8 @@ module Homebrew
|
|||||||
"even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set. "
|
"even if `$HOMEBREW_BUNDLE_NO_UPGRADE` is set. "
|
||||||
switch "--install",
|
switch "--install",
|
||||||
description: "Run `install` before continuing to other operations e.g. `exec`."
|
description: "Run `install` before continuing to other operations e.g. `exec`."
|
||||||
|
switch "--services",
|
||||||
|
description: "Temporarily start services while running the `exec` or `sh` command."
|
||||||
switch "-f", "--force",
|
switch "-f", "--force",
|
||||||
description: "`install` runs with `--force`/`--overwrite`. " \
|
description: "`install` runs with `--force`/`--overwrite`. " \
|
||||||
"`dump` overwrites an existing `Brewfile`. " \
|
"`dump` overwrites an existing `Brewfile`. " \
|
||||||
@ -133,7 +135,7 @@ module Homebrew
|
|||||||
require "bundle"
|
require "bundle"
|
||||||
|
|
||||||
subcommand = args.named.first.presence
|
subcommand = args.named.first.presence
|
||||||
if ["exec", "add", "remove"].exclude?(subcommand) && args.named.size > 1
|
if %w[exec add remove].exclude?(subcommand) && args.named.size > 1
|
||||||
raise UsageError, "This command does not take more than 1 subcommand argument."
|
raise UsageError, "This command does not take more than 1 subcommand argument."
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -232,7 +234,7 @@ module Homebrew
|
|||||||
["env"]
|
["env"]
|
||||||
end
|
end
|
||||||
require "bundle/commands/exec"
|
require "bundle/commands/exec"
|
||||||
Homebrew::Bundle::Commands::Exec.run(*named_args, global:, file:, subcommand:)
|
Homebrew::Bundle::Commands::Exec.run(*named_args, global:, file:, subcommand:, services: args.services?)
|
||||||
when "list"
|
when "list"
|
||||||
require "bundle/commands/list"
|
require "bundle/commands/list"
|
||||||
Homebrew::Bundle::Commands::List.run(
|
Homebrew::Bundle::Commands::List.run(
|
||||||
|
@ -38,13 +38,14 @@ module Homebrew
|
|||||||
[`sudo`] `brew services start` (<formula>|`--all`|`--file=`):
|
[`sudo`] `brew services start` (<formula>|`--all`|`--file=`):
|
||||||
Start the service <formula> immediately and register it to launch at login (or boot).
|
Start the service <formula> immediately and register it to launch at login (or boot).
|
||||||
|
|
||||||
[`sudo`] `brew services stop` (<formula>|`--all`):
|
[`sudo`] `brew services stop` (`--keep`) (`--no-wait`|`--max-wait=`) (<formula>|`--all`):
|
||||||
Stop the service <formula> immediately and unregister it from launching at login (or boot).
|
Stop the service <formula> immediately and unregister it from launching at login (or boot),
|
||||||
|
unless `--keep` is specified.
|
||||||
|
|
||||||
[`sudo`] `brew services kill` (<formula>|`--all`):
|
[`sudo`] `brew services kill` (<formula>|`--all`):
|
||||||
Stop the service <formula> immediately but keep it registered to launch at login (or boot).
|
Stop the service <formula> immediately but keep it registered to launch at login (or boot).
|
||||||
|
|
||||||
[`sudo`] `brew services restart` (<formula>|`--all`):
|
[`sudo`] `brew services restart` (<formula>|`--all`|`--file=`):
|
||||||
Stop (if necessary) and start the service <formula> immediately and register it to launch at login (or boot).
|
Stop (if necessary) and start the service <formula> immediately and register it to launch at login (or boot).
|
||||||
|
|
||||||
[`sudo`] `brew services cleanup`:
|
[`sudo`] `brew services cleanup`:
|
||||||
@ -57,6 +58,7 @@ module Homebrew
|
|||||||
switch "--all", description: "Run <subcommand> on all services."
|
switch "--all", description: "Run <subcommand> on all services."
|
||||||
switch "--json", description: "Output as JSON."
|
switch "--json", description: "Output as JSON."
|
||||||
switch "--no-wait", description: "Don't wait for `stop` to finish stopping the service."
|
switch "--no-wait", description: "Don't wait for `stop` to finish stopping the service."
|
||||||
|
switch "--keep", description: "When stopped, don't unregister the service from launching at login (or boot)."
|
||||||
conflicts "--max-wait=", "--no-wait"
|
conflicts "--max-wait=", "--no-wait"
|
||||||
named_args
|
named_args
|
||||||
end
|
end
|
||||||
@ -108,6 +110,7 @@ module Homebrew
|
|||||||
file_commands = [
|
file_commands = [
|
||||||
*Homebrew::Services::Commands::Start::TRIGGERS,
|
*Homebrew::Services::Commands::Start::TRIGGERS,
|
||||||
*Homebrew::Services::Commands::Run::TRIGGERS,
|
*Homebrew::Services::Commands::Run::TRIGGERS,
|
||||||
|
*Homebrew::Services::Commands::Restart::TRIGGERS,
|
||||||
]
|
]
|
||||||
if file_commands.exclude?(subcommand)
|
if file_commands.exclude?(subcommand)
|
||||||
raise UsageError, "The `#{subcommand}` subcommand does not accept the --file= argument!"
|
raise UsageError, "The `#{subcommand}` subcommand does not accept the --file= argument!"
|
||||||
@ -117,6 +120,14 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
unless Homebrew::Services::Commands::Stop::TRIGGERS.include?(subcommand)
|
||||||
|
raise UsageError, "The `#{subcommand}` subcommand does not accept the --keep argument!" if args.keep?
|
||||||
|
raise UsageError, "The `#{subcommand}` subcommand does not accept the --no-wait argument!" if args.no_wait?
|
||||||
|
if args.max_wait
|
||||||
|
raise UsageError, "The `#{subcommand}` subcommand does not accept the --max-wait= argument!"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
opoo "The --all argument overrides provided formula argument!" if formulae.present? && args.all?
|
opoo "The --all argument overrides provided formula argument!" if formulae.present? && args.all?
|
||||||
|
|
||||||
targets = if args.all?
|
targets = if args.all?
|
||||||
@ -156,14 +167,19 @@ module Homebrew
|
|||||||
when *Homebrew::Services::Commands::Info::TRIGGERS
|
when *Homebrew::Services::Commands::Info::TRIGGERS
|
||||||
Homebrew::Services::Commands::Info.run(targets, verbose: args.verbose?, json: args.json?)
|
Homebrew::Services::Commands::Info.run(targets, verbose: args.verbose?, json: args.json?)
|
||||||
when *Homebrew::Services::Commands::Restart::TRIGGERS
|
when *Homebrew::Services::Commands::Restart::TRIGGERS
|
||||||
Homebrew::Services::Commands::Restart.run(targets, verbose: args.verbose?)
|
Homebrew::Services::Commands::Restart.run(targets, args.file, verbose: args.verbose?)
|
||||||
when *Homebrew::Services::Commands::Run::TRIGGERS
|
when *Homebrew::Services::Commands::Run::TRIGGERS
|
||||||
Homebrew::Services::Commands::Run.run(targets, args.file, verbose: args.verbose?)
|
Homebrew::Services::Commands::Run.run(targets, args.file, verbose: args.verbose?)
|
||||||
when *Homebrew::Services::Commands::Start::TRIGGERS
|
when *Homebrew::Services::Commands::Start::TRIGGERS
|
||||||
Homebrew::Services::Commands::Start.run(targets, args.file, verbose: args.verbose?)
|
Homebrew::Services::Commands::Start.run(targets, args.file, verbose: args.verbose?)
|
||||||
when *Homebrew::Services::Commands::Stop::TRIGGERS
|
when *Homebrew::Services::Commands::Stop::TRIGGERS
|
||||||
max_wait = args.max_wait.to_f
|
Homebrew::Services::Commands::Stop.run(
|
||||||
Homebrew::Services::Commands::Stop.run(targets, verbose: args.verbose?, no_wait: args.no_wait?, max_wait:)
|
targets,
|
||||||
|
verbose: args.verbose?,
|
||||||
|
no_wait: args.no_wait?,
|
||||||
|
max_wait: args.max_wait.to_f,
|
||||||
|
keep: args.keep?,
|
||||||
|
)
|
||||||
when *Homebrew::Services::Commands::Kill::TRIGGERS
|
when *Homebrew::Services::Commands::Kill::TRIGGERS
|
||||||
Homebrew::Services::Commands::Kill.run(targets, verbose: args.verbose?)
|
Homebrew::Services::Commands::Kill.run(targets, verbose: args.verbose?)
|
||||||
else
|
else
|
||||||
|
@ -159,12 +159,13 @@ module Homebrew
|
|||||||
verbose: T::Boolean,
|
verbose: T::Boolean,
|
||||||
no_wait: T::Boolean,
|
no_wait: T::Boolean,
|
||||||
max_wait: T.nilable(T.any(Integer, Float)),
|
max_wait: T.nilable(T.any(Integer, Float)),
|
||||||
|
keep: T::Boolean,
|
||||||
).void
|
).void
|
||||||
}
|
}
|
||||||
def self.stop(targets, verbose: false, no_wait: false, max_wait: 0)
|
def self.stop(targets, verbose: false, no_wait: false, max_wait: 0, keep: false)
|
||||||
targets.each do |service|
|
targets.each do |service|
|
||||||
unless service.loaded?
|
unless service.loaded?
|
||||||
rm service.dest if service.dest.exist? # get rid of installed service file anyway, dude
|
rm service.dest if !keep && service.dest.exist? # get rid of installed service file anyway, dude
|
||||||
if service.service_file_present?
|
if service.service_file_present?
|
||||||
odie <<~EOS
|
odie <<~EOS
|
||||||
Service `#{service.name}` is started as `#{service.owner}`. Try:
|
Service `#{service.name}` is started as `#{service.owner}`. Try:
|
||||||
@ -188,7 +189,11 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
if System.systemctl?
|
if System.systemctl?
|
||||||
|
if keep
|
||||||
|
System::Systemctl.quiet_run(*systemctl_args, "stop", service.service_name)
|
||||||
|
else
|
||||||
System::Systemctl.quiet_run(*systemctl_args, "disable", "--now", service.service_name)
|
System::Systemctl.quiet_run(*systemctl_args, "disable", "--now", service.service_name)
|
||||||
|
end
|
||||||
elsif System.launchctl?
|
elsif System.launchctl?
|
||||||
quiet_system System.launchctl, "bootout", "#{System.domain_target}/#{service.service_name}"
|
quiet_system System.launchctl, "bootout", "#{System.domain_target}/#{service.service_name}"
|
||||||
unless no_wait
|
unless no_wait
|
||||||
@ -204,9 +209,11 @@ module Homebrew
|
|||||||
quiet_system System.launchctl, "stop", "#{System.domain_target}/#{service.service_name}" if service.pid?
|
quiet_system System.launchctl, "stop", "#{System.domain_target}/#{service.service_name}" if service.pid?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
unless keep
|
||||||
rm service.dest if service.dest.exist?
|
rm service.dest if service.dest.exist?
|
||||||
# Run daemon-reload on systemctl to finish unloading stopped and deleted service.
|
# Run daemon-reload on systemctl to finish unloading stopped and deleted service.
|
||||||
System::Systemctl.run(*systemctl_args, "daemon-reload") if System.systemctl?
|
System::Systemctl.run(*systemctl_args, "daemon-reload") if System.systemctl?
|
||||||
|
end
|
||||||
|
|
||||||
if service.pid? || service.loaded?
|
if service.pid? || service.loaded?
|
||||||
opoo "Unable to stop `#{service.name}` (label: #{service.service_name})"
|
opoo "Unable to stop `#{service.name}` (label: #{service.service_name})"
|
||||||
|
@ -53,6 +53,7 @@ module Homebrew
|
|||||||
return out unless verbose
|
return out unless verbose
|
||||||
|
|
||||||
out += "File: #{hash[:file]} #{pretty_bool(hash[:file].present?)}\n"
|
out += "File: #{hash[:file]} #{pretty_bool(hash[:file].present?)}\n"
|
||||||
|
out += "Registered at login: #{pretty_bool(hash[:registered])}\n"
|
||||||
out += "Command: #{hash[:command]}\n" unless hash[:command].nil?
|
out += "Command: #{hash[:command]}\n" unless hash[:command].nil?
|
||||||
out += "Working directory: #{hash[:working_dir]}\n" unless hash[:working_dir].nil?
|
out += "Working directory: #{hash[:working_dir]}\n" unless hash[:working_dir].nil?
|
||||||
out += "Root directory: #{hash[:root_dir]}\n" unless hash[:root_dir].nil?
|
out += "Root directory: #{hash[:root_dir]}\n" unless hash[:root_dir].nil?
|
||||||
|
@ -14,8 +14,14 @@ module Homebrew
|
|||||||
|
|
||||||
TRIGGERS = %w[restart relaunch reload r].freeze
|
TRIGGERS = %w[restart relaunch reload r].freeze
|
||||||
|
|
||||||
sig { params(targets: T::Array[Services::FormulaWrapper], verbose: T::Boolean).void }
|
sig {
|
||||||
def self.run(targets, verbose:)
|
params(
|
||||||
|
targets: T::Array[Services::FormulaWrapper],
|
||||||
|
custom_plist: T.nilable(String),
|
||||||
|
verbose: T::Boolean,
|
||||||
|
).void
|
||||||
|
}
|
||||||
|
def self.run(targets, custom_plist, verbose:)
|
||||||
Services::Cli.check(targets)
|
Services::Cli.check(targets)
|
||||||
|
|
||||||
ran = []
|
ran = []
|
||||||
@ -30,8 +36,8 @@ module Homebrew
|
|||||||
Services::Cli.stop([service], verbose:) if service.loaded?
|
Services::Cli.stop([service], verbose:) if service.loaded?
|
||||||
end
|
end
|
||||||
|
|
||||||
Services::Cli.run(targets, verbose:) if ran.present?
|
Services::Cli.run(targets, custom_plist, verbose:) if ran.present?
|
||||||
Services::Cli.start(started, verbose:) if started.present?
|
Services::Cli.start(started, custom_plist, verbose:) if started.present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -15,11 +15,12 @@ module Homebrew
|
|||||||
verbose: T::Boolean,
|
verbose: T::Boolean,
|
||||||
no_wait: T::Boolean,
|
no_wait: T::Boolean,
|
||||||
max_wait: T.nilable(Float),
|
max_wait: T.nilable(Float),
|
||||||
|
keep: T::Boolean,
|
||||||
).void
|
).void
|
||||||
}
|
}
|
||||||
def self.run(targets, verbose:, no_wait:, max_wait:)
|
def self.run(targets, verbose:, no_wait:, max_wait:, keep:)
|
||||||
Services::Cli.check(targets)
|
Services::Cli.check(targets)
|
||||||
Services::Cli.stop(targets, verbose:, no_wait:, max_wait:)
|
Services::Cli.stop(targets, verbose:, no_wait:, max_wait:, keep:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -201,6 +201,7 @@ module Homebrew
|
|||||||
user: owner,
|
user: owner,
|
||||||
status: status_symbol,
|
status: status_symbol,
|
||||||
file: service_file_present? ? dest : service_file,
|
file: service_file_present? ? dest : service_file,
|
||||||
|
registered: service_file_present?,
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash unless service?
|
return hash unless service?
|
||||||
|
@ -59,6 +59,9 @@ class Homebrew::Cmd::Bundle::Args < Homebrew::CLI::Args
|
|||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def no_vscode?; end
|
def no_vscode?; end
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
|
def services?; end
|
||||||
|
|
||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def tap?; end
|
def tap?; end
|
||||||
|
|
||||||
|
@ -20,6 +20,9 @@ class Homebrew::Cmd::Services::Args < Homebrew::CLI::Args
|
|||||||
sig { returns(T::Boolean) }
|
sig { returns(T::Boolean) }
|
||||||
def json?; end
|
def json?; end
|
||||||
|
|
||||||
|
sig { returns(T::Boolean) }
|
||||||
|
def keep?; end
|
||||||
|
|
||||||
sig { returns(T.nilable(String)) }
|
sig { returns(T.nilable(String)) }
|
||||||
def max_wait; end
|
def max_wait; end
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ RSpec.describe Homebrew::Bundle::BrewInstaller do
|
|||||||
context "with a successful installation" do
|
context "with a successful installation" do
|
||||||
it "start service" do
|
it "start service" do
|
||||||
expect(Homebrew::Bundle::BrewServices).to \
|
expect(Homebrew::Bundle::BrewServices).to \
|
||||||
receive(:start).with(formula_name, verbose: false).and_return(true)
|
receive(:start).with(formula_name, file: nil, verbose: false).and_return(true)
|
||||||
described_class.preinstall(formula_name, start_service: true)
|
described_class.preinstall(formula_name, start_service: true)
|
||||||
described_class.install(formula_name, start_service: true)
|
described_class.install(formula_name, start_service: true)
|
||||||
end
|
end
|
||||||
@ -67,7 +67,7 @@ RSpec.describe Homebrew::Bundle::BrewInstaller do
|
|||||||
context "with a skipped installation" do
|
context "with a skipped installation" do
|
||||||
it "start service" do
|
it "start service" do
|
||||||
expect(Homebrew::Bundle::BrewServices).to \
|
expect(Homebrew::Bundle::BrewServices).to \
|
||||||
receive(:start).with(formula_name, verbose: false).and_return(true)
|
receive(:start).with(formula_name, file: nil, verbose: false).and_return(true)
|
||||||
described_class.install(formula_name, preinstall: false, start_service: true)
|
described_class.install(formula_name, preinstall: false, start_service: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -83,7 +83,7 @@ RSpec.describe Homebrew::Bundle::BrewInstaller do
|
|||||||
context "with a successful installation" do
|
context "with a successful installation" do
|
||||||
it "restart service" do
|
it "restart service" do
|
||||||
expect(Homebrew::Bundle::BrewServices).to \
|
expect(Homebrew::Bundle::BrewServices).to \
|
||||||
receive(:restart).with(formula_name, verbose: false).and_return(true)
|
receive(:restart).with(formula_name, file: nil, verbose: false).and_return(true)
|
||||||
described_class.preinstall(formula_name, restart_service: :always)
|
described_class.preinstall(formula_name, restart_service: :always)
|
||||||
described_class.install(formula_name, restart_service: :always)
|
described_class.install(formula_name, restart_service: :always)
|
||||||
end
|
end
|
||||||
@ -92,7 +92,7 @@ RSpec.describe Homebrew::Bundle::BrewInstaller do
|
|||||||
context "with a skipped installation" do
|
context "with a skipped installation" do
|
||||||
it "restart service" do
|
it "restart service" do
|
||||||
expect(Homebrew::Bundle::BrewServices).to \
|
expect(Homebrew::Bundle::BrewServices).to \
|
||||||
receive(:restart).with(formula_name, verbose: false).and_return(true)
|
receive(:restart).with(formula_name, file: nil, verbose: false).and_return(true)
|
||||||
described_class.install(formula_name, preinstall: false, restart_service: :always)
|
described_class.install(formula_name, preinstall: false, restart_service: :always)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -201,7 +201,8 @@ RSpec.describe Homebrew::Bundle::BrewInstaller do
|
|||||||
verbose:).and_return(true)
|
verbose:).and_return(true)
|
||||||
expect(Homebrew::Bundle::BrewServices).to receive(:stop).with("mysql55", verbose:).and_return(true)
|
expect(Homebrew::Bundle::BrewServices).to receive(:stop).with("mysql55", verbose:).and_return(true)
|
||||||
expect(Homebrew::Bundle::BrewServices).to receive(:stop).with("mysql56", verbose:).and_return(true)
|
expect(Homebrew::Bundle::BrewServices).to receive(:stop).with("mysql56", verbose:).and_return(true)
|
||||||
expect(Homebrew::Bundle::BrewServices).to receive(:restart).with(formula_name, verbose:).and_return(true)
|
expect(Homebrew::Bundle::BrewServices).to receive(:restart).with(formula_name, file: nil,
|
||||||
|
verbose:).and_return(true)
|
||||||
described_class.preinstall(formula_name, restart_service: :always, conflicts_with: ["mysql56"])
|
described_class.preinstall(formula_name, restart_service: :always, conflicts_with: ["mysql56"])
|
||||||
described_class.install(formula_name, restart_service: :always, conflicts_with: ["mysql56"])
|
described_class.install(formula_name, restart_service: :always, conflicts_with: ["mysql56"])
|
||||||
end
|
end
|
||||||
@ -216,7 +217,8 @@ RSpec.describe Homebrew::Bundle::BrewInstaller do
|
|||||||
verbose:).and_return(true)
|
verbose:).and_return(true)
|
||||||
expect(Homebrew::Bundle::BrewServices).to receive(:stop).with("mysql55", verbose:).and_return(true)
|
expect(Homebrew::Bundle::BrewServices).to receive(:stop).with("mysql55", verbose:).and_return(true)
|
||||||
expect(Homebrew::Bundle::BrewServices).to receive(:stop).with("mysql56", verbose:).and_return(true)
|
expect(Homebrew::Bundle::BrewServices).to receive(:stop).with("mysql56", verbose:).and_return(true)
|
||||||
expect(Homebrew::Bundle::BrewServices).to receive(:restart).with(formula_name, verbose:).and_return(true)
|
expect(Homebrew::Bundle::BrewServices).to receive(:restart).with(formula_name, file: nil,
|
||||||
|
verbose:).and_return(true)
|
||||||
described_class.preinstall(formula_name, restart_service: :always, conflicts_with: ["mysql56"], verbose: true)
|
described_class.preinstall(formula_name, restart_service: :always, conflicts_with: ["mysql56"], verbose: true)
|
||||||
described_class.install(formula_name, restart_service: :always, conflicts_with: ["mysql56"], verbose: true)
|
described_class.install(formula_name, restart_service: :always, conflicts_with: ["mysql56"], verbose: true)
|
||||||
end
|
end
|
||||||
|
@ -46,6 +46,14 @@ RSpec.describe Homebrew::Bundle::BrewServices do
|
|||||||
expect(described_class.started_services).to include("nginx")
|
expect(described_class.started_services).to include("nginx")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "runs the service" do
|
||||||
|
allow(described_class).to receive(:started_services).and_return([])
|
||||||
|
expect(Homebrew::Bundle).to receive(:system).with(HOMEBREW_BREW_FILE, "services", "run", "nginx",
|
||||||
|
verbose: false).and_return(true)
|
||||||
|
expect(described_class.run("nginx")).to be(true)
|
||||||
|
expect(described_class.started_services).to include("nginx")
|
||||||
|
end
|
||||||
|
|
||||||
it "restarts the service" do
|
it "restarts the service" do
|
||||||
allow(described_class).to receive(:started_services).and_return([])
|
allow(described_class).to receive(:started_services).and_return([])
|
||||||
expect(Homebrew::Bundle).to receive(:system).with(HOMEBREW_BREW_FILE, "services", "restart", "nginx",
|
expect(Homebrew::Bundle).to receive(:system).with(HOMEBREW_BREW_FILE, "services", "restart", "nginx",
|
||||||
@ -54,4 +62,32 @@ RSpec.describe Homebrew::Bundle::BrewServices do
|
|||||||
expect(described_class.started_services).to include("nginx")
|
expect(described_class.started_services).to include("nginx")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".versioned_service_file" do
|
||||||
|
let(:foo) do
|
||||||
|
instance_double(
|
||||||
|
Formula,
|
||||||
|
name: "fooformula",
|
||||||
|
version: "1.0",
|
||||||
|
rack: HOMEBREW_CELLAR/"fooformula",
|
||||||
|
plist_name: "homebrew.mxcl.fooformula",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the versioned service file" do
|
||||||
|
expect(Formula).to receive(:[]).with(foo.name).and_return(foo)
|
||||||
|
expect(Homebrew::Bundle).to receive(:formula_versions_from_env).and_return(foo.name => foo.version)
|
||||||
|
|
||||||
|
prefix = foo.rack/"1.0"
|
||||||
|
allow(FileTest).to receive(:directory?).and_call_original
|
||||||
|
expect(FileTest).to receive(:directory?).with(prefix.to_s).and_return(true)
|
||||||
|
|
||||||
|
service_file = prefix/"#{foo.plist_name}.plist"
|
||||||
|
expect(Homebrew::Services::System).to receive(:launchctl?).and_return(true)
|
||||||
|
allow(FileTest).to receive(:file?).and_call_original
|
||||||
|
expect(FileTest).to receive(:file?).with(service_file.to_s).and_return(true)
|
||||||
|
|
||||||
|
expect(described_class.versioned_service_file(foo.name)).to eq(service_file)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -89,7 +89,7 @@ RSpec.describe Homebrew::Services::Commands::Info do
|
|||||||
it "returns verbose output" do
|
it "returns verbose output" do
|
||||||
out = "service ()\nRunning: true\n"
|
out = "service ()\nRunning: true\n"
|
||||||
out += "Loaded: true\nSchedulable: false\n"
|
out += "Loaded: true\nSchedulable: false\n"
|
||||||
out += "User: user\nPID: 42\nFile: /dev/null true\nCommand: /bin/command\n"
|
out += "User: user\nPID: 42\nFile: /dev/null true\nRegistered at login: true\nCommand: /bin/command\n"
|
||||||
out += "Working directory: /working/dir\nRoot directory: /root/dir\nLog: /log/dir\nError log: /log/dir/error\n"
|
out += "Working directory: /working/dir\nRoot directory: /root/dir\nLog: /log/dir\nError log: /log/dir/error\n"
|
||||||
out += "Interval: 3600s\nCron: 5 * * * *\n"
|
out += "Interval: 3600s\nCron: 5 * * * *\n"
|
||||||
formula = {
|
formula = {
|
||||||
@ -97,6 +97,7 @@ RSpec.describe Homebrew::Services::Commands::Info do
|
|||||||
user: "user",
|
user: "user",
|
||||||
status: :started,
|
status: :started,
|
||||||
file: "/dev/null",
|
file: "/dev/null",
|
||||||
|
registered: true,
|
||||||
running: true,
|
running: true,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
schedulable: false,
|
schedulable: false,
|
||||||
|
@ -12,7 +12,7 @@ RSpec.describe Homebrew::Services::Commands::Restart do
|
|||||||
describe "#run" do
|
describe "#run" do
|
||||||
it "fails with empty list" do
|
it "fails with empty list" do
|
||||||
expect do
|
expect do
|
||||||
described_class.run([], verbose: false)
|
described_class.run([], nil, verbose: false)
|
||||||
end.to raise_error UsageError, "Invalid usage: Formula(e) missing, please provide a formula name or use --all"
|
end.to raise_error UsageError, "Invalid usage: Formula(e) missing, please provide a formula name or use --all"
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ RSpec.describe Homebrew::Services::Commands::Restart do
|
|||||||
expect(Homebrew::Services::Cli).not_to receive(:stop)
|
expect(Homebrew::Services::Cli).not_to receive(:stop)
|
||||||
expect(Homebrew::Services::Cli).to receive(:start).once
|
expect(Homebrew::Services::Cli).to receive(:start).once
|
||||||
service = instance_double(Homebrew::Services::FormulaWrapper, service_name: "name", loaded?: false)
|
service = instance_double(Homebrew::Services::FormulaWrapper, service_name: "name", loaded?: false)
|
||||||
expect { described_class.run([service], verbose: false) }.not_to raise_error
|
expect { described_class.run([service], nil, verbose: false) }.not_to raise_error
|
||||||
end
|
end
|
||||||
|
|
||||||
it "starts if services are loaded with file" do
|
it "starts if services are loaded with file" do
|
||||||
@ -30,7 +30,7 @@ RSpec.describe Homebrew::Services::Commands::Restart do
|
|||||||
expect(Homebrew::Services::Cli).to receive(:stop).once
|
expect(Homebrew::Services::Cli).to receive(:stop).once
|
||||||
service = instance_double(Homebrew::Services::FormulaWrapper, service_name: "name", loaded?: true,
|
service = instance_double(Homebrew::Services::FormulaWrapper, service_name: "name", loaded?: true,
|
||||||
service_file_present?: true)
|
service_file_present?: true)
|
||||||
expect { described_class.run([service], verbose: false) }.not_to raise_error
|
expect { described_class.run([service], nil, verbose: false) }.not_to raise_error
|
||||||
end
|
end
|
||||||
|
|
||||||
it "runs if services are loaded without file" do
|
it "runs if services are loaded without file" do
|
||||||
@ -39,7 +39,7 @@ service_file_present?: true)
|
|||||||
expect(Homebrew::Services::Cli).to receive(:stop).once
|
expect(Homebrew::Services::Cli).to receive(:stop).once
|
||||||
service = instance_double(Homebrew::Services::FormulaWrapper, service_name: "name", loaded?: true,
|
service = instance_double(Homebrew::Services::FormulaWrapper, service_name: "name", loaded?: true,
|
||||||
service_file_present?: false)
|
service_file_present?: false)
|
||||||
expect { described_class.run([service], verbose: false) }.not_to raise_error
|
expect { described_class.run([service], nil, verbose: false) }.not_to raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -371,6 +371,7 @@ RSpec.describe Homebrew::Services::FormulaWrapper do
|
|||||||
loaded: false,
|
loaded: false,
|
||||||
name: "mysql",
|
name: "mysql",
|
||||||
pid: nil,
|
pid: nil,
|
||||||
|
registered: false,
|
||||||
running: false,
|
running: false,
|
||||||
schedulable: nil,
|
schedulable: nil,
|
||||||
service_name: "plist-mysql-test",
|
service_name: "plist-mysql-test",
|
||||||
@ -384,13 +385,14 @@ RSpec.describe Homebrew::Services::FormulaWrapper do
|
|||||||
ENV["HOME"] = "/tmp_home"
|
ENV["HOME"] = "/tmp_home"
|
||||||
allow(Homebrew::Services::System).to receive_messages(launchctl?: true, systemctl?: false)
|
allow(Homebrew::Services::System).to receive_messages(launchctl?: true, systemctl?: false)
|
||||||
expect(service).to receive(:service?).twice.and_return(false)
|
expect(service).to receive(:service?).twice.and_return(false)
|
||||||
expect(service).to receive(:service_file_present?).and_return(true)
|
expect(service).to receive(:service_file_present?).twice.and_return(true)
|
||||||
expected = {
|
expected = {
|
||||||
exit_code: nil,
|
exit_code: nil,
|
||||||
file: Pathname.new("/tmp_home/Library/LaunchAgents/homebrew.mysql.plist"),
|
file: Pathname.new("/tmp_home/Library/LaunchAgents/homebrew.mysql.plist"),
|
||||||
loaded: false,
|
loaded: false,
|
||||||
name: "mysql",
|
name: "mysql",
|
||||||
pid: nil,
|
pid: nil,
|
||||||
|
registered: true,
|
||||||
running: false,
|
running: false,
|
||||||
schedulable: nil,
|
schedulable: nil,
|
||||||
service_name: "plist-mysql-test",
|
service_name: "plist-mysql-test",
|
||||||
@ -404,7 +406,7 @@ RSpec.describe Homebrew::Services::FormulaWrapper do
|
|||||||
ENV["HOME"] = "/tmp_home"
|
ENV["HOME"] = "/tmp_home"
|
||||||
allow(Homebrew::Services::System).to receive_messages(launchctl?: true, systemctl?: false)
|
allow(Homebrew::Services::System).to receive_messages(launchctl?: true, systemctl?: false)
|
||||||
expect(service).to receive(:service?).twice.and_return(true)
|
expect(service).to receive(:service?).twice.and_return(true)
|
||||||
expect(service).to receive(:service_file_present?).and_return(true)
|
expect(service).to receive(:service_file_present?).twice.and_return(true)
|
||||||
expect(service).to receive(:load_service).twice.and_return(service_object)
|
expect(service).to receive(:load_service).twice.and_return(service_object)
|
||||||
expected = {
|
expected = {
|
||||||
command: "/bin/cmd",
|
command: "/bin/cmd",
|
||||||
@ -417,6 +419,7 @@ RSpec.describe Homebrew::Services::FormulaWrapper do
|
|||||||
log_path: nil,
|
log_path: nil,
|
||||||
name: "mysql",
|
name: "mysql",
|
||||||
pid: nil,
|
pid: nil,
|
||||||
|
registered: true,
|
||||||
root_dir: nil,
|
root_dir: nil,
|
||||||
running: false,
|
running: false,
|
||||||
schedulable: false,
|
schedulable: false,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user