Merge pull request #14371 from dawidd6/os-specific-service

Allow defining service run command per platform
This commit is contained in:
Mike McQuaid 2023-01-20 15:21:47 +00:00 committed by GitHub
commit 4cf365f6c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 113 additions and 13 deletions

View File

@ -153,6 +153,7 @@ class Caveats
def service_caveats def service_caveats
return if !f.plist && !f.service? && !keg&.plist_installed? return if !f.plist && !f.service? && !keg&.plist_installed?
return if f.service? && f.service.command.blank?
s = [] s = []

View File

@ -108,6 +108,13 @@ module OnSystem
result result
end end
base.define_method(:on_system_conditional) do |macos: nil, linux: nil|
@on_system_blocks_exist = true
return macos if OnSystem.os_condition_met?(:macos) && macos.present?
return linux if OnSystem.os_condition_met?(:linux) && linux.present?
end
end end
sig { params(base: Class).void } sig { params(base: Class).void }

View File

@ -278,8 +278,7 @@ module FormulaCellarChecks
def check_service_command(formula) def check_service_command(formula)
return unless formula.prefix.directory? return unless formula.prefix.directory?
return unless formula.service? return unless formula.service?
return if formula.service.command.blank?
return "Service command blank" if formula.service.command.blank?
"Service command does not exist" unless File.exist?(formula.service.command.first) "Service command does not exist" unless File.exist?(formula.service.command.first)
end end

View File

@ -1031,7 +1031,7 @@ class FormulaInstaller
return return
end end
if formula.service? if formula.service? && formula.service.command.present?
service_path = formula.systemd_service_path service_path = formula.systemd_service_path
service_path.atomic_write(formula.service.to_systemd_unit) service_path.atomic_write(formula.service.to_systemd_unit)
service_path.chmod 0644 service_path.chmod 0644
@ -1043,7 +1043,7 @@ class FormulaInstaller
end end
end end
service = if formula.service? service = if formula.service? && formula.service.command.present?
formula.service.to_plist formula.service.to_plist
elsif formula.plist elsif formula.plist
formula.plist formula.plist
@ -1057,6 +1057,7 @@ class FormulaInstaller
log = formula.var/"log" log = formula.var/"log"
log.mkpath if service.include? log.to_s log.mkpath if service.include? log.to_s
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
puts e
ofail "Failed to install service files" ofail "Failed to install service files"
odebug e, e.backtrace odebug e, e.backtrace
end end

View File

@ -1,6 +1,8 @@
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "extend/on_system"
module Homebrew module Homebrew
# The {Service} class implements the DSL methods used in a formula's # The {Service} class implements the DSL methods used in a formula's
# `service` block and stores related instance variables. Most of these methods # `service` block and stores related instance variables. Most of these methods
@ -8,6 +10,7 @@ module Homebrew
class Service class Service
extend T::Sig extend T::Sig
extend Forwardable extend Forwardable
include OnSystem::MacOSAndLinux
RUN_TYPE_IMMEDIATE = :immediate RUN_TYPE_IMMEDIATE = :immediate
RUN_TYPE_INTERVAL = :interval RUN_TYPE_INTERVAL = :interval
@ -33,8 +36,15 @@ module Homebrew
@formula @formula
end end
sig { params(command: T.nilable(T.any(T::Array[String], String, Pathname))).returns(T.nilable(Array)) } sig {
def run(command = nil) params(
command: T.nilable(T.any(T::Array[String], String, Pathname)),
macos: T.nilable(T.any(T::Array[String], String, Pathname)),
linux: T.nilable(T.any(T::Array[String], String, Pathname)),
).returns(T.nilable(Array))
}
def run(command = nil, macos: nil, linux: nil)
command ||= on_system_conditional(macos: macos, linux: linux)
case T.unsafe(command) case T.unsafe(command)
when nil when nil
@run @run
@ -326,10 +336,10 @@ module Homebrew
"#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin" "#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin"
end end
sig { returns(T::Array[String]) } sig { returns(T.nilable(T::Array[String])) }
def command def command
instance_eval(&@service_block) instance_eval(&@service_block)
@run.map(&:to_s) @run&.map(&:to_s)
end end
# Returns the `String` command to run manually instead of the service. # Returns the `String` command to run manually instead of the service.
@ -340,7 +350,8 @@ module Homebrew
vars = @environment_variables.except(:PATH) vars = @environment_variables.except(:PATH)
.map { |k, v| "#{k}=\"#{v}\"" } .map { |k, v| "#{k}=\"#{v}\"" }
out = vars + command cmd = command
out = vars + cmd if cmd.present?
out.join(" ") out.join(" ")
end end
@ -427,7 +438,7 @@ module Homebrew
EOS EOS
# command needs to be first because it initializes all other values # command needs to be first because it initializes all other values
cmd = command.join(" ") cmd = command&.join(" ")
options = [] options = []
options << "Type=#{(@launch_only_once == true) ? "oneshot" : "simple"}" options << "Type=#{(@launch_only_once == true) ? "oneshot" : "simple"}"

