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