module Bundler

Some versions of the Bundler 1.1 RC series introduced corrupted lockfiles. There were two major problems:

As a result, Bundler 1.1 contains code that fixes the earlier corruption. We will remove this fix-up code in Bundler 1.2.

This is the latest iteration of the gem dependency resolving algorithm. As of now, it can resolve (as a success or failure) any set of gem dependencies we throw at it in a reasonable amount of time. The most iterations I've seen it take is about 150. The actual implementation of the algorithm is not as good as it could be yet, but that can come later.

Constants

Deprecate
FREEBSD
NULL
ORIGINAL_ENV
VERSION

We're doing this because we might write tests that deal with other versions of bundler and we are unsure how to handle this better.

WINDOWS
YamlSyntaxError

Attributes

bundle_path[W]
rubygems[R]

Public Class Methods

current_ruby() click to toggle source

Returns current version of Ruby

@return [CurrentRuby] Current version of Ruby

# File lib/bundler/current_ruby.rb, line 5
def self.current_ruby
  @current_ruby ||= CurrentRuby.new
end
issues_url(exception) click to toggle source
# File lib/bundler/friendly_errors.rb, line 82
def self.issues_url(exception)
  'https://github.com/bundler/bundler/search?q='      "#{CGI.escape(exception.message.lines.first.chomp)}&type=Issues"
end
preserve_gem_path() click to toggle source
# File lib/bundler/gem_path_manipulation.rb, line 2
def self.preserve_gem_path
  original_gem_path = ENV["_ORIGINAL_GEM_PATH"]
  gem_path          = ENV["GEM_PATH"]
  ENV["_ORIGINAL_GEM_PATH"] = gem_path          if original_gem_path.nil? || original_gem_path == ""
  ENV["GEM_PATH"]           = original_gem_path if gem_path.nil? || gem_path == ""
end
request_issue_report_for(e) click to toggle source
# File lib/bundler/friendly_errors.rb, line 44
  def self.request_issue_report_for(e)
    Bundler.ui.info "      #{'--- ERROR REPORT TEMPLATE -------------------------------------------------------'}
      - What did you do?

        I ran the command `#{$PROGRAM_NAME} #{ARGV.join(' ')}`

      - What did you expect to happen?

        I expected Bundler to...

      - What happened instead?

        Instead, what actually happened was...


      Error details

          #{e.class}: #{e.message}
            #{e.backtrace.join("\n            ")}

      #{Bundler::Env.new.report(:print_gemfile => false).gsub(/\n/, "\n      ").strip}
      #{'--- TEMPLATE END ----------------------------------------------------------------'}

".gsub(/^ {6}/, '')

    Bundler.ui.error "Unfortunately, an unexpected error occurred, and Bundler cannot continue."

    Bundler.ui.warn "
      First, try this link to see if there are any existing issue reports for this error:
      #{issues_url(e)}

      If there aren't any reports for this error yet, please create copy and paste the report template above into a new issue. Don't forget to anonymize any private data! The new issue form is located at:
      https://github.com/bundler/bundler/issues/new
".gsub(/^ {6}/, '')
  end
root() click to toggle source
# File lib/bundler/inline.rb, line 33
def Bundler.root
  Pathname.pwd.expand_path
end
with_friendly_errors() { || ... } click to toggle source
# File lib/bundler/friendly_errors.rb, line 5
  def self.with_friendly_errors
    yield
  rescue Bundler::Dsl::DSLError => e
    Bundler.ui.error e.message
    exit e.status_code
  rescue Bundler::BundlerError => e
    Bundler.ui.error e.message, :wrap => true
    Bundler.ui.trace e
    exit e.status_code
  rescue Thor::AmbiguousTaskError => e
    Bundler.ui.error e.message
    exit 15
  rescue Thor::UndefinedTaskError => e
    Bundler.ui.error e.message
    exit 15
  rescue Thor::Error => e
    Bundler.ui.error e.message
    exit 1
  rescue LoadError => e
    raise e unless e.message =~ /cannot load such file -- openssl|openssl.so|libcrypto.so/
    Bundler.ui.error "\nCould not load OpenSSL."
    Bundler.ui.warn "      You must recompile Ruby with OpenSSL support or change the sources in your \
      Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL \
      using RVM are available at http://rvm.io/packages/openssl.
", :wrap => true
    Bundler.ui.trace e
    exit 1
  rescue Interrupt => e
    Bundler.ui.error "\nQuitting..."
    Bundler.ui.trace e
    exit 1
  rescue SystemExit => e
    exit e.status
  rescue Exception => e
    request_issue_report_for(e)
    exit 1
  end

Public Instance Methods

