2023-03-07 17:24:20 -08:00
|
|
|
# typed: true
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-01-04 23:14:58 +01:00
|
|
|
require "keg"
|
|
|
|
require "language/python"
|
|
|
|
require "formula"
|
2020-05-19 22:22:31 +09:00
|
|
|
require "formulary"
|
2016-01-04 23:14:58 +01:00
|
|
|
require "version"
|
2016-07-29 20:31:32 -06:00
|
|
|
require "development_tools"
|
2016-08-10 23:19:09 -07:00
|
|
|
require "utils/shell"
|
2020-07-10 10:36:59 -04:00
|
|
|
require "system_config"
|
|
|
|
require "cask/caskroom"
|
|
|
|
require "cask/quarantine"
|
2024-01-26 17:33:55 -08:00
|
|
|
require "system_command"
|
2016-01-04 23:14:58 +01:00
|
|
|
|
|
|
|
module Homebrew
|
2020-08-14 04:33:33 +02:00
|
|
|
# Module containing diagnostic checks.
|
|
|
|
#
|
|
|
|
# @api private
|
2016-01-04 23:14:58 +01:00
|
|
|
module Diagnostic
|
2023-03-08 00:29:47 +00:00
|
|
|
def self.missing_deps(formulae, hide = nil)
|
2016-01-04 23:14:58 +01:00
|
|
|
missing = {}
|
2023-03-08 00:29:47 +00:00
|
|
|
formulae.each do |f|
|
2024-03-07 16:20:20 +00:00
|
|
|
missing_dependencies = f.missing_dependencies(hide:)
|
2018-03-25 12:43:24 +01:00
|
|
|
next if missing_dependencies.empty?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2018-03-25 12:43:24 +01:00
|
|
|
yield f.full_name, missing_dependencies if block_given?
|
|
|
|
missing[f.full_name] = missing_dependencies
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
missing
|
|
|
|
end
|
|
|
|
|
2020-09-11 12:05:22 +01:00
|
|
|
def self.checks(type, fatal: true)
|
|
|
|
@checks ||= Checks.new
|
2023-03-07 17:24:20 -08:00
|
|
|
failed = T.let(false, T::Boolean)
|
2020-09-11 12:05:22 +01:00
|
|
|
@checks.public_send(type).each do |check|
|
|
|
|
out = @checks.public_send(check)
|
|
|
|
next if out.nil?
|
|
|
|
|
|
|
|
if fatal
|
|
|
|
failed ||= true
|
|
|
|
ofail out
|
|
|
|
else
|
|
|
|
opoo out
|
|
|
|
end
|
|
|
|
end
|
|
|
|
exit 1 if failed && fatal
|
|
|
|
end
|
|
|
|
|
2020-08-14 04:33:33 +02:00
|
|
|
# Diagnostic checks.
|
2016-01-04 23:14:58 +01:00
|
|
|
class Checks
|
2024-01-26 17:33:55 -08:00
|
|
|
include SystemCommand::Mixin
|
|
|
|
|
2020-08-19 17:12:32 +01:00
|
|
|
def initialize(verbose: true)
|
2020-07-10 10:36:59 -04:00
|
|
|
@verbose = verbose
|
|
|
|
end
|
|
|
|
|
2020-11-05 15:19:56 -05:00
|
|
|
############# @!group HELPERS
|
2018-10-18 21:42:43 -04:00
|
|
|
# Finds files in `HOMEBREW_PREFIX` *and* /usr/local.
|
2019-04-08 12:47:15 -04:00
|
|
|
# Specify paths relative to a prefix, e.g. "include/foo.h".
|
2016-01-04 23:14:58 +01:00
|
|
|
# Sets @found for your convenience.
|
|
|
|
def find_relative_paths(*relative_paths)
|
2018-09-02 20:14:54 +01:00
|
|
|
@found = [HOMEBREW_PREFIX, "/usr/local"].uniq.reduce([]) do |found, prefix|
|
2016-01-04 23:14:58 +01:00
|
|
|
found + relative_paths.map { |f| File.join(prefix, f) }.select { |f| File.exist? f }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-07 17:24:20 -08:00
|
|
|
sig { params(list: T::Array[String], string: String).returns(String) }
|
2016-09-21 14:36:11 +02:00
|
|
|
def inject_file_list(list, string)
|
2019-04-20 14:07:29 +09:00
|
|
|
list.reduce(string.dup) { |acc, elem| acc << " #{elem}\n" }
|
|
|
|
.freeze
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
2020-07-10 10:36:59 -04:00
|
|
|
|
|
|
|
def user_tilde(path)
|
2022-05-30 04:48:54 +01:00
|
|
|
path.gsub(Dir.home, "~")
|
2020-07-10 10:36:59 -04:00
|
|
|
end
|
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(String) }
|
2020-07-10 10:36:59 -04:00
|
|
|
def none_string
|
|
|
|
"<NONE>"
|
|
|
|
end
|
|
|
|
|
|
|
|
def add_info(*args)
|
|
|
|
ohai(*args) if @verbose
|
|
|
|
end
|
2020-11-05 15:19:56 -05:00
|
|
|
############# @!endgroup END HELPERS
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2019-01-21 19:23:31 +00:00
|
|
|
def fatal_preinstall_checks
|
2018-09-06 18:38:43 +01:00
|
|
|
%w[
|
|
|
|
check_access_directories
|
|
|
|
].freeze
|
|
|
|
end
|
|
|
|
|
2019-01-21 19:23:31 +00:00
|
|
|
def fatal_build_from_source_checks
|
2016-07-04 18:35:03 +01:00
|
|
|
%w[
|
|
|
|
check_for_installed_developer_tools
|
2016-11-05 10:38:39 -04:00
|
|
|
].freeze
|
2016-07-04 18:35:03 +01:00
|
|
|
end
|
|
|
|
|
2020-09-11 12:05:22 +01:00
|
|
|
def fatal_setup_build_environment_checks
|
|
|
|
[].freeze
|
|
|
|
end
|
|
|
|
|
2019-01-21 19:23:31 +00:00
|
|
|
def supported_configuration_checks
|
|
|
|
[].freeze
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_from_source_checks
|
|
|
|
[].freeze
|
2016-11-05 10:38:39 -04:00
|
|
|
end
|
2016-11-05 10:39:00 -04:00
|
|
|
|
|
|
|
def build_error_checks
|
2019-01-21 19:23:31 +00:00
|
|
|
supported_configuration_checks + build_from_source_checks
|
2016-09-07 09:11:06 +01:00
|
|
|
end
|
|
|
|
|
2019-01-01 15:46:57 -08:00
|
|
|
def please_create_pull_requests(what = "unsupported configuration")
|
|
|
|
<<~EOS
|
2022-10-06 10:01:02 +01:00
|
|
|
It is expected behaviour that some formulae will fail to build in this #{what}.
|
|
|
|
It is expected behaviour that Homebrew will be buggy and slow.
|
|
|
|
Do not create any issues about this on Homebrew's GitHub repositories.
|
|
|
|
Do not create any issues even if you think this message is unrelated.
|
|
|
|
Any opened issues will be immediately closed without response.
|
2023-02-17 14:33:53 +00:00
|
|
|
Do not ask for help from Homebrew or its maintainers on social media.
|
2022-10-06 10:01:02 +01:00
|
|
|
You may ask for help in Homebrew's discussions but are unlikely to receive a response.
|
|
|
|
Try to figure out the problem yourself and submit a fix as a pull request.
|
|
|
|
We will review it but may or may not accept it.
|
2019-01-01 15:46:57 -08:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2023-04-15 19:06:40 -07:00
|
|
|
sig { params(repository_path: GitRepository, desired_origin: String).returns(T.nilable(String)) }
|
2019-02-18 13:09:58 +11:00
|
|
|
def examine_git_origin(repository_path, desired_origin)
|
2023-04-15 16:46:13 -07:00
|
|
|
return if !Utils::Git.available? || !repository_path.git_repo?
|
2019-02-18 13:09:58 +11:00
|
|
|
|
2023-04-15 16:46:13 -07:00
|
|
|
current_origin = repository_path.origin_url
|
2019-12-19 00:05:20 +09:00
|
|
|
|
2019-02-18 13:09:58 +11:00
|
|
|
if current_origin.nil?
|
|
|
|
<<~EOS
|
|
|
|
Missing #{desired_origin} git origin remote.
|
|
|
|
|
|
|
|
Without a correctly configured origin, Homebrew won't update
|
|
|
|
properly. You can solve this by adding the remote:
|
2020-01-09 14:14:44 +00:00
|
|
|
git -C "#{repository_path}" remote add origin #{Formatter.url(desired_origin)}
|
2019-02-18 13:09:58 +11:00
|
|
|
EOS
|
2019-12-19 00:05:20 +09:00
|
|
|
elsif !current_origin.match?(%r{#{desired_origin}(\.git|/)?$}i)
|
2019-02-18 13:09:58 +11:00
|
|
|
<<~EOS
|
|
|
|
Suspicious #{desired_origin} git origin remote found.
|
|
|
|
The current git origin is:
|
|
|
|
#{current_origin}
|
|
|
|
|
|
|
|
With a non-standard origin, Homebrew won't update properly.
|
|
|
|
You can solve this by setting the origin remote:
|
2020-01-09 14:14:44 +00:00
|
|
|
git -C "#{repository_path}" remote set-url origin #{Formatter.url(desired_origin)}
|
2019-02-18 13:09:58 +11:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-06-01 00:41:44 +08:00
|
|
|
def broken_tap(tap)
|
|
|
|
return unless Utils::Git.available?
|
2021-05-12 16:07:47 +01:00
|
|
|
|
2023-04-15 19:06:40 -07:00
|
|
|
repo = GitRepository.new(HOMEBREW_REPOSITORY)
|
|
|
|
return unless repo.git_repo?
|
2021-06-01 00:41:44 +08:00
|
|
|
|
2021-06-02 00:08:33 +08:00
|
|
|
message = <<~EOS
|
|
|
|
#{tap.full_name} was not tapped properly! Run:
|
|
|
|
rm -rf "#{tap.path}"
|
|
|
|
brew tap #{tap.name}
|
|
|
|
EOS
|
|
|
|
|
|
|
|
return message if tap.remote.blank?
|
2021-06-01 00:41:44 +08:00
|
|
|
|
|
|
|
tap_head = tap.git_head
|
2021-06-02 00:08:33 +08:00
|
|
|
return message if tap_head.blank?
|
2023-04-15 19:06:40 -07:00
|
|
|
return if tap_head != repo.head_ref
|
2021-06-01 00:41:44 +08:00
|
|
|
|
2021-06-02 00:08:33 +08:00
|
|
|
message
|
2021-06-01 00:41:44 +08:00
|
|
|
end
|
|
|
|
|
2016-07-04 18:35:03 +01:00
|
|
|
def check_for_installed_developer_tools
|
|
|
|
return if DevelopmentTools.installed?
|
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2016-07-04 18:35:03 +01:00
|
|
|
No developer tools installed.
|
2016-07-16 21:03:12 +01:00
|
|
|
#{DevelopmentTools.installation_instructions}
|
2016-07-04 18:35:03 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2020-06-06 19:12:12 +01:00
|
|
|
def __check_stray_files(dir, pattern, allow_list, message)
|
2016-01-04 23:14:58 +01:00
|
|
|
return unless File.directory?(dir)
|
|
|
|
|
|
|
|
files = Dir.chdir(dir) do
|
2020-06-06 19:12:12 +01:00
|
|
|
(Dir.glob(pattern) - Dir.glob(allow_list))
|
2017-10-07 00:31:28 +02:00
|
|
|
.select { |f| File.file?(f) && !File.symlink?(f) }
|
|
|
|
.map { |f| File.join(dir, f) }
|
|
|
|
end
|
2016-04-06 05:08:53 +02:00
|
|
|
return if files.empty?
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2017-10-20 22:44:11 +01:00
|
|
|
inject_file_list(files.sort, message)
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_stray_dylibs
|
|
|
|
# Dylibs which are generally OK should be added to this list,
|
|
|
|
# with a short description of the software they come with.
|
2020-06-06 19:12:12 +01:00
|
|
|
allow_list = [
|
2016-01-04 23:14:58 +01:00
|
|
|
"libfuse.2.dylib", # MacFuse
|
|
|
|
"libfuse_ino64.2.dylib", # MacFuse
|
|
|
|
"libmacfuse_i32.2.dylib", # OSXFuse MacFuse compatibility layer
|
|
|
|
"libmacfuse_i64.2.dylib", # OSXFuse MacFuse compatibility layer
|
|
|
|
"libosxfuse_i32.2.dylib", # OSXFuse
|
|
|
|
"libosxfuse_i64.2.dylib", # OSXFuse
|
2016-02-20 19:24:30 +00:00
|
|
|
"libosxfuse.2.dylib", # OSXFuse
|
2017-06-01 16:06:51 +02:00
|
|
|
"libTrAPI.dylib", # TrAPI/Endpoint Security VPN
|
2016-01-04 23:14:58 +01:00
|
|
|
"libntfs-3g.*.dylib", # NTFS-3G
|
|
|
|
"libntfs.*.dylib", # NTFS-3G
|
|
|
|
"libublio.*.dylib", # NTFS-3G
|
|
|
|
"libUFSDNTFS.dylib", # Paragon NTFS
|
|
|
|
"libUFSDExtFS.dylib", # Paragon ExtFS
|
2016-11-04 14:35:54 +00:00
|
|
|
"libecomlodr.dylib", # Symantec Endpoint Protection
|
2017-06-22 16:00:54 +08:00
|
|
|
"libsymsea*.dylib", # Symantec Endpoint Protection
|
2016-11-04 12:18:23 -04:00
|
|
|
"sentinel.dylib", # SentinelOne
|
2017-11-28 17:34:16 -05:00
|
|
|
"sentinel-*.dylib", # SentinelOne
|
2016-01-04 23:14:58 +01:00
|
|
|
]
|
|
|
|
|
2020-06-06 19:12:12 +01:00
|
|
|
__check_stray_files "/usr/local/lib", "*.dylib", allow_list, <<~EOS
|
2016-04-06 05:08:53 +02:00
|
|
|
Unbrewed dylibs were found in /usr/local/lib.
|
|
|
|
If you didn't put them there on purpose they could cause problems when
|
|
|
|
building Homebrew formulae, and may need to be deleted.
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2016-04-06 05:08:53 +02:00
|
|
|
Unexpected dylibs:
|
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_stray_static_libs
|
|
|
|
# Static libs which are generally OK should be added to this list,
|
|
|
|
# with a short description of the software they come with.
|
2020-06-06 19:12:12 +01:00
|
|
|
allow_list = [
|
2016-01-04 23:14:58 +01:00
|
|
|
"libntfs-3g.a", # NTFS-3G
|
|
|
|
"libntfs.a", # NTFS-3G
|
|
|
|
"libublio.a", # NTFS-3G
|
2016-11-04 14:35:54 +00:00
|
|
|
"libappfirewall.a", # Symantec Endpoint Protection
|
|
|
|
"libautoblock.a", # Symantec Endpoint Protection
|
|
|
|
"libautosetup.a", # Symantec Endpoint Protection
|
|
|
|
"libconnectionsclient.a", # Symantec Endpoint Protection
|
|
|
|
"liblocationawareness.a", # Symantec Endpoint Protection
|
|
|
|
"libpersonalfirewall.a", # Symantec Endpoint Protection
|
|
|
|
"libtrustedcomponents.a", # Symantec Endpoint Protection
|
2016-01-04 23:14:58 +01:00
|
|
|
]
|
|
|
|
|
2020-06-06 19:12:12 +01:00
|
|
|
__check_stray_files "/usr/local/lib", "*.a", allow_list, <<~EOS
|
2016-04-06 05:08:53 +02:00
|
|
|
Unbrewed static libraries were found in /usr/local/lib.
|
|
|
|
If you didn't put them there on purpose they could cause problems when
|
|
|
|
building Homebrew formulae, and may need to be deleted.
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2016-04-06 05:08:53 +02:00
|
|
|
Unexpected static libraries:
|
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_stray_pcs
|
|
|
|
# Package-config files which are generally OK should be added to this list,
|
|
|
|
# with a short description of the software they come with.
|
2020-06-06 19:12:12 +01:00
|
|
|
allow_list = [
|
2016-01-04 23:14:58 +01:00
|
|
|
"fuse.pc", # OSXFuse/MacFuse
|
|
|
|
"macfuse.pc", # OSXFuse MacFuse compatibility layer
|
|
|
|
"osxfuse.pc", # OSXFuse
|
|
|
|
"libntfs-3g.pc", # NTFS-3G
|
|
|
|
"libublio.pc", # NTFS-3G
|
|
|
|
]
|
|
|
|
|
2020-06-06 19:12:12 +01:00
|
|
|
__check_stray_files "/usr/local/lib/pkgconfig", "*.pc", allow_list, <<~EOS
|
2021-01-26 15:21:24 -05:00
|
|
|
Unbrewed '.pc' files were found in /usr/local/lib/pkgconfig.
|
2016-04-06 05:08:53 +02:00
|
|
|
If you didn't put them there on purpose they could cause problems when
|
|
|
|
building Homebrew formulae, and may need to be deleted.
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2021-01-26 15:21:24 -05:00
|
|
|
Unexpected '.pc' files:
|
2016-04-06 05:08:53 +02:00
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_stray_las
|
2020-06-06 19:12:12 +01:00
|
|
|
allow_list = [
|
2016-01-04 23:14:58 +01:00
|
|
|
"libfuse.la", # MacFuse
|
|
|
|
"libfuse_ino64.la", # MacFuse
|
|
|
|
"libosxfuse_i32.la", # OSXFuse
|
|
|
|
"libosxfuse_i64.la", # OSXFuse
|
2016-02-20 19:24:30 +00:00
|
|
|
"libosxfuse.la", # OSXFuse
|
2016-01-04 23:14:58 +01:00
|
|
|
"libntfs-3g.la", # NTFS-3G
|
|
|
|
"libntfs.la", # NTFS-3G
|
|
|
|
"libublio.la", # NTFS-3G
|
|
|
|
]
|
|
|
|
|
2020-06-06 19:12:12 +01:00
|
|
|
__check_stray_files "/usr/local/lib", "*.la", allow_list, <<~EOS
|
2021-01-26 15:21:24 -05:00
|
|
|
Unbrewed '.la' files were found in /usr/local/lib.
|
2016-04-06 05:08:53 +02:00
|
|
|
If you didn't put them there on purpose they could cause problems when
|
|
|
|
building Homebrew formulae, and may need to be deleted.
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2021-01-26 15:21:24 -05:00
|
|
|
Unexpected '.la' files:
|
2016-04-06 05:08:53 +02:00
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_stray_headers
|
2020-06-06 19:12:12 +01:00
|
|
|
allow_list = [
|
2016-01-04 23:14:58 +01:00
|
|
|
"fuse.h", # MacFuse
|
|
|
|
"fuse/**/*.h", # MacFuse
|
|
|
|
"macfuse/**/*.h", # OSXFuse MacFuse compatibility layer
|
|
|
|
"osxfuse/**/*.h", # OSXFuse
|
|
|
|
"ntfs/**/*.h", # NTFS-3G
|
|
|
|
"ntfs-3g/**/*.h", # NTFS-3G
|
|
|
|
]
|
|
|
|
|
2020-06-06 19:12:12 +01:00
|
|
|
__check_stray_files "/usr/local/include", "**/*.h", allow_list, <<~EOS
|
2016-04-06 05:08:53 +02:00
|
|
|
Unbrewed header files were found in /usr/local/include.
|
|
|
|
If you didn't put them there on purpose they could cause problems when
|
|
|
|
building Homebrew formulae, and may need to be deleted.
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2016-04-06 05:08:53 +02:00
|
|
|
Unexpected header files:
|
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_broken_symlinks
|
|
|
|
broken_symlinks = []
|
|
|
|
|
2018-09-25 22:03:29 +01:00
|
|
|
Keg::MUST_EXIST_SUBDIRECTORIES.each do |d|
|
2016-01-04 23:14:58 +01:00
|
|
|
next unless d.directory?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-01-04 23:14:58 +01:00
|
|
|
d.find do |path|
|
2019-02-19 13:11:32 +00:00
|
|
|
broken_symlinks << path if path.symlink? && !path.resolved_path_exists?
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
return if broken_symlinks.empty?
|
2016-04-06 05:08:53 +02:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
inject_file_list broken_symlinks, <<~EOS
|
2019-01-02 13:21:34 +00:00
|
|
|
Broken symlinks were found. Remove them with `brew cleanup`:
|
2016-01-04 23:14:58 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2016-09-09 13:08:02 +01:00
|
|
|
def check_tmpdir_sticky_bit
|
|
|
|
world_writable = HOMEBREW_TEMP.stat.mode & 0777 == 0777
|
|
|
|
return if !world_writable || HOMEBREW_TEMP.sticky?
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2016-09-09 13:08:02 +01:00
|
|
|
#{HOMEBREW_TEMP} is world-writable but does not have the sticky bit set.
|
2021-01-24 21:25:12 -05:00
|
|
|
To set it, run the following command:
|
|
|
|
sudo chmod +t #{HOMEBREW_TEMP}
|
2016-01-04 23:14:58 +01:00
|
|
|
EOS
|
|
|
|
end
|
2020-08-24 00:22:17 +02:00
|
|
|
alias generic_check_tmpdir_sticky_bit check_tmpdir_sticky_bit
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2018-09-06 18:38:43 +01:00
|
|
|
def check_exist_directories
|
2024-03-27 06:26:32 +00:00
|
|
|
return if HOMEBREW_PREFIX.writable?
|
2020-12-07 14:32:56 +00:00
|
|
|
|
2018-09-06 18:38:43 +01:00
|
|
|
not_exist_dirs = Keg::MUST_EXIST_DIRECTORIES.reject(&:exist?)
|
|
|
|
return if not_exist_dirs.empty?
|
2016-04-06 05:08:53 +02:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2018-09-06 18:38:43 +01:00
|
|
|
The following directories do not exist:
|
|
|
|
#{not_exist_dirs.join("\n")}
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2021-01-26 15:21:24 -05:00
|
|
|
You should create these directories and change their ownership to your user.
|
2018-09-06 18:38:43 +01:00
|
|
|
sudo mkdir -p #{not_exist_dirs.join(" ")}
|
2023-09-29 12:32:22 +01:00
|
|
|
sudo chown -R #{current_user} #{not_exist_dirs.join(" ")}
|
2016-01-04 23:14:58 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2018-09-06 18:38:43 +01:00
|
|
|
def check_access_directories
|
|
|
|
not_writable_dirs =
|
|
|
|
Keg::MUST_BE_WRITABLE_DIRECTORIES.select(&:exist?)
|
2024-03-27 06:26:32 +00:00
|
|
|
.reject(&:writable?)
|
2016-09-09 08:06:37 +01:00
|
|
|
return if not_writable_dirs.empty?
|
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2018-09-06 18:38:43 +01:00
|
|
|
The following directories are not writable by your user:
|
2016-09-09 08:06:37 +01:00
|
|
|
#{not_writable_dirs.join("\n")}
|
|
|
|
|
2018-09-06 18:38:43 +01:00
|
|
|
You should change the ownership of these directories to your user.
|
2023-09-29 12:32:22 +01:00
|
|
|
sudo chown -R #{current_user} #{not_writable_dirs.join(" ")}
|
2019-03-22 22:45:41 -04:00
|
|
|
|
|
|
|
And make sure that your user has write permission.
|
|
|
|
chmod u+w #{not_writable_dirs.join(" ")}
|
2016-01-04 23:14:58 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2016-12-13 00:19:46 +00:00
|
|
|
def check_multiple_cellars
|
|
|
|
return if HOMEBREW_PREFIX.to_s == HOMEBREW_REPOSITORY.to_s
|
|
|
|
return unless (HOMEBREW_REPOSITORY/"Cellar").exist?
|
|
|
|
return unless (HOMEBREW_PREFIX/"Cellar").exist?
|
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2016-12-13 00:19:46 +00:00
|
|
|
You have multiple Cellars.
|
|
|
|
You should delete #{HOMEBREW_REPOSITORY}/Cellar:
|
|
|
|
rm -rf #{HOMEBREW_REPOSITORY}/Cellar
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2016-01-04 23:14:58 +01:00
|
|
|
def check_user_path_1
|
2017-10-07 00:31:28 +02:00
|
|
|
@seen_prefix_bin = false
|
|
|
|
@seen_prefix_sbin = false
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2016-04-06 05:08:53 +02:00
|
|
|
message = ""
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2017-11-17 17:41:58 +00:00
|
|
|
paths.each do |p|
|
2016-01-04 23:14:58 +01:00
|
|
|
case p
|
|
|
|
when "/usr/bin"
|
2017-10-07 00:31:28 +02:00
|
|
|
unless @seen_prefix_bin
|
2016-01-04 23:14:58 +01:00
|
|
|
# only show the doctor message if there are any conflicts
|
|
|
|
# rationale: a default install should not trigger any brew doctor messages
|
2016-09-17 15:17:27 +01:00
|
|
|
conflicts = Dir["#{HOMEBREW_PREFIX}/bin/*"]
|
|
|
|
.map { |fn| File.basename fn }
|
|
|
|
.select { |bn| File.exist? "/usr/bin/#{bn}" }
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2016-09-17 15:17:27 +01:00
|
|
|
unless conflicts.empty?
|
2017-10-15 02:28:32 +02:00
|
|
|
message = inject_file_list conflicts, <<~EOS
|
2021-01-26 15:21:24 -05:00
|
|
|
/usr/bin occurs before #{HOMEBREW_PREFIX}/bin in your PATH.
|
2016-04-06 05:08:53 +02:00
|
|
|
This means that system-provided programs will be used instead of those
|
2020-07-14 18:48:47 +08:00
|
|
|
provided by Homebrew. Consider setting your PATH so that
|
|
|
|
#{HOMEBREW_PREFIX}/bin occurs before /usr/bin. Here is a one-liner:
|
2017-04-22 16:28:07 +01:00
|
|
|
#{Utils::Shell.prepend_path_in_profile("#{HOMEBREW_PREFIX}/bin")}
|
2020-07-14 18:48:47 +08:00
|
|
|
|
|
|
|
The following tools exist at both paths:
|
2016-04-06 05:08:53 +02:00
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
when "#{HOMEBREW_PREFIX}/bin"
|
2017-10-07 00:31:28 +02:00
|
|
|
@seen_prefix_bin = true
|
2016-01-04 23:14:58 +01:00
|
|
|
when "#{HOMEBREW_PREFIX}/sbin"
|
2017-10-07 00:31:28 +02:00
|
|
|
@seen_prefix_sbin = true
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
end
|
2016-04-06 05:08:53 +02:00
|
|
|
|
|
|
|
message unless message.empty?
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_user_path_2
|
2017-10-07 00:31:28 +02:00
|
|
|
return if @seen_prefix_bin
|
2016-04-06 05:08:53 +02:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2021-01-26 15:21:24 -05:00
|
|
|
Homebrew's "bin" was not found in your PATH.
|
|
|
|
Consider setting your PATH for example like so:
|
2017-04-22 16:28:07 +01:00
|
|
|
#{Utils::Shell.prepend_path_in_profile("#{HOMEBREW_PREFIX}/bin")}
|
2016-01-04 23:14:58 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_user_path_3
|
2017-10-07 00:31:28 +02:00
|
|
|
return if @seen_prefix_sbin
|
2016-04-06 05:08:53 +02:00
|
|
|
|
2016-01-04 23:14:58 +01:00
|
|
|
# Don't complain about sbin not being in the path if it doesn't exist
|
2017-06-01 16:06:51 +02:00
|
|
|
sbin = HOMEBREW_PREFIX/"sbin"
|
2019-10-09 19:33:11 +01:00
|
|
|
return unless sbin.directory?
|
|
|
|
return if sbin.children.empty?
|
|
|
|
return if sbin.children.one? && sbin.children.first.basename.to_s == ".keepme"
|
2016-04-06 05:08:53 +02:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2021-01-26 15:21:24 -05:00
|
|
|
Homebrew's "sbin" was not found in your PATH but you have installed
|
2016-04-06 05:08:53 +02:00
|
|
|
formulae that put executables in #{HOMEBREW_PREFIX}/sbin.
|
2021-01-26 15:21:24 -05:00
|
|
|
Consider setting your PATH for example like so:
|
2017-04-22 16:28:07 +01:00
|
|
|
#{Utils::Shell.prepend_path_in_profile("#{HOMEBREW_PREFIX}/sbin")}
|
2016-04-06 05:08:53 +02:00
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_symlinked_cellar
|
|
|
|
return unless HOMEBREW_CELLAR.exist?
|
2016-04-06 05:08:53 +02:00
|
|
|
return unless HOMEBREW_CELLAR.symlink?
|
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
Symlinked Cellars can cause problems.
|
|
|
|
Your Homebrew Cellar is a symlink: #{HOMEBREW_CELLAR}
|
|
|
|
which resolves to: #{HOMEBREW_CELLAR.realpath}
|
|
|
|
|
|
|
|
The recommended Homebrew installations are either:
|
|
|
|
(A) Have Cellar be a real directory inside of your HOMEBREW_PREFIX
|
|
|
|
(B) Symlink "bin/brew" into your prefix, but don't symlink "Cellar".
|
|
|
|
|
|
|
|
Older installations of Homebrew may have created a symlinked Cellar, but this can
|
2019-04-08 12:47:15 -04:00
|
|
|
cause problems when two formulae install to locations that are mapped on top of each
|
2016-01-04 23:14:58 +01:00
|
|
|
other during the linking step.
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2016-06-13 02:57:35 +02:00
|
|
|
def check_git_version
|
2022-05-30 04:37:09 +01:00
|
|
|
minimum_version = ENV.fetch("HOMEBREW_MINIMUM_GIT_VERSION")
|
2020-08-23 06:32:26 +02:00
|
|
|
return unless Utils::Git.available?
|
2023-07-06 16:47:09 +01:00
|
|
|
return if Version.new(Utils::Git.version) >= Version.new(minimum_version)
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2016-04-06 05:08:53 +02:00
|
|
|
git = Formula["git"]
|
|
|
|
git_upgrade_cmd = git.any_version_installed? ? "upgrade" : "install"
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2020-08-23 06:32:26 +02:00
|
|
|
An outdated version (#{Utils::Git.version}) of Git was detected in your PATH.
|
2018-09-06 12:38:20 +01:00
|
|
|
Git #{minimum_version} or newer is required for Homebrew.
|
2016-04-06 05:08:53 +02:00
|
|
|
Please upgrade:
|
|
|
|
brew #{git_upgrade_cmd} git
|
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_git
|
2020-08-23 06:32:26 +02:00
|
|
|
return if Utils::Git.available?
|
2016-06-13 02:57:35 +02:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2016-06-13 02:57:35 +02:00
|
|
|
Git could not be found in your PATH.
|
|
|
|
Homebrew uses Git for several internal functions, and some formulae use Git
|
|
|
|
checkouts instead of stable tarballs. You may want to install Git:
|
|
|
|
brew install git
|
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_git_newline_settings
|
2020-08-23 06:32:26 +02:00
|
|
|
return unless Utils::Git.available?
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2016-02-26 13:35:36 -05:00
|
|
|
autocrlf = HOMEBREW_REPOSITORY.cd { `git config --get core.autocrlf`.chomp }
|
2023-04-18 15:06:50 -07:00
|
|
|
return if autocrlf != "true"
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2016-04-06 05:08:53 +02:00
|
|
|
Suspicious Git newline settings found.
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2016-04-06 05:08:53 +02:00
|
|
|
The detected Git newline settings will cause checkout problems:
|
|
|
|
core.autocrlf = #{autocrlf}
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2016-04-06 05:08:53 +02:00
|
|
|
If you are not routinely dealing with Windows-based projects,
|
|
|
|
consider removing these by running:
|
|
|
|
git config --global core.autocrlf input
|
2016-01-04 23:14:58 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2017-03-26 20:28:11 +01:00
|
|
|
def check_brew_git_origin
|
2023-04-15 19:06:40 -07:00
|
|
|
repo = GitRepository.new(HOMEBREW_REPOSITORY)
|
2021-05-12 16:07:47 +01:00
|
|
|
examine_git_origin(repo, Homebrew::EnvConfig.brew_git_remote)
|
2017-03-26 20:28:11 +01:00
|
|
|
end
|
|
|
|
|
2021-06-01 00:41:44 +08:00
|
|
|
def check_coretap_integrity
|
2024-02-20 21:10:15 +01:00
|
|
|
core_tap = CoreTap.instance
|
|
|
|
unless core_tap.installed?
|
2023-02-24 13:25:18 +00:00
|
|
|
return unless EnvConfig.no_install_from_api?
|
2022-08-26 12:38:03 +00:00
|
|
|
|
2024-02-20 21:10:15 +01:00
|
|
|
core_tap.ensure_installed!
|
2022-08-26 12:38:03 +00:00
|
|
|
end
|
2021-10-27 01:41:57 -04:00
|
|
|
|
2024-02-20 21:10:15 +01:00
|
|
|
broken_tap(core_tap) || examine_git_origin(core_tap.git_repo, Homebrew::EnvConfig.core_git_remote)
|
2019-02-18 13:09:58 +11:00
|
|
|
end
|
2017-03-26 20:28:11 +01:00
|
|
|
|
2021-06-01 00:41:44 +08:00
|
|
|
def check_casktap_integrity
|
2024-02-20 21:10:15 +01:00
|
|
|
core_cask_tap = CoreCaskTap.instance
|
|
|
|
return unless core_cask_tap.installed?
|
2020-01-09 14:14:44 +00:00
|
|
|
|
2024-02-20 21:10:15 +01:00
|
|
|
broken_tap(core_cask_tap) || examine_git_origin(core_cask_tap.git_repo, core_cask_tap.remote)
|
2019-01-24 22:51:33 -08:00
|
|
|
end
|
2017-09-27 16:32:13 -04:00
|
|
|
|
2020-11-26 13:20:22 +11:00
|
|
|
sig { returns(T.nilable(String)) }
|
|
|
|
def check_tap_git_branch
|
2018-02-12 16:38:10 +00:00
|
|
|
return if ENV["CI"]
|
2020-11-26 13:20:22 +11:00
|
|
|
return unless Utils::Git.available?
|
2017-09-27 16:32:13 -04:00
|
|
|
|
2024-03-06 20:58:34 -08:00
|
|
|
commands = Tap.installed.filter_map do |tap|
|
2023-04-17 06:32:15 -07:00
|
|
|
next if tap.git_repo.default_origin_branch?
|
2019-01-24 22:51:33 -08:00
|
|
|
|
2023-04-17 06:32:15 -07:00
|
|
|
"git -C $(brew --repo #{tap.name}) checkout #{tap.git_repo.origin_branch_name}"
|
2024-02-22 23:29:55 +00:00
|
|
|
end
|
2017-09-27 16:32:13 -04:00
|
|
|
|
2020-11-26 13:20:22 +11:00
|
|
|
return if commands.blank?
|
|
|
|
|
|
|
|
<<~EOS
|
|
|
|
Some taps are not on the default git origin branch and may not receive
|
|
|
|
updates. If this is a surprise to you, check out the default branch with:
|
|
|
|
#{commands.join("\n ")}
|
2017-09-27 16:32:13 -04:00
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
2019-02-16 20:07:10 +00:00
|
|
|
def check_deprecated_official_taps
|
|
|
|
tapped_deprecated_taps =
|
|
|
|
Tap.select(&:official?).map(&:repo) & DEPRECATED_OFFICIAL_TAPS
|
|
|
|
return if tapped_deprecated_taps.empty?
|
|
|
|
|
|
|
|
<<~EOS
|
|
|
|
You have the following deprecated, official taps tapped:
|
2019-02-21 00:06:57 +09:00
|
|
|
Homebrew/homebrew-#{tapped_deprecated_taps.join("\n Homebrew/homebrew-")}
|
2019-02-16 20:07:10 +00:00
|
|
|
Untap them with `brew untap`.
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2023-03-10 23:46:07 +00:00
|
|
|
def __check_linked_brew(formula)
|
|
|
|
formula.installed_prefixes.each do |prefix|
|
2016-01-04 23:14:58 +01:00
|
|
|
prefix.find do |src|
|
|
|
|
next if src == prefix
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-01-04 23:14:58 +01:00
|
|
|
dst = HOMEBREW_PREFIX + src.relative_path_from(prefix)
|
|
|
|
return true if dst.symlink? && src == dst.resolved_path
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_other_frameworks
|
|
|
|
# Other frameworks that are known to cause problems when present
|
2016-04-06 05:08:53 +02:00
|
|
|
frameworks_to_check = %w[
|
|
|
|
expat.framework
|
|
|
|
libexpat.framework
|
|
|
|
libcurl.framework
|
|
|
|
]
|
2016-09-17 15:17:27 +01:00
|
|
|
frameworks_found = frameworks_to_check
|
|
|
|
.map { |framework| "/Library/Frameworks/#{framework}" }
|
|
|
|
.select { |framework| File.exist? framework }
|
2016-04-06 05:08:53 +02:00
|
|
|
return if frameworks_found.empty?
|
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
inject_file_list frameworks_found, <<~EOS
|
2019-04-08 12:47:15 -04:00
|
|
|
Some frameworks can be picked up by CMake's build system and will likely
|
2016-04-06 05:08:53 +02:00
|
|
|
cause the build to fail. To compile CMake, you may wish to move these
|
|
|
|
out of the way:
|
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_tmpdir
|
2022-05-30 04:37:09 +01:00
|
|
|
tmpdir = ENV.fetch("TMPDIR", nil)
|
2016-04-06 05:08:53 +02:00
|
|
|
return if tmpdir.nil? || File.directory?(tmpdir)
|
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2016-04-06 05:08:53 +02:00
|
|
|
TMPDIR #{tmpdir.inspect} doesn't exist.
|
|
|
|
EOS
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_missing_deps
|
|
|
|
return unless HOMEBREW_CELLAR.exist?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-01-04 23:14:58 +01:00
|
|
|
missing = Set.new
|
|
|
|
Homebrew::Diagnostic.missing_deps(Formula.installed).each_value do |deps|
|
|
|
|
missing.merge(deps)
|
|
|
|
end
|
2016-04-06 05:08:53 +02:00
|
|
|
return if missing.empty?
|
2016-01-04 23:14:58 +01:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2018-02-07 09:50:01 +01:00
|
|
|
Some installed formulae are missing dependencies.
|
2016-01-04 23:14:58 +01:00
|
|
|
You should `brew install` the missing dependencies:
|
2016-04-06 05:08:53 +02:00
|
|
|
brew install #{missing.sort_by(&:full_name) * " "}
|
2016-01-04 23:14:58 +01:00
|
|
|
|
|
|
|
Run `brew missing` for more details.
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2020-04-01 13:43:15 +01:00
|
|
|
def check_deprecated_disabled
|
|
|
|
return unless HOMEBREW_CELLAR.exist?
|
|
|
|
|
|
|
|
deprecated_or_disabled = Formula.installed.select(&:deprecated?)
|
|
|
|
deprecated_or_disabled += Formula.installed.select(&:disabled?)
|
|
|
|
return if deprecated_or_disabled.empty?
|
|
|
|
|
|
|
|
<<~EOS
|
|
|
|
Some installed formulae are deprecated or disabled.
|
|
|
|
You should find replacements for the following formulae:
|
|
|
|
#{deprecated_or_disabled.sort_by(&:full_name).uniq * "\n "}
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2023-12-04 00:30:49 -05:00
|
|
|
def check_cask_deprecated_disabled
|
|
|
|
deprecated_or_disabled = Cask::Caskroom.casks.select(&:deprecated?)
|
|
|
|
deprecated_or_disabled += Cask::Caskroom.casks.select(&:disabled?)
|
|
|
|
return if deprecated_or_disabled.empty?
|
|
|
|
|
|
|
|
<<~EOS
|
|
|
|
Some installed casks are deprecated or disabled.
|
|
|
|
You should find replacements for the following casks:
|
|
|
|
#{deprecated_or_disabled.sort_by(&:token).uniq * "\n "}
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2023-03-07 17:24:20 -08:00
|
|
|
sig { returns(T.nilable(String)) }
|
2016-01-04 23:14:58 +01:00
|
|
|
def check_git_status
|
2020-08-23 06:32:26 +02:00
|
|
|
return unless Utils::Git.available?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2023-03-07 17:24:20 -08:00
|
|
|
message = T.let(nil, T.nilable(String))
|
2020-03-11 17:25:07 +00:00
|
|
|
|
2021-05-30 16:26:58 +09:00
|
|
|
repos = {
|
2020-03-11 17:25:07 +00:00
|
|
|
"Homebrew/brew" => HOMEBREW_REPOSITORY,
|
|
|
|
"Homebrew/homebrew-core" => CoreTap.instance.path,
|
2021-05-24 23:30:46 +09:00
|
|
|
}
|
|
|
|
|
2023-02-21 12:39:07 +01:00
|
|
|
OFFICIAL_CASK_TAPS.each do |tap|
|
2021-05-27 21:43:08 +09:00
|
|
|
cask_tap = Tap.fetch "homebrew", tap
|
2021-05-30 16:26:58 +09:00
|
|
|
repos[cask_tap.full_name] = cask_tap.path if cask_tap.installed?
|
2021-05-24 23:30:46 +09:00
|
|
|
end
|
|
|
|
|
2021-05-30 16:26:58 +09:00
|
|
|
repos.each do |name, path|
|
2021-10-27 01:41:57 -04:00
|
|
|
next unless path.exist?
|
|
|
|
|
2020-03-11 17:25:07 +00:00
|
|
|
status = path.cd do
|
|
|
|
`git status --untracked-files=all --porcelain 2>/dev/null`
|
|
|
|
end
|
|
|
|
next if status.blank?
|
|
|
|
|
|
|
|
message ||= ""
|
|
|
|
message += "\n" unless message.empty?
|
|
|
|
message += <<~EOS
|
|
|
|
You have uncommitted modifications to #{name}.
|
|
|
|
If this is a surprise to you, then you should stash these modifications.
|
|
|
|
Stashing returns Homebrew to a pristine state but can be undone
|
|
|
|
should you later need to do so for some reason.
|
2022-12-04 11:59:15 +02:00
|
|
|
cd #{path} && git stash -u && git clean -d -f
|
2020-03-11 17:25:07 +00:00
|
|
|
EOS
|
2019-10-18 09:22:34 +01:00
|
|
|
|
|
|
|
modified = status.split("\n")
|
2019-10-11 11:47:33 -04:00
|
|
|
message += inject_file_list modified, <<~EOS
|
|
|
|
|
2020-03-11 17:25:07 +00:00
|
|
|
Uncommitted files:
|
2019-10-11 11:47:33 -04:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
|
|
|
message
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_non_prefixed_coreutils
|
2016-01-27 00:54:46 +01:00
|
|
|
coreutils = Formula["coreutils"]
|
|
|
|
return unless coreutils.any_version_installed?
|
|
|
|
|
|
|
|
gnubin = %W[#{coreutils.opt_libexec}/gnubin #{coreutils.libexec}/gnubin]
|
2024-01-18 14:11:43 +00:00
|
|
|
return unless paths.intersect?(gnubin)
|
2016-01-27 00:54:46 +01:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2020-07-29 17:31:11 -04:00
|
|
|
Putting non-prefixed coreutils in your path can cause GMP builds to fail.
|
2016-01-27 00:54:46 +01:00
|
|
|
EOS
|
2016-04-25 17:58:50 +01:00
|
|
|
rescue FormulaUnavailableError
|
2018-03-06 09:36:49 +00:00
|
|
|
nil
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_pydistutils_cfg_in_home
|
2022-05-30 04:48:54 +01:00
|
|
|
return unless File.exist? "#{Dir.home}/.pydistutils.cfg"
|
2016-04-06 05:08:53 +02:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2021-01-26 15:21:24 -05:00
|
|
|
A '.pydistutils.cfg' file was found in $HOME, which may cause Python
|
2016-04-06 05:08:53 +02:00
|
|
|
builds to fail. See:
|
2016-09-17 03:21:51 +02:00
|
|
|
#{Formatter.url("https://bugs.python.org/issue6138")}
|
|
|
|
#{Formatter.url("https://bugs.python.org/issue4655")}
|
2016-01-04 23:14:58 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2019-04-02 14:38:59 +01:00
|
|
|
def check_for_unreadable_installed_formula
|
|
|
|
formula_unavailable_exceptions = []
|
|
|
|
Formula.racks.each do |rack|
|
2019-10-13 10:03:26 +01:00
|
|
|
Formulary.from_rack(rack)
|
|
|
|
rescue FormulaUnreadableError, FormulaClassUnavailableError,
|
|
|
|
TapFormulaUnreadableError, TapFormulaClassUnavailableError => e
|
|
|
|
formula_unavailable_exceptions << e
|
2024-02-16 21:27:02 +01:00
|
|
|
rescue FormulaUnavailableError, TapFormulaAmbiguityError
|
2019-10-13 10:03:26 +01:00
|
|
|
nil
|
2019-04-02 14:38:59 +01:00
|
|
|
end
|
|
|
|
return if formula_unavailable_exceptions.empty?
|
|
|
|
|
|
|
|
<<~EOS
|
|
|
|
Some installed formulae are not readable:
|
|
|
|
#{formula_unavailable_exceptions.join("\n\n ")}
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2016-01-04 23:14:58 +01:00
|
|
|
def check_for_unlinked_but_not_keg_only
|
|
|
|
unlinked = Formula.racks.reject do |rack|
|
2020-11-09 20:09:16 +11:00
|
|
|
if (HOMEBREW_LINKED_KEGS/rack.basename).directory?
|
|
|
|
true
|
|
|
|
else
|
2016-01-04 23:14:58 +01:00
|
|
|
begin
|
|
|
|
Formulary.from_rack(rack).keg_only?
|
2024-02-16 21:27:02 +01:00
|
|
|
rescue FormulaUnavailableError, TapFormulaAmbiguityError
|
2016-01-04 23:14:58 +01:00
|
|
|
false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end.map(&:basename)
|
|
|
|
return if unlinked.empty?
|
2016-04-06 05:08:53 +02:00
|
|
|
|
2017-10-15 02:28:32 +02:00
|
|
|
inject_file_list unlinked, <<~EOS
|
2019-04-08 12:47:15 -04:00
|
|
|
You have unlinked kegs in your Cellar.
|
2021-01-26 15:21:24 -05:00
|
|
|
Leaving kegs unlinked can lead to build-trouble and cause formulae that depend on
|
2016-04-06 05:08:53 +02:00
|
|
|
those kegs to fail to run properly once built. Run `brew link` on these:
|
2016-01-04 23:14:58 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_external_cmd_name_conflict
|
2017-11-17 17:41:58 +00:00
|
|
|
cmds = Tap.cmd_directories.flat_map { |p| Dir["#{p}/brew-*"] }.uniq
|
2016-01-04 23:14:58 +01:00
|
|
|
cmds = cmds.select { |cmd| File.file?(cmd) && File.executable?(cmd) }
|
|
|
|
cmd_map = {}
|
|
|
|
cmds.each do |cmd|
|
|
|
|
cmd_name = File.basename(cmd, ".rb")
|
|
|
|
cmd_map[cmd_name] ||= []
|
|
|
|
cmd_map[cmd_name] << cmd
|
|
|
|
end
|
|
|
|
cmd_map.reject! { |_cmd_name, cmd_paths| cmd_paths.size == 1 }
|
|
|
|
return if cmd_map.empty?
|
2016-04-06 05:08:53 +02:00
|
|
|
|
2022-05-30 04:37:09 +01:00
|
|
|
if ENV["CI"].present? && cmd_map.keys.length == 1 &&
|
2017-06-17 14:01:42 +01:00
|
|
|
cmd_map.keys.first == "brew-test-bot"
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2016-04-06 05:08:53 +02:00
|
|
|
message = "You have external commands with conflicting names.\n"
|
2016-01-04 23:14:58 +01:00
|
|
|
cmd_map.each do |cmd_name, cmd_paths|
|
2017-10-15 02:28:32 +02:00
|
|
|
message += inject_file_list cmd_paths, <<~EOS
|
2019-04-08 12:47:15 -04:00
|
|
|
Found command `#{cmd_name}` in the following places:
|
2016-01-04 23:14:58 +01:00
|
|
|
EOS
|
|
|
|
end
|
2016-04-06 05:08:53 +02:00
|
|
|
|
|
|
|
message
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
|
2016-12-13 01:53:05 +00:00
|
|
|
def check_for_tap_ruby_files_locations
|
|
|
|
bad_tap_files = {}
|
2024-03-06 20:58:34 -08:00
|
|
|
Tap.installed.each do |tap|
|
2016-12-13 01:53:05 +00:00
|
|
|
unused_formula_dirs = tap.potential_formula_dirs - [tap.formula_dir]
|
|
|
|
unused_formula_dirs.each do |dir|
|
|
|
|
next unless dir.exist?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-12-13 01:53:05 +00:00
|
|
|
dir.children.each do |path|
|
2023-04-18 15:06:50 -07:00
|
|
|
next if path.extname != ".rb"
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-12-13 01:53:05 +00:00
|
|
|
bad_tap_files[tap] ||= []
|
|
|
|
bad_tap_files[tap] << path
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return if bad_tap_files.empty?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-12-13 01:53:05 +00:00
|
|
|
bad_tap_files.keys.map do |tap|
|
2017-10-15 02:28:32 +02:00
|
|
|
<<~EOS
|
2019-04-08 12:47:15 -04:00
|
|
|
Found Ruby file outside #{tap} tap formula directory.
|
2016-12-13 01:53:05 +00:00
|
|
|
(#{tap.formula_dir}):
|
|
|
|
#{bad_tap_files[tap].join("\n ")}
|
|
|
|
EOS
|
|
|
|
end.join("\n")
|
|
|
|
end
|
|
|
|
|
2019-01-01 18:11:59 -08:00
|
|
|
def check_homebrew_prefix
|
2019-01-21 12:37:42 +00:00
|
|
|
return if Homebrew.default_prefix?
|
2019-01-01 18:11:59 -08:00
|
|
|
|
|
|
|
<<~EOS
|
|
|
|
Your Homebrew's prefix is not #{Homebrew::DEFAULT_PREFIX}.
|
2022-10-06 10:01:02 +01:00
|
|
|
|
|
|
|
Many of Homebrew's bottles (binary packages) can only be used with the default prefix.
|
|
|
|
Consider uninstalling Homebrew and reinstalling into the default prefix.
|
2019-01-21 12:39:44 +00:00
|
|
|
#{please_create_pull_requests}
|
2019-01-01 18:11:59 -08:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2020-05-17 17:23:23 +09:00
|
|
|
def check_deleted_formula
|
2021-10-27 01:41:57 -04:00
|
|
|
kegs = Keg.all
|
2021-06-15 22:07:36 +09:00
|
|
|
|
2024-02-22 23:29:55 +00:00
|
|
|
deleted_formulae = kegs.filter_map do |keg|
|
2024-02-16 21:27:02 +01:00
|
|
|
tap = Tab.for_keg(keg).tap
|
2024-03-12 10:41:06 -04:00
|
|
|
tap_keg_name = tap ? "#{tap}/#{keg.name}" : keg.name
|
2024-02-16 21:27:02 +01:00
|
|
|
|
|
|
|
loadable = [
|
|
|
|
Formulary::FromAPILoader,
|
2024-03-11 19:43:22 -04:00
|
|
|
Formulary::FromTapLoader,
|
2024-02-16 21:27:02 +01:00
|
|
|
Formulary::FromNameLoader,
|
|
|
|
].any? do |loader_class|
|
|
|
|
loader = begin
|
2024-03-12 10:41:06 -04:00
|
|
|
loader_class.try_new(tap_keg_name, warn: false)
|
2024-02-16 21:27:02 +01:00
|
|
|
rescue TapFormulaAmbiguityError => e
|
|
|
|
e.loaders.first
|
|
|
|
end
|
|
|
|
|
2024-03-11 19:43:22 -04:00
|
|
|
loader.instance_of?(Formulary::FromTapLoader) ? loader.path.exist? : loader.present?
|
2024-02-08 21:13:49 +01:00
|
|
|
end
|
2021-10-27 01:41:57 -04:00
|
|
|
|
2024-02-16 21:27:02 +01:00
|
|
|
keg.name unless loadable
|
2024-02-22 23:29:55 +00:00
|
|
|
end.uniq
|
2021-06-15 22:07:36 +09:00
|
|
|
|
2020-05-17 17:23:23 +09:00
|
|
|
return if deleted_formulae.blank?
|
|
|
|
|
2020-07-07 11:29:33 +01:00
|
|
|
<<~EOS
|
2020-11-04 10:19:52 +00:00
|
|
|
Some installed kegs have no formulae!
|
2022-05-02 21:14:34 +02:00
|
|
|
This means they were either deleted or installed manually.
|
2020-05-17 17:23:23 +09:00
|
|
|
You should find replacements for the following formulae:
|
2020-05-18 20:41:55 +09:00
|
|
|
#{deleted_formulae.join("\n ")}
|
2020-05-17 17:23:23 +09:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2023-04-30 15:03:51 +01:00
|
|
|
def check_for_unnecessary_core_tap
|
2023-04-30 19:06:07 +01:00
|
|
|
return if Homebrew::EnvConfig.developer?
|
|
|
|
return if Homebrew::EnvConfig.no_install_from_api?
|
|
|
|
return if Homebrew::Settings.read("devcmdrun") == "true"
|
2023-04-30 15:03:51 +01:00
|
|
|
return unless CoreTap.instance.installed?
|
|
|
|
|
|
|
|
<<~EOS
|
|
|
|
You have an unnecessary local Core tap!
|
|
|
|
This can cause problems installing up-to-date formulae.
|
|
|
|
Please remove it by running:
|
|
|
|
brew untap #{CoreTap.instance.name}
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_for_unnecessary_cask_tap
|
2023-04-30 19:06:07 +01:00
|
|
|
return if Homebrew::EnvConfig.developer?
|
|
|
|
return if Homebrew::EnvConfig.no_install_from_api?
|
|
|
|
return if Homebrew::Settings.read("devcmdrun") == "true"
|
2023-04-30 19:09:41 +01:00
|
|
|
|
2023-07-13 19:28:39 +01:00
|
|
|
cask_tap = CoreCaskTap.instance
|
2023-04-30 19:06:07 +01:00
|
|
|
return unless cask_tap.installed?
|
2023-04-30 15:03:51 +01:00
|
|
|
|
|
|
|
<<~EOS
|
|
|
|
You have an unnecessary local Cask tap.
|
|
|
|
This can cause problems installing up-to-date casks.
|
|
|
|
Please remove it by running:
|
|
|
|
brew untap #{cask_tap.name}
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
2020-07-10 10:36:59 -04:00
|
|
|
def check_cask_software_versions
|
|
|
|
add_info "Homebrew Version", HOMEBREW_VERSION
|
|
|
|
add_info "macOS", MacOS.full_version
|
|
|
|
add_info "SIP", begin
|
|
|
|
csrutil = "/usr/bin/csrutil"
|
|
|
|
if File.executable?(csrutil)
|
|
|
|
Open3.capture2(csrutil, "status")
|
|
|
|
.first
|
|
|
|
.gsub("This is an unsupported configuration, likely to break in " \
|
2020-07-11 11:26:11 -04:00
|
|
|
"the future and leave your machine in an unknown state.", "")
|
2020-07-10 10:36:59 -04:00
|
|
|
.gsub("System Integrity Protection status: ", "")
|
2022-12-13 10:54:22 +00:00
|
|
|
.delete("\t.")
|
2020-07-10 10:36:59 -04:00
|
|
|
.capitalize
|
|
|
|
.strip
|
|
|
|
else
|
|
|
|
"N/A"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_cask_install_location
|
|
|
|
locations = Dir.glob(HOMEBREW_CELLAR.join("brew-cask", "*")).reverse
|
|
|
|
return if locations.empty?
|
|
|
|
|
|
|
|
locations.map do |l|
|
|
|
|
"Legacy install at #{l}. Run `brew uninstall --force brew-cask`."
|
|
|
|
end.join "\n"
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_cask_staging_location
|
2020-07-11 11:26:11 -04:00
|
|
|
# Skip this check when running CI since the staging path is not writable for security reasons
|
2020-08-07 09:14:07 +01:00
|
|
|
return if ENV["GITHUB_ACTIONS"]
|
2020-07-11 11:26:11 -04:00
|
|
|
|
2020-07-10 10:36:59 -04:00
|
|
|
path = Cask::Caskroom.path
|
|
|
|
|
|
|
|
add_info "Homebrew Cask Staging Location", user_tilde(path.to_s)
|
|
|
|
|
2021-01-07 13:49:05 -08:00
|
|
|
return if !path.exist? || path.writable?
|
2020-07-10 10:36:59 -04:00
|
|
|
|
|
|
|
<<~EOS
|
|
|
|
The staging path #{user_tilde(path.to_s)} is not writable by the current user.
|
2021-01-24 21:25:12 -05:00
|
|
|
To fix, run:
|
2023-09-29 12:32:22 +01:00
|
|
|
sudo chown -R #{current_user} #{user_tilde(path.to_s)}
|
2020-07-10 10:36:59 -04:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_cask_taps
|
|
|
|
error_tap_paths = []
|
|
|
|
|
2024-02-20 20:13:03 +01:00
|
|
|
taps = (Tap.to_a + [CoreCaskTap.instance]).uniq
|
|
|
|
|
|
|
|
add_info "Homebrew Cask Taps:", (taps.map do |tap|
|
2024-02-20 17:59:32 +01:00
|
|
|
cask_count = begin
|
|
|
|
tap.cask_files.count
|
|
|
|
rescue
|
|
|
|
error_tap_paths << tap.path
|
|
|
|
0
|
2020-07-10 10:36:59 -04:00
|
|
|
end
|
2024-02-20 17:59:32 +01:00
|
|
|
|
|
|
|
"#{tap.path} (#{Utils.pluralize("cask", cask_count, include_count: true)})"
|
2020-07-10 10:36:59 -04:00
|
|
|
end)
|
|
|
|
|
2023-07-18 10:31:51 +01:00
|
|
|
taps_string = Utils.pluralize("tap", error_tap_paths.count)
|
|
|
|
"Unable to read from cask #{taps_string}: #{error_tap_paths.to_sentence}" if error_tap_paths.present?
|
2020-07-10 10:36:59 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_cask_load_path
|
|
|
|
paths = $LOAD_PATH.map(&method(:user_tilde))
|
|
|
|
|
|
|
|
add_info "$LOAD_PATHS", paths.presence || none_string
|
|
|
|
|
|
|
|
"$LOAD_PATH is empty" if paths.blank?
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_cask_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
|
|
|
|
|
|
|
|
add_info "Cask Environment Variables:", ((locale_variables + environment_variables).sort.each do |var|
|
|
|
|
next unless ENV.key?(var)
|
|
|
|
|
2022-05-30 04:37:09 +01:00
|
|
|
var = %Q(#{var}="#{ENV.fetch(var)}")
|
2020-07-10 10:36:59 -04:00
|
|
|
user_tilde(var)
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_cask_xattr
|
2021-07-19 10:02:19 +08:00
|
|
|
result = system_command "/usr/bin/xattr", args: ["-h"]
|
2020-07-10 10:36:59 -04:00
|
|
|
|
|
|
|
return if result.status.success?
|
|
|
|
|
|
|
|
if result.stderr.include? "ImportError: No module named pkg_resources"
|
2020-09-21 01:15:31 +10:00
|
|
|
result = Utils.popen_read "/usr/bin/python", "--version", err: :out
|
2020-07-10 10:36:59 -04:00
|
|
|
|
2020-09-21 01:15:31 +10:00
|
|
|
if result.include? "Python 2.7"
|
2020-07-10 10:36:59 -04:00
|
|
|
<<~EOS
|
|
|
|
Your Python installation has a broken version of setuptools.
|
2021-01-24 21:25:12 -05:00
|
|
|
To fix, reinstall macOS or run:
|
|
|
|
sudo /usr/bin/python -m pip install -I setuptools
|
2020-07-10 10:36:59 -04:00
|
|
|
EOS
|
|
|
|
else
|
|
|
|
<<~EOS
|
|
|
|
The system Python version is wrong.
|
2021-01-24 21:25:12 -05:00
|
|
|
To fix, run:
|
|
|
|
defaults write com.apple.versioner.python Version 2.7
|
2020-07-10 10:36:59 -04:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
elsif result.stderr.include? "pkg_resources.DistributionNotFound"
|
2021-01-24 21:40:41 -05:00
|
|
|
"Your Python installation is unable to find `xattr`."
|
2020-07-10 10:36:59 -04:00
|
|
|
else
|
|
|
|
"unknown xattr error: #{result.stderr.split("\n").last}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def check_cask_quarantine_support
|
|
|
|
case Cask::Quarantine.check_quarantine_support
|
|
|
|
when :quarantine_available
|
|
|
|
nil
|
|
|
|
when :xattr_broken
|
2022-09-14 12:32:26 +01:00
|
|
|
"No Cask quarantine support available: there's no working version of `xattr` on this system."
|
2020-07-10 10:36:59 -04:00
|
|
|
when :no_swift
|
2022-09-14 12:32:26 +01:00
|
|
|
"No Cask quarantine support available: there's no available version of `swift` on this system."
|
2020-07-10 10:36:59 -04:00
|
|
|
else
|
2022-09-14 12:32:26 +01:00
|
|
|
"No Cask quarantine support available: unknown reason."
|
2020-07-10 10:36:59 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-01-04 23:14:58 +01:00
|
|
|
def all
|
2021-06-22 20:57:09 +09:00
|
|
|
methods.map(&:to_s).grep(/^check_/).sort
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
2020-07-10 10:36:59 -04:00
|
|
|
|
|
|
|
def cask_checks
|
|
|
|
all.grep(/^check_cask_/)
|
|
|
|
end
|
2023-09-29 12:32:22 +01:00
|
|
|
|
|
|
|
def current_user
|
|
|
|
ENV.fetch("USER", "$(whoami)")
|
|
|
|
end
|
2017-10-21 19:52:43 +02:00
|
|
|
end
|
2016-01-04 23:14:58 +01:00
|
|
|
end
|
|
|
|
end
|
2016-04-25 17:58:50 +01:00
|
|
|
|
|
|
|
require "extend/os/diagnostic"
|