bootsnap 1.13.0 → 1.16.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 +19 -0
- data/README.md +8 -2
- data/ext/bootsnap/bootsnap.c +23 -8
- data/lib/bootsnap/compile_cache/yaml.rb +5 -2
- data/lib/bootsnap/compile_cache.rb +5 -1
- data/lib/bootsnap/load_path_cache/change_observer.rb +1 -1
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +2 -2
- data/lib/bootsnap/load_path_cache/path.rb +2 -2
- data/lib/bootsnap/load_path_cache/path_scanner.rb +6 -0
- data/lib/bootsnap/load_path_cache/store.rb +3 -2
- data/lib/bootsnap/load_path_cache.rb +3 -3
- data/lib/bootsnap/version.rb +1 -1
- data/lib/bootsnap.rb +13 -27
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bf1eca00971c561ca1e15941903dcf193ec8fc84c68736177a3aa72558c536b
|
4
|
+
data.tar.gz: bcd5596d1b4b00905af82cf25693fb72e71897685e024b27311353eef6f588bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d3e37e56d994647ac88a1c9b83f087f137d32acfc09bfba1e71a85ce254697b1dcf6c9e1c90b5c71728ce0f3c0a63ee86680455a8f95003d237671435042859
|
7
|
+
data.tar.gz: 270bf8fc609981d25441c9c4bd975348130177564f2e1a0744f18720d7f59cda3c3da24bea0c07f2498a185308647b05715e1b1dd5a6045e653600ab2f5907a1
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.16.0
|
4
|
+
|
5
|
+
* Use `RbConfig::CONFIG["rubylibdir"]` instead of `RbConfig::CONFIG["libdir"]` to check for stdlib files. See #431.
|
6
|
+
* Fix the cached version of `YAML.load_file` being slightly more permissive than the default `Psych` one. See #434.
|
7
|
+
`Date` and `Time` values are now properly rejected, as well as aliases.
|
8
|
+
If this causes a regression in your application, it is recommended to load *trusted* YAML files with `YAML.unsafe_load_file`.
|
9
|
+
|
10
|
+
# 1.15.0
|
11
|
+
|
12
|
+
* Add a readonly mode, for environments in which the updated cache wouldn't be persisted. See #428 and #423.
|
13
|
+
|
14
|
+
# 1.14.0
|
15
|
+
|
16
|
+
* Require Ruby 2.6.
|
17
|
+
* Add a way to skip directories during load path scanning.
|
18
|
+
If you have large non-ruby directories in the middle of your load path, it can severely slow down scanning.
|
19
|
+
Typically this is a problem with `node_modules`. See #277.
|
20
|
+
* Fix `Bootsnap.unload_cache!`, it simply wouldn't work at all becaue of a merge mistake. See #421.
|
21
|
+
|
3
22
|
# 1.13.0
|
4
23
|
|
5
24
|
* Stop decorating `Kernel.load`. This used to be very useful in development because the Rails "classic" autoloader
|
data/README.md
CHANGED
@@ -52,10 +52,12 @@ require 'bootsnap'
|
|
52
52
|
env = ENV['RAILS_ENV'] || "development"
|
53
53
|
Bootsnap.setup(
|
54
54
|
cache_dir: 'tmp/cache', # Path to your cache
|
55
|
+
ignore_directories: ['node_modules'], # Directory names to skip.
|
55
56
|
development_mode: env == 'development', # Current working environment, e.g. RACK_ENV, RAILS_ENV, etc
|
56
57
|
load_path_cache: true, # Optimize the LOAD_PATH with a cache
|
57
58
|
compile_cache_iseq: true, # Compile Ruby code into ISeq cache, breaks coverage reporting.
|
58
|
-
compile_cache_yaml: true
|
59
|
+
compile_cache_yaml: true, # Compile YAML into a cache
|
60
|
+
readonly: true, # Use the caches but don't update them on miss or stale entries.
|
59
61
|
)
|
60
62
|
```
|
61
63
|
|
@@ -66,7 +68,7 @@ will help optimize boot time further if you have an extremely large `$LOAD_PATH`
|
|
66
68
|
Note: Bootsnap and [Spring](https://github.com/rails/spring) are orthogonal tools. While Bootsnap
|
67
69
|
speeds up the loading of individual source files, Spring keeps a copy of a pre-booted Rails process
|
68
70
|
on hand to completely skip parts of the boot process the next time it's needed. The two tools work
|
69
|
-
well together
|
71
|
+
well together.
|
70
72
|
|
71
73
|
### Environment variables
|
72
74
|
|
@@ -76,7 +78,11 @@ well together, and are both included in a newly-generated Rails applications by
|
|
76
78
|
- `DISABLE_BOOTSNAP` allows to entirely disable bootsnap.
|
77
79
|
- `DISABLE_BOOTSNAP_LOAD_PATH_CACHE` allows to disable load path caching.
|
78
80
|
- `DISABLE_BOOTSNAP_COMPILE_CACHE` allows to disable ISeq and YAML caches.
|
81
|
+
- `BOOTSNAP_READONLY` configure bootsnap to not update the cache on miss or stale entries.
|
79
82
|
- `BOOTSNAP_LOG` configure bootsnap to log all caches misses to STDERR.
|
83
|
+
- `BOOTSNAP_IGNORE_DIRECTORIES` a comma separated list of directories that shouldn't be scanned.
|
84
|
+
Useful when you have large directories of non-ruby files inside `$LOAD_PATH`.
|
85
|
+
It defaults to ignore any directory named `node_modules`.
|
80
86
|
|
81
87
|
### Environments
|
82
88
|
|
data/ext/bootsnap/bootsnap.c
CHANGED
@@ -90,9 +90,11 @@ static ID instrumentation_method;
|
|
90
90
|
static VALUE sym_miss;
|
91
91
|
static VALUE sym_stale;
|
92
92
|
static bool instrumentation_enabled = false;
|
93
|
+
static bool readonly = false;
|
93
94
|
|
94
95
|
/* Functions exposed as module functions on Bootsnap::CompileCache::Native */
|
95
96
|
static VALUE bs_instrumentation_enabled_set(VALUE self, VALUE enabled);
|
97
|
+
static VALUE bs_readonly_set(VALUE self, VALUE enabled);
|
96
98
|
static VALUE bs_compile_option_crc32_set(VALUE self, VALUE crc32_v);
|
97
99
|
static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler, VALUE args);
|
98
100
|
static VALUE bs_rb_precompile(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler);
|
@@ -166,6 +168,7 @@ Init_bootsnap(void)
|
|
166
168
|
rb_global_variable(&sym_stale);
|
167
169
|
|
168
170
|
rb_define_module_function(rb_mBootsnap, "instrumentation_enabled=", bs_instrumentation_enabled_set, 1);
|
171
|
+
rb_define_module_function(rb_mBootsnap_CompileCache_Native, "readonly=", bs_readonly_set, 1);
|
169
172
|
rb_define_module_function(rb_mBootsnap_CompileCache_Native, "coverage_running?", bs_rb_coverage_running, 0);
|
170
173
|
rb_define_module_function(rb_mBootsnap_CompileCache_Native, "fetch", bs_rb_fetch, 4);
|
171
174
|
rb_define_module_function(rb_mBootsnap_CompileCache_Native, "precompile", bs_rb_precompile, 3);
|
@@ -182,6 +185,13 @@ bs_instrumentation_enabled_set(VALUE self, VALUE enabled)
|
|
182
185
|
return enabled;
|
183
186
|
}
|
184
187
|
|
188
|
+
static VALUE
|
189
|
+
bs_readonly_set(VALUE self, VALUE enabled)
|
190
|
+
{
|
191
|
+
readonly = RTEST(enabled);
|
192
|
+
return enabled;
|
193
|
+
}
|
194
|
+
|
185
195
|
/*
|
186
196
|
* Bootsnap's ruby code registers a hook that notifies us via this function
|
187
197
|
* when compile_option changes. These changes invalidate all existing caches.
|
@@ -945,12 +955,17 @@ try_input_to_storage(VALUE arg)
|
|
945
955
|
static int
|
946
956
|
bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data)
|
947
957
|
{
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
958
|
+
if (readonly) {
|
959
|
+
*storage_data = rb_cBootsnap_CompileCache_UNCOMPILABLE;
|
960
|
+
return 0;
|
961
|
+
} else {
|
962
|
+
int state;
|
963
|
+
struct i2s_data i2s_data = {
|
964
|
+
.handler = handler,
|
965
|
+
.input_data = input_data,
|
966
|
+
.pathval = pathval,
|
967
|
+
};
|
968
|
+
*storage_data = rb_protect(try_input_to_storage, (VALUE)&i2s_data, &state);
|
969
|
+
return state;
|
970
|
+
}
|
956
971
|
}
|
@@ -65,7 +65,7 @@ module Bootsnap
|
|
65
65
|
end
|
66
66
|
|
67
67
|
unless const_defined?(:NoTagsVisitor)
|
68
|
-
visitor = Class.new(Psych::Visitors::
|
68
|
+
visitor = Class.new(Psych::Visitors::NoAliasRuby) do
|
69
69
|
def visit(target)
|
70
70
|
if target.tag
|
71
71
|
raise UnsupportedTags, "YAML tags are not supported: #{target.tag}"
|
@@ -129,7 +129,10 @@ module Bootsnap
|
|
129
129
|
ast = ::YAML.parse(payload)
|
130
130
|
return ast unless ast
|
131
131
|
|
132
|
-
|
132
|
+
loader = ::Psych::ClassLoader::Restricted.new(["Symbol"], [])
|
133
|
+
scanner = ::Psych::ScalarScanner.new(loader)
|
134
|
+
|
135
|
+
NoTagsVisitor.new(scanner, loader).visit(ast)
|
133
136
|
end
|
134
137
|
end
|
135
138
|
|
@@ -10,7 +10,7 @@ module Bootsnap
|
|
10
10
|
Error = Class.new(StandardError)
|
11
11
|
PermissionError = Class.new(Error)
|
12
12
|
|
13
|
-
def self.setup(cache_dir:, iseq:, yaml:, json:)
|
13
|
+
def self.setup(cache_dir:, iseq:, yaml:, json:, readonly: false)
|
14
14
|
if iseq
|
15
15
|
if supported?
|
16
16
|
require_relative("compile_cache/iseq")
|
@@ -37,6 +37,10 @@ module Bootsnap
|
|
37
37
|
warn("[bootsnap/setup] JSON parsing caching is not supported on this implementation of Ruby")
|
38
38
|
end
|
39
39
|
end
|
40
|
+
|
41
|
+
if supported? && defined?(Bootsnap::CompileCache::Native)
|
42
|
+
Bootsnap::CompileCache::Native.readonly = readonly
|
43
|
+
end
|
40
44
|
end
|
41
45
|
|
42
46
|
def self.permission_error(path)
|
@@ -66,7 +66,7 @@ module Bootsnap
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def self.unregister(arr)
|
69
|
-
return unless arr.instance_variable_get(:@lpc_observer)
|
69
|
+
return unless arr.instance_variable_defined?(:@lpc_observer) && arr.instance_variable_get(:@lpc_observer)
|
70
70
|
|
71
71
|
ArrayMixin.instance_methods.each do |method_name|
|
72
72
|
arr.singleton_class.send(:remove_method, method_name)
|
@@ -40,7 +40,7 @@ module Bootsnap
|
|
40
40
|
|
41
41
|
# /a/b/lib/my/foo.rb
|
42
42
|
# ^^^^^^^^^
|
43
|
-
short = feat[(lpe.length + 1)
|
43
|
+
short = feat[(lpe.length + 1)..]
|
44
44
|
stripped = strip_extension_if_elidable(short)
|
45
45
|
@lfi[short] = hash
|
46
46
|
@lfi[stripped] = hash
|
@@ -76,7 +76,7 @@ module Bootsnap
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def identify(short, cursor)
|
79
|
-
$LOADED_FEATURES[cursor
|
79
|
+
$LOADED_FEATURES[cursor..].detect do |feat|
|
80
80
|
offset = 0
|
81
81
|
while (offset = feat.index(short, offset))
|
82
82
|
if feat.index(".", offset + 1) && !feat.index("/", offset + 2)
|
@@ -116,8 +116,8 @@ module Bootsnap
|
|
116
116
|
VOLATILE = :volatile
|
117
117
|
|
118
118
|
# Built-in ruby lib stuff doesn't change, but things can occasionally be
|
119
|
-
# installed into sitedir, which generally lives under
|
120
|
-
RUBY_LIBDIR = RbConfig::CONFIG["
|
119
|
+
# installed into sitedir, which generally lives under rubylibdir.
|
120
|
+
RUBY_LIBDIR = RbConfig::CONFIG["rubylibdir"]
|
121
121
|
RUBY_SITEDIR = RbConfig::CONFIG["sitedir"]
|
122
122
|
|
123
123
|
def stability
|
@@ -15,7 +15,11 @@ module Bootsnap
|
|
15
15
|
""
|
16
16
|
end
|
17
17
|
|
18
|
+
@ignored_directories = %w(node_modules)
|
19
|
+
|
18
20
|
class << self
|
21
|
+
attr_accessor :ignored_directories
|
22
|
+
|
19
23
|
def call(path)
|
20
24
|
path = File.expand_path(path.to_s).freeze
|
21
25
|
return [[], []] unless File.directory?(path)
|
@@ -50,6 +54,8 @@ module Bootsnap
|
|
50
54
|
|
51
55
|
absolute_path = "#{absolute_dir_path}/#{name}"
|
52
56
|
if File.directory?(absolute_path)
|
57
|
+
next if ignored_directories.include?(name)
|
58
|
+
|
53
59
|
if yield relative_path, absolute_path, true
|
54
60
|
walk(absolute_path, relative_path, &block)
|
55
61
|
end
|
@@ -13,10 +13,11 @@ module Bootsnap
|
|
13
13
|
NestedTransactionError = Class.new(StandardError)
|
14
14
|
SetOutsideTransactionNotAllowed = Class.new(StandardError)
|
15
15
|
|
16
|
-
def initialize(store_path)
|
16
|
+
def initialize(store_path, readonly: false)
|
17
17
|
@store_path = store_path
|
18
18
|
@txn_mutex = Mutex.new
|
19
19
|
@dirty = false
|
20
|
+
@readonly = readonly
|
20
21
|
load_data
|
21
22
|
end
|
22
23
|
|
@@ -63,7 +64,7 @@ module Bootsnap
|
|
63
64
|
end
|
64
65
|
|
65
66
|
def commit_transaction
|
66
|
-
if @dirty
|
67
|
+
if @dirty && !@readonly
|
67
68
|
dump_data
|
68
69
|
@dirty = false
|
69
70
|
end
|
@@ -28,17 +28,18 @@ module Bootsnap
|
|
28
28
|
alias_method :enabled?, :enabled
|
29
29
|
remove_method(:enabled)
|
30
30
|
|
31
|
-
def setup(cache_path:, development_mode:)
|
31
|
+
def setup(cache_path:, development_mode:, ignore_directories:, readonly: false)
|
32
32
|
unless supported?
|
33
33
|
warn("[bootsnap/setup] Load path caching is not supported on this implementation of Ruby") if $VERBOSE
|
34
34
|
return
|
35
35
|
end
|
36
36
|
|
37
|
-
store = Store.new(cache_path)
|
37
|
+
store = Store.new(cache_path, readonly: readonly)
|
38
38
|
|
39
39
|
@loaded_features_index = LoadedFeaturesIndex.new
|
40
40
|
|
41
41
|
@load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
|
42
|
+
PathScanner.ignored_directories = ignore_directories if ignore_directories
|
42
43
|
@enabled = true
|
43
44
|
require_relative("load_path_cache/core_ext/kernel_require")
|
44
45
|
require_relative("load_path_cache/core_ext/loaded_features")
|
@@ -50,7 +51,6 @@ module Bootsnap
|
|
50
51
|
@realpath_cache = nil
|
51
52
|
@load_path_cache = nil
|
52
53
|
ChangeObserver.unregister($LOAD_PATH)
|
53
|
-
::Kernel.alias_method(:require_relative, :require_relative_without_bootsnap)
|
54
54
|
end
|
55
55
|
|
56
56
|
def supported?
|
data/lib/bootsnap/version.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
@@ -39,32 +39,18 @@ module Bootsnap
|
|
39
39
|
cache_dir:,
|
40
40
|
development_mode: true,
|
41
41
|
load_path_cache: true,
|
42
|
-
|
43
|
-
|
42
|
+
ignore_directories: nil,
|
43
|
+
readonly: false,
|
44
44
|
compile_cache_iseq: true,
|
45
45
|
compile_cache_yaml: true,
|
46
46
|
compile_cache_json: true
|
47
47
|
)
|
48
|
-
unless autoload_paths_cache.nil?
|
49
|
-
warn "[DEPRECATED] Bootsnap's `autoload_paths_cache:` option is deprecated and will be removed. " \
|
50
|
-
"If you use Zeitwerk this option is useless, and if you are still using the classic autoloader " \
|
51
|
-
"upgrading is recommended."
|
52
|
-
end
|
53
|
-
|
54
|
-
unless disable_trace.nil?
|
55
|
-
warn "[DEPRECATED] Bootsnap's `disable_trace:` option is deprecated and will be removed. " \
|
56
|
-
"If you use Ruby 2.5 or newer this option is useless, if not upgrading is recommended."
|
57
|
-
end
|
58
|
-
|
59
|
-
if compile_cache_iseq && !iseq_cache_supported?
|
60
|
-
warn "Ruby 2.5 has a bug that break code tracing when code is loaded from cache. It is recommened " \
|
61
|
-
"to turn `compile_cache_iseq` off on Ruby 2.5"
|
62
|
-
end
|
63
|
-
|
64
48
|
if load_path_cache
|
65
49
|
Bootsnap::LoadPathCache.setup(
|
66
50
|
cache_path: "#{cache_dir}/bootsnap/load-path-cache",
|
67
51
|
development_mode: development_mode,
|
52
|
+
ignore_directories: ignore_directories,
|
53
|
+
readonly: readonly,
|
68
54
|
)
|
69
55
|
end
|
70
56
|
|
@@ -73,20 +59,14 @@ module Bootsnap
|
|
73
59
|
iseq: compile_cache_iseq,
|
74
60
|
yaml: compile_cache_yaml,
|
75
61
|
json: compile_cache_json,
|
62
|
+
readonly: readonly,
|
76
63
|
)
|
77
64
|
end
|
78
65
|
|
79
|
-
def
|
66
|
+
def unload_cache!
|
80
67
|
LoadPathCache.unload!
|
81
68
|
end
|
82
69
|
|
83
|
-
def iseq_cache_supported?
|
84
|
-
return @iseq_cache_supported if defined? @iseq_cache_supported
|
85
|
-
|
86
|
-
ruby_version = Gem::Version.new(RUBY_VERSION)
|
87
|
-
@iseq_cache_supported = ruby_version < Gem::Version.new("2.5.0") || ruby_version >= Gem::Version.new("2.6.0")
|
88
|
-
end
|
89
|
-
|
90
70
|
def default_setup
|
91
71
|
env = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || ENV["ENV"]
|
92
72
|
development_mode = ["", nil, "development"].include?(env)
|
@@ -113,13 +93,19 @@ module Bootsnap
|
|
113
93
|
cache_dir = File.join(app_root, "tmp", "cache")
|
114
94
|
end
|
115
95
|
|
96
|
+
ignore_directories = if ENV.key?("BOOTSNAP_IGNORE_DIRECTORIES")
|
97
|
+
ENV["BOOTSNAP_IGNORE_DIRECTORIES"].split(",")
|
98
|
+
end
|
99
|
+
|
116
100
|
setup(
|
117
101
|
cache_dir: cache_dir,
|
118
102
|
development_mode: development_mode,
|
119
103
|
load_path_cache: !ENV["DISABLE_BOOTSNAP_LOAD_PATH_CACHE"],
|
120
|
-
compile_cache_iseq: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"]
|
104
|
+
compile_cache_iseq: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
|
121
105
|
compile_cache_yaml: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
|
122
106
|
compile_cache_json: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
|
107
|
+
readonly: !!ENV["BOOTSNAP_READONLY"],
|
108
|
+
ignore_directories: ignore_directories,
|
123
109
|
)
|
124
110
|
|
125
111
|
if ENV["BOOTSNAP_LOG"]
|
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.16.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:
|
11
|
+
date: 2023-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -76,7 +76,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
76
76
|
requirements:
|
77
77
|
- - ">="
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
version: 2.
|
79
|
+
version: 2.6.0
|
80
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
81
|
requirements:
|
82
82
|
- - ">="
|