diff --git a/xbar/brew-services.10m.rb b/xbar/brew-services.10m.rb index 3b9eb00..1e15c8e 100755 --- a/xbar/brew-services.10m.rb +++ b/xbar/brew-services.10m.rb @@ -113,7 +113,19 @@ module Brew attr_reader :name, :status, :user def self.from_line(line) - name, status, user, _plist = line.split + parts = line.split + name = parts[0] + if %w[started stopped error unknown].include?(parts[1]) + status = parts[1] + user = parts[2] + else + # Some services (dbus and logrotate for example) don't show a status + # when running "brew services list" at the moment. Instead they only + # show the service name and the user. So we work around this issue. + status = 'unknown' + user = parts[1] + end + new(name: name, status: status, user: user) end @@ -128,7 +140,15 @@ module Brew end def stopped? - !started? + @stopped ||= @status.downcase == 'stopped' + end + + def error? + @error ||= @status.downcase == 'error' + end + + def unknown_status? + @unknown_status ||= @status.downcase == 'unknown' end end @@ -141,72 +161,125 @@ module Brew brew_check(printer) printer.item( - "#{prefix}#{started_services.size}/#{stopped_services.size}", + "#{prefix}" \ + "#{started_services.size}/#{services.size - started_services.size}", dropdown: false ) printer.sep printer.item('Brew Services') - printer.item( - "#{started_services.size} started / " \ - "#{stopped_services.size} stopped" - ) do |printer| + + printer.item(status_label) do |printer| printer.sep printer.item(':hourglass: Refresh', refresh: true) printer.sep - printer.item( - "Start All (#{stopped_services.size} services)", - terminal: false, refresh: true, shell: brew_path, - param1: 'services', param2: 'start', param3: '--all' - ) - printer.item( - "Stop All (#{started_services.size} services)", - terminal: false, refresh: true, shell: brew_path, - param1: 'services', param2: 'stop', param3: '--all' - ) - printer.item( - 'Restart All ' \ - "(#{started_services.size + stopped_services.size} services)", - terminal: false, refresh: true, shell: brew_path, - param1: 'services', param2: 'restart', param3: '--all' - ) + if stopped_services.size.positive? + printer.item( + "Start All (#{stopped_services.size} services)", + terminal: false, refresh: true, shell: brew_path, + param1: 'services', param2: 'start', param3: '--all' + ) + else + printer.item("Start All (#{stopped_services.size} services)") + end + if started_services.size.positive? + printer.item( + "Stop All (#{started_services.size} services)", + terminal: false, refresh: true, shell: brew_path, + param1: 'services', param2: 'stop', param3: '--all' + ) + else + printer.item("Stop All (#{started_services.size} services)") + end + if services.size.positive? + printer.item( + 'Restart All ' \ + "(#{started_services.size + stopped_services.size} services)", + terminal: false, refresh: true, shell: brew_path, + param1: 'services', param2: 'restart', param3: '--all' + ) + else + printer.item("Restart All (#{services.size} services)") + end end - printer.sep use_groups? ? print_service_groups(printer) : print_services(printer) end private + def status_label + label = [] + if started_services.size.positive? + label << "#{started_services.size} started" + end + if stopped_services.size.positive? + label << "#{stopped_services.size} stopped" + end + if errored_services.size.positive? + label << "#{errored_services.size} error" + end + if unknown_status_services.size.positive? + label << "#{unknown_status_services.size} unknown" + end + + label = ['no services available'] if label.empty? + label.join(' / ') + end + def use_groups? ENV.fetch('VAR_GROUPS', 'true') == 'true' end def print_service_groups(printer) - printer.item('Started:') - started_services.each do |service| - print_service(printer, service) + if started_services.size.positive? + printer.sep + printer.item("Started (#{started_services.size}):") + started_services.each do |service| + print_service(printer, service) + end end - printer.sep - printer.item('Stopped:') - stopped_services.each do |service| - print_service(printer, service) + if stopped_services.size.positive? + printer.sep + printer.item("Stopped (#{stopped_services.size}):") + stopped_services.each do |service| + print_service(printer, service) + end + end + if errored_services.size.positive? + printer.sep + printer.item("Error (#{errored_services.size}):") + errored_services.each do |service| + print_service(printer, service) + end + end + if unknown_status_services.size.positive? + printer.sep + printer.item("Unknown Status (#{unknown_status_services.size}):") + unknown_status_services.each do |service| + print_service(printer, service) + end end end def print_services(printer) + printer.sep services.each do |service| print_service(printer, service) end end def print_service(printer, service) - label = if service.started? - ":white_check_mark: #{service.name}" - else - ":ballot_box_with_check: #{service.name}" - end + icon = if service.started? + ':white_check_mark:' + elsif service.stopped? + ':ballot_box_with_check:' + elsif service.error? + ':warning:' + elsif service.unknown_status? + ':question:' + end - printer.item(label) do |printer| - if service.started? + printer.item("#{icon} #{service.name}") do |printer| + if service.started? || service.error? || service.unknown_status? printer.item( 'Stop', terminal: false, refresh: true, shell: brew_path, @@ -217,7 +290,8 @@ module Brew terminal: false, refresh: true, shell: brew_path, param1: 'services', param2: 'restart', param3: service.name ) - else + end + if service.stopped? || service.unknown_status? printer.item( 'Start', terminal: false, refresh: true, shell: brew_path, @@ -250,14 +324,29 @@ module Brew end def stopped_services - @stopped_services ||= services.reject(&:started?) + @stopped_services ||= services.select(&:stopped?) + end + + def errored_services + @errored_services ||= services.select(&:error?) + end + + def unknown_status_services + @unknown_status_services ||= services.select(&:unknown_status?) end def services - @services ||= cmd( + return @services if @services + + found = false + @services = cmd( brew_path, 'services', 'list' ).each_line.each_with_object([]) do |line, memo| - next if line.match(/^Name\s+Status\s+User\s+Plist$/) + # Ignore header line and everything before it. + unless found + found = line.strip.match(/^Name\s+Status\s+User\s+(File|Plist)$/) + next + end memo.push(Service.from_line(line)) end