bootsnap 1.10.3 → 1.18.6
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 +4 -4
- data/CHANGELOG.md +106 -0
- data/README.md +21 -12
- data/ext/bootsnap/bootsnap.c +260 -120
- data/ext/bootsnap/extconf.rb +20 -13
- data/lib/bootsnap/bundler.rb +1 -1
- data/lib/bootsnap/cli/worker_pool.rb +72 -0
- data/lib/bootsnap/cli.rb +30 -26
- data/lib/bootsnap/compile_cache/iseq.rb +15 -9
- data/lib/bootsnap/compile_cache/json.rb +18 -17
- data/lib/bootsnap/compile_cache/yaml.rb +46 -60
- data/lib/bootsnap/compile_cache.rb +11 -17
- data/lib/bootsnap/explicit_require.rb +5 -0
- data/lib/bootsnap/load_path_cache/cache.rb +24 -21
- data/lib/bootsnap/load_path_cache/change_observer.rb +19 -2
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +8 -45
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +3 -3
- data/lib/bootsnap/load_path_cache/path.rb +37 -17
- data/lib/bootsnap/load_path_cache/path_scanner.rb +7 -1
- data/lib/bootsnap/load_path_cache/store.rb +34 -17
- data/lib/bootsnap/load_path_cache.rb +36 -15
- data/lib/bootsnap/setup.rb +1 -1
- data/lib/bootsnap/version.rb +1 -1
- data/lib/bootsnap.rb +63 -36
- metadata +4 -8
- data/lib/bootsnap/load_path_cache/realpath_cache.rb +0 -33
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../explicit_require"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module LoadPathCache
|
@@ -24,8 +24,16 @@ module Bootsnap
|
|
24
24
|
@mutex.synchronize { @dirs[dir] }
|
25
25
|
end
|
26
26
|
|
27
|
+
TRUFFLERUBY_LIB_DIR_PREFIX = if RUBY_ENGINE == "truffleruby"
|
28
|
+
"#{File.join(RbConfig::CONFIG['libdir'], 'truffle')}#{File::SEPARATOR}"
|
29
|
+
end
|
30
|
+
|
27
31
|
# { 'enumerator' => nil, 'enumerator.so' => nil, ... }
|
28
32
|
BUILTIN_FEATURES = $LOADED_FEATURES.each_with_object({}) do |feat, features|
|
33
|
+
if TRUFFLERUBY_LIB_DIR_PREFIX && feat.start_with?(TRUFFLERUBY_LIB_DIR_PREFIX)
|
34
|
+
feat = feat.byteslice(TRUFFLERUBY_LIB_DIR_PREFIX.bytesize..-1)
|
35
|
+
end
|
36
|
+
|
29
37
|
# Builtin features are of the form 'enumerator.so'.
|
30
38
|
# All others include paths.
|
31
39
|
next unless feat.size < 20 && !feat.include?("/")
|
@@ -45,20 +53,19 @@ module Bootsnap
|
|
45
53
|
|
46
54
|
# Try to resolve this feature to an absolute path without traversing the
|
47
55
|
# loadpath.
|
48
|
-
def find(feature
|
56
|
+
def find(feature)
|
49
57
|
reinitialize if (@has_relative_paths && dir_changed?) || stale?
|
50
58
|
feature = feature.to_s.freeze
|
51
59
|
|
52
60
|
return feature if Bootsnap.absolute_path?(feature)
|
53
61
|
|
54
62
|
if feature.start_with?("./", "../")
|
55
|
-
return
|
63
|
+
return expand_path(feature)
|
56
64
|
end
|
57
65
|
|
58
66
|
@mutex.synchronize do
|
59
|
-
x = search_index(feature
|
67
|
+
x = search_index(feature)
|
60
68
|
return x if x
|
61
|
-
return unless try_extensions
|
62
69
|
|
63
70
|
# Ruby has some built-in features that require lies about.
|
64
71
|
# For example, 'enumerator' is built in. If you require it, ruby
|
@@ -115,7 +122,7 @@ module Bootsnap
|
|
115
122
|
def reinitialize(path_obj = @path_obj)
|
116
123
|
@mutex.synchronize do
|
117
124
|
@path_obj = path_obj
|
118
|
-
ChangeObserver.register(
|
125
|
+
ChangeObserver.register(@path_obj, self)
|
119
126
|
@index = {}
|
120
127
|
@dirs = {}
|
121
128
|
@generated_at = now
|
@@ -142,6 +149,8 @@ module Bootsnap
|
|
142
149
|
@has_relative_paths = true if p.relative?
|
143
150
|
next if p.non_directory?
|
144
151
|
|
152
|
+
p = p.to_realpath
|
153
|
+
|
145
154
|
expanded_path = p.expanded_path
|
146
155
|
entries, dirs = p.entries_and_dirs(@store)
|
147
156
|
# push -> low precedence -> set only if unset
|
@@ -157,6 +166,8 @@ module Bootsnap
|
|
157
166
|
p = Path.new(path)
|
158
167
|
next if p.non_directory?
|
159
168
|
|
169
|
+
p = p.to_realpath
|
170
|
+
|
160
171
|
expanded_path = p.expanded_path
|
161
172
|
entries, dirs = p.entries_and_dirs(@store)
|
162
173
|
# unshift -> high precedence -> unconditional set
|
@@ -179,15 +190,11 @@ module Bootsnap
|
|
179
190
|
end
|
180
191
|
|
181
192
|
if DLEXT2
|
182
|
-
def search_index(feature
|
183
|
-
|
184
|
-
try_index(feature +
|
185
|
-
|
186
|
-
try_index(feature + DLEXT2) ||
|
187
|
-
try_index(feature)
|
188
|
-
else
|
193
|
+
def search_index(feature)
|
194
|
+
try_index(feature + DOT_RB) ||
|
195
|
+
try_index(feature + DLEXT) ||
|
196
|
+
try_index(feature + DLEXT2) ||
|
189
197
|
try_index(feature)
|
190
|
-
end
|
191
198
|
end
|
192
199
|
|
193
200
|
def maybe_append_extension(feature)
|
@@ -197,12 +204,8 @@ module Bootsnap
|
|
197
204
|
feature
|
198
205
|
end
|
199
206
|
else
|
200
|
-
def search_index(feature
|
201
|
-
|
202
|
-
try_index(feature + DOT_RB) || try_index(feature + DLEXT) || try_index(feature)
|
203
|
-
else
|
204
|
-
try_index(feature)
|
205
|
-
end
|
207
|
+
def search_index(feature)
|
208
|
+
try_index(feature + DOT_RB) || try_index(feature + DLEXT) || try_index(feature)
|
206
209
|
end
|
207
210
|
|
208
211
|
def maybe_append_extension(feature)
|
@@ -212,7 +215,7 @@ module Bootsnap
|
|
212
215
|
|
213
216
|
s = rand.to_s.force_encoding(Encoding::US_ASCII).freeze
|
214
217
|
if s.respond_to?(:-@)
|
215
|
-
if (-s).equal?(s) && (-s.dup).equal?(s) || RUBY_VERSION >= "2.7"
|
218
|
+
if ((-s).equal?(s) && (-s.dup).equal?(s)) || RUBY_VERSION >= "2.7"
|
216
219
|
def try_index(feature)
|
217
220
|
if (path = @index[feature])
|
218
221
|
-File.join(path, feature).freeze
|
@@ -54,13 +54,30 @@ module Bootsnap
|
|
54
54
|
ret
|
55
55
|
end
|
56
56
|
end
|
57
|
+
|
58
|
+
def dup
|
59
|
+
[] + self
|
60
|
+
end
|
61
|
+
|
62
|
+
alias_method :clone, :dup
|
57
63
|
end
|
58
64
|
|
59
|
-
def self.register(
|
65
|
+
def self.register(arr, observer)
|
60
66
|
return if arr.frozen? # can't register observer, but no need to.
|
61
67
|
|
62
68
|
arr.instance_variable_set(:@lpc_observer, observer)
|
63
|
-
|
69
|
+
ArrayMixin.instance_methods.each do |method_name|
|
70
|
+
arr.singleton_class.send(:define_method, method_name, ArrayMixin.instance_method(method_name))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.unregister(arr)
|
75
|
+
return unless arr.instance_variable_defined?(:@lpc_observer) && arr.instance_variable_get(:@lpc_observer)
|
76
|
+
|
77
|
+
ArrayMixin.instance_methods.each do |method_name|
|
78
|
+
arr.singleton_class.send(:remove_method, method_name)
|
79
|
+
end
|
80
|
+
arr.instance_variable_set(:@lpc_observer, nil)
|
64
81
|
end
|
65
82
|
end
|
66
83
|
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Kernel
|
4
|
-
|
4
|
+
alias_method :require_without_bootsnap, :require
|
5
5
|
|
6
|
-
alias_method
|
6
|
+
alias_method :require, :require # Avoid method redefinition warnings
|
7
7
|
|
8
|
-
def require(path)
|
9
|
-
|
8
|
+
def require(path) # rubocop:disable Lint/DuplicateMethods
|
9
|
+
return require_without_bootsnap(path) unless Bootsnap::LoadPathCache.enabled?
|
10
|
+
|
11
|
+
string_path = Bootsnap.rb_get_path(path)
|
10
12
|
return false if Bootsnap::LoadPathCache.loaded_features_index.key?(string_path)
|
11
13
|
|
12
14
|
resolved = Bootsnap::LoadPathCache.load_path_cache.find(string_path)
|
@@ -22,9 +24,7 @@ module Kernel
|
|
22
24
|
elsif false == resolved
|
23
25
|
return false
|
24
26
|
elsif resolved.nil?
|
25
|
-
|
26
|
-
error.instance_variable_set(:@path, path)
|
27
|
-
raise error
|
27
|
+
return require_without_bootsnap(path)
|
28
28
|
else
|
29
29
|
# Note that require registers to $LOADED_FEATURES while load does not.
|
30
30
|
ret = require_without_bootsnap(resolved)
|
@@ -33,42 +33,5 @@ module Kernel
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
def require_relative(path)
|
38
|
-
location = caller_locations(1..1).first
|
39
|
-
realpath = Bootsnap::LoadPathCache.realpath_cache.call(
|
40
|
-
location.absolute_path || location.path, path
|
41
|
-
)
|
42
|
-
require(realpath)
|
43
|
-
end
|
44
|
-
|
45
|
-
alias_method(:load_without_bootsnap, :load)
|
46
|
-
def load(path, wrap = false)
|
47
|
-
if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(path, try_extensions: false))
|
48
|
-
load_without_bootsnap(resolved, wrap)
|
49
|
-
else
|
50
|
-
load_without_bootsnap(path, wrap)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
class Module
|
56
|
-
alias_method(:autoload_without_bootsnap, :autoload)
|
57
|
-
def autoload(const, path)
|
58
|
-
# NOTE: This may defeat LoadedFeaturesIndex, but it's not immediately
|
59
|
-
# obvious how to make it work. This feels like a pretty niche case, unclear
|
60
|
-
# if it will ever burn anyone.
|
61
|
-
#
|
62
|
-
# The challenge is that we don't control the point at which the entry gets
|
63
|
-
# added to $LOADED_FEATURES and won't be able to hook that modification
|
64
|
-
# since it's done in C-land.
|
65
|
-
resolved = Bootsnap::LoadPathCache.load_path_cache.find(path)
|
66
|
-
if Bootsnap::LoadPathCache::FALLBACK_SCAN.equal?(resolved)
|
67
|
-
autoload_without_bootsnap(const, path)
|
68
|
-
elsif resolved == false
|
69
|
-
return false
|
70
|
-
else
|
71
|
-
autoload_without_bootsnap(const, resolved || path)
|
72
|
-
end
|
73
|
-
end
|
36
|
+
private :require
|
74
37
|
end
|
@@ -40,7 +40,7 @@ module Bootsnap
|
|
40
40
|
|
41
41
|
# /a/b/lib/my/foo.rb
|
42
42
|
# ^^^^^^^^^
|
43
|
-
short = feat[(lpe.length + 1)
|
43
|
+
short = feat[(lpe.length + 1)..]
|
44
44
|
stripped = strip_extension_if_elidable(short)
|
45
45
|
@lfi[short] = hash
|
46
46
|
@lfi[stripped] = hash
|
@@ -76,7 +76,7 @@ module Bootsnap
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def identify(short, cursor)
|
79
|
-
$LOADED_FEATURES[cursor
|
79
|
+
$LOADED_FEATURES[cursor..].detect do |feat|
|
80
80
|
offset = 0
|
81
81
|
while (offset = feat.index(short, offset))
|
82
82
|
if feat.index(".", offset + 1) && !feat.index("/", offset + 2)
|
@@ -142,7 +142,7 @@ module Bootsnap
|
|
142
142
|
# will _never_ run on MacOS, and therefore think they can get away
|
143
143
|
# with calling a Ruby file 'x.dylib.rb' and then requiring it as 'x.dylib'.)
|
144
144
|
#
|
145
|
-
# See <https://ruby-
|
145
|
+
# See <https://docs.ruby-lang.org/en/master/Kernel.html#method-i-require>.
|
146
146
|
def extension_elidable?(feature)
|
147
147
|
feature.to_s.end_with?(".rb", ".so", ".o", ".dll", ".dylib")
|
148
148
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "path_scanner"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module LoadPathCache
|
@@ -21,14 +21,32 @@ module Bootsnap
|
|
21
21
|
|
22
22
|
attr_reader(:path)
|
23
23
|
|
24
|
-
def initialize(path)
|
24
|
+
def initialize(path, real: false)
|
25
25
|
@path = path.to_s.freeze
|
26
|
+
@real = real
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_realpath
|
30
|
+
return self if @real
|
31
|
+
|
32
|
+
realpath = begin
|
33
|
+
File.realpath(path)
|
34
|
+
rescue Errno::ENOENT
|
35
|
+
return self
|
36
|
+
end
|
37
|
+
|
38
|
+
if realpath == path
|
39
|
+
@real = true
|
40
|
+
self
|
41
|
+
else
|
42
|
+
Path.new(realpath, real: true)
|
43
|
+
end
|
26
44
|
end
|
27
45
|
|
28
46
|
# True if the path exists, but represents a non-directory object
|
29
47
|
def non_directory?
|
30
48
|
!File.stat(path).directory?
|
31
|
-
rescue Errno::ENOENT, Errno::ENOTDIR
|
49
|
+
rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
|
32
50
|
false
|
33
51
|
end
|
34
52
|
|
@@ -62,7 +80,11 @@ module Bootsnap
|
|
62
80
|
end
|
63
81
|
|
64
82
|
def expanded_path
|
65
|
-
|
83
|
+
if @real
|
84
|
+
path
|
85
|
+
else
|
86
|
+
@expanded_path ||= File.expand_path(path).freeze
|
87
|
+
end
|
66
88
|
end
|
67
89
|
|
68
90
|
private
|
@@ -79,7 +101,7 @@ module Bootsnap
|
|
79
101
|
["", *dirs].each do |dir|
|
80
102
|
curr = begin
|
81
103
|
File.mtime("#{path}/#{dir}").to_i
|
82
|
-
rescue Errno::ENOENT, Errno::ENOTDIR
|
104
|
+
rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
|
83
105
|
-1
|
84
106
|
end
|
85
107
|
max = curr if curr > max
|
@@ -94,21 +116,19 @@ module Bootsnap
|
|
94
116
|
VOLATILE = :volatile
|
95
117
|
|
96
118
|
# Built-in ruby lib stuff doesn't change, but things can occasionally be
|
97
|
-
# installed into sitedir, which generally lives under
|
98
|
-
RUBY_LIBDIR = RbConfig::CONFIG["
|
119
|
+
# installed into sitedir, which generally lives under rubylibdir.
|
120
|
+
RUBY_LIBDIR = RbConfig::CONFIG["rubylibdir"]
|
99
121
|
RUBY_SITEDIR = RbConfig::CONFIG["sitedir"]
|
100
122
|
|
101
123
|
def stability
|
102
|
-
@stability ||=
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
VOLATILE
|
111
|
-
end
|
124
|
+
@stability ||= if Gem.path.detect { |p| expanded_path.start_with?(p.to_s) }
|
125
|
+
STABLE
|
126
|
+
elsif Bootsnap.bundler? && expanded_path.start_with?(Bundler.bundle_path.to_s)
|
127
|
+
STABLE
|
128
|
+
elsif expanded_path.start_with?(RUBY_LIBDIR) && !expanded_path.start_with?(RUBY_SITEDIR)
|
129
|
+
STABLE
|
130
|
+
else
|
131
|
+
VOLATILE
|
112
132
|
end
|
113
133
|
end
|
114
134
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../explicit_require"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module LoadPathCache
|
@@ -15,7 +15,11 @@ module Bootsnap
|
|
15
15
|
""
|
16
16
|
end
|
17
17
|
|
18
|
+
@ignored_directories = %w(node_modules)
|
19
|
+
|
18
20
|
class << self
|
21
|
+
attr_accessor :ignored_directories
|
22
|
+
|
19
23
|
def call(path)
|
20
24
|
path = File.expand_path(path.to_s).freeze
|
21
25
|
return [[], []] unless File.directory?(path)
|
@@ -50,6 +54,8 @@ module Bootsnap
|
|
50
54
|
|
51
55
|
absolute_path = "#{absolute_dir_path}/#{name}"
|
52
56
|
if File.directory?(absolute_path)
|
57
|
+
next if ignored_directories.include?(name) || ignored_directories.include?(absolute_path)
|
58
|
+
|
53
59
|
if yield relative_path, absolute_path, true
|
54
60
|
walk(absolute_path, relative_path, &block)
|
55
61
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../explicit_require"
|
4
4
|
|
5
|
-
Bootsnap::ExplicitRequire.with_gems("msgpack") { require
|
5
|
+
Bootsnap::ExplicitRequire.with_gems("msgpack") { require "msgpack" }
|
6
6
|
|
7
7
|
module Bootsnap
|
8
8
|
module LoadPathCache
|
@@ -13,10 +13,11 @@ module Bootsnap
|
|
13
13
|
NestedTransactionError = Class.new(StandardError)
|
14
14
|
SetOutsideTransactionNotAllowed = Class.new(StandardError)
|
15
15
|
|
16
|
-
def initialize(store_path)
|
16
|
+
def initialize(store_path, readonly: false)
|
17
17
|
@store_path = store_path
|
18
18
|
@txn_mutex = Mutex.new
|
19
19
|
@dirty = false
|
20
|
+
@readonly = readonly
|
20
21
|
load_data
|
21
22
|
end
|
22
23
|
|
@@ -29,8 +30,8 @@ module Bootsnap
|
|
29
30
|
|
30
31
|
v = get(key)
|
31
32
|
unless v
|
32
|
-
@dirty = true
|
33
33
|
v = yield
|
34
|
+
mark_for_mutation!
|
34
35
|
@data[key] = v
|
35
36
|
end
|
36
37
|
v
|
@@ -40,7 +41,7 @@ module Bootsnap
|
|
40
41
|
raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
|
41
42
|
|
42
43
|
if value != @data[key]
|
43
|
-
|
44
|
+
mark_for_mutation!
|
44
45
|
@data[key] = value
|
45
46
|
end
|
46
47
|
end
|
@@ -49,18 +50,21 @@ module Bootsnap
|
|
49
50
|
raise(NestedTransactionError) if @txn_mutex.owned?
|
50
51
|
|
51
52
|
@txn_mutex.synchronize do
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
commit_transaction
|
56
|
-
end
|
53
|
+
yield
|
54
|
+
ensure
|
55
|
+
commit_transaction
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
60
59
|
private
|
61
60
|
|
61
|
+
def mark_for_mutation!
|
62
|
+
@dirty = true
|
63
|
+
@data = @data.dup if @data.frozen?
|
64
|
+
end
|
65
|
+
|
62
66
|
def commit_transaction
|
63
|
-
if @dirty
|
67
|
+
if @dirty && !@readonly
|
64
68
|
dump_data
|
65
69
|
@dirty = false
|
66
70
|
end
|
@@ -69,7 +73,7 @@ module Bootsnap
|
|
69
73
|
def load_data
|
70
74
|
@data = begin
|
71
75
|
data = File.open(@store_path, encoding: Encoding::BINARY) do |io|
|
72
|
-
MessagePack.load(io)
|
76
|
+
MessagePack.load(io, freeze: true)
|
73
77
|
end
|
74
78
|
if data.is_a?(Hash) && data[VERSION_KEY] == CURRENT_VERSION
|
75
79
|
data
|
@@ -89,19 +93,17 @@ module Bootsnap
|
|
89
93
|
end
|
90
94
|
|
91
95
|
def dump_data
|
92
|
-
require "fileutils" unless defined? FileUtils
|
93
|
-
|
94
96
|
# Change contents atomically so other processes can't get invalid
|
95
97
|
# caches if they read at an inopportune time.
|
96
98
|
tmp = "#{@store_path}.#{Process.pid}.#{(rand * 100_000).to_i}.tmp"
|
97
|
-
|
99
|
+
mkdir_p(File.dirname(tmp))
|
98
100
|
exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY
|
99
101
|
# `encoding:` looks redundant wrt `binwrite`, but necessary on windows
|
100
102
|
# because binary is part of mode.
|
101
103
|
File.open(tmp, mode: exclusive_write, encoding: Encoding::BINARY) do |io|
|
102
|
-
MessagePack.dump(@data, io
|
104
|
+
MessagePack.dump(@data, io)
|
103
105
|
end
|
104
|
-
|
106
|
+
File.rename(tmp, @store_path)
|
105
107
|
rescue Errno::EEXIST
|
106
108
|
retry
|
107
109
|
rescue SystemCallError
|
@@ -110,6 +112,21 @@ module Bootsnap
|
|
110
112
|
def default_data
|
111
113
|
{VERSION_KEY => CURRENT_VERSION}
|
112
114
|
end
|
115
|
+
|
116
|
+
def mkdir_p(path)
|
117
|
+
stack = []
|
118
|
+
until File.directory?(path)
|
119
|
+
stack.push path
|
120
|
+
path = File.dirname(path)
|
121
|
+
end
|
122
|
+
stack.reverse_each do |dir|
|
123
|
+
Dir.mkdir(dir)
|
124
|
+
rescue SystemCallError
|
125
|
+
# Check for broken symlinks. Calling File.realpath will raise Errno::ENOENT if that is the case
|
126
|
+
File.realpath(dir) if File.symlink?(dir)
|
127
|
+
raise unless File.directory?(dir)
|
128
|
+
end
|
129
|
+
end
|
113
130
|
end
|
114
131
|
end
|
115
132
|
end
|
@@ -21,39 +21,60 @@ module Bootsnap
|
|
21
21
|
|
22
22
|
CACHED_EXTENSIONS = DLEXT2 ? [DOT_RB, DLEXT, DLEXT2] : [DOT_RB, DLEXT]
|
23
23
|
|
24
|
+
@enabled = false
|
25
|
+
|
24
26
|
class << self
|
25
|
-
attr_reader(:load_path_cache, :loaded_features_index, :
|
27
|
+
attr_reader(:load_path_cache, :loaded_features_index, :enabled)
|
28
|
+
alias_method :enabled?, :enabled
|
29
|
+
remove_method(:enabled)
|
26
30
|
|
27
|
-
def setup(cache_path:, development_mode:)
|
31
|
+
def setup(cache_path:, development_mode:, ignore_directories:, readonly: false)
|
28
32
|
unless supported?
|
29
33
|
warn("[bootsnap/setup] Load path caching is not supported on this implementation of Ruby") if $VERBOSE
|
30
34
|
return
|
31
35
|
end
|
32
36
|
|
33
|
-
store = Store.new(cache_path)
|
37
|
+
store = Store.new(cache_path, readonly: readonly)
|
34
38
|
|
35
39
|
@loaded_features_index = LoadedFeaturesIndex.new
|
36
|
-
@realpath_cache = RealpathCache.new
|
37
40
|
|
41
|
+
PathScanner.ignored_directories = ignore_directories if ignore_directories
|
38
42
|
@load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
|
39
|
-
|
40
|
-
require_relative
|
43
|
+
@enabled = true
|
44
|
+
require_relative "load_path_cache/core_ext/kernel_require"
|
45
|
+
require_relative "load_path_cache/core_ext/loaded_features"
|
46
|
+
end
|
47
|
+
|
48
|
+
def unload!
|
49
|
+
@enabled = false
|
50
|
+
@loaded_features_index = nil
|
51
|
+
@realpath_cache = nil
|
52
|
+
@load_path_cache = nil
|
53
|
+
ChangeObserver.unregister($LOAD_PATH) if supported?
|
41
54
|
end
|
42
55
|
|
43
56
|
def supported?
|
44
|
-
|
45
|
-
|
57
|
+
if RUBY_PLATFORM.match?(/darwin|linux|bsd|mswin|mingw|cygwin/)
|
58
|
+
case RUBY_ENGINE
|
59
|
+
when "truffleruby"
|
60
|
+
# https://github.com/oracle/truffleruby/issues/3131
|
61
|
+
RUBY_ENGINE_VERSION >= "23.1.0"
|
62
|
+
when "ruby"
|
63
|
+
true
|
64
|
+
else
|
65
|
+
false
|
66
|
+
end
|
67
|
+
end
|
46
68
|
end
|
47
69
|
end
|
48
70
|
end
|
49
71
|
end
|
50
72
|
|
51
73
|
if Bootsnap::LoadPathCache.supported?
|
52
|
-
require_relative
|
53
|
-
require_relative
|
54
|
-
require_relative
|
55
|
-
require_relative
|
56
|
-
require_relative
|
57
|
-
require_relative
|
58
|
-
require_relative("load_path_cache/realpath_cache")
|
74
|
+
require_relative "load_path_cache/path_scanner"
|
75
|
+
require_relative "load_path_cache/path"
|
76
|
+
require_relative "load_path_cache/cache"
|
77
|
+
require_relative "load_path_cache/store"
|
78
|
+
require_relative "load_path_cache/change_observer"
|
79
|
+
require_relative "load_path_cache/loaded_features_index"
|
59
80
|
end
|
data/lib/bootsnap/setup.rb
CHANGED
data/lib/bootsnap/version.rb
CHANGED