module Bundler - bundler-1.9.9 Documentation

# module Bundler

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

- multiple copies of the same GIT section appeared in the lockfile

- when this happened, those sections got multiple copies of gems in those sections.

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]
ui[W]

### Public Class 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 105
    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 100
    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 373
    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

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

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 377
    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

issues_url(exception) click to toggle source

    # File lib/bundler/friendly_errors.rb, line 79
    def self.issues_url(exception)
      'https://github.com/bundler/bundler/search?q='      "#{CGI.escape(exception.message.lines.first.chomp)}&type=Issues"
    end

load() click to toggle source

    # File lib/bundler.rb, line 137
    def load
      @load ||= Runtime.new(root, definition)
    end

load_gemspec(file) click to toggle source

    # File lib/bundler.rb, line 350
    def load_gemspec(file)
      @gemspec_cache ||= {}
      key = File.expand_path(file)
      spec = ( @gemspec_cache[key] ||= load_gemspec_uncached(file) )
      # Protect against caching side-effected gemspecs by returning a
      # new instance each time.
      spec.dup if spec
    end

load_gemspec_uncached(file) click to toggle source

    # File lib/bundler.rb, line 359
    def load_gemspec_uncached(file)
      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
          eval_yaml_gemspec(path, contents)
        else
          eval_gemspec(path, contents)
        end
      end
    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

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

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

request_issue_report_for(e) click to toggle source

    # File lib/bundler/friendly_errors.rb, line 41
      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

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 386
    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 382
    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 114
    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
        @completed_groups ||= []
        # Figure out which groups haven't been loaded yet
        unloaded = groups - @completed_groups
        # Record groups that are now loaded
        @completed_groups = groups
        unloaded.any? ? load.setup(*groups) : load
      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 + " "

          %x`sudo -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
      @ui ||= UI::Silent.new
    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_friendly_errors() { || ... } click to toggle source

    # File lib/bundler/friendly_errors.rb, line 5
      def self.with_friendly_errors
        yield
      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

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 Class Methods

configure_gem_home() click to toggle source

    # File lib/bundler.rb, line 429
    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 415
    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 400
    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 392
    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 437
    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