bootsnap 1.16.0 → 1.18.6

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.
@@ -1,16 +1,88 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "etc"
4
+ require "rbconfig"
5
+ require "io/wait" unless IO.method_defined?(:wait_readable)
6
+
3
7
  module Bootsnap
4
8
  class CLI
5
9
  class WorkerPool
6
10
  class << self
7
11
  def create(size:, jobs:)
12
+ size ||= default_size
8
13
  if size > 0 && Process.respond_to?(:fork)
9
14
  new(size: size, jobs: jobs)
10
15
  else
11
16
  Inline.new(jobs: jobs)
12
17
  end
13
18
  end
19
+
20
+ def default_size
21
+ nprocessors = Etc.nprocessors
22
+ size = [nprocessors, cpu_quota&.to_i || nprocessors].min
23
+ case size
24
+ when 0, 1
25
+ 0
26
+ else
27
+ if fork_defunct?
28
+ $stderr.puts "warning: faulty fork(2) detected, probably in cross platform docker builds. " \
29
+ "Disabling parallel compilation."
30
+ 0
31
+ else
32
+ size
33
+ end
34
+ end
35
+ end
36
+
37
+ def cpu_quota
38
+ if RbConfig::CONFIG["target_os"].include?("linux")
39
+ if File.exist?("/sys/fs/cgroup/cpu.max")
40
+ # cgroups v2: https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu-interface-files
41
+ cpu_max = File.read("/sys/fs/cgroup/cpu.max")
42
+ return nil if cpu_max.start_with?("max ") # no limit
43
+
44
+ max, period = cpu_max.split.map(&:to_f)
45
+ max / period
46
+ elsif File.exist?("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us")
47
+ # cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt
48
+ max = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us").to_i
49
+ # If the cpu.cfs_quota_us is -1, cgroup does not adhere to any CPU time restrictions
50
+ # https://docs.kernel.org/scheduler/sched-bwc.html#management
51
+ return nil if max <= 0
52
+
53
+ period = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us").to_f
54
+ max / period
55
+ end
56
+ end
57
+ end
58
+
59
+ def fork_defunct?
60
+ return true unless ::Process.respond_to?(:fork)
61
+
62
+ # Ref: https://github.com/Shopify/bootsnap/issues/495
63
+ # The second forked process will hang on some QEMU environments
64
+ r, w = IO.pipe
65
+ pids = 2.times.map do
66
+ ::Process.fork do
67
+ exit!(true)
68
+ end
69
+ end
70
+ w.close
71
+ r.wait_readable(1) # Wait at most 1s
72
+
73
+ defunct = false
74
+
75
+ pids.each do |pid|
76
+ _pid, status = ::Process.wait2(pid, ::Process::WNOHANG)
77
+ if status.nil? # Didn't exit in 1s
78
+ defunct = true
79
+ Process.kill(:KILL, pid)
80
+ ::Process.wait2(pid)
81
+ end
82
+ end
83
+
84
+ defunct
85
+ end
14
86
  end
15
87
 
16
88
  class Inline
data/lib/bootsnap/cli.rb CHANGED
@@ -4,7 +4,6 @@ require "bootsnap"
4
4
  require "bootsnap/cli/worker_pool"
5
5
  require "optparse"
6
6
  require "fileutils"
7
- require "etc"
8
7
 
9
8
  module Bootsnap
10
9
  class CLI
@@ -29,23 +28,23 @@ module Bootsnap
29
28
  self.compile_gemfile = false
30
29
  self.exclude = nil
31
30
  self.verbose = false
32
- self.jobs = Etc.nprocessors
31
+ self.jobs = nil
33
32
  self.iseq = true
34
33
  self.yaml = true
35
34
  self.json = true
36
35
  end
37
36
 
38
37
  def precompile_command(*sources)
39
- require "bootsnap/compile_cache/iseq"
40
- require "bootsnap/compile_cache/yaml"
41
- require "bootsnap/compile_cache/json"
38
+ require "bootsnap/compile_cache"
42
39
 
43
40
  fix_default_encoding do
44
- Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
45
- Bootsnap::CompileCache::YAML.init!
46
- Bootsnap::CompileCache::YAML.cache_dir = cache_dir
47
- Bootsnap::CompileCache::JSON.init!
48
- Bootsnap::CompileCache::JSON.cache_dir = cache_dir
41
+ Bootsnap::CompileCache.setup(
42
+ cache_dir: cache_dir,
43
+ iseq: iseq,
44
+ yaml: yaml,
45
+ json: json,
46
+ revalidation: true,
47
+ )
49
48
 
