diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb index 736f35ff19..807c9024b6 100644 --- a/Library/Homebrew/diagnostic.rb +++ b/Library/Homebrew/diagnostic.rb @@ -480,60 +480,6 @@ module Homebrew EOS 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 return unless HOMEBREW_CELLAR.exist? real_cellar = HOMEBREW_CELLAR.realpath @@ -571,17 +517,17 @@ module Homebrew EOS end - def check_dyld_vars - dyld_vars = ENV.keys.grep(/^DYLD_/) - return if dyld_vars.empty? + def check_ld_vars + ld_vars = ENV.keys.grep(/^(|DY)LD_/) + 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 - Setting DYLD_* vars can break dynamic linking. + Setting DYLD_* or LD_* variables can break dynamic linking. Set variables: EOS - if dyld_vars.include? "DYLD_INSERT_LIBRARIES" + if ld_vars.include? "DYLD_INSERT_LIBRARIES" message += <<~EOS Setting DYLD_INSERT_LIBRARIES can cause Go builds to fail. @@ -612,38 +558,6 @@ module Homebrew EOS 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 # https://help.github.com/articles/https-cloning-errors return unless Utils.git_available? @@ -859,21 +773,6 @@ module Homebrew nil 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 return unless File.exist? "#{ENV["HOME"]}/.pydistutils.cfg" diff --git a/Library/Homebrew/extend/os/diagnostic.rb b/Library/Homebrew/extend/os/diagnostic.rb index 3e0d104fc4..34d09f9614 100644 --- a/Library/Homebrew/extend/os/diagnostic.rb +++ b/Library/Homebrew/extend/os/diagnostic.rb @@ -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 diff --git a/Library/Homebrew/extend/os/linux/diagnostic.rb b/Library/Homebrew/extend/os/linux/diagnostic.rb new file mode 100644 index 0000000000..63f8d7b479 --- /dev/null +++ b/Library/Homebrew/extend/os/linux/diagnostic.rb @@ -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 diff --git a/Library/Homebrew/extend/os/mac/diagnostic.rb b/Library/Homebrew/extend/os/mac/diagnostic.rb index 92fb3f315f..cef36ac8f9 100644 --- a/Library/Homebrew/extend/os/mac/diagnostic.rb +++ b/Library/Homebrew/extend/os/mac/diagnostic.rb @@ -29,6 +29,21 @@ module Homebrew ]).freeze 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 return if ARGV.homebrew_developer? @@ -275,6 +290,95 @@ module Homebrew may not build correctly with a non-/usr/local prefix. EOS 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 diff --git a/Library/Homebrew/os/linux/diagnostic.rb b/Library/Homebrew/os/linux/diagnostic.rb new file mode 100644 index 0000000000..66cd7fe8af --- /dev/null +++ b/Library/Homebrew/os/linux/diagnostic.rb @@ -0,0 +1,7 @@ +module Homebrew + module Diagnostic + class Checks + alias generic_check_tmpdir_sticky_bit check_tmpdir_sticky_bit + end + end +end diff --git a/Library/Homebrew/test/diagnostic_spec.rb b/Library/Homebrew/test/diagnostic_spec.rb index 52e7d3a392..0ac855ab75 100644 --- a/Library/Homebrew/test/diagnostic_spec.rb +++ b/Library/Homebrew/test/diagnostic_spec.rb @@ -145,11 +145,6 @@ describe Homebrew::Diagnostic::Checks do 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 begin HOMEBREW_CELLAR.rmtree @@ -165,6 +160,26 @@ describe Homebrew::Diagnostic::Checks do 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 ENV["TMPDIR"] = "/i/don/t/exis/t" expect(subject.check_tmpdir).to match("doesn't exist") diff --git a/Library/Homebrew/test/os/mac/diagnostic_spec.rb b/Library/Homebrew/test/os/mac/diagnostic_spec.rb index ffa4ebca9e..22cbd158f1 100644 --- a/Library/Homebrew/test/os/mac/diagnostic_spec.rb +++ b/Library/Homebrew/test/os/mac/diagnostic_spec.rb @@ -45,4 +45,9 @@ describe Homebrew::Diagnostic::Checks do expect(subject.check_ruby_version) .to match "Ruby version 1.8.6 is unsupported on 10.12" end + + specify "#check_dyld_insert" do + ENV["DYLD_INSERT_LIBRARIES"] = "foo" + expect(subject.check_ld_vars).to match("Setting DYLD_INSERT_LIBRARIES") + end end diff --git a/Library/Homebrew/test/utils/shell_spec.rb b/Library/Homebrew/test/utils/shell_spec.rb index d32f9928fd..a9456ae117 100644 --- a/Library/Homebrew/test/utils/shell_spec.rb +++ b/Library/Homebrew/test/utils/shell_spec.rb @@ -75,19 +75,20 @@ describe Utils::Shell do it "supports Tcsh" do ENV["SHELL"] = "/bin/tcsh" expect(subject.prepend_path_in_profile(path)) - .to start_with("echo 'setenv PATH #{path}:$") + .to eq("echo 'setenv PATH #{path}:$PATH' >> #{shell_profile}") end it "supports Bash" do ENV["SHELL"] = "/bin/bash" expect(subject.prepend_path_in_profile(path)) - .to start_with("echo 'export PATH=\"#{path}:$") + .to eq("echo 'export PATH=\"#{path}:$PATH\"' >> #{shell_profile}") end it "supports Fish" do ENV["SHELL"] = "/usr/local/bin/fish" + ENV["fish_user_paths"] = "/some/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 diff --git a/Library/Homebrew/utils/shell.rb b/Library/Homebrew/utils/shell.rb index 8c1c5f984b..56ea7fd1e6 100644 --- a/Library/Homebrew/utils/shell.rb +++ b/Library/Homebrew/utils/shell.rb @@ -40,6 +40,17 @@ module Utils SHELL_PROFILE_MAP.fetch(preferred, "~/.bash_profile") 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) case preferred when :bash, :ksh, :sh, :zsh, nil