bootsnap 1.9.0 → 1.9.4

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: 40e9beab427c546339a38041cdc59b826389b30d1976fb9586b6782daf728ed3
4
- data.tar.gz: 1cfa891e84615fe3ed6d76a8c222420568c9ddb09077378199f6ba8862789d9f
3
+ metadata.gz: 7602567343afc549df266a1b3def7e8c1e755b03a9ce486d17bba7051e97dfda
4
+ data.tar.gz: 607abfa5738cb016172bba2eb94af48b80b9e73dddea1090be77b7ca7d9f121d
5
5
  SHA512:
6
- metadata.gz: 5d74ccbd9cadf8fa00e6cef7c4159a34448a2f5e8fb0b94b6e63ee3b0032f1555ca613706821236965ad6f005f00eb305727e6eb62a6125c449a419bbb1db34a
7
- data.tar.gz: 5a2e9d7e599797747370bbf3733ed442a795f69f040f2fa5db0736132de815a4c6a82254cf988602aec47c10fbfb73e696bf752581723a83b241a22f5d08b2c2
6
+ metadata.gz: 7effd658adb07d075cfbc883f47382c23f774a872fcfa2daa0b137ff5f903057a1f825a90cd96cd5784a2e72fcb583ce05b4fcf98201a2a2cb6830c90109e096
7
+ data.tar.gz: ed2f42c2e5e91c373c8882fbe17abfab93c43e6ab39b83a7aa3031d6dba48088da9c3a271b52bbb7bc83ace117d677ec25e4865936972d939a00b08580f5e45e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Unreleased
2
2
 
3
+ # 1.9.4
4
+
5
+ * Ignore absolute paths in the loaded feature index. (#385)
6
+ This fixes a compatibility issue with Zeitwerk when Zeitwerk is loaded before bootsnap. It also should
7
+ reduce the memory usage and improve load performance of Zeitwerk managed files.
8
+
9
+ * Automatically invalidate the load path cache whenever the Ruby version change. (#387)
10
+ This is to avoid issues in case the same installation path is re-used for subsequent ruby patch releases.
11
+
12
+ # 1.9.3
13
+
14
+ * Only disable the compile cache for source files impacted by [Ruby 3.0.3 [Bug 18250]](https://bugs.ruby-lang.org/issues/18250).
15
+ This should keep the performance loss to a minimum.
16
+
17
+ # 1.9.2
18
+
19
+ * Disable compile cache if [Ruby 3.0.3's ISeq cache bug](https://bugs.ruby-lang.org/issues/18250) is detected.
20
+ AKA `iseq.rb:13 to_binary: wrong argument type false (expected Symbol)`
21
+ * Fix `Kernel.load` behavior: before `load 'a'` would load `a.rb` (and other tried extensions) and wouldn't load `a` unless `development_mode: true`, now only `a` would be loaded and files with extensions wouldn't be.
22
+
23
+ # 1.9.1
24
+
25
+ * Removed a forgotten debug statement in JSON precompilation.
26
+
3
27
  # 1.9.0
4
28
 
5
29
  * Added a compilation cache for `JSON.load_file`. (#370)
data/lib/bootsnap/cli.rb CHANGED
@@ -161,7 +161,7 @@ module Bootsnap
161
161
 
162
162
  def precompile_json(*json_files)
163
163
  Array(json_files).each do |json_file|
164
- if p(CompileCache::JSON.precompile(json_file, cache_dir: cache_dir))
164
+ if CompileCache::JSON.precompile(json_file, cache_dir: cache_dir)
165
165
  STDERR.puts(json_file) if verbose
166
166
  end
167
167
  end
@@ -9,10 +9,35 @@ module Bootsnap
9
9
  attr_accessor(:cache_dir)
10
10
  end
11
11
 
12
- def self.input_to_storage(_, path)
13
- RubyVM::InstructionSequence.compile_file(path).to_binary
14
- rescue SyntaxError
15
- raise(Uncompilable, 'syntax error')
12
+ has_ruby_bug_18250 = begin # https://bugs.ruby-lang.org/issues/18250
13
+ if defined? RubyVM::InstructionSequence
14
+ RubyVM::InstructionSequence.compile("def foo(*); ->{ super }; end; def foo(**); ->{ super }; end").to_binary
15
+ end
16
+ false
17
+ rescue TypeError
18
+ true
19
+ end
20
+
21
+ if has_ruby_bug_18250
22
+ def self.input_to_storage(_, path)
23
+ iseq = begin
24
+ RubyVM::InstructionSequence.compile_file(path)
25
+ rescue SyntaxError
26
+ raise(Uncompilable, 'syntax error')
27
+ end
28
+
29
+ begin
30
+ iseq.to_binary
31
+ rescue TypeError
32
+ raise(Uncompilable, 'ruby bug #18250')
33
+ end
34
+ end
35
+ else
36
+ def self.input_to_storage(_, path)
37
+ RubyVM::InstructionSequence.compile_file(path).to_binary
38
+ rescue SyntaxError
39
+ raise(Uncompilable, 'syntax error')
40
+ end
16
41
  end
17
42
 
18
43
  def self.storage_to_output(binary, _args)
@@ -28,7 +28,7 @@ module Bootsnap
28
28
  require_relative('compile_cache/json')
29
29
  Bootsnap::CompileCache::JSON.install!(cache_dir)
30
30
  elsif $VERBOSE
31
- warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
31
+ warn("[bootsnap/setup] JSON parsing caching is not supported on this implementation of Ruby")
32
32
  end
33
33
  end
34
34
  end
@@ -44,14 +44,20 @@ module Bootsnap
44
44
 
45
45
  # Try to resolve this feature to an absolute path without traversing the
46
46
  # loadpath.
47
- def find(feature)
47
+ def find(feature, try_extensions: true)
48
48
  reinitialize if (@has_relative_paths && dir_changed?) || stale?
49
49
  feature = feature.to_s.freeze
50
- return feature if absolute_path?(feature)
51
- return expand_path(feature) if feature.start_with?('./')
50
+
51
+ return feature if Bootsnap.absolute_path?(feature)
52
+
53
+ if feature.start_with?('./', '../')
54
+ return try_extensions ? expand_path(feature) : File.expand_path(feature).freeze
55
+ end
56
+
52
57
  @mutex.synchronize do
53
- x = search_index(feature)
58
+ x = search_index(feature, try_extensions: try_extensions)
54
59
  return x if x
60
+ return unless try_extensions
55
61
 
56
62
  # Ruby has some built-in features that require lies about.
57
63
  # For example, 'enumerator' is built in. If you require it, ruby
@@ -92,16 +98,6 @@ module Bootsnap
92
98
  raise(LoadPathCache::FallbackScan, '', []) if @development_mode
93
99
  end
94
100
 
95
- if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
96
- def absolute_path?(path)
97
- path[1] == ':'
98
- end
99
- else
100
- def absolute_path?(path)
101
- path.start_with?(SLASH)
102
- end
103
- end
104
-
105
101
  def unshift_paths(sender, *paths)
106
102
  return unless sender == @path_obj
107
103
  @mutex.synchronize { unshift_paths_locked(*paths) }
@@ -177,16 +173,24 @@ module Bootsnap
177
173
  end
178
174
 
179
175
  if DLEXT2
180
- def search_index(f)
181
- try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f + DLEXT2) || try_index(f)
176
+ def search_index(f, try_extensions: true)
177
+ if try_extensions
178
+ try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f + DLEXT2) || try_index(f)
179
+ else
180
+ try_index(f)
181
+ end
182
182
  end
183
183
 
184
184
  def maybe_append_extension(f)
185
185
  try_ext(f + DOT_RB) || try_ext(f + DLEXT) || try_ext(f + DLEXT2) || f
186
186
  end
187
187
  else
188
- def search_index(f)
189
- try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f)
188
+ def search_index(f, try_extensions: true)
189
+ if try_extensions
190
+ try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f)
191
+ else
192
+ try_index(f)
193
+ end
190
194
  end
191
195
 
192
196
  def maybe_append_extension(f)
@@ -56,25 +56,9 @@ module Kernel
56
56
 
57
57
  alias_method(:load_without_bootsnap, :load)
58
58
  def load(path, wrap = false)
59
- if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(path))
60
- return load_without_bootsnap(resolved, wrap)
61
- end
62
-
63
- # load also allows relative paths from pwd even when not in $:
64
- if File.exist?(relative = File.expand_path(path).freeze)
65
- return load_without_bootsnap(relative, wrap)
66
- end
67
-
68
- raise(Bootsnap::LoadPathCache::CoreExt.make_load_error(path))
69
- rescue LoadError => e
70
- e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
71
- raise(e)
72
- rescue Bootsnap::LoadPathCache::ReturnFalse
73
- false
74
- rescue Bootsnap::LoadPathCache::FallbackScan
75
- fallback = true
76
- ensure
77
- if fallback
59
+ if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(path, try_extensions: false))
60
+ load_without_bootsnap(resolved, wrap)
61
+ else
78
62
  load_without_bootsnap(path, wrap)
79
63
  end
80
64
  end
@@ -83,11 +83,24 @@ module Bootsnap
83
83
  # 2. Inspect $LOADED_FEATURES upon return from yield to find the matching
84
84
  # entry.
85
85
  def register(short, long = nil)
86
+ # Absolute paths are not a concern.
87
+ if Bootsnap.absolute_path?(short.to_s)
88
+ return yield
89
+ end
90
+
86
91
  if long.nil?
87
- pat = %r{/#{Regexp.escape(short)}(\.[^/]+)?$}
88
92
  len = $LOADED_FEATURES.size
89
93
  ret = yield
90
- long = $LOADED_FEATURES[len..-1].detect { |feat| feat =~ pat }
94
+ long = $LOADED_FEATURES[len..-1].detect do |feat|
95
+ offset = 0
96
+ while offset = feat.index(short, offset)
97
+ if feat.index(".", offset + 1) && !feat.index("/", offset + 2)
98
+ break true
99
+ else
100
+ offset += 1
101
+ end
102
+ end
103
+ end
91
104
  else
92
105
  ret = yield
93
106
  end
@@ -7,6 +7,9 @@ Bootsnap::ExplicitRequire.from_rubylibdir('fileutils')
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
12
+
10
13
  NestedTransactionError = Class.new(StandardError)
11
14
  SetOutsideTransactionNotAllowed = Class.new(StandardError)
12
15
 
@@ -62,15 +65,20 @@ module Bootsnap
62
65
 
63
66
  def load_data
64
67
  @data = begin
65
- File.open(@store_path, encoding: Encoding::BINARY) do |io|
68
+ data = File.open(@store_path, encoding: Encoding::BINARY) do |io|
66
69
  MessagePack.load(io)
67
70
  end
71
+ if data.is_a?(Hash) && data[VERSION_KEY] == CURRENT_VERSION
72
+ data
73
+ else
74
+ default_data
75
+ end
68
76
  # handle malformed data due to upgrade incompatibility
69
77
  rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
70
- {}
78
+ default_data
71
79
  rescue ArgumentError => error
72
80
  if error.message =~ /negative array size/
73
- {}
81
+ default_data
74
82
  else
75
83
  raise
76
84
  end
@@ -93,6 +101,10 @@ module Bootsnap
93
101
  retry
94
102
  rescue SystemCallError
95
103
  end
104
+
105
+ def default_data
106
+ { VERSION_KEY => CURRENT_VERSION }
107
+ end
96
108
  end
97
109
  end
98
110
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Bootsnap
3
- VERSION = "1.9.0"
3
+ VERSION = "1.9.4"
4
4
  end
data/lib/bootsnap.rb CHANGED
@@ -123,4 +123,14 @@ module Bootsnap
123
123
  end
124
124
  end
125
125
  end
126
+
127
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
128
+ def self.absolute_path?(path)
129
+ path[1] == ':'
130
+ end
131
+ else
132
+ def self.absolute_path?(path)
133
+ path.start_with?('/')
134
+ end
135
+ end
126
136
  end
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.9.0
4
+ version: 1.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Burke Libbey
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-16 00:00:00.000000000 Z
11
+ date: 2022-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler