diff --git a/Library/Homebrew/service.rb b/Library/Homebrew/service.rb index 205ac4085c039..2a870048edc5d 100644 --- a/Library/Homebrew/service.rb +++ b/Library/Homebrew/service.rb @@ -112,6 +112,18 @@ def keep_alive(value = nil) end end + sig { params(value: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) } + def launch_only_once(value = nil) + case T.unsafe(value) + when nil + @launch_only_once + when true, false + @launch_only_once = value + else + raise TypeError, "Service#launch_only_once expects a Boolean" + end + end + sig { params(value: T.nilable(Integer)).returns(T.nilable(Integer)) } def restart_delay(value = nil) case T.unsafe(value) @@ -291,6 +303,7 @@ def to_plist } base[:KeepAlive] = @keep_alive if @keep_alive == true + base[:LaunchOnlyOnce] = @launch_only_once if @launch_only_once == true base[:LegacyTimers] = @macos_legacy_timers if @macos_legacy_timers == true base[:TimeOut] = @restart_delay if @restart_delay.present? base[:ProcessType] = @process_type.to_s.capitalize if @process_type.present? @@ -321,11 +334,14 @@ def to_systemd_unit WantedBy=multi-user.target [Service] - Type=simple - ExecStart=#{command.join(" ")} EOS + # command needs to be first because it initializes all other values + cmd = command.join(" ") + options = [] + options << "Type=#{@launch_only_once == true ? "oneshot" : "simple"}" + options << "ExecStart=#{cmd}" options << "Restart=always" if @keep_alive == true options << "RestartSec=#{restart_delay}" if @restart_delay.present? options << "WorkingDirectory=#{@working_dir}" if @working_dir.present? diff --git a/Library/Homebrew/test/service_spec.rb b/Library/Homebrew/test/service_spec.rb index da1c8ec20d40c..72e587f07fd72 100644 --- a/Library/Homebrew/test/service_spec.rb +++ b/Library/Homebrew/test/service_spec.rb @@ -102,6 +102,7 @@ root_dir var working_dir var keep_alive true + launch_only_once true process_type :interactive restart_delay 30 interval 5 @@ -127,6 +128,8 @@ \t \tLabel \thomebrew.mxcl.formula_name + \tLaunchOnlyOnce + \t \tLegacyTimers \t \tProcessType @@ -288,10 +291,11 @@ expect(unit).to eq(unit_expect.strip) end - it "returns valid partial unit" do + it "returns valid partial oneshot unit" do f.class.service do run opt_bin/"beanstalkd" run_type :immediate + launch_only_once true end unit = f.service.to_systemd_unit @@ -303,10 +307,10 @@ WantedBy=multi-user.target [Service] - Type=simple + Type=oneshot ExecStart=#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd EOS - expect(unit).to eq(unit_expect) + expect(unit).to eq(unit_expect.strip) end end