Bundler.setupが読み込まれる流れを見てみる
昨日rails初期化を追っている中で、require 'bundler/setup’している部分がありました。
その時はそのプロジェクトで使うバージョンのgemをbundlerで読みこむ設定をしているというくらいしか調べませんでしたが、具体的に何をしているのかみてみようと思いました。
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メソッド以降の流れを再チャレンジします!!