Class: Homebrew::Services::FormulaWrapper Private

Inherits:
Object
  • Object
show all
Includes:
Utils::Output::Mixin
Defined in:
services/formula_wrapper.rb

This class is part of a private API. This class may only be used in the Homebrew/brew repository. Third parties should avoid using this class if possible, as it may be removed or changed without warning.

Defined Under Namespace

Classes: StatusOutputSuccessType

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Utils::Output::Mixin

#issue_reporting_message, #odebug, #odeprecated, #odie, #odisabled, #ofail, #oh1, #oh1_title, #ohai, #ohai_title, #onoe, #opoo, #opoo_outside_github_actions, #opoo_without_github_actions_annotation, #pretty_cannot_install, #pretty_deprecated, #pretty_disabled, #pretty_duration, #pretty_install_status, #pretty_installed, #pretty_uninstalled, #pretty_unmarked, #pretty_upgradable, #pretty_warning

Constructor Details

#initialize(formula, service_name: nil) ⇒ void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Initialize a new Service instance with supplied formula.

Parameters:

  • formula (Formula)
  • service_name (String, nil) (defaults to: nil)

Raises:



62
63
64
65
66
67
68
69
70
71
# File 'services/formula_wrapper.rb', line 62

def initialize(formula, service_name: nil)
  @formula = formula
  @service_name_override = service_name
  @status_output_success_type = T.let(nil, T.nilable(StatusOutputSuccessType))
  @loaded_service_names = T.let(nil, T.nilable(T::Array[String]))

  return if System.launchctl? || System.systemctl?

  raise UsageError, System::MISSING_DAEMON_MANAGER_EXCEPTION_MESSAGE
end

Instance Attribute Details

#formulaFormula (readonly)

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Access the Formula instance.

Returns:



15
16
17
# File 'services/formula_wrapper.rb', line 15

def formula
  @formula
end

Class Method Details

.from(path_or_label) ⇒ FormulaWrapper?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Create a new Service instance from either a path or label.

Parameters:

Returns:



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'services/formula_wrapper.rb', line 19

def self.from(path_or_label)
  label = path_or_label.to_s.sub(/\.(?:plist|service)\z/, "")
  match = label.match(path_or_label_regex)
  return unless match

  service_name = match[1]
  formula_name = match[2]
  return if service_name.nil? || formula_name.nil?

  begin
    new(Formulary.factory(formula_name), service_name:)
  rescue
    nil
  end
end

.service_file_label(file) ⇒ String?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'services/formula_wrapper.rb', line 36

def self.service_file_label(file)
  return if file.nil? || !File.file?(file)

  require "plist"
  plist = begin
    Plist.parse_xml(file, marshal: false)
  rescue
    nil
  end
  if plist.nil? && File.binread(file, 8) == "bplist00"
    require "system_command"
    result = SystemCommand.run(
      "/usr/bin/plutil",
      args:         ["-convert", "xml1", "-o", "-", file],
      print_stderr: false,
    )
    plist = result.plist if result.success?
  end
  label = plist["Label"] if plist
  label if label.is_a?(String) && label.present?
rescue
  nil
end

Instance Method Details

#active_service_nameString

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



260
261
262
# File 'services/formula_wrapper.rb', line 260

def active_service_name
  status_output_success_type.service_name
end

#destPathname

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Path to destination service. If run as root, it's in boot_path, else user_path.

Returns:



204
205
206
# File 'services/formula_wrapper.rb', line 204

def dest
  destinations.fetch(0)
end

#dest_dirPathname

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Path to destination service directory. If run as root, it's boot_path, else user_path.

Returns:



198
199
200
# File 'services/formula_wrapper.rb', line 198

def dest_dir
  System.root? ? System.boot_path : System.user_path
end

#destinationsArray<Pathname>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



209
210
211
# File 'services/formula_wrapper.rb', line 209

def destinations
  service_names.map { |name| dest_dir/service_file_basename(name) }
end

#error?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:

  • (Boolean)


306
307
308
309
310
# File 'services/formula_wrapper.rb', line 306

def error?
  return false if pid?

  (exit_code = self.exit_code).present? && !exit_code.zero?
end

#exit_codeInteger?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Get current exit code of daemon process from status output.

Returns:



325
326
327
# File 'services/formula_wrapper.rb', line 325

def exit_code
  Regexp.last_match(1).to_i if status_output =~ exit_code_regex(status_type)
end

#installed?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns true if any version of the formula is installed.

Returns:

  • (Boolean)


223
224
225
# File 'services/formula_wrapper.rb', line 223

def installed?
  formula.any_version_installed?
end

#keep_alive?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Delegate access to formula.service.keep_alive?.

