bootsnap 1.11.1 → 1.18.3
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 +76 -0
- data/README.md +19 -10
- data/ext/bootsnap/bootsnap.c +253 -112
- data/ext/bootsnap/extconf.rb +20 -13
- data/lib/bootsnap/bundler.rb +1 -1
- data/lib/bootsnap/cli.rb +18 -16
- data/lib/bootsnap/compile_cache/iseq.rb +14 -8
- 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 -15
- data/lib/bootsnap/load_path_cache/cache.rb +20 -21
- data/lib/bootsnap/load_path_cache/change_observer.rb +19 -2
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +7 -35
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +2 -2
- data/lib/bootsnap/load_path_cache/path.rb +16 -18
- data/lib/bootsnap/load_path_cache/path_scanner.rb +7 -1
- data/lib/bootsnap/load_path_cache/store.rb +11 -14
- data/lib/bootsnap/load_path_cache.rb +36 -13
- data/lib/bootsnap/setup.rb +1 -1
- data/lib/bootsnap/version.rb +1 -1
- data/lib/bootsnap.rb +36 -32
- metadata +4 -4
data/ext/bootsnap/extconf.rb
CHANGED
@@ -1,26 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "mkmf"
|
4
4
|
|
5
|
-
if RUBY_ENGINE
|
6
|
-
|
7
|
-
|
5
|
+
if %w[ruby truffleruby].include?(RUBY_ENGINE)
|
6
|
+
have_func "fdatasync", "unistd.h"
|
7
|
+
|
8
|
+
unless RUBY_PLATFORM.match?(/mswin|mingw|cygwin/)
|
9
|
+
append_cppflags ["-D_GNU_SOURCE"] # Needed of O_NOATIME
|
10
|
+
end
|
11
|
+
|
12
|
+
append_cflags ["-O3", "-std=c99"]
|
8
13
|
|
9
14
|
# ruby.h has some -Wpedantic fails in some cases
|
10
15
|
# (e.g. https://github.com/Shopify/bootsnap/issues/15)
|
11
16
|
unless ["0", "", nil].include?(ENV["BOOTSNAP_PEDANTIC"])
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
17
|
+
append_cflags([
|
18
|
+
"-Wall",
|
19
|
+
"-Werror",
|
20
|
+
"-Wextra",
|
21
|
+
"-Wpedantic",
|
16
22
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
23
|
+
"-Wno-unused-parameter", # VALUE self has to be there but we don't care what it is.
|
24
|
+
"-Wno-keyword-macro", # hiding return
|
25
|
+
"-Wno-gcc-compat", # ruby.h 2.6.0 on macos 10.14, dunno
|
26
|
+
"-Wno-compound-token-split-by-macro",
|
27
|
+
])
|
21
28
|
end
|
22
29
|
|
23
30
|
create_makefile("bootsnap/bootsnap")
|
24
31
|
else
|
25
|
-
File.write("Makefile", dummy_makefile($srcdir).join
|
32
|
+
File.write("Makefile", dummy_makefile($srcdir).join)
|
26
33
|
end
|
data/lib/bootsnap/bundler.rb
CHANGED
data/lib/bootsnap/cli.rb
CHANGED
@@ -60,14 +60,16 @@ module Bootsnap
|
|
60
60
|
precompile_json_files(main_sources)
|
61
61
|
|
62
62
|
if compile_gemfile
|
63
|
-
# Some gems embed their tests, they're very unlikely to be loaded, so not worth precompiling.
|
64
|
-
gem_exclude = Regexp.union([exclude, "/spec/", "/test/"].compact)
|
65
|
-
precompile_ruby_files($LOAD_PATH.map { |d| File.expand_path(d) }, exclude: gem_exclude)
|
66
|
-
|
67
63
|
# Gems that include JSON or YAML files usually don't put them in `lib/`.
|
68
64
|
# So we look at the gem root.
|
69
|
-
|
70
|
-
|
65
|
+
# Similarly, gems that include Rails engines generally file Ruby files in `app/`.
|
66
|
+
# However some gems embed their tests, they're very unlikely to be loaded, so not worth precompiling.
|
67
|
+
gem_exclude = Regexp.union([exclude, "/spec/", "/test/", "/features/"].compact)
|
68
|
+
|
69
|
+
gem_pattern = %r{^#{Regexp.escape(Bundler.bundle_path.to_s)}/?(?:bundler/)?gems/[^/]+}
|
70
|
+
gem_paths = $LOAD_PATH.map { |p| p[gem_pattern] || p }.uniq
|
71
|
+
|
72
|
+
precompile_ruby_files(gem_paths, exclude: gem_exclude)
|
71
73
|
precompile_yaml_files(gem_paths, exclude: gem_exclude)
|
72
74
|
precompile_json_files(gem_paths, exclude: gem_exclude)
|
73
75
|
end
|
@@ -138,8 +140,8 @@ module Bootsnap
|
|
138
140
|
|
139
141
|
def precompile_yaml(*yaml_files)
|
140
142
|
Array(yaml_files).each do |yaml_file|
|
141
|
-
if CompileCache::YAML.precompile(yaml_file)
|
142
|
-
|
143
|
+
if CompileCache::YAML.precompile(yaml_file) && verbose
|
144
|
+
$stderr.puts(yaml_file)
|
143
145
|
end
|
144
146
|
end
|
145
147
|
end
|
@@ -161,8 +163,8 @@ module Bootsnap
|
|
161
163
|
|
162
164
|
def precompile_json(*json_files)
|
163
165
|
Array(json_files).each do |json_file|
|
164
|
-
if CompileCache::JSON.precompile(json_file)
|
165
|
-
|
166
|
+
if CompileCache::JSON.precompile(json_file) && verbose
|
167
|
+
$stderr.puts(json_file)
|
166
168
|
end
|
167
169
|
end
|
168
170
|
end
|
@@ -172,7 +174,7 @@ module Bootsnap
|
|
172
174
|
|
173
175
|
load_paths.each do |path|
|
174
176
|
if !exclude || !exclude.match?(path)
|
175
|
-
list_files(path, "
|
177
|
+
list_files(path, "**/{*.rb,*.rake,Rakefile}").each do |ruby_file|
|
176
178
|
if !exclude || !exclude.match?(ruby_file)
|
177
179
|
@work_pool.push(:ruby, ruby_file)
|
178
180
|
end
|
@@ -183,8 +185,8 @@ module Bootsnap
|
|
183
185
|
|
184
186
|
def precompile_ruby(*ruby_files)
|
185
187
|
Array(ruby_files).each do |ruby_file|
|
186
|
-
if CompileCache::ISeq.precompile(ruby_file)
|
187
|
-
|
188
|
+
if CompileCache::ISeq.precompile(ruby_file) && verbose
|
189
|
+
$stderr.puts(ruby_file)
|
188
190
|
end
|
189
191
|
end
|
190
192
|
end
|
@@ -203,9 +205,9 @@ module Bootsnap
|
|
203
205
|
end
|
204
206
|
|
205
207
|
def invalid_usage!(message)
|
206
|
-
|
207
|
-
|
208
|
-
|
208
|
+
$stderr.puts message
|
209
|
+
$stderr.puts
|
210
|
+
$stderr.puts parser
|
209
211
|
1
|
210
212
|
end
|
211
213
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "bootsnap/bootsnap"
|
4
|
+
require "zlib"
|
5
5
|
|
6
6
|
module Bootsnap
|
7
7
|
module CompileCache
|
@@ -12,6 +12,10 @@ module Bootsnap
|
|
12
12
|
def cache_dir=(cache_dir)
|
13
13
|
@cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}iseq" : "#{cache_dir}-iseq"
|
14
14
|
end
|
15
|
+
|
16
|
+
def supported?
|
17
|
+
CompileCache.supported? && defined?(RubyVM)
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
has_ruby_bug_18250 = begin # https://bugs.ruby-lang.org/issues/18250
|
@@ -34,14 +38,14 @@ module Bootsnap
|
|
34
38
|
begin
|
35
39
|
iseq.to_binary
|
36
40
|
rescue TypeError
|
37
|
-
|
41
|
+
UNCOMPILABLE # ruby bug #18250
|
38
42
|
end
|
39
43
|
end
|
40
44
|
else
|
41
45
|
def self.input_to_storage(_, path)
|
42
46
|
RubyVM::InstructionSequence.compile_file(path).to_binary
|
43
47
|
rescue SyntaxError
|
44
|
-
|
48
|
+
UNCOMPILABLE # syntax error
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
@@ -49,7 +53,7 @@ module Bootsnap
|
|
49
53
|
RubyVM::InstructionSequence.load_from_binary(binary)
|
50
54
|
rescue RuntimeError => error
|
51
55
|
if error.message == "broken binary format"
|
52
|
-
|
56
|
+
$stderr.puts("[Bootsnap::CompileCache] warning: rejecting broken binary")
|
53
57
|
nil
|
54
58
|
else
|
55
59
|
raise
|
@@ -83,8 +87,6 @@ module Bootsnap
|
|
83
87
|
return nil if defined?(Coverage) && Bootsnap::CompileCache::Native.coverage_running?
|
84
88
|
|
85
89
|
Bootsnap::CompileCache::ISeq.fetch(path.to_s)
|
86
|
-
rescue Errno::EACCES
|
87
|
-
Bootsnap::CompileCache.permission_error(path)
|
88
90
|
rescue RuntimeError => error
|
89
91
|
if error.message =~ /unmatched platform/
|
90
92
|
puts("unmatched platform for file #{path}")
|
@@ -103,11 +105,15 @@ module Bootsnap
|
|
103
105
|
crc = Zlib.crc32(option.inspect)
|
104
106
|
Bootsnap::CompileCache::Native.compile_option_crc32 = crc
|
105
107
|
end
|
106
|
-
compile_option_updated
|
108
|
+
compile_option_updated if supported?
|
107
109
|
|
108
110
|
def self.install!(cache_dir)
|
109
111
|
Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
|
112
|
+
|
113
|
+
return unless supported?
|
114
|
+
|
110
115
|
Bootsnap::CompileCache::ISeq.compile_option_updated
|
116
|
+
|
111
117
|
class << RubyVM::InstructionSequence
|
112
118
|
prepend(InstructionSequenceMixin)
|
113
119
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "bootsnap/bootsnap"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module CompileCache
|
@@ -46,18 +46,23 @@ module Bootsnap
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def init!
|
49
|
-
require
|
50
|
-
require
|
49
|
+
require "json"
|
50
|
+
require "msgpack"
|
51
51
|
|
52
52
|
self.msgpack_factory = MessagePack::Factory.new
|
53
53
|
self.supported_options = [:symbolize_names]
|
54
|
-
if
|
55
|
-
|
56
|
-
self.supported_options = [:freeze]
|
57
|
-
end
|
54
|
+
if supports_freeze?
|
55
|
+
self.supported_options = [:freeze]
|
58
56
|
end
|
59
57
|
supported_options.freeze
|
60
58
|
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def supports_freeze?
|
63
|
+
::JSON.parse('["foo"]', freeze: true).first.frozen? &&
|
64
|
+
MessagePack.load(MessagePack.dump("foo"), freeze: true).frozen?
|
65
|
+
end
|
61
66
|
end
|
62
67
|
|
63
68
|
module Patch
|
@@ -69,16 +74,12 @@ module Bootsnap
|
|
69
74
|
return super unless (kwargs.keys - ::Bootsnap::CompileCache::JSON.supported_options).empty?
|
70
75
|
end
|
71
76
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
)
|
79
|
-
rescue Errno::EACCES
|
80
|
-
::Bootsnap::CompileCache.permission_error(path)
|
81
|
-
end
|
77
|
+
::Bootsnap::CompileCache::Native.fetch(
|
78
|
+
Bootsnap::CompileCache::JSON.cache_dir,
|
79
|
+
File.realpath(path),
|
80
|
+
::Bootsnap::CompileCache::JSON,
|
81
|
+
kwargs,
|
82
|
+
)
|
82
83
|
end
|
83
84
|
|
84
85
|
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "bootsnap/bootsnap"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module CompileCache
|
@@ -55,15 +55,28 @@ module Bootsnap
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def init!
|
58
|
-
require
|
59
|
-
require
|
60
|
-
require
|
58
|
+
require "yaml"
|
59
|
+
require "msgpack"
|
60
|
+
require "date"
|
61
61
|
|
62
62
|
@implementation = ::YAML::VERSION >= "4" ? Psych4 : Psych3
|
63
63
|
if @implementation::Patch.method_defined?(:unsafe_load_file) && !::YAML.respond_to?(:unsafe_load_file)
|
64
64
|
@implementation::Patch.send(:remove_method, :unsafe_load_file)
|
65
65
|
end
|
66
66
|
|
67
|
+
unless const_defined?(:NoTagsVisitor)
|
68
|
+
visitor = Class.new(Psych::Visitors::NoAliasRuby) do
|
69
|
+
def visit(target)
|
70
|
+
if target.tag
|
71
|
+
raise UnsupportedTags, "YAML tags are not supported: #{target.tag}"
|
72
|
+
end
|
73
|
+
|
74
|
+
super
|
75
|
+
end
|
76
|
+
end
|
77
|
+
const_set(:NoTagsVisitor, visitor)
|
78
|
+
end
|
79
|
+
|
67
80
|
# MessagePack serializes symbols as strings by default.
|
68
81
|
# We want them to roundtrip cleanly, so we use a custom factory.
|
69
82
|
# see: https://github.com/msgpack/msgpack-ruby/pull/122
|
@@ -102,10 +115,8 @@ module Bootsnap
|
|
102
115
|
if params.include?([:key, :symbolize_names])
|
103
116
|
supported_options << :symbolize_names
|
104
117
|
end
|
105
|
-
if params.include?([:key, :freeze])
|
106
|
-
|
107
|
-
supported_options << :freeze
|
108
|
-
end
|
118
|
+
if params.include?([:key, :freeze]) && factory.load(factory.dump("yaml"), freeze: true).frozen?
|
119
|
+
supported_options << :freeze
|
109
120
|
end
|
110
121
|
supported_options.freeze
|
111
122
|
end
|
@@ -118,19 +129,10 @@ module Bootsnap
|
|
118
129
|
ast = ::YAML.parse(payload)
|
119
130
|
return ast unless ast
|
120
131
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
def strict_visitor
|
125
|
-
self::NoTagsVisitor ||= Class.new(Psych::Visitors::ToRuby) do
|
126
|
-
def visit(target)
|
127
|
-
if target.tag
|
128
|
-
raise UnsupportedTags, "YAML tags are not supported: #{target.tag}"
|
129
|
-
end
|
132
|
+
loader = ::Psych::ClassLoader::Restricted.new(["Symbol"], [])
|
133
|
+
scanner = ::Psych::ScalarScanner.new(loader)
|
130
134
|
|
131
|
-
|
132
|
-
end
|
133
|
-
end
|
135
|
+
NoTagsVisitor.new(scanner, loader).visit(ast)
|
134
136
|
end
|
135
137
|
end
|
136
138
|
|
@@ -227,16 +229,12 @@ module Bootsnap
|
|
227
229
|
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
228
230
|
end
|
229
231
|
|
230
|
-
|
231
|
-
CompileCache::
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
)
|
237
|
-
rescue Errno::EACCES
|
238
|
-
CompileCache.permission_error(path)
|
239
|
-
end
|
232
|
+
CompileCache::Native.fetch(
|
233
|
+
CompileCache::YAML.cache_dir,
|
234
|
+
File.realpath(path),
|
235
|
+
CompileCache::YAML::Psych4::SafeLoad,
|
236
|
+
kwargs,
|
237
|
+
)
|
240
238
|
end
|
241
239
|
|
242
240
|
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
@@ -251,16 +249,12 @@ module Bootsnap
|
|
251
249
|
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
252
250
|
end
|
253
251
|
|
254
|
-
|
255
|
-
CompileCache::
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
)
|
261
|
-
rescue Errno::EACCES
|
262
|
-
CompileCache.permission_error(path)
|
263
|
-
end
|
252
|
+
CompileCache::Native.fetch(
|
253
|
+
CompileCache::YAML.cache_dir,
|
254
|
+
File.realpath(path),
|
255
|
+
CompileCache::YAML::Psych4::UnsafeLoad,
|
256
|
+
kwargs,
|
257
|
+
)
|
264
258
|
end
|
265
259
|
|
266
260
|
ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
|
@@ -307,16 +301,12 @@ module Bootsnap
|
|
307
301
|
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
308
302
|
end
|
309
303
|
|
310
|
-
|
311
|
-
CompileCache::
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
)
|
317
|
-
rescue Errno::EACCES
|
318
|
-
CompileCache.permission_error(path)
|
319
|
-
end
|
304
|
+
CompileCache::Native.fetch(
|
305
|
+
CompileCache::YAML.cache_dir,
|
306
|
+
File.realpath(path),
|
307
|
+
CompileCache::YAML::Psych3,
|
308
|
+
kwargs,
|
309
|
+
)
|
320
310
|
end
|
321
311
|
|
322
312
|
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
@@ -331,16 +321,12 @@ module Bootsnap
|
|
331
321
|
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
332
322
|
end
|
333
323
|
|
334
|
-
|
335
|
-
CompileCache::
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
)
|
341
|
-
rescue Errno::EACCES
|
342
|
-
CompileCache.permission_error(path)
|
343
|
-
end
|
324
|
+
CompileCache::Native.fetch(
|
325
|
+
CompileCache::YAML.cache_dir,
|
326
|
+
File.realpath(path),
|
327
|
+
CompileCache::YAML::Psych3,
|
328
|
+
kwargs,
|
329
|
+
)
|
344
330
|
end
|
345
331
|
|
346
332
|
ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
|
@@ -8,12 +8,11 @@ module Bootsnap
|
|
8
8
|
end
|
9
9
|
|
10
10
|
Error = Class.new(StandardError)
|
11
|
-
PermissionError = Class.new(Error)
|
12
11
|
|
13
|
-
def self.setup(cache_dir:, iseq:, yaml:, json:)
|
12
|
+
def self.setup(cache_dir:, iseq:, yaml:, json:, readonly: false, revalidation: false)
|
14
13
|
if iseq
|
15
14
|
if supported?
|
16
|
-
require_relative
|
15
|
+
require_relative "compile_cache/iseq"
|
17
16
|
Bootsnap::CompileCache::ISeq.install!(cache_dir)
|
18
17
|
elsif $VERBOSE
|
19
18
|
warn("[bootsnap/setup] bytecode caching is not supported on this implementation of Ruby")
|
@@ -22,7 +21,7 @@ module Bootsnap
|
|
22
21
|
|
23
22
|
if yaml
|
24
23
|
if supported?
|
25
|
-
require_relative
|
24
|
+
require_relative "compile_cache/yaml"
|
26
25
|
Bootsnap::CompileCache::YAML.install!(cache_dir)
|
27
26
|
elsif $VERBOSE
|
28
27
|
warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
|
@@ -31,26 +30,23 @@ module Bootsnap
|
|
31
30
|
|
32
31
|
if json
|
33
32
|
if supported?
|
34
|
-
require_relative
|
33
|
+
require_relative "compile_cache/json"
|
35
34
|
Bootsnap::CompileCache::JSON.install!(cache_dir)
|
36
35
|
elsif $VERBOSE
|
37
36
|
warn("[bootsnap/setup] JSON parsing caching is not supported on this implementation of Ruby")
|
38
37
|
end
|
39
38
|
end
|
40
|
-
end
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
"bootsnap doesn't have permission to write cache entries in '#{cpath}' " \
|
47
|
-
"(or, less likely, doesn't have permission to read '#{path}')",
|
48
|
-
)
|
40
|
+
if supported? && defined?(Bootsnap::CompileCache::Native)
|
41
|
+
Bootsnap::CompileCache::Native.readonly = readonly
|
42
|
+
Bootsnap::CompileCache::Native.revalidation = revalidation
|
43
|
+
end
|
49
44
|
end
|
50
45
|
|
51
46
|
def self.supported?
|
52
|
-
# only enable on 'ruby' (MRI)
|
53
|
-
|
47
|
+
# only enable on 'ruby' (MRI) and TruffleRuby for POSIX (darwin, linux, *bsd), Windows (RubyInstaller2)
|
48
|
+
%w[ruby truffleruby].include?(RUBY_ENGINE) &&
|
49
|
+
RUBY_PLATFORM.match?(/darwin|linux|bsd|mswin|mingw|cygwin/)
|
54
50
|
end
|
55
51
|
end
|
56
52
|
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
|
@@ -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
|
@@ -183,15 +190,11 @@ module Bootsnap
|
|
183
190
|
end
|
184
191
|
|
185
192
|
if DLEXT2
|
186
|
-
def search_index(feature
|
187
|
-
|
188
|
-
try_index(feature +
|
189
|
-
|
190
|
-
try_index(feature + DLEXT2) ||
|
191
|
-
try_index(feature)
|
192
|
-
else
|
193
|
+
def search_index(feature)
|
194
|
+
try_index(feature + DOT_RB) ||
|
195
|
+
try_index(feature + DLEXT) ||
|
196
|
+
try_index(feature + DLEXT2) ||
|
193
197
|
try_index(feature)
|
194
|
-
end
|
195
198
|
end
|
196
199
|
|
197
200
|
def maybe_append_extension(feature)
|
@@ -201,12 +204,8 @@ module Bootsnap
|
|
201
204
|
feature
|
202
205
|
end
|
203
206
|
else
|
204
|
-
def search_index(feature
|
205
|
-
|
206
|
-
try_index(feature + DOT_RB) || try_index(feature + DLEXT) || try_index(feature)
|
207
|
-
else
|
208
|
-
try_index(feature)
|
209
|
-
end
|
207
|
+
def search_index(feature)
|
208
|
+
try_index(feature + DOT_RB) || try_index(feature + DLEXT) || try_index(feature)
|
210
209
|
end
|
211
210
|
|
212
211
|
def maybe_append_extension(feature)
|
@@ -216,7 +215,7 @@ module Bootsnap
|
|
216
215
|
|
217
216
|
s = rand.to_s.force_encoding(Encoding::US_ASCII).freeze
|
218
217
|
if s.respond_to?(:-@)
|
219
|
-
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"
|
220
219
|
def try_index(feature)
|
221
220
|
if (path = @index[feature])
|
222
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
|