bootsnap 1.16.0 → 1.17.1
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 +14 -2
- data/README.md +6 -4
- data/ext/bootsnap/bootsnap.c +37 -23
- data/ext/bootsnap/extconf.rb +2 -2
- data/lib/bootsnap/bundler.rb +1 -1
- data/lib/bootsnap/compile_cache/iseq.rb +11 -5
- data/lib/bootsnap/compile_cache/json.rb +9 -13
- data/lib/bootsnap/compile_cache/yaml.rb +28 -44
- data/lib/bootsnap/compile_cache.rb +6 -15
- data/lib/bootsnap/load_path_cache/cache.rb +9 -1
- data/lib/bootsnap/load_path_cache/change_observer.rb +6 -0
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +6 -6
- data/lib/bootsnap/load_path_cache/path.rb +1 -1
- data/lib/bootsnap/load_path_cache/path_scanner.rb +2 -2
- data/lib/bootsnap/load_path_cache/store.rb +2 -2
- data/lib/bootsnap/load_path_cache.rb +21 -12
- data/lib/bootsnap/setup.rb +1 -1
- data/lib/bootsnap/version.rb +1 -1
- data/lib/bootsnap.rb +4 -4
- 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: 13123a80c1d6f0e73ff602768433dd998a28ab8e63caec7d0e29188990c4afe9
|
4
|
+
data.tar.gz: cc2e19bea1080f9ce2337095fcb161407e6def9e3412c38fdbb03c0e0ddc2a81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8fbd0f6652387c744f0a345d46e9d7238c1609597c8e26f93ad92cd928178f7c5a3afd2075390c5561c3ace19084c318b27ff3acec9d96bd0153c53ea8a4cb95
|
7
|
+
data.tar.gz: f35f769e3b39c8f28857a74c874e77cdbe04b4db0df3141fa988ba26ea55bf485e8d560b4cab65d5887508ac2b927eb97d49b6791321b0a68c896db2b617eb6d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.17.1
|
4
|
+
|
5
|
+
* Fix a compatibility issue with the `prism` library that ships with Ruby 3.3. See #463.
|
6
|
+
* Improved the `Kernel#require` decorator to not cause a method redefinition warning. See #461.
|
7
|
+
|
8
|
+
# 1.17.0
|
9
|
+
|
10
|
+
* Ensure `$LOAD_PATH.dup` is Ractor shareable to fix an conflict with `did_you_mean`.
|
11
|
+
* Allow to ignore directories using absolute paths.
|
12
|
+
* Support YAML and JSON CompileCache on TruffleRuby.
|
13
|
+
* Support LoadPathCache on TruffleRuby.
|
14
|
+
|
3
15
|
# 1.16.0
|
4
16
|
|
5
17
|
* Use `RbConfig::CONFIG["rubylibdir"]` instead of `RbConfig::CONFIG["libdir"]` to check for stdlib files. See #431.
|
@@ -17,7 +29,7 @@
|
|
17
29
|
* Add a way to skip directories during load path scanning.
|
18
30
|
If you have large non-ruby directories in the middle of your load path, it can severely slow down scanning.
|
19
31
|
Typically this is a problem with `node_modules`. See #277.
|
20
|
-
* Fix `Bootsnap.unload_cache!`, it simply wouldn't work at all
|
32
|
+
* Fix `Bootsnap.unload_cache!`, it simply wouldn't work at all because of a merge mistake. See #421.
|
21
33
|
|
22
34
|
# 1.13.0
|
23
35
|
|
@@ -36,7 +48,7 @@
|
|
36
48
|
|
37
49
|
* Stop decorating `Module#autoload` as it was only useful for supporting Ruby 2.2 and older.
|
38
50
|
|
39
|
-
* Remove `uname` and other
|
51
|
+
* Remove `uname` and other platform specific version from the cache keys. `RUBY_PLATFORM + RUBY_REVISION` should be
|
40
52
|
enough to ensure bytecode compatibility. This should improve caching for alpine based setups. See #409.
|
41
53
|
|
42
54
|
# 1.11.1
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Bootsnap [](https://github.com/Shopify/bootsnap/actions)
|
2
2
|
|
3
|
-
Bootsnap is a library that plugs into Ruby, with optional support for `YAML`,
|
3
|
+
Bootsnap is a library that plugs into Ruby, with optional support for `YAML` and `JSON`,
|
4
4
|
to optimize and cache expensive computations. See [How Does This Work](#how-does-this-work).
|
5
5
|
|
6
6
|
#### Performance
|
@@ -57,6 +57,7 @@ Bootsnap.setup(
|
|
57
57
|
load_path_cache: true, # Optimize the LOAD_PATH with a cache
|
58
58
|
compile_cache_iseq: true, # Compile Ruby code into ISeq cache, breaks coverage reporting.
|
59
59
|
compile_cache_yaml: true, # Compile YAML into a cache
|
60
|
+
compile_cache_json: true, # Compile JSON into a cache
|
60
61
|
readonly: true, # Use the caches but don't update them on miss or stale entries.
|
61
62
|
)
|
62
63
|
```
|
@@ -119,6 +120,7 @@ into two broad categories:
|
|
119
120
|
compilation.
|
120
121
|
* `YAML.load_file` is modified to cache the result of loading a YAML object in MessagePack format
|
121
122
|
(or Marshal, if the message uses types unsupported by MessagePack).
|
123
|
+
* `JSON.load_file` is modified to cache the result of loading a JSON object in MessagePack format
|
122
124
|
|
123
125
|
### Path Pre-Scanning
|
124
126
|
|
@@ -189,9 +191,9 @@ translated ruby source to an internal bytecode format, which is then executed by
|
|
189
191
|
allows caching that bytecode. This allows us to bypass the relatively-expensive compilation step on
|
190
192
|
subsequent loads of the same file.
|
191
193
|
|
192
|
-
We also noticed that we spend a lot of time loading YAML documents during our application boot, and
|
193
|
-
that MessagePack and Marshal are *much* faster at deserialization than YAML, even with a fast
|
194
|
-
implementation. We use the same strategy of compilation caching for YAML documents, with the
|
194
|
+
We also noticed that we spend a lot of time loading YAML and JSON documents during our application boot, and
|
195
|
+
that MessagePack and Marshal are *much* faster at deserialization than YAML and JSON, even with a fast
|
196
|
+
implementation. We use the same strategy of compilation caching for YAML and JSON documents, with the
|
195
197
|
equivalent of Ruby's "bytecode" format being a MessagePack document (or, in the case of YAML
|
196
198
|
documents with types unsupported by MessagePack, a Marshal stream).
|
197
199
|
|
data/ext/bootsnap/bootsnap.c
CHANGED
@@ -377,7 +377,9 @@ open_current_file(char * path, struct bs_cache_key * key, const char ** errno_pr
|
|
377
377
|
|
378
378
|
if (fstat(fd, &statbuf) < 0) {
|
379
379
|
*errno_provenance = "bs_fetch:open_current_file:fstat";
|
380
|
+
int previous_errno = errno;
|
380
381
|
close(fd);
|
382
|
+
errno = previous_errno;
|
381
383
|
return -1;
|
382
384
|
}
|
383
385
|
|
@@ -467,7 +469,6 @@ open_cache_file(const char * path, struct bs_cache_key * key, const char ** errn
|
|
467
469
|
static int
|
468
470
|
fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE * output_data, int * exception_tag, const char ** errno_provenance)
|
469
471
|
{
|
470
|
-
char * data = NULL;
|
471
472
|
ssize_t nread;
|
472
473
|
int ret;
|
473
474
|
|
@@ -479,8 +480,8 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE *
|
|
479
480
|
ret = ERROR_WITH_ERRNO;
|
480
481
|
goto done;
|
481
482
|
}
|
482
|
-
|
483
|
-
nread = read(fd,
|
483
|
+
storage_data = rb_str_buf_new(data_size);
|
484
|
+
nread = read(fd, RSTRING_PTR(storage_data), data_size);
|
484
485
|
if (nread < 0) {
|
485
486
|
*errno_provenance = "bs_fetch:fetch_cached_data:read";
|
486
487
|
ret = ERROR_WITH_ERRNO;
|
@@ -491,7 +492,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE *
|
|
491
492
|
goto done;
|
492
493
|
}
|
493
494
|
|
494
|
-
storage_data
|
495
|
+
rb_str_set_len(storage_data, nread);
|
495
496
|
|
496
497
|
*exception_tag = bs_storage_to_output(handler, args, storage_data, output_data);
|
497
498
|
if (*output_data == rb_cBootsnap_CompileCache_UNCOMPILABLE) {
|
@@ -500,7 +501,6 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE *
|
|
500
501
|
}
|
501
502
|
ret = 0;
|
502
503
|
done:
|
503
|
-
if (data != NULL) xfree(data);
|
504
504
|
return ret;
|
505
505
|
}
|
506
506
|
|
@@ -607,17 +607,22 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, cons
|
|
607
607
|
|
608
608
|
|
609
609
|
/* Read contents from an fd, whose contents are asserted to be +size+ bytes
|
610
|
-
* long,
|
611
|
-
static
|
612
|
-
bs_read_contents(int fd, size_t size,
|
610
|
+
* long, returning a Ruby string on success and Qfalse on failure */
|
611
|
+
static VALUE
|
612
|
+
bs_read_contents(int fd, size_t size, const char ** errno_provenance)
|
613
613
|
{
|
614
|
+
VALUE contents;
|
614
615
|
ssize_t nread;
|
615
|
-
|
616
|
-
nread = read(fd,
|
616
|
+
contents = rb_str_buf_new(size);
|
617
|
+
nread = read(fd, RSTRING_PTR(contents), size);
|
618
|
+
|
617
619
|
if (nread < 0) {
|
618
620
|
*errno_provenance = "bs_fetch:bs_read_contents:read";
|
621
|
+
return Qfalse;
|
622
|
+
} else {
|
623
|
+
rb_str_set_len(contents, nread);
|
624
|
+
return contents;
|
619
625
|
}
|
620
|
-
return nread;
|
621
626
|
}
|
622
627
|
|
623
628
|
/*
|
@@ -668,7 +673,6 @@ static VALUE
|
|
668
673
|
bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args)
|
669
674
|
{
|
670
675
|
struct bs_cache_key cached_key, current_key;
|
671
|
-
char * contents = NULL;
|
672
676
|
int cache_fd = -1, current_fd = -1;
|
673
677
|
int res, valid_cache = 0, exception_tag = 0;
|
674
678
|
const char * errno_provenance = NULL;
|
@@ -678,10 +682,14 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
678
682
|
VALUE output_data; /* return data, e.g. ruby hash or loaded iseq */
|
679
683
|
|
680
684
|
VALUE exception; /* ruby exception object to raise instead of returning */
|
685
|
+
VALUE exception_message; /* ruby exception string to use instead of errno_provenance */
|
681
686
|
|
682
687
|
/* Open the source file and generate a cache key for it */
|
683
688
|
current_fd = open_current_file(path, ¤t_key, &errno_provenance);
|
684
|
-
if (current_fd < 0)
|
689
|
+
if (current_fd < 0) {
|
690
|
+
exception_message = path_v;
|
691
|
+
goto fail_errno;
|
692
|
+
}
|
685
693
|
|
686
694
|
/* Open the cache key if it exists, and read its cache key in */
|
687
695
|
cache_fd = open_cache_file(cache_path, &cached_key, &errno_provenance);
|
@@ -691,6 +699,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
691
699
|
rb_funcall(rb_mBootsnap, instrumentation_method, 2, cache_fd == CACHE_MISS ? sym_miss : sym_stale, path_v);
|
692
700
|
}
|
693
701
|
} else if (cache_fd < 0) {
|
702
|
+
exception_message = rb_str_new_cstr(cache_path);
|
694
703
|
goto fail_errno;
|
695
704
|
} else {
|
696
705
|
/* True if the cache existed and no invalidating changes have occurred since
|
@@ -713,13 +722,18 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
713
722
|
else if (res == CACHE_UNCOMPILABLE) {
|
714
723
|
/* If fetch_cached_data returned `Uncompilable` we fallback to `input_to_output`
|
715
724
|
This happens if we have say, an unsafe YAML cache, but try to load it in safe mode */
|
716
|
-
if (bs_read_contents(current_fd, current_key.size, &
|
717
|
-
|
725
|
+
if ((input_data = bs_read_contents(current_fd, current_key.size, &errno_provenance)) == Qfalse){
|
726
|
+
exception_message = path_v;
|
727
|
+
goto fail_errno;
|
728
|
+
}
|
718
729
|
bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
|
719
730
|
if (exception_tag != 0) goto raise;
|
720
731
|
goto succeed;
|
721
732
|
} else if (res == CACHE_MISS || res == CACHE_STALE) valid_cache = 0;
|
722
|
-
else if (res == ERROR_WITH_ERRNO)
|
733
|
+
else if (res == ERROR_WITH_ERRNO){
|
734
|
+
exception_message = rb_str_new_cstr(cache_path);
|
735
|
+
goto fail_errno;
|
736
|
+
}
|
723
737
|
else if (!NIL_P(output_data)) goto succeed; /* fast-path, goal */
|
724
738
|
}
|
725
739
|
close(cache_fd);
|
@@ -727,8 +741,10 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
727
741
|
/* Cache is stale, invalid, or missing. Regenerate and write it out. */
|
728
742
|
|
729
743
|
/* Read the contents of the source file into a buffer */
|
730
|
-
if (bs_read_contents(current_fd, current_key.size, &
|
731
|
-
|
744
|
+
if ((input_data = bs_read_contents(current_fd, current_key.size, &errno_provenance)) == Qfalse){
|
745
|
+
exception_message = path_v;
|
746
|
+
goto fail_errno;
|
747
|
+
}
|
732
748
|
|
733
749
|
/* Try to compile the input_data using input_to_storage(input_data) */
|
734
750
|
exception_tag = bs_input_to_storage(handler, args, input_data, path_v, &storage_data);
|
@@ -765,6 +781,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
765
781
|
* No point raising an error */
|
766
782
|
if (errno != ENOENT) {
|
767
783
|
errno_provenance = "bs_fetch:unlink";
|
784
|
+
exception_message = rb_str_new_cstr(cache_path);
|
768
785
|
goto fail_errno;
|
769
786
|
}
|
770
787
|
}
|
@@ -775,7 +792,6 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
775
792
|
goto succeed; /* output_data is now the correct return. */
|
776
793
|
|
777
794
|
#define CLEANUP \
|
778
|
-
if (contents != NULL) xfree(contents); \
|
779
795
|
if (current_fd >= 0) close(current_fd); \
|
780
796
|
if (cache_fd >= 0) close(cache_fd);
|
781
797
|
|
@@ -784,7 +800,7 @@ succeed:
|
|
784
800
|
return output_data;
|
785
801
|
fail_errno:
|
786
802
|
CLEANUP;
|
787
|
-
exception =
|
803
|
+
exception = rb_syserr_new_str(errno, exception_message);
|
788
804
|
rb_exc_raise(exception);
|
789
805
|
__builtin_unreachable();
|
790
806
|
raise:
|
@@ -836,8 +852,7 @@ bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE handler)
|
|
836
852
|
/* Cache is stale, invalid, or missing. Regenerate and write it out. */
|
837
853
|
|
838
854
|
/* Read the contents of the source file into a buffer */
|
839
|
-
if (bs_read_contents(current_fd, current_key.size, &
|
840
|
-
input_data = rb_str_new(contents, current_key.size);
|
855
|
+
if ((input_data = bs_read_contents(current_fd, current_key.size, &errno_provenance)) == Qfalse) goto fail;
|
841
856
|
|
842
857
|
/* Try to compile the input_data using input_to_storage(input_data) */
|
843
858
|
exception_tag = bs_input_to_storage(handler, Qnil, input_data, path_v, &storage_data);
|
@@ -858,7 +873,6 @@ bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE handler)
|
|
858
873
|
goto succeed;
|
859
874
|
|
860
875
|
#define CLEANUP \
|
861
|
-
if (contents != NULL) xfree(contents); \
|
862
876
|
if (current_fd >= 0) close(current_fd); \
|
863
877
|
if (cache_fd >= 0) close(cache_fd);
|
864
878
|
|
data/ext/bootsnap/extconf.rb
CHANGED
data/lib/bootsnap/bundler.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "bootsnap/bootsnap"
|
4
|
+
require "zlib"
|
5
5
|
|
6
6
|
module Bootsnap
|
7
7
|
module CompileCache
|
@@ -12,6 +12,10 @@ module Bootsnap
|
|
12
12
|
def cache_dir=(cache_dir)
|
13
13
|
@cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}iseq" : "#{cache_dir}-iseq"
|
14
14
|
end
|
15
|
+
|
16
|
+
def supported?
|
17
|
+
CompileCache.supported? && defined?(RubyVM)
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
has_ruby_bug_18250 = begin # https://bugs.ruby-lang.org/issues/18250
|
@@ -83,8 +87,6 @@ module Bootsnap
|
|
83
87
|
return nil if defined?(Coverage) && Bootsnap::CompileCache::Native.coverage_running?
|
84
88
|
|
85
89
|
Bootsnap::CompileCache::ISeq.fetch(path.to_s)
|
86
|
-
rescue Errno::EACCES
|
87
|
-
Bootsnap::CompileCache.permission_error(path)
|
88
90
|
rescue RuntimeError => error
|
89
91
|
if error.message =~ /unmatched platform/
|
90
92
|
puts("unmatched platform for file #{path}")
|
@@ -103,11 +105,15 @@ module Bootsnap
|
|
103
105
|
crc = Zlib.crc32(option.inspect)
|
104
106
|
Bootsnap::CompileCache::Native.compile_option_crc32 = crc
|
105
107
|
end
|
106
|
-
compile_option_updated
|
108
|
+
compile_option_updated if supported?
|
107
109
|
|
108
110
|
def self.install!(cache_dir)
|
109
111
|
Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
|
112
|
+
|
113
|
+
return unless supported?
|
114
|
+
|
110
115
|
Bootsnap::CompileCache::ISeq.compile_option_updated
|
116
|
+
|
111
117
|
class << RubyVM::InstructionSequence
|
112
118
|
prepend(InstructionSequenceMixin)
|
113
119
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "bootsnap/bootsnap"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module CompileCache
|
@@ -46,8 +46,8 @@ module Bootsnap
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def init!
|
49
|
-
require
|
50
|
-
require
|
49
|
+
require "json"
|
50
|
+
require "msgpack"
|
51
51
|
|
52
52
|
self.msgpack_factory = MessagePack::Factory.new
|
53
53
|
self.supported_options = [:symbolize_names]
|
@@ -74,16 +74,12 @@ module Bootsnap
|
|
74
74
|
return super unless (kwargs.keys - ::Bootsnap::CompileCache::JSON.supported_options).empty?
|
75
75
|
end
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
)
|
84
|
-
rescue Errno::EACCES
|
85
|
-
::Bootsnap::CompileCache.permission_error(path)
|
86
|
-
end
|
77
|
+
::Bootsnap::CompileCache::Native.fetch(
|
78
|
+
Bootsnap::CompileCache::JSON.cache_dir,
|
79
|
+
File.realpath(path),
|
80
|
+
::Bootsnap::CompileCache::JSON,
|
81
|
+
kwargs,
|
82
|
+
)
|
87
83
|
end
|
88
84
|
|
89
85
|
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "bootsnap/bootsnap"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module CompileCache
|
@@ -55,9 +55,9 @@ module Bootsnap
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def init!
|
58
|
-
require
|
59
|
-
require
|
60
|
-
require
|
58
|
+
require "yaml"
|
59
|
+
require "msgpack"
|
60
|
+
require "date"
|
61
61
|
|
62
62
|
@implementation = ::YAML::VERSION >= "4" ? Psych4 : Psych3
|
63
63
|
if @implementation::Patch.method_defined?(:unsafe_load_file) && !::YAML.respond_to?(:unsafe_load_file)
|
@@ -229,16 +229,12 @@ module Bootsnap
|
|
229
229
|
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
230
230
|
end
|
231
231
|
|
232
|
-
|
233
|
-
CompileCache::
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
)
|
239
|
-
rescue Errno::EACCES
|
240
|
-
CompileCache.permission_error(path)
|
241
|
-
end
|
232
|
+
CompileCache::Native.fetch(
|
233
|
+
CompileCache::YAML.cache_dir,
|
234
|
+
File.realpath(path),
|
235
|
+
CompileCache::YAML::Psych4::SafeLoad,
|
236
|
+
kwargs,
|
237
|
+
)
|
242
238
|
end
|
243
239
|
|
244
240
|
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
@@ -253,16 +249,12 @@ module Bootsnap
|
|
253
249
|
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
254
250
|
end
|
255
251
|
|
256
|
-
|
257
|
-
CompileCache::
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
)
|
263
|
-
rescue Errno::EACCES
|
264
|
-
CompileCache.permission_error(path)
|
265
|
-
end
|
252
|
+
CompileCache::Native.fetch(
|
253
|
+
CompileCache::YAML.cache_dir,
|
254
|
+
File.realpath(path),
|
255
|
+
CompileCache::YAML::Psych4::UnsafeLoad,
|
256
|
+
kwargs,
|
257
|
+
)
|
266
258
|
end
|
267
259
|
|
268
260
|
ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
|
@@ -309,16 +301,12 @@ module Bootsnap
|
|
309
301
|
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
310
302
|
end
|
311
303
|
|
312
|
-
|
313
|
-
CompileCache::
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
)
|
319
|
-
rescue Errno::EACCES
|
320
|
-
CompileCache.permission_error(path)
|
321
|
-
end
|
304
|
+
CompileCache::Native.fetch(
|
305
|
+
CompileCache::YAML.cache_dir,
|
306
|
+
File.realpath(path),
|
307
|
+
CompileCache::YAML::Psych3,
|
308
|
+
kwargs,
|
309
|
+
)
|
322
310
|
end
|
323
311
|
|
324
312
|
ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
|
@@ -333,16 +321,12 @@ module Bootsnap
|
|
333
321
|
return super unless (kwargs.keys - CompileCache::YAML.supported_options).empty?
|
334
322
|
end
|
335
323
|
|
336
|
-
|
337
|
-
CompileCache::
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
)
|
343
|
-
rescue Errno::EACCES
|
344
|
-
CompileCache.permission_error(path)
|
345
|
-
end
|
324
|
+
CompileCache::Native.fetch(
|
325
|
+
CompileCache::YAML.cache_dir,
|
326
|
+
File.realpath(path),
|
327
|
+
CompileCache::YAML::Psych3,
|
328
|
+
kwargs,
|
329
|
+
)
|
346
330
|
end
|
347
331
|
|
348
332
|
ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
|
@@ -8,12 +8,11 @@ module Bootsnap
|
|
8
8
|
end
|
9
9
|
|
10
10
|
Error = Class.new(StandardError)
|
11
|
-
PermissionError = Class.new(Error)
|
12
11
|
|
13
12
|
def self.setup(cache_dir:, iseq:, yaml:, json:, readonly: false)
|
14
13
|
if iseq
|
15
14
|
if supported?
|
16
|
-
require_relative
|
15
|
+
require_relative "compile_cache/iseq"
|
17
16
|
Bootsnap::CompileCache::ISeq.install!(cache_dir)
|
18
17
|
elsif $VERBOSE
|
19
18
|
warn("[bootsnap/setup] bytecode caching is not supported on this implementation of Ruby")
|
@@ -22,7 +21,7 @@ module Bootsnap
|
|
22
21
|
|
23
22
|
if yaml
|
24
23
|
if supported?
|
25
|
-
require_relative
|
24
|
+
require_relative "compile_cache/yaml"
|
26
25
|
Bootsnap::CompileCache::YAML.install!(cache_dir)
|
27
26
|
elsif $VERBOSE
|
28
27
|
warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
|
@@ -31,7 +30,7 @@ module Bootsnap
|
|
31
30
|
|
32
31
|
if json
|
33
32
|
if supported?
|
34
|
-
require_relative
|
33
|
+
require_relative "compile_cache/json"
|
35
34
|
Bootsnap::CompileCache::JSON.install!(cache_dir)
|
36
35
|
elsif $VERBOSE
|
37
36
|
warn("[bootsnap/setup] JSON parsing caching is not supported on this implementation of Ruby")
|
@@ -43,18 +42,10 @@ module Bootsnap
|
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
46
|
-
def self.permission_error(path)
|
47
|
-
cpath = Bootsnap::CompileCache::ISeq.cache_dir
|
48
|
-
raise(
|
49
|
-
PermissionError,
|
50
|
-
"bootsnap doesn't have permission to write cache entries in '#{cpath}' " \
|
51
|
-
"(or, less likely, doesn't have permission to read '#{path}')",
|
52
|
-
)
|
53
|
-
end
|
54
|
-
|
55
45
|
def self.supported?
|
56
|
-
# only enable on 'ruby' (MRI)
|
57
|
-
|
46
|
+
# only enable on 'ruby' (MRI) and TruffleRuby for POSIX (darwin, linux, *bsd), Windows (RubyInstaller2)
|
47
|
+
%w[ruby truffleruby].include?(RUBY_ENGINE) &&
|
48
|
+
RUBY_PLATFORM.match?(/darwin|linux|bsd|mswin|mingw|cygwin/)
|
58
49
|
end
|
59
50
|
end
|
60
51
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../explicit_require"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module LoadPathCache
|
@@ -24,8 +24,16 @@ module Bootsnap
|
|
24
24
|
@mutex.synchronize { @dirs[dir] }
|
25
25
|
end
|
26
26
|
|
27
|
+
TRUFFLERUBY_LIB_DIR_PREFIX = if RUBY_ENGINE == "truffleruby"
|
28
|
+
"#{File.join(RbConfig::CONFIG['libdir'], 'truffle')}#{File::SEPARATOR}"
|
29
|
+
end
|
30
|
+
|
27
31
|
# { 'enumerator' => nil, 'enumerator.so' => nil, ... }
|
28
32
|
BUILTIN_FEATURES = $LOADED_FEATURES.each_with_object({}) do |feat, features|
|
33
|
+
if TRUFFLERUBY_LIB_DIR_PREFIX && feat.start_with?(TRUFFLERUBY_LIB_DIR_PREFIX)
|
34
|
+
feat = feat.byteslice(TRUFFLERUBY_LIB_DIR_PREFIX.bytesize..-1)
|
35
|
+
end
|
36
|
+
|
29
37
|
# Builtin features are of the form 'enumerator.so'.
|
30
38
|
# All others include paths.
|
31
39
|
next unless feat.size < 20 && !feat.include?("/")
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Kernel
|
4
|
-
|
4
|
+
alias_method :require_without_bootsnap, :require
|
5
5
|
|
6
|
-
alias_method
|
6
|
+
alias_method :require, :require # Avoid method redefinition warnings
|
7
7
|
|
8
|
-
def require(path)
|
8
|
+
def require(path) # rubocop:disable Lint/DuplicateMethods
|
9
9
|
return require_without_bootsnap(path) unless Bootsnap::LoadPathCache.enabled?
|
10
10
|
|
11
11
|
string_path = Bootsnap.rb_get_path(path)
|
@@ -24,9 +24,7 @@ module Kernel
|
|
24
24
|
elsif false == resolved
|
25
25
|
return false
|
26
26
|
elsif resolved.nil?
|
27
|
-
|
28
|
-
error.instance_variable_set(:@path, path)
|
29
|
-
raise error
|
27
|
+
return require_without_bootsnap(path)
|
30
28
|
else
|
31
29
|
# Note that require registers to $LOADED_FEATURES while load does not.
|
32
30
|
ret = require_without_bootsnap(resolved)
|
@@ -34,4 +32,6 @@ module Kernel
|
|
34
32
|
return ret
|
35
33
|
end
|
36
34
|
end
|
35
|
+
|
36
|
+
private :require
|
37
37
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../explicit_require"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module LoadPathCache
|
@@ -54,7 +54,7 @@ module Bootsnap
|
|
54
54
|
|
55
55
|
absolute_path = "#{absolute_dir_path}/#{name}"
|
56
56
|
if File.directory?(absolute_path)
|
57
|
-
next if ignored_directories.include?(name)
|
57
|
+
next if ignored_directories.include?(name) || ignored_directories.include?(absolute_path)
|
58
58
|
|
59
59
|
if yield relative_path, absolute_path, true
|
60
60
|
walk(absolute_path, relative_path, &block)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../explicit_require"
|
4
4
|
|
5
|
-
Bootsnap::ExplicitRequire.with_gems("msgpack") { require
|
5
|
+
Bootsnap::ExplicitRequire.with_gems("msgpack") { require "msgpack" }
|
6
6
|
|
7
7
|
module Bootsnap
|
8
8
|
module LoadPathCache
|
@@ -38,11 +38,11 @@ module Bootsnap
|
|
38
38
|
|
39
39
|
@loaded_features_index = LoadedFeaturesIndex.new
|
40
40
|
|
41
|
-
@load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
|
42
41
|
PathScanner.ignored_directories = ignore_directories if ignore_directories
|
42
|
+
@load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
|
43
43
|
@enabled = true
|
44
|
-
require_relative
|
45
|
-
require_relative
|
44
|
+
require_relative "load_path_cache/core_ext/kernel_require"
|
45
|
+
require_relative "load_path_cache/core_ext/loaded_features"
|
46
46
|
end
|
47
47
|
|
48
48
|
def unload!
|
@@ -50,22 +50,31 @@ module Bootsnap
|
|
50
50
|
@loaded_features_index = nil
|
51
51
|
@realpath_cache = nil
|
52
52
|
@load_path_cache = nil
|
53
|
-
ChangeObserver.unregister($LOAD_PATH)
|
53
|
+
ChangeObserver.unregister($LOAD_PATH) if supported?
|
54
54
|
end
|
55
55
|
|
56
56
|
def supported?
|
57
|
-
|
58
|
-
|
57
|
+
if RUBY_PLATFORM.match?(/darwin|linux|bsd|mswin|mingw|cygwin/)
|
58
|
+
case RUBY_ENGINE
|
59
|
+
when "truffleruby"
|
60
|
+
# https://github.com/oracle/truffleruby/issues/3131
|
61
|
+
RUBY_ENGINE_VERSION >= "23.1.0"
|
62
|
+
when "ruby"
|
63
|
+
true
|
64
|
+
else
|
65
|
+
false
|
66
|
+
end
|
67
|
+
end
|
59
68
|
end
|
60
69
|
end
|
61
70
|
end
|
62
71
|
end
|
63
72
|
|
64
73
|
if Bootsnap::LoadPathCache.supported?
|
65
|
-
require_relative
|
66
|
-
require_relative
|
67
|
-
require_relative
|
68
|
-
require_relative
|
69
|
-
require_relative
|
70
|
-
require_relative
|
74
|
+
require_relative "load_path_cache/path_scanner"
|
75
|
+
require_relative "load_path_cache/path"
|
76
|
+
require_relative "load_path_cache/cache"
|
77
|
+
require_relative "load_path_cache/store"
|
78
|
+
require_relative "load_path_cache/change_observer"
|
79
|
+
require_relative "load_path_cache/loaded_features_index"
|
71
80
|
end
|
data/lib/bootsnap/setup.rb
CHANGED
data/lib/bootsnap/version.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
3
|
+
require_relative "bootsnap/version"
|
4
|
+
require_relative "bootsnap/bundler"
|
5
|
+
require_relative "bootsnap/load_path_cache"
|
6
|
+
require_relative "bootsnap/compile_cache"
|
7
7
|
|
8
8
|
module Bootsnap
|
9
9
|
InvalidConfiguration = Class.new(StandardError)
|
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.17.1
|
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: 2024-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -83,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
83
|
- !ruby/object:Gem::Version
|
84
84
|
version: '0'
|
85
85
|
requirements: []
|
86
|
-
rubygems_version: 3.
|
86
|
+
rubygems_version: 3.5.4
|
87
87
|
signing_key:
|
88
88
|
specification_version: 4
|
89
89
|
summary: Boot large ruby/rails apps faster
|