View File

@ -0,0 +1,7 @@
# typed: strict
module Homebrew
class Service
def on_system_conditional(macos: nil, linux: nil); end
end
end

View File

@ -564,7 +564,7 @@ module Homebrew
RUBY RUBY
mkdir_p fa.formula.prefix mkdir_p fa.formula.prefix
expect(fa.check_service_command(fa.formula)).to match "Service command blank" expect(fa.check_service_command(fa.formula)).to match nil
end end
specify "Invalid command" do specify "Invalid command" do

View File

@ -226,13 +226,14 @@ describe FormulaInstaller do
expect(formula).to receive(:plist).and_return(nil) expect(formula).to receive(:plist).and_return(nil)
expect(formula).to receive(:service?).exactly(3).and_return(true) expect(formula).to receive(:service?).exactly(3).and_return(true)
expect(formula).to receive(:service).exactly(3).and_return(service) expect(formula).to receive(:service).exactly(5).and_return(service)
expect(formula).to receive(:plist_path).and_call_original expect(formula).to receive(:plist_path).and_call_original
expect(formula).to receive(:systemd_service_path).and_call_original expect(formula).to receive(:systemd_service_path).and_call_original
expect(service).to receive(:timed?).and_return(false) expect(service).to receive(:timed?).and_return(false)
expect(service).to receive(:to_plist).and_return("plist") expect(service).to receive(:to_plist).and_return("plist")
expect(service).to receive(:to_systemd_unit).and_return("unit") expect(service).to receive(:to_systemd_unit).and_return("unit")
expect(service).to receive(:command).exactly(2).and_return("/bin/sh")
installer = described_class.new(formula) installer = described_class.new(formula)
expect { expect {
@ -253,7 +254,7 @@ describe FormulaInstaller do
expect(formula).to receive(:plist).and_return(nil) expect(formula).to receive(:plist).and_return(nil)
expect(formula).to receive(:service?).exactly(3).and_return(true) expect(formula).to receive(:service?).exactly(3).and_return(true)
expect(formula).to receive(:service).exactly(4).and_return(service) expect(formula).to receive(:service).exactly(6).and_return(service)
expect(formula).to receive(:plist_path).and_call_original expect(formula).to receive(:plist_path).and_call_original
expect(formula).to receive(:systemd_service_path).and_call_original expect(formula).to receive(:systemd_service_path).and_call_original
expect(formula).to receive(:systemd_timer_path).and_call_original expect(formula).to receive(:systemd_timer_path).and_call_original
@ -262,6 +263,7 @@ describe FormulaInstaller do
expect(service).to receive(:timed?).and_return(true) expect(service).to receive(:timed?).and_return(true)
expect(service).to receive(:to_systemd_unit).and_return("unit") expect(service).to receive(:to_systemd_unit).and_return("unit")
expect(service).to receive(:to_systemd_timer).and_return("timer") expect(service).to receive(:to_systemd_timer).and_return("timer")
expect(service).to receive(:command).exactly(2).and_return("/bin/sh")
installer = described_class.new(formula) installer = described_class.new(formula)
expect { expect {

View File

@ -803,5 +803,77 @@ describe Homebrew::Service do
command = f.service.command command = f.service.command
expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test"]) expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test"])
end end
it "returns @run data on Linux", :needs_linux do
f = stub_formula do
service do
run linux: [opt_bin/"beanstalkd", "test"]
run_type :immediate
end
end
command = f.service.command
expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test"])
end
it "returns nil on Linux", :needs_linux do
f = stub_formula do
service do
run macos: [opt_bin/"beanstalkd", "test"]
run_type :immediate
end
end
command = f.service.command
expect(command).to be_nil
end
it "returns @run data on macOS", :needs_macos do
f = stub_formula do
service do
run macos: [opt_bin/"beanstalkd", "test"]
run_type :immediate
end
end
command = f.service.command
expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test"])
end
it "returns nil on macOS", :needs_macos do
f = stub_formula do
service do
run linux: [opt_bin/"beanstalkd", "test"]
run_type :immediate
end
end
command = f.service.command
expect(command).to be_nil
end
it "returns appropriate @run data on Linux", :needs_linux do
f = stub_formula do
service do
run macos: [opt_bin/"beanstalkd", "test", "macos"], linux: [opt_bin/"beanstalkd", "test", "linux"]
run_type :immediate
end
end
command = f.service.command
expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test", "linux"])
end
it "returns appropriate @run data on macOS", :needs_macos do
f = stub_formula do
service do
run macos: [opt_bin/"beanstalkd", "test", "macos"], linux: [opt_bin/"beanstalkd", "test", "linux"]
run_type :immediate
end
end
command = f.service.command
expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test", "macos"])
end
end end
end end