252 lines
6.8 KiB
Ruby
Raw Normal View History

2017-11-03 08:37:06 +10:00
require "system_config"
require "hbc/checkable"
2017-11-03 08:37:06 +10:00
2016-09-24 13:52:43 +02:00
module Hbc
class CLI
2017-05-20 19:08:03 +02:00
class Doctor < AbstractCommand
include Checkable
2017-05-21 00:15:56 +02:00
def initialize(*)
super
return if args.empty?
raise ArgumentError, "#{self.class.command_name} does not take arguments."
end
def success?
!(errors? || warnings?)
end
def summary_header
2018-01-29 13:43:21 +00:00
"Cask's Doctor Checkup"
end
2017-05-21 00:15:56 +02:00
def run
check_software_versions
check_install_location
check_staging_location
2018-02-13 21:03:06 +10:00
check_cached_downloads
check_taps
check_load_path
check_environment_variables
puts summary unless success?
2018-01-29 13:43:21 +00:00
raise CaskError, "There are some problems with your setup." unless success?
end
def check_software_versions
2017-02-05 06:48:08 +01:00
ohai "Homebrew-Cask Version", Hbc.full_version
2017-11-03 08:37:06 +10:00
ohai "macOS", MacOS.full_version
2018-01-13 08:47:05 +10:00
ohai "SIP", self.class.check_sip
2017-11-03 08:37:06 +10:00
ohai "Java", SystemConfig.describe_java
end
# This could be done by calling into Homebrew, but the situation
# where "doctor" is needed is precisely the situation where such
# things are less dependable.
def check_install_location
ohai "Homebrew-Cask Install Location"
locations = Dir.glob(HOMEBREW_CELLAR.join("brew-cask", "*")).reverse
if locations.empty?
puts self.class.none_string
else
locations.collect do |l|
add_error "Legacy install at #{l}. Run \"brew uninstall --force brew-cask\"."
puts l
end
end
end
def check_staging_location
ohai "Homebrew-Cask Staging Location"
path = Pathname.new(user_tilde(Caskroom.path.to_s))
if !path.exist?
add_error "The staging path #{path} does not exist."
elsif !path.writable?
add_error "The staging path #{path} is not writable by the current user."
end
puts path
end
def check_cached_downloads
ohai "Homebrew-Cask Cached Downloads"
cleanup = CLI::Cleanup.new
count = cleanup.cache_files.count
size = cleanup.disk_cleanup_size
msg = user_tilde(Cache.path.to_s)
msg << " (#{number_readable(count)} files, #{disk_usage_readable(size)})" unless count.zero?
puts msg
end
def check_taps
2018-06-09 10:13:28 +02:00
default_tap = Tap.default_cask_tap
alt_taps = Tap.select { |t| t.cask_dir.exist? && t != default_tap }
2018-06-09 10:13:28 +02:00
ohai "Homebrew-Cask Taps:"
[default_tap, *alt_taps].each do |tap|
if tap.path.nil? || tap.path.to_s.empty?
puts none_string
else
puts "#{tap.path} (#{cask_count_for_tap(tap)})"
end
end
end
def check_load_path
ohai "Contents of $LOAD_PATH"
paths = $LOAD_PATH.map(&method(:user_tilde))
if paths.empty?
puts none_string
add_error "$LOAD_PATH is empty"
else
puts paths
end
end
def check_environment_variables
2017-02-05 06:48:08 +01:00
ohai "Environment Variables"
2017-05-29 18:24:52 +01:00
environment_variables = %w[
RUBYLIB
RUBYOPT
RUBYPATH
RBENV_VERSION
CHRUBY_VERSION
GEM_HOME
GEM_PATH
BUNDLE_PATH
PATH
SHELL
2018-03-23 11:40:58 +10:00
HOMEBREW_CASK_OPTS
]
locale_variables = ENV.keys.grep(/^(?:LC_\S+|LANG|LANGUAGE)\Z/).sort
(locale_variables + environment_variables).sort.each(&method(:render_env_var))
end
def user_tilde(path)
self.class.user_tilde(path)
end
def cask_count_for_tap(tap)
self.class.cask_count_for_tap(tap)
end
def none_string
self.class.none_string
end
def render_env_var(var)
self.class.render_env_var(var)
2016-09-24 13:52:43 +02:00
end
2016-08-18 22:11:42 +03:00
2018-01-13 08:47:05 +10:00
def self.check_sip
csrutil = "/usr/bin/csrutil"
return "N/A" unless File.executable?(csrutil)
Open3.capture2(csrutil, "status")[0]
.gsub("This is an unsupported configuration, likely to break in the future and leave your machine in an unknown state.", "")
.gsub("System Integrity Protection status: ", "")
.delete("\t\.").capitalize.strip
end
2016-09-24 13:52:43 +02:00
def self.locale_variables
ENV.keys.grep(/^(?:LC_\S+|LANG|LANGUAGE)\Z/).sort
2016-09-24 13:52:43 +02:00
end
2016-08-18 22:11:42 +03:00
2016-09-24 13:52:43 +02:00
def self.none_string
"<NONE>"
end
2016-08-18 22:11:42 +03:00
2016-09-24 13:52:43 +02:00
def self.error_string(string = "Error")
2016-08-30 21:38:13 +02:00
Formatter.error("(#{string})")
2016-09-24 13:52:43 +02:00
end
2016-08-18 22:11:42 +03:00
2016-09-24 13:52:43 +02:00
def self.render_with_none(string)
return string if !string.nil? && string.respond_to?(:to_s) && !string.to_s.empty?
none_string
end
2016-08-18 22:11:42 +03:00
2017-01-25 00:36:38 +01:00
def self.alt_taps
2018-06-09 10:13:28 +02:00
Tap.select { |t| t.cask_dir.exist? && t != Tap.default_cask_tap }
2017-01-25 00:36:38 +01:00
end
def self.cask_count_for_tap(tap)
Formatter.pluralize(tap.cask_files.count, "cask")
2017-01-25 00:36:38 +01:00
rescue StandardError
add_error "Unable to read from Tap: #{tap.path}"
"0"
2016-09-24 13:52:43 +02:00
end
2016-08-18 22:11:42 +03:00
2017-01-25 00:36:38 +01:00
def self.render_taps(*taps)
taps.collect do |tap|
if tap.path.nil? || tap.path.to_s.empty?
2016-09-24 13:52:43 +02:00
none_string
else
2017-01-25 00:36:38 +01:00
"#{tap.path} (#{cask_count_for_tap(tap)})"
2016-09-24 13:52:43 +02:00
end
end
2016-08-18 22:11:42 +03:00
end
2016-09-24 13:52:43 +02:00
def self.render_env_var(var)
return unless ENV.key?(var)
var = %Q(#{var}="#{ENV[var]}")
puts user_tilde(var)
2016-09-24 13:52:43 +02:00
end
2016-08-18 22:11:42 +03:00
def self.user_tilde(path)
path.gsub(ENV["HOME"], "~")
end
2016-09-24 13:52:43 +02:00
# This could be done by calling into Homebrew, but the situation
# where "doctor" is needed is precisely the situation where such
# things are less dependable.
def self.render_install_location
2017-01-25 00:36:38 +01:00
locations = Dir.glob(HOMEBREW_CELLAR.join("brew-cask", "*")).reverse
2016-09-24 13:52:43 +02:00
if locations.empty?
none_string
else
locations.collect do |l|
"#{l} #{error_string 'error: legacy install. Run "brew uninstall --force brew-cask".'}"
end
end
2016-08-18 22:11:42 +03:00
end
2016-09-24 13:52:43 +02:00
def self.render_staging_location(path)
path = Pathname.new(user_tilde(path.to_s))
2016-09-24 13:52:43 +02:00
if !path.exist?
2017-04-21 00:24:09 +02:00
"#{path} #{error_string "error: path does not exist"}"
2016-09-24 13:52:43 +02:00
elsif !path.writable?
"#{path} #{error_string "error: not writable by current user"}"
else
path
end
end
2016-08-18 22:11:42 +03:00
2016-09-24 13:52:43 +02:00
def self.render_load_path(paths)
paths.map(&method(:user_tilde))
2016-09-24 13:52:43 +02:00
return "#{none_string} #{error_string}" if [*paths].empty?
paths
end
2016-08-18 22:11:42 +03:00
2016-09-24 13:52:43 +02:00
def self.render_cached_downloads
2017-05-19 20:27:25 +02:00
cleanup = CLI::Cleanup.new
2017-02-04 21:53:02 +01:00
count = cleanup.cache_files.count
2016-09-24 13:52:43 +02:00
size = cleanup.disk_cleanup_size
msg = user_tilde(Cache.path.to_s)
2017-02-04 21:53:02 +01:00
msg << " (#{number_readable(count)} files, #{disk_usage_readable(size)})" unless count.zero?
msg
2016-09-24 13:52:43 +02:00
end
2016-08-18 22:11:42 +03:00
2016-09-24 13:52:43 +02:00
def self.help
"checks for configuration issues"
end
end
2016-08-18 22:11:42 +03:00
end
end