Returns:

  • (Boolean)


96
97
98
99
100
101
# File 'services/formula_wrapper.rb', line 96

def keep_alive?
  return @keep_alive unless @keep_alive.nil?

  @keep_alive = T.let(service? && load_service.keep_alive?, T.nilable(T::Boolean))
  @keep_alive ||= false
end

#loaded?(cached: false) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns true if the service is loaded, else false.

Parameters:

  • cached (Boolean) (defaults to: false)

Returns:

  • (Boolean)


235
236
237
238
239
240
241
242
243
# File 'services/formula_wrapper.rb', line 235

def loaded?(cached: false)
  reset_cache! unless cached

  if System.launchctl?
    status_success
  else # System.systemctl?
    loaded_service_names.present?
  end
end

#loaded_fileString?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



330
331
332
# File 'services/formula_wrapper.rb', line 330

def loaded_file
  Regexp.last_match(1) if status_output =~ loaded_file_regex(status_type)
end

#loaded_service_namesArray<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



246
247
248
249
250
251
252
253
254
255
256
257
# File 'services/formula_wrapper.rb', line 246

def loaded_service_names
  @loaded_service_names ||= if System.systemctl?
    service_names.select do |name|
      (timed? && System::Systemctl.quiet_run("status", "#{name}.timer")) ||
        System::Systemctl.quiet_run("status", "#{name}.service")
    end
  elsif System.launchctl?
    launchctl_service_names.select { |name| System.launchctl_service_running?(name) }
  else
    []
  end
end

#nameString

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Delegate access to formula.name.

Returns:



75
76
77
# File 'services/formula_wrapper.rb', line 75

def name
  @name ||= T.let(formula.name, T.nilable(String))
end

#ownerString?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'services/formula_wrapper.rb', line 279

def owner
  if System.launchctl? && registered_destination.exist?
    # read the username from the plist file
    require "plist"
    plist = begin
      Plist.parse_xml(registered_destination.read, marshal: false)
    rescue
      nil
    end
    plist_username = plist["UserName"] if plist

    return plist_username if plist_username.present?
    return "root" if registered_destination.dirname == System.boot_path
    return System.user if registered_destination.dirname == System.user_path
  end
  return "root" if boot_path_service_file_present?
  return System.user if user_path_service_file_present?

  nil
end

#path_dirsArray<Pathname>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



104
105
106
107
108
# File 'services/formula_wrapper.rb', line 104

def path_dirs
  return [] unless service?

  load_service.path_dirs
end

#pidInteger?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Get current PID of daemon process from status output.

Returns:



319
320
321
# File 'services/formula_wrapper.rb', line 319

def pid
  Regexp.last_match(1).to_i if status_output =~ pid_regex(status_type)
end

#pid?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:

  • (Boolean)


301
302
303
# File 'services/formula_wrapper.rb', line 301

def pid?
  (pid = self.pid).present? && pid.positive?
end

#registered_destinationPathname

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



214
215
216
217
218
219
# File 'services/formula_wrapper.rb', line 214

def registered_destination
  active_destination = dest_dir/service_file_basename(active_service_name)
  return active_destination if active_destination.exist?

  destinations.find(&:exist?) || dest
end

#reset_cache!void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.



228
229
230
231
# File 'services/formula_wrapper.rb', line 228

def reset_cache!
  @status_output_success_type = nil
  @loaded_service_names = nil
end

#service?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Delegate access to formula.service?.

Returns:

  • (Boolean)


81
82
83
# File 'services/formula_wrapper.rb', line 81

def service?
  @service ||= T.let(formula.service?, T.nilable(T::Boolean))
end

#service_contentsString

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Generate the service file content (plist or systemd unit), including any per-service user environment variable overrides, or read the package-provided service file if the formula's service block does not define a command.

Returns:



373
374
375
376
377
378
379
380
381
# File 'services/formula_wrapper.rb', line 373

def service_contents
  if !service_file_generated?
    source_service_file.read
  elsif System.launchctl?
    load_service.to_plist
  else
    load_service.to_systemd_unit
  end
end

#service_filePathname

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

service_file delegates with formula.launchd_service_path or formula.systemd_service_path for systemd.

Returns:



143
144
145
# File 'services/formula_wrapper.rb', line 143

def service_file
  service_files.fetch(0)
end

#service_file_generated?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:

  • (Boolean)


111
112
113
# File 'services/formula_wrapper.rb', line 111

def service_file_generated?
  service? && load_service.command?
end

#service_file_present?(type: nil) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns true if service is present (e.g. .plist is present in boot or user service path), else false Accepts type with values :root for boot path or :user for user path.

Parameters:

  • type (Symbol, nil) (defaults to: nil)

