Merge pull request #19535 from Homebrew/services-run-file

Support `--file` for `brew services run`
This commit is contained in:
Mike McQuaid 2025-03-19 09:08:02 +00:00 committed by GitHub
commit 2fb3f35634
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 50 additions and 16 deletions

View File

@ -32,7 +32,7 @@ module Homebrew
[`sudo`] `brew services info` (<formula>|`--all`|`--json`):
List all managed services for the current user (or root).
[`sudo`] `brew services run` (<formula>|`--all`):
[`sudo`] `brew services run` (<formula>|`--all`|`--file=`):
Run the service <formula> without registering to launch at login (or boot).
[`sudo`] `brew services start` (<formula>|`--all`|`--file=`):
@ -105,10 +105,15 @@ module Homebrew
end
if args.file
if Homebrew::Services::Commands::Start::TRIGGERS.exclude?(subcommand)
file_commands = [
*Homebrew::Services::Commands::Start::TRIGGERS,
*Homebrew::Services::Commands::Run::TRIGGERS,
]
if file_commands.exclude?(subcommand)
raise UsageError, "The `#{subcommand}` subcommand does not accept the --file= argument!"
elsif args.all?
raise UsageError, "The start subcommand does not accept the --all and --file= arguments at the same time!"
raise UsageError,
"The `#{subcommand}` subcommand does not accept the --all and --file= arguments at the same time!"
end
end
@ -153,7 +158,7 @@ module Homebrew
when *Homebrew::Services::Commands::Restart::TRIGGERS
Homebrew::Services::Commands::Restart.run(targets, verbose: args.verbose?)
when *Homebrew::Services::Commands::Run::TRIGGERS
Homebrew::Services::Commands::Run.run(targets, verbose: args.verbose?)
Homebrew::Services::Commands::Run.run(targets, args.file, verbose: args.verbose?)
when *Homebrew::Services::Commands::Start::TRIGGERS
Homebrew::Services::Commands::Start.run(targets, args.file, verbose: args.verbose?)
when *Homebrew::Services::Commands::Stop::TRIGGERS

View File

@ -79,8 +79,19 @@ module Homebrew
end
# Run a service as defined in the formula. This does not clean the service file like `start` does.
sig { params(targets: T::Array[Services::FormulaWrapper], verbose: T::Boolean).void }
def self.run(targets, verbose: false)
sig {
params(
targets: T::Array[Services::FormulaWrapper],
service_file: T.nilable(String),
verbose: T::Boolean,
).void
}
def self.run(targets, service_file = nil, verbose: false)
if service_file.present?
file = Pathname.new service_file
raise UsageError, "Provided service file does not exist" unless file.exist?
end
targets.each do |service|
if service.pid?
puts "Service `#{service.name}` already running, use `#{bin} restart #{service.name}` to restart."
@ -90,7 +101,7 @@ module Homebrew
next
end
service_load(service, enable: false)
service_load(service, file, enable: false)
end
end
@ -98,7 +109,7 @@ module Homebrew
sig {
params(
targets: T::Array[Services::FormulaWrapper],
service_file: T.nilable(T.any(String, Pathname)),
service_file: T.nilable(String),
verbose: T::Boolean,
).void
}
@ -137,7 +148,7 @@ module Homebrew
next if take_root_ownership(service).nil? && System.root?
service_load(service, enable: true)
service_load(service, nil, enable: true)
end
end
@ -313,8 +324,8 @@ module Homebrew
System::Systemctl.run("enable", service.service_name) if enable
end
sig { params(service: Services::FormulaWrapper, enable: T::Boolean).void }
def self.service_load(service, enable:)
sig { params(service: Services::FormulaWrapper, file: T.nilable(Pathname), enable: T::Boolean).void }
def self.service_load(service, file, enable:)
if System.root? && !service.service_startup?
opoo "#{service.name} must be run as non-root to start at user login!"
elsif !System.root? && service.service_startup?
@ -322,12 +333,12 @@ module Homebrew
end
if System.launchctl?
file = enable ? service.dest : service.service_file
file ||= enable ? service.dest : service.service_file
launchctl_load(service, file:, enable:)
elsif System.systemctl?
# Systemctl loads based upon location so only install service
# file when it is not installed. Used with the `run` command.
install_service_file(service, nil) unless service.dest.exist?
install_service_file(service, file) unless service.dest.exist?
systemd_load(service, enable:)
end

View File

@ -9,10 +9,16 @@ module Homebrew
module Run
TRIGGERS = ["run"].freeze
sig { params(targets: T::Array[Services::FormulaWrapper], verbose: T::Boolean).void }
def self.run(targets, verbose:)
sig {
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.run(targets, verbose:)
Services::Cli.run(targets, custom_plist, verbose:)
end
end
end

View File

@ -83,6 +83,13 @@ RSpec.describe Homebrew::Services::Cli do
end
describe "#run" do
it "checks missing file causes error" do
expect(Homebrew::Services::System).not_to receive(:root?)
expect do
services_cli.start(["service_name"], "/non/existent/path")
end.to raise_error(UsageError, "Invalid usage: Provided service file does not exist")
end
it "checks empty targets cause no error" do
expect(Homebrew::Services::System).not_to receive(:root?)
services_cli.run([])
@ -225,6 +232,7 @@ RSpec.describe Homebrew::Services::Cli do
service_name: "service.name",
service_startup?: false,
),
nil,
enable: false,
)
end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout
@ -242,6 +250,7 @@ RSpec.describe Homebrew::Services::Cli do
service_name: "service.name",
service_startup?: true,
),
nil,
enable: false,
)
end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout
@ -261,6 +270,7 @@ RSpec.describe Homebrew::Services::Cli do
service_startup?: false,
service_file: instance_double(Pathname, exist?: false),
),
nil,
enable: false,
)
end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout
@ -280,6 +290,7 @@ RSpec.describe Homebrew::Services::Cli do
service_startup?: false,
dest: instance_double(Pathname, exist?: true),
),
nil,
enable: false,
)
end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout
@ -299,6 +310,7 @@ RSpec.describe Homebrew::Services::Cli do
service_startup?: false,
dest: instance_double(Pathname, exist?: true),
),
nil,
enable: true,
)
end.to output("==> Successfully started `name` (label: service.name)\n").to_stdout