bootsnap 1.7.2 → 1.11.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.
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Bootsnap
3
4
  module LoadPathCache
4
5
  module ChangeObserver
@@ -15,11 +16,13 @@ module Bootsnap
15
16
  @lpc_observer.push_paths(self, *entries.map(&:to_s))
16
17
  super
17
18
  end
19
+ alias_method :append, :push
18
20
 
19
21
  def unshift(*entries)
20
22
  @lpc_observer.unshift_paths(self, *entries.map(&:to_s))
21
23
  super
22
24
  end
25
+ alias_method :prepend, :unshift
23
26
 
24
27
  def concat(entries)
25
28
  @lpc_observer.push_paths(self, *entries.map(&:to_s))
@@ -55,6 +58,7 @@ module Bootsnap
55
58
 
56
59
  def self.register(observer, arr)
57
60
  return if arr.frozen? # can't register observer, but no need to.
61
+
58
62
  arr.instance_variable_set(:@lpc_observer, observer)
59
63
  arr.extend(ArrayMixin)
60
64
  end
@@ -1,79 +1,43 @@
1
1
  # frozen_string_literal: true
2
- module Bootsnap
3
- module LoadPathCache
4
- module CoreExt
5
- def self.make_load_error(path)
6
- err = LoadError.new(+"cannot load such file -- #{path}")
7
- err.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
8
- err.define_singleton_method(:path) { path }
9
- err
10
- end
11
- end
12
- end
13
- end
14
2
 
15
3
  module Kernel
16
- module_function # rubocop:disable Style/ModuleFunction
4
+ module_function
17
5
 
18
6
  alias_method(:require_without_bootsnap, :require)
19
7
 
20
- # Note that require registers to $LOADED_FEATURES while load does not.
21
- def require_with_bootsnap_lfi(path, resolved = nil)
22
- Bootsnap::LoadPathCache.loaded_features_index.register(path, resolved) do
23
- require_without_bootsnap(resolved || path)
24
- end
25
- end
26
-
27
8
  def require(path)
28
- return false if Bootsnap::LoadPathCache.loaded_features_index.key?(path)
29
-
30
- if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(path))
31
- return require_with_bootsnap_lfi(path, resolved)
32
- end
9
+ string_path = Bootsnap.rb_get_path(path)
10
+ return false if Bootsnap::LoadPathCache.loaded_features_index.key?(string_path)
33
11
 
34
- raise(Bootsnap::LoadPathCache::CoreExt.make_load_error(path))
35
- rescue LoadError => e
36
- e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
37
- raise(e)
38
- rescue Bootsnap::LoadPathCache::ReturnFalse
39
- false
40
- rescue Bootsnap::LoadPathCache::FallbackScan
41
- fallback = true
42
- ensure
43
- if fallback
44
- require_with_bootsnap_lfi(path)
12
+ resolved = Bootsnap::LoadPathCache.load_path_cache.find(string_path)
13
+ if Bootsnap::LoadPathCache::FALLBACK_SCAN.equal?(resolved)
14
+ if (cursor = Bootsnap::LoadPathCache.loaded_features_index.cursor(string_path))
15
+ ret = require_without_bootsnap(path)
16
+ resolved = Bootsnap::LoadPathCache.loaded_features_index.identify(string_path, cursor)
17
+ Bootsnap::LoadPathCache.loaded_features_index.register(string_path, resolved)
18
+ return ret
19
+ else
20
+ return require_without_bootsnap(path)
21
+ end
22
+ elsif false == resolved
23
+ return false
24
+ elsif resolved.nil?
25
+ error = LoadError.new(+"cannot load such file -- #{path}")
26
+ error.instance_variable_set(:@path, path)
27
+ raise error
28
+ else
29
+ # Note that require registers to $LOADED_FEATURES while load does not.
30
+ ret = require_without_bootsnap(resolved)
31
+ Bootsnap::LoadPathCache.loaded_features_index.register(string_path, resolved)
32
+ return ret
45
33
  end
