bootsnap 1.8.1 → 1.10.2
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 +57 -0
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/exe/bootsnap +1 -1
- data/ext/bootsnap/bootsnap.c +38 -36
- 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 +216 -78
- data/lib/bootsnap/compile_cache.rb +19 -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 +43 -29
- 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,66 +1,42 @@
|
|
|
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
|
-
attr_accessor(:msgpack_factory, :cache_dir, :supported_options)
|
|
9
|
-
|
|
10
|
-
def input_to_storage(contents, _)
|
|
11
|
-
obj = strict_load(contents)
|
|
12
|
-
msgpack_factory.dump(obj)
|
|
13
|
-
rescue NoMethodError, RangeError
|
|
14
|
-
# The object included things that we can't serialize
|
|
15
|
-
raise(Uncompilable)
|
|
16
|
-
end
|
|
8
|
+
UnsupportedTags = Class.new(StandardError)
|
|
17
9
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
end
|
|
22
|
-
msgpack_factory.load(data, kwargs)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def input_to_output(data, kwargs)
|
|
26
|
-
if ::YAML.respond_to?(:unsafe_load)
|
|
27
|
-
::YAML.unsafe_load(data, **(kwargs || {}))
|
|
28
|
-
else
|
|
29
|
-
::YAML.load(data, **(kwargs || {}))
|
|
30
|
-
end
|
|
31
|
-
end
|
|
10
|
+
class << self
|
|
11
|
+
attr_accessor(:msgpack_factory, :supported_options)
|
|
12
|
+
attr_reader(:implementation, :cache_dir)
|
|
32
13
|
|
|
33
|
-
def
|
|
34
|
-
|
|
35
|
-
return ast unless ast
|
|
36
|
-
strict_visitor.create(*args).visit(ast)
|
|
14
|
+
def cache_dir=(cache_dir)
|
|
15
|
+
@cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}yaml" : "#{cache_dir}-yaml"
|
|
37
16
|
end
|
|
38
|
-
ruby2_keywords :strict_load if respond_to?(:ruby2_keywords, true)
|
|
39
17
|
|
|
40
|
-
def precompile(path
|
|
18
|
+
def precompile(path)
|
|
41
19
|
Bootsnap::CompileCache::Native.precompile(
|
|
42
20
|
cache_dir,
|
|
43
21
|
path.to_s,
|
|
44
|
-
|
|
22
|
+
@implementation,
|
|
45
23
|
)
|
|
46
24
|
end
|
|
47
25
|
|
|
48
26
|
def install!(cache_dir)
|
|
49
27
|
self.cache_dir = cache_dir
|
|
50
28
|
init!
|
|
51
|
-
::YAML.singleton_class.prepend(Patch)
|
|
29
|
+
::YAML.singleton_class.prepend(@implementation::Patch)
|
|
52
30
|
end
|
|
53
31
|
|
|
54
32
|
def init!
|
|
55
|
-
require(
|
|
56
|
-
require(
|
|
57
|
-
require(
|
|
33
|
+
require("yaml")
|
|
34
|
+
require("msgpack")
|
|
35
|
+
require("date")
|
|
58
36
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if Patch.method_defined?(:load_file) && ::YAML::VERSION >= '4'
|
|
63
|
-
Patch.send(:remove_method, :load_file)
|
|
37
|
+
@implementation = ::YAML::VERSION >= "4" ? Psych4 : Psych3
|
|
38
|
+
if @implementation::Patch.method_defined?(:unsafe_load_file) && !::YAML.respond_to?(:unsafe_load_file)
|
|
39
|
+
@implementation::Patch.send(:remove_method, :unsafe_load_file)
|
|
64
40
|
end
|
|
65
41
|
|
|
66
42
|
# MessagePack serializes symbols as strings by default.
|
|
@@ -74,7 +50,7 @@ module Bootsnap
|
|
|
74
50
|
MessagePack::Timestamp::TYPE, # or just -1
|
|
75
51
|
Time,
|
|
76
52
|
packer: MessagePack::Time::Packer,
|
|
77
|
-
unpacker: MessagePack::Time::Unpacker
|
|
53
|
+
unpacker: MessagePack::Time::Unpacker,
|
|
78
54
|
)
|
|
79
55
|
|
|
80
56
|
marshal_fallback = {
|
|
@@ -94,70 +70,232 @@ module Bootsnap
|
|
|
94
70
|
self.supported_options = []
|
|
95
71
|
params = ::YAML.method(:load).parameters
|
|
96
72
|
if params.include?([:key, :symbolize_names])
|
|
97
|
-
|
|
73
|
+
supported_options << :symbolize_names
|
|
98
74
|
end
|
|
99
75
|
if params.include?([:key, :freeze])
|
|
100
|
-
if factory.load(factory.dump(
|
|
101
|
-
|
|
76
|
+
if factory.load(factory.dump("yaml"), freeze: true).frozen?
|
|
77
|
+
supported_options << :freeze
|
|
102
78
|
end
|
|
103
79
|
end
|
|
104
|
-
|
|
80
|
+
supported_options.freeze
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def patch
|
|
84
|
+
@implementation::Patch
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def strict_load(payload)
|
|
88
|
+
ast = ::YAML.parse(payload)
|
|
89
|
+
return ast unless ast
|
|
90
|
+
|
|
91
|
+
strict_visitor.create.visit(ast)
|
|
105
92
|
end
|
|
106
93
|
|
|
107
94
|
def strict_visitor
|
|
108
95
|
self::NoTagsVisitor ||= Class.new(Psych::Visitors::ToRuby) do
|
|
109
96
|
def visit(target)
|
|
110
97
|
if target.tag
|
|
111
|
-
raise
|
|
98
|
+
raise UnsupportedTags, "YAML tags are not supported: #{target.tag}"
|
|
112
99
|
end
|
|
100
|
+
|
|
113
101
|
super
|
|
114
102
|
end
|
|
115
103
|
end
|
|
116
104
|
end
|
|
117
105
|
end
|
|
118
106
|
|
|
119
|
-
module
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
107
|
+
module Psych4
|
|
108
|
+
extend self
|
|
109
|
+
|
|
110
|
+
def input_to_storage(contents, _)
|
|
111
|
+
obj = SafeLoad.input_to_storage(contents, nil)
|
|
112
|
+
if UNCOMPILABLE.equal?(obj)
|
|
113
|
+
obj = UnsafeLoad.input_to_storage(contents, nil)
|
|
125
114
|
end
|
|
115
|
+
obj
|
|
116
|
+
end
|
|
126
117
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
|
|
118
|
+
module UnsafeLoad
|
|
119
|
+
extend self
|
|
120
|
+
|
|
121
|
+
def input_to_storage(contents, _)
|
|
122
|
+
obj = CompileCache::YAML.strict_load(contents)
|
|
123
|
+
packer = CompileCache::YAML.msgpack_factory.packer
|
|
124
|
+
packer.pack(false) # not safe loaded
|
|
125
|
+
packer.pack(obj)
|
|
126
|
+
packer.to_s
|
|
127
|
+
rescue NoMethodError, RangeError, UnsupportedTags
|
|
128
|
+
UNCOMPILABLE # The object included things that we can't serialize
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def storage_to_output(data, kwargs)
|
|
132
|
+
if kwargs&.key?(:symbolize_names)
|
|
133
|
+
kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
unpacker = CompileCache::YAML.msgpack_factory.unpacker(kwargs)
|
|
137
|
+
unpacker.feed(data)
|
|
138
|
+
_safe_loaded = unpacker.unpack
|
|
139
|
+
unpacker.unpack
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def input_to_output(data, kwargs)
|
|
143
|
+
::YAML.unsafe_load(data, **(kwargs || {}))
|
|
136
144
|
end
|
|
137
145
|
end
|
|
138
146
|
|
|
139
|
-
|
|
147
|
+
module SafeLoad
|
|
148
|
+
extend self
|
|
140
149
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
150
|
+
def input_to_storage(contents, _)
|
|
151
|
+
obj = ::YAML.load(contents)
|
|
152
|
+
packer = CompileCache::YAML.msgpack_factory.packer
|
|
153
|
+
packer.pack(true) # safe loaded
|
|
154
|
+
packer.pack(obj)
|
|
155
|
+
packer.to_s
|
|
156
|
+
rescue NoMethodError, RangeError, Psych::DisallowedClass, Psych::BadAlias
|
|
157
|
+
UNCOMPILABLE # The object included things that we can't serialize
|
|
146
158
|
end
|
|
147
159
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
|
|
160
|
+
def storage_to_output(data, kwargs)
|
|
161
|
+
if kwargs&.key?(:symbolize_names)
|
|
162
|
+
kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
unpacker = CompileCache::YAML.msgpack_factory.unpacker(kwargs)
|
|
166
|
+
unpacker.feed(data)
|
|
167
|
+
safe_loaded = unpacker.unpack
|
|
168
|
+
if safe_loaded
|
|
169
|
+
unpacker.unpack
|
|
170
|
+
else
|
|
171
|
+
UNCOMPILABLE
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def input_to_output(data, kwargs)
|
|
176
|
+
::YAML.load(data, **(kwargs || {}))
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
module Patch
|
|
181
|
+
def load_file(path, *args)
|
|
182
|
+
return super if args.size > 1
|
|
183
|
+
|
|
184
|
+
if (kwargs = args.first)
|
|
185
|
+
return super unless kwargs.is_a?(Hash)
|
|
186
|
+
return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
begin
|
|
190
|
+
::Bootsnap::CompileCache::Native.fetch(
|
|
191
|
+
Bootsnap::CompileCache::YAML.cache_dir,
|
|
192
|
+
File.realpath(path),
|
|
193
|
+
::Bootsnap::CompileCache::YAML::Psych4::SafeLoad,
|
|
194
|
+
kwargs,
|
|
195
|
+
)
|
|
196
|
+
rescue Errno::EACCES
|
|
197
|
+
::Bootsnap::CompileCache.permission_error(path)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
|
202
|
+
|
|
203
|
+
def unsafe_load_file(path, *args)
|
|
204
|
+
return super if args.size > 1
|
|
205
|
+
|
|
206
|
+
if (kwargs = args.first)
|
|
207
|
+
return super unless kwargs.is_a?(Hash)
|
|
208
|
+
return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
begin
|
|
212
|
+
::Bootsnap::CompileCache::Native.fetch(
|
|
213
|
+
Bootsnap::CompileCache::YAML.cache_dir,
|
|
214
|
+
File.realpath(path),
|
|
215
|
+
::Bootsnap::CompileCache::YAML::Psych4::UnsafeLoad,
|
|
216
|
+
kwargs,
|
|
217
|
+
)
|
|
218
|
+
rescue Errno::EACCES
|
|
219
|
+
::Bootsnap::CompileCache.permission_error(path)
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
module Psych3
|
|
228
|
+
extend self
|
|
229
|
+
|
|
230
|
+
def input_to_storage(contents, _)
|
|
231
|
+
obj = CompileCache::YAML.strict_load(contents)
|
|
232
|
+
packer = CompileCache::YAML.msgpack_factory.packer
|
|
233
|
+
packer.pack(false) # not safe loaded
|
|
234
|
+
packer.pack(obj)
|
|
235
|
+
packer.to_s
|
|
236
|
+
rescue NoMethodError, RangeError, UnsupportedTags
|
|
237
|
+
UNCOMPILABLE # The object included things that we can't serialize
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def storage_to_output(data, kwargs)
|
|
241
|
+
if kwargs&.key?(:symbolize_names)
|
|
242
|
+
kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
|
|
157
243
|
end
|
|
244
|
+
unpacker = CompileCache::YAML.msgpack_factory.unpacker(kwargs)
|
|
245
|
+
unpacker.feed(data)
|
|
246
|
+
_safe_loaded = unpacker.unpack
|
|
247
|
+
unpacker.unpack
|
|
158
248
|
end
|
|
159
249
|
|
|
160
|
-
|
|
250
|
+
def input_to_output(data, kwargs)
|
|
251
|
+
::YAML.load(data, **(kwargs || {}))
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
module Patch
|
|
255
|
+
def load_file(path, *args)
|
|
256
|
+
return super if args.size > 1
|
|
257
|
+
|
|
258
|
+
if (kwargs = args.first)
|
|
259
|
+
return super unless kwargs.is_a?(Hash)
|
|
260
|
+
return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
begin
|
|
264
|
+
::Bootsnap::CompileCache::Native.fetch(
|
|
265
|
+
Bootsnap::CompileCache::YAML.cache_dir,
|
|
266
|
+
File.realpath(path),
|
|
267
|
+
::Bootsnap::CompileCache::YAML::Psych3,
|
|
268
|
+
kwargs,
|
|
269
|
+
)
|
|
270
|
+
rescue Errno::EACCES
|
|
271
|
+
::Bootsnap::CompileCache.permission_error(path)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
|
276
|
+
|
|
277
|
+
def unsafe_load_file(path, *args)
|
|
278
|
+
return super if args.size > 1
|
|
279
|
+
|
|
280
|
+
if (kwargs = args.first)
|
|
281
|
+
return super unless kwargs.is_a?(Hash)
|
|
282
|
+
return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
begin
|
|
286
|
+
::Bootsnap::CompileCache::Native.fetch(
|
|
287
|
+
Bootsnap::CompileCache::YAML.cache_dir,
|
|
288
|
+
File.realpath(path),
|
|
289
|
+
::Bootsnap::CompileCache::YAML::Psych3,
|
|
290
|
+
kwargs,
|
|
291
|
+
)
|
|
292
|
+
rescue Errno::EACCES
|
|
293
|
+
::Bootsnap::CompileCache.permission_error(path)
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
|
|
298
|
+
end
|
|
161
299
|
end
|
|
162
300
|
end
|
|
163
301
|
end
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Bootsnap
|
|
3
4
|
module CompileCache
|
|
4
|
-
|
|
5
|
+
UNCOMPILABLE = BasicObject.new
|
|
6
|
+
|
|
7
|
+
Error = Class.new(StandardError)
|
|
5
8
|
PermissionError = Class.new(Error)
|
|
6
9
|
|
|
7
|
-
def self.setup(cache_dir:, iseq:, yaml:)
|
|
10
|
+
def self.setup(cache_dir:, iseq:, yaml:, json:)
|
|
8
11
|
if iseq
|
|
9
12
|
if supported?
|
|
10
|
-
require_relative(
|
|
13
|
+
require_relative("compile_cache/iseq")
|
|
11
14
|
Bootsnap::CompileCache::ISeq.install!(cache_dir)
|
|
12
15
|
elsif $VERBOSE
|
|
13
16
|
warn("[bootsnap/setup] bytecode caching is not supported on this implementation of Ruby")
|
|
@@ -16,12 +19,21 @@ module Bootsnap
|
|
|
16
19
|
|
|
17
20
|
if yaml
|
|
18
21
|
if supported?
|
|
19
|
-
require_relative(
|
|
22
|
+
require_relative("compile_cache/yaml")
|
|
20
23
|
Bootsnap::CompileCache::YAML.install!(cache_dir)
|
|
21
24
|
elsif $VERBOSE
|
|
22
25
|
warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
|
|
23
26
|
end
|
|
24
27
|
end
|
|
28
|
+
|
|
29
|
+
if json
|
|
30
|
+
if supported?
|
|
31
|
+
require_relative("compile_cache/json")
|
|
32
|
+
Bootsnap::CompileCache::JSON.install!(cache_dir)
|
|
33
|
+
elsif $VERBOSE
|
|
34
|
+
warn("[bootsnap/setup] JSON parsing caching is not supported on this implementation of Ruby")
|
|
35
|
+
end
|
|
36
|
+
end
|
|
25
37
|
end
|
|
26
38
|
|
|
27
39
|
def self.permission_error(path)
|
|
@@ -35,9 +47,9 @@ module Bootsnap
|
|
|
35
47
|
|
|
36
48
|
def self.supported?
|
|
37
49
|
# only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), Windows (RubyInstaller2) and >= 2.3.0
|
|
38
|
-
RUBY_ENGINE ==
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
RUBY_ENGINE == "ruby" &&
|
|
51
|
+
RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/ &&
|
|
52
|
+
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
|
|
41
53
|
end
|
|
42
54
|
end
|
|
43
55
|
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}")
|