bootsnap 1.11.1 → 1.18.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,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
@@ -35,18 +35,18 @@ module Bootsnap
35
35
  return self
36
36
  end
37
37
 
38
- if realpath != path
39
- Path.new(realpath, real: true)
40
- else
38
+ if realpath == path
41
39
  @real = true
42
40
  self
41
+ else
42
+ Path.new(realpath, real: true)
43
43
  end
44
44
  end
45
45
 
46
46
  # True if the path exists, but represents a non-directory object
47
47
  def non_directory?
48
48
  !File.stat(path).directory?
49
- rescue Errno::ENOENT, Errno::ENOTDIR
49
+ rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
50
50
  false
51
51
  end
52
52
 
@@ -101,7 +101,7 @@ module Bootsnap
101
101
  ["", *dirs].each do |dir|
102
102
  curr = begin
103
103
  File.mtime("#{path}/#{dir}").to_i
104
- rescue Errno::ENOENT, Errno::ENOTDIR
104
+ rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
105
105
  -1
106
106
  end
107
107
  max = curr if curr > max
@@ -116,21 +116,19 @@ module Bootsnap
116
116
  VOLATILE = :volatile
117
117
 
118
118
  # Built-in ruby lib stuff doesn't change, but things can occasionally be
119
- # installed into sitedir, which generally lives under libdir.
120
- RUBY_LIBDIR = RbConfig::CONFIG["libdir"]
119
+ # installed into sitedir, which generally lives under rubylibdir.
120
+ RUBY_LIBDIR = RbConfig::CONFIG["rubylibdir"]
121
121
  RUBY_SITEDIR = RbConfig::CONFIG["sitedir"]
122
122
 
123
123
  def stability
124
- @stability ||= begin
125
- if Gem.path.detect { |p| expanded_path.start_with?(p.to_s) }
126
- STABLE
127
- elsif Bootsnap.bundler? && expanded_path.start_with?(Bundler.bundle_path.to_s)
128
- STABLE
129
- elsif expanded_path.start_with?(RUBY_LIBDIR) && !expanded_path.start_with?(RUBY_SITEDIR)
130
- STABLE
131
- else
132
- VOLATILE
133
- end
124
+ @stability ||= if Gem.path.detect { |p| expanded_path.start_with?(p.to_s) }
125
+ STABLE
126
+ elsif Bootsnap.bundler? && expanded_path.start_with?(Bundler.bundle_path.to_s)
127
+ STABLE
128
+ elsif expanded_path.start_with?(RUBY_LIBDIR) && !expanded_path.start_with?(RUBY_SITEDIR)
129
+ STABLE
130
+ else
131
+ VOLATILE
134
132
  end
135
133
  end
136
134
  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
@@ -15,7 +15,11 @@ module Bootsnap
15
15
  ""
16
16
  end
17
17
 
18
+ @ignored_directories = %w(node_modules)
19
+
18
20
  class << self
21
+ attr_accessor :ignored_directories
22
+
19
23
  def call(path)
20
24
  path = File.expand_path(path.to_s).freeze
21
25
  return [[], []] unless File.directory?(path)
@@ -50,6 +54,8 @@ module Bootsnap
50
54
 
51
55
  absolute_path = "#{absolute_dir_path}/#{name}"
52
56
  if File.directory?(absolute_path)
57
+ next if ignored_directories.include?(name) || ignored_directories.include?(absolute_path)
58
+
53
59
  if yield relative_path, absolute_path, true
54
60
  walk(absolute_path, relative_path, &block)
55
61
  end
@@ -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
@@ -13,10 +13,11 @@ module Bootsnap
13
13
  NestedTransactionError = Class.new(StandardError)
14
14
  SetOutsideTransactionNotAllowed = Class.new(StandardError)
15
15
 
16
- def initialize(store_path)
16
+ def initialize(store_path, readonly: false)
17
17
  @store_path = store_path
18
18
  @txn_mutex = Mutex.new
19
19
  @dirty = false
20
+ @readonly = readonly
20
21
  load_data
21
22
  end
22
23
 
@@ -49,11 +50,9 @@ module Bootsnap
49
50
  raise(NestedTransactionError) if @txn_mutex.owned?
50
51
 
51
52
  @txn_mutex.synchronize do
52
- begin
53
- yield
54
- ensure
55
- commit_transaction
56
- end
53
+ yield
54
+ ensure
55
+ commit_transaction
57
56
  end
58
57
  end
59
58
 
@@ -65,7 +64,7 @@ module Bootsnap
65
64
  end
66
65
 
67
66
  def commit_transaction
68
- if @dirty
67
+ if @dirty && !@readonly
69
68
  dump_data
70
69
  @dirty = false
71
70
  end
@@ -121,11 +120,9 @@ module Bootsnap
121
120
  path = File.dirname(path)
122
121
  end
123
122
  stack.reverse_each do |dir|
124
- begin
125
- Dir.mkdir(dir)
126
- rescue SystemCallError
127
- raise unless File.directory?(dir)
128
- end
123
+ Dir.mkdir(dir)
124
+ rescue SystemCallError
125
+ raise unless File.directory?(dir)
129
126
  end
130
127
  end
131
128
  end
@@ -21,37 +21,60 @@ module Bootsnap
21
21
 
22
22
  CACHED_EXTENSIONS = DLEXT2 ? [DOT_RB, DLEXT, DLEXT2] : [DOT_RB, DLEXT]
23
23
 
24
+ @enabled = false
25
+
24
26
  class << self
25
- attr_reader(:load_path_cache, :loaded_features_index)
27
+ attr_reader(:load_path_cache, :loaded_features_index, :enabled)
28
+ alias_method :enabled?, :enabled
29
+ remove_method(:enabled)
26
30
 
27
- def setup(cache_path:, development_mode:)
31
+ def setup(cache_path:, development_mode:, ignore_directories:, readonly: false)
28
32
  unless supported?
29
33
  warn("[bootsnap/setup] Load path caching is not supported on this implementation of Ruby") if $VERBOSE
30
34
  return
31
35
  end
32
36
 
33
- store = Store.new(cache_path)
37
+ store = Store.new(cache_path, readonly: readonly)
34
38
 
35
39
  @loaded_features_index = LoadedFeaturesIndex.new
36
40
 
41
+ PathScanner.ignored_directories = ignore_directories if ignore_directories
37
42
  @load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
38
- require_relative("load_path_cache/core_ext/kernel_require")
39
- require_relative("load_path_cache/core_ext/loaded_features")
43
+ @enabled = true
44
+ require_relative "load_path_cache/core_ext/kernel_require"
45
+ require_relative "load_path_cache/core_ext/loaded_features"
46
+ end
47
+
48
+ def unload!
49
+ @enabled = false
50
+ @loaded_features_index = nil
51
+ @realpath_cache = nil
52
+ @load_path_cache = nil
53
+ ChangeObserver.unregister($LOAD_PATH) if supported?
40
54
  end
41
55
 
42
56
  def supported?
43
- RUBY_ENGINE == "ruby" &&
44
- 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
45
68
  end
46
69
  end
47
70
  end
48
71
  end
49
72
 
50
73
  if Bootsnap::LoadPathCache.supported?
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")
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"
57
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.11.1"
4
+ VERSION = "1.18.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)
@@ -11,6 +11,16 @@ module Bootsnap
11
11
  class << self
12
12
  attr_reader :logger
13
13
 
14
+ def log_stats!
15
+ stats = {hit: 0, revalidated: 0, miss: 0, stale: 0}
16
+ self.instrumentation = ->(event, _path) { stats[event] += 1 }
17
+ Kernel.at_exit do
18
+ stats.each do |event, count|
19
+ $stderr.puts "bootsnap #{event}: #{count}"
20
+ end
21
+ end
22
+ end
23
+
14
24
  def log!
15
25
  self.logger = $stderr.method(:puts)
16
26
  end
@@ -18,9 +28,9 @@ module Bootsnap
18
28
  def logger=(logger)
19
29
  @logger = logger
20
30
  self.instrumentation = if logger.respond_to?(:debug)
21
- ->(event, path) { @logger.debug("[Bootsnap] #{event} #{path}") }
31
+ ->(event, path) { @logger.debug("[Bootsnap] #{event} #{path}") unless event == :hit }
22
32
  else
23
- ->(event, path) { @logger.call("[Bootsnap] #{event} #{path}") }
33
+ ->(event, path) { @logger.call("[Bootsnap] #{event} #{path}") unless event == :hit }
24
34
  end
25
35
  end
26
36
 
@@ -39,48 +49,32 @@ module Bootsnap
39
49
  cache_dir:,
40
50
  development_mode: true,
41
51
  load_path_cache: true,
42
- autoload_paths_cache: nil,
43
- disable_trace: nil,
52
+ ignore_directories: nil,
53
+ readonly: false,
44
54
  compile_cache_iseq: true,
45
55
  compile_cache_yaml: true,
46
56
  compile_cache_json: true
47
57
  )
48
- unless autoload_paths_cache.nil?
49
- warn "[DEPRECATED] Bootsnap's `autoload_paths_cache:` option is deprecated and will be removed. " \
50
- "If you use Zeitwerk this option is useless, and if you are still using the classic autoloader " \
51
- "upgrading is recommended."
52
- end
53
-
54
- unless disable_trace.nil?
55
- warn "[DEPRECATED] Bootsnap's `disable_trace:` option is deprecated and will be removed. " \
56
- "If you use Ruby 2.5 or newer this option is useless, if not upgrading is recommended."
57
- end
58
-
59
- if compile_cache_iseq && !iseq_cache_supported?
60
- warn "Ruby 2.5 has a bug that break code tracing when code is loaded from cache. It is recommened " \
61
- "to turn `compile_cache_iseq` off on Ruby 2.5"
62
- end
63
-
64
58
  if load_path_cache
65
59
  Bootsnap::LoadPathCache.setup(
66
- cache_path: cache_dir + "/bootsnap/load-path-cache",
60
+ cache_path: "#{cache_dir}/bootsnap/load-path-cache",
67
61
  development_mode: development_mode,
62
+ ignore_directories: ignore_directories,
63
+ readonly: readonly,
68
64
  )
69
65
  end
70
66
 
71
67
  Bootsnap::CompileCache.setup(
72
- cache_dir: cache_dir + "/bootsnap/compile-cache",
68
+ cache_dir: "#{cache_dir}/bootsnap/compile-cache",
73
69
  iseq: compile_cache_iseq,
74
70
  yaml: compile_cache_yaml,
75
71
  json: compile_cache_json,
72
+ readonly: readonly,
76
73
  )
77
74
  end
78
75
 
79
- def iseq_cache_supported?
80
- return @iseq_cache_supported if defined? @iseq_cache_supported
81
-
82
- ruby_version = Gem::Version.new(RUBY_VERSION)
83
- @iseq_cache_supported = ruby_version < Gem::Version.new("2.5.0") || ruby_version >= Gem::Version.new("2.6.0")
76
+ def unload_cache!
77
+ LoadPathCache.unload!
84
78
  end
85
79
 
86
80
  def default_setup
@@ -109,17 +103,25 @@ module Bootsnap
109
103
  cache_dir = File.join(app_root, "tmp", "cache")
110
104
  end
111
105
 
106
+ ignore_directories = if ENV.key?("BOOTSNAP_IGNORE_DIRECTORIES")
107
+ ENV["BOOTSNAP_IGNORE_DIRECTORIES"].split(",")
108
+ end
109
+
112
110
  setup(
113
111
  cache_dir: cache_dir,
114
112
  development_mode: development_mode,
115
113
  load_path_cache: !ENV["DISABLE_BOOTSNAP_LOAD_PATH_CACHE"],
116
- compile_cache_iseq: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"] && iseq_cache_supported?,
114
+ compile_cache_iseq: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
117
115
  compile_cache_yaml: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
118
116
  compile_cache_json: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
117
+ readonly: !!ENV["BOOTSNAP_READONLY"],
118
+ ignore_directories: ignore_directories,
119
119
  )
120
120
 
121
121
  if ENV["BOOTSNAP_LOG"]
122
122
  log!
123
+ elsif ENV["BOOTSNAP_STATS"]
124
+ log_stats!
123
125
  end
124
126
  end
125
127
  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.11.1
4
+ version: 1.18.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: 2022-03-08 00:00:00.000000000 Z
11
+ date: 2024-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -76,14 +76,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
76
  requirements:
77
77
  - - ">="
78
78
  - !ruby/object:Gem::Version
79
- version: 2.4.0
79
+ version: 2.6.0
80
80
  required_rubygems_version: !ruby/object:Gem::Requirement
81
81
  requirements:
82
82
  - - ">="
83
83
  - !ruby/object:Gem::Version
84
84
  version: '0'
85
85
  requirements: []
86
- rubygems_version: 3.2.20
86
+ rubygems_version: 3.5.5
87
87
  signing_key:
88
88
  specification_version: 4
89
89
  summary: Boot large ruby/rails apps faster