| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  | # typed: true | 
					
						
							|  |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Homebrew | 
					
						
							|  |  |  |   # The {Service} class implements the DSL methods used in a formula's | 
					
						
							|  |  |  |   # `service` block and stores related instance variables. Most of these methods | 
					
						
							|  |  |  |   # also return the related instance variable when no argument is provided. | 
					
						
							|  |  |  |   class Service | 
					
						
							|  |  |  |     extend T::Sig | 
					
						
							| 
									
										
										
										
											2021-04-08 10:06:45 +02:00
										 |  |  |     extend Forwardable | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     RUN_TYPE_IMMEDIATE = "immediate" | 
					
						
							|  |  |  |     RUN_TYPE_INTERVAL = "interval" | 
					
						
							|  |  |  |     RUN_TYPE_CRON = "cron" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-08 21:54:13 -07:00
										 |  |  |     PROCESS_TYPE_BACKGROUND = "background" | 
					
						
							|  |  |  |     PROCESS_TYPE_STANDARD = "standard" | 
					
						
							|  |  |  |     PROCESS_TYPE_INTERACTIVE = "interactive" | 
					
						
							|  |  |  |     PROCESS_TYPE_ADAPTIVE = "adaptive" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |     # sig { params(formula: Formula).void } | 
					
						
							| 
									
										
										
										
											2021-04-08 10:06:45 +02:00
										 |  |  |     def initialize(formula, &block) | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |       @formula = formula | 
					
						
							|  |  |  |       @run_type = RUN_TYPE_IMMEDIATE | 
					
						
							|  |  |  |       @environment_variables = {} | 
					
						
							| 
									
										
										
										
											2021-04-08 10:06:45 +02:00
										 |  |  |       @service_block = block | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { params(command: T.nilable(T.any(T::Array[String], String, Pathname))).returns(T.nilable(Array)) } | 
					
						
							|  |  |  |     def run(command = nil) | 
					
						
							|  |  |  |       case T.unsafe(command) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @run | 
					
						
							|  |  |  |       when String, Pathname | 
					
						
							|  |  |  |         @run = [command] | 
					
						
							|  |  |  |       when Array | 
					
						
							|  |  |  |         @run = command | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise TypeError, "Service#run expects an Array" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { params(path: T.nilable(T.any(String, Pathname))).returns(T.nilable(String)) } | 
					
						
							|  |  |  |     def working_dir(path = nil) | 
					
						
							|  |  |  |       case T.unsafe(path) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @working_dir | 
					
						
							|  |  |  |       when String, Pathname | 
					
						
							|  |  |  |         @working_dir = path.to_s | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise TypeError, "Service#working_dir expects a String" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 18:17:36 +02:00
										 |  |  |     sig { params(path: T.nilable(T.any(String, Pathname))).returns(T.nilable(String)) } | 
					
						
							|  |  |  |     def root_dir(path = nil) | 
					
						
							|  |  |  |       case T.unsafe(path) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @root_dir | 
					
						
							|  |  |  |       when String, Pathname | 
					
						
							|  |  |  |         @root_dir = path.to_s | 
					
						
							|  |  |  |       else | 
					
						
							| 
									
										
										
										
											2021-05-24 14:20:46 +02:00
										 |  |  |         raise TypeError, "Service#root_dir expects a String or Pathname" | 
					
						
							| 
									
										
										
										
											2021-05-22 18:17:36 +02:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { params(path: T.nilable(T.any(String, Pathname))).returns(T.nilable(String)) } | 
					
						
							|  |  |  |     def input_path(path = nil) | 
					
						
							|  |  |  |       case T.unsafe(path) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @input_path | 
					
						
							|  |  |  |       when String, Pathname | 
					
						
							|  |  |  |         @input_path = path.to_s | 
					
						
							|  |  |  |       else | 
					
						
							| 
									
										
										
										
											2021-05-24 14:20:46 +02:00
										 |  |  |         raise TypeError, "Service#input_path expects a String or Pathname" | 
					
						
							| 
									
										
										
										
											2021-05-22 18:17:36 +02:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |     sig { params(path: T.nilable(T.any(String, Pathname))).returns(T.nilable(String)) } | 
					
						
							|  |  |  |     def log_path(path = nil) | 
					
						
							|  |  |  |       case T.unsafe(path) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @log_path | 
					
						
							|  |  |  |       when String, Pathname | 
					
						
							|  |  |  |         @log_path = path.to_s | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise TypeError, "Service#log_path expects a String" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { params(path: T.nilable(T.any(String, Pathname))).returns(T.nilable(String)) } | 
					
						
							|  |  |  |     def error_log_path(path = nil) | 
					
						
							|  |  |  |       case T.unsafe(path) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @error_log_path | 
					
						
							|  |  |  |       when String, Pathname | 
					
						
							|  |  |  |         @error_log_path = path.to_s | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise TypeError, "Service#error_log_path expects a String" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { params(value: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) } | 
					
						
							|  |  |  |     def keep_alive(value = nil) | 
					
						
							|  |  |  |       case T.unsafe(value) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @keep_alive | 
					
						
							|  |  |  |       when true, false | 
					
						
							|  |  |  |         @keep_alive = value | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise TypeError, "Service#keep_alive expects a Boolean" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 18:17:36 +02:00
										 |  |  |     sig { params(value: T.nilable(Integer)).returns(T.nilable(Integer)) } | 
					
						
							|  |  |  |     def restart_delay(value = nil) | 
					
						
							|  |  |  |       case T.unsafe(value) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @restart_delay | 
					
						
							|  |  |  |       when Integer | 
					
						
							|  |  |  |         @restart_delay = value | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise TypeError, "Service#restart_delay expects an Integer" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-08 21:54:13 -07:00
										 |  |  |     sig { params(type: T.nilable(String)).returns(T.nilable(String)) } | 
					
						
							|  |  |  |     def process_type(type = nil) | 
					
						
							|  |  |  |       case T.unsafe(type) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @process_type | 
					
						
							|  |  |  |       when PROCESS_TYPE_BACKGROUND, PROCESS_TYPE_STANDARD, PROCESS_TYPE_INTERACTIVE, PROCESS_TYPE_ADAPTIVE | 
					
						
							|  |  |  |         @process_type = type.to_s | 
					
						
							|  |  |  |       when String | 
					
						
							|  |  |  |         raise TypeError, "Service#process_type allows: "\ | 
					
						
							|  |  |  |                          "'#{PROCESS_TYPE_BACKGROUND}'/'#{PROCESS_TYPE_STANDARD}'/"\ | 
					
						
							|  |  |  |                          "'#{PROCESS_TYPE_INTERACTIVE}'/'#{PROCESS_TYPE_ADAPTIVE}'" | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise TypeError, "Service#process_type expects a String" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |     sig { params(type: T.nilable(T.any(String, Symbol))).returns(T.nilable(String)) } | 
					
						
							|  |  |  |     def run_type(type = nil) | 
					
						
							|  |  |  |       case T.unsafe(type) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @run_type | 
					
						
							|  |  |  |       when "immediate", :immediate | 
					
						
							|  |  |  |         @run_type = type.to_s | 
					
						
							|  |  |  |       when RUN_TYPE_INTERVAL, RUN_TYPE_CRON | 
					
						
							|  |  |  |         raise TypeError, "Service#run_type does not support timers" | 
					
						
							|  |  |  |       when String | 
					
						
							|  |  |  |         raise TypeError, "Service#run_type allows: '#{RUN_TYPE_IMMEDIATE}'/'#{RUN_TYPE_INTERVAL}'/'#{RUN_TYPE_CRON}'" | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise TypeError, "Service#run_type expects a string" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 10:43:39 +02:00
										 |  |  |     sig { params(variables: T::Hash[String, String]).returns(T.nilable(T::Hash[String, String])) } | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |     def environment_variables(variables = {}) | 
					
						
							|  |  |  |       case T.unsafe(variables) | 
					
						
							|  |  |  |       when Hash | 
					
						
							| 
									
										
										
										
											2021-05-22 10:43:39 +02:00
										 |  |  |         @environment_variables = variables.transform_values(&:to_s) | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |       else | 
					
						
							|  |  |  |         raise TypeError, "Service#environment_variables expects a hash" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 18:17:36 +02:00
										 |  |  |     sig { params(value: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) } | 
					
						
							|  |  |  |     def macos_legacy_timers(value = nil) | 
					
						
							|  |  |  |       case T.unsafe(value) | 
					
						
							|  |  |  |       when nil | 
					
						
							|  |  |  |         @macos_legacy_timers | 
					
						
							|  |  |  |       when true, false | 
					
						
							|  |  |  |         @macos_legacy_timers = value | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise TypeError, "Service#macos_legacy_timers expects a Boolean" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-10 00:00:24 +05:30
										 |  |  |     delegate [:bin, :etc, :libexec, :opt_bin, :opt_libexec, :opt_pkgshare, :opt_prefix, :opt_sbin, :var] => :@formula | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sig { returns(String) } | 
					
						
							|  |  |  |     def std_service_path_env | 
					
						
							|  |  |  |       "#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 11:25:56 +02:00
										 |  |  |     sig { returns(T::Array[String]) } | 
					
						
							|  |  |  |     def command | 
					
						
							|  |  |  |       instance_eval(&@service_block) | 
					
						
							| 
									
										
										
										
											2021-04-29 09:43:39 +02:00
										 |  |  |       @run.map(&:to_s) | 
					
						
							| 
									
										
										
										
											2021-04-13 11:25:56 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 10:59:28 +02:00
										 |  |  |     sig { returns(String) } | 
					
						
							|  |  |  |     def manual_command | 
					
						
							|  |  |  |       instance_eval(&@service_block) | 
					
						
							|  |  |  |       vars = @environment_variables.except(:PATH) | 
					
						
							|  |  |  |                                    .map { |k, v| "#{k}=\"#{v}\"" } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       out = vars + command | 
					
						
							|  |  |  |       out.join(" ") | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |     # Returns a `String` plist. | 
					
						
							|  |  |  |     # @return [String] | 
					
						
							|  |  |  |     sig { returns(String) } | 
					
						
							|  |  |  |     def to_plist | 
					
						
							|  |  |  |       base = { | 
					
						
							|  |  |  |         Label:            @formula.plist_name, | 
					
						
							|  |  |  |         RunAtLoad:        @run_type == RUN_TYPE_IMMEDIATE, | 
					
						
							| 
									
										
										
										
											2021-04-29 09:43:39 +02:00
										 |  |  |         ProgramArguments: command, | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       base[:KeepAlive] = @keep_alive if @keep_alive == true | 
					
						
							| 
									
										
										
										
											2021-05-22 18:17:36 +02:00
										 |  |  |       base[:LegacyTimers] = @macos_legacy_timers if @macos_legacy_timers == true | 
					
						
							|  |  |  |       base[:TimeOut] = @restart_delay if @restart_delay.present? | 
					
						
							| 
									
										
										
										
											2021-09-08 21:54:13 -07:00
										 |  |  |       base[:ProcessType] = @process_type.capitalize if @process_type.present? | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |       base[:WorkingDirectory] = @working_dir if @working_dir.present? | 
					
						
							| 
									
										
										
										
											2021-05-22 18:17:36 +02:00
										 |  |  |       base[:RootDirectory] = @root_dir if @root_dir.present? | 
					
						
							|  |  |  |       base[:StandardInPath] = @input_path if @input_path.present? | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |       base[:StandardOutPath] = @log_path if @log_path.present? | 
					
						
							|  |  |  |       base[:StandardErrorPath] = @error_log_path if @error_log_path.present? | 
					
						
							|  |  |  |       base[:EnvironmentVariables] = @environment_variables unless @environment_variables.empty? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       base.to_plist | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2021-04-13 16:59:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Returns a `String` systemd unit. | 
					
						
							|  |  |  |     # @return [String] | 
					
						
							|  |  |  |     sig { returns(String) } | 
					
						
							|  |  |  |     def to_systemd_unit | 
					
						
							|  |  |  |       unit = <<~EOS | 
					
						
							|  |  |  |         [Unit] | 
					
						
							|  |  |  |         Description=Homebrew generated unit for #{@formula.name} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-05 17:59:17 +02:00
										 |  |  |         [Install] | 
					
						
							|  |  |  |         WantedBy=multi-user.target | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 16:59:59 +02:00
										 |  |  |         [Service] | 
					
						
							|  |  |  |         Type=simple | 
					
						
							| 
									
										
										
										
											2021-04-29 09:43:39 +02:00
										 |  |  |         ExecStart=#{command.join(" ")} | 
					
						
							| 
									
										
										
										
											2021-04-13 16:59:59 +02:00
										 |  |  |       EOS | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       options = [] | 
					
						
							|  |  |  |       options << "Restart=always" if @keep_alive == true | 
					
						
							| 
									
										
										
										
											2021-05-22 18:17:36 +02:00
										 |  |  |       options << "RestartSec=#{restart_delay}" if @restart_delay.present? | 
					
						
							| 
									
										
										
										
											2021-04-13 16:59:59 +02:00
										 |  |  |       options << "WorkingDirectory=#{@working_dir}" if @working_dir.present? | 
					
						
							| 
									
										
										
										
											2021-05-22 18:17:36 +02:00
										 |  |  |       options << "RootDirectory=#{@root_dir}" if @root_dir.present? | 
					
						
							|  |  |  |       options << "StandardInput=file:#{@input_path}" if @input_path.present? | 
					
						
							| 
									
										
										
										
											2021-04-13 16:59:59 +02:00
										 |  |  |       options << "StandardOutput=append:#{@log_path}" if @log_path.present? | 
					
						
							|  |  |  |       options << "StandardError=append:#{@error_log_path}" if @error_log_path.present? | 
					
						
							| 
									
										
										
										
											2021-05-25 11:46:18 +02:00
										 |  |  |       options += @environment_variables.map { |k, v| "Environment=\"#{k}=#{v}\"" } if @environment_variables.present? | 
					
						
							| 
									
										
										
										
											2021-04-13 16:59:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       unit + options.join("\n") | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2020-12-11 23:14:50 +01:00
										 |  |  |   end | 
					
						
							|  |  |  | end |