From 084ddca27a8ddbbfe67da173e463c412ce67d10a Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Thu, 13 Mar 2025 14:50:03 +0000 Subject: [PATCH] Cleanup and fix homebrew-services migration --- .devcontainer/devcontainer.json | 5 - .devcontainer/on-create-command.sh | 1 - Library/Homebrew/cmd/services.rb | 65 ++++---- .../{service/services_cli.rb => cli.rb} | 30 ++-- .../{service => }/commands/cleanup.rb | 6 +- .../services/{service => }/commands/info.rb | 9 +- Library/Homebrew/services/commands/kill.rb | 16 ++ .../services/{service => }/commands/list.rb | 7 +- .../{service => }/commands/restart.rb | 12 +- Library/Homebrew/services/commands/run.rb | 16 ++ .../services/{service => }/commands/start.rb | 8 +- .../services/{service => }/commands/stop.rb | 8 +- .../services/{service => }/formula_wrapper.rb | 2 +- .../services/{service => }/formulae.rb | 6 +- Library/Homebrew/services/service.rb | 17 -- .../services/service/commands/kill.rb | 16 -- .../Homebrew/services/service/commands/run.rb | 16 -- .../Homebrew/services/{service => }/system.rb | 2 +- .../{service => }/system/systemctl.rb | 2 +- .../{services_cli_spec.rb => cli_spec.rb} | 153 +++++++++--------- .../test/services/commands/cleanup_spec.rb | 24 +-- .../test/services/commands/info_spec.rb | 52 ++---- .../test/services/commands/list_spec.rb | 74 +++------ .../test/services/commands/restart_spec.rb | 34 ++-- .../Homebrew/test/services/formulae_spec.rb | 6 +- .../test/services/formulae_wrapper_spec.rb | 57 +++---- .../test/services/system/systemctl_spec.rb | 9 +- Library/Homebrew/test/services/system_spec.rb | 4 +- Library/Homebrew/test/spec_helper.rb | 2 +- Library/Homebrew/test/tap_spec.rb | 14 +- docs/External-Commands.md | 2 +- docs/Formula-Cookbook.md | 4 +- 32 files changed, 311 insertions(+), 368 deletions(-) rename Library/Homebrew/services/{service/services_cli.rb => cli.rb} (92%) rename Library/Homebrew/services/{service => }/commands/cleanup.rb (69%) rename Library/Homebrew/services/{service => }/commands/info.rb (90%) create mode 100644 Library/Homebrew/services/commands/kill.rb rename Library/Homebrew/services/{service => }/commands/list.rb (96%) rename Library/Homebrew/services/{service => }/commands/restart.rb (66%) create mode 100644 Library/Homebrew/services/commands/run.rb rename Library/Homebrew/services/{service => }/commands/start.rb (56%) rename Library/Homebrew/services/{service => }/commands/stop.rb (67%) rename Library/Homebrew/services/{service => }/formula_wrapper.rb (99%) rename Library/Homebrew/services/{service => }/formulae.rb (89%) delete mode 100644 Library/Homebrew/services/service.rb delete mode 100644 Library/Homebrew/services/service/commands/kill.rb delete mode 100644 Library/Homebrew/services/service/commands/run.rb rename Library/Homebrew/services/{service => }/system.rb (99%) rename Library/Homebrew/services/{service => }/system/systemctl.rb (98%) rename Library/Homebrew/test/services/{services_cli_spec.rb => cli_spec.rb} (56%) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 260f7c7d7e..dd573af595 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,11 +12,6 @@ "permissions": { "contents": "write" } - }, - "Homebrew/homebrew-services": { - "permissions": { - "contents": "write" - } } } }, diff --git a/.devcontainer/on-create-command.sh b/.devcontainer/on-create-command.sh index 7762064c88..db9856d3d3 100755 --- a/.devcontainer/on-create-command.sh +++ b/.devcontainer/on-create-command.sh @@ -25,7 +25,6 @@ brew cleanup brew tap --force homebrew/core # tap some other repos so codespaces can be used for developing multiple taps brew tap homebrew/bundle -brew tap homebrew/services # install some useful development things sudo apt-get update diff --git a/Library/Homebrew/cmd/services.rb b/Library/Homebrew/cmd/services.rb index 7fb6eadc45..044db3865b 100644 --- a/Library/Homebrew/cmd/services.rb +++ b/Library/Homebrew/cmd/services.rb @@ -2,7 +2,16 @@ # frozen_string_literal: true require "abstract_command" -require "services/service" +require "services/system" +require "services/cli" +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 @@ -64,36 +73,36 @@ module Homebrew # Keep this after the .parse to keep --help fast. require "utils" - if !::Service::System.launchctl? && !::Service::System.systemctl? + if !::Services::System.launchctl? && !::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 ::Service::System.root? + unless ::Services::System.root? raise UsageError, "`brew services` is supported only when running as root!" end - unless ::Service::System.launchctl? + unless ::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 - ::Service::ServicesCli.sudo_service_user = sudo_service_user + ::Services::Cli.sudo_service_user = sudo_service_user end # Parse arguments. subcommand, formula, = args.named - if [*::Service::Commands::List::TRIGGERS, *::Service::Commands::Cleanup::TRIGGERS].include?(subcommand) + if [*::Services::Commands::List::TRIGGERS, *::Services::Commands::Cleanup::TRIGGERS].include?(subcommand) raise UsageError, "The `#{subcommand}` subcommand does not accept a formula argument!" if formula raise UsageError, "The `#{subcommand}` subcommand does not accept the --all argument!" if args.all? end if args.file - if ::Service::Commands::Start::TRIGGERS.exclude?(subcommand) + if ::Services::Commands::Start::TRIGGERS.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!" @@ -104,14 +113,14 @@ module Homebrew targets = if args.all? if subcommand == "start" - ::Service::Formulae.available_services(loaded: false, skip_root: !::Service::System.root?) + ::Services::Formulae.available_services(loaded: false, skip_root: !::Services::System.root?) elsif subcommand == "stop" - ::Service::Formulae.available_services(loaded: true, skip_root: !::Service::System.root?) + ::Services::Formulae.available_services(loaded: true, skip_root: !::Services::System.root?) else - ::Service::Formulae.available_services + ::Services::Formulae.available_services end elsif formula - [::Service::FormulaWrapper.new(Formulary.factory(formula))] + [::Services::FormulaWrapper.new(Formulary.factory(formula))] else [] end @@ -119,30 +128,30 @@ module Homebrew # Exit successfully if --all was used but there is nothing to do return if args.all? && targets.empty? - if ::Service::System.systemctl? + if ::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 *::Service::Commands::List::TRIGGERS - ::Service::Commands::List.run(json: args.json?) - when *::Service::Commands::Cleanup::TRIGGERS - ::Service::Commands::Cleanup.run - when *::Service::Commands::Info::TRIGGERS - ::Service::Commands::Info.run(targets, verbose: args.verbose?, json: args.json?) - when *::Service::Commands::Restart::TRIGGERS - ::Service::Commands::Restart.run(targets, verbose: args.verbose?) - when *::Service::Commands::Run::TRIGGERS - ::Service::Commands::Run.run(targets, verbose: args.verbose?) - when *::Service::Commands::Start::TRIGGERS - ::Service::Commands::Start.run(targets, args.file, verbose: args.verbose?) - when *::Service::Commands::Stop::TRIGGERS + when *::Services::Commands::List::TRIGGERS + ::Services::Commands::List.run(json: args.json?) + when *::Services::Commands::Cleanup::TRIGGERS + ::Services::Commands::Cleanup.run + when *::Services::Commands::Info::TRIGGERS + ::Services::Commands::Info.run(targets, verbose: args.verbose?, json: args.json?) + when *::Services::Commands::Restart::TRIGGERS + ::Services::Commands::Restart.run(targets, verbose: args.verbose?) + when *::Services::Commands::Run::TRIGGERS + ::Services::Commands::Run.run(targets, verbose: args.verbose?) + when *::Services::Commands::Start::TRIGGERS + ::Services::Commands::Start.run(targets, args.file, verbose: args.verbose?) + when *::Services::Commands::Stop::TRIGGERS max_wait = args.max_wait.to_f - ::Service::Commands::Stop.run(targets, verbose: args.verbose?, no_wait: args.no_wait?, max_wait:) - when *::Service::Commands::Kill::TRIGGERS - ::Service::Commands::Kill.run(targets, verbose: args.verbose?) + ::Services::Commands::Stop.run(targets, verbose: args.verbose?, no_wait: args.no_wait?, max_wait:) + when *::Services::Commands::Kill::TRIGGERS + ::Services::Commands::Kill.run(targets, verbose: args.verbose?) else raise UsageError, "unknown subcommand: `#{subcommand}`" end diff --git a/Library/Homebrew/services/service/services_cli.rb b/Library/Homebrew/services/cli.rb similarity index 92% rename from Library/Homebrew/services/service/services_cli.rb rename to Library/Homebrew/services/cli.rb index 4cb2e30242..9dc301d5e9 100644 --- a/Library/Homebrew/services/service/services_cli.rb +++ b/Library/Homebrew/services/cli.rb @@ -1,8 +1,8 @@ # typed: strict # frozen_string_literal: true -module Service - module ServicesCli +module Services + module Cli extend FileUtils sig { returns(T.nilable(String)) } @@ -46,7 +46,7 @@ module Service end # Kill services that don't have a service file - sig { returns(T::Array[Service::FormulaWrapper]) } + sig { returns(T::Array[Services::FormulaWrapper]) } def self.kill_orphaned_services cleaned_labels = [] cleaned_services = [] @@ -79,7 +79,7 @@ module Service end # Run a service as defined in the formula. This does not clean the service file like `start` does. - sig { params(targets: T::Array[Service::FormulaWrapper], verbose: T.nilable(T::Boolean)).void } + sig { params(targets: T::Array[Services::FormulaWrapper], verbose: T.nilable(T::Boolean)).void } def self.run(targets, verbose: false) targets.each do |service| if service.pid? @@ -96,7 +96,7 @@ module Service # Start a service. sig { - params(targets: T::Array[Service::FormulaWrapper], service_file: T.nilable(T.any(String, Pathname)), + params(targets: T::Array[Services::FormulaWrapper], service_file: T.nilable(T.any(String, Pathname)), verbose: T.nilable(T::Boolean)).void } def self.start(targets, service_file = nil, verbose: false) @@ -138,7 +138,7 @@ module Service # Stop a service and unload it. sig { - params(targets: T::Array[Service::FormulaWrapper], + params(targets: T::Array[Services::FormulaWrapper], verbose: T.nilable(T::Boolean), no_wait: T.nilable(T::Boolean), max_wait: T.nilable(T.any(Integer, Float))).void @@ -199,7 +199,7 @@ module Service end # Stop a service but keep it registered. - sig { params(targets: T::Array[Service::FormulaWrapper], verbose: T.nilable(T::Boolean)).void } + sig { params(targets: T::Array[Services::FormulaWrapper], verbose: T.nilable(T::Boolean)).void } def self.kill(targets, verbose: false) targets.each do |service| if !service.pid? @@ -209,7 +209,7 @@ module Service else puts "Killing `#{service.name}`... (might take a while)" if System.systemctl? - System::Systemctl.quiet_run("stop", T.must(service.service_name)) + System::Systemctl.quiet_run("stop", service.service_name) elsif System.launchctl? quiet_system System.launchctl, "stop", "#{System.domain_target}/#{service.service_name}" end @@ -290,7 +290,7 @@ module Service end sig { - params(service: Service::FormulaWrapper, file: T.nilable(T.any(String, Pathname)), + params(service: Services::FormulaWrapper, file: T.nilable(T.any(String, Pathname)), enable: T.nilable(T::Boolean)).void } def self.launchctl_load(service, file:, enable:) @@ -298,13 +298,13 @@ module Service safe_system System.launchctl, "bootstrap", System.domain_target, file end - sig { params(service: Service::FormulaWrapper, enable: T.nilable(T::Boolean)).void } + sig { params(service: Services::FormulaWrapper, enable: T.nilable(T::Boolean)).void } def self.systemd_load(service, enable:) System::Systemctl.run("start", T.must(service.service_name)) System::Systemctl.run("enable", T.must(service.service_name)) if enable end - sig { params(service: Service::FormulaWrapper, enable: T.nilable(T::Boolean)).void } + sig { params(service: Services::FormulaWrapper, enable: T.nilable(T::Boolean)).void } def self.service_load(service, enable:) if System.root? && !service.service_startup? opoo "#{service.name} must be run as non-root to start at user login!" @@ -326,7 +326,7 @@ module Service ohai("Successfully #{function} `#{service.name}` (label: #{service.service_name})") end - sig { params(service: Service::FormulaWrapper, file: T.nilable(Pathname)).void } + sig { params(service: Services::FormulaWrapper, file: T.nilable(Pathname)).void } def self.install_service_file(service, file) raise UsageError, "Formula `#{service.name}` is not installed" unless service.installed? @@ -339,9 +339,9 @@ module Service temp << if T.must(file).blank? contents = T.must(service.service_file).read - if sudo_service_user && Service::System.launchctl? + if sudo_service_user && Services::System.launchctl? # set the username in the new plist file - ohai "Setting username in #{service.service_name} to #{Service::System.user}" + ohai "Setting username in #{service.service_name} to #{Services::System.user}" plist_data = Plist.parse_xml(contents, marshal: false) plist_data["UserName"] = sudo_service_user plist_data.to_plist @@ -362,7 +362,7 @@ module Service chmod 0644, service.dest - Service::System::Systemctl.run("daemon-reload") if System.systemctl? + Services::System::Systemctl.run("daemon-reload") if System.systemctl? end end end diff --git a/Library/Homebrew/services/service/commands/cleanup.rb b/Library/Homebrew/services/commands/cleanup.rb similarity index 69% rename from Library/Homebrew/services/service/commands/cleanup.rb rename to Library/Homebrew/services/commands/cleanup.rb index e5712f0a27..c8c934f684 100644 --- a/Library/Homebrew/services/service/commands/cleanup.rb +++ b/Library/Homebrew/services/commands/cleanup.rb @@ -1,7 +1,7 @@ # typed: strict # frozen_string_literal: true -module Service +module Services module Commands module Cleanup TRIGGERS = %w[cleanup clean cl rm].freeze @@ -10,8 +10,8 @@ module Service def self.run cleaned = [] - cleaned += Service::ServicesCli.kill_orphaned_services - cleaned += Service::ServicesCli.remove_unused_service_files + cleaned += Services::Cli.kill_orphaned_services + cleaned += Services::Cli.remove_unused_service_files puts "All #{System.root? ? "root" : "user-space"} services OK, nothing cleaned..." if cleaned.empty? end diff --git a/Library/Homebrew/services/service/commands/info.rb b/Library/Homebrew/services/commands/info.rb similarity index 90% rename from Library/Homebrew/services/service/commands/info.rb rename to Library/Homebrew/services/commands/info.rb index 708c0006b3..89f6f61502 100644 --- a/Library/Homebrew/services/service/commands/info.rb +++ b/Library/Homebrew/services/commands/info.rb @@ -1,17 +1,20 @@ # typed: strict # frozen_string_literal: true -module Service +require "services/formula_wrapper" +require "services/cli" + +module Services module Commands module Info TRIGGERS = %w[info i].freeze sig { - params(targets: T::Array[Service::FormulaWrapper], verbose: T.nilable(T::Boolean), + params(targets: T::Array[Services::FormulaWrapper], verbose: T.nilable(T::Boolean), json: T.nilable(T::Boolean)).void } def self.run(targets, verbose:, json:) - Service::ServicesCli.check(targets) + Services::Cli.check(targets) output = targets.map(&:to_hash) diff --git a/Library/Homebrew/services/commands/kill.rb b/Library/Homebrew/services/commands/kill.rb new file mode 100644 index 0000000000..cb92f93f66 --- /dev/null +++ b/Library/Homebrew/services/commands/kill.rb @@ -0,0 +1,16 @@ +# typed: strict +# frozen_string_literal: true + +module Services + module Commands + module Kill + TRIGGERS = %w[kill k].freeze + + sig { params(targets: T::Array[Services::FormulaWrapper], verbose: T.nilable(T::Boolean)).void } + def self.run(targets, verbose:) + Services::Cli.check(targets) + Services::Cli.kill(targets, verbose:) + end + end + end +end diff --git a/Library/Homebrew/services/service/commands/list.rb b/Library/Homebrew/services/commands/list.rb similarity index 96% rename from Library/Homebrew/services/service/commands/list.rb rename to Library/Homebrew/services/commands/list.rb index 3a227a66bf..d198d385de 100644 --- a/Library/Homebrew/services/service/commands/list.rb +++ b/Library/Homebrew/services/commands/list.rb @@ -1,9 +1,10 @@ # typed: strict # frozen_string_literal: true -require "service/formulae" +require "services/formulae" +require "services/cli" -module Service +module Services module Commands module List TRIGGERS = [nil, "list", "ls"].freeze @@ -12,7 +13,7 @@ module Service def self.run(json: false) formulae = Formulae.services_list if formulae.blank? - opoo "No services available to control with `#{Service::ServicesCli.bin}`" if $stderr.tty? + opoo "No services available to control with `#{Services::Cli.bin}`" if $stderr.tty? return end diff --git a/Library/Homebrew/services/service/commands/restart.rb b/Library/Homebrew/services/commands/restart.rb similarity index 66% rename from Library/Homebrew/services/service/commands/restart.rb rename to Library/Homebrew/services/commands/restart.rb index 9483c9eb5f..589a68a07e 100644 --- a/Library/Homebrew/services/service/commands/restart.rb +++ b/Library/Homebrew/services/commands/restart.rb @@ -1,7 +1,7 @@ # typed: strict # frozen_string_literal: true -module Service +module Services module Commands module Restart # NOTE: The restart command is used to update service files @@ -11,9 +11,9 @@ module Service TRIGGERS = %w[restart relaunch reload r].freeze - sig { params(targets: T::Array[Service::FormulaWrapper], verbose: T.nilable(T::Boolean)).returns(NilClass) } + sig { params(targets: T::Array[Services::FormulaWrapper], verbose: T.nilable(T::Boolean)).returns(NilClass) } def self.run(targets, verbose:) - Service::ServicesCli.check(targets) + Services::Cli.check(targets) ran = [] started = [] @@ -24,11 +24,11 @@ module Service # group not-started services with started ones for restart started << service end - Service::ServicesCli.stop([service], verbose:) if service.loaded? + Services::Cli.stop([service], verbose:) if service.loaded? end - Service::ServicesCli.run(targets, verbose:) if ran.present? - Service::ServicesCli.start(started, verbose:) if started.present? + Services::Cli.run(targets, verbose:) if ran.present? + Services::Cli.start(started, verbose:) if started.present? nil end end diff --git a/Library/Homebrew/services/commands/run.rb b/Library/Homebrew/services/commands/run.rb new file mode 100644 index 0000000000..26f3d7f88d --- /dev/null +++ b/Library/Homebrew/services/commands/run.rb @@ -0,0 +1,16 @@ +# typed: strict +# frozen_string_literal: true + +module Services + module Commands + module Run + TRIGGERS = ["run"].freeze + + sig { params(targets: T::Array[Services::FormulaWrapper], verbose: T.nilable(T::Boolean)).void } + def self.run(targets, verbose:) + Services::Cli.check(targets) + Services::Cli.run(targets, verbose:) + end + end + end +end diff --git a/Library/Homebrew/services/service/commands/start.rb b/Library/Homebrew/services/commands/start.rb similarity index 56% rename from Library/Homebrew/services/service/commands/start.rb rename to Library/Homebrew/services/commands/start.rb index 03c235a9b2..ef0aba3f42 100644 --- a/Library/Homebrew/services/service/commands/start.rb +++ b/Library/Homebrew/services/commands/start.rb @@ -1,18 +1,18 @@ # typed: strict # frozen_string_literal: true -module Service +module Services module Commands module Start TRIGGERS = %w[start launch load s l].freeze sig { - params(targets: T::Array[Service::FormulaWrapper], custom_plist: T.nilable(String), + params(targets: T::Array[Services::FormulaWrapper], custom_plist: T.nilable(String), verbose: T.nilable(T::Boolean)).void } def self.run(targets, custom_plist, verbose:) - Service::ServicesCli.check(targets) - Service::ServicesCli.start(targets, custom_plist, verbose:) + Services::Cli.check(targets) + Services::Cli.start(targets, custom_plist, verbose:) end end end diff --git a/Library/Homebrew/services/service/commands/stop.rb b/Library/Homebrew/services/commands/stop.rb similarity index 67% rename from Library/Homebrew/services/service/commands/stop.rb rename to Library/Homebrew/services/commands/stop.rb index df06471fcc..b3bc9dc0f8 100644 --- a/Library/Homebrew/services/service/commands/stop.rb +++ b/Library/Homebrew/services/commands/stop.rb @@ -1,20 +1,20 @@ # typed: strict # frozen_string_literal: true -module Service +module Services module Commands module Stop TRIGGERS = %w[stop unload terminate term t u].freeze sig { - params(targets: T::Array[Service::FormulaWrapper], + params(targets: T::Array[Services::FormulaWrapper], verbose: T.nilable(T::Boolean), no_wait: T.nilable(T::Boolean), max_wait: T.nilable(Float)).void } def self.run(targets, verbose:, no_wait:, max_wait:) - Service::ServicesCli.check(targets) - Service::ServicesCli.stop(targets, verbose:, no_wait:, max_wait:) + Services::Cli.check(targets) + Services::Cli.stop(targets, verbose:, no_wait:, max_wait:) end end end diff --git a/Library/Homebrew/services/service/formula_wrapper.rb b/Library/Homebrew/services/formula_wrapper.rb similarity index 99% rename from Library/Homebrew/services/service/formula_wrapper.rb rename to Library/Homebrew/services/formula_wrapper.rb index 415cf0a487..3bf0028a5a 100644 --- a/Library/Homebrew/services/service/formula_wrapper.rb +++ b/Library/Homebrew/services/formula_wrapper.rb @@ -3,7 +3,7 @@ # Wrapper for a formula to handle service-related stuff like parsing and # generating the service/plist files. -module Service +module Services class FormulaWrapper # Access the `Formula` instance. sig { returns(Formula) } diff --git a/Library/Homebrew/services/service/formulae.rb b/Library/Homebrew/services/formulae.rb similarity index 89% rename from Library/Homebrew/services/service/formulae.rb rename to Library/Homebrew/services/formulae.rb index a052d8a3b3..29836eee32 100644 --- a/Library/Homebrew/services/service/formulae.rb +++ b/Library/Homebrew/services/formulae.rb @@ -1,11 +1,13 @@ # typed: strict # frozen_string_literal: true -module Service +require "services/formula_wrapper" + +module Services module Formulae # All available services, with optional filters applied # @private - sig { params(loaded: T.nilable(T::Boolean), skip_root: T::Boolean).returns(T::Array[Service::FormulaWrapper]) } + sig { params(loaded: T.nilable(T::Boolean), skip_root: T::Boolean).returns(T::Array[Services::FormulaWrapper]) } def self.available_services(loaded: nil, skip_root: false) require "formula" diff --git a/Library/Homebrew/services/service.rb b/Library/Homebrew/services/service.rb deleted file mode 100644 index c08565a27d..0000000000 --- a/Library/Homebrew/services/service.rb +++ /dev/null @@ -1,17 +0,0 @@ -# typed: strict -# frozen_string_literal: true - -# fix loadppath -$LOAD_PATH.unshift(File.expand_path(__dir__)) - -require "service/formula_wrapper" -require "service/services_cli" -require "service/system" -require "service/commands/cleanup" -require "service/commands/info" -require "service/commands/list" -require "service/commands/restart" -require "service/commands/run" -require "service/commands/start" -require "service/commands/stop" -require "service/commands/kill" diff --git a/Library/Homebrew/services/service/commands/kill.rb b/Library/Homebrew/services/service/commands/kill.rb deleted file mode 100644 index 2f8d1fa6b6..0000000000 --- a/Library/Homebrew/services/service/commands/kill.rb +++ /dev/null @@ -1,16 +0,0 @@ -# typed: strict -# frozen_string_literal: true - -module Service - module Commands - module Kill - TRIGGERS = %w[kill k].freeze - - sig { params(targets: T::Array[Service::FormulaWrapper], verbose: T.nilable(T::Boolean)).void } - def self.run(targets, verbose:) - Service::ServicesCli.check(targets) - Service::ServicesCli.kill(targets, verbose:) - end - end - end -end diff --git a/Library/Homebrew/services/service/commands/run.rb b/Library/Homebrew/services/service/commands/run.rb deleted file mode 100644 index e4fcde1746..0000000000 --- a/Library/Homebrew/services/service/commands/run.rb +++ /dev/null @@ -1,16 +0,0 @@ -# typed: strict -# frozen_string_literal: true - -module Service - module Commands - module Run - TRIGGERS = ["run"].freeze - - sig { params(targets: T::Array[Service::FormulaWrapper], verbose: T.nilable(T::Boolean)).void } - def self.run(targets, verbose:) - Service::ServicesCli.check(targets) - Service::ServicesCli.run(targets, verbose:) - end - end - end -end diff --git a/Library/Homebrew/services/service/system.rb b/Library/Homebrew/services/system.rb similarity index 99% rename from Library/Homebrew/services/service/system.rb rename to Library/Homebrew/services/system.rb index 661e3f308e..341a7d129f 100644 --- a/Library/Homebrew/services/service/system.rb +++ b/Library/Homebrew/services/system.rb @@ -3,7 +3,7 @@ require_relative "system/systemctl" -module Service +module Services module System extend FileUtils diff --git a/Library/Homebrew/services/service/system/systemctl.rb b/Library/Homebrew/services/system/systemctl.rb similarity index 98% rename from Library/Homebrew/services/service/system/systemctl.rb rename to Library/Homebrew/services/system/systemctl.rb index 2f47ba3634..a7a8d912cb 100644 --- a/Library/Homebrew/services/service/system/systemctl.rb +++ b/Library/Homebrew/services/system/systemctl.rb @@ -1,7 +1,7 @@ # typed: strict # frozen_string_literal: true -module Service +module Services module System module Systemctl sig { returns(T.nilable(Pathname)) } diff --git a/Library/Homebrew/test/services/services_cli_spec.rb b/Library/Homebrew/test/services/cli_spec.rb similarity index 56% rename from Library/Homebrew/test/services/services_cli_spec.rb rename to Library/Homebrew/test/services/cli_spec.rb index a627b504ca..6d9c002a41 100644 --- a/Library/Homebrew/test/services/services_cli_spec.rb +++ b/Library/Homebrew/test/services/cli_spec.rb @@ -1,8 +1,10 @@ # frozen_string_literal: true -require "services/service" +require "services/cli" +require "services/system" +require "services/formula_wrapper" -RSpec.describe Service::ServicesCli do +RSpec.describe Services::Cli do subject(:services_cli) { described_class } let(:service_string) { "service" } @@ -15,7 +17,7 @@ RSpec.describe Service::ServicesCli do describe "#running" do it "macOS - returns the currently running services" do - allow(Service::System).to receive_messages(launchctl?: true, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: true, systemctl?: false) allow(Utils).to receive(:popen_read).and_return <<~EOS 77513 50 homebrew.mxcl.php 495 0 homebrew.mxcl.node_exporter @@ -29,8 +31,8 @@ RSpec.describe Service::ServicesCli do end it "systemD - returns the currently running services" do - allow(Service::System).to receive(:launchctl?).and_return(false) - allow(Service::System::Systemctl).to receive(:popen_read).and_return <<~EOS + allow(Services::System).to receive(:launchctl?).and_return(false) + allow(Services::System::Systemctl).to receive(:popen_read).and_return <<~EOS homebrew.php.service loaded active running Homebrew PHP service systemd-udevd.service loaded active running Rule-based Manager for Device Events and Files udisks2.service loaded active running Disk Manager @@ -44,26 +46,23 @@ RSpec.describe Service::ServicesCli do it "checks the input does not exist" do expect do services_cli.check([]) - end.to raise_error(UsageError, - a_string_including("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 it "checks the input exists" do expect do services_cli.check("hello") end.not_to raise_error(UsageError, - a_string_including("Formula(e) missing, please provide a formula name or use --all")) + "Invalid usage: Formula(e) missing, please provide a formula name or use --all") end end describe "#kill_orphaned_services" do it "skips unmanaged services" do - service = instance_double(service_string, name: "example_service") allow(services_cli).to receive(:running).and_return(["example_service"]) - allow(Service::FormulaWrapper).to receive(:from).and_return(service) expect do services_cli.kill_orphaned_services - end.to output("Service example_service not managed by `brew services` => skipping\n").to_stdout + end.to output("Warning: Service example_service not managed by `brew services` => skipping\n").to_stderr end it "tries but is unable to kill a non existing service" do @@ -75,18 +74,17 @@ RSpec.describe Service::ServicesCli do keep_alive?: false, ) allow(service).to receive(:service_name) - allow(Service::FormulaWrapper).to receive(:from).and_return(service) + allow(Services::FormulaWrapper).to receive(:from).and_return(service) allow(services_cli).to receive(:running).and_return(["example_service"]) expect do services_cli.kill_orphaned_services - end.to output(a_string_including("Killing `example_service`... (might take a while)")).to_stdout.and - output(a_string_including("Unable to kill `example_service` (label: )")).to_stderr + end.to output("Killing `example_service`... (might take a while)\n").to_stdout end end describe "#run" do it "checks empty targets cause no error" do - expect(Service::System).not_to receive(:root?) + expect(Services::System).not_to receive(:root?) services_cli.run([]) end @@ -102,14 +100,14 @@ RSpec.describe Service::ServicesCli do describe "#start" do it "checks missing file causes error" do - expect(Service::System).not_to receive(:root?) + expect(Services::System).not_to receive(:root?) expect do services_cli.start(["service_name"], "/hfdkjshksdjhfkjsdhf/fdsjghsdkjhb") - end.to raise_error(UsageError, a_string_including("Provided service file does not exist")) + end.to raise_error(UsageError, "Invalid usage: Provided service file does not exist") end it "checks empty targets cause no error" do - expect(Service::System).not_to receive(:root?) + expect(Services::System).not_to receive(:root?) services_cli.start([]) end @@ -125,14 +123,14 @@ RSpec.describe Service::ServicesCli do describe "#stop" do it "checks empty targets cause no error" do - expect(Service::System).not_to receive(:root?) + expect(Services::System).not_to receive(:root?) services_cli.stop([]) end end describe "#kill" do it "checks empty targets cause no error" do - expect(Service::System).not_to receive(:root?) + expect(Services::System).not_to receive(:root?) services_cli.kill([]) end @@ -155,15 +153,15 @@ RSpec.describe Service::ServicesCli do describe "#install_service_file" do it "checks service is installed" do - service = instance_double(Service::FormulaWrapper, name: "name", installed?: false) + service = instance_double(Services::FormulaWrapper, name: "name", installed?: false) expect do services_cli.install_service_file(service, nil) - end.to raise_error(UsageError, a_string_including("Formula `name` is not installed")) + end.to raise_error(UsageError, "Invalid usage: Formula `name` is not installed") end it "checks service file exists" do service = instance_double( - Service::FormulaWrapper, + Services::FormulaWrapper, name: "name", installed?: true, service_file: instance_double(Pathname, exist?: false), @@ -172,28 +170,26 @@ RSpec.describe Service::ServicesCli do services_cli.install_service_file(service, nil) end.to raise_error( UsageError, - a_string_including( - "Formula `name` has not implemented #plist, #service or installed a locatable service file", - ), + "Invalid usage: Formula `name` has not implemented #plist, #service or installed a locatable service file", ) end end describe "#systemd_load", :needs_linux do it "checks non-enabling run" do - expect(Service::System::Systemctl).to receive(:executable).once.and_return("/bin/systemctl") - expect(Service::System::Systemctl).to receive(:scope).once.and_return("--user") + expect(Services::System::Systemctl).to receive(:executable).once.and_return("/bin/systemctl") + expect(Services::System::Systemctl).to receive(:scope).once.and_return("--user") services_cli.systemd_load( - instance_double(Service::FormulaWrapper, service_name: "name"), + instance_double(Services::FormulaWrapper, service_name: "name"), enable: false, ) end it "checks enabling run" do - expect(Service::System::Systemctl).to receive(:executable).twice.and_return("/bin/systemctl") - expect(Service::System::Systemctl).to receive(:scope).twice.and_return("--user") + expect(Services::System::Systemctl).to receive(:executable).twice.and_return("/bin/systemctl") + expect(Services::System::Systemctl).to receive(:scope).twice.and_return("--user") services_cli.systemd_load( - instance_double(Service::FormulaWrapper, service_name: "name"), + instance_double(Services::FormulaWrapper, service_name: "name"), enable: true, ) end @@ -201,70 +197,76 @@ RSpec.describe Service::ServicesCli do describe "#launchctl_load", :needs_macos do it "checks non-enabling run" do - expect(Service::System).to receive(:domain_target).once.and_return("target") - expect(Service::System).to receive(:launchctl).once.and_return("/bin/launchctl") - services_cli.launchctl_load(instance_double(Service::FormulaWrapper), file: "a", enable: false) + expect(Services::System).to receive(:domain_target).once.and_return("target") + expect(Services::System).to receive(:launchctl).once.and_return("/bin/launchctl") + expect(described_class).to receive(:safe_system).once.and_return(true) + services_cli.launchctl_load(instance_double(Services::FormulaWrapper), file: "a", enable: false) end it "checks enabling run" do - expect(Service::System).to receive(:domain_target).twice.and_return("target") - expect(Service::System).to receive(:launchctl).twice.and_return("/bin/launchctl") - services_cli.launchctl_load(instance_double(Service::FormulaWrapper, service_name: "name"), file: "a", - enable: true) + expect(Services::System).to receive(:domain_target).twice.and_return("target") + expect(Services::System).to receive(:launchctl).twice.and_return("/bin/launchctl") + expect(described_class).to receive(:safe_system).twice.and_return(true) + services_cli.launchctl_load(instance_double(Services::FormulaWrapper, service_name: "name"), file: "a", + enable: true) end end describe "#service_load" do it "checks non-root for login" do - expect(Service::System).to receive(:launchctl?).once.and_return(false) - expect(Service::System).to receive(:systemctl?).once.and_return(false) - expect(Service::System).to receive(:root?).once.and_return(true) + expect(Services::System).to receive(:launchctl?).once.and_return(false) + expect(Services::System).to receive(:systemctl?).once.and_return(false) + expect(Services::System).to receive(:root?).once.and_return(true) expect do services_cli.service_load( - instance_double(Service::FormulaWrapper, name: "name", service_name: "service.name", + instance_double(Services::FormulaWrapper, name: "name", service_name: "service.name", service_startup?: false), enable: false ) - end.to output(a_string_including("Successfully ran `name` (label: service.name)")).to_stdout.and - output(a_string_including("name must be run as non-root to start at user login!")).to_stderr + end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout end it "checks root for startup" do - expect(Service::System).to receive(:launchctl?).once.and_return(false) - expect(Service::System).to receive(:systemctl?).once.and_return(false) - expect(Service::System).to receive(:root?).twice.and_return(false) + expect(Services::System).to receive(:launchctl?).once.and_return(false) + expect(Services::System).to receive(:systemctl?).once.and_return(false) + expect(Services::System).to receive(:root?).twice.and_return(false) expect do services_cli.service_load( - instance_double(Service::FormulaWrapper, name: "name", service_name: "service.name", + instance_double(Services::FormulaWrapper, name: "name", service_name: "service.name", service_startup?: true), enable: false, ) - end.to output(a_string_including("Successfully ran `name` (label: service.name)")).to_stdout.and - output(a_string_including("name must be run as root to start at system startup!")).to_stderr + end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout end it "triggers launchctl" do - expect(Service::System).to receive(:domain_target).once.and_return("target") - expect(Service::System).to receive(:launchctl?).once.and_return(true) - expect(Service::System).to receive(:launchctl).once - expect(Service::System).not_to receive(:systemctl?) - expect(Service::System).to receive(:root?).twice.and_return(false) - expect do - services_cli.service_load( - instance_double(Service::FormulaWrapper, name: "name", service_name: "service.name", -service_startup?: false), enable: false - ) - end.to output("Successfully ran `name` (label: service.name)\n").to_stdout - end - - it "triggers systemctl" do - expect(Service::System).to receive(:launchctl?).once.and_return(false) - expect(Service::System).to receive(:systemctl?).once.and_return(true) - expect(Service::System).to receive(:root?).thrice.and_return(false) + expect(Services::System).to receive(:launchctl?).once.and_return(true) + expect(Services::System).not_to receive(:systemctl?) + expect(Services::System).to receive(:root?).twice.and_return(false) + expect(described_class).to receive(:launchctl_load).once.and_return(true) expect do services_cli.service_load( instance_double( - Service::FormulaWrapper, + Services::FormulaWrapper, + name: "name", + service_name: "service.name", + service_startup?: false, + service_file: instance_double(Pathname, exist?: false), + ), + enable: false, + ) + end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout + end + + it "triggers systemctl" do + expect(Services::System).to receive(:launchctl?).once.and_return(false) + expect(Services::System).to receive(:systemctl?).once.and_return(true) + expect(Services::System).to receive(:root?).twice.and_return(false) + expect(Services::System::Systemctl).to receive(:run).once.and_return(true) + expect do + services_cli.service_load( + instance_double( + Services::FormulaWrapper, name: "name", service_name: "service.name", service_startup?: false, @@ -272,17 +274,18 @@ service_startup?: false), enable: false ), enable: false, ) - end.to output("Successfully ran `name` (label: service.name)\n").to_stdout + end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout end it "represents correct action" do - expect(Service::System).to receive(:launchctl?).once.and_return(false) - expect(Service::System).to receive(:systemctl?).once.and_return(true) - expect(Service::System).to receive(:root?).exactly(4).times.and_return(false) + expect(Services::System).to receive(:launchctl?).once.and_return(false) + expect(Services::System).to receive(:systemctl?).once.and_return(true) + expect(Services::System).to receive(:root?).twice.and_return(false) + expect(Services::System::Systemctl).to receive(:run).twice.and_return(true) expect do services_cli.service_load( instance_double( - Service::FormulaWrapper, + Services::FormulaWrapper, name: "name", service_name: "service.name", service_startup?: false, @@ -290,7 +293,7 @@ service_startup?: false), enable: false ), enable: true, ) - end.to output("Successfully started `name` (label: service.name)\n").to_stdout + end.to output("==> Successfully started `name` (label: service.name)\n").to_stdout end end end diff --git a/Library/Homebrew/test/services/commands/cleanup_spec.rb b/Library/Homebrew/test/services/commands/cleanup_spec.rb index aa0e4563e3..bb9aa046d8 100644 --- a/Library/Homebrew/test/services/commands/cleanup_spec.rb +++ b/Library/Homebrew/test/services/commands/cleanup_spec.rb @@ -1,8 +1,10 @@ # frozen_string_literal: true -require "services/service" +require "services/commands/cleanup" +require "services/system" +require "services/cli" -RSpec.describe Service::Commands::Cleanup do +RSpec.describe Services::Commands::Cleanup do describe "#TRIGGERS" do it "contains all restart triggers" do expect(described_class::TRIGGERS).to eq(%w[cleanup clean cl rm]) @@ -11,9 +13,9 @@ RSpec.describe Service::Commands::Cleanup do describe "#run" do it "root - prints on empty cleanup" do - expect(Service::System).to receive(:root?).once.and_return(true) - expect(Service::ServicesCli).to receive(:kill_orphaned_services).once.and_return([]) - expect(Service::ServicesCli).to receive(:remove_unused_service_files).once.and_return([]) + expect(Services::System).to receive(:root?).once.and_return(true) + expect(Services::Cli).to receive(:kill_orphaned_services).once.and_return([]) + expect(Services::Cli).to receive(:remove_unused_service_files).once.and_return([]) expect do described_class.run @@ -21,9 +23,9 @@ RSpec.describe Service::Commands::Cleanup do end it "user - prints on empty cleanup" do - expect(Service::System).to receive(:root?).once.and_return(false) - expect(Service::ServicesCli).to receive(:kill_orphaned_services).once.and_return([]) - expect(Service::ServicesCli).to receive(:remove_unused_service_files).once.and_return([]) + expect(Services::System).to receive(:root?).once.and_return(false) + expect(Services::Cli).to receive(:kill_orphaned_services).once.and_return([]) + expect(Services::Cli).to receive(:remove_unused_service_files).once.and_return([]) expect do described_class.run @@ -31,9 +33,9 @@ RSpec.describe Service::Commands::Cleanup do end it "prints nothing on cleanup" do - expect(Service::System).not_to receive(:root?) - expect(Service::ServicesCli).to receive(:kill_orphaned_services).once.and_return(["a"]) - expect(Service::ServicesCli).to receive(:remove_unused_service_files).once.and_return(["b"]) + expect(Services::System).not_to receive(:root?) + expect(Services::Cli).to receive(:kill_orphaned_services).once.and_return(["a"]) + expect(Services::Cli).to receive(:remove_unused_service_files).once.and_return(["b"]) expect do described_class.run diff --git a/Library/Homebrew/test/services/commands/info_spec.rb b/Library/Homebrew/test/services/commands/info_spec.rb index 6251da7f84..08ab6c344b 100644 --- a/Library/Homebrew/test/services/commands/info_spec.rb +++ b/Library/Homebrew/test/services/commands/info_spec.rb @@ -1,37 +1,10 @@ # frozen_string_literal: true -require "services/service" +require "services/commands/info" -# needs for tty color tests -module Tty - def self.green - "" - end - - def self.yellow - "" - end - - def self.red - "" - end - - def self.default - "" - end - - def self.bold - "" - end - - def self.reset - "" - end -end - -RSpec.describe Service::Commands::Info do +RSpec.describe Services::Commands::Info do before do - allow_any_instance_of(IO).to receive(:tty?).and_return(true) + allow_any_instance_of(IO).to receive(:tty?).and_return(false) end describe "#TRIGGERS" do @@ -44,12 +17,11 @@ RSpec.describe Service::Commands::Info do it "fails with empty list" do expect do described_class.run([], verbose: false, json: false) - end.to raise_error UsageError, - a_string_including("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 it "succeeds with items" do - out = "service ()\nRunning: true\nLoaded: true\nSchedulable: false\n" + out = "service ()\nRunning: true\nLoaded: true\nSchedulable: false\n" formula = { name: "service", user: "user", @@ -83,8 +55,8 @@ RSpec.describe Service::Commands::Info do describe "#output" do it "returns minimal output" do - out = "service ()\nRunning: \n" - out += "Loaded: \nSchedulable: \n" + out = "service ()\nRunning: true\n" + out += "Loaded: true\nSchedulable: false\n" formula = { name: "service", user: "user", @@ -98,8 +70,8 @@ RSpec.describe Service::Commands::Info do end it "returns normal output" do - out = "service ()\nRunning: \n" - out += "Loaded: \nSchedulable: \n" + out = "service ()\nRunning: true\n" + out += "Loaded: true\nSchedulable: false\n" out += "User: user\nPID: 42\n" formula = { name: "service", @@ -115,9 +87,9 @@ RSpec.describe Service::Commands::Info do end it "returns verbose output" do - out = "service ()\nRunning: \n" - out += "Loaded: \nSchedulable: \n" - out += "User: user\nPID: 42\nFile: /dev/null \nCommand: /bin/command\n" + out = "service ()\nRunning: true\n" + out += "Loaded: true\nSchedulable: false\n" + out += "User: user\nPID: 42\nFile: /dev/null true\nCommand: /bin/command\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" formula = { diff --git a/Library/Homebrew/test/services/commands/list_spec.rb b/Library/Homebrew/test/services/commands/list_spec.rb index c936d31869..40c38e8227 100644 --- a/Library/Homebrew/test/services/commands/list_spec.rb +++ b/Library/Homebrew/test/services/commands/list_spec.rb @@ -1,35 +1,8 @@ # frozen_string_literal: true -require "services/service" +require "services/commands/list" -# needs for tty color tests -module Tty - def self.green - "" - end - - def self.yellow - "" - end - - def self.red - "" - end - - def self.default - "" - end - - def self.bold - "" - end - - def self.reset - "" - end -end - -RSpec.describe Service::Commands::List do +RSpec.describe Services::Commands::List do describe "#TRIGGERS" do it "contains all restart triggers" do expect(described_class::TRIGGERS).to eq([nil, "list", "ls"]) @@ -38,24 +11,23 @@ RSpec.describe Service::Commands::List do describe "#run" do it "fails with empty list" do - allow_any_instance_of(IO).to receive(:tty?).and_return(true) - expect(Service::Formulae).to receive(:services_list).and_return([]) + expect(Services::Formulae).to receive(:services_list).and_return([]) expect do + allow($stderr).to receive(:tty?).and_return(true) described_class.run end.to output(a_string_including("No services available to control with `brew services`")).to_stderr end it "succeeds with list" do - out = "Name Status User File\nservice started user /dev/null\n" - formula = instance_double( - Service::FormulaWrapper, - name: "service", - owner: "user", - status_symbol: :started, - service_file: +File::NULL, - loaded?: true, - ) - expect(Service::Formulae).to receive(:services_list).and_return([formula]) + out = "Name Status User File\nservice started user /dev/null\n" + formula = { + name: "service", + user: "user", + status: :started, + file: "/dev/null", + loaded: true, + } + expect(Services::Formulae).to receive(:services_list).and_return([formula]) expect do described_class.run end.to output(out).to_stdout @@ -75,7 +47,7 @@ RSpec.describe Service::Commands::List do filtered_formula = formula.slice(*described_class::JSON_FIELDS) expected_output = "#{JSON.pretty_generate([filtered_formula])}\n" - expect(Service::Formulae).to receive(:services_list).and_return([formula]) + expect(Services::Formulae).to receive(:services_list).and_return([formula]) expect do described_class.run(json: true) end.to output(expected_output).to_stdout @@ -87,20 +59,20 @@ RSpec.describe Service::Commands::List do formula = { name: "a", user: "u", file: Pathname.new("/tmp/file.file"), status: :stopped } expect do described_class.print_table([formula]) - end.to output("Name Status User File\na stopped u \n").to_stdout + end.to output("Name Status User File\na stopped u \n").to_stdout end it "prints without user or file data" do formula = { name: "a", user: nil, file: nil, status: :started, loaded: true } expect do described_class.print_table([formula]) - end.to output("Name Status User File\na started \n").to_stdout + end.to output("Name Status User File\na started \n").to_stdout end it "prints shortened home directory" do ENV["HOME"] = "/tmp" formula = { name: "a", user: "u", file: Pathname.new("/tmp/file.file"), status: :started, loaded: true } - expected_output = "Name Status User File\na started u ~/file.file\n" + expected_output = "Name Status User File\na started u ~/file.file\n" expect do described_class.print_table([formula]) end.to output(expected_output).to_stdout @@ -109,7 +81,7 @@ RSpec.describe Service::Commands::List do it "prints an error code" do file = Pathname.new("/tmp/file.file") formula = { name: "a", user: "u", file:, status: :error, exit_code: 256, loaded: true } - expected_output = "Name Status User File\na error 256 u /tmp/file.file\n" + expected_output = "Name Status User File\na error 256 u /tmp/file.file\n" expect do described_class.print_table([formula]) end.to output(expected_output).to_stdout @@ -147,23 +119,23 @@ RSpec.describe Service::Commands::List do describe "#get_status_string" do it "returns started" do - expect(described_class.get_status_string(:started)).to eq("started") + expect(described_class.get_status_string(:started)).to eq("started") end it "returns stopped" do - expect(described_class.get_status_string(:stopped)).to eq("stopped") + expect(described_class.get_status_string(:stopped)).to eq("stopped") end it "returns error" do - expect(described_class.get_status_string(:error)).to eq("error ") + expect(described_class.get_status_string(:error)).to eq("error ") end it "returns unknown" do - expect(described_class.get_status_string(:unknown)).to eq("unknown") + expect(described_class.get_status_string(:unknown)).to eq("unknown") end it "returns other" do - expect(described_class.get_status_string(:other)).to eq("other") + expect(described_class.get_status_string(:other)).to eq("other") end end end diff --git a/Library/Homebrew/test/services/commands/restart_spec.rb b/Library/Homebrew/test/services/commands/restart_spec.rb index 6c939c1de7..5af0acfef3 100644 --- a/Library/Homebrew/test/services/commands/restart_spec.rb +++ b/Library/Homebrew/test/services/commands/restart_spec.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true -require "services/service" - -RSpec.describe Service::Commands::Restart do +require "services/commands/restart" +require "services/cli" +require "services/formula_wrapper" +RSpec.describe Services::Commands::Restart do describe "#TRIGGERS" do it "contains all restart triggers" do expect(described_class::TRIGGERS).to eq(%w[restart relaunch reload r]) @@ -13,32 +14,31 @@ RSpec.describe Service::Commands::Restart do it "fails with empty list" do expect do described_class.run([], verbose: false) - end.to raise_error UsageError, - a_string_including("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 it "starts if services are not loaded" do - expect(Service::ServicesCli).not_to receive(:run) - expect(Service::ServicesCli).not_to receive(:stop) - expect(Service::ServicesCli).to receive(:start).once - service = instance_double(Service::FormulaWrapper, service_name: "name", loaded?: false) + expect(Services::Cli).not_to receive(:run) + expect(Services::Cli).not_to receive(:stop) + expect(Services::Cli).to receive(:start).once + service = instance_double(Services::FormulaWrapper, service_name: "name", loaded?: false) expect(described_class.run([service], verbose: false)).to be_nil end it "starts if services are loaded with file" do - expect(Service::ServicesCli).not_to receive(:run) - expect(Service::ServicesCli).to receive(:start).once - expect(Service::ServicesCli).to receive(:stop).once - service = instance_double(Service::FormulaWrapper, service_name: "name", loaded?: true, + expect(Services::Cli).not_to receive(:run) + expect(Services::Cli).to receive(:start).once + expect(Services::Cli).to receive(:stop).once + service = instance_double(Services::FormulaWrapper, service_name: "name", loaded?: true, service_file_present?: true) expect(described_class.run([service], verbose: false)).to be_nil end it "runs if services are loaded without file" do - expect(Service::ServicesCli).not_to receive(:start) - expect(Service::ServicesCli).to receive(:run).once - expect(Service::ServicesCli).to receive(:stop).once - service = instance_double(Service::FormulaWrapper, service_name: "name", loaded?: true, + expect(Services::Cli).not_to receive(:start) + expect(Services::Cli).to receive(:run).once + expect(Services::Cli).to receive(:stop).once + service = instance_double(Services::FormulaWrapper, service_name: "name", loaded?: true, service_file_present?: false) expect(described_class.run([service], verbose: false)).to be_nil end diff --git a/Library/Homebrew/test/services/formulae_spec.rb b/Library/Homebrew/test/services/formulae_spec.rb index 9ccc2753c3..96f4e3e74c 100644 --- a/Library/Homebrew/test/services/formulae_spec.rb +++ b/Library/Homebrew/test/services/formulae_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require "services/service" +require "services/formulae" -RSpec.describe Service::Formulae do +RSpec.describe Services::Formulae do describe "#services_list" do it "empty list without available formulae" do allow(described_class).to receive(:available_services).and_return({}) @@ -10,7 +10,7 @@ RSpec.describe Service::Formulae do end it "list with available formulae" do - formula = instance_double(Service::FormulaWrapper) + formula = instance_double(Services::FormulaWrapper) expected = [ { file: Pathname.new("/Library/LaunchDaemons/file.plist"), diff --git a/Library/Homebrew/test/services/formulae_wrapper_spec.rb b/Library/Homebrew/test/services/formulae_wrapper_spec.rb index fa6bc33d4b..317995b777 100644 --- a/Library/Homebrew/test/services/formulae_wrapper_spec.rb +++ b/Library/Homebrew/test/services/formulae_wrapper_spec.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true -require "services/service" +require "services/system" +require "services/formula_wrapper" require "tempfile" -RSpec.describe Service::FormulaWrapper do +RSpec.describe Services::FormulaWrapper do subject(:service) { described_class.new(formula) } let(:formula) do @@ -40,17 +41,17 @@ RSpec.describe Service::FormulaWrapper do describe "#service_file" do it "macOS - outputs the full service file path" do - allow(Service::System).to receive(:launchctl?).and_return(true) + allow(Services::System).to receive(:launchctl?).and_return(true) expect(service.service_file.to_s).to eq("/usr/local/opt/mysql/homebrew.mysql.plist") end it "systemD - outputs the full service file path" do - allow(Service::System).to receive_messages(launchctl?: false, systemctl?: true) + allow(Services::System).to receive_messages(launchctl?: false, systemctl?: true) expect(service.service_file.to_s).to eq("/usr/local/opt/mysql/homebrew.mysql.service") end it "Other - outputs no service file" do - allow(Service::System).to receive_messages(launchctl?: false, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: false, systemctl?: false) expect(service.service_file).to be_nil end end @@ -63,45 +64,45 @@ RSpec.describe Service::FormulaWrapper do describe "#service_name" do it "macOS - outputs the service name" do - allow(Service::System).to receive(:launchctl?).and_return(true) + allow(Services::System).to receive(:launchctl?).and_return(true) expect(service.service_name).to eq("plist-mysql-test") end it "systemD - outputs the service name" do - allow(Service::System).to receive_messages(launchctl?: false, systemctl?: true) + allow(Services::System).to receive_messages(launchctl?: false, systemctl?: true) expect(service.service_name).to eq("plist-mysql-test") end it "Other - outputs no service name" do - allow(Service::System).to receive_messages(launchctl?: false, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: false, systemctl?: false) expect(service.service_name).to be_nil end end describe "#dest_dir" do before do - allow(Service::System).to receive_messages(launchctl?: false, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: false, systemctl?: false) end it "macOS - user - outputs the destination directory for the service file" do ENV["HOME"] = "/tmp_home" - allow(Service::System).to receive_messages(root?: false, launchctl?: true) + allow(Services::System).to receive_messages(root?: false, launchctl?: true) expect(service.dest_dir.to_s).to eq("/tmp_home/Library/LaunchAgents") end it "macOS - root - outputs the destination directory for the service file" do - allow(Service::System).to receive_messages(launchctl?: true, root?: true) + allow(Services::System).to receive_messages(launchctl?: true, root?: true) expect(service.dest_dir.to_s).to eq("/Library/LaunchDaemons") end it "systemD - user - outputs the destination directory for the service file" do ENV["HOME"] = "/tmp_home" - allow(Service::System).to receive_messages(root?: false, launchctl?: false, systemctl?: true) + allow(Services::System).to receive_messages(root?: false, launchctl?: false, systemctl?: true) expect(service.dest_dir.to_s).to eq("/tmp_home/.config/systemd/user") end it "systemD - root - outputs the destination directory for the service file" do - allow(Service::System).to receive_messages(root?: true, launchctl?: false, systemctl?: true) + allow(Services::System).to receive_messages(root?: true, launchctl?: false, systemctl?: true) expect(service.dest_dir.to_s).to eq("/usr/lib/systemd/system") end end @@ -109,16 +110,16 @@ RSpec.describe Service::FormulaWrapper do describe "#dest" do before do ENV["HOME"] = "/tmp_home" - allow(Service::System).to receive_messages(launchctl?: false, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: false, systemctl?: false) end it "macOS - outputs the destination for the service file" do - allow(Service::System).to receive(:launchctl?).and_return(true) + allow(Services::System).to receive(:launchctl?).and_return(true) expect(service.dest.to_s).to eq("/tmp_home/Library/LaunchAgents/homebrew.mysql.plist") end it "systemD - outputs the destination for the service file" do - allow(Service::System).to receive(:systemctl?).and_return(true) + allow(Services::System).to receive(:systemctl?).and_return(true) expect(service.dest.to_s).to eq("/tmp_home/.config/systemd/user/homebrew.mysql.service") end end @@ -131,20 +132,20 @@ RSpec.describe Service::FormulaWrapper do describe "#loaded?" do it "macOS - outputs if the service is loaded" do - allow(Service::System).to receive_messages(launchctl?: true, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: true, systemctl?: false) allow(Utils).to receive(:safe_popen_read) expect(service.loaded?).to be(false) end it "systemD - outputs if the service is loaded" do - allow(Service::System).to receive_messages(launchctl?: false, systemctl?: true) - allow(Service::System::Systemctl).to receive(:quiet_run).and_return(false) + allow(Services::System).to receive_messages(launchctl?: false, systemctl?: true) + allow(Services::System::Systemctl).to receive(:quiet_run).and_return(false) allow(Utils).to receive(:safe_popen_read) expect(service.loaded?).to be(false) end it "Other - outputs no status" do - allow(Service::System).to receive_messages(launchctl?: false, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: false, systemctl?: false) expect(service.loaded?).to be_nil end end @@ -181,7 +182,7 @@ RSpec.describe Service::FormulaWrapper do it "user if file present" do allow(service).to receive_messages(boot_path_service_file_present?: false, user_path_service_file_present?: true) - allow(Service::System).to receive(:user).and_return("user") + allow(Services::System).to receive(:user).and_return("user") expect(service.owner).to eq("user") end @@ -194,24 +195,24 @@ RSpec.describe Service::FormulaWrapper do describe "#service_file_present?" do it "macOS - outputs if the service file is present" do - allow(Service::System).to receive_messages(launchctl?: true, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: true, systemctl?: false) expect(service.service_file_present?).to be(false) end it "macOS - outputs if the service file is present for root" do - allow(Service::System).to receive_messages(launchctl?: true, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: true, systemctl?: false) expect(service.service_file_present?(for: :root)).to be(false) end it "macOS - outputs if the service file is present for user" do - allow(Service::System).to receive_messages(launchctl?: true, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: true, systemctl?: false) expect(service.service_file_present?(for: :user)).to be(false) end end describe "#owner?" do it "macOS - outputs the service file owner" do - allow(Service::System).to receive_messages(launchctl?: true, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: true, systemctl?: false) expect(service.owner).to be_nil end end @@ -320,7 +321,7 @@ RSpec.describe Service::FormulaWrapper do describe "#to_hash" do it "represents non-service values" do - allow(Service::System).to receive_messages(launchctl?: true, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: true, systemctl?: false) allow_any_instance_of(described_class).to receive_messages(service?: false, service_file_present?: false) expected = { exit_code: nil, @@ -339,7 +340,7 @@ RSpec.describe Service::FormulaWrapper do it "represents running non-service values" do ENV["HOME"] = "/tmp_home" - allow(Service::System).to receive_messages(launchctl?: true, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: true, systemctl?: false) expect(service).to receive(:service?).twice.and_return(false) expect(service).to receive(:service_file_present?).and_return(true) expected = { @@ -359,7 +360,7 @@ RSpec.describe Service::FormulaWrapper do it "represents service values" do ENV["HOME"] = "/tmp_home" - allow(Service::System).to receive_messages(launchctl?: true, systemctl?: false) + allow(Services::System).to receive_messages(launchctl?: true, systemctl?: false) expect(service).to receive(:service?).twice.and_return(true) expect(service).to receive(:service_file_present?).and_return(true) expect(service).to receive(:load_service).twice.and_return(service_object) diff --git a/Library/Homebrew/test/services/system/systemctl_spec.rb b/Library/Homebrew/test/services/system/systemctl_spec.rb index d4d5208e28..5a17d8632f 100644 --- a/Library/Homebrew/test/services/system/systemctl_spec.rb +++ b/Library/Homebrew/test/services/system/systemctl_spec.rb @@ -1,16 +1,17 @@ # frozen_string_literal: true -require "services/service" +require "services/system" +require "services/system/systemctl" -RSpec.describe Service::System::Systemctl do +RSpec.describe Services::System::Systemctl do describe ".scope" do it "outputs systemctl scope for user" do - allow(Service::System).to receive(:root?).and_return(false) + allow(Services::System).to receive(:root?).and_return(false) expect(described_class.scope).to eq("--user") end it "outputs systemctl scope for root" do - allow(Service::System).to receive(:root?).and_return(true) + allow(Services::System).to receive(:root?).and_return(true) expect(described_class.scope).to eq("--system") end end diff --git a/Library/Homebrew/test/services/system_spec.rb b/Library/Homebrew/test/services/system_spec.rb index 9e14362684..9d6c1f3650 100644 --- a/Library/Homebrew/test/services/system_spec.rb +++ b/Library/Homebrew/test/services/system_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require "services/service" +require "services/system" -RSpec.describe Service::System do +RSpec.describe Services::System do describe "#launchctl" do it "macOS - outputs launchctl command location", :needs_macos do expect(described_class.launchctl).to eq(Pathname.new("/bin/launchctl")) diff --git a/Library/Homebrew/test/spec_helper.rb b/Library/Homebrew/test/spec_helper.rb index 92c2135b5a..d1dfebdd6e 100644 --- a/Library/Homebrew/test/spec_helper.rb +++ b/Library/Homebrew/test/spec_helper.rb @@ -286,7 +286,7 @@ RSpec.configure do |config| HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-bar", HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-bundle", HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-foo", - HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-services", + HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-test-bot", HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-shallow", HOMEBREW_LIBRARY/"PinnedTaps", HOMEBREW_REPOSITORY/".git", diff --git a/Library/Homebrew/test/tap_spec.rb b/Library/Homebrew/test/tap_spec.rb index 9c969e44b7..8bea008043 100644 --- a/Library/Homebrew/test/tap_spec.rb +++ b/Library/Homebrew/test/tap_spec.rb @@ -214,11 +214,11 @@ RSpec.describe Tap do expect(homebrew_foo_tap.remote).to eq("https://github.com/Homebrew/homebrew-foo") expect(homebrew_foo_tap).not_to have_custom_remote - services_tap = described_class.fetch("Homebrew", "services") + services_tap = described_class.fetch("Homebrew", "test-bot") services_tap.path.mkpath services_tap.path.cd do system "git", "init" - system "git", "remote", "add", "origin", "https://github.com/Homebrew/homebrew-services" + system "git", "remote", "add", "origin", "https://github.com/Homebrew/homebrew-test-bot" end expect(services_tap).not_to be_private end @@ -240,7 +240,7 @@ RSpec.describe Tap do expect(homebrew_foo_tap.remote_repository).to eq("Homebrew/homebrew-foo") - services_tap = described_class.fetch("Homebrew", "services") + services_tap = described_class.fetch("Homebrew", "test-bot") services_tap.path.mkpath services_tap.path.cd do system "git", "init" @@ -254,7 +254,7 @@ RSpec.describe Tap do expect(homebrew_foo_tap.remote_repository).to eq("Homebrew/homebrew-foo") - services_tap = described_class.fetch("Homebrew", "services") + services_tap = described_class.fetch("Homebrew", "test-bot") services_tap.path.mkpath services_tap.path.cd do system "git", "init" @@ -275,7 +275,7 @@ RSpec.describe Tap do end describe "#custom_remote?" do - subject(:tap) { described_class.fetch("Homebrew", "services") } + subject(:tap) { described_class.fetch("Homebrew", "test-bot") } let(:remote) { nil } @@ -293,13 +293,13 @@ RSpec.describe Tap do end context "when using the default remote" do - let(:remote) { "https://github.com/Homebrew/homebrew-services" } + let(:remote) { "https://github.com/Homebrew/homebrew-test-bot" } it(:custom_remote?) { expect(tap.custom_remote?).to be false } end context "when using a non-default remote" do - let(:remote) { "git@github.com:Homebrew/homebrew-services" } + let(:remote) { "git@github.com:Homebrew/homebrew-test-bot" } it(:custom_remote?) { expect(tap.custom_remote?).to be true } end diff --git a/docs/External-Commands.md b/docs/External-Commands.md index ed6932e8ea..915e9cfe70 100644 --- a/docs/External-Commands.md +++ b/docs/External-Commands.md @@ -40,7 +40,7 @@ An executable script for a command named `extcmd` should be named `brew-extcmd`. ## Providing `--help` -All internal and external Homebrew commands can provide styled `--help` output by using Homebrew’s [argument parser](https://rubydoc.brew.sh/Homebrew/CLI/Parser), as seen in the [`brew services` command](https://github.com/Homebrew/homebrew-services/blob/HEAD/cmd/services.rb); or by including lines starting with `#:` (a comment then `:` character in both Bash and Ruby), as seen in the [header of `update.sh`](https://github.com/Homebrew/brew/blob/cf7def0c68903814c6b4e04a55fe8f3cb3f5605e/Library/Homebrew/cmd/update.sh#L1-L10), which is printed with `brew update --help`. +All internal and external Homebrew commands can provide styled `--help` output by using Homebrew’s [argument parser](https://rubydoc.brew.sh/Homebrew/CLI/Parser), as seen in the [`brew test-bot` command](https://github.com/Homebrew/homebrew-test-bot/blob/HEAD/cmd/test-bot.rb); or by including lines starting with `#:` (a comment then `:` character in both Bash and Ruby), as seen in the [header of `update.sh`](https://github.com/Homebrew/brew/blob/cf7def0c68903814c6b4e04a55fe8f3cb3f5605e/Library/Homebrew/cmd/update.sh#L1-L10), which is printed with `brew update --help`. ## Unofficial external commands diff --git a/docs/Formula-Cookbook.md b/docs/Formula-Cookbook.md index 7451e5312e..8662f7f487 100644 --- a/docs/Formula-Cookbook.md +++ b/docs/Formula-Cookbook.md @@ -27,7 +27,7 @@ A *formula* is a package definition written in Ruby. It can be created with `bre | **bottle** | pre-built **keg** poured into a **rack** of the **Cellar** instead of building from upstream sources | `qt--6.5.1.ventura.bottle.tar.gz` | | **tab** | information about a **keg**, e.g. whether it was poured from a **bottle** or built from source | `/opt/homebrew/Cellar/foo/0.1/INSTALL_RECEIPT.json` | | **Brew Bundle** | an [extension of Homebrew](https://github.com/Homebrew/homebrew-bundle) to describe dependencies | `brew 'myservice', restart_service: true` | -| **Brew Services** | an [extension of Homebrew](https://github.com/Homebrew/homebrew-services) to manage services | `brew services start myservice` | +| **Brew Services** | the Homebrew command to manage background services | `brew services start myservice` | ## An introduction @@ -1042,7 +1042,7 @@ Another example would be configuration files that should not be overwritten on p ### Service files -There are two ways to add `launchd` plists and `systemd` services to a formula, so that [`brew services`](https://github.com/Homebrew/homebrew-services) can pick them up: +There are two ways to add `launchd` plists and `systemd` services to a formula, so that `brew services` can pick them up: 1. If the package already provides a service file the formula can reference it by name: