bootsnap 1.8.1 → 1.10.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 +78 -3
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/exe/bootsnap +1 -1
- data/ext/bootsnap/bootsnap.c +39 -37
- data/ext/bootsnap/extconf.rb +13 -11
- data/lib/bootsnap/bundler.rb +1 -0
- data/lib/bootsnap/cli/worker_pool.rb +1 -0
- data/lib/bootsnap/cli.rb +78 -43
- data/lib/bootsnap/compile_cache/iseq.rb +42 -12
- data/lib/bootsnap/compile_cache/json.rb +88 -0
- data/lib/bootsnap/compile_cache/yaml.rb +264 -77
- data/lib/bootsnap/compile_cache.rb +22 -7
- data/lib/bootsnap/explicit_require.rb +4 -3
- data/lib/bootsnap/load_path_cache/cache.rb +57 -41
- data/lib/bootsnap/load_path_cache/change_observer.rb +2 -0
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +33 -65
- data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +1 -0
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +32 -21
- data/lib/bootsnap/load_path_cache/path.rb +5 -3
- data/lib/bootsnap/load_path_cache/path_scanner.rb +6 -5
- data/lib/bootsnap/load_path_cache/realpath_cache.rb +1 -0
- data/lib/bootsnap/load_path_cache/store.rb +24 -7
- data/lib/bootsnap/load_path_cache.rb +16 -22
- data/lib/bootsnap/setup.rb +2 -1
- data/lib/bootsnap/version.rb +2 -1
- data/lib/bootsnap.rb +103 -89
- metadata +6 -75
@@ -1,24 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require(
|
2
|
+
|
3
|
+
require("bootsnap/bootsnap")
|
4
|
+
require("zlib")
|
4
5
|
|
5
6
|
module Bootsnap
|
6
7
|
module CompileCache
|
7
8
|
module ISeq
|
8
9
|
class << self
|
9
|
-
|
10
|
+
attr_reader(:cache_dir)
|
11
|
+
|
12
|
+
def cache_dir=(cache_dir)
|
13
|
+
@cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}iseq" : "#{cache_dir}-iseq"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
has_ruby_bug_18250 = begin # https://bugs.ruby-lang.org/issues/18250
|
18
|
+
if defined? RubyVM::InstructionSequence
|
19
|
+
RubyVM::InstructionSequence.compile("def foo(*); ->{ super }; end; def foo(**); ->{ super }; end").to_binary
|
20
|
+
end
|
21
|
+
false
|
22
|
+
rescue TypeError
|
23
|
+
true
|
10
24
|
end
|
11
25
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
26
|
+
if has_ruby_bug_18250
|
27
|
+
def self.input_to_storage(_, path)
|
28
|
+
iseq = begin
|
29
|
+
RubyVM::InstructionSequence.compile_file(path)
|
30
|
+
rescue SyntaxError
|
31
|
+
return UNCOMPILABLE # syntax error
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
iseq.to_binary
|
36
|
+
rescue TypeError
|
37
|
+
return UNCOMPILABLE # ruby bug #18250
|
38
|
+
end
|
39
|
+
end
|
40
|
+
else
|
41
|
+
def self.input_to_storage(_, path)
|
42
|
+
RubyVM::InstructionSequence.compile_file(path).to_binary
|
43
|
+
rescue SyntaxError
|
44
|
+
return UNCOMPILABLE # syntax error
|
45
|
+
end
|
16
46
|
end
|
17
47
|
|
18
48
|
def self.storage_to_output(binary, _args)
|
19
49
|
RubyVM::InstructionSequence.load_from_binary(binary)
|
20
|
-
rescue RuntimeError =>
|
21
|
-
if
|
50
|
+
rescue RuntimeError => error
|
51
|
+
if error.message == "broken binary format"
|
22
52
|
STDERR.puts("[Bootsnap::CompileCache] warning: rejecting broken binary")
|
23
53
|
nil
|
24
54
|
else
|
@@ -35,7 +65,7 @@ module Bootsnap
|
|
35
65
|
)
|
36
66
|
end
|
37
67
|
|
38
|
-
def self.precompile(path
|
68
|
+
def self.precompile(path)
|
39
69
|
Bootsnap::CompileCache::Native.precompile(
|
40
70
|
cache_dir,
|
41
71
|
path.to_s,
|
@@ -55,8 +85,8 @@ module Bootsnap
|
|
55
85
|
Bootsnap::CompileCache::ISeq.fetch(path.to_s)
|
56
86
|
rescue Errno::EACCES
|
57
87
|
Bootsnap::CompileCache.permission_error(path)
|
58
|
-
rescue RuntimeError =>
|
59
|
-
if
|
88
|
+
rescue RuntimeError => error
|
89
|
+
if error.message =~ /unmatched platform/
|
60
90
|
puts("unmatched platform for file #{path}")
|
61
91
|
end
|
62
92
|
raise
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require("bootsnap/bootsnap")
|
4
|
+
|
5
|
+
module Bootsnap
|
6
|
+
module CompileCache
|
7
|
+
module JSON
|
8
|
+
class << self
|
9
|
+
attr_accessor(:msgpack_factory, :supported_options)
|
10
|
+
attr_reader(:cache_dir)
|
11
|
+
|
12
|
+
def cache_dir=(cache_dir)
|
13
|
+
@cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}json" : "#{cache_dir}-json"
|
14
|
+
end
|
15
|
+
|
16
|
+
def input_to_storage(payload, _)
|
17
|
+
obj = ::JSON.parse(payload)
|
18
|
+
msgpack_factory.dump(obj)
|
19
|
+
end
|
20
|
+
|
21
|
+
def storage_to_output(data, kwargs)
|
22
|
+
if kwargs&.key?(:symbolize_names)
|
23
|
+
kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
|
24
|
+
end
|
25
|
+
msgpack_factory.load(data, kwargs)
|
26
|
+
end
|
27
|
+
|
28
|
+
def input_to_output(data, kwargs)
|
29
|
+
::JSON.parse(data, **(kwargs || {}))
|
30
|
+
end
|
31
|
+
|
32
|
+
def precompile(path)
|
33
|
+
Bootsnap::CompileCache::Native.precompile(
|
34
|
+
cache_dir,
|
35
|
+
path.to_s,
|
36
|
+
self,
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def install!(cache_dir)
|
41
|
+
self.cache_dir = cache_dir
|
42
|
+
init!
|
43
|
+
if ::JSON.respond_to?(:load_file)
|
44
|
+
::JSON.singleton_class.prepend(Patch)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def init!
|
49
|
+
require("json")
|
50
|
+
require("msgpack")
|
51
|
+
|
52
|
+
self.msgpack_factory = MessagePack::Factory.new
|
53
|
+
self.supported_options = [:symbolize_names]
|
54
|
+
if ::JSON.parse('["foo"]', freeze: true).first.frozen?
|
55
|
+
if MessagePack.load(MessagePack.dump("foo"), freeze: true).frozen?
|
56
|
+
self.supported_options = [:freeze]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
supported_options.freeze
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module Patch
|
64
|
+
def load_file(path, *args)
|
65
|
+
return super if args.size > 1
|
66
|
+
|
67
|
+
if (kwargs = args.first)
|
68
|
+
return super unless kwargs.is_a?(Hash)
|
69
|
+
return super unless (kwargs.keys - ::Bootsnap::CompileCache::JSON.supported_options).empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
begin
|
73
|
+
::Bootsnap::CompileCache::Native.fetch(
|
74
|
+
Bootsnap::CompileCache::JSON.cache_dir,
|
75
|
+
File.realpath(path),
|
76
|
+
::Bootsnap::CompileCache::JSON,
|
77
|
+
kwargs,
|
78
|
+
)
|
79
|
+
rescue Errno::EACCES
|
80
|
+
::Bootsnap::CompileCache.permission_error(path)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -1,80 +1,86 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require("bootsnap/bootsnap")
|
3
4
|
|
4
5
|
module Bootsnap
|
5
6
|
module CompileCache
|
6
7
|
module YAML
|
7
|
-
|
8
|
-
|
8
|
+
Uncompilable = Class.new(StandardError)
|
9
|
+
UnsupportedTags = Class.new(Uncompilable)
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
11
|
+
SUPPORTED_INTERNAL_ENCODINGS = [
|
12
|
+
nil, # UTF-8
|
13
|
+
Encoding::UTF_8,
|
14
|
+
Encoding::ASCII,
|
15
|
+
Encoding::BINARY,
|
16
|
+
].freeze
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
msgpack_factory.load(data, kwargs)
|
23
|
-
end
|
18
|
+
class << self
|
19
|
+
attr_accessor(:msgpack_factory, :supported_options)
|
20
|
+
attr_reader(:implementation, :cache_dir)
|
24
21
|
|
25
|
-
def
|
26
|
-
|
27
|
-
::YAML.unsafe_load(data, **(kwargs || {}))
|
28
|
-
else
|
29
|
-
::YAML.load(data, **(kwargs || {}))
|
30
|
-
end
|
22
|
+
def cache_dir=(cache_dir)
|
23
|
+
@cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}yaml" : "#{cache_dir}-yaml"
|
31
24
|
end
|
32
25
|
|
33
|
-
def
|
34
|
-
|
35
|
-
return ast unless ast
|
36
|
-
strict_visitor.create(*args).visit(ast)
|
37
|
-
end
|
38
|
-
ruby2_keywords :strict_load if respond_to?(:ruby2_keywords, true)
|
26
|
+
def precompile(path)
|
27
|
+
return false unless CompileCache::YAML.supported_internal_encoding?
|
39
28
|
|
40
|
-
|
41
|
-
Bootsnap::CompileCache::Native.precompile(
|
29
|
+
CompileCache::Native.precompile(
|
42
30
|
cache_dir,
|
43
31
|
path.to_s,
|
44
|
-
|
32
|
+
@implementation,
|
45
33
|
)
|
46
34
|
end
|
47
35
|
|
48
36
|
def install!(cache_dir)
|
49
37
|
self.cache_dir = cache_dir
|
50
38
|
init!
|
51
|
-
::YAML.singleton_class.prepend(Patch)
|
39
|
+
::YAML.singleton_class.prepend(@implementation::Patch)
|
52
40
|
end
|
53
41
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
42
|
+
# Psych coerce strings to `Encoding.default_internal` but Message Pack only support
|
43
|
+
# UTF-8, US-ASCII and BINARY. So if Encoding.default_internal is set to anything else
|
44
|
+
# we can't safely use the cache
|
45
|
+
def supported_internal_encoding?
|
46
|
+
SUPPORTED_INTERNAL_ENCODINGS.include?(Encoding.default_internal)
|
47
|
+
end
|
48
|
+
|
49
|
+
module EncodingAwareSymbols
|
50
|
+
extend self
|
58
51
|
|
59
|
-
|
60
|
-
|
52
|
+
def unpack(payload)
|
53
|
+
(+payload).force_encoding(Encoding::UTF_8).to_sym
|
61
54
|
end
|
62
|
-
|
63
|
-
|
55
|
+
end
|
56
|
+
|
57
|
+
def init!
|
58
|
+
require("yaml")
|
59
|
+
require("msgpack")
|
60
|
+
require("date")
|
61
|
+
|
62
|
+
@implementation = ::YAML::VERSION >= "4" ? Psych4 : Psych3
|
63
|
+
if @implementation::Patch.method_defined?(:unsafe_load_file) && !::YAML.respond_to?(:unsafe_load_file)
|
64
|
+
@implementation::Patch.send(:remove_method, :unsafe_load_file)
|
64
65
|
end
|
65
66
|
|
66
67
|
# MessagePack serializes symbols as strings by default.
|
67
68
|
# We want them to roundtrip cleanly, so we use a custom factory.
|
68
69
|
# see: https://github.com/msgpack/msgpack-ruby/pull/122
|
69
70
|
factory = MessagePack::Factory.new
|
70
|
-
factory.register_type(
|
71
|
+
factory.register_type(
|
72
|
+
0x00,
|
73
|
+
Symbol,
|
74
|
+
packer: :to_msgpack_ext,
|
75
|
+
unpacker: EncodingAwareSymbols.method(:unpack).to_proc,
|
76
|
+
)
|
71
77
|
|
72
78
|
if defined? MessagePack::Timestamp
|
73
79
|
factory.register_type(
|
74
80
|
MessagePack::Timestamp::TYPE, # or just -1
|
75
81
|
Time,
|
76
82
|
packer: MessagePack::Time::Packer,
|
77
|
-
unpacker: MessagePack::Time::Unpacker
|
83
|
+
unpacker: MessagePack::Time::Unpacker,
|
78
84
|
)
|
79
85
|
|
80
86
|
marshal_fallback = {
|
@@ -94,70 +100,251 @@ module Bootsnap
|
|
94
100
|
self.supported_options = []
|
95
101
|
params = ::YAML.method(:load).parameters
|
96
102
|
if params.include?([:key, :symbolize_names])
|
97
|
-
|
103
|
+
supported_options << :symbolize_names
|
98
104
|
end
|
99
105
|
if params.include?([:key, :freeze])
|
100
|
-
if factory.load(factory.dump(
|
101
|
-
|
106
|
+
if factory.load(factory.dump("yaml"), freeze: true).frozen?
|
107
|
+
supported_options << :freeze
|
102
108
|
end
|
103
109
|
end
|
104
|
-
|
110
|
+
supported_options.freeze
|
111
|
+
end
|
112
|
+
|
113
|
+
def patch
|
114
|
+
@implementation::Patch
|
115
|
+
end
|
116
|
+
|
117
|
+
def strict_load(payload)
|
118
|
+
ast = ::YAML.parse(payload)
|
119
|
+
return ast unless ast
|
120
|
+
|
121
|
+
strict_visitor.create.visit(ast)
|
105
122
|
end
|
106
123
|
|
107
124
|
def strict_visitor
|
108
125
|
self::NoTagsVisitor ||= Class.new(Psych::Visitors::ToRuby) do
|
109
126
|
def visit(target)
|
110
127
|
if target.tag
|
111
|
-
raise
|
128
|
+
raise UnsupportedTags, "YAML tags are not supported: #{target.tag}"
|
112
129
|
end
|
130
|
+
|
113
131
|
super
|
114
132
|
end
|
115
133
|
end
|
116
134
|
end
|
117
135
|
end
|
118
136
|
|
119
|
-
module
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
137
|
+
module Psych4
|
138
|
+
extend self
|
139
|
+
|
140
|
+
def input_to_storage(contents, _)
|
141
|
+
obj = SafeLoad.input_to_storage(contents, nil)
|
142
|
+
if UNCOMPILABLE.equal?(obj)
|
143
|
+
obj = UnsafeLoad.input_to_storage(contents, nil)
|
125
144
|
end
|
145
|
+
obj
|
146
|
+
end
|
126
147
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
)
|
134
|
-
|
135
|
-
|
148
|
+
module UnsafeLoad
|
149
|
+
extend self
|
150
|
+
|
151
|
+
def input_to_storage(contents, _)
|
152
|
+
obj = ::YAML.unsafe_load(contents)
|
153
|
+
packer = CompileCache::YAML.msgpack_factory.packer
|
154
|
+
packer.pack(false) # not safe loaded
|
155
|
+
begin
|
156
|
+
packer.pack(obj)
|
157
|
+
rescue NoMethodError, RangeError
|
158
|
+
return UNCOMPILABLE # The object included things that we can't serialize
|
159
|
+
end
|
160
|
+
packer.to_s
|
161
|
+
end
|
162
|
+
|
163
|
+
def storage_to_output(data, kwargs)
|
164
|
+
if kwargs&.key?(:symbolize_names)
|
165
|
+
kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
|
166
|
+
end
|
167
|
+
|
168
|
+
unpacker = CompileCache::YAML.msgpack_factory.unpacker(kwargs)
|
169
|
+
unpacker.feed(data)
|
170
|
+
_safe_loaded = unpacker.unpack
|
171
|
+
unpacker.unpack
|
172
|
+
end
|
173
|
+
|
174
|
+
def input_to_output(data, kwargs)
|
175
|
+
::YAML.unsafe_load(data, **(kwargs || {}))
|
136
176
|
end
|
137
177
|
end
|
138
178
|
|
139
|
-
|
179
|
+
module SafeLoad
|
180
|
+
extend self
|
140
181
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
182
|
+
def input_to_storage(contents, _)
|
183
|
+
obj = begin
|
184
|
+
CompileCache::YAML.strict_load(contents)
|
185
|
+
rescue Psych::DisallowedClass, Psych::BadAlias, Uncompilable
|
186
|
+
return UNCOMPILABLE
|
187
|
+
end
|
188
|
+
|
189
|
+
packer = CompileCache::YAML.msgpack_factory.packer
|
190
|
+
packer.pack(true) # safe loaded
|
191
|
+
begin
|
192
|
+
packer.pack(obj)
|
193
|
+
rescue NoMethodError, RangeError
|
194
|
+
return UNCOMPILABLE
|
195
|
+
end
|
196
|
+
packer.to_s
|
146
197
|
end
|
147
198
|
|
199
|
+
def storage_to_output(data, kwargs)
|
200
|
+
if kwargs&.key?(:symbolize_names)
|
201
|
+
kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
|
202
|
+
end
|
203
|
+
|
204
|
+
unpacker = CompileCache::YAML.msgpack_factory.unpacker(kwargs)
|
205
|
+
unpacker.feed(data)
|
206
|
+
safe_loaded = unpacker.unpack
|
207
|
+
if safe_loaded
|
208
|
+
unpacker.unpack
|
209
|
+
else
|
210
|
+
UNCOMPILABLE
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def input_to_output(data, kwargs)
|
215
|
+
::YAML.load(data, **(kwargs || {}))
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
module Patch
|
220
|
+
def load_file(path, *args)
|
221
|
+
return super unless CompileCache::YAML.supported_internal_encoding?
|
222
|
+
|
223
|
+
return super if args.size > 1
|
224
|
+
|
225
|
+
if (kwargs = args.first)
|
226
|
+
return super unless kwargs.is_a?(Hash)
|
227
|
+
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
228
|
+
end
|
229
|
+
|
230
|
+
begin
|
231
|
+
CompileCache::Native.fetch(
|
232
|
+
CompileCache::YAML.cache_dir,
|
233
|
+
File.realpath(path),
|
234
|
+
CompileCache::YAML::Psych4::SafeLoad,
|
235
|
+
kwargs,
|
236
|
+
)
|
237
|
+
rescue Errno::EACCES
|
238
|
+
CompileCache.permission_error(path)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
243
|
+
|
244
|
+
def unsafe_load_file(path, *args)
|
245
|
+
return super unless CompileCache::YAML.supported_internal_encoding?
|
246
|
+
|
247
|
+
return super if args.size > 1
|
248
|
+
|
249
|
+
if (kwargs = args.first)
|
250
|
+
return super unless kwargs.is_a?(Hash)
|
251
|
+
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
252
|
+
end
|
253
|
+
|
254
|
+
begin
|
255
|
+
CompileCache::Native.fetch(
|
256
|
+
CompileCache::YAML.cache_dir,
|
257
|
+
File.realpath(path),
|
258
|
+
CompileCache::YAML::Psych4::UnsafeLoad,
|
259
|
+
kwargs,
|
260
|
+
)
|
261
|
+
rescue Errno::EACCES
|
262
|
+
CompileCache.permission_error(path)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
module Psych3
|
271
|
+
extend self
|
272
|
+
|
273
|
+
def input_to_storage(contents, _)
|
274
|
+
obj = ::YAML.load(contents)
|
275
|
+
packer = CompileCache::YAML.msgpack_factory.packer
|
276
|
+
packer.pack(false) # not safe loaded
|
148
277
|
begin
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
::Bootsnap::CompileCache::YAML,
|
153
|
-
kwargs,
|
154
|
-
)
|
155
|
-
rescue Errno::EACCES
|
156
|
-
::Bootsnap::CompileCache.permission_error(path)
|
278
|
+
packer.pack(obj)
|
279
|
+
rescue NoMethodError, RangeError
|
280
|
+
return UNCOMPILABLE # The object included things that we can't serialize
|
157
281
|
end
|
282
|
+
packer.to_s
|
158
283
|
end
|
159
284
|
|
160
|
-
|
285
|
+
def storage_to_output(data, kwargs)
|
286
|
+
if kwargs&.key?(:symbolize_names)
|
287
|
+
kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
|
288
|
+
end
|
289
|
+
unpacker = CompileCache::YAML.msgpack_factory.unpacker(kwargs)
|
290
|
+
unpacker.feed(data)
|
291
|
+
_safe_loaded = unpacker.unpack
|
292
|
+
unpacker.unpack
|
293
|
+
end
|
294
|
+
|
295
|
+
def input_to_output(data, kwargs)
|
296
|
+
::YAML.load(data, **(kwargs || {}))
|
297
|
+
end
|
298
|
+
|
299
|
+
module Patch
|
300
|
+
def load_file(path, *args)
|
301
|
+
return super unless CompileCache::YAML.supported_internal_encoding?
|
302
|
+
|
303
|
+
return super if args.size > 1
|
304
|
+
|
305
|
+
if (kwargs = args.first)
|
306
|
+
return super unless kwargs.is_a?(Hash)
|
307
|
+
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
308
|
+
end
|
309
|
+
|
310
|
+
begin
|
311
|
+
CompileCache::Native.fetch(
|
312
|
+
CompileCache::YAML.cache_dir,
|
313
|
+
File.realpath(path),
|
314
|
+
CompileCache::YAML::Psych3,
|
315
|
+
kwargs,
|
316
|
+
)
|
317
|
+
rescue Errno::EACCES
|
318
|
+
CompileCache.permission_error(path)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
323
|
+
|
324
|
+
def unsafe_load_file(path, *args)
|
325
|
+
return super unless CompileCache::YAML.supported_internal_encoding?
|
326
|
+
|
327
|
+
return super if args.size > 1
|
328
|
+
|
329
|
+
if (kwargs = args.first)
|
330
|
+
return super unless kwargs.is_a?(Hash)
|
331
|
+
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
332
|
+
end
|
333
|
+
|
334
|
+
begin
|
335
|
+
CompileCache::Native.fetch(
|
336
|
+
CompileCache::YAML.cache_dir,
|
337
|
+
File.realpath(path),
|
338
|
+
CompileCache::YAML::Psych3,
|
339
|
+
kwargs,
|
340
|
+
)
|
341
|
+
rescue Errno::EACCES
|
342
|
+
CompileCache.permission_error(path)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
|
347
|
+
end
|
161
348
|
end
|
162
349
|
end
|
163
350
|
end
|
@@ -1,13 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Bootsnap
|
3
4
|
module CompileCache
|
4
|
-
|
5
|
+
UNCOMPILABLE = BasicObject.new
|
6
|
+
def UNCOMPILABLE.inspect
|
7
|
+
"<Bootsnap::UNCOMPILABLE>"
|
8
|
+
end
|
9
|
+
|
10
|
+
Error = Class.new(StandardError)
|
5
11
|
PermissionError = Class.new(Error)
|
6
12
|
|
7
|
-
def self.setup(cache_dir:, iseq:, yaml:)
|
13
|
+
def self.setup(cache_dir:, iseq:, yaml:, json:)
|
8
14
|
if iseq
|
9
15
|
if supported?
|
10
|
-
require_relative(
|
16
|
+
require_relative("compile_cache/iseq")
|
11
17
|
Bootsnap::CompileCache::ISeq.install!(cache_dir)
|
12
18
|
elsif $VERBOSE
|
13
19
|
warn("[bootsnap/setup] bytecode caching is not supported on this implementation of Ruby")
|
@@ -16,12 +22,21 @@ module Bootsnap
|
|
16
22
|
|
17
23
|
if yaml
|
18
24
|
if supported?
|
19
|
-
require_relative(
|
25
|
+
require_relative("compile_cache/yaml")
|
20
26
|
Bootsnap::CompileCache::YAML.install!(cache_dir)
|
21
27
|
elsif $VERBOSE
|
22
28
|
warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
|
23
29
|
end
|
24
30
|
end
|
31
|
+
|
32
|
+
if json
|
33
|
+
if supported?
|
34
|
+
require_relative("compile_cache/json")
|
35
|
+
Bootsnap::CompileCache::JSON.install!(cache_dir)
|
36
|
+
elsif $VERBOSE
|
37
|
+
warn("[bootsnap/setup] JSON parsing caching is not supported on this implementation of Ruby")
|
38
|
+
end
|
39
|
+
end
|
25
40
|
end
|
26
41
|
|
27
42
|
def self.permission_error(path)
|
@@ -35,9 +50,9 @@ module Bootsnap
|
|
35
50
|
|
36
51
|
def self.supported?
|
37
52
|
# only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), Windows (RubyInstaller2) and >= 2.3.0
|
38
|
-
RUBY_ENGINE ==
|
39
|
-
|
40
|
-
|
53
|
+
RUBY_ENGINE == "ruby" &&
|
54
|
+
RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/ &&
|
55
|
+
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
|
41
56
|
end
|
42
57
|
end
|
43
58
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Bootsnap
|
3
4
|
module ExplicitRequire
|
4
|
-
ARCHDIR = RbConfig::CONFIG[
|
5
|
-
RUBYLIBDIR = RbConfig::CONFIG[
|
6
|
-
DLEXT = RbConfig::CONFIG[
|
5
|
+
ARCHDIR = RbConfig::CONFIG["archdir"]
|
6
|
+
RUBYLIBDIR = RbConfig::CONFIG["rubylibdir"]
|
7
|
+
DLEXT = RbConfig::CONFIG["DLEXT"]
|
7
8
|
|
8
9
|
def self.from_self(feature)
|
9
10
|
require_relative("../#{feature}")
|