class Bundler::CLI::Doctor

Constants

DARWIN_REGEX
LDD_REGEX

Attributes

options[R]

Public Class Methods

new(options) click to toggle source
# File bundler/cli/doctor.rb, line 14
def initialize(options)
  @options = options
end

Public Instance Methods

bundles_for_gem(spec) click to toggle source
# File bundler/cli/doctor.rb, line 56
def bundles_for_gem(spec)
  Dir.glob("#{spec.full_gem_path}/**/*.bundle")
end
check!() click to toggle source
# File bundler/cli/doctor.rb, line 60
def check!
  require_relative "check"
  Bundler::CLI::Check.new({}).run
end
dylibs(path) click to toggle source
# File bundler/cli/doctor.rb, line 42
def dylibs(path)
  case RbConfig::CONFIG["host_os"]
  when /darwin/
    return [] unless otool_available?
    dylibs_darwin(path)
  when /(linux|solaris|bsd)/
    return [] unless ldd_available?
    dylibs_ldd(path)
  else # Windows, etc.
    Bundler.ui.warn("Dynamic library check not supported on this platform.")
    []
  end
end
dylibs_darwin(path) click to toggle source
# File bundler/cli/doctor.rb, line 26
def dylibs_darwin(path)
  output = `/usr/bin/otool -L #{path.shellescape}`.chomp
  dylibs = output.split("\n")[1..-1].map {|l| l.match(DARWIN_REGEX).captures[0] }.uniq
  # ignore @rpath and friends
  dylibs.reject {|dylib| dylib.start_with? "@" }
end
dylibs_ldd(path) click to toggle source
# File bundler/cli/doctor.rb, line 33
def dylibs_ldd(path)
  output = `/usr/bin/ldd #{path.shellescape}`.chomp
  output.split("\n").map do |l|
    match = l.match(LDD_REGEX)
    next if match.nil?
    match.captures[0]
  end.compact
end
ldd_available?() click to toggle source
# File bundler/cli/doctor.rb, line 22
def ldd_available?
  Bundler.which("ldd")
end
otool_available?() click to toggle source
# File bundler/cli/doctor.rb, line 18
def otool_available?
  Bundler.which("otool")
end
run() click to toggle source
# File bundler/cli/doctor.rb, line 65
def run
  Bundler.ui.level = "warn" if options[:quiet]
  Bundler.settings.validate!
  check!

  definition = Bundler.definition
  broken_links = {}

  definition.specs.each do |spec|
    bundles_for_gem(spec).each do |bundle|
      bad_paths = dylibs(bundle).select do |f|
        begin
          Fiddle.dlopen(f)
          false
        rescue Fiddle::DLError
          true
        end
      end
      if bad_paths.any?
        broken_links[spec] ||= []
        broken_links[spec].concat(bad_paths)
      end
    end
  end

  permissions_valid = check_home_permissions

  if broken_links.any?
    message = "The following gems are missing OS dependencies:"
    broken_links.map do |spec, paths|
      paths.uniq.map do |path|
        "\n * #{spec.name}: #{path}"
      end
    end.flatten.sort.each {|m| message += m }
    raise ProductionError, message
  elsif !permissions_valid
    Bundler.ui.info "No issues found with the installed bundle"
  end
end

Private Instance Methods

check_home_permissions() click to toggle source
# File bundler/cli/doctor.rb, line 107
def check_home_permissions
  require "find"
  files_not_readable_or_writable = []
  files_not_rw_and_owned_by_different_user = []
  files_not_owned_by_current_user_but_still_rw = []
  broken_symlinks = []
  Find.find(Bundler.bundle_path.to_s).each do |f|
    if !File.exist?(f)
      broken_symlinks << f
    elsif !File.writable?(f) || !File.readable?(f)
      if File.stat(f).uid != Process.uid
        files_not_rw_and_owned_by_different_user << f
      else
        files_not_readable_or_writable << f
      end
    elsif File.stat(f).uid != Process.uid
      files_not_owned_by_current_user_but_still_rw << f
    end
  end

  ok = true

  if broken_symlinks.any?
    Bundler.ui.warn "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{broken_symlinks.join("\n - ")}"

    ok = false
  end

  if files_not_owned_by_current_user_but_still_rw.any?
    Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \
      "user, but are still readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}"

    ok = false
  end

  if files_not_rw_and_owned_by_different_user.any?
    Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \
      "user, and are not readable/writable. These files are:\n - #{files_not_rw_and_owned_by_different_user.join("\n - ")}"

    ok = false
  end

  if files_not_readable_or_writable.any?
    Bundler.ui.warn "Files exist in the Bundler home that are not " \
      "readable/writable by the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}"

    ok = false
  end

  ok
end