46
34
  end
47
35
 
48
- alias_method(:require_relative_without_bootsnap, :require_relative)
49
- def require_relative(path)
50
- realpath = Bootsnap::LoadPathCache.realpath_cache.call(
51
- caller_locations(1..1).first.absolute_path, path
52
- )
53
- require(realpath)
54
- end
55
-
56
36
  alias_method(:load_without_bootsnap, :load)
57
37
  def load(path, wrap = false)
58
- if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(path))
59
- return load_without_bootsnap(resolved, wrap)
60
- end
61
-
62
- # load also allows relative paths from pwd even when not in $:
63
- if File.exist?(relative = File.expand_path(path).freeze)
64
- return load_without_bootsnap(relative, wrap)
65
- end
66
-
67
- raise(Bootsnap::LoadPathCache::CoreExt.make_load_error(path))
68
- rescue LoadError => e
69
- e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
70
- raise(e)
71
- rescue Bootsnap::LoadPathCache::ReturnFalse
72
- false
73
- rescue Bootsnap::LoadPathCache::FallbackScan
74
- fallback = true
75
- ensure
76
- if fallback
38
+ if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(Bootsnap.rb_get_path(path), try_extensions: false))
39
+ load_without_bootsnap(resolved, wrap)
40
+ else
77
41
  load_without_bootsnap(path, wrap)
78
42
  end
79
43
  end
@@ -89,17 +53,13 @@ class Module
89
53
  # The challenge is that we don't control the point at which the entry gets
90
54
  # added to $LOADED_FEATURES and won't be able to hook that modification
91
55
  # since it's done in C-land.
92
- autoload_without_bootsnap(const, Bootsnap::LoadPathCache.load_path_cache.find(path) || path)
93
- rescue LoadError => e
94
- e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
95
- raise(e)
96
- rescue Bootsnap::LoadPathCache::ReturnFalse
97
- false
98
- rescue Bootsnap::LoadPathCache::FallbackScan
99
- fallback = true
100
- ensure
101
- if fallback
56
+ resolved = Bootsnap::LoadPathCache.load_path_cache.find(Bootsnap.rb_get_path(path))
57
+ if Bootsnap::LoadPathCache::FALLBACK_SCAN.equal?(resolved)
102
58
  autoload_without_bootsnap(const, path)
59
+ elsif resolved == false
60
+ return false
61
+ else
62
+ autoload_without_bootsnap(const, resolved || path)
103
63
  end
104
64
  end
105
65
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class << $LOADED_FEATURES
3
4
  alias_method(:delete_without_bootsnap, :delete)
4
5
  def delete(key)
@@ -29,14 +29,15 @@ module Bootsnap
29
29
  @mutex = Mutex.new
30
30
 
31
31
  # In theory the user could mutate $LOADED_FEATURES and invalidate our
32
- # cache. If this ever comes up in practice or if you, the
33
- # enterprising reader, feels inclined to solve this problem we could
32
+ # cache. If this ever comes up in practice - or if you, the
33
+ # enterprising reader, feels inclined to solve this problem - we could
34
34
  # parallel the work done with ChangeObserver on $LOAD_PATH to mirror
35
35
  # updates to our @lfi.
36
36
  $LOADED_FEATURES.each do |feat|
37
37
  hash = feat.hash
38
38
  $LOAD_PATH.each do |lpe|
39
39
  next unless feat.start_with?(lpe)
40
+
40
41
  # /a/b/lib/my/foo.rb
41
42
  # ^^^^^^^^^
42
43
  short = feat[(lpe.length + 1)..-1]
@@ -58,9 +59,9 @@ module Bootsnap
58
59
  end
59
60
 
60
61
  def purge_multi(features)
61
- rejected_hashes = features.map(&:hash).to_set
62
+ rejected_hashes = features.each_with_object({}) { |f, h| h[f.hash] = true }
62
63
  @mutex.synchronize do
63
- @lfi.reject! { |_, hash| rejected_hashes.include?(hash) }
64
+ @lfi.reject! { |_, hash| rejected_hashes.key?(hash) }
64
65
  end
65
66
  end
66
67
 
@@ -68,11 +69,30 @@ module Bootsnap
68
69
  @mutex.synchronize { @lfi.key?(feature) }
69
70
  end
70
71
 
72
+ def cursor(short)
73
+ unless Bootsnap.absolute_path?(short.to_s)
74
+ $LOADED_FEATURES.size
75
+ end
76
+ end
77
+
78
+ def identify(short, cursor)
79
+ $LOADED_FEATURES[cursor..-1].detect do |feat|
80
+ offset = 0
81
+ while (offset = feat.index(short, offset))
82
+ if feat.index(".", offset + 1) && !feat.index("/", offset + 2)
83
+ break true
84
+ else
85
+ offset += 1
86
+ end
87
+ end
88
+ end
89
+ end
90
+
71
91
  # There is a relatively uncommon case where we could miss adding an
72
92
  # entry:
73
93
  #
74
94
  # If the user asked for e.g. `require 'bundler'`, and we went through the
75
- # `FallbackScan` pathway in `kernel_require.rb` and therefore did not
95
+ # `FALLBACK_SCAN` pathway in `kernel_require.rb` and therefore did not
76
96
  # pass `long` (the full expanded absolute path), then we did are not able
77
97
  # to confidently add the `bundler.rb` form to @lfi.
78
98
  #
@@ -82,15 +102,8 @@ module Bootsnap
82
102
  # not quite right; or
83
103
  # 2. Inspect $LOADED_FEATURES upon return from yield to find the matching
84
104
  # entry.
