bootsnap 1.4.4-java → 1.4.9-java
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 +33 -0
- data/README.md +1 -1
- data/ext/bootsnap/bootsnap.c +113 -65
- data/ext/bootsnap/extconf.rb +1 -0
- data/lib/bootsnap.rb +2 -0
- data/lib/bootsnap/bundler.rb +1 -0
- data/lib/bootsnap/compile_cache.rb +4 -3
- data/lib/bootsnap/compile_cache/iseq.rb +6 -4
- data/lib/bootsnap/compile_cache/yaml.rb +67 -38
- data/lib/bootsnap/explicit_require.rb +1 -0
- data/lib/bootsnap/load_path_cache.rb +1 -1
- data/lib/bootsnap/load_path_cache/cache.rb +8 -8
- data/lib/bootsnap/load_path_cache/change_observer.rb +2 -1
- data/lib/bootsnap/load_path_cache/core_ext/active_support.rb +1 -0
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +18 -5
- data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +1 -0
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +33 -10
- data/lib/bootsnap/load_path_cache/path.rb +3 -2
- data/lib/bootsnap/load_path_cache/path_scanner.rb +39 -26
- data/lib/bootsnap/load_path_cache/realpath_cache.rb +5 -5
- data/lib/bootsnap/load_path_cache/store.rb +18 -14
- data/lib/bootsnap/setup.rb +1 -0
- data/lib/bootsnap/version.rb +2 -1
- metadata +9 -26
- data/.github/CODEOWNERS +0 -2
- data/.github/probots.yml +0 -2
- data/.gitignore +0 -17
- data/.rubocop.yml +0 -20
- data/.travis.yml +0 -21
- data/CODE_OF_CONDUCT.md +0 -74
- data/CONTRIBUTING.md +0 -21
- data/Gemfile +0 -8
- data/README.jp.md +0 -231
- data/Rakefile +0 -12
- data/bin/ci +0 -10
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/bin/test-minimal-support +0 -7
- data/bin/testunit +0 -8
- data/bootsnap.gemspec +0 -45
- data/dev.yml +0 -10
- data/shipit.rubygems.yml +0 -0
data/ext/bootsnap/extconf.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
data/lib/bootsnap/bundler.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Bootsnap
|
2
3
|
module CompileCache
|
3
4
|
Error = Class.new(StandardError)
|
@@ -28,14 +29,14 @@ module Bootsnap
|
|
28
29
|
raise(
|
29
30
|
PermissionError,
|
30
31
|
"bootsnap doesn't have permission to write cache entries in '#{cpath}' " \
|
31
|
-
"(or, less likely, doesn't have
|
32
|
+
"(or, less likely, doesn't have permission to read '#{path}')",
|
32
33
|
)
|
33
34
|
end
|
34
35
|
|
35
36
|
def self.supported?
|
36
|
-
# only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), and >= 2.3.0
|
37
|
+
# only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), Windows (RubyInstaller2) and >= 2.3.0
|
37
38
|
RUBY_ENGINE == 'ruby' &&
|
38
|
-
RUBY_PLATFORM =~ /darwin|linux|bsd/ &&
|
39
|
+
RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/ &&
|
39
40
|
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
|
40
41
|
end
|
41
42
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require('bootsnap/bootsnap')
|
2
3
|
require('zlib')
|
3
4
|
|
@@ -8,13 +9,13 @@ module Bootsnap
|
|
8
9
|
attr_accessor(:cache_dir)
|
9
10
|
end
|
10
11
|
|
11
|
-
def self.input_to_storage(_, path)
|
12
|
+
def self.input_to_storage(_, path, _args)
|
12
13
|
RubyVM::InstructionSequence.compile_file(path).to_binary
|
13
14
|
rescue SyntaxError
|
14
15
|
raise(Uncompilable, 'syntax error')
|
15
16
|
end
|
16
17
|
|
17
|
-
def self.storage_to_output(binary)
|
18
|
+
def self.storage_to_output(binary, _args)
|
18
19
|
RubyVM::InstructionSequence.load_from_binary(binary)
|
19
20
|
rescue RuntimeError => e
|
20
21
|
if e.message == 'broken binary format'
|
@@ -25,7 +26,7 @@ module Bootsnap
|
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
|
-
def self.input_to_output(_)
|
29
|
+
def self.input_to_output(_, _)
|
29
30
|
nil # ruby handles this
|
30
31
|
end
|
31
32
|
|
@@ -37,7 +38,8 @@ module Bootsnap
|
|
37
38
|
Bootsnap::CompileCache::Native.fetch(
|
38
39
|
Bootsnap::CompileCache::ISeq.cache_dir,
|
39
40
|
path.to_s,
|
40
|
-
Bootsnap::CompileCache::ISeq
|
41
|
+
Bootsnap::CompileCache::ISeq,
|
42
|
+
nil,
|
41
43
|
)
|
42
44
|
rescue Errno::EACCES
|
43
45
|
Bootsnap::CompileCache.permission_error(path)
|
@@ -1,59 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require('bootsnap/bootsnap')
|
2
3
|
|
3
4
|
module Bootsnap
|
4
5
|
module CompileCache
|
5
6
|
module YAML
|
6
7
|
class << self
|
7
|
-
attr_accessor(:msgpack_factory)
|
8
|
-
end
|
8
|
+
attr_accessor(:msgpack_factory, :cache_dir, :supported_options)
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
def input_to_storage(contents, _, kwargs)
|
11
|
+
raise(Uncompilable) if contents.index("!ruby/object")
|
12
|
+
obj = ::YAML.load(contents, **(kwargs || {}))
|
13
|
+
msgpack_factory.dump(obj)
|
14
|
+
rescue NoMethodError, RangeError
|
15
|
+
# if the object included things that we can't serialize, fall back to
|
16
|
+
# Marshal. It's a bit slower, but can encode anything yaml can.
|
17
|
+
# NoMethodError is unexpected types; RangeError is Bignums
|
18
|
+
Marshal.dump(obj)
|
19
|
+
end
|
20
|
+
|
21
|
+
def storage_to_output(data, kwargs)
|
22
|
+
# This could have a meaning in messagepack, and we're being a little lazy
|
23
|
+
# about it. -- but a leading 0x04 would indicate the contents of the YAML
|
24
|
+
# is a positive integer, which is rare, to say the least.
|
25
|
+
if data[0] == 0x04.chr && data[1] == 0x08.chr
|
26
|
+
Marshal.load(data)
|
27
|
+
else
|
28
|
+
msgpack_factory.load(data, **(kwargs || {}))
|
29
|
+
end
|
30
|
+
end
|
20
31
|
|
21
|
-
|
22
|
-
|
23
|
-
# about it. -- but a leading 0x04 would indicate the contents of the YAML
|
24
|
-
# is a positive integer, which is rare, to say the least.
|
25
|
-
if data[0] == 0x04.chr && data[1] == 0x08.chr
|
26
|
-
Marshal.load(data)
|
27
|
-
else
|
28
|
-
msgpack_factory.unpacker.feed(data).read
|
32
|
+
def input_to_output(data, kwargs)
|
33
|
+
::YAML.load(data, **(kwargs || {}))
|
29
34
|
end
|
30
|
-
end
|
31
35
|
|
32
|
-
|
33
|
-
|
36
|
+
def install!(cache_dir)
|
37
|
+
self.cache_dir = cache_dir
|
38
|
+
init!
|
39
|
+
::YAML.singleton_class.prepend(Patch)
|
40
|
+
end
|
41
|
+
|
42
|
+
def init!
|
43
|
+
require('yaml')
|
44
|
+
require('msgpack')
|
45
|
+
|
46
|
+
# MessagePack serializes symbols as strings by default.
|
47
|
+
# We want them to roundtrip cleanly, so we use a custom factory.
|
48
|
+
# see: https://github.com/msgpack/msgpack-ruby/pull/122
|
49
|
+
factory = MessagePack::Factory.new
|
50
|
+
factory.register_type(0x00, Symbol)
|
51
|
+
self.msgpack_factory = factory
|
52
|
+
|
53
|
+
self.supported_options = []
|
54
|
+
params = ::YAML.method(:load).parameters
|
55
|
+
if params.include?([:key, :symbolize_names])
|
56
|
+
self.supported_options << :symbolize_names
|
57
|
+
end
|
58
|
+
if params.include?([:key, :freeze])
|
59
|
+
if factory.load(factory.dump('yaml'), freeze: true).frozen?
|
60
|
+
self.supported_options << :freeze
|
61
|
+
end
|
62
|
+
end
|
63
|
+
self.supported_options.freeze
|
64
|
+
end
|
34
65
|
end
|
35
66
|
|
36
|
-
|
37
|
-
|
38
|
-
require('msgpack')
|
67
|
+
module Patch
|
68
|
+
extend self
|
39
69
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
70
|
+
def load_file(path, *args)
|
71
|
+
return super if args.size > 1
|
72
|
+
if kwargs = args.first
|
73
|
+
return super unless kwargs.is_a?(Hash)
|
74
|
+
return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
|
75
|
+
end
|
46
76
|
|
47
|
-
klass = class << ::YAML; self; end
|
48
|
-
klass.send(:define_method, :load_file) do |path|
|
49
77
|
begin
|
50
|
-
Bootsnap::CompileCache::Native.fetch(
|
51
|
-
cache_dir,
|
78
|
+
::Bootsnap::CompileCache::Native.fetch(
|
79
|
+
Bootsnap::CompileCache::YAML.cache_dir,
|
52
80
|
path,
|
53
|
-
Bootsnap::CompileCache::YAML
|
81
|
+
::Bootsnap::CompileCache::YAML,
|
82
|
+
kwargs,
|
54
83
|
)
|
55
84
|
rescue Errno::EACCES
|
56
|
-
Bootsnap::CompileCache.permission_error(path)
|
85
|
+
::Bootsnap::CompileCache.permission_error(path)
|
57
86
|
end
|
58
87
|
end
|
59
88
|
end
|
@@ -46,7 +46,7 @@ module Bootsnap
|
|
46
46
|
# loadpath.
|
47
47
|
def find(feature)
|
48
48
|
reinitialize if (@has_relative_paths && dir_changed?) || stale?
|
49
|
-
feature = feature.to_s
|
49
|
+
feature = feature.to_s.freeze
|
50
50
|
return feature if absolute_path?(feature)
|
51
51
|
return expand_path(feature) if feature.start_with?('./')
|
52
52
|
@mutex.synchronize do
|
@@ -67,7 +67,7 @@ module Bootsnap
|
|
67
67
|
# native dynamic extension, e.g. .bundle or .so), we know it was a
|
68
68
|
# failure and there's nothing more we can do to find the file.
|
69
69
|
# no extension, .rb, (.bundle or .so)
|
70
|
-
when '', *CACHED_EXTENSIONS
|
70
|
+
when '', *CACHED_EXTENSIONS
|
71
71
|
nil
|
72
72
|
# Ruby allows specifying native extensions as '.so' even when DLEXT
|
73
73
|
# is '.bundle'. This is where we handle that case.
|
@@ -144,7 +144,7 @@ module Bootsnap
|
|
144
144
|
expanded_path = p.expanded_path
|
145
145
|
entries, dirs = p.entries_and_dirs(@store)
|
146
146
|
# push -> low precedence -> set only if unset
|
147
|
-
dirs.each { |dir| @dirs[dir]
|
147
|
+
dirs.each { |dir| @dirs[dir] ||= path }
|
148
148
|
entries.each { |rel| @index[rel] ||= expanded_path }
|
149
149
|
end
|
150
150
|
end
|
@@ -178,25 +178,25 @@ module Bootsnap
|
|
178
178
|
|
179
179
|
if DLEXT2
|
180
180
|
def search_index(f)
|
181
|
-
try_index(f
|
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(f
|
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(f
|
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(f
|
193
|
+
try_ext("#{f}#{DOT_RB}") || try_ext("#{f}#{DLEXT}") || f
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
197
197
|
def try_index(f)
|
198
198
|
if (p = @index[f])
|
199
|
-
p
|
199
|
+
"#{p}/#{f}"
|
200
200
|
end
|
201
201
|
end
|
202
202
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Bootsnap
|
2
3
|
module LoadPathCache
|
3
4
|
module ChangeObserver
|
@@ -25,7 +26,7 @@ module Bootsnap
|
|
25
26
|
super
|
26
27
|
end
|
27
28
|
|
28
|
-
# uniq! keeps the first
|
29
|
+
# uniq! keeps the first occurrence of each path, otherwise preserving
|
29
30
|
# order, preserving the effective load path
|
30
31
|
def uniq!(*args)
|
31
32
|
ret = super
|
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Bootsnap
|
2
3
|
module LoadPathCache
|
3
4
|
module CoreExt
|
4
5
|
def self.make_load_error(path)
|
5
|
-
err = LoadError.new("cannot load such file -- #{path}")
|
6
|
+
err = LoadError.new(+"cannot load such file -- #{path}")
|
6
7
|
err.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
|
7
8
|
err.define_singleton_method(:path) { path }
|
8
9
|
err
|
@@ -37,7 +38,11 @@ module Kernel
|
|
37
38
|
rescue Bootsnap::LoadPathCache::ReturnFalse
|
38
39
|
false
|
39
40
|
rescue Bootsnap::LoadPathCache::FallbackScan
|
40
|
-
|
41
|
+
fallback = true
|
42
|
+
ensure
|
43
|
+
if fallback
|
44
|
+
require_with_bootsnap_lfi(path)
|
45
|
+
end
|
41
46
|
end
|
42
47
|
|
43
48
|
alias_method(:require_relative_without_bootsnap, :require_relative)
|
@@ -55,7 +60,7 @@ module Kernel
|
|
55
60
|
end
|
56
61
|
|
57
62
|
# load also allows relative paths from pwd even when not in $:
|
58
|
-
if File.exist?(relative = File.expand_path(path))
|
63
|
+
if File.exist?(relative = File.expand_path(path).freeze)
|
59
64
|
return load_without_bootsnap(relative, wrap)
|
60
65
|
end
|
61
66
|
|
@@ -66,7 +71,11 @@ module Kernel
|
|
66
71
|
rescue Bootsnap::LoadPathCache::ReturnFalse
|
67
72
|
false
|
68
73
|
rescue Bootsnap::LoadPathCache::FallbackScan
|
69
|
-
|
74
|
+
fallback = true
|
75
|
+
ensure
|
76
|
+
if fallback
|
77
|
+
load_without_bootsnap(path, wrap)
|
78
|
+
end
|
70
79
|
end
|
71
80
|
end
|
72
81
|
|
@@ -87,6 +96,10 @@ class Module
|
|
87
96
|
rescue Bootsnap::LoadPathCache::ReturnFalse
|
88
97
|
false
|
89
98
|
rescue Bootsnap::LoadPathCache::FallbackScan
|
90
|
-
|
99
|
+
fallback = true
|
100
|
+
ensure
|
101
|
+
if fallback
|
102
|
+
autoload_without_bootsnap(const, path)
|
103
|
+
end
|
91
104
|
end
|
92
105
|
end
|
@@ -40,7 +40,7 @@ module Bootsnap
|
|
40
40
|
# /a/b/lib/my/foo.rb
|
41
41
|
# ^^^^^^^^^
|
42
42
|
short = feat[(lpe.length + 1)..-1]
|
43
|
-
stripped =
|
43
|
+
stripped = strip_extension_if_elidable(short)
|
44
44
|
@lfi[short] = hash
|
45
45
|
@lfi[stripped] = hash
|
46
46
|
end
|
@@ -94,13 +94,14 @@ module Bootsnap
|
|
94
94
|
|
95
95
|
hash = long.hash
|
96
96
|
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
#
|
97
|
+
# Do we have a filename with an elidable extension, e.g.,
|
98
|
+
# 'bundler.rb', or 'libgit2.so'?
|
99
|
+
altname = if extension_elidable?(short)
|
100
|
+
# Strip the extension off, e.g. 'bundler.rb' -> 'bundler'.
|
101
|
+
strip_extension_if_elidable(short)
|
102
|
+
elsif long && (ext = File.extname(long.freeze))
|
103
|
+
# We already know the extension of the actual file this
|
104
|
+
# resolves to, so put that back on.
|
104
105
|
short + ext
|
105
106
|
end
|
106
107
|
|
@@ -117,8 +118,30 @@ module Bootsnap
|
|
117
118
|
STRIP_EXTENSION = /\.[^.]*?$/
|
118
119
|
private_constant(:STRIP_EXTENSION)
|
119
120
|
|
120
|
-
|
121
|
-
|
121
|
+
# Might Ruby automatically search for this extension if
|
122
|
+
# someone tries to 'require' the file without it? E.g. Ruby
|
123
|
+
# will implicitly try 'x.rb' if you ask for 'x'.
|
124
|
+
#
|
125
|
+
# This is complex and platform-dependent, and the Ruby docs are a little
|
126
|
+
# handwavy about what will be tried when and in what order.
|
127
|
+
# So optimistically pretend that all known elidable extensions
|
128
|
+
# will be tried on all platforms, and that people are unlikely
|
129
|
+
# to name files in a way that assumes otherwise.
|
130
|
+
# (E.g. It's unlikely that someone will know that their code
|
131
|
+
# will _never_ run on MacOS, and therefore think they can get away
|
132
|
+
# with calling a Ruby file 'x.dylib.rb' and then requiring it as 'x.dylib'.)
|
133
|
+
#
|
134
|
+
# See <https://ruby-doc.org/core-2.6.4/Kernel.html#method-i-require>.
|
135
|
+
def extension_elidable?(f)
|
136
|
+
f.to_s.end_with?('.rb', '.so', '.o', '.dll', '.dylib')
|
137
|
+
end
|
138
|
+
|
139
|
+
def strip_extension_if_elidable(f)
|
140
|
+
if extension_elidable?(f)
|
141
|
+
f.sub(STRIP_EXTENSION, '')
|
142
|
+
else
|
143
|
+
f
|
144
|
+
end
|
122
145
|
end
|
123
146
|
end
|
124
147
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative('path_scanner')
|
2
3
|
|
3
4
|
module Bootsnap
|
@@ -20,7 +21,7 @@ module Bootsnap
|
|
20
21
|
attr_reader(:path)
|
21
22
|
|
22
23
|
def initialize(path)
|
23
|
-
@path = path.to_s
|
24
|
+
@path = path.to_s.freeze
|
24
25
|
end
|
25
26
|
|
26
27
|
# True if the path exists, but represents a non-directory object
|
@@ -59,7 +60,7 @@ module Bootsnap
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def expanded_path
|
62
|
-
File.expand_path(path)
|
63
|
+
File.expand_path(path).freeze
|
63
64
|
end
|
64
65
|
|
65
66
|
private
|