bootsnap 1.3.2 → 1.4.0.pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +13 -2
- data/CHANGELOG.md +11 -0
- data/README.jp.md +4 -2
- data/Rakefile +2 -2
- data/bin/ci +10 -0
- data/bin/console +3 -3
- data/bin/test-minimal-support +7 -0
- data/bootsnap.gemspec +15 -9
- data/dev.yml +1 -1
- data/ext/bootsnap/extconf.rb +2 -1
- data/lib/bootsnap.rb +9 -6
- data/lib/bootsnap/bundler.rb +2 -2
- data/lib/bootsnap/compile_cache.rb +19 -4
- data/lib/bootsnap/compile_cache/iseq.rb +8 -8
- data/lib/bootsnap/compile_cache/yaml.rb +6 -6
- data/lib/bootsnap/explicit_require.rb +1 -1
- data/lib/bootsnap/load_path_cache.rb +25 -12
- data/lib/bootsnap/load_path_cache/cache.rb +12 -5
- data/lib/bootsnap/load_path_cache/core_ext/active_support.rb +3 -1
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +16 -12
- data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +7 -0
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +20 -6
- data/lib/bootsnap/load_path_cache/path.rb +5 -5
- data/lib/bootsnap/load_path_cache/path_scanner.rb +7 -3
- data/lib/bootsnap/load_path_cache/store.rb +8 -8
- data/lib/bootsnap/setup.rb +7 -13
- data/lib/bootsnap/version.rb +1 -1
- metadata +16 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 27963f8b281c516cef838264adcfb1b16e45b59d0c173f196642b5bc938c6de0
|
4
|
+
data.tar.gz: b21f67ce3edab72f1e77b825d18893a13f940a0084b37bbeab9f41855edf7ce4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96eeff9ea1052acb331c2328b5179b6c51598eaaf91ea2a1807e6af1ccc5d8086a1b9250bc1d032a090048f1df3fae5464542773a6fbbf4bcdb1b0e78229edad
|
7
|
+
data.tar.gz: 97371ef01bfbb3dbc9709856a8bb8831879b561787bf5b03ad6f8bf7e9e5ad159257278b857615a588715b3b8da76dcf65c74393c185f78ecdcab60d059ed8f0
|
data/.travis.yml
CHANGED
@@ -8,6 +8,17 @@ os:
|
|
8
8
|
rvm:
|
9
9
|
- ruby-2.4
|
10
10
|
- ruby-2.5
|
11
|
+
- ruby-head
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
matrix:
|
14
|
+
allow_failures:
|
15
|
+
- rvm: ruby-head
|
16
|
+
include:
|
17
|
+
- rvm: jruby
|
18
|
+
os: linux
|
19
|
+
env: MINIMAL_SUPPORT=1
|
20
|
+
- rvm: truffleruby
|
21
|
+
os: linux
|
22
|
+
env: MINIMAL_SUPPORT=1
|
23
|
+
|
24
|
+
script: bin/ci
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# 1.4.0
|
2
|
+
|
3
|
+
* When running in development mode, always fall back to a full path scan on LoadError, making
|
4
|
+
bootsnap more able to detect newly-created files. (#230)
|
5
|
+
* Respect `$LOADED_FEATURES.delete` in order to support code reloading, for integration with
|
6
|
+
Zeitwerk. (#230)
|
7
|
+
* Minor performance improvement: flow-control exceptions no longer generate backtraces.
|
8
|
+
* Better support for requiring from environments where some features are not supported (especially
|
9
|
+
JRuby). (#226)k
|
10
|
+
* More robust handling of OS errors when creating files. (#225)
|
11
|
+
|
1
12
|
# 1.3.2
|
2
13
|
|
3
14
|
* Fix Spring + Bootsnap incompatibility when there are files with similar names.
|
data/README.jp.md
CHANGED
@@ -12,7 +12,7 @@ Bootsnap は RubyVM におけるバイトコード生成やファイルルック
|
|
12
12
|
|
13
13
|
## 使用方法
|
14
14
|
|
15
|
-
この gem は
|
15
|
+
この gem は macOS と Linux で作動します。まずは、`bootsnap` を `Gemfile` に追加します:
|
16
16
|
|
17
17
|
```ruby
|
18
18
|
gem 'bootsnap', require: false
|
@@ -24,6 +24,8 @@ Rails を使用している場合は、以下のコードを、`config/boot.rb`
|
|
24
24
|
require 'bootsnap/setup'
|
25
25
|
```
|
26
26
|
|
27
|
+
単に `gem 'bootsnap', require: 'bootsnap/setup'` と指定することも技術的には可能ですが、最大限のパフォーマンス改善を得るためには Bootsnap をできるだけ早く読み込むことが重要です。
|
28
|
+
|
27
29
|
この require の仕組みは[こちら](https://github.com/Shopify/bootsnap/blob/master/lib/bootsnap/setup.rb)で確認できます。
|
28
30
|
|
29
31
|
Rails を使用していない場合、または、より多くの設定を変更したい場合は、以下のコードを `require 'bundler/setup'` の直後に追加してください(早く読み込まれるほど、より多くのものを最適化することができます)。
|
@@ -67,7 +69,7 @@ Bootsnap は、処理に時間のかかるメソッドの結果をキャッシ
|
|
67
69
|
_(このライブラリは [bootscale](https://github.com/byroot/bootscale) という別のライブラリを元に開発されました)_
|
68
70
|
|
69
71
|
Bootsnap の初期化時、あるいはパス(例えば、`$LOAD_PATH`)の変更時に、`Bootsnap::LoadPathCache` がキャッシュから必要なエントリーのリストを読み込みます。または、必要に応じてフルスキャンを実行し結果をキャッシュします。
|
70
|
-
その後、たとえば `require 'foo'` を評価する場合, Ruby は `$LOAD_PATH` `['x', 'y', ...]` のすべてのエントリーを繰り返し評価することで `x/foo.rb`, `y/foo.rb` などを探索します。これに対して Bootsnap は、キャッシュされた
|
72
|
+
その後、たとえば `require 'foo'` を評価する場合, Ruby は `$LOAD_PATH` `['x', 'y', ...]` のすべてのエントリーを繰り返し評価することで `x/foo.rb`, `y/foo.rb` などを探索します。これに対して Bootsnap は、キャッシュされた require 可能なファイルと `$LOAD_PATH` を見ることで、Rubyが最終的に選択するであろうパスで置き換えます。
|
71
73
|
|
72
74
|
この動作によって生成された syscall を見ると、最終的な結果は以前なら次のようになります。
|
73
75
|
|
data/Rakefile
CHANGED
data/bin/ci
ADDED
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require("bundler/setup")
|
4
|
+
require("bootsnap")
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +10,5 @@ require "bootsnap"
|
|
10
10
|
# require "pry"
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
13
|
+
require("irb")
|
14
14
|
IRB.start(__FILE__)
|
data/bootsnap.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require('bootsnap/version')
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "bootsnap"
|
@@ -15,10 +15,16 @@ Gem::Specification.new do |spec|
|
|
15
15
|
spec.description = spec.summary
|
16
16
|
spec.homepage = "https://github.com/Shopify/bootsnap"
|
17
17
|
|
18
|
-
spec.
|
18
|
+
spec.metadata = {
|
19
|
+
'bug_tracker_uri' => 'https://github.com/Shopify/bootsnap/issues',
|
20
|
+
'changelog_uri' => 'https://github.com/Shopify/bootsnap/blob/master/CHANGELOG.md',
|
21
|
+
'source_code_uri' => 'https://github.com/Shopify/bootsnap',
|
22
|
+
}
|
23
|
+
|
24
|
+
spec.files = %x(git ls-files -z).split("\x0").reject do |f|
|
19
25
|
f.match(%r{^(test|spec|features)/})
|
20
26
|
end
|
21
|
-
spec.require_paths =
|
27
|
+
spec.require_paths = %w(lib)
|
22
28
|
|
23
29
|
spec.required_ruby_version = '>= 2.0.0'
|
24
30
|
|
@@ -29,11 +35,11 @@ Gem::Specification.new do |spec|
|
|
29
35
|
spec.extensions = ['ext/bootsnap/extconf.rb']
|
30
36
|
end
|
31
37
|
|
32
|
-
spec.add_development_dependency
|
33
|
-
spec.add_development_dependency
|
34
|
-
spec.add_development_dependency
|
35
|
-
spec.add_development_dependency
|
36
|
-
spec.add_development_dependency
|
38
|
+
spec.add_development_dependency("bundler")
|
39
|
+
spec.add_development_dependency('rake', '~> 10.0')
|
40
|
+
spec.add_development_dependency('rake-compiler', '~> 0')
|
41
|
+
spec.add_development_dependency("minitest", "~> 5.0")
|
42
|
+
spec.add_development_dependency("mocha", "~> 1.2")
|
37
43
|
|
38
|
-
spec.add_runtime_dependency
|
44
|
+
spec.add_runtime_dependency("msgpack", "~> 1.0")
|
39
45
|
end
|
data/dev.yml
CHANGED
data/ext/bootsnap/extconf.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require("mkmf")
|
2
2
|
$CFLAGS << ' -O3 '
|
3
3
|
$CFLAGS << ' -std=c99'
|
4
4
|
|
@@ -12,6 +12,7 @@ unless ['0', '', nil].include?(ENV['BOOTSNAP_PEDANTIC'])
|
|
12
12
|
|
13
13
|
$CFLAGS << ' -Wno-unused-parameter' # VALUE self has to be there but we don't care what it is.
|
14
14
|
$CFLAGS << ' -Wno-keyword-macro' # hiding return
|
15
|
+
$CFLAGS << ' -Wno-gcc-compat' # ruby.h 2.6.0 on macos 10.14, dunno
|
15
16
|
end
|
16
17
|
|
17
18
|
create_makefile("bootsnap/bootsnap")
|
data/lib/bootsnap.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
3
|
-
require_relative
|
4
|
-
require_relative
|
1
|
+
require_relative('bootsnap/version')
|
2
|
+
require_relative('bootsnap/bundler')
|
3
|
+
require_relative('bootsnap/load_path_cache')
|
4
|
+
require_relative('bootsnap/compile_cache')
|
5
5
|
|
6
6
|
module Bootsnap
|
7
7
|
InvalidConfiguration = Class.new(StandardError)
|
@@ -16,7 +16,7 @@ module Bootsnap
|
|
16
16
|
compile_cache_yaml: true
|
17
17
|
)
|
18
18
|
if autoload_paths_cache && !load_path_cache
|
19
|
-
raise
|
19
|
+
raise(InvalidConfiguration, "feature 'autoload_paths_cache' depends on feature 'load_path_cache'")
|
20
20
|
end
|
21
21
|
|
22
22
|
setup_disable_trace if disable_trace
|
@@ -36,7 +36,10 @@ module Bootsnap
|
|
36
36
|
|
37
37
|
def self.setup_disable_trace
|
38
38
|
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
|
39
|
-
warn(
|
39
|
+
warn(
|
40
|
+
"from #{caller_locations(1, 1)[0]}: The 'disable_trace' method is not allowed with this Ruby version. " \
|
41
|
+
"current: #{RUBY_VERSION}, allowed version: < 2.5.0",
|
42
|
+
)
|
40
43
|
else
|
41
44
|
RubyVM::InstructionSequence.compile_option = { trace_instruction: false }
|
42
45
|
end
|
data/lib/bootsnap/bundler.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module Bootsnap
|
2
|
-
|
2
|
+
extend(self)
|
3
3
|
|
4
4
|
def bundler?
|
5
5
|
return false unless defined?(::Bundler)
|
6
6
|
|
7
7
|
# Bundler environment variable
|
8
|
-
|
8
|
+
%w(BUNDLE_BIN_PATH BUNDLE_GEMFILE).each do |current|
|
9
9
|
return true if ENV.key?(current)
|
10
10
|
end
|
11
11
|
|
@@ -2,14 +2,29 @@ module Bootsnap
|
|
2
2
|
module CompileCache
|
3
3
|
def self.setup(cache_dir:, iseq:, yaml:)
|
4
4
|
if iseq
|
5
|
-
|
6
|
-
|
5
|
+
if supported?
|
6
|
+
require_relative('compile_cache/iseq')
|
7
|
+
Bootsnap::CompileCache::ISeq.install!(cache_dir)
|
8
|
+
elsif $VERBOSE
|
9
|
+
warn("[bootsnap/setup] bytecode caching is not supported on this implementation of Ruby")
|
10
|
+
end
|
7
11
|
end
|
8
12
|
|
9
13
|
if yaml
|
10
|
-
|
11
|
-
|
14
|
+
if supported?
|
15
|
+
require_relative('compile_cache/yaml')
|
16
|
+
Bootsnap::CompileCache::YAML.install!(cache_dir)
|
17
|
+
elsif $VERBOSE
|
18
|
+
warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
|
19
|
+
end
|
12
20
|
end
|
13
21
|
end
|
22
|
+
|
23
|
+
def self.supported?
|
24
|
+
# only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), and >= 2.3.0
|
25
|
+
RUBY_ENGINE == 'ruby' &&
|
26
|
+
RUBY_PLATFORM =~ /darwin|linux|bsd/ &&
|
27
|
+
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
|
28
|
+
end
|
14
29
|
end
|
15
30
|
end
|
@@ -1,25 +1,25 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require('bootsnap/bootsnap')
|
2
|
+
require('zlib')
|
3
3
|
|
4
4
|
module Bootsnap
|
5
5
|
module CompileCache
|
6
6
|
module ISeq
|
7
7
|
class << self
|
8
|
-
attr_accessor
|
8
|
+
attr_accessor(:cache_dir)
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.input_to_storage(_, path)
|
12
12
|
RubyVM::InstructionSequence.compile_file(path).to_binary
|
13
13
|
rescue SyntaxError
|
14
|
-
raise
|
14
|
+
raise(Uncompilable, 'syntax error')
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.storage_to_output(binary)
|
18
18
|
RubyVM::InstructionSequence.load_from_binary(binary)
|
19
19
|
rescue RuntimeError => e
|
20
20
|
if e.message == 'broken binary format'
|
21
|
-
STDERR.puts
|
22
|
-
|
21
|
+
STDERR.puts("[Bootsnap::CompileCache] warning: rejecting broken binary")
|
22
|
+
nil
|
23
23
|
else
|
24
24
|
raise
|
25
25
|
end
|
@@ -41,7 +41,7 @@ module Bootsnap
|
|
41
41
|
)
|
42
42
|
rescue RuntimeError => e
|
43
43
|
if e.message =~ /unmatched platform/
|
44
|
-
puts
|
44
|
+
puts("unmatched platform for file #{path}")
|
45
45
|
end
|
46
46
|
raise
|
47
47
|
end
|
@@ -62,7 +62,7 @@ module Bootsnap
|
|
62
62
|
Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
|
63
63
|
Bootsnap::CompileCache::ISeq.compile_option_updated
|
64
64
|
class << RubyVM::InstructionSequence
|
65
|
-
prepend
|
65
|
+
prepend(InstructionSequenceMixin)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
@@ -1,21 +1,21 @@
|
|
1
|
-
require
|
1
|
+
require('bootsnap/bootsnap')
|
2
2
|
|
3
3
|
module Bootsnap
|
4
4
|
module CompileCache
|
5
5
|
module YAML
|
6
6
|
class << self
|
7
|
-
attr_accessor
|
7
|
+
attr_accessor(:msgpack_factory)
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.input_to_storage(contents, _)
|
11
|
-
raise
|
11
|
+
raise(Uncompilable) if contents.index("!ruby/object")
|
12
12
|
obj = ::YAML.load(contents)
|
13
13
|
msgpack_factory.packer.write(obj).to_s
|
14
14
|
rescue NoMethodError, RangeError
|
15
15
|
# if the object included things that we can't serialize, fall back to
|
16
16
|
# Marshal. It's a bit slower, but can encode anything yaml can.
|
17
17
|
# NoMethodError is unexpected types; RangeError is Bignums
|
18
|
-
|
18
|
+
Marshal.dump(obj)
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.storage_to_output(data)
|
@@ -34,8 +34,8 @@ module Bootsnap
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.install!(cache_dir)
|
37
|
-
require
|
38
|
-
require
|
37
|
+
require('yaml')
|
38
|
+
require('msgpack')
|
39
39
|
|
40
40
|
# MessagePack serializes symbols as strings by default.
|
41
41
|
# We want them to roundtrip cleanly, so we use a custom factory.
|
@@ -21,38 +21,51 @@ module Bootsnap
|
|
21
21
|
CACHED_EXTENSIONS = DLEXT2 ? [DOT_RB, DLEXT, DLEXT2] : [DOT_RB, DLEXT]
|
22
22
|
|
23
23
|
class << self
|
24
|
-
attr_reader
|
25
|
-
|
24
|
+
attr_reader(:load_path_cache, :autoload_paths_cache,
|
25
|
+
:loaded_features_index, :realpath_cache)
|
26
26
|
|
27
27
|
def setup(cache_path:, development_mode:, active_support: true)
|
28
|
+
unless supported?
|
29
|
+
warn("[bootsnap/setup] Load path caching is not supported on this implementation of Ruby") if $VERBOSE
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
28
33
|
store = Store.new(cache_path)
|
29
34
|
|
30
35
|
@loaded_features_index = LoadedFeaturesIndex.new
|
31
36
|
@realpath_cache = RealpathCache.new
|
32
37
|
|
33
38
|
@load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
|
34
|
-
require_relative
|
39
|
+
require_relative('load_path_cache/core_ext/kernel_require')
|
40
|
+
require_relative('load_path_cache/core_ext/loaded_features')
|
35
41
|
|
36
42
|
if active_support
|
37
43
|
# this should happen after setting up the initial cache because it
|
38
44
|
# loads a lot of code. It's better to do after +require+ is optimized.
|
39
|
-
require
|
45
|
+
require('active_support/dependencies')
|
40
46
|
@autoload_paths_cache = Cache.new(
|
41
47
|
store,
|
42
48
|
::ActiveSupport::Dependencies.autoload_paths,
|
43
49
|
development_mode: development_mode
|
44
50
|
)
|
45
|
-
require_relative
|
51
|
+
require_relative('load_path_cache/core_ext/active_support')
|
46
52
|
end
|
47
53
|
end
|
54
|
+
|
55
|
+
def supported?
|
56
|
+
RUBY_ENGINE == 'ruby' &&
|
57
|
+
RUBY_PLATFORM =~ /darwin|linux|bsd/
|
58
|
+
end
|
48
59
|
end
|
49
60
|
end
|
50
61
|
end
|
51
62
|
|
52
|
-
|
53
|
-
require_relative
|
54
|
-
require_relative
|
55
|
-
require_relative
|
56
|
-
require_relative
|
57
|
-
require_relative
|
58
|
-
require_relative
|
63
|
+
if Bootsnap::LoadPathCache.supported?
|
64
|
+
require_relative('load_path_cache/path_scanner')
|
65
|
+
require_relative('load_path_cache/path')
|
66
|
+
require_relative('load_path_cache/cache')
|
67
|
+
require_relative('load_path_cache/store')
|
68
|
+
require_relative('load_path_cache/change_observer')
|
69
|
+
require_relative('load_path_cache/loaded_features_index')
|
70
|
+
require_relative('load_path_cache/realpath_cache')
|
71
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative('../explicit_require')
|
2
2
|
|
3
3
|
module Bootsnap
|
4
4
|
module LoadPathCache
|
@@ -56,7 +56,7 @@ module Bootsnap
|
|
56
56
|
# returns false as if it were already loaded; however, there is no
|
57
57
|
# file to find on disk. We've pre-built a list of these, and we
|
58
58
|
# return false if any of them is loaded.
|
59
|
-
raise
|
59
|
+
raise(LoadPathCache::ReturnFalse, '', []) if BUILTIN_FEATURES.key?(feature)
|
60
60
|
|
61
61
|
# The feature wasn't found on our preliminary search through the index.
|
62
62
|
# We resolve this differently depending on what the extension was.
|
@@ -73,14 +73,21 @@ module Bootsnap
|
|
73
73
|
x = search_index(feature[0..-4] + DLEXT)
|
74
74
|
return x if x
|
75
75
|
if DLEXT2
|
76
|
-
search_index(feature[0..-4] + DLEXT2)
|
76
|
+
x = search_index(feature[0..-4] + DLEXT2)
|
77
|
+
return x if x
|
77
78
|
end
|
78
79
|
else
|
79
80
|
# other, unknown extension. For example, `.rake`. Since we haven't
|
80
81
|
# cached these, we legitimately need to run the load path search.
|
81
|
-
raise
|
82
|
+
raise(LoadPathCache::FallbackScan, '', [])
|
82
83
|
end
|
83
84
|
end
|
85
|
+
|
86
|
+
# In development mode, we don't want to confidently return failures for
|
87
|
+
# cases where the file doesn't appear to be on the load path. We should
|
88
|
+
# be able to detect newly-created files without rebooting the
|
89
|
+
# application.
|
90
|
+
raise(LoadPathCache::FallbackScan, '', []) if @development_mode
|
84
91
|
end
|
85
92
|
|
86
93
|
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
@@ -174,7 +181,7 @@ module Bootsnap
|
|
174
181
|
end
|
175
182
|
|
176
183
|
def try_index(f)
|
177
|
-
if p = @index[f]
|
184
|
+
if (p = @index[f])
|
178
185
|
p + '/' + f
|
179
186
|
end
|
180
187
|
end
|
@@ -30,6 +30,8 @@ module Bootsnap
|
|
30
30
|
Bootsnap::LoadPathCache.autoload_paths_cache.find(path)
|
31
31
|
rescue Bootsnap::LoadPathCache::ReturnFalse
|
32
32
|
nil # doesn't really apply here
|
33
|
+
rescue Bootsnap::LoadPathCache::FallbackScan
|
34
|
+
nil # doesn't really apply here
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -92,7 +94,7 @@ end
|
|
92
94
|
module ActiveSupport
|
93
95
|
module Dependencies
|
94
96
|
class << self
|
95
|
-
prepend
|
97
|
+
prepend(Bootsnap::LoadPathCache::CoreExt::ActiveSupport::ClassMethods)
|
96
98
|
end
|
97
99
|
end
|
98
100
|
end
|
@@ -11,32 +11,36 @@ module Bootsnap
|
|
11
11
|
end
|
12
12
|
|
13
13
|
module Kernel
|
14
|
-
|
14
|
+
extend(self)
|
15
15
|
|
16
|
-
alias_method
|
16
|
+
alias_method(:require_without_bootsnap, :require)
|
17
17
|
|
18
18
|
# Note that require registers to $LOADED_FEATURES while load does not.
|
19
19
|
def require_with_bootsnap_lfi(path, resolved = nil)
|
20
20
|
Bootsnap::LoadPathCache.loaded_features_index.register(path, resolved) do
|
21
21
|
require_without_bootsnap(resolved || path)
|
22
|
+
# TODO(burke): if resolved was nil, the correct thing here is probably to
|
23
|
+
# ingress the appended contents to $LOADED_FEATURES into the LFI, but
|
24
|
+
# it's hard to imagine how to do this without creating a bunch of
|
25
|
+
# redundant work, since require can call itself a bunch of times.
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
25
29
|
def require(path)
|
26
30
|
return false if Bootsnap::LoadPathCache.loaded_features_index.key?(path)
|
27
31
|
|
28
|
-
if resolved = Bootsnap::LoadPathCache.load_path_cache.find(path)
|
32
|
+
if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(path))
|
29
33
|
return require_with_bootsnap_lfi(path, resolved)
|
30
34
|
end
|
31
35
|
|
32
|
-
raise
|
36
|
+
raise(Bootsnap::LoadPathCache::CoreExt.make_load_error(path))
|
33
37
|
rescue Bootsnap::LoadPathCache::ReturnFalse
|
34
|
-
|
38
|
+
false
|
35
39
|
rescue Bootsnap::LoadPathCache::FallbackScan
|
36
40
|
require_with_bootsnap_lfi(path)
|
37
41
|
end
|
38
42
|
|
39
|
-
alias_method
|
43
|
+
alias_method(:require_relative_without_bootsnap, :require_relative)
|
40
44
|
def require_relative(path)
|
41
45
|
realpath = Bootsnap::LoadPathCache.realpath_cache.call(
|
42
46
|
caller_locations(1..1).first.absolute_path, path
|
@@ -44,9 +48,9 @@ module Kernel
|
|
44
48
|
require(realpath)
|
45
49
|
end
|
46
50
|
|
47
|
-
alias_method
|
51
|
+
alias_method(:load_without_bootsnap, :load)
|
48
52
|
def load(path, wrap = false)
|
49
|
-
if resolved = Bootsnap::LoadPathCache.load_path_cache.find(path)
|
53
|
+
if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(path))
|
50
54
|
return load_without_bootsnap(resolved, wrap)
|
51
55
|
end
|
52
56
|
|
@@ -55,16 +59,16 @@ module Kernel
|
|
55
59
|
return load_without_bootsnap(relative, wrap)
|
56
60
|
end
|
57
61
|
|
58
|
-
raise
|
62
|
+
raise(Bootsnap::LoadPathCache::CoreExt.make_load_error(path))
|
59
63
|
rescue Bootsnap::LoadPathCache::ReturnFalse
|
60
|
-
|
64
|
+
false
|
61
65
|
rescue Bootsnap::LoadPathCache::FallbackScan
|
62
66
|
load_without_bootsnap(path, wrap)
|
63
67
|
end
|
64
68
|
end
|
65
69
|
|
66
70
|
class Module
|
67
|
-
alias_method
|
71
|
+
alias_method(:autoload_without_bootsnap, :autoload)
|
68
72
|
def autoload(const, path)
|
69
73
|
# NOTE: This may defeat LoadedFeaturesIndex, but it's not immediately
|
70
74
|
# obvious how to make it work. This feels like a pretty niche case, unclear
|
@@ -75,7 +79,7 @@ class Module
|
|
75
79
|
# since it's done in C-land.
|
76
80
|
autoload_without_bootsnap(const, Bootsnap::LoadPathCache.load_path_cache.find(path) || path)
|
77
81
|
rescue Bootsnap::LoadPathCache::ReturnFalse
|
78
|
-
|
82
|
+
false
|
79
83
|
rescue Bootsnap::LoadPathCache::FallbackScan
|
80
84
|
autoload_without_bootsnap(const, path)
|
81
85
|
end
|
@@ -32,17 +32,29 @@ module Bootsnap
|
|
32
32
|
# parallel the work done with ChangeObserver on $LOAD_PATH to mirror
|
33
33
|
# updates to our @lfi.
|
34
34
|
$LOADED_FEATURES.each do |feat|
|
35
|
+
hash = feat.hash
|
35
36
|
$LOAD_PATH.each do |lpe|
|
36
37
|
next unless feat.start_with?(lpe)
|
37
38
|
# /a/b/lib/my/foo.rb
|
38
39
|
# ^^^^^^^^^
|
39
40
|
short = feat[(lpe.length + 1)..-1]
|
40
|
-
|
41
|
-
@lfi[
|
41
|
+
stripped = strip_extension(short)
|
42
|
+
@lfi[short] = hash
|
43
|
+
@lfi[stripped] = hash
|
42
44
|
end
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
48
|
+
# We've optimized for initialize and register to be fast, and purge to be tolerable.
|
49
|
+
# If access patterns make this not-okay, we can lazy-invert the LFI on
|
50
|
+
# first purge and work from there.
|
51
|
+
def purge(feature)
|
52
|
+
@mutex.synchronize do
|
53
|
+
feat_hash = feature.hash
|
54
|
+
@lfi.reject! { |_, hash| hash == feat_hash }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
46
58
|
def key?(feature)
|
47
59
|
@mutex.synchronize { @lfi.key?(feature) }
|
48
60
|
end
|
@@ -64,19 +76,21 @@ module Bootsnap
|
|
64
76
|
def register(short, long = nil)
|
65
77
|
ret = yield
|
66
78
|
|
79
|
+
hash = long.hash # N.B. this won't be "correct" when long is nil
|
80
|
+
|
67
81
|
# do we have 'bundler' or 'bundler.rb'?
|
68
82
|
altname = if File.extname(short) != ''
|
69
83
|
# strip the path from 'bundler.rb' -> 'bundler'
|
70
84
|
strip_extension(short)
|
71
|
-
elsif long && ext = File.extname(long)
|
85
|
+
elsif long && (ext = File.extname(long))
|
72
86
|
# get the extension from the expanded path if given
|
73
87
|
# 'bundler' + '.rb'
|
74
88
|
short + ext
|
75
89
|
end
|
76
90
|
|
77
91
|
@mutex.synchronize do
|
78
|
-
@lfi[short] =
|
79
|
-
(@lfi[altname] =
|
92
|
+
@lfi[short] = hash
|
93
|
+
(@lfi[altname] = hash) if altname
|
80
94
|
end
|
81
95
|
|
82
96
|
ret
|
@@ -85,7 +99,7 @@ module Bootsnap
|
|
85
99
|
private
|
86
100
|
|
87
101
|
STRIP_EXTENSION = /\.[^.]*?$/
|
88
|
-
private_constant
|
102
|
+
private_constant(:STRIP_EXTENSION)
|
89
103
|
|
90
104
|
def strip_extension(f)
|
91
105
|
f.sub(STRIP_EXTENSION, '')
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative('path_scanner')
|
2
2
|
|
3
3
|
module Bootsnap
|
4
4
|
module LoadPathCache
|
@@ -17,7 +17,7 @@ module Bootsnap
|
|
17
17
|
stability == VOLATILE
|
18
18
|
end
|
19
19
|
|
20
|
-
attr_reader
|
20
|
+
attr_reader(:path)
|
21
21
|
|
22
22
|
def initialize(path)
|
23
23
|
@path = path.to_s
|
@@ -26,7 +26,7 @@ module Bootsnap
|
|
26
26
|
# True if the path exists, but represents a non-directory object
|
27
27
|
def non_directory?
|
28
28
|
!File.stat(path).directory?
|
29
|
-
rescue Errno::ENOENT
|
29
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
30
30
|
false
|
31
31
|
end
|
32
32
|
|
@@ -76,8 +76,8 @@ module Bootsnap
|
|
76
76
|
["", *dirs].each do |dir|
|
77
77
|
curr = begin
|
78
78
|
File.mtime("#{path}/#{dir}").to_i
|
79
|
-
|
80
|
-
|
79
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
80
|
+
-1
|
81
81
|
end
|
82
82
|
max = curr if curr > max
|
83
83
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative('../explicit_require')
|
2
2
|
|
3
3
|
module Bootsnap
|
4
4
|
module LoadPathCache
|
@@ -7,8 +7,12 @@ module Bootsnap
|
|
7
7
|
REQUIRABLE_EXTENSIONS = [DOT_RB] + DL_EXTENSIONS
|
8
8
|
NORMALIZE_NATIVE_EXTENSIONS = !DL_EXTENSIONS.include?(LoadPathCache::DOT_SO)
|
9
9
|
ALTERNATIVE_NATIVE_EXTENSIONS_PATTERN = /\.(o|bundle|dylib)\z/
|
10
|
-
|
11
|
-
|
10
|
+
|
11
|
+
BUNDLE_PATH = if Bootsnap.bundler?
|
12
|
+
(Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze
|
13
|
+
else
|
14
|
+
''.freeze
|
15
|
+
end
|
12
16
|
|
13
17
|
def self.call(path)
|
14
18
|
path = path.to_s
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative('../explicit_require')
|
2
2
|
|
3
|
-
Bootsnap::ExplicitRequire.with_gems('msgpack') { require
|
3
|
+
Bootsnap::ExplicitRequire.with_gems('msgpack') { require('msgpack') }
|
4
4
|
Bootsnap::ExplicitRequire.from_rubylibdir('fileutils')
|
5
5
|
|
6
6
|
module Bootsnap
|
@@ -21,7 +21,7 @@ module Bootsnap
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def fetch(key)
|
24
|
-
raise
|
24
|
+
raise(SetOutsideTransactionNotAllowed) unless @in_txn
|
25
25
|
v = get(key)
|
26
26
|
unless v
|
27
27
|
@dirty = true
|
@@ -32,7 +32,7 @@ module Bootsnap
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def set(key, value)
|
35
|
-
raise
|
35
|
+
raise(SetOutsideTransactionNotAllowed) unless @in_txn
|
36
36
|
if value != @data[key]
|
37
37
|
@dirty = true
|
38
38
|
@data[key] = value
|
@@ -40,7 +40,7 @@ module Bootsnap
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def transaction
|
43
|
-
raise
|
43
|
+
raise(NestedTransactionError) if @in_txn
|
44
44
|
@in_txn = true
|
45
45
|
yield
|
46
46
|
ensure
|
@@ -60,9 +60,9 @@ module Bootsnap
|
|
60
60
|
def load_data
|
61
61
|
@data = begin
|
62
62
|
MessagePack.load(File.binread(@store_path))
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
# handle malformed data due to upgrade incompatability
|
64
|
+
rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
|
65
|
+
{}
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
data/lib/bootsnap/setup.rb
CHANGED
@@ -1,14 +1,8 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative('../bootsnap')
|
2
2
|
|
3
3
|
env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || ENV['ENV']
|
4
4
|
development_mode = ['', nil, 'development'].include?(env)
|
5
5
|
|
6
|
-
# only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), and >= 2.3.0
|
7
|
-
enable_cc =
|
8
|
-
RUBY_ENGINE == 'ruby' &&
|
9
|
-
RUBY_PLATFORM =~ /darwin|linux|bsd/ &&
|
10
|
-
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
|
11
|
-
|
12
6
|
cache_dir = ENV['BOOTSNAP_CACHE_DIR']
|
13
7
|
unless cache_dir
|
14
8
|
config_dir_frame = caller.detect do |line|
|
@@ -16,11 +10,11 @@ unless cache_dir
|
|
16
10
|
end
|
17
11
|
|
18
12
|
unless config_dir_frame
|
19
|
-
$stderr.puts
|
20
|
-
$stderr.puts
|
21
|
-
$stderr.puts
|
13
|
+
$stderr.puts("[bootsnap/setup] couldn't infer cache directory! Either:")
|
14
|
+
$stderr.puts("[bootsnap/setup] 1. require bootsnap/setup from your application's config directory; or")
|
15
|
+
$stderr.puts("[bootsnap/setup] 2. Define the environment variable BOOTSNAP_CACHE_DIR")
|
22
16
|
|
23
|
-
raise
|
17
|
+
raise("couldn't infer bootsnap cache directory")
|
24
18
|
end
|
25
19
|
|
26
20
|
path = config_dir_frame.split(/:\d+:/).first
|
@@ -36,6 +30,6 @@ Bootsnap.setup(
|
|
36
30
|
load_path_cache: true,
|
37
31
|
autoload_paths_cache: true, # assume rails. open to PRs to impl. detection
|
38
32
|
disable_trace: false,
|
39
|
-
compile_cache_iseq:
|
40
|
-
compile_cache_yaml:
|
33
|
+
compile_cache_iseq: true,
|
34
|
+
compile_cache_yaml: true,
|
41
35
|
)
|
data/lib/bootsnap/version.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bootsnap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0.pre2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -113,8 +113,10 @@ files:
|
|
113
113
|
- README.jp.md
|
114
114
|
- README.md
|
115
115
|
- Rakefile
|
116
|
+
- bin/ci
|
116
117
|
- bin/console
|
117
118
|
- bin/setup
|
119
|
+
- bin/test-minimal-support
|
118
120
|
- bin/testunit
|
119
121
|
- bootsnap.gemspec
|
120
122
|
- dev.yml
|
@@ -132,6 +134,7 @@ files:
|
|
132
134
|
- lib/bootsnap/load_path_cache/change_observer.rb
|
133
135
|
- lib/bootsnap/load_path_cache/core_ext/active_support.rb
|
134
136
|
- lib/bootsnap/load_path_cache/core_ext/kernel_require.rb
|
137
|
+
- lib/bootsnap/load_path_cache/core_ext/loaded_features.rb
|
135
138
|
- lib/bootsnap/load_path_cache/loaded_features_index.rb
|
136
139
|
- lib/bootsnap/load_path_cache/path.rb
|
137
140
|
- lib/bootsnap/load_path_cache/path_scanner.rb
|
@@ -143,7 +146,10 @@ files:
|
|
143
146
|
homepage: https://github.com/Shopify/bootsnap
|
144
147
|
licenses:
|
145
148
|
- MIT
|
146
|
-
metadata:
|
149
|
+
metadata:
|
150
|
+
bug_tracker_uri: https://github.com/Shopify/bootsnap/issues
|
151
|
+
changelog_uri: https://github.com/Shopify/bootsnap/blob/master/CHANGELOG.md
|
152
|
+
source_code_uri: https://github.com/Shopify/bootsnap
|
147
153
|
post_install_message:
|
148
154
|
rdoc_options: []
|
149
155
|
require_paths:
|
@@ -155,12 +161,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
161
|
version: 2.0.0
|
156
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
163
|
requirements:
|
158
|
-
- - "
|
164
|
+
- - ">"
|
159
165
|
- !ruby/object:Gem::Version
|
160
|
-
version:
|
166
|
+
version: 1.3.1
|
161
167
|
requirements: []
|
162
|
-
|
163
|
-
rubygems_version: 2.6.14
|
168
|
+
rubygems_version: 3.0.2
|
164
169
|
signing_key:
|
165
170
|
specification_version: 4
|
166
171
|
summary: Boot large ruby/rails apps faster
|