Bundler.setupが読み込まれる流れを見てみる

昨日rails初期化を追っている中で、require 'bundler/setup’している部分がありました。

その時はそのプロジェクトで使うバージョンのgembundlerで読みこむ設定をしているというくらいしか調べませんでしたが、具体的に何をしているのかみてみようと思いました。

 

 

bundler/setupが読み込まれる流れ

まずrequire 'bundler/setup'されるとbundler gemのbundler/lib/bundler/setup.rbが読まれます。

bundler/lib/bundler/setup.rb

# frozen_string_literal: true

require "bundler/shared_helpers"

if Bundler::SharedHelpers.in_bundle?
require "bundler"

if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"]
begin
Bundler.setup
rescue Bundler::BundlerError => e
puts "\e[31m#{e.message}\e[0m"
puts e.backtrace.join("\n") if ENV["DEBUG"]
if e.is_a?(Bundler::GemNotFound)
puts "\e[33mRun `bundle install` to install missing gems.\e[0m"
end
exit e.status_code
end
else
Bundler.setup
end

# Add bundler to the load path after disabling system gems
bundler_lib = File.expand_path("../..", __FILE__)
$LOAD_PATH.unshift(bundler_lib) unless $LOAD_PATH.include?(bundler_lib)

Bundler.ui = nil
end

この中でbundler/shared_helpersをrequireし、bundlerをrequireし、Bundler.setupを行なっております。

Bundler.setupが何をしているかbundler/lib/bundler.rbを見てみます。

 

bundler/lib/bundler.rb


module Bundler

class << self

def setup(*groups)
# Return if all groups are already loaded
return @setup if defined?(@setup) && @setup

definition.validate_runtime!

SharedHelpers.print_major_deprecations!

if groups.empty?
# Load all groups, but only once
@setup = load.setup
else
load.setup(*groups)
end
end

def require(*groups)
setup(*groups).require(*groups)
end

def load
@load ||= Runtime.new(root, definition)
end
 

 

setupメソッドの中では、Runtimeのインスタンスにsetupメソッドを呼んでいるようです。

Runtimeのが何者か調べるため、bundler/lib/bundler/runtime.rbを見に行きます。

bundler/lib/bundler/runtime.rb


module Bundler
class Runtime
include SharedHelpers

def initialize(root, definition)
@root = root
@definition = definition
end

def setup(*groups)
@definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen_bundle?

groups.map!(&:to_sym)

# Has to happen first
clean_load_path

specs = groups.any? ? @definition.specs_for(groups) : requested_specs

SharedHelpers.set_bundle_environment
Bundler.rubygems.replace_entrypoints(specs)

# Activate the specs
load_paths = specs.map do |spec|
unless spec.loaded_from
raise GemNotFound, "#{spec.full_name} is missing. Run `bundle install` to get it."
end

check_for_activated_spec!(spec)

Bundler.rubygems.mark_loaded(spec)
spec.load_paths.reject {|path| $LOAD_PATH.include?(path) }
end.reverse.flatten

# See Gem::Specification#add_self_to_load_path (since RubyGems 1.8)
if insert_index = Bundler.rubygems.load_path_insert_index
# Gem directories must come after -I and ENV['RUBYLIB']
$LOAD_PATH.insert(insert_index, *load_paths)
else
# We are probably testing in core, -I and RUBYLIB don't apply
$LOAD_PATH.unshift(*load_paths)
end

setup_manpath

lock(:preserve_unknown_sections => true)

self
end

Runtime.new(root, definition)すると、root、definitionそれぞれをインスタンス変数に入れています。

さらにそのインスタンスに同じファイルで定義しているsetupというインスタンスメソッドが呼ばれます。

@definitionにensure_equivalent_gemfile_and_lockfileを実行し、ensure_equivalent_gemfile_and_lockfileメソッドの中ではいろんな変数を設定しておりました。

clean_load_pathメソッドでは、すでにload済みのgemのパスを消しているようでした。

specs_forメソッドの部分はよくわからず。。。

set_bundle_environmentメソッドではいろんなパスや変数を設定しておりました。

rubygems.replace_entrypointsメソッドの部分もよくわからず。。。

それ以降の部分もよく分からず。。。

 

 

感想その他

日を改めて読み返してみると分かることがたまにあるので、また後日Runtimeのsetupメソッド以降の流れを再チャレンジします!!