50
49
  @work_pool = WorkerPool.create(size: jobs, jobs: {
51
50
  ruby: method(:precompile_ruby),
@@ -60,14 +59,16 @@ module Bootsnap
60
59
  precompile_json_files(main_sources)
61
60
 
62
61
  if compile_gemfile
63
- # Some gems embed their tests, they're very unlikely to be loaded, so not worth precompiling.
64
- gem_exclude = Regexp.union([exclude, "/spec/", "/test/"].compact)
65
- precompile_ruby_files($LOAD_PATH.map { |d| File.expand_path(d) }, exclude: gem_exclude)
66
-
67
62
  # Gems that include JSON or YAML files usually don't put them in `lib/`.
68
63
  # So we look at the gem root.
64
+ # Similarly, gems that include Rails engines generally file Ruby files in `app/`.
65
+ # However some gems embed their tests, they're very unlikely to be loaded, so not worth precompiling.
66
+ gem_exclude = Regexp.union([exclude, "/spec/", "/test/", "/features/"].compact)
67
+
69
68
  gem_pattern = %r{^#{Regexp.escape(Bundler.bundle_path.to_s)}/?(?:bundler/)?gems/[^/]+}
70
- gem_paths = $LOAD_PATH.map { |p| p[gem_pattern] }.compact.uniq
69
+ gem_paths = $LOAD_PATH.map { |p| p[gem_pattern] || p }.uniq
70
+
71
+ precompile_ruby_files(gem_paths, exclude: gem_exclude)
71
72
  precompile_yaml_files(gem_paths, exclude: gem_exclude)
72
73
  precompile_json_files(gem_paths, exclude: gem_exclude)
73
74
  end
@@ -220,6 +221,9 @@ module Bootsnap
220
221
 
221
222
  def parser
222
223
  @parser ||= OptionParser.new do |opts|
224
+ opts.version = Bootsnap::VERSION
225
+ opts.program_name = "bootsnap"
226
+
223
227
  opts.banner = "Usage: bootsnap COMMAND [ARGS]"
224
228
  opts.separator ""
225
229
  opts.separator "GLOBAL OPTIONS"
@@ -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
@@ -80,11 +84,9 @@ module Bootsnap
80
84
  module InstructionSequenceMixin
81
85
  def load_iseq(path)
82
86
  # Having coverage enabled prevents iseq dumping/loading.
83
- return nil if defined?(Coverage) && Bootsnap::CompileCache::Native.coverage_running?
87
+ return nil if defined?(Coverage) && 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
- def self.setup(cache_dir:, iseq:, yaml:, json:, readonly: false)
12
+ def self.setup(cache_dir:, iseq:, yaml:, json:, readonly: false, revalidation: 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")
@@ -40,21 +39,14 @@ module Bootsnap
40
39
 
41
40
  if supported? && defined?(Bootsnap::CompileCache::Native)
42
41
  Bootsnap::CompileCache::Native.readonly = readonly
42
+ Bootsnap::CompileCache::Native.revalidation = revalidation
43
43
  end
44
44
  end
45
45
 
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
46
  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/)
47
+ # only enable on 'ruby' (MRI) and TruffleRuby for POSIX (darwin, linux, *bsd), Windows (RubyInstaller2)
48
+ %w[ruby truffleruby].include?(RUBY_ENGINE) &&
49
+ RUBY_PLATFORM.match?(/darwin|linux|bsd|mswin|mingw|cygwin/)
58
50
  end
59
51
  end
60
52
  end
@@ -25,6 +25,11 @@ module Bootsnap
25
25
  # This is useful before bootsnap is fully-initialized to load gems that it
26
26
  # depends on, without forcing full LOAD_PATH traversals.
27
27
  def self.with_gems(*gems)
28
+ # Ensure the gems are activated (their paths are in $LOAD_PATH)
29
+ gems.each do |gem_name|
30
+ gem gem_name
31
+ end
32
+
28
33
  orig = $LOAD_PATH.dup
29
34
  $LOAD_PATH.clear
30
35
  gems.each do |gem|
@@ -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
@@ -142,7 +142,7 @@ module Bootsnap
142
142
  # will _never_ run on MacOS, and therefore think they can get away
143
143
  # with calling a Ruby file 'x.dylib.rb' and then requiring it as 'x.dylib'.)
144
144
  #
145
- # See <https://ruby-doc.org/core-2.6.4/Kernel.html#method-i-require>.
145
+ # See <https://docs.ruby-lang.org/en/master/Kernel.html#method-i-require>.
146
146
  def extension_elidable?(feature)
147
147
  feature.to_s.end_with?(".rb", ".so", ".o", ".dll", ".dylib")
148
148
  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
@@ -122,6 +122,8 @@ module Bootsnap
122
122
  stack.reverse_each do |dir|
123
123
  Dir.mkdir(dir)
124
124
  rescue SystemCallError
125
+ # Check for broken symlinks. Calling File.realpath will raise Errno::ENOENT if that is the case
126
+ File.realpath(dir) if File.symlink?(dir)
125
127
  raise unless File.directory?(dir)
126
128
  end
127
129
  end
@@ -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.18.6"
5
5
  end