Skip to content

Commit c4b0246

Browse files
committed
Reduce shape variations in Homebrew::Service
1 parent 00c528b commit c4b0246

File tree

2 files changed

+65
-50
lines changed

2 files changed

+65
-50
lines changed

Library/Homebrew/formula_cellar_checks.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ def check_service_command(formula)
306306
return unless formula.service?
307307
return unless formula.service.command?
308308

309-
"Service command does not exist" unless File.exist?(T.must(formula.service.command).first)
309+
"Service command does not exist" unless File.exist?(formula.service.command.first)
310310
end
311311

312312
sig { params(formula: Formula).returns(T.nilable(String)) }

Library/Homebrew/service.rb

Lines changed: 64 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# typed: true # rubocop:todo Sorbet/StrictSigil
1+
# typed: strict
22
# frozen_string_literal: true
33

44
require "ipaddr"
@@ -23,13 +23,38 @@ class Service
2323
PROCESS_TYPE_ADAPTIVE = :adaptive
2424

2525
KEEP_ALIVE_KEYS = [:always, :successful_exit, :crashed, :path].freeze
26+
SOCKET_STRING_REGEX = %r{^([a-z]+)://(.+):([0-9]+)$}i
27+
28+
RunParam = T.type_alias { T.nilable(T.any(T::Array[T.any(String, Pathname)], String, Pathname)) }
29+
Sockets = T.type_alias { T::Hash[Symbol, { host: String, port: String, type: String }] }
2630

27-
# sig { params(formula: Formula).void }
31+
sig { returns(String) }
32+
attr_reader :plist_name, :service_name
33+
34+
sig { params(formula: Formula, block: T.nilable(T.proc.void)).void }
2835
def initialize(formula, &block)
36+
@cron = T.let({}, T::Hash[Symbol, T.any(Integer, String)])
37+
@environment_variables = T.let({}, T::Hash[Symbol, String])
38+
@error_log_path = T.let(nil, T.nilable(String))
2939
@formula = formula
30-
@run_type = RUN_TYPE_IMMEDIATE
31-
@run_at_load = true
32-
@environment_variables = {}
40+
@input_path = T.let(nil, T.nilable(String))
41+
@interval = T.let(nil, T.nilable(Integer))
42+
@keep_alive = T.let({}, T::Hash[Symbol, T.untyped])
43+
@launch_only_once = T.let(false, T::Boolean)
44+
@log_path = T.let(nil, T.nilable(String))
45+
@macos_legacy_timers = T.let(false, T::Boolean)
46+
@plist_name = T.let(default_plist_name, String)
47+
@process_type = T.let(nil, T.nilable(Symbol))
48+
@require_root = T.let(false, T::Boolean)
49+
@restart_delay = T.let(nil, T.nilable(Integer))
50+
@root_dir = T.let(nil, T.nilable(String))
51+
@run = T.let([], T::Array[String])
52+
@run_at_load = T.let(true, T::Boolean)
53+
@run_params = T.let(nil, T.any(RunParam, T::Hash[Symbol, RunParam]))
54+
@run_type = T.let(RUN_TYPE_IMMEDIATE, Symbol)
55+
@service_name = T.let(default_service_name, String)
56+
@sockets = T.let({}, Sockets)
57+
@working_dir = T.let(nil, T.nilable(String))
3358
instance_eval(&block) if block
3459
end
3560

@@ -43,21 +68,11 @@ def default_plist_name
4368
"homebrew.mxcl.#{@formula.name}"
4469
end
4570

46-
sig { returns(String) }
47-
def plist_name
48-
@plist_name ||= default_plist_name
49-
end
50-
5171
sig { returns(String) }
5272
def default_service_name
5373
"homebrew.#{@formula.name}"
5474
end
5575

56-
sig { returns(String) }
57-
def service_name
58-
@service_name ||= default_service_name
59-
end
60-
6176
sig { params(macos: T.nilable(String), linux: T.nilable(String)).void }
6277
def name(macos: nil, linux: nil)
6378
raise TypeError, "Service#name expects at least one String" if [macos, linux].none?(String)
@@ -68,27 +83,27 @@ def name(macos: nil, linux: nil)
6883

6984
sig {
7085
params(
71-
command: T.nilable(T.any(T::Array[T.any(String, Pathname)], String, Pathname)),
72-
macos: T.nilable(T.any(T::Array[T.any(String, Pathname)], String, Pathname)),
73-
linux: T.nilable(T.any(T::Array[T.any(String, Pathname)], String, Pathname)),
86+
command: T.nilable(RunParam),
87+
macos: T.nilable(RunParam),
88+
linux: T.nilable(RunParam),
7489
).returns(T.nilable(T::Array[T.any(String, Pathname)]))
7590
}
7691
def run(command = nil, macos: nil, linux: nil)
7792
# Save parameters for serialization
7893
if command
7994
@run_params = command
8095
elsif macos || linux
81-
@run_params = { macos:, linux: }.compact
96+
@run_params = { macos:, linux: }.compact, T.any(RunParam, T::Hash[Symbol, RunParam])
8297
end
8398

8499
command ||= on_system_conditional(macos:, linux:)
85100
case command
86101
when nil
87102
@run
88103
when String, Pathname
89-
@run = [command]
104+
@run = [command.to_s]
90105
when Array
91-
@run = command
106+
@run = command.map(&:to_s)
92107
end
93108
end
94109

@@ -161,12 +176,12 @@ def keep_alive(value = nil)
161176
end
162177
end
163178

164-
sig { params(value: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) }
179+
sig { params(value: T.nilable(T::Boolean)).returns(T::Boolean) }
165180
def require_root(value = nil)
166181
case value
167182
when nil
168183
@require_root
169-
when true, false
184+
when TrueClass, FalseClass
170185
@require_root = value
171186
end
172187
end
@@ -183,16 +198,14 @@ def run_at_load(value = nil)
183198
case value
184199
when nil
185200
@run_at_load
186-
when true, false
201+
when TrueClass, FalseClass
187202
@run_at_load = value
188203
end
189204
end
190205

191-
SOCKET_STRING_REGEX = %r{^([a-z]+)://(.+):([0-9]+)$}i
192-
193206
sig {
194207
params(value: T.nilable(T.any(String, T::Hash[Symbol, String])))
195-
.returns(T.nilable(T::Hash[Symbol, T::Hash[Symbol, String]]))
208+
.returns(T::Hash[Symbol, T::Hash[Symbol, String]])
196209
}
197210
def sockets(value = nil)
198211
return @sockets if value.nil?
@@ -204,9 +217,11 @@ def sockets(value = nil)
204217
value
205218
end.transform_values do |socket_string|
206219
match = socket_string.match(SOCKET_STRING_REGEX)
207-
raise TypeError, "Service#sockets a formatted socket definition as <type>://<host>:<port>" if match.blank?
220+
raise TypeError, "Service#sockets a formatted socket definition as <type>://<host>:<port>" unless match
208221

209-
type, host, port = match.captures
222+
type = T.must(match[1])
223+
host = T.must(match[2])
224+
port = T.must(match[3])
210225

211226
begin
212227
IPAddr.new(host)
@@ -222,15 +237,15 @@ def sockets(value = nil)
222237
# @return [Boolean]
223238
sig { returns(T::Boolean) }
224239
def keep_alive?
225-
@keep_alive.present? && @keep_alive[:always] != false
240+
!@keep_alive.empty? && @keep_alive[:always] != false
226241
end
227242

228-
sig { params(value: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) }
243+
sig { params(value: T.nilable(T::Boolean)).returns(T::Boolean) }
229244
def launch_only_once(value = nil)
230245
case value
231246
when nil
232247
@launch_only_once
233-
when true, false
248+
when TrueClass, FalseClass
234249
@launch_only_once = value
235250
end
236251
end
@@ -281,13 +296,13 @@ def interval(value = nil)
281296
end
282297
end
283298

284-
sig { params(value: T.nilable(String)).returns(T.nilable(Hash)) }
299+
sig { params(value: T.nilable(String)).returns(T::Hash[Symbol, T.any(Integer, String)]) }
285300
def cron(value = nil)
286301
case value
287302
when nil
288303
@cron
289304
when String
290-
@cron = parse_cron(T.must(value))
305+
@cron = parse_cron(value)
291306
end
292307
end
293308

@@ -345,12 +360,12 @@ def environment_variables(variables = {})
345360
end
346361
end
347362

348-
sig { params(value: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) }
363+
sig { params(value: T.nilable(T::Boolean)).returns(T::Boolean) }
349364
def macos_legacy_timers(value = nil)
350365
case value
351366
when nil
352367
@macos_legacy_timers
353-
when true, false
368+
when TrueClass, FalseClass
354369
@macos_legacy_timers = value
355370
end
356371
end
@@ -362,14 +377,14 @@ def std_service_path_env
362377
"#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin"
363378
end
364379

365-
sig { returns(T.nilable(T::Array[String])) }
380+
sig { returns(T::Array[String]) }
366381
def command
367-
@run&.map(&:to_s)&.map { |arg| arg.start_with?("~") ? File.expand_path(arg) : arg }
382+
@run.map(&:to_s).map { |arg| arg.start_with?("~") ? File.expand_path(arg) : arg }
368383
end
369384

370385
sig { returns(T::Boolean) }
371386
def command?
372-
@run.present?
387+
!@run.empty?
373388
end
374389

375390
# Returns the `String` command to run manually instead of the service.
@@ -379,8 +394,8 @@ def manual_command
379394
vars = @environment_variables.except(:PATH)
380395
.map { |k, v| "#{k}=\"#{v}\"" }
381396

382-
out = vars + T.must(command).map { |arg| Utils::Shell.sh_quote(arg) } if command?
383-
out.join(" ")
397+
vars.concat(command.map { |arg| Utils::Shell.sh_quote(arg) })
398+
vars.join(" ")
384399
end
385400

386401
# Returns a `Boolean` describing if a service is timed.
@@ -425,7 +440,7 @@ def to_plist
425440
end
426441
end
427442

428-
if @sockets.present?
443+
unless @sockets.empty?
429444
base[:Sockets] = {}
430445
@sockets.each do |name, info|
431446
base[:Sockets][name] = {
@@ -436,7 +451,7 @@ def to_plist
436451
end
437452
end
438453

439-
if @cron.present? && @run_type == RUN_TYPE_CRON
454+
if !@cron.empty? && @run_type == RUN_TYPE_CRON
440455
base[:StartCalendarInterval] = @cron.reject { |_, value| value == "*" }
441456
end
442457

@@ -456,8 +471,8 @@ def to_plist
456471
sig { returns(String) }
457472
def to_systemd_unit
458473
# command needs to be first because it initializes all other values
459-
cmd = command&.map { |arg| Utils::Service.systemd_quote(arg) }
460-
&.join(" ")
474+
cmd = command.map { |arg| Utils::Service.systemd_quote(arg) }
475+
.join(" ")
461476

462477
options = []
463478
options << "Type=#{(@launch_only_once == true) ? "oneshot" : "simple"}"
@@ -512,7 +527,7 @@ def to_systemd_timer
512527
end
513528

514529
# Prepare the service hash for inclusion in the formula API JSON.
515-
sig { returns(Hash) }
530+
sig { returns(T::Hash[Symbol, T.untyped]) }
516531
def to_hash
517532
name_params = {
518533
macos: (plist_name if plist_name != default_plist_name),
@@ -521,13 +536,13 @@ def to_hash
521536

522537
return { name: name_params }.compact_blank if @run_params.blank?
523538

524-
cron_string = if @cron.present?
539+
cron_string = unless @cron.empty?
525540
[:Minute, :Hour, :Day, :Month, :Weekday]
526541
.map { |key| @cron[key].to_s }
527542
.join(" ")
528543
end
529544

530-
sockets_var = if @sockets.present?
545+
sockets_var = unless @sockets.empty?
531546
@sockets.transform_values { |info| "#{info[:type]}://#{info[:host]}:#{info[:port]}" }
532547
.then do |sockets_hash|
533548
# TODO: Remove this code when all users are running on versions of Homebrew
@@ -565,7 +580,7 @@ def to_hash
565580
end
566581

567582
# Turn the service API hash values back into what is expected by the formula DSL.
568-
sig { params(api_hash: Hash).returns(Hash) }
583+
sig { params(api_hash: T::Hash[String, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
569584
def self.from_hash(api_hash)
570585
hash = {}
571586
hash[:name] = api_hash["name"].transform_keys(&:to_sym) if api_hash.key?("name")

0 commit comments

Comments
 (0)