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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1bf1eca00971c561ca1e15941903dcf193ec8fc84c68736177a3aa72558c536b
4
- data.tar.gz: bcd5596d1b4b00905af82cf25693fb72e71897685e024b27311353eef6f588bf
3
+ metadata.gz: 13123a80c1d6f0e73ff602768433dd998a28ab8e63caec7d0e29188990c4afe9
4
+ data.tar.gz: cc2e19bea1080f9ce2337095fcb161407e6def9e3412c38fdbb03c0e0ddc2a81
5
5
  SHA512:
6
- metadata.gz: 0d3e37e56d994647ac88a1c9b83f087f137d32acfc09bfba1e71a85ce254697b1dcf6c9e1c90b5c71728ce0f3c0a63ee86680455a8f95003d237671435042859
7
- data.tar.gz: 270bf8fc609981d25441c9c4bd975348130177564f2e1a0744f18720d7f59cda3c3da24bea0c07f2498a185308647b05715e1b1dd5a6045e653600ab2f5907a1
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 becaue of a merge mistake. See #421.
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 patform specific version from the cache keys. `RUBY_PLATFORM + RUBY_REVISION` should be
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 [![Actions Status](https://github.com/Shopify/bootsnap/workflows/ci/badge.svg)](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
 
@@ -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
- data = ALLOC_N(char, data_size);
483
- nread = read(fd, data, data_size);
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 = rb_str_new(data, data_size);
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, into a buffer */
611
- static ssize_t
612
- bs_read_contents(int fd, size_t size, char ** contents, const char ** errno_provenance)
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
- *contents = ALLOC_N(char, size);
616
- nread = read(fd, *contents, size);
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, &current_key, &errno_provenance);
684
- if (current_fd < 0) goto fail_errno;
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, &contents, &errno_provenance) < 0) goto fail_errno;
717
- input_data = rb_str_new(contents, current_key.size);
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) goto fail_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, &contents, &errno_provenance) < 0) goto fail_errno;
731
- input_data = rb_str_new(contents, current_key.size);
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 = rb_syserr_new(errno, errno_provenance);
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, &contents, &errno_provenance) < 0) goto fail;
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
 
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require("mkmf")
3
+ require "mkmf"
4
4
 
5
- if RUBY_ENGINE == "ruby"
5
+ if %w[ruby truffleruby].include?(RUBY_ENGINE)
6
6
  $CFLAGS << " -O3 "
7
7
  $CFLAGS << " -std=c99"
8
8
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bootsnap
4
- extend(self)
4
+ extend self
5
5
 
6
6
  def bundler?
7
7
  return false unless defined?(::Bundler)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require("bootsnap/bootsnap")
4
- require("zlib")
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("bootsnap/bootsnap")
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("json")
50
- require("msgpack")
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
- begin
78
- ::Bootsnap::CompileCache::Native.fetch(
79
- Bootsnap::CompileCache::JSON.cache_dir,
80
- File.realpath(path),
81
- ::Bootsnap::CompileCache::JSON,
82
- kwargs,
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("bootsnap/bootsnap")
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("yaml")
59
- require("msgpack")
60
- require("date")
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
- begin
233
- CompileCache::Native.fetch(
234
- CompileCache::YAML.cache_dir,
235
- File.realpath(path),
236
- CompileCache::YAML::Psych4::SafeLoad,
237
- kwargs,
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
- begin
257
- CompileCache::Native.fetch(
258
- CompileCache::YAML.cache_dir,
259
- File.realpath(path),
260
- CompileCache::YAML::Psych4::UnsafeLoad,
261
- kwargs,
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
- begin
313
- CompileCache::Native.fetch(
314
- CompileCache::YAML.cache_dir,
315
- File.realpath(path),
316
- CompileCache::YAML::Psych3,
317
- kwargs,
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
- begin
337
- CompileCache::Native.fetch(
338
- CompileCache::YAML.cache_dir,
339
- File.realpath(path),
340
- CompileCache::YAML::Psych3,
341
- kwargs,
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("compile_cache/iseq")
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("compile_cache/yaml")
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("compile_cache/json")
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), POSIX (darwin, linux, *bsd), Windows (RubyInstaller2) and >= 2.3.0
57
- RUBY_ENGINE == "ruby" && RUBY_PLATFORM.match?(/darwin|linux|bsd|mswin|mingw|cygwin/)
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("../explicit_require")
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?("/")
@@ -54,6 +54,12 @@ module Bootsnap
54
54
  ret
55
55
  end
56
56
  end
57
+
58
+ def dup
59
+ [] + self
60
+ end
61
+
62
+ alias_method :clone, :dup
57
63
  end
58
64
 
59
65
  def self.register(arr, observer)
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kernel
4
- module_function
4
+ alias_method :require_without_bootsnap, :require
5
5
 
6
- alias_method(:require_without_bootsnap, :require)
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
- error = LoadError.new(+"cannot load such file -- #{path}")
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("path_scanner")
3
+ require_relative "path_scanner"
4
4
 
5
5
  module Bootsnap
6
6
  module LoadPathCache
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative("../explicit_require")
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("../explicit_require")
3
+ require_relative "../explicit_require"
4
4
 
5
- Bootsnap::ExplicitRequire.with_gems("msgpack") { require("msgpack") }
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("load_path_cache/core_ext/kernel_require")
45
- require_relative("load_path_cache/core_ext/loaded_features")
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
- RUBY_ENGINE == "ruby" &&
58
- RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/
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("load_path_cache/path_scanner")
66
- require_relative("load_path_cache/path")
67
- require_relative("load_path_cache/cache")
68
- require_relative("load_path_cache/store")
69
- require_relative("load_path_cache/change_observer")
70
- require_relative("load_path_cache/loaded_features_index")
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative("../bootsnap")
3
+ require_relative "../bootsnap"
4
4
 
5
5
  Bootsnap.default_setup
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bootsnap
4
- VERSION = "1.16.0"
4
+ VERSION = "1.17.1"
5
5
  end
data/lib/bootsnap.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative("bootsnap/version")
4
- require_relative("bootsnap/bundler")
5
- require_relative("bootsnap/load_path_cache")
6
- require_relative("bootsnap/compile_cache")
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.16.0
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: 2023-01-25 00:00:00.000000000 Z
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.3.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