bootsnap 1.10.3 → 1.11.0
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 +13 -0
- data/ext/bootsnap/bootsnap.c +10 -1
- data/lib/bootsnap/compile_cache.rb +1 -3
- data/lib/bootsnap/load_path_cache/cache.rb +4 -0
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +3 -12
- data/lib/bootsnap/load_path_cache/path.rb +24 -2
- data/lib/bootsnap/load_path_cache/store.rb +19 -6
- data/lib/bootsnap/load_path_cache.rb +1 -3
- data/lib/bootsnap/version.rb +1 -1
- data/lib/bootsnap.rb +11 -0
- metadata +3 -4
- data/lib/bootsnap/load_path_cache/realpath_cache.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af127c58fb31e53309de406862116407d9f57d43514937d400a0f87c13080447
|
4
|
+
data.tar.gz: 497f3a471eed46b68e624f8cda87bc6d5e97d5a17bdf4cbeb2221019fb21d531
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32c3bba78bf66bb71b47d78e06592e4a670735d581c84043b4c125704fb91d4cff900da0e2884c910f3c66ddf9e31f4860a33718da978cc9f2719e32a9f1f617
|
7
|
+
data.tar.gz: 11a5bdee97b35fc99d346ae2cd44e95e8fc3cfd949bddc06a7561b7329fd42a0e63ef5e747a90fa599125100cc368d9ef6c9ad207a1a69fe51f6c32e71992611
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.11.0
|
4
|
+
|
5
|
+
* Drop dependency on `fileutils`.
|
6
|
+
|
7
|
+
* Better respect `Kernel#require` duck typing. While it almost never comes up in practice, `Kernel#require`
|
8
|
+
follow a fairly intricate duck-typing protocol on its argument implemented as `rb_get_path(VALUE)` in MRI.
|
9
|
+
So when applicable we bind `rb_get_path` and use it for improved compatibility. See #396 and #406.
|
10
|
+
|
11
|
+
* Get rid of the `Kernel.require_relative` decorator by resolving `$LOAD_PATH` members to their real path.
|
12
|
+
This way we handle symlinks in `$LOAD_PATH` much more efficiently. See #402 for the detailed explanation.
|
13
|
+
|
14
|
+
* Drop support for Ruby 2.3 (to allow getting rid of the `Kernel.require_relative` decorator).
|
15
|
+
|
3
16
|
# 1.10.3
|
4
17
|
|
5
18
|
* Fix Regexp and Date type support in YAML compile cache. (#400)
|
data/ext/bootsnap/bootsnap.c
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
* Suggested reading order:
|
3
3
|
* 1. Skim Init_bootsnap
|
4
4
|
* 2. Skim bs_fetch
|
5
|
-
* 3. The rest of
|
5
|
+
* 3. The rest of everything
|
6
6
|
*
|
7
7
|
* Init_bootsnap sets up the ruby objects and binds bs_fetch to
|
8
8
|
* Bootsnap::CompileCache::Native.fetch.
|
@@ -135,6 +135,12 @@ bs_rb_coverage_running(VALUE self)
|
|
135
135
|
return RTEST(cov) ? Qtrue : Qfalse;
|
136
136
|
}
|
137
137
|
|
138
|
+
static VALUE
|
139
|
+
bs_rb_get_path(VALUE self, VALUE fname)
|
140
|
+
{
|
141
|
+
return rb_get_path(fname);
|
142
|
+
}
|
143
|
+
|
138
144
|
/*
|
139
145
|
* Ruby C extensions are initialized by calling Init_<extname>.
|
140
146
|
*
|
@@ -146,6 +152,9 @@ void
|
|
146
152
|
Init_bootsnap(void)
|
147
153
|
{
|
148
154
|
rb_mBootsnap = rb_define_module("Bootsnap");
|
155
|
+
|
156
|
+
rb_define_singleton_method(rb_mBootsnap, "rb_get_path", bs_rb_get_path, 1);
|
157
|
+
|
149
158
|
rb_mBootsnap_CompileCache = rb_define_module_under(rb_mBootsnap, "CompileCache");
|
150
159
|
rb_mBootsnap_CompileCache_Native = rb_define_module_under(rb_mBootsnap_CompileCache, "Native");
|
151
160
|
rb_cBootsnap_CompileCache_UNCOMPILABLE = rb_const_get(rb_mBootsnap_CompileCache, rb_intern("UNCOMPILABLE"));
|
@@ -50,9 +50,7 @@ module Bootsnap
|
|
50
50
|
|
51
51
|
def self.supported?
|
52
52
|
# only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), Windows (RubyInstaller2) and >= 2.3.0
|
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")
|
53
|
+
RUBY_ENGINE == "ruby" && RUBY_PLATFORM.match?(/darwin|linux|bsd|mswin|mingw|cygwin/)
|
56
54
|
end
|
57
55
|
end
|
58
56
|
end
|
@@ -142,6 +142,8 @@ module Bootsnap
|
|
142
142
|
@has_relative_paths = true if p.relative?
|
143
143
|
next if p.non_directory?
|
144
144
|
|
145
|
+
p = p.to_realpath
|
146
|
+
|
145
147
|
expanded_path = p.expanded_path
|
146
148
|
entries, dirs = p.entries_and_dirs(@store)
|
147
149
|
# push -> low precedence -> set only if unset
|
@@ -157,6 +159,8 @@ module Bootsnap
|
|
157
159
|
p = Path.new(path)
|
158
160
|
next if p.non_directory?
|
159
161
|
|
162
|
+
p = p.to_realpath
|
163
|
+
|
160
164
|
expanded_path = p.expanded_path
|
161
165
|
entries, dirs = p.entries_and_dirs(@store)
|
162
166
|
# unshift -> high precedence -> unconditional set
|
@@ -6,7 +6,7 @@ module Kernel
|
|
6
6
|
alias_method(:require_without_bootsnap, :require)
|
7
7
|
|
8
8
|
def require(path)
|
9
|
-
string_path = path
|
9
|
+
string_path = Bootsnap.rb_get_path(path)
|
10
10
|
return false if Bootsnap::LoadPathCache.loaded_features_index.key?(string_path)
|
11
11
|
|
12
12
|
resolved = Bootsnap::LoadPathCache.load_path_cache.find(string_path)
|
@@ -33,18 +33,9 @@ module Kernel
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
alias_method(:require_relative_without_bootsnap, :require_relative)
|
37
|
-
def require_relative(path)
|
38
|
-
location = caller_locations(1..1).first
|
39
|
-
realpath = Bootsnap::LoadPathCache.realpath_cache.call(
|
40
|
-
location.absolute_path || location.path, path
|
41
|
-
)
|
42
|
-
require(realpath)
|
43
|
-
end
|
44
|
-
|
45
36
|
alias_method(:load_without_bootsnap, :load)
|
46
37
|
def load(path, wrap = false)
|
47
|
-
if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(path, try_extensions: false))
|
38
|
+
if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(Bootsnap.rb_get_path(path), try_extensions: false))
|
48
39
|
load_without_bootsnap(resolved, wrap)
|
49
40
|
else
|
50
41
|
load_without_bootsnap(path, wrap)
|
@@ -62,7 +53,7 @@ class Module
|
|
62
53
|
# The challenge is that we don't control the point at which the entry gets
|
63
54
|
# added to $LOADED_FEATURES and won't be able to hook that modification
|
64
55
|
# since it's done in C-land.
|
65
|
-
resolved = Bootsnap::LoadPathCache.load_path_cache.find(path)
|
56
|
+
resolved = Bootsnap::LoadPathCache.load_path_cache.find(Bootsnap.rb_get_path(path))
|
66
57
|
if Bootsnap::LoadPathCache::FALLBACK_SCAN.equal?(resolved)
|
67
58
|
autoload_without_bootsnap(const, path)
|
68
59
|
elsif resolved == false
|
@@ -21,8 +21,26 @@ module Bootsnap
|
|
21
21
|
|
22
22
|
attr_reader(:path)
|
23
23
|
|
24
|
-
def initialize(path)
|
24
|
+
def initialize(path, real: false)
|
25
25
|
@path = path.to_s.freeze
|
26
|
+
@real = real
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_realpath
|
30
|
+
return self if @real
|
31
|
+
|
32
|
+
realpath = begin
|
33
|
+
File.realpath(path)
|
34
|
+
rescue Errno::ENOENT
|
35
|
+
return self
|
36
|
+
end
|
37
|
+
|
38
|
+
if realpath != path
|
39
|
+
Path.new(realpath, real: true)
|
40
|
+
else
|
41
|
+
@real = true
|
42
|
+
self
|
43
|
+
end
|
26
44
|
end
|
27
45
|
|
28
46
|
# True if the path exists, but represents a non-directory object
|
@@ -62,7 +80,11 @@ module Bootsnap
|
|
62
80
|
end
|
63
81
|
|
64
82
|
def expanded_path
|
65
|
-
|
83
|
+
if @real
|
84
|
+
path
|
85
|
+
else
|
86
|
+
@expanded_path ||= File.expand_path(path).freeze
|
87
|
+
end
|
66
88
|
end
|
67
89
|
|
68
90
|
private
|
@@ -69,7 +69,7 @@ module Bootsnap
|
|
69
69
|
def load_data
|
70
70
|
@data = begin
|
71
71
|
data = File.open(@store_path, encoding: Encoding::BINARY) do |io|
|
72
|
-
MessagePack.load(io)
|
72
|
+
MessagePack.load(io, freeze: true)
|
73
73
|
end
|
74
74
|
if data.is_a?(Hash) && data[VERSION_KEY] == CURRENT_VERSION
|
75
75
|
data
|
@@ -89,19 +89,17 @@ module Bootsnap
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def dump_data
|
92
|
-
require "fileutils" unless defined? FileUtils
|
93
|
-
|
94
92
|
# Change contents atomically so other processes can't get invalid
|
95
93
|
# caches if they read at an inopportune time.
|
96
94
|
tmp = "#{@store_path}.#{Process.pid}.#{(rand * 100_000).to_i}.tmp"
|
97
|
-
|
95
|
+
mkdir_p(File.dirname(tmp))
|
98
96
|
exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY
|
99
97
|
# `encoding:` looks redundant wrt `binwrite`, but necessary on windows
|
100
98
|
# because binary is part of mode.
|
101
99
|
File.open(tmp, mode: exclusive_write, encoding: Encoding::BINARY) do |io|
|
102
|
-
MessagePack.dump(@data, io
|
100
|
+
MessagePack.dump(@data, io)
|
103
101
|
end
|
104
|
-
|
102
|
+
File.rename(tmp, @store_path)
|
105
103
|
rescue Errno::EEXIST
|
106
104
|
retry
|
107
105
|
rescue SystemCallError
|
@@ -110,6 +108,21 @@ module Bootsnap
|
|
110
108
|
def default_data
|
111
109
|
{VERSION_KEY => CURRENT_VERSION}
|
112
110
|
end
|
111
|
+
|
112
|
+
def mkdir_p(path)
|
113
|
+
stack = []
|
114
|
+
until File.directory?(path)
|
115
|
+
stack.push path
|
116
|
+
path = File.dirname(path)
|
117
|
+
end
|
118
|
+
stack.reverse_each do |dir|
|
119
|
+
begin
|
120
|
+
Dir.mkdir(dir)
|
121
|
+
rescue SystemCallError
|
122
|
+
raise unless File.directory?(dir)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
113
126
|
end
|
114
127
|
end
|
115
128
|
end
|
@@ -22,7 +22,7 @@ module Bootsnap
|
|
22
22
|
CACHED_EXTENSIONS = DLEXT2 ? [DOT_RB, DLEXT, DLEXT2] : [DOT_RB, DLEXT]
|
23
23
|
|
24
24
|
class << self
|
25
|
-
attr_reader(:load_path_cache, :loaded_features_index
|
25
|
+
attr_reader(:load_path_cache, :loaded_features_index)
|
26
26
|
|
27
27
|
def setup(cache_path:, development_mode:)
|
28
28
|
unless supported?
|
@@ -33,7 +33,6 @@ module Bootsnap
|
|
33
33
|
store = Store.new(cache_path)
|
34
34
|
|
35
35
|
@loaded_features_index = LoadedFeaturesIndex.new
|
36
|
-
@realpath_cache = RealpathCache.new
|
37
36
|
|
38
37
|
@load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
|
39
38
|
require_relative("load_path_cache/core_ext/kernel_require")
|
@@ -55,5 +54,4 @@ if Bootsnap::LoadPathCache.supported?
|
|
55
54
|
require_relative("load_path_cache/store")
|
56
55
|
require_relative("load_path_cache/change_observer")
|
57
56
|
require_relative("load_path_cache/loaded_features_index")
|
58
|
-
require_relative("load_path_cache/realpath_cache")
|
59
57
|
end
|
data/lib/bootsnap/version.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
@@ -133,5 +133,16 @@ module Bootsnap
|
|
133
133
|
path.start_with?("/")
|
134
134
|
end
|
135
135
|
end
|
136
|
+
|
137
|
+
# This is a semi-accurate ruby implementation of the native `rb_get_path(VALUE)` function.
|
138
|
+
# The native version is very intricate and may behave differently on windows etc.
|
139
|
+
# But we only use it for non-MRI platform.
|
140
|
+
def rb_get_path(fname)
|
141
|
+
path_path = fname.respond_to?(:to_path) ? fname.to_path : fname
|
142
|
+
String.try_convert(path_path) || raise(TypeError, "no implicit conversion of #{path_path.class} into String")
|
143
|
+
end
|
144
|
+
|
145
|
+
# Allow the C extension to redefine `rb_get_path` without warning.
|
146
|
+
alias_method :rb_get_path, :rb_get_path # rubocop:disable Lint/DuplicateMethods
|
136
147
|
end
|
137
148
|
end
|
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.
|
4
|
+
version: 1.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -57,7 +57,6 @@ files:
|
|
57
57
|
- lib/bootsnap/load_path_cache/loaded_features_index.rb
|
58
58
|
- lib/bootsnap/load_path_cache/path.rb
|
59
59
|
- lib/bootsnap/load_path_cache/path_scanner.rb
|
60
|
-
- lib/bootsnap/load_path_cache/realpath_cache.rb
|
61
60
|
- lib/bootsnap/load_path_cache/store.rb
|
62
61
|
- lib/bootsnap/setup.rb
|
63
62
|
- lib/bootsnap/version.rb
|
@@ -77,7 +76,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
77
76
|
requirements:
|
78
77
|
- - ">="
|
79
78
|
- !ruby/object:Gem::Version
|
80
|
-
version: 2.
|
79
|
+
version: 2.4.0
|
81
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
81
|
requirements:
|
83
82
|
- - ">="
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Bootsnap
|
4
|
-
module LoadPathCache
|
5
|
-
class RealpathCache
|
6
|
-
def initialize
|
7
|
-
@cache = Hash.new { |h, k| h[k] = realpath(*k) }
|
8
|
-
end
|
9
|
-
|
10
|
-
def call(*key)
|
11
|
-
@cache[key]
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def realpath(caller_location, path)
|
17
|
-
base = File.dirname(caller_location)
|
18
|
-
abspath = File.expand_path(path, base).freeze
|
19
|
-
find_file(abspath)
|
20
|
-
end
|
21
|
-
|
22
|
-
def find_file(name)
|
23
|
-
return File.realpath(name).freeze if File.exist?(name)
|
24
|
-
|
25
|
-
CACHED_EXTENSIONS.each do |ext|
|
26
|
-
filename = "#{name}#{ext}"
|
27
|
-
return File.realpath(filename).freeze if File.exist?(filename)
|
28
|
-
end
|
29
|
-
name
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|