app_cache(custom_path = nil) click to toggle source
# File lib/bundler.rb, line 209
def app_cache(custom_path = nil)
  path = custom_path || root
  path.join(self.settings.app_cache_path)
end
app_config_path() click to toggle source
# File lib/bundler.rb, line 203
def app_config_path
  ENV['BUNDLE_APP_CONFIG'] ?
    Pathname.new(ENV['BUNDLE_APP_CONFIG']).expand_path(root) :
    root.join('.bundle')
end
bin_path() click to toggle source

Returns absolute location of where binstubs are installed to.

# File lib/bundler.rb, line 110
def bin_path
  @bin_path ||= begin
    path = settings[:bin] || "bin"
    path = Pathname.new(path).expand_path(root).expand_path
    FileUtils.mkdir_p(path)
    path
  end
end
bundle_path() click to toggle source

Returns absolute path of where gems are installed on the filesystem.

# File lib/bundler.rb, line 105
def bundle_path
  @bundle_path ||= Pathname.new(settings.path).expand_path(root)
end
cache() click to toggle source
# File lib/bundler.rb, line 189
def cache
  bundle_path.join("cache/bundler")
end
clean_exec(*args) click to toggle source
# File lib/bundler.rb, line 253
def clean_exec(*args)
  with_clean_env { Kernel.exec(*args) }
end
clean_system(*args) click to toggle source
# File lib/bundler.rb, line 249
def clean_system(*args)
  with_clean_env { Kernel.system(*args) }
end
clear_gemspec_cache() click to toggle source
# File lib/bundler.rb, line 379
def clear_gemspec_cache
  @gemspec_cache = {}
end
configure() click to toggle source
# File lib/bundler.rb, line 91
def configure
  @configured ||= configure_gem_home_and_path
end
default_bundle_dir() click to toggle source
# File lib/bundler.rb, line 265
def default_bundle_dir
  SharedHelpers.default_bundle_dir
end
default_gemfile() click to toggle source
# File lib/bundler.rb, line 257
def default_gemfile
  SharedHelpers.default_gemfile
end
default_lockfile() click to toggle source
# File lib/bundler.rb, line 261
def default_lockfile
  SharedHelpers.default_lockfile
end
definition(unlock = nil) click to toggle source

Returns an instance of Bundler::Definition for given Gemfile and lockfile

@param unlock [Hash, Boolean, nil] Gems that have been requested

to be updated or true if all gems should be updated

@return [Bundler::Definition]

# File lib/bundler.rb, line 150
def definition(unlock = nil)
  @definition = nil if unlock
  @definition ||= begin
    configure
    upgrade_lockfile
    Definition.build(default_gemfile, default_lockfile, unlock)
  end
end
environment() click to toggle source
# File lib/bundler.rb, line 141
def environment
  Bundler::Environment.new(root, definition)
end
git_present?() click to toggle source
# File lib/bundler.rb, line 383
def git_present?
  return @git_present if defined?(@git_present)
  @git_present = Bundler.which("git") || Bundler.which("git.exe")
end
home() click to toggle source
# File lib/bundler.rb, line 177
def home
  bundle_path.join("bundler")
end
install_path() click to toggle source
# File lib/bundler.rb, line 181
def install_path
  home.join("gems")
end
load() click to toggle source
# File lib/bundler.rb, line 137
def load
  @load ||= Runtime.new(root, definition)
end
load_gemspec(file, validate = false) click to toggle source
# File lib/bundler.rb, line 350
def load_gemspec(file, validate = false)
  @gemspec_cache ||= {}
  key = File.expand_path(file)
  @gemspec_cache[key] ||= load_gemspec_uncached(file, validate)
  # Protect against caching side-effected gemspecs by returning a
  # new instance each time.
  @gemspec_cache[key].dup if @gemspec_cache[key]
end
load_gemspec_uncached(file, validate = false) click to toggle source
# File lib/bundler.rb, line 359
def load_gemspec_uncached(file, validate = false)
  path = Pathname.new(file)
  # Eval the gemspec from its parent directory, because some gemspecs
  # depend on "./" relative paths.
  SharedHelpers.chdir(path.dirname.to_s) do
    contents = path.read
    if contents[0..2] == "---" # YAML header
      spec = eval_yaml_gemspec(path, contents)
    else
      spec = eval_gemspec(path, contents)
    end
    Bundler.rubygems.validate(spec) if spec && validate
    spec
  end
rescue Gem::InvalidSpecificationException => e
  Bundler.ui.warn "The gemspec at #{file} is not valid. "          "The validation error was '#{e.message}'"
  nil
end
load_marshal(data) click to toggle source
# File lib/bundler.rb, line 344
def load_marshal(data)
  Marshal.load(data)