Returns:

  • (Boolean)


267
268
269
270
271
272
273
274
275
276
# File 'services/formula_wrapper.rb', line 267

def service_file_present?(type: nil)
  case type
  when :root
    boot_path_service_file_present?
  when :user
    user_path_service_file_present?
  else
    boot_path_service_file_present? || user_path_service_file_present?
  end
end

#service_filesArray<Pathname>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



148
149
150
151
152
153
154
155
156
# File 'services/formula_wrapper.rb', line 148

def service_files
  @service_files ||= T.let(
    if System.launchctl?
      formula.launchd_service_paths
    else # System.systemctl?
      formula.systemd_service_paths
    end, T.nilable(T::Array[Pathname])
  )
end

#service_nameString

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

service_name delegates with formula.plist_name or formula.service_name for systemd (e.g., sh.brew.<formula>).

Returns:



118
119
120
121
122
123
124
125
126
# File 'services/formula_wrapper.rb', line 118

def service_name
  @service_name ||= T.let(
    if System.launchctl?
      @service_name_override || formula.plist_name
    else # System.systemctl?
      @service_name_override || formula.service_name
    end, T.nilable(String)
  )
end

#service_namesArray<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



129
130
131
132
133
134
135
136
137
138
139
# File 'services/formula_wrapper.rb', line 129

def service_names
  @service_names ||= T.let(
    if @service_name_override
      [@service_name_override]
    elsif System.launchctl?
      formula.plist_names
    else # System.systemctl?
      formula.service_names
    end, T.nilable(T::Array[String])
  )
end

#service_startup?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Whether the service should be launched at startup

Returns:

  • (Boolean)


186
187
188
189
190
191
192
193
194
# File 'services/formula_wrapper.rb', line 186

def service_startup?
  @service_startup ||= T.let(
    if service?
      load_service.requires_root?
    else
      false
    end, T.nilable(T::Boolean)
  )
end

#source_service_filePathname

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



159
160
161
# File 'services/formula_wrapper.rb', line 159

def source_service_file
  service_files.find(&:exist?) || service_file
end

#timed?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Delegate access to formula.service.timed?.

Returns:

  • (Boolean)


87
88
89
90
91
92
# File 'services/formula_wrapper.rb', line 87

def timed?
  return @timed unless @timed.nil?

  @timed = T.let(service? && load_service.timed?, T.nilable(T::Boolean))
  @timed ||= false
end

#timer_contentsString

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



384
385
386
387
388
389
390
391
392
393
394
# File 'services/formula_wrapper.rb', line 384

def timer_contents
  if service_file_generated?
    load_service.to_systemd_timer
  else
    timer_file.read.sub(
      /^([ \t]*Unit[ \t]*=[ \t]*)#{Regexp.union(service_names.map { |name| "#{name}.service" })}([ \t]*)$/,
    ) do
      "#{Regexp.last_match(1)}#{service_name}.service#{Regexp.last_match(2)}"
    end
  end
end

#timer_destPathname

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



175
176
177
# File 'services/formula_wrapper.rb', line 175

def timer_dest
  timer_destinations.fetch(0)
end

#timer_destinationsArray<Pathname>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



180
181
182
# File 'services/formula_wrapper.rb', line 180

def timer_destinations
  service_names.map { |name| dest_dir/"#{name}.timer" }
end

#timer_filePathname

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



164
165
166
167
# File 'services/formula_wrapper.rb', line 164

def timer_file
  files = formula.systemd_timer_paths
  files.find(&:exist?) || files.fetch(0)
end

#timer_nameString

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



170
171
172
# File 'services/formula_wrapper.rb', line 170

def timer_name
  "#{service_name}.timer"
end

#to_hashHash{Symbol => T.anything}

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'services/formula_wrapper.rb', line 335

def to_hash
  hash = {
    name:,
    service_name: active_service_name,
    running:      pid?,
    loaded:       loaded?(cached: true),
    schedulable:  timed?,
    pid:,
    exit_code:,
    user:         owner,
    status:       status_symbol,
    file:         service_file_present? ? registered_destination : source_service_file,
    registered:   service_file_present?,
    loaded_file:,
  }

  return hash unless service?

  service = load_service

  return hash if service.command.blank?

  hash[:command] = service.manual_command
  hash[:working_dir] = service.working_dir
  hash[:root_dir] = service.root_dir
  hash[:log_path] = service.log_path
  hash[:error_log_path] = service.error_log_path
  hash[:interval] = service.interval
  hash[:cron] = service.cron.presence

  hash
end

#unknown_status?Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:

  • (Boolean)


313
314
315
# File 'services/formula_wrapper.rb', line 313

def unknown_status?
  status_output.blank? && !pid?
end