mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00

Symptom (relevant portions):
```
$ brew cask doctor
==> Homebrew-Cask Version
Homebrew-Cask 1.6.7-56-g9ebcef7
Homebrew/homebrew-cask (git revision fc24e; last commit 2018-06-09)
==> macOS
10.13.5
==> SIP
Enabled
...
==> Homebrew-Cask Install Location
<NONE>
==> Homebrew-Cask Staging Location
~/homebrew/Caskroom
...
==> Environment Variables
HOMEBREW_CASK_OPTS="--appdir=~/Applications"
LC_ALL="en_US.UTF-8"
PATH="/usr/bin:/bin:/usr/sbin:/sbin:~/homebrew/Library/Homebrew/shims/scm"
SHELL="/bin/bash"
Cask's Doctor Checkup: failed
- The staging path ~/homebrew/Caskroom does not exist.
Error: There are some problems with your setup.
```
Analysis:
* The source code is
[this](9ebcef785e/Library/Homebrew/cask/lib/hbc/cli/doctor.rb (L63-L66)
).
* The issue is reproducible in `brew irb`:
```
$ ls -dl ~/homebrew/Caskroom
drwxrwxr-x 10 luca admin 340 9 Jun 16:22 /Users/luca/homebrew/Caskroom
$ ( cd ~ && pwd; )
/Users/luca
$ ls -dl /Users/luca/homebrew/Caskroom
drwxrwxr-x 10 luca admin 340 9 Jun 16:22 /Users/luca/homebrew/Caskroom
$ brew irb
==> Interactive Homebrew Shell
Example commands available with: brew irb --examples
irb(main):001:0> Pathname.new("~/homebrew/Caskroom").exist?
=> false
irb(main):002:0> Pathname.new("/Users/luca/homebrew/Caskroom").exist?
=> true
```
195 lines
5.0 KiB
Ruby
195 lines
5.0 KiB
Ruby
require "system_config"
|
|
require "hbc/checkable"
|
|
|
|
module Hbc
|
|
class CLI
|
|
class Doctor < AbstractCommand
|
|
include Checkable
|
|
|
|
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
|
|
"Cask's Doctor Checkup"
|
|
end
|
|
|
|
def run
|
|
check_software_versions
|
|
check_install_location
|
|
check_staging_location
|
|
check_cached_downloads
|
|
check_taps
|
|
check_load_path
|
|
check_environment_variables
|
|
|
|
puts summary unless success?
|
|
raise CaskError, "There are some problems with your setup." unless success?
|
|
end
|
|
|
|
def check_software_versions
|
|
ohai "Homebrew-Cask Version", Hbc.full_version
|
|
ohai "macOS", MacOS.full_version
|
|
ohai "SIP", self.class.check_sip
|
|
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 = Caskroom.path
|
|
|
|
if path.exist? && !path.writable?
|
|
add_error "The staging path #{user_tilde(path.to_s)} is not writable by the current user."
|
|
end
|
|
|
|
puts user_tilde(path.to_s)
|
|
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
|
|
default_tap = Tap.default_cask_tap
|
|
alt_taps = Tap.select { |t| t.cask_dir.exist? && t != default_tap }
|
|
|
|
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
|
|
ohai "Environment Variables"
|
|
|
|
environment_variables = %w[
|
|
RUBYLIB
|
|
RUBYOPT
|
|
RUBYPATH
|
|
RBENV_VERSION
|
|
CHRUBY_VERSION
|
|
GEM_HOME
|
|
GEM_PATH
|
|
BUNDLE_PATH
|
|
PATH
|
|
SHELL
|
|
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)
|
|
end
|
|
|
|
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
|
|
|
|
def self.locale_variables
|
|
ENV.keys.grep(/^(?:LC_\S+|LANG|LANGUAGE)\Z/).sort
|
|
end
|
|
|
|
def self.none_string
|
|
"<NONE>"
|
|
end
|
|
|
|
def self.error_string(string = "Error")
|
|
Formatter.error("(#{string})")
|
|
end
|
|
|
|
def self.alt_taps
|
|
Tap.select { |t| t.cask_dir.exist? && t != Tap.default_cask_tap }
|
|
end
|
|
|
|
def self.cask_count_for_tap(tap)
|
|
Formatter.pluralize(tap.cask_files.count, "cask")
|
|
rescue StandardError
|
|
add_error "Unable to read from Tap: #{tap.path}"
|
|
"0"
|
|
end
|
|
|
|
def self.render_env_var(var)
|
|
return unless ENV.key?(var)
|
|
var = %Q(#{var}="#{ENV[var]}")
|
|
puts user_tilde(var)
|
|
end
|
|
|
|
def self.user_tilde(path)
|
|
path.gsub(ENV["HOME"], "~")
|
|
end
|
|
|
|
def self.help
|
|
"checks for configuration issues"
|
|
end
|
|
end
|
|
end
|
|
end
|