bootsnap 1.7.1.pre1 → 1.7.5
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 +21 -0
- data/ext/bootsnap/bootsnap.c +6 -5
- data/lib/bootsnap.rb +3 -1
- data/lib/bootsnap/compile_cache/yaml.rb +37 -17
- data/lib/bootsnap/load_path_cache/cache.rb +26 -9
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +1 -1
- data/lib/bootsnap/load_path_cache/path_scanner.rb +14 -3
- data/lib/bootsnap/load_path_cache/store.rb +17 -9
- data/lib/bootsnap/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7dac6bb1ac2018e46d1cdac77a243cc1e2d46d8dc24deb0a9248320451549ba
|
4
|
+
data.tar.gz: 9cd95e8c52993daffd79f1d21961c5754f88642250c9552881f30f26f9dcc462
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6cee7f1ed6c30d819e576fa79d1e627585996d139dd4add684fc22d4bf720ae1c0f778bb1ee23c2a7819d788c7956b9632f03b5861bb7f6e507f3562687b70e
|
7
|
+
data.tar.gz: 505de0bcbfa90ab03fde256bea4dec4f5728482b61d452887da7a49c84894daff61c1aa0b16a2a114ddab142ae2a75d09f4447de80a6b33068ea0c15ec0fdd8f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.7.5
|
4
|
+
|
5
|
+
* Handle a regression of Ruby 2.7.3 causing Bootsnap to call the deprecated `untaint` method. (#360)
|
6
|
+
* Gracefully handle read-only file system as well as other errors preventing to persist the load path cache. (#358)
|
7
|
+
|
8
|
+
# 1.7.4
|
9
|
+
|
10
|
+
* Stop raising errors when encoutering various file system errors. The cache is now best effort,
|
11
|
+
if somehow it can't be saved, bootsnapp will gracefully fallback to the original operation (e.g. `Kernel.require`).
|
12
|
+
(#353, #177, #262)
|
13
|
+
|
14
|
+
# 1.7.3
|
15
|
+
|
16
|
+
* Disable YAML precompilation when encountering YAML tags. (#351)
|
17
|
+
|
18
|
+
# 1.7.2
|
19
|
+
|
20
|
+
* Fix compatibility with msgpack < 1. (#349)
|
21
|
+
|
22
|
+
# 1.7.1
|
23
|
+
|
3
24
|
* Warn Ruby 2.5 users if they turn ISeq caching on. (#327, #244)
|
4
25
|
* Disable ISeq caching for the whole 2.5.x series again.
|
5
26
|
* Better handle hashing of Ruby strings. (#318)
|
data/ext/bootsnap/bootsnap.c
CHANGED
@@ -464,8 +464,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, const char ** errn
|
|
464
464
|
fd = open(path, O_RDONLY);
|
465
465
|
if (fd < 0) {
|
466
466
|
*errno_provenance = "bs_fetch:open_cache_file:open";
|
467
|
-
|
468
|
-
return ERROR_WITH_ERRNO;
|
467
|
+
return CACHE_MISS;
|
469
468
|
}
|
470
469
|
#ifdef _WIN32
|
471
470
|
setmode(fd, O_BINARY);
|
@@ -763,9 +762,11 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
763
762
|
/* If storage_data isn't a string, we can't cache it */
|
764
763
|
if (!RB_TYPE_P(storage_data, T_STRING)) goto invalid_type_storage_data;
|
765
764
|
|
766
|
-
/*
|
767
|
-
|
768
|
-
|
765
|
+
/* Attempt to write the cache key and storage_data to the cache directory.
|
766
|
+
* We do however ignore any failures to persist the cache, as it's better
|
767
|
+
* to move along, than to interrupt the process.
|
768
|
+
*/
|
769
|
+
atomic_write_cache_file(cache_path, ¤t_key, storage_data, &errno_provenance);
|
769
770
|
|
770
771
|
/* Having written the cache, now convert storage_data to output_data */
|
771
772
|
exception_tag = bs_storage_to_output(handler, args, storage_data, &output_data);
|
data/lib/bootsnap.rb
CHANGED
@@ -27,7 +27,9 @@ module Bootsnap
|
|
27
27
|
|
28
28
|
def self.instrumentation=(callback)
|
29
29
|
@instrumentation = callback
|
30
|
-
|
30
|
+
if respond_to?(:instrumentation_enabled=, true)
|
31
|
+
self.instrumentation_enabled = !!callback
|
32
|
+
end
|
31
33
|
end
|
32
34
|
|
33
35
|
def self._instrument(event, path)
|
@@ -8,8 +8,7 @@ module Bootsnap
|
|
8
8
|
attr_accessor(:msgpack_factory, :cache_dir, :supported_options)
|
9
9
|
|
10
10
|
def input_to_storage(contents, _)
|
11
|
-
|
12
|
-
obj = ::YAML.load(contents)
|
11
|
+
obj = strict_load(contents)
|
13
12
|
msgpack_factory.dump(obj)
|
14
13
|
rescue NoMethodError, RangeError
|
15
14
|
# The object included things that we can't serialize
|
@@ -27,6 +26,13 @@ module Bootsnap
|
|
27
26
|
::YAML.load(data, **(kwargs || {}))
|
28
27
|
end
|
29
28
|
|
29
|
+
def strict_load(payload, *args)
|
30
|
+
ast = ::YAML.parse(payload)
|
31
|
+
return ast unless ast
|
32
|
+
strict_visitor.create(*args).visit(ast)
|
33
|
+
end
|
34
|
+
ruby2_keywords :strict_load if respond_to?(:ruby2_keywords, true)
|
35
|
+
|
30
36
|
def precompile(path, cache_dir: YAML.cache_dir)
|
31
37
|
Bootsnap::CompileCache::Native.precompile(
|
32
38
|
cache_dir,
|
@@ -51,22 +57,25 @@ module Bootsnap
|
|
51
57
|
# see: https://github.com/msgpack/msgpack-ruby/pull/122
|
52
58
|
factory = MessagePack::Factory.new
|
53
59
|
factory.register_type(0x00, Symbol)
|
54
|
-
factory.register_type(
|
55
|
-
MessagePack::Timestamp::TYPE, # or just -1
|
56
|
-
Time,
|
57
|
-
packer: MessagePack::Time::Packer,
|
58
|
-
unpacker: MessagePack::Time::Unpacker
|
59
|
-
)
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
61
|
+
if defined? MessagePack::Timestamp
|
62
|
+
factory.register_type(
|
63
|
+
MessagePack::Timestamp::TYPE, # or just -1
|
64
|
+
Time,
|
65
|
+
packer: MessagePack::Time::Packer,
|
66
|
+
unpacker: MessagePack::Time::Unpacker
|
67
|
+
)
|
68
|
+
|
69
|
+
marshal_fallback = {
|
70
|
+
packer: ->(value) { Marshal.dump(value) },
|
71
|
+
unpacker: ->(payload) { Marshal.load(payload) },
|
72
|
+
}
|
73
|
+
{
|
74
|
+
Date => 0x01,
|
75
|
+
Regexp => 0x02,
|
76
|
+
}.each do |type, code|
|
77
|
+
factory.register_type(code, type, marshal_fallback)
|
78
|
+
end
|
70
79
|
end
|
71
80
|
|
72
81
|
self.msgpack_factory = factory
|
@@ -83,6 +92,17 @@ module Bootsnap
|
|
83
92
|
end
|
84
93
|
self.supported_options.freeze
|
85
94
|
end
|
95
|
+
|
96
|
+
def strict_visitor
|
97
|
+
self::NoTagsVisitor ||= Class.new(Psych::Visitors::ToRuby) do
|
98
|
+
def visit(target)
|
99
|
+
if target.tag
|
100
|
+
raise Uncompilable, "YAML tags are not supported: #{target.tag}"
|
101
|
+
end
|
102
|
+
super
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
86
106
|
end
|
87
107
|
|
88
108
|
module Patch
|
@@ -10,8 +10,8 @@ module Bootsnap
|
|
10
10
|
def initialize(store, path_obj, development_mode: false)
|
11
11
|
@development_mode = development_mode
|
12
12
|
@store = store
|
13
|
-
@mutex =
|
14
|
-
@path_obj = path_obj.map! { |f| File.exist?(f) ? File.realpath(f) : f }
|
13
|
+
@mutex = Mutex.new
|
14
|
+
@path_obj = path_obj.map! { |f| PathScanner.os_path(File.exist?(f) ? File.realpath(f) : f.dup) }
|
15
15
|
@has_relative_paths = nil
|
16
16
|
reinitialize
|
17
17
|
end
|
@@ -178,25 +178,42 @@ module Bootsnap
|
|
178
178
|
|
179
179
|
if DLEXT2
|
180
180
|
def search_index(f)
|
181
|
-
try_index(
|
181
|
+
try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f + DLEXT2) || try_index(f)
|
182
182
|
end
|
183
183
|
|
184
184
|
def maybe_append_extension(f)
|
185
|
-
try_ext(
|
185
|
+
try_ext(f + DOT_RB) || try_ext(f + DLEXT) || try_ext(f + DLEXT2) || f
|
186
186
|
end
|
187
187
|
else
|
188
188
|
def search_index(f)
|
189
|
-
try_index(
|
189
|
+
try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f)
|
190
190
|
end
|
191
191
|
|
192
192
|
def maybe_append_extension(f)
|
193
|
-
try_ext(
|
193
|
+
try_ext(f + DOT_RB) || try_ext(f + DLEXT) || f
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
197
|
-
|
198
|
-
|
199
|
-
|
197
|
+
s = rand.to_s.force_encoding(Encoding::US_ASCII).freeze
|
198
|
+
if s.respond_to?(:-@)
|
199
|
+
if (-s).equal?(s) && (-s.dup).equal?(s) || RUBY_VERSION >= '2.7'
|
200
|
+
def try_index(f)
|
201
|
+
if (p = @index[f])
|
202
|
+
-(File.join(p, f).freeze)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
else
|
206
|
+
def try_index(f)
|
207
|
+
if (p = @index[f])
|
208
|
+
-File.join(p, f).untaint
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
else
|
213
|
+
def try_index(f)
|
214
|
+
if (p = @index[f])
|
215
|
+
File.join(p, f)
|
216
|
+
end
|
200
217
|
end
|
201
218
|
end
|
202
219
|
|
@@ -26,7 +26,7 @@ module Bootsnap
|
|
26
26
|
class LoadedFeaturesIndex
|
27
27
|
def initialize
|
28
28
|
@lfi = {}
|
29
|
-
@mutex =
|
29
|
+
@mutex = Mutex.new
|
30
30
|
|
31
31
|
# In theory the user could mutate $LOADED_FEATURES and invalidate our
|
32
32
|
# cache. If this ever comes up in practice — or if you, the
|
@@ -33,10 +33,10 @@ module Bootsnap
|
|
33
33
|
requirables = []
|
34
34
|
walk(path, nil) do |relative_path, absolute_path, is_directory|
|
35
35
|
if is_directory
|
36
|
-
dirs << relative_path
|
36
|
+
dirs << os_path(relative_path)
|
37
37
|
!contains_bundle_path || !absolute_path.start_with?(BUNDLE_PATH)
|
38
38
|
elsif relative_path.end_with?(*REQUIRABLE_EXTENSIONS)
|
39
|
-
requirables << relative_path
|
39
|
+
requirables << os_path(relative_path)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
[requirables, dirs]
|
@@ -45,7 +45,7 @@ module Bootsnap
|
|
45
45
|
def walk(absolute_dir_path, relative_dir_path, &block)
|
46
46
|
Dir.foreach(absolute_dir_path) do |name|
|
47
47
|
next if name.start_with?('.')
|
48
|
-
relative_path = relative_dir_path ?
|
48
|
+
relative_path = relative_dir_path ? File.join(relative_dir_path, name) : name
|
49
49
|
|
50
50
|
absolute_path = "#{absolute_dir_path}/#{name}"
|
51
51
|
if File.directory?(absolute_path)
|
@@ -57,6 +57,17 @@ module Bootsnap
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
60
|
+
|
61
|
+
if RUBY_VERSION >= '3.1'
|
62
|
+
def os_path(path)
|
63
|
+
path.freeze
|
64
|
+
end
|
65
|
+
else
|
66
|
+
def os_path(path)
|
67
|
+
path.force_encoding(Encoding::US_ASCII) if path.ascii_only?
|
68
|
+
path.freeze
|
69
|
+
end
|
70
|
+
end
|
60
71
|
end
|
61
72
|
end
|
62
73
|
end
|
@@ -12,8 +12,7 @@ module Bootsnap
|
|
12
12
|
|
13
13
|
def initialize(store_path)
|
14
14
|
@store_path = store_path
|
15
|
-
|
16
|
-
@txn_mutex = defined?(::Mutex) ? ::Mutex.new : ::Thread::Mutex.new
|
15
|
+
@txn_mutex = Mutex.new
|
17
16
|
@dirty = false
|
18
17
|
load_data
|
19
18
|
end
|
@@ -63,12 +62,18 @@ module Bootsnap
|
|
63
62
|
|
64
63
|
def load_data
|
65
64
|
@data = begin
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
65
|
+
File.open(@store_path, encoding: Encoding::BINARY) do |io|
|
66
|
+
MessagePack.load(io)
|
67
|
+
end
|
68
|
+
# handle malformed data due to upgrade incompatibility
|
69
|
+
rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
|
70
|
+
{}
|
71
|
+
rescue ArgumentError => error
|
72
|
+
if error.message =~ /negative array size/
|
73
|
+
{}
|
74
|
+
else
|
75
|
+
raise
|
76
|
+
end
|
72
77
|
end
|
73
78
|
end
|
74
79
|
|
@@ -80,10 +85,13 @@ module Bootsnap
|
|
80
85
|
exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY
|
81
86
|
# `encoding:` looks redundant wrt `binwrite`, but necessary on windows
|
82
87
|
# because binary is part of mode.
|
83
|
-
File.
|
88
|
+
File.open(tmp, mode: exclusive_write, encoding: Encoding::BINARY) do |io|
|
89
|
+
MessagePack.dump(@data, io, freeze: true)
|
90
|
+
end
|
84
91
|
FileUtils.mv(tmp, @store_path)
|
85
92
|
rescue Errno::EEXIST
|
86
93
|
retry
|
94
|
+
rescue SystemCallError
|
87
95
|
end
|
88
96
|
end
|
89
97
|
end
|
data/lib/bootsnap/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bootsnap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.7.
|
4
|
+
version: 1.7.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -42,14 +42,14 @@ dependencies:
|
|
42
42
|
name: rake-compiler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
@@ -149,9 +149,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
149
149
|
version: 2.3.0
|
150
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
151
|
requirements:
|
152
|
-
- - "
|
152
|
+
- - ">="
|
153
153
|
- !ruby/object:Gem::Version
|
154
|
-
version:
|
154
|
+
version: '0'
|
155
155
|
requirements: []
|
156
156
|
rubygems_version: 3.0.3
|
157
157
|
signing_key:
|