Class: Cask::Cmd::Doctor

Inherits:
AbstractCommand show all
Includes:
Cask::Checkable
Defined in:
brew/Library/Homebrew/cask/cmd/doctor.rb

Instance Attribute Summary

Attributes inherited from AbstractCommand

#args

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Cask::Checkable

#add_error, #add_warning, #errors, #errors?, #result, #summary, #warnings, #warnings?

Methods inherited from AbstractCommand

abstract?, command_name, run, visible

Methods included from Homebrew::Search

#query_regexp, #search_casks, #search_descriptions, #search_formulae, #search_taps

Methods included from Options

#process_arguments

Constructor Details

#initializeDoctor

Returns a new instance of Doctor

Raises:

  • (ArgumentError)


11
12
13
14
15
16
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 11

def initialize(*)
  super
  return if args.empty?

  raise ArgumentError, "#{self.class.command_name} does not take arguments."
end

Class Method Details

.alt_tapsObject



183
184
185
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 183

def self.alt_taps
  Tap.select { |t| t.cask_dir.exist? && t != Tap.default_cask_tap }
end

.cask_count_for_tap(tap) ⇒ Object



187
188
189
190
191
192
193
194
195
196
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 187

def self.cask_count_for_tap(tap)
  cask_count = begin
    tap.cask_files.count
  rescue
    add_error "Unable to read from Tap: #{tap.path}"
    0
  end

  "#{cask_count} #{"cask".pluralize(cask_count)}"
end

.check_sipObject



157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 157

def self.check_sip
  csrutil = "/usr/bin/csrutil"
  return "N/A" unless File.executable?(csrutil)

  Open3.capture2(csrutil, "status")
       .first
       .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

.error_string(string = "Error") ⇒ Object



179
180
181
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 179

def self.error_string(string = "Error")
  Formatter.error("(#{string})")
end

.helpObject



209
210
211
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 209

def self.help
  "checks for configuration issues"
end

.locale_variablesObject



171
172
173
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 171

def self.locale_variables
  ENV.keys.grep(/^(?:LC_\S+|LANG|LANGUAGE)\Z/).sort
end

.none_stringObject



175
176
177
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 175

def self.none_string
  "<NONE>"
end

.render_env_var(var) ⇒ Object



198
199
200
201
202
203
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 198

def self.render_env_var(var)
  return unless ENV.key?(var)

  var = %Q(#{var}="#{ENV[var]}")
  puts user_tilde(var)
end

.user_tilde(path) ⇒ Object



205
206
207
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 205

def self.user_tilde(path)
  path.gsub(ENV["HOME"], "~")
end

Instance Method Details

#cask_count_for_tap(tap) ⇒ Object



145
146
147
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 145

def cask_count_for_tap(tap)
  self.class.cask_count_for_tap(tap)
end

#check_environment_variablesObject



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 102

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

#check_install_locationObject

This could be done by calling into Homebrew, but the situation where brew doctor is needed is precisely the situation where such things are less dependable.



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 49

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.map do |l|
      add_error "Legacy install at #{l}. Run `brew uninstall --force brew-cask`."
      puts l
    end
  end
end

#check_load_pathObject



90
91
92
93
94
95
96
97
98
99
100
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 90

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

#check_quarantine_supportObject



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 124

def check_quarantine_support
  ohai "Gatekeeper support"

  case Quarantine.check_quarantine_support
  when :quarantine_available
    puts "Enabled"
  when :xattr_broken
    add_error "There's not a working version of xattr."
  when :no_swift
    add_error "Swift is not available on this system."
  when :no_quarantine
    add_error "This feature requires the macOS 10.10 SDK or higher."
  else
    onoe "Unknown support status"
  end
end

#check_software_versionsObject



39
40
41
42
43
44
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 39

def check_software_versions
  ohai "Homebrew Version", HOMEBREW_VERSION
  ohai "macOS", MacOS.full_version
  ohai "SIP", self.class.check_sip
  ohai "Java", SystemConfig.describe_java
end

#check_staging_locationObject



63
64
65
66
67
68
69
70
71
72
73
74
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 63

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."
    add_error "To fix, run \'sudo chown -R $(whoami):staff #{user_tilde(path.to_s)}'"
  end

  puts user_tilde(path.to_s)
end

#check_tapsObject



76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 76

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.blank?
      puts none_string
    else
      puts "#{tap.path} (#{cask_count_for_tap(tap)})"
    end
  end
end

#none_stringObject



149
150
151
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 149

def none_string
  self.class.none_string
end

#render_env_var(var) ⇒ Object



153
154
155
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 153

def render_env_var(var)
  self.class.render_env_var(var)
end

#runObject

Raises:



26
27
28
29
30
31
32
33
34
35
36
37
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 26

def run
  check_software_versions
  check_quarantine_support
  check_install_location
  check_staging_location
  check_taps
  check_load_path
  check_environment_variables

  puts summary unless success?
  raise CaskError, "There are some problems with your setup." unless success?
end

#success?Boolean

Returns:

  • (Boolean)


18
19
20
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 18

def success?
  !(errors? || warnings?)
end

#summary_headerObject



22
23
24
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 22

def summary_header
  "Cask's Doctor Checkup"
end

#user_tilde(path) ⇒ Object



141
142
143
# File 'brew/Library/Homebrew/cask/cmd/doctor.rb', line 141

def user_tilde(path)
  self.class.user_tilde(path)
end