mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
192 lines
8.5 KiB
Ruby
192 lines
8.5 KiB
Ruby
# typed: strict
|
|
# frozen_string_literal: true
|
|
|
|
require "abstract_command"
|
|
require "services/system"
|
|
require "services/commands/list"
|
|
require "services/commands/cleanup"
|
|
require "services/commands/info"
|
|
require "services/commands/restart"
|
|
require "services/commands/run"
|
|
require "services/commands/start"
|
|
require "services/commands/stop"
|
|
require "services/commands/kill"
|
|
|
|
module Homebrew
|
|
module Cmd
|
|
class Services < AbstractCommand
|
|
cmd_args do
|
|
usage_banner <<~EOS
|
|
`services` [<subcommand>]
|
|
|
|
Manage background services with macOS' `launchctl`(1) daemon manager or
|
|
Linux's `systemctl`(1) service manager.
|
|
|
|
If `sudo` is passed, operate on `/Library/LaunchDaemons` or `/usr/lib/systemd/system` (started at boot).
|
|
Otherwise, operate on `~/Library/LaunchAgents` or `~/.config/systemd/user` (started at login).
|
|
|
|
[`sudo`] `brew services` [`list`] (`--json`) (`--debug`):
|
|
List information about all managed services for the current user (or root).
|
|
Provides more output from Homebrew and `launchctl`(1) or `systemctl`(1) if run with `--debug`.
|
|
|
|
[`sudo`] `brew services info` (<formula>|`--all`|`--json`):
|
|
List all managed services for the current user (or root).
|
|
|
|
[`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=`):
|
|
Start the service <formula> immediately and register it to launch at login (or boot).
|
|
|
|
[`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),
|
|
unless `--keep` is specified.
|
|
|
|
[`sudo`] `brew services kill` (<formula>|`--all`):
|
|
Stop the service <formula> immediately but keep it registered to launch at login (or boot).
|
|
|
|
[`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).
|
|
|
|
[`sudo`] `brew services cleanup`:
|
|
Remove all unused services.
|
|
EOS
|
|
flag "--file=", description: "Use the service file from this location to `start` the service."
|
|
flag "--sudo-service-user=", description: "When run as root on macOS, run the service(s) as this user."
|
|
flag "--max-wait=", description: "Wait at most this many seconds for `stop` to finish stopping a service. " \
|
|
"Defaults to 60. Set this to zero (0) seconds to wait indefinitely."
|
|
switch "--all", description: "Run <subcommand> on all services."
|
|
switch "--json", description: "Output as JSON."
|
|
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"
|
|
named_args %w[list info run start stop kill restart cleanup]
|
|
end
|
|
|
|
sig { override.void }
|
|
def run
|
|
# pbpaste's exit status is a proxy for detecting the use of reattach-to-user-namespace
|
|
if ENV.fetch("HOMEBREW_TMUX", nil) && File.exist?("/usr/bin/pbpaste") && !quiet_system("/usr/bin/pbpaste")
|
|
raise UsageError,
|
|
"`brew services` cannot run under tmux!"
|
|
end
|
|
|
|
# Keep this after the .parse to keep --help fast.
|
|
require "utils"
|
|
|
|
if !Homebrew::Services::System.launchctl? && !Homebrew::Services::System.systemctl?
|
|
raise UsageError,
|
|
"`brew services` is supported only on macOS or Linux (with systemd)!"
|
|
end
|
|
|
|
if (sudo_service_user = args.sudo_service_user)
|
|
unless Homebrew::Services::System.root?
|
|
raise UsageError,
|
|
"`brew services` is supported only when running as root!"
|
|
end
|
|
|
|
unless Homebrew::Services::System.launchctl?
|
|
raise UsageError,
|
|
"`brew services --sudo-service-user` is currently supported only on macOS " \
|
|
"(but we'd love a PR to add Linux support)!"
|
|
end
|
|
|
|
Homebrew::Services::Cli.sudo_service_user = sudo_service_user
|
|
end
|
|
|
|
# Parse arguments.
|
|
subcommand, *formulae = args.named
|
|
|
|
no_named_formula_commands = [
|
|
*Homebrew::Services::Commands::List::TRIGGERS,
|
|
*Homebrew::Services::Commands::Cleanup::TRIGGERS,
|
|
]
|
|
if no_named_formula_commands.include?(subcommand)
|
|
raise UsageError, "The `#{subcommand}` subcommand does not accept a formula argument!" if formulae.present?
|
|
raise UsageError, "The `#{subcommand}` subcommand does not accept the --all argument!" if args.all?
|
|
end
|
|
|
|
if args.file
|
|
file_commands = [
|
|
*Homebrew::Services::Commands::Start::TRIGGERS,
|
|
*Homebrew::Services::Commands::Run::TRIGGERS,
|
|
*Homebrew::Services::Commands::Restart::TRIGGERS,
|
|
]
|
|
if file_commands.exclude?(subcommand)
|
|
raise UsageError, "The `#{subcommand}` subcommand does not accept the --file= argument!"
|
|
elsif args.all?
|
|
raise UsageError,
|
|
"The `#{subcommand}` subcommand does not accept the --all and --file= arguments at the same time!"
|
|
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?
|
|
|
|
targets = if args.all?
|
|
if subcommand == "start"
|
|
Homebrew::Services::Formulae.available_services(
|
|
loaded: false,
|
|
skip_root: !Homebrew::Services::System.root?,
|
|
)
|
|
elsif subcommand == "stop"
|
|
Homebrew::Services::Formulae.available_services(
|
|
loaded: true,
|
|
skip_root: !Homebrew::Services::System.root?,
|
|
)
|
|
else
|
|
Homebrew::Services::Formulae.available_services
|
|
end
|
|
elsif formulae.present?
|
|
formulae.map { |formula| Homebrew::Services::FormulaWrapper.new(Formulary.factory(formula)) }
|
|
else
|
|
[]
|
|
end
|
|
|
|
# Exit successfully if --all was used but there is nothing to do
|
|
return if args.all? && targets.empty?
|
|
|
|
if Homebrew::Services::System.systemctl?
|
|
ENV["DBUS_SESSION_BUS_ADDRESS"] = ENV.fetch("HOMEBREW_DBUS_SESSION_BUS_ADDRESS", nil)
|
|
ENV["XDG_RUNTIME_DIR"] = ENV.fetch("HOMEBREW_XDG_RUNTIME_DIR", nil)
|
|
end
|
|
|
|
# Dispatch commands and aliases.
|
|
case subcommand.presence
|
|
when *Homebrew::Services::Commands::List::TRIGGERS
|
|
Homebrew::Services::Commands::List.run(json: args.json?)
|
|
when *Homebrew::Services::Commands::Cleanup::TRIGGERS
|
|
Homebrew::Services::Commands::Cleanup.run
|
|
when *Homebrew::Services::Commands::Info::TRIGGERS
|
|
Homebrew::Services::Commands::Info.run(targets, verbose: args.verbose?, json: args.json?)
|
|
when *Homebrew::Services::Commands::Restart::TRIGGERS
|
|
Homebrew::Services::Commands::Restart.run(targets, args.file, verbose: args.verbose?)
|
|
when *Homebrew::Services::Commands::Run::TRIGGERS
|
|
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
|
|
Homebrew::Services::Commands::Stop.run(
|
|
targets,
|
|
verbose: args.verbose?,
|
|
no_wait: args.no_wait?,
|
|
max_wait: args.max_wait&.to_f || 60.0,
|
|
keep: args.keep?,
|
|
)
|
|
when *Homebrew::Services::Commands::Kill::TRIGGERS
|
|
Homebrew::Services::Commands::Kill.run(targets, verbose: args.verbose?)
|
|
else
|
|
raise UsageError, "unknown subcommand: `#{subcommand}`"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|