85
- def register(short, long = nil)
86
- if long.nil?
87
- pat = %r{/#{Regexp.escape(short)}(\.[^/]+)?$}
88
- len = $LOADED_FEATURES.size
89
- ret = yield
90
- long = $LOADED_FEATURES[len..-1].detect { |feat| feat =~ pat }
91
- else
92
- ret = yield
93
- end
105
+ def register(short, long)
106
+ return if Bootsnap.absolute_path?(short)
94
107
 
95
108
  hash = long.hash
96
109
 
@@ -109,13 +122,11 @@ module Bootsnap
109
122
  @lfi[short] = hash
110
123
  (@lfi[altname] = hash) if altname
111
124
  end
112
-
113
- ret
114
125
  end
115
126
 
116
127
  private
117
128
 
118
- STRIP_EXTENSION = /\.[^.]*?$/
129
+ STRIP_EXTENSION = /\.[^.]*?$/.freeze
119
130
  private_constant(:STRIP_EXTENSION)
120
131
 
121
132
  # Might Ruby automatically search for this extension if
@@ -132,15 +143,15 @@ module Bootsnap
132
143
  # with calling a Ruby file 'x.dylib.rb' and then requiring it as 'x.dylib'.)
133
144
  #
134
145
  # See <https://ruby-doc.org/core-2.6.4/Kernel.html#method-i-require>.
135
- def extension_elidable?(f)
136
- f.to_s.end_with?('.rb', '.so', '.o', '.dll', '.dylib')
146
+ def extension_elidable?(feature)
147
+ feature.to_s.end_with?(".rb", ".so", ".o", ".dll", ".dylib")
137
148
  end
138
149
 
139
- def strip_extension_if_elidable(f)
140
- if extension_elidable?(f)
141
- f.sub(STRIP_EXTENSION, '')
150
+ def strip_extension_if_elidable(feature)
151
+ if extension_elidable?(feature)
152
+ feature.sub(STRIP_EXTENSION, "")
142
153
  else
143
- f
154
+ feature
144
155
  end
145
156
  end
146
157
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require_relative('path_scanner')
2
+
3
+ require_relative("path_scanner")
3
4
 
4
5
  module Bootsnap
5
6
  module LoadPathCache
@@ -20,8 +21,26 @@ module Bootsnap
20
21
 
21
22
  attr_reader(:path)
22
23
 
23
- def initialize(path)
24
+ def initialize(path, real: false)
24
25
  @path = path.to_s.freeze
26
+ @real = real
27
+ end
28
+
29
+ def to_realpath
30
+ return self if @real
31
+
32
+ realpath = begin
33
+ File.realpath(path)
34
+ rescue Errno::ENOENT
35
+ return self
36
+ end
37
+
38
+ if realpath != path
39
+ Path.new(realpath, real: true)
40
+ else
41
+ @real = true
42
+ self
43
+ end
25
44
  end
26
45
 
27
46
  # True if the path exists, but represents a non-directory object
@@ -43,6 +62,7 @@ module Bootsnap
43
62
  # set to zero anyway, just in case we change the stability heuristics.
44
63
  _, entries, dirs = store.get(expanded_path)
45
64
  return [entries, dirs] if entries # cache hit
65
+
46
66
  entries, dirs = scan!
47
67
  store.set(expanded_path, [0, entries, dirs])
48
68
  return [entries, dirs]
@@ -60,7 +80,11 @@ module Bootsnap
60
80
  end
61
81
 
62
82
  def expanded_path
63
- File.expand_path(path).freeze
83
+ if @real
84
+ path
85
+ else
86
+ @expanded_path ||= File.expand_path(path).freeze
87
+ end
64
88
  end
65
89
 
66
90
  private
@@ -93,8 +117,8 @@ module Bootsnap
93
117
 
94
118
  # Built-in ruby lib stuff doesn't change, but things can occasionally be
95
119
  # installed into sitedir, which generally lives under libdir.
96
- RUBY_LIBDIR = RbConfig::CONFIG['libdir']
97
- RUBY_SITEDIR = RbConfig::CONFIG['sitedir']
120
+ RUBY_LIBDIR = RbConfig::CONFIG["libdir"]
121
+ RUBY_SITEDIR = RbConfig::CONFIG["sitedir"]
98
122
 
99
123
  def stability
100
124
  @stability ||= begin
@@ -1,18 +1,18 @@
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
7
7
  module PathScanner
8
8
  REQUIRABLE_EXTENSIONS = [DOT_RB] + DL_EXTENSIONS
9
9
  NORMALIZE_NATIVE_EXTENSIONS = !DL_EXTENSIONS.include?(LoadPathCache::DOT_SO)
10
- ALTERNATIVE_NATIVE_EXTENSIONS_PATTERN = /\.(o|bundle|dylib)\z/
10
+ ALTERNATIVE_NATIVE_EXTENSIONS_PATTERN = /\.(o|bundle|dylib)\z/.freeze
11
11
 
12
12
  BUNDLE_PATH = if Bootsnap.bundler?
13
13
  (Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze
14
14
  else
15
- ''
15
+ ""
16
16
  end
17
17
 
18
18
  class << self
@@ -44,7 +44,8 @@ module Bootsnap
44
44
 
45
45
  def walk(absolute_dir_path, relative_dir_path, &block)
46
46
  Dir.foreach(absolute_dir_path) do |name|
47
- next if name.start_with?('.')
47
+ next if name.start_with?(".")
48
+
48
49
  relative_path = relative_dir_path ? File.join(relative_dir_path, name) : name
49
50
 
50
51
  absolute_path = "#{absolute_dir_path}/#{name}"
@@ -58,7 +59,7 @@ module Bootsnap
58
59
  end
59
60
  end
60
61
 
61
- if RUBY_VERSION >= '3.1'
62
+ if RUBY_VERSION >= "3.1"
62
63
  def os_path(path)
63
64
  path.freeze
64
65
  end
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
- require_relative('../explicit_require')
3
2
 
4
- Bootsnap::ExplicitRequire.with_gems('msgpack') { require('msgpack') }
5
- Bootsnap::ExplicitRequire.from_rubylibdir('fileutils')
3
+ require_relative("../explicit_require")
4
+
5
+ Bootsnap::ExplicitRequire.with_gems("msgpack") { require("msgpack") }
6
6
 
7
7
  module Bootsnap
8
8
  module LoadPathCache
9
9
  class Store
10
+ VERSION_KEY = "__bootsnap_ruby_version__"
11
+ CURRENT_VERSION = "#{RUBY_REVISION}-#{RUBY_PLATFORM}".freeze # rubocop:disable Style/RedundantFreeze
12
+
10
13
  NestedTransactionError = Class.new(StandardError)
11
14
  SetOutsideTransactionNotAllowed = Class.new(StandardError)
12
15
 
@@ -23,10 +26,11 @@ module Bootsnap
23
26
 
24
27
  def fetch(key)
25
28
  raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
29
+
26
30
  v = get(key)
27
31
  unless v
28
- @dirty = true
29
32
  v = yield
33
+ mark_for_mutation!
30
34
  @data[key] = v
31
35
  end
32
36
  v
@@ -34,14 +38,16 @@ module Bootsnap
34
38
 
35
39
  def set(key, value)
36
40
  raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
41
+
37
42
  if value != @data[key]
38
- @dirty = true
43
+ mark_for_mutation!
39
44
  @data[key] = value
40
45
  end
41
46
  end
42
47
 
43
48
  def transaction
44
49
  raise(NestedTransactionError) if @txn_mutex.owned?
50
+
45
51
  @txn_mutex.synchronize do
46
52
  begin
47
53
  yield
@@ -53,6 +59,11 @@ module Bootsnap
53
59
 
54
60
  private
55
61
 
62
+ def mark_for_mutation!
63
+ @dirty = true
64
+ @data = @data.dup if @data.frozen?
65
+ end
66
+
56
67
  def commit_transaction
57
68
  if @dirty
58
69
  dump_data
@@ -62,15 +73,20 @@ module Bootsnap
62
73
 
63
74
  def load_data
64
75
  @data = begin
65
- File.open(@store_path, encoding: Encoding::BINARY) do |io|
66
- MessagePack.load(io)
76
+ data = File.open(@store_path, encoding: Encoding::BINARY) do |io|
77
+ MessagePack.load(io, freeze: true)
78
+ end
79
+ if data.is_a?(Hash) && data[VERSION_KEY] == CURRENT_VERSION
80
+ data
81
+ else
82
+ default_data
67
83
  end
68
84
  # handle malformed data due to upgrade incompatibility
69
85
  rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
70
- {}
86
+ default_data
71
87
  rescue ArgumentError => error
72
88
  if error.message =~ /negative array size/
73
- {}
89
+ default_data
74
90
  else
75
91
  raise
76
92
  end
@@ -80,17 +96,37 @@ module Bootsnap
80
96
  def dump_data
81
97
  # Change contents atomically so other processes can't get invalid
82
98
  # caches if they read at an inopportune time.
83
- tmp = "#{@store_path}.#{Process.pid}.#{(rand * 100000).to_i}.tmp"
84
- FileUtils.mkpath(File.dirname(tmp))
99
+ tmp = "#{@store_path}.#{Process.pid}.#{(rand * 100_000).to_i}.tmp"
100
+ mkdir_p(File.dirname(tmp))
85
101
  exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY
86
102
  # `encoding:` looks redundant wrt `binwrite`, but necessary on windows
87
103
  # because binary is part of mode.
88
104
  File.open(tmp, mode: exclusive_write, encoding: Encoding::BINARY) do |io|
89
- MessagePack.dump(@data, io, freeze: true)
105
+ MessagePack.dump(@data, io)
90
106
  end
91
- FileUtils.mv(tmp, @store_path)
107
+ File.rename(tmp, @store_path)
92
108
  rescue Errno::EEXIST
93
109
  retry
110
+ rescue SystemCallError
111
+ end
112
+
113
+ def default_data
114
+ {VERSION_KEY => CURRENT_VERSION}
115
+ end
116
+
117
+ def mkdir_p(path)
118
+ stack = []
119
+ until File.directory?(path)
120
+ stack.push path
121
+ path = File.dirname(path)
122
+ end
123
+ stack.reverse_each do |dir|
124
+ begin
125
+ Dir.mkdir(dir)
126
+ rescue SystemCallError
127
+ raise unless File.directory?(dir)
128
+ end
129
+ end
94
130
  end
95
131
  end
96
132
  end
@@ -2,20 +2,14 @@
2
2
 
3
3
  module Bootsnap
4
4
  module LoadPathCache
5
- ReturnFalse = Class.new(StandardError)
6
- FallbackScan = Class.new(StandardError)
5
+ FALLBACK_SCAN = BasicObject.new
7
6
 
8
- DOT_RB = '.rb'
9
- DOT_SO = '.so'
10
- SLASH = '/'
11
-
12
- # If a NameError happens several levels deep, don't re-handle it
13
- # all the way up the chain: mark it once and bubble it up without
14
- # more retries.
15
- ERROR_TAG_IVAR = :@__bootsnap_rescued
7
+ DOT_RB = ".rb"
8
+ DOT_SO = ".so"
9
+ SLASH = "/"
16
10
 
17
11
  DL_EXTENSIONS = ::RbConfig::CONFIG
18
- .values_at('DLEXT', 'DLEXT2')
12
+ .values_at("DLEXT", "DLEXT2")
19
13
  .reject { |ext| !ext || ext.empty? }
20
14
  .map { |ext| ".#{ext}" }
21
15
  .freeze
@@ -28,7 +22,7 @@ module Bootsnap
28
22
  CACHED_EXTENSIONS = DLEXT2 ? [DOT_RB, DLEXT, DLEXT2] : [DOT_RB, DLEXT]
29
23
 
30
24
  class << self
31
- attr_reader(:load_path_cache, :loaded_features_index, :realpath_cache)
25
+ attr_reader(:load_path_cache, :loaded_features_index)
32
26
 
33
27
  def setup(cache_path:, development_mode:)
34
28
  unless supported?
@@ -39,27 +33,25 @@ module Bootsnap
39
33
  store = Store.new(cache_path)
40
34
 
41
35
  @loaded_features_index = LoadedFeaturesIndex.new
42
- @realpath_cache = RealpathCache.new
43
36
 
44
37
  @load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
45
- require_relative('load_path_cache/core_ext/kernel_require')
46
- require_relative('load_path_cache/core_ext/loaded_features')
38
+ require_relative("load_path_cache/core_ext/kernel_require")
39
+ require_relative("load_path_cache/core_ext/loaded_features")
47
40
  end
48
41
 
49
42
  def supported?
50
- RUBY_ENGINE == 'ruby' &&
51
- RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/
43
+ RUBY_ENGINE == "ruby" &&
44
+ RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/
52
45
  end
53
46
  end
54
47
  end
55
48
  end
56
49
 
57
50
  if Bootsnap::LoadPathCache.supported?
58
- require_relative('load_path_cache/path_scanner')
59
- require_relative('load_path_cache/path')
60
- require_relative('load_path_cache/cache')
61
- require_relative('load_path_cache/store')
62
- require_relative('load_path_cache/change_observer')
63
- require_relative('load_path_cache/loaded_features_index')
64
- require_relative('load_path_cache/realpath_cache')
51
+ require_relative("load_path_cache/path_scanner")
52
+ require_relative("load_path_cache/path")
53
+ require_relative("load_path_cache/cache")
54
+ require_relative("load_path_cache/store")
55
+ require_relative("load_path_cache/change_observer")
56
+ require_relative("load_path_cache/loaded_features_index")
65
57
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require_relative('../bootsnap')
2
+
3
+ require_relative("../bootsnap")
3
4
 
4
5
  Bootsnap.default_setup
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Bootsnap
3
- VERSION = "1.7.2"
4
+ VERSION = "1.11.1"
4
5
  end