Fold brew bundle services into exec
This commit is contained in:
parent
c7e8b66da3
commit
650f62bcba
@ -158,10 +158,10 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
if services
|
if services
|
||||||
require "bundle/commands/services"
|
require "bundle/brew_services"
|
||||||
|
|
||||||
exit_code = 0
|
exit_code = 0
|
||||||
Services.run_services(@dsl.entries) do
|
run_services(@dsl.entries) do
|
||||||
Kernel.system(*args)
|
Kernel.system(*args)
|
||||||
exit_code = $CHILD_STATUS.exitstatus
|
exit_code = $CHILD_STATUS.exitstatus
|
||||||
end
|
end
|
||||||
@ -170,6 +170,123 @@ module Homebrew
|
|||||||
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
|
||||||
|
|||||||
@ -1,143 +0,0 @@
|
|||||||
# typed: strict
|
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require "bundle/brewfile"
|
|
||||||
require "bundle/brew_services"
|
|
||||||
require "formula"
|
|
||||||
|
|
||||||
module Homebrew
|
|
||||||
module Bundle
|
|
||||||
module Commands
|
|
||||||
module Services
|
|
||||||
sig { params(args: String, global: T::Boolean, file: T.nilable(String)).void }
|
|
||||||
def self.run(*args, global:, file:)
|
|
||||||
raise UsageError, "invalid `brew bundle services` arguments" if args.length != 1
|
|
||||||
|
|
||||||
parsed_entries = Brewfile.read(global:, file:).entries
|
|
||||||
|
|
||||||
subcommand = args.first
|
|
||||||
case subcommand
|
|
||||||
when "run"
|
|
||||||
run_services(parsed_entries)
|
|
||||||
when "stop"
|
|
||||||
stop_services(parsed_entries)
|
|
||||||
else
|
|
||||||
raise UsageError, "unknown bundle services subcommand: #{subcommand}"
|
|
||||||
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_entries(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 }
|
|
||||||
def self.run_services(entries, &_block)
|
|
||||||
map_entries(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 conflict["running"] && !Bundle::BrewServices.stop(conflict["name"], keep: true)
|
|
||||||
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
|
|
||||||
|
|
||||||
return unless block_given?
|
|
||||||
|
|
||||||
begin
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
stop_services(entries)
|
|
||||||
|
|
||||||
conflicting_services.each do |conflict|
|
|
||||||
if conflict["running"] && conflict["registered"] && !Bundle::BrewServices.run(conflict["name"])
|
|
||||||
opoo "Failed to restart #{conflict["name"]} service"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
sig { params(entries: T::Array[Homebrew::Bundle::Dsl::Entry]).void }
|
|
||||||
def self.stop_services(entries)
|
|
||||||
map_entries(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
|
|
||||||
@ -61,12 +61,6 @@ module Homebrew
|
|||||||
|
|
||||||
`brew bundle env`:
|
`brew bundle env`:
|
||||||
Print the environment variables that would be set in a `brew bundle exec` environment.
|
Print the environment variables that would be set in a `brew bundle exec` environment.
|
||||||
|
|
||||||
`brew bundle services run`:
|
|
||||||
Start services for formulae specified in the `Brewfile`.
|
|
||||||
|
|
||||||
`brew bundle services stop`:
|
|
||||||
Stop services for formulae specified in the `Brewfile`.
|
|
||||||
EOS
|
EOS
|
||||||
flag "--file=",
|
flag "--file=",
|
||||||
description: "Read from or write to the `Brewfile` from this location. " \
|
description: "Read from or write to the `Brewfile` from this location. " \
|
||||||
@ -141,7 +135,7 @@ module Homebrew
|
|||||||
require "bundle"
|
require "bundle"
|
||||||
|
|
||||||
subcommand = args.named.first.presence
|
subcommand = args.named.first.presence
|
||||||
if %w[exec add remove services].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
|
||||||
|
|
||||||
@ -281,10 +275,6 @@ module Homebrew
|
|||||||
require "bundle/commands/remove"
|
require "bundle/commands/remove"
|
||||||
Homebrew::Bundle::Commands::Remove.run(*named_args, type: selected_types.first, global:, file:)
|
Homebrew::Bundle::Commands::Remove.run(*named_args, type: selected_types.first, global:, file:)
|
||||||
end
|
end
|
||||||
when "services"
|
|
||||||
_, *named_args = args.named
|
|
||||||
require "bundle/commands/services"
|
|
||||||
Homebrew::Bundle::Commands::Services.run(*named_args, global:, file:)
|
|
||||||
else
|
else
|
||||||
raise UsageError, "unknown subcommand: #{subcommand}"
|
raise UsageError, "unknown subcommand: #{subcommand}"
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user