bootsnap 1.6.0 → 1.18.3
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 +4 -4
- data/CHANGELOG.md +218 -0
- data/LICENSE.txt +1 -1
- data/README.md +48 -22
- data/exe/bootsnap +1 -1
- data/ext/bootsnap/bootsnap.c +347 -145
- data/ext/bootsnap/extconf.rb +29 -15
- data/lib/bootsnap/bundler.rb +2 -1
- data/lib/bootsnap/cli/worker_pool.rb +6 -1
- data/lib/bootsnap/cli.rb +90 -53
- data/lib/bootsnap/compile_cache/iseq.rb +52 -16
- data/lib/bootsnap/compile_cache/json.rb +89 -0
- data/lib/bootsnap/compile_cache/yaml.rb +285 -60
- data/lib/bootsnap/compile_cache.rb +26 -17
- data/lib/bootsnap/explicit_require.rb +4 -3
- data/lib/bootsnap/load_path_cache/cache.rb +71 -35
- data/lib/bootsnap/load_path_cache/change_observer.rb +23 -2
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +26 -94
- data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +1 -0
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +36 -25
- data/lib/bootsnap/load_path_cache/path.rb +40 -18
- data/lib/bootsnap/load_path_cache/path_scanner.rb +25 -7
- data/lib/bootsnap/load_path_cache/store.rb +64 -24
- data/lib/bootsnap/load_path_cache.rb +40 -38
- data/lib/bootsnap/setup.rb +2 -36
- data/lib/bootsnap/version.rb +2 -1
- data/lib/bootsnap.rb +139 -36
- metadata +8 -79
- data/lib/bootsnap/load_path_cache/core_ext/active_support.rb +0 -107
- data/lib/bootsnap/load_path_cache/realpath_cache.rb +0 -32
@@ -1,21 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
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
|
+
@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)
|
@@ -33,10 +37,10 @@ module Bootsnap
|
|
33
37
|
requirables = []
|
34
38
|
walk(path, nil) do |relative_path, absolute_path, is_directory|
|
35
39
|
if is_directory
|
36
|
-
dirs << relative_path
|
40
|
+
dirs << os_path(relative_path)
|
37
41
|
!contains_bundle_path || !absolute_path.start_with?(BUNDLE_PATH)
|
38
42
|
elsif relative_path.end_with?(*REQUIRABLE_EXTENSIONS)
|
39
|
-
requirables << relative_path
|
43
|
+
requirables << os_path(relative_path)
|
40
44
|
end
|
41
45
|
end
|
42
46
|
[requirables, dirs]
|
@@ -44,11 +48,14 @@ module Bootsnap
|
|
44
48
|
|
45
49
|
def walk(absolute_dir_path, relative_dir_path, &block)
|
46
50
|
Dir.foreach(absolute_dir_path) do |name|
|
47
|
-
next if name.start_with?(
|
48
|
-
|
51
|
+
next if name.start_with?(".")
|
52
|
+
|
53
|
+
relative_path = relative_dir_path ? File.join(relative_dir_path, name) : name
|
49
54
|
|
50
55
|
absolute_path = "#{absolute_dir_path}/#{name}"
|
51
56
|
if File.directory?(absolute_path)
|
57
|
+
next if ignored_directories.include?(name) || ignored_directories.include?(absolute_path)
|
58
|
+
|
52
59
|
if yield relative_path, absolute_path, true
|
53
60
|
walk(absolute_path, relative_path, &block)
|
54
61
|
end
|
@@ -57,6 +64,17 @@ module Bootsnap
|
|
57
64
|
end
|
58
65
|
end
|
59
66
|
end
|
67
|
+
|
68
|
+
if RUBY_VERSION >= "3.1"
|
69
|
+
def os_path(path)
|
70
|
+
path.freeze
|
71
|
+
end
|
72
|
+
else
|
73
|
+
def os_path(path)
|
74
|
+
path.force_encoding(Encoding::US_ASCII) if path.ascii_only?
|
75
|
+
path.freeze
|
76
|
+
end
|
77
|
+
end
|
60
78
|
end
|
61
79
|
end
|
62
80
|
end
|
@@ -1,20 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require_relative('../explicit_require')
|
3
2
|
|
4
|
-
|
5
|
-
|
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
|
|
13
|
-
def initialize(store_path)
|
16
|
+
def initialize(store_path, readonly: false)
|
14
17
|
@store_path = store_path
|
15
|
-
|
16
|
-
@txn_mutex = defined?(::Mutex) ? ::Mutex.new : ::Thread::Mutex.new
|
18
|
+
@txn_mutex = Mutex.new
|
17
19
|
@dirty = false
|
20
|
+
@readonly = readonly
|
18
21
|
load_data
|
19
22
|
end
|
20
23
|
|
@@ -24,10 +27,11 @@ module Bootsnap
|
|
24
27
|
|
25
28
|
def fetch(key)
|
26
29
|
raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
|
30
|
+
|
27
31
|
v = get(key)
|
28
32
|
unless v
|
29
|
-
@dirty = true
|
30
33
|
v = yield
|
34
|
+
mark_for_mutation!
|
31
35
|
@data[key] = v
|
32
36
|
end
|
33
37
|
v
|
@@ -35,27 +39,32 @@ module Bootsnap
|
|
35
39
|
|
36
40
|
def set(key, value)
|
37
41
|
raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
|
42
|
+
|
38
43
|
if value != @data[key]
|
39
|
-
|
44
|
+
mark_for_mutation!
|
40
45
|
@data[key] = value
|
41
46
|
end
|
42
47
|
end
|
43
48
|
|
44
49
|
def transaction
|
45
50
|
raise(NestedTransactionError) if @txn_mutex.owned?
|
51
|
+
|
46
52
|
@txn_mutex.synchronize do
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
commit_transaction
|
51
|
-
end
|
53
|
+
yield
|
54
|
+
ensure
|
55
|
+
commit_transaction
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
55
59
|
private
|
56
60
|
|
61
|
+
def mark_for_mutation!
|
62
|
+
@dirty = true
|
63
|
+
@data = @data.dup if @data.frozen?
|
64
|
+
end
|
65
|
+
|
57
66
|
def commit_transaction
|
58
|
-
if @dirty
|
67
|
+
if @dirty && !@readonly
|
59
68
|
dump_data
|
60
69
|
@dirty = false
|
61
70
|
end
|
@@ -63,27 +72,58 @@ module Bootsnap
|
|
63
72
|
|
64
73
|
def load_data
|
65
74
|
@data = begin
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
75
|
+
data = File.open(@store_path, encoding: Encoding::BINARY) do |io|
|
76
|
+
MessagePack.load(io, freeze: true)
|
77
|
+
end
|
78
|
+
if data.is_a?(Hash) && data[VERSION_KEY] == CURRENT_VERSION
|
79
|
+
data
|
80
|
+
else
|
81
|
+
default_data
|
82
|
+
end
|
83
|
+
# handle malformed data due to upgrade incompatibility
|
84
|
+
rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
|
85
|
+
default_data
|
86
|
+
rescue ArgumentError => error
|
87
|
+
if error.message =~ /negative array size/
|
88
|
+
default_data
|
89
|
+
else
|
90
|
+
raise
|
91
|
+
end
|
72
92
|
end
|
73
93
|
end
|
74
94
|
|
75
95
|
def dump_data
|
76
96
|
# Change contents atomically so other processes can't get invalid
|
77
97
|
# caches if they read at an inopportune time.
|
78
|
-
tmp = "#{@store_path}.#{Process.pid}.#{(rand *
|
79
|
-
|
98
|
+
tmp = "#{@store_path}.#{Process.pid}.#{(rand * 100_000).to_i}.tmp"
|
99
|
+
mkdir_p(File.dirname(tmp))
|
80
100
|
exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY
|
81
101
|
# `encoding:` looks redundant wrt `binwrite`, but necessary on windows
|
82
102
|
# because binary is part of mode.
|
83
|
-
File.
|
84
|
-
|
103
|
+
File.open(tmp, mode: exclusive_write, encoding: Encoding::BINARY) do |io|
|
104
|
+
MessagePack.dump(@data, io)
|
105
|
+
end
|
106
|
+
File.rename(tmp, @store_path)
|
85
107
|
rescue Errno::EEXIST
|
86
108
|
retry
|
109
|
+
rescue SystemCallError
|
110
|
+
end
|
111
|
+
|
112
|
+
def default_data
|
113
|
+
{VERSION_KEY => CURRENT_VERSION}
|
114
|
+
end
|
115
|
+
|
116
|
+
def mkdir_p(path)
|
117
|
+
stack = []
|
118
|
+
until File.directory?(path)
|
119
|
+
stack.push path
|
120
|
+
path = File.dirname(path)
|
121
|
+
end
|
122
|
+
stack.reverse_each do |dir|
|
123
|
+
Dir.mkdir(dir)
|
124
|
+
rescue SystemCallError
|
125
|
+
raise unless File.directory?(dir)
|
126
|
+
end
|
87
127
|
end
|
88
128
|
end
|
89
129
|
end
|
@@ -2,20 +2,14 @@
|
|
2
2
|
|
3
3
|
module Bootsnap
|
4
4
|
module LoadPathCache
|
5
|
-
|
6
|
-
FallbackScan = Class.new(StandardError)
|
5
|
+
FALLBACK_SCAN = BasicObject.new
|
7
6
|
|
8
|
-
DOT_RB =
|
9
|
-
DOT_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(
|
12
|
+
.values_at("DLEXT", "DLEXT2")
|
19
13
|
.reject { |ext| !ext || ext.empty? }
|
20
14
|
.map { |ext| ".#{ext}" }
|
21
15
|
.freeze
|
@@ -27,52 +21,60 @@ module Bootsnap
|
|
27
21
|
|
28
22
|
CACHED_EXTENSIONS = DLEXT2 ? [DOT_RB, DLEXT, DLEXT2] : [DOT_RB, DLEXT]
|
29
23
|
|
24
|
+
@enabled = false
|
25
|
+
|
30
26
|
class << self
|
31
|
-
attr_reader(:load_path_cache, :
|
32
|
-
|
27
|
+
attr_reader(:load_path_cache, :loaded_features_index, :enabled)
|
28
|
+
alias_method :enabled?, :enabled
|
29
|
+
remove_method(:enabled)
|
33
30
|
|
34
|
-
def setup(cache_path:, development_mode:,
|
31
|
+
def setup(cache_path:, development_mode:, ignore_directories:, readonly: false)
|
35
32
|
unless supported?
|
36
33
|
warn("[bootsnap/setup] Load path caching is not supported on this implementation of Ruby") if $VERBOSE
|
37
34
|
return
|
38
35
|
end
|
39
36
|
|
40
|
-
store = Store.new(cache_path)
|
37
|
+
store = Store.new(cache_path, readonly: readonly)
|
41
38
|
|
42
39
|
@loaded_features_index = LoadedFeaturesIndex.new
|
43
|
-
@realpath_cache = RealpathCache.new
|
44
40
|
|
41
|
+
PathScanner.ignored_directories = ignore_directories if ignore_directories
|
45
42
|
@load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
|
46
|
-
|
47
|
-
require_relative
|
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
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
::ActiveSupport::Dependencies.autoload_paths,
|
56
|
-
development_mode: development_mode
|
57
|
-
)
|
58
|
-
require_relative('load_path_cache/core_ext/active_support')
|
59
|
-
end
|
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?
|
60
54
|
end
|
61
55
|
|
62
56
|
def supported?
|
63
|
-
|
64
|
-
|
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
|
65
68
|
end
|
66
69
|
end
|
67
70
|
end
|
68
71
|
end
|
69
72
|
|
70
73
|
if Bootsnap::LoadPathCache.supported?
|
71
|
-
require_relative
|
72
|
-
require_relative
|
73
|
-
require_relative
|
74
|
-
require_relative
|
75
|
-
require_relative
|
76
|
-
require_relative
|
77
|
-
require_relative('load_path_cache/realpath_cache')
|
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"
|
78
80
|
end
|
data/lib/bootsnap/setup.rb
CHANGED
@@ -1,39 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require_relative('../bootsnap')
|
3
2
|
|
4
|
-
|
5
|
-
development_mode = ['', nil, 'development'].include?(env)
|
3
|
+
require_relative "../bootsnap"
|
6
4
|
|
7
|
-
|
8
|
-
unless cache_dir
|
9
|
-
config_dir_frame = caller.detect do |line|
|
10
|
-
line.include?('/config/')
|
11
|
-
end
|
12
|
-
|
13
|
-
unless config_dir_frame
|
14
|
-
$stderr.puts("[bootsnap/setup] couldn't infer cache directory! Either:")
|
15
|
-
$stderr.puts("[bootsnap/setup] 1. require bootsnap/setup from your application's config directory; or")
|
16
|
-
$stderr.puts("[bootsnap/setup] 2. Define the environment variable BOOTSNAP_CACHE_DIR")
|
17
|
-
|
18
|
-
raise("couldn't infer bootsnap cache directory")
|
19
|
-
end
|
20
|
-
|
21
|
-
path = config_dir_frame.split(/:\d+:/).first
|
22
|
-
path = File.dirname(path) until File.basename(path) == 'config'
|
23
|
-
app_root = File.dirname(path)
|
24
|
-
|
25
|
-
cache_dir = File.join(app_root, 'tmp', 'cache')
|
26
|
-
end
|
27
|
-
|
28
|
-
ruby_version = Gem::Version.new(RUBY_VERSION)
|
29
|
-
iseq_cache_enabled = ruby_version < Gem::Version.new('2.5.0') || ruby_version >= Gem::Version.new('2.6.0')
|
30
|
-
|
31
|
-
Bootsnap.setup(
|
32
|
-
cache_dir: cache_dir,
|
33
|
-
development_mode: development_mode,
|
34
|
-
load_path_cache: true,
|
35
|
-
autoload_paths_cache: true, # assume rails. open to PRs to impl. detection
|
36
|
-
disable_trace: false,
|
37
|
-
compile_cache_iseq: iseq_cache_enabled,
|
38
|
-
compile_cache_yaml: true,
|
39
|
-
)
|
5
|
+
Bootsnap.default_setup
|
data/lib/bootsnap/version.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
@@ -1,49 +1,152 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
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)
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
11
|
+
class << self
|
12
|
+
attr_reader :logger
|
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
|
+
|
24
|
+
def log!
|
25
|
+
self.logger = $stderr.method(:puts)
|
26
|
+
end
|
27
|
+
|
28
|
+
def logger=(logger)
|
29
|
+
@logger = logger
|
30
|
+
self.instrumentation = if logger.respond_to?(:debug)
|
31
|
+
->(event, path) { @logger.debug("[Bootsnap] #{event} #{path}") unless event == :hit }
|
32
|
+
else
|
33
|
+
->(event, path) { @logger.call("[Bootsnap] #{event} #{path}") unless event == :hit }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def instrumentation=(callback)
|
38
|
+
@instrumentation = callback
|
39
|
+
if respond_to?(:instrumentation_enabled=, true)
|
40
|
+
self.instrumentation_enabled = !!callback
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def _instrument(event, path)
|
45
|
+
@instrumentation.call(event, path)
|
46
|
+
end
|
47
|
+
|
48
|
+
def setup(
|
49
|
+
cache_dir:,
|
50
|
+
development_mode: true,
|
51
|
+
load_path_cache: true,
|
52
|
+
ignore_directories: nil,
|
53
|
+
readonly: false,
|
54
|
+
revalidation: false,
|
55
|
+
compile_cache_iseq: true,
|
56
|
+
compile_cache_yaml: true,
|
57
|
+
compile_cache_json: true
|
36
58
|
)
|
37
|
-
|
59
|
+
if load_path_cache
|
60
|
+
Bootsnap::LoadPathCache.setup(
|
61
|
+
cache_path: "#{cache_dir}/bootsnap/load-path-cache",
|
62
|
+
development_mode: development_mode,
|
63
|
+
ignore_directories: ignore_directories,
|
64
|
+
readonly: readonly,
|
65
|
+
)
|
66
|
+
end
|
38
67
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
68
|
+
Bootsnap::CompileCache.setup(
|
69
|
+
cache_dir: "#{cache_dir}/bootsnap/compile-cache",
|
70
|
+
iseq: compile_cache_iseq,
|
71
|
+
yaml: compile_cache_yaml,
|
72
|
+
json: compile_cache_json,
|
73
|
+
readonly: readonly,
|
74
|
+
revalidation: revalidation,
|
44
75
|
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def unload_cache!
|
79
|
+
LoadPathCache.unload!
|
80
|
+
end
|
81
|
+
|
82
|
+
def default_setup
|
83
|
+
env = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || ENV["ENV"]
|
84
|
+
development_mode = ["", nil, "development"].include?(env)
|
85
|
+
|
86
|
+
unless ENV["DISABLE_BOOTSNAP"]
|
87
|
+
cache_dir = ENV["BOOTSNAP_CACHE_DIR"]
|
88
|
+
unless cache_dir
|
89
|
+
config_dir_frame = caller.detect do |line|
|
90
|
+
line.include?("/config/")
|
91
|
+
end
|
92
|
+
|
93
|
+
unless config_dir_frame
|
94
|
+
$stderr.puts("[bootsnap/setup] couldn't infer cache directory! Either:")
|
95
|
+
$stderr.puts("[bootsnap/setup] 1. require bootsnap/setup from your application's config directory; or")
|
96
|
+
$stderr.puts("[bootsnap/setup] 2. Define the environment variable BOOTSNAP_CACHE_DIR")
|
97
|
+
|
98
|
+
raise("couldn't infer bootsnap cache directory")
|
99
|
+
end
|
100
|
+
|
101
|
+
path = config_dir_frame.split(/:\d+:/).first
|
102
|
+
path = File.dirname(path) until File.basename(path) == "config"
|
103
|
+
app_root = File.dirname(path)
|
104
|
+
|
105
|
+
cache_dir = File.join(app_root, "tmp", "cache")
|
106
|
+
end
|
107
|
+
|
108
|
+
ignore_directories = if ENV.key?("BOOTSNAP_IGNORE_DIRECTORIES")
|
109
|
+
ENV["BOOTSNAP_IGNORE_DIRECTORIES"].split(",")
|
110
|
+
end
|
111
|
+
|
112
|
+
setup(
|
113
|
+
cache_dir: cache_dir,
|
114
|
+
development_mode: development_mode,
|
115
|
+
load_path_cache: !ENV["DISABLE_BOOTSNAP_LOAD_PATH_CACHE"],
|
116
|
+
compile_cache_iseq: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
|
117
|
+
compile_cache_yaml: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
|
118
|
+
compile_cache_json: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
|
119
|
+
readonly: !!ENV["BOOTSNAP_READONLY"],
|
120
|
+
ignore_directories: ignore_directories,
|
121
|
+
)
|
122
|
+
|
123
|
+
if ENV["BOOTSNAP_LOG"]
|
124
|
+
log!
|
125
|
+
elsif ENV["BOOTSNAP_STATS"]
|
126
|
+
log_stats!
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
if RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
|
132
|
+
def absolute_path?(path)
|
133
|
+
path[1] == ":"
|
134
|
+
end
|
45
135
|
else
|
46
|
-
|
136
|
+
def absolute_path?(path)
|
137
|
+
path.start_with?("/")
|
138
|
+
end
|
47
139
|
end
|
140
|
+
|
141
|
+
# This is a semi-accurate ruby implementation of the native `rb_get_path(VALUE)` function.
|
142
|
+
# The native version is very intricate and may behave differently on windows etc.
|
143
|
+
# But we only use it for non-MRI platform.
|
144
|
+
def rb_get_path(fname)
|
145
|
+
path_path = fname.respond_to?(:to_path) ? fname.to_path : fname
|
146
|
+
String.try_convert(path_path) || raise(TypeError, "no implicit conversion of #{path_path.class} into String")
|
147
|
+
end
|
148
|
+
|
149
|
+
# Allow the C extension to redefine `rb_get_path` without warning.
|
150
|
+
alias_method :rb_get_path, :rb_get_path # rubocop:disable Lint/DuplicateMethods
|
48
151
|
end
|
49
152
|
end
|