diff --git a/Library/Homebrew/service.rb b/Library/Homebrew/service.rb index 88f88abaf8..5f76cd6daf 100644 --- a/Library/Homebrew/service.rb +++ b/Library/Homebrew/service.rb @@ -141,5 +141,36 @@ module Homebrew base.to_plist end + + # Returns a `String` systemd unit. + # @return [String] + sig { returns(String) } + def to_systemd_unit + instance_eval(&@service_block) + + clean_command = @run.select { |i| i.is_a?(Pathname) } + .map(&:to_s) + + unit = <<~EOS + [Unit] + Description=Homebrew generated unit for #{@formula.name} + + [Service] + Type=simple + ExecStart=#{clean_command.join} + EOS + + options = [] + options << "Restart=always" if @keep_alive == true + options << "WorkingDirectory=#{@working_dir}" if @working_dir.present? + options << "StandardOutput=append:#{@log_path}" if @log_path.present? + options << "StandardError=append:#{@error_log_path}" if @error_log_path.present? + if @environment_variables.present? + list = @environment_variables.map { |k, v| "#{k}=#{v}" }.join("&") + options << "Environment=\"#{list}\"" + end + + unit + options.join("\n") + end end end diff --git a/Library/Homebrew/test/service_spec.rb b/Library/Homebrew/test/service_spec.rb index aad43d0aea..881128e20d 100644 --- a/Library/Homebrew/test/service_spec.rb +++ b/Library/Homebrew/test/service_spec.rb @@ -15,6 +15,23 @@ describe Homebrew::Service do let(:spec) { :stable } let(:f) { klass.new(name, path, spec) } + describe "#std_service_path_env" do + it "returns valid std_service_path_env" do + f.class.service do + run opt_bin/"beanstalkd" + run_type :immediate + environment_variables PATH: std_service_path_env + error_log_path var/"log/beanstalkd.error.log" + log_path var/"log/beanstalkd.log" + working_dir var + keep_alive true + end + + path = f.service.std_service_path_env + expect(path).to eq("#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin") + end + end + describe "#to_plist" do it "returns valid plist" do f.class.service do @@ -63,4 +80,47 @@ describe Homebrew::Service do expect(plist).not_to include("EnvironmentVariables") end end + + describe "#to_systemd_unit" do + it "returns valid unit" do + f.class.service do + run opt_bin/"beanstalkd" + run_type :immediate + environment_variables PATH: std_service_path_env + error_log_path var/"log/beanstalkd.error.log" + log_path var/"log/beanstalkd.log" + working_dir var + keep_alive true + end + + unit = f.service.to_systemd_unit + expect(unit).to include("Description=Homebrew generated unit for formula_name") + expect(unit).to include("Type=simple") + expect(unit).to include("ExecStart=#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd") + expect(unit).to include("Restart=always") + expect(unit).to include("WorkingDirectory=#{HOMEBREW_PREFIX}/var") + expect(unit).to include("StandardOutput=append:#{HOMEBREW_PREFIX}/var/log/beanstalkd.log") + expect(unit).to include("StandardError=append:#{HOMEBREW_PREFIX}/var/log/beanstalkd.error.log") + std_path = "#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin" + expect(unit).to include("Environment=\"PATH=#{std_path}\"") + end + + it "returns valid partial unit" do + f.class.service do + run opt_bin/"beanstalkd" + run_type :immediate + end + + unit = f.service.to_systemd_unit + expect(unit).to include("Description=Homebrew generated unit for formula_name") + expect(unit).to include("Type=simple") + expect(unit).to include("ExecStart=#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd") + expect(unit).not_to include("Restart=always") + expect(unit).not_to include("WorkingDirectory=#{HOMEBREW_PREFIX}/var") + expect(unit).not_to include("StandardOutput=append:#{HOMEBREW_PREFIX}/var/log/beanstalkd.log") + expect(unit).not_to include("StandardError=append:#{HOMEBREW_PREFIX}/var/log/beanstalkd.error.log") + std_path = "#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin" + expect(unit).not_to include("Environment=\"PATH=#{std_path}\"") + end + end end