From da003521c6383bca18a1121a75590a3a695f3c5e Mon Sep 17 00:00:00 2001 From: Bo Anderson Date: Wed, 19 Mar 2025 05:49:26 +0000 Subject: [PATCH] Support `--file` for `brew services run` --- Library/Homebrew/cmd/services.rb | 13 +++++++--- Library/Homebrew/services/cli.rb | 29 +++++++++++++++------- Library/Homebrew/services/commands/run.rb | 12 ++++++--- Library/Homebrew/test/services/cli_spec.rb | 12 +++++++++ 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/Library/Homebrew/cmd/services.rb b/Library/Homebrew/cmd/services.rb index e2dcd80b95..2a5938e3f0 100644 --- a/Library/Homebrew/cmd/services.rb +++ b/Library/Homebrew/cmd/services.rb @@ -32,7 +32,7 @@ module Homebrew [`sudo`] `brew services info` (|`--all`|`--json`): List all managed services for the current user (or root). - [`sudo`] `brew services run` (|`--all`): + [`sudo`] `brew services run` (|`--all`|`--file=`): Run the service without registering to launch at login (or boot). [`sudo`] `brew services start` (|`--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 diff --git a/Library/Homebrew/services/cli.rb b/Library/Homebrew/services/cli.rb index ea1b78568f..8e7e009526 100644 --- a/Library/Homebrew/services/cli.rb +++ b/Library/Homebrew/services/cli.rb @@ -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 diff --git a/Library/Homebrew/services/commands/run.rb b/Library/Homebrew/services/commands/run.rb index 467d31a7df..b46cc0c75b 100644 --- a/Library/Homebrew/services/commands/run.rb +++ b/Library/Homebrew/services/commands/run.rb @@ -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 diff --git a/Library/Homebrew/test/services/cli_spec.rb b/Library/Homebrew/test/services/cli_spec.rb index dead5151f8..8135b8fe13 100644 --- a/Library/Homebrew/test/services/cli_spec.rb +++ b/Library/Homebrew/test/services/cli_spec.rb @@ -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