rescue => e
  raise MarshalError, "#{e.class}: #{e.message}"
end
locked_gems() click to toggle source
# File lib/bundler.rb, line 159
def locked_gems
  return @locked_gems if defined?(@locked_gems)
  if Bundler.default_lockfile.exist?
    lock = Bundler.read_file(Bundler.default_lockfile)
    @locked_gems = LockfileParser.new(lock)
  else
    @locked_gems = nil
  end
end
mkdir_p(path) click to toggle source
# File lib/bundler.rb, line 304
def mkdir_p(path)
  if requires_sudo?
    sudo "mkdir -p '#{path}'" unless File.exist?(path)
  else
    FileUtils.mkdir_p(path)
  end
end
read_file(file) click to toggle source
# File lib/bundler.rb, line 340
def read_file(file)
  File.open(file, "rb") { |f| f.read }
end
require(*groups) click to toggle source
# File lib/bundler.rb, line 133
def require(*groups)
  setup(*groups).require(*groups)
end
requires_sudo?() click to toggle source
# File lib/bundler.rb, line 278
def requires_sudo?
  return @requires_sudo if defined?(@requires_sudo_ran)

  if settings.allow_sudo?
    sudo_present = which "sudo"
  end

  if sudo_present
    # the bundle path and subdirectories need to be writable for Rubygems
    # to be able to unpack and install gems without exploding
    path = bundle_path
    path = path.parent until path.exist?

    # bins are written to a different location on OS X
    bin_dir = Pathname.new(Bundler.system_bindir)
    bin_dir = bin_dir.parent until bin_dir.exist?

    # if any directory is not writable, we need sudo
    files = [path, bin_dir] | Dir[path.join('build_info/*').to_s] | Dir[path.join('*').to_s]
    sudo_needed = files.any?{|f| !File.writable?(f) }
  end

  @requires_sudo_ran = true
  @requires_sudo = settings.allow_sudo? && sudo_present && sudo_needed
end
reset!() click to toggle source
# File lib/bundler.rb, line 392
def reset!
  @definition = nil
end
rm_rf(path) click to toggle source
# File lib/bundler.rb, line 218
def rm_rf(path)
  FileUtils.remove_entry_secure(path) if path && File.exist?(path)
end
root() click to toggle source
# File lib/bundler.rb, line 193
def root
  @root ||= begin
              default_gemfile.dirname.expand_path
            rescue GemfileNotFound
              bundle_dir = default_bundle_dir
              raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir
              Pathname.new(File.expand_path("..", bundle_dir))
            end
end
ruby_scope() click to toggle source
# File lib/bundler.rb, line 169
def ruby_scope
  "#{Bundler.rubygems.ruby_engine}/#{Bundler.rubygems.config_map[:ruby_version]}"
end
ruby_version() click to toggle source
# File lib/bundler.rb, line 388
def ruby_version
  @ruby_version ||= SystemRubyVersion.new
end
settings() click to toggle source
# File lib/bundler.rb, line 222
def settings
  return @settings if defined?(@settings)
  @settings = Settings.new(app_config_path)
rescue GemfileNotFound
  @settings = Settings.new(Pathname.new(".bundle").expand_path)
end
setup(*groups) click to toggle source
# File lib/bundler.rb, line 119
def setup(*groups)
  # Just return if all groups are already loaded
  return @setup if defined?(@setup)

  definition.validate_ruby!

  if groups.empty?
    # Load all groups, but only once
    @setup = load.setup
  else
    load.setup(*groups)
  end
end
specs_path() click to toggle source
# File lib/bundler.rb, line 185
def specs_path
  bundle_path.join("specifications")
end
sudo(str) click to toggle source
# File lib/bundler.rb, line 324
    def sudo(str)
      prompt = "\n\n" + "      Your user account isn't allowed to install to the system Rubygems.
      You can cancel this installation and run:

          bundle install --path vendor/bundle

      to install the gems into ./vendor/bundle/, or you can enter your password
      and install the bundled gems to Rubygems using sudo.

      Password:
".gsub(/^ {6}/, '').strip + " "

      %xsudo -p "#{prompt}" #{str}`
    end
system_bindir() click to toggle source
# File lib/bundler.rb, line 269
def system_bindir
  # Gem.bindir doesn't always return the location that Rubygems will install
  # system binaries. If you put '-n foo' in your .gemrc, Rubygems will
  # install binstubs there instead. Unfortunately, Rubygems doesn't expose
  # that directory at all, so rather than parse .gemrc ourselves, we allow
  # the directory to be set as well, via `bundle config bindir foo`.
  Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir
end
tmp(name = Process.pid.to_s) click to toggle source
# File lib/bundler.rb, line 214
def tmp(name = Process.pid.to_s)
  Pathname.new(Dir.mktmpdir(["bundler", name]))
end
ui() click to toggle source
# File lib/bundler.rb, line 95
def ui
  (defined?(@ui) && @ui) || (self.ui = UI::Silent.new)
end
ui=(ui) click to toggle source
# File lib/bundler.rb, line 99
def ui=(ui)
  Bundler.rubygems.ui = ui ? UI::RGProxy.new(ui) : nil
  @ui = ui
end
user_bundle_path() click to toggle source
# File lib/bundler.rb, line 173
def user_bundle_path
  Pathname.new(Bundler.rubygems.user_home).join(".bundler")
end
which(executable) click to toggle source
# File lib/bundler.rb, line 312
def which(executable)
  if File.file?(executable) && File.executable?(executable)
    executable
  elsif ENV['PATH']
    path = ENV['PATH'].split(File::PATH_SEPARATOR).find do |p|
      abs_path = File.join(p, executable)
      File.file?(abs_path) && File.executable?(abs_path)
    end
    path && File.expand_path(executable, path)
  end
end
with_clean_env() { || ... } click to toggle source
# File lib/bundler.rb, line 237
def with_clean_env
  with_original_env do
    ENV['MANPATH'] = ENV['BUNDLE_ORIG_MANPATH']
    ENV.delete_if { |k,_| k[0,7] == 'BUNDLE_' }
    if ENV.has_key? 'RUBYOPT'
      ENV['RUBYOPT'] = ENV['RUBYOPT'].sub '-rbundler/setup', ''
      ENV['RUBYOPT'] = ENV['RUBYOPT'].sub "-I#{File.expand_path('..', __FILE__)}", ''
    end
    yield
  end
end
with_original_env() { || ... } click to toggle source
# File lib/bundler.rb, line 229
def with_original_env
  bundled_env = ENV.to_hash
  ENV.replace(ORIGINAL_ENV)
  yield
ensure
  ENV.replace(bundled_env.to_hash)
end

Private Instance Methods

configure_gem_home() click to toggle source
# File lib/bundler.rb, line 435
def configure_gem_home
  # TODO: This mkdir_p is only needed for JRuby <= 1.5 and should go away (GH #602)
  FileUtils.mkdir_p bundle_path.to_s rescue nil

  ENV['GEM_HOME'] = File.expand_path(bundle_path, root)
  Bundler.rubygems.clear_paths
end
configure_gem_home_and_path() click to toggle source
# File lib/bundler.rb, line 421
def configure_gem_home_and_path
  blank_home = ENV['GEM_HOME'].nil? || ENV['GEM_HOME'].empty?
  if settings[:disable_shared_gems]
    ENV['GEM_PATH'] = ''
  elsif blank_home || Bundler.rubygems.gem_dir != bundle_path.to_s
    possibles = [Bundler.rubygems.gem_dir, Bundler.rubygems.gem_path]
    paths = possibles.flatten.compact.uniq.reject { |p| p.empty? }
    ENV["GEM_PATH"] = paths.join(File::PATH_SEPARATOR)
  end

  configure_gem_home
  bundle_path
end
eval_gemspec(path, contents) click to toggle source
# File lib/bundler.rb, line 406
def eval_gemspec(path, contents)
  eval(contents, TOPLEVEL_BINDING, path.expand_path.to_s)
rescue ScriptError, StandardError => e
  original_line = e.backtrace.find { |line| line.include?(path.to_s) }
  msg  = "There was a #{e.class} while loading #{path.basename}: \n#{e.message}"
  msg << " from\n  #{original_line}" if original_line
  msg << "\n"

  if e.is_a?(LoadError) && RUBY_VERSION >= "1.9"
    msg << "\nDoes it try to require a relative path? That's been removed in Ruby 1.9."
  end

  raise GemspecError, msg
end
eval_yaml_gemspec(path, contents) click to toggle source
# File lib/bundler.rb, line 398
def eval_yaml_gemspec(path, contents)
  # If the YAML is invalid, Syck raises an ArgumentError, and Psych
  # raises a Psych::SyntaxError. See psyched_yaml.rb for more info.
  Gem::Specification.from_yaml(contents)
rescue YamlSyntaxError, ArgumentError, Gem::EndOfYAMLException, Gem::Exception
  eval_gemspec(path, contents)
end
upgrade_lockfile() click to toggle source
# File lib/bundler.rb, line 443
def upgrade_lockfile
  lockfile = default_lockfile
  if lockfile.exist? && lockfile.read(3) == "---"
    Bundler.ui.warn "Detected Gemfile.lock generated by 0.9, deleting..."
    lockfile.rmtree
  end
end