mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Cross-platform diagnostics.
This commit is contained in:
parent
4ebccf79a8
commit
e5435dfeb7
@ -480,60 +480,6 @@ module Homebrew
|
|||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_for_gettext
|
|
||||||
find_relative_paths("lib/libgettextlib.dylib",
|
|
||||||
"lib/libintl.dylib",
|
|
||||||
"include/libintl.h")
|
|
||||||
return if @found.empty?
|
|
||||||
|
|
||||||
# Our gettext formula will be caught by check_linked_keg_only_brews
|
|
||||||
gettext = begin
|
|
||||||
Formulary.factory("gettext")
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
homebrew_owned = @found.all? do |path|
|
|
||||||
Pathname.new(path).realpath.to_s.start_with? "#{HOMEBREW_CELLAR}/gettext"
|
|
||||||
end
|
|
||||||
return if gettext&.linked_keg&.directory? && homebrew_owned
|
|
||||||
|
|
||||||
inject_file_list @found, <<~EOS
|
|
||||||
gettext files detected at a system prefix.
|
|
||||||
These files can cause compilation and link failures, especially if they
|
|
||||||
are compiled with improper architectures. Consider removing these files:
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_for_iconv
|
|
||||||
find_relative_paths("lib/libiconv.dylib", "include/iconv.h")
|
|
||||||
return if @found.empty?
|
|
||||||
|
|
||||||
libiconv = begin
|
|
||||||
Formulary.factory("libiconv")
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
if libiconv&.linked_keg&.directory?
|
|
||||||
unless libiconv.keg_only?
|
|
||||||
<<~EOS
|
|
||||||
A libiconv formula is installed and linked.
|
|
||||||
This will break stuff. For serious. Unlink it.
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
else
|
|
||||||
inject_file_list @found, <<~EOS
|
|
||||||
libiconv files detected at a system prefix other than /usr.
|
|
||||||
Homebrew doesn't provide a libiconv formula, and expects to link against
|
|
||||||
the system version in /usr. libiconv in other prefixes can cause
|
|
||||||
compile or link failure, especially if compiled with improper
|
|
||||||
architectures. macOS itself never installs anything to /usr/local so
|
|
||||||
it was either installed by a user or some other third party software.
|
|
||||||
|
|
||||||
tl;dr: delete these files:
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_for_config_scripts
|
def check_for_config_scripts
|
||||||
return unless HOMEBREW_CELLAR.exist?
|
return unless HOMEBREW_CELLAR.exist?
|
||||||
real_cellar = HOMEBREW_CELLAR.realpath
|
real_cellar = HOMEBREW_CELLAR.realpath
|
||||||
@ -571,17 +517,17 @@ module Homebrew
|
|||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_dyld_vars
|
def check_ld_vars
|
||||||
dyld_vars = ENV.keys.grep(/^DYLD_/)
|
ld_vars = ENV.keys.grep(/^(|DY)LD_/)
|
||||||
return if dyld_vars.empty?
|
return if ld_vars.empty?
|
||||||
|
|
||||||
values = dyld_vars.map { |var| "#{var}: #{ENV.fetch(var)}" }
|
values = ld_vars.map { |var| "#{var}: #{ENV.fetch(var)}" }
|
||||||
message = inject_file_list values, <<~EOS
|
message = inject_file_list values, <<~EOS
|
||||||
Setting DYLD_* vars can break dynamic linking.
|
Setting DYLD_* or LD_* variables can break dynamic linking.
|
||||||
Set variables:
|
Set variables:
|
||||||
EOS
|
EOS
|
||||||
|
|
||||||
if dyld_vars.include? "DYLD_INSERT_LIBRARIES"
|
if ld_vars.include? "DYLD_INSERT_LIBRARIES"
|
||||||
message += <<~EOS
|
message += <<~EOS
|
||||||
|
|
||||||
Setting DYLD_INSERT_LIBRARIES can cause Go builds to fail.
|
Setting DYLD_INSERT_LIBRARIES can cause Go builds to fail.
|
||||||
@ -612,38 +558,6 @@ module Homebrew
|
|||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_for_multiple_volumes
|
|
||||||
return unless HOMEBREW_CELLAR.exist?
|
|
||||||
volumes = Volumes.new
|
|
||||||
|
|
||||||
# Find the volumes for the TMP folder & HOMEBREW_CELLAR
|
|
||||||
real_cellar = HOMEBREW_CELLAR.realpath
|
|
||||||
where_cellar = volumes.which real_cellar
|
|
||||||
|
|
||||||
begin
|
|
||||||
tmp = Pathname.new(Dir.mktmpdir("doctor", HOMEBREW_TEMP))
|
|
||||||
begin
|
|
||||||
real_tmp = tmp.realpath.parent
|
|
||||||
where_tmp = volumes.which real_tmp
|
|
||||||
ensure
|
|
||||||
Dir.delete tmp
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
return if where_cellar == where_tmp
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Your Cellar and TEMP directories are on different volumes.
|
|
||||||
macOS won't move relative symlinks across volumes unless the target file already
|
|
||||||
exists. Brews known to be affected by this are Git and Narwhal.
|
|
||||||
|
|
||||||
You should set the "HOMEBREW_TEMP" environmental variable to a suitable
|
|
||||||
directory on the same volume as your Cellar.
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_git_version
|
def check_git_version
|
||||||
# https://help.github.com/articles/https-cloning-errors
|
# https://help.github.com/articles/https-cloning-errors
|
||||||
return unless Utils.git_available?
|
return unless Utils.git_available?
|
||||||
@ -859,21 +773,6 @@ module Homebrew
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_for_non_prefixed_findutils
|
|
||||||
findutils = Formula["findutils"]
|
|
||||||
return unless findutils.any_version_installed?
|
|
||||||
|
|
||||||
gnubin = %W[#{findutils.opt_libexec}/gnubin #{findutils.libexec}/gnubin]
|
|
||||||
default_names = Tab.for_name("findutils").with? "default-names"
|
|
||||||
return if !default_names && (paths & gnubin).empty?
|
|
||||||
|
|
||||||
<<~EOS
|
|
||||||
Putting non-prefixed findutils in your path can cause python builds to fail.
|
|
||||||
EOS
|
|
||||||
rescue FormulaUnavailableError
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_for_pydistutils_cfg_in_home
|
def check_for_pydistutils_cfg_in_home
|
||||||
return unless File.exist? "#{ENV["HOME"]}/.pydistutils.cfg"
|
return unless File.exist? "#{ENV["HOME"]}/.pydistutils.cfg"
|
||||||
|
|
||||||
|
@ -1 +1,5 @@
|
|||||||
require "extend/os/mac/diagnostic" if OS.mac?
|
if OS.mac?
|
||||||
|
require "extend/os/mac/diagnostic"
|
||||||
|
elsif OS.linux?
|
||||||
|
require "extend/os/linux/diagnostic"
|
||||||
|
end
|
||||||
|
33
Library/Homebrew/extend/os/linux/diagnostic.rb
Normal file
33
Library/Homebrew/extend/os/linux/diagnostic.rb
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
require "tempfile"
|
||||||
|
require "utils/shell"
|
||||||
|
require "os/linux/diagnostic"
|
||||||
|
|
||||||
|
module Homebrew
|
||||||
|
module Diagnostic
|
||||||
|
class Checks
|
||||||
|
def check_tmpdir_sticky_bit
|
||||||
|
message = generic_check_tmpdir_sticky_bit
|
||||||
|
return if message.nil?
|
||||||
|
message + <<~EOS
|
||||||
|
If you don't have administrative privileges on this machine,
|
||||||
|
create a directory and set the HOMEBREW_TEMP environment variable,
|
||||||
|
for example:
|
||||||
|
install -d -m 1755 ~/tmp
|
||||||
|
#{Utils::Shell.set_variable_in_profile("HOMEBREW_TEMP", "~/tmp")}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_xdg_data_dirs
|
||||||
|
return if ENV["XDG_DATA_DIRS"].to_s.empty?
|
||||||
|
return if ENV["XDG_DATA_DIRS"].split("/").include?(HOMEBREW_PREFIX/"share")
|
||||||
|
<<~EOS
|
||||||
|
Homebrew's share was not found in your XDG_DATA_DIRS but you have
|
||||||
|
this variable set to include other locations.
|
||||||
|
Some programs like `vapigen` may not work correctly.
|
||||||
|
Consider adding Homebrew's share directory to XDG_DATA_DIRS like so:
|
||||||
|
#{Utils::Shell.prepend_variable_in_profile("XDG_DATA_DIRS", HOMEBREW_PREFIX/"share")}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -29,6 +29,21 @@ module Homebrew
|
|||||||
]).freeze
|
]).freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_for_non_prefixed_findutils
|
||||||
|
findutils = Formula["findutils"]
|
||||||
|
return unless findutils.any_version_installed?
|
||||||
|
|
||||||
|
gnubin = %W[#{findutils.opt_libexec}/gnubin #{findutils.libexec}/gnubin]
|
||||||
|
default_names = Tab.for_name("findutils").with? "default-names"
|
||||||
|
return if !default_names && (paths & gnubin).empty?
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Putting non-prefixed findutils in your path can cause python builds to fail.
|
||||||
|
EOS
|
||||||
|
rescue FormulaUnavailableError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
def check_for_unsupported_macos
|
def check_for_unsupported_macos
|
||||||
return if ARGV.homebrew_developer?
|
return if ARGV.homebrew_developer?
|
||||||
|
|
||||||
@ -275,6 +290,95 @@ module Homebrew
|
|||||||
may not build correctly with a non-/usr/local prefix.
|
may not build correctly with a non-/usr/local prefix.
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_for_gettext
|
||||||
|
find_relative_paths("lib/libgettextlib.dylib",
|
||||||
|
"lib/libintl.dylib",
|
||||||
|
"include/libintl.h")
|
||||||
|
return if @found.empty?
|
||||||
|
|
||||||
|
# Our gettext formula will be caught by check_linked_keg_only_brews
|
||||||
|
gettext = begin
|
||||||
|
Formulary.factory("gettext")
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if gettext&.linked_keg&.directory?
|
||||||
|
homebrew_owned = @found.all? do |path|
|
||||||
|
Pathname.new(path).realpath.to_s.start_with? "#{HOMEBREW_CELLAR}/gettext"
|
||||||
|
end
|
||||||
|
return if homebrew_owned
|
||||||
|
end
|
||||||
|
|
||||||
|
inject_file_list @found, <<~EOS
|
||||||
|
gettext files detected at a system prefix.
|
||||||
|
These files can cause compilation and link failures, especially if they
|
||||||
|
are compiled with improper architectures. Consider removing these files:
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_for_iconv
|
||||||
|
find_relative_paths("lib/libiconv.dylib", "include/iconv.h")
|
||||||
|
return if @found.empty?
|
||||||
|
|
||||||
|
libiconv = begin
|
||||||
|
Formulary.factory("libiconv")
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
if libiconv&.linked_keg&.directory?
|
||||||
|
unless libiconv.keg_only?
|
||||||
|
<<~EOS
|
||||||
|
A libiconv formula is installed and linked.
|
||||||
|
This will break stuff. For serious. Unlink it.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
else
|
||||||
|
inject_file_list @found, <<~EOS
|
||||||
|
libiconv files detected at a system prefix other than /usr.
|
||||||
|
Homebrew doesn't provide a libiconv formula, and expects to link against
|
||||||
|
the system version in /usr. libiconv in other prefixes can cause
|
||||||
|
compile or link failure, especially if compiled with improper
|
||||||
|
architectures. macOS itself never installs anything to /usr/local so
|
||||||
|
it was either installed by a user or some other third party software.
|
||||||
|
|
||||||
|
tl;dr: delete these files:
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_for_multiple_volumes
|
||||||
|
return unless HOMEBREW_CELLAR.exist?
|
||||||
|
volumes = Volumes.new
|
||||||
|
|
||||||
|
# Find the volumes for the TMP folder & HOMEBREW_CELLAR
|
||||||
|
real_cellar = HOMEBREW_CELLAR.realpath
|
||||||
|
where_cellar = volumes.which real_cellar
|
||||||
|
|
||||||
|
begin
|
||||||
|
tmp = Pathname.new(Dir.mktmpdir("doctor", HOMEBREW_TEMP))
|
||||||
|
begin
|
||||||
|
real_tmp = tmp.realpath.parent
|
||||||
|
where_tmp = volumes.which real_tmp
|
||||||
|
ensure
|
||||||
|
Dir.delete tmp
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
return if where_cellar == where_tmp
|
||||||
|
|
||||||
|
<<~EOS
|
||||||
|
Your Cellar and TEMP directories are on different volumes.
|
||||||
|
macOS won't move relative symlinks across volumes unless the target file already
|
||||||
|
exists. Brews known to be affected by this are Git and Narwhal.
|
||||||
|
|
||||||
|
You should set the "HOMEBREW_TEMP" environmental variable to a suitable
|
||||||
|
directory on the same volume as your Cellar.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
7
Library/Homebrew/os/linux/diagnostic.rb
Normal file
7
Library/Homebrew/os/linux/diagnostic.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module Homebrew
|
||||||
|
module Diagnostic
|
||||||
|
class Checks
|
||||||
|
alias generic_check_tmpdir_sticky_bit check_tmpdir_sticky_bit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -145,11 +145,6 @@ describe Homebrew::Diagnostic::Checks do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "#check_dyld_vars" do
|
|
||||||
ENV["DYLD_INSERT_LIBRARIES"] = "foo"
|
|
||||||
expect(subject.check_dyld_vars).to match("Setting DYLD_INSERT_LIBRARIES")
|
|
||||||
end
|
|
||||||
|
|
||||||
specify "#check_for_symlinked_cellar" do
|
specify "#check_for_symlinked_cellar" do
|
||||||
begin
|
begin
|
||||||
HOMEBREW_CELLAR.rmtree
|
HOMEBREW_CELLAR.rmtree
|
||||||
@ -165,6 +160,26 @@ describe Homebrew::Diagnostic::Checks do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
specify "#check_ld_vars catches LD vars" do
|
||||||
|
ENV["LD_LIBRARY_PATH"] = "foo"
|
||||||
|
expect(subject.check_ld_vars).to match("Setting DYLD_\\* or LD_\\* variables")
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "#check_ld_vars catches DYLD vars" do
|
||||||
|
ENV["DYLD_LIBRARY_PATH"] = "foo"
|
||||||
|
expect(subject.check_ld_vars).to match("Setting DYLD_\\* or LD_\\* variables")
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "#check_ld_vars catches LD and DYLD vars" do
|
||||||
|
ENV["LD_LIBRARY_PATH"] = "foo"
|
||||||
|
ENV["DYLD_LIBRARY_PATH"] = "foo"
|
||||||
|
expect(subject.check_ld_vars).to match("Setting DYLD_\\* or LD_\\* variables")
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "#check_ld_vars returns success when neither LD nor DYLD vars are set" do
|
||||||
|
expect(subject.check_ld_vars).to be nil
|
||||||
|
end
|
||||||
|
|
||||||
specify "#check_tmpdir" do
|
specify "#check_tmpdir" do
|
||||||
ENV["TMPDIR"] = "/i/don/t/exis/t"
|
ENV["TMPDIR"] = "/i/don/t/exis/t"
|
||||||
expect(subject.check_tmpdir).to match("doesn't exist")
|
expect(subject.check_tmpdir).to match("doesn't exist")
|
||||||
|
@ -45,4 +45,9 @@ describe Homebrew::Diagnostic::Checks do
|
|||||||
expect(subject.check_ruby_version)
|
expect(subject.check_ruby_version)
|
||||||
.to match "Ruby version 1.8.6 is unsupported on 10.12"
|
.to match "Ruby version 1.8.6 is unsupported on 10.12"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
specify "#check_dyld_insert" do
|
||||||
|
ENV["DYLD_INSERT_LIBRARIES"] = "foo"
|
||||||
|
expect(subject.check_ld_vars).to match("Setting DYLD_INSERT_LIBRARIES")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -75,19 +75,20 @@ describe Utils::Shell do
|
|||||||
it "supports Tcsh" do
|
it "supports Tcsh" do
|
||||||
ENV["SHELL"] = "/bin/tcsh"
|
ENV["SHELL"] = "/bin/tcsh"
|
||||||
expect(subject.prepend_path_in_profile(path))
|
expect(subject.prepend_path_in_profile(path))
|
||||||
.to start_with("echo 'setenv PATH #{path}:$")
|
.to eq("echo 'setenv PATH #{path}:$PATH' >> #{shell_profile}")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports Bash" do
|
it "supports Bash" do
|
||||||
ENV["SHELL"] = "/bin/bash"
|
ENV["SHELL"] = "/bin/bash"
|
||||||
expect(subject.prepend_path_in_profile(path))
|
expect(subject.prepend_path_in_profile(path))
|
||||||
.to start_with("echo 'export PATH=\"#{path}:$")
|
.to eq("echo 'export PATH=\"#{path}:$PATH\"' >> #{shell_profile}")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "supports Fish" do
|
it "supports Fish" do
|
||||||
ENV["SHELL"] = "/usr/local/bin/fish"
|
ENV["SHELL"] = "/usr/local/bin/fish"
|
||||||
|
ENV["fish_user_paths"] = "/some/path"
|
||||||
expect(subject.prepend_path_in_profile(path))
|
expect(subject.prepend_path_in_profile(path))
|
||||||
.to start_with("echo 'set -g fish_user_paths \"#{path}\" $fish_user_paths' >>")
|
.to eq("echo 'set -g fish_user_paths \"#{path}\" $fish_user_paths' >> #{shell_profile}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -40,6 +40,17 @@ module Utils
|
|||||||
SHELL_PROFILE_MAP.fetch(preferred, "~/.bash_profile")
|
SHELL_PROFILE_MAP.fetch(preferred, "~/.bash_profile")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_variable_in_profile(variable, value)
|
||||||
|
case preferred
|
||||||
|
when :bash, :ksh, :sh, :zsh, nil
|
||||||
|
"echo 'export #{variable}=#{sh_quote(value)}' >> #{profile}"
|
||||||
|
when :csh, :tcsh
|
||||||
|
"echo 'setenv #{variable} #{csh_quote(value)}' >> #{profile}"
|
||||||
|
when :fish
|
||||||
|
"echo 'set -gx #{variable} #{sh_quote(value)}' >> #{profile}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def prepend_path_in_profile(path)
|
def prepend_path_in_profile(path)
|
||||||
case preferred
|
case preferred
|
||||||
when :bash, :ksh, :sh, :zsh, nil
|
when :bash, :ksh, :sh, :zsh, nil
|
||||||
|
Loading…
x
Reference in New Issue
Block a user