bootsnap 0.2.15 → 1.0.0
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 +20 -0
- data/README.md +35 -27
- data/ext/bootsnap/bootsnap.c +546 -394
- data/ext/bootsnap/bootsnap.h +1 -3
- data/lib/bootsnap/compile_cache/iseq.rb +13 -1
- data/lib/bootsnap/compile_cache/yaml.rb +2 -1
- data/lib/bootsnap/compile_cache.rb +3 -3
- data/lib/bootsnap/load_path_cache/cache.rb +14 -3
- data/lib/bootsnap/load_path_cache/path.rb +19 -11
- data/lib/bootsnap/load_path_cache/path_scanner.rb +0 -3
- data/lib/bootsnap/load_path_cache/store.rb +1 -1
- data/lib/bootsnap/version.rb +1 -1
- data/lib/bootsnap.rb +1 -0
- metadata +2 -2
data/ext/bootsnap/bootsnap.h
CHANGED
|
@@ -4,10 +4,20 @@ require 'zlib'
|
|
|
4
4
|
module Bootsnap
|
|
5
5
|
module CompileCache
|
|
6
6
|
module ISeq
|
|
7
|
+
class << self
|
|
8
|
+
attr_accessor :cache_dir
|
|
9
|
+
end
|
|
10
|
+
|
|
7
11
|
def self.input_to_storage(_, path)
|
|
8
12
|
RubyVM::InstructionSequence.compile_file(path).to_binary
|
|
9
13
|
rescue SyntaxError
|
|
10
14
|
raise Uncompilable, 'syntax error'
|
|
15
|
+
rescue RuntimeError => e
|
|
16
|
+
if e.message == 'should not compile with coverage'
|
|
17
|
+
raise Uncompilable, 'coverage is enabled'
|
|
18
|
+
else
|
|
19
|
+
raise
|
|
20
|
+
end
|
|
11
21
|
end
|
|
12
22
|
|
|
13
23
|
def self.storage_to_output(binary)
|
|
@@ -28,6 +38,7 @@ module Bootsnap
|
|
|
28
38
|
module InstructionSequenceMixin
|
|
29
39
|
def load_iseq(path)
|
|
30
40
|
Bootsnap::CompileCache::Native.fetch(
|
|
41
|
+
Bootsnap::CompileCache::ISeq.cache_dir,
|
|
31
42
|
path.to_s,
|
|
32
43
|
Bootsnap::CompileCache::ISeq
|
|
33
44
|
)
|
|
@@ -62,7 +73,8 @@ module Bootsnap
|
|
|
62
73
|
Bootsnap::CompileCache::Native.compile_option_crc32 = crc
|
|
63
74
|
end
|
|
64
75
|
|
|
65
|
-
def self.install!
|
|
76
|
+
def self.install!(cache_dir)
|
|
77
|
+
Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
|
|
66
78
|
Bootsnap::CompileCache::ISeq.compile_option_updated
|
|
67
79
|
class << RubyVM::InstructionSequence
|
|
68
80
|
prepend InstructionSequenceMixin
|
|
@@ -30,7 +30,7 @@ module Bootsnap
|
|
|
30
30
|
::YAML.load(data)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def self.install!
|
|
33
|
+
def self.install!(cache_dir)
|
|
34
34
|
require 'yaml'
|
|
35
35
|
require 'msgpack'
|
|
36
36
|
|
|
@@ -44,6 +44,7 @@ module Bootsnap
|
|
|
44
44
|
klass = class << ::YAML; self; end
|
|
45
45
|
klass.send(:define_method, :load_file) do |path|
|
|
46
46
|
Bootsnap::CompileCache::Native.fetch(
|
|
47
|
+
cache_dir,
|
|
47
48
|
path.to_s,
|
|
48
49
|
Bootsnap::CompileCache::YAML
|
|
49
50
|
)
|
|
@@ -3,13 +3,13 @@ require_relative 'compile_cache/yaml'
|
|
|
3
3
|
|
|
4
4
|
module Bootsnap
|
|
5
5
|
module CompileCache
|
|
6
|
-
def self.setup(iseq:, yaml:)
|
|
6
|
+
def self.setup(cache_dir:, iseq:, yaml:)
|
|
7
7
|
if iseq
|
|
8
|
-
Bootsnap::CompileCache::ISeq.install!
|
|
8
|
+
Bootsnap::CompileCache::ISeq.install!(cache_dir)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
if yaml
|
|
12
|
-
Bootsnap::CompileCache::YAML.install!
|
|
12
|
+
Bootsnap::CompileCache::YAML.install!(cache_dir)
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -46,7 +46,7 @@ module Bootsnap
|
|
|
46
46
|
# Try to resolve this feature to an absolute path without traversing the
|
|
47
47
|
# loadpath.
|
|
48
48
|
def find(feature)
|
|
49
|
-
reinitialize if stale?
|
|
49
|
+
reinitialize if (@has_relative_paths && dir_changed?) || stale?
|
|
50
50
|
feature = feature.to_s
|
|
51
51
|
return feature if feature.start_with?(SLASH)
|
|
52
52
|
return File.expand_path(feature) if feature.start_with?('./')
|
|
@@ -116,15 +116,26 @@ module Bootsnap
|
|
|
116
116
|
|
|
117
117
|
private
|
|
118
118
|
|
|
119
|
+
def dir_changed?
|
|
120
|
+
@prev_dir ||= Dir.pwd
|
|
121
|
+
if @prev_dir == Dir.pwd
|
|
122
|
+
false
|
|
123
|
+
else
|
|
124
|
+
@prev_dir = Dir.pwd
|
|
125
|
+
true
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
119
129
|
def push_paths_locked(*paths)
|
|
120
130
|
@store.transaction do
|
|
121
131
|
paths.map(&:to_s).each do |path|
|
|
122
132
|
p = Path.new(path)
|
|
133
|
+
@has_relative_paths = true if p.relative?
|
|
123
134
|
next if p.non_directory?
|
|
124
135
|
entries, dirs = p.entries_and_dirs(@store)
|
|
125
136
|
# push -> low precedence -> set only if unset
|
|
126
137
|
dirs.each { |dir| @dirs[dir] ||= true }
|
|
127
|
-
entries.each { |rel| @index[rel] ||=
|
|
138
|
+
entries.each { |rel| @index[rel] ||= p.expanded_path }
|
|
128
139
|
end
|
|
129
140
|
end
|
|
130
141
|
end
|
|
@@ -137,7 +148,7 @@ module Bootsnap
|
|
|
137
148
|
entries, dirs = p.entries_and_dirs(@store)
|
|
138
149
|
# unshift -> high precedence -> unconditional set
|
|
139
150
|
dirs.each { |dir| @dirs[dir] = true }
|
|
140
|
-
entries.each { |rel| @index[rel] =
|
|
151
|
+
entries.each { |rel| @index[rel] = p.expanded_path }
|
|
141
152
|
end
|
|
142
153
|
end
|
|
143
154
|
end
|
|
@@ -30,34 +30,42 @@ module Bootsnap
|
|
|
30
30
|
false
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
def relative?
|
|
34
|
+
!path.start_with?(SLASH)
|
|
35
|
+
end
|
|
36
|
+
|
|
33
37
|
# Return a list of all the requirable files and all of the subdirectories
|
|
34
38
|
# of this +Path+.
|
|
35
39
|
def entries_and_dirs(store)
|
|
36
40
|
if stable?
|
|
37
41
|
# the cached_mtime field is unused for 'stable' paths, but is
|
|
38
42
|
# set to zero anyway, just in case we change the stability heuristics.
|
|
39
|
-
_, entries, dirs = store.get(
|
|
43
|
+
_, entries, dirs = store.get(expanded_path)
|
|
40
44
|
return [entries, dirs] if entries # cache hit
|
|
41
45
|
entries, dirs = scan!
|
|
42
|
-
store.set(
|
|
46
|
+
store.set(expanded_path, [0, entries, dirs])
|
|
43
47
|
return [entries, dirs]
|
|
44
48
|
end
|
|
45
49
|
|
|
46
|
-
cached_mtime, entries, dirs = store.get(
|
|
50
|
+
cached_mtime, entries, dirs = store.get(expanded_path)
|
|
47
51
|
|
|
48
|
-
current_mtime = latest_mtime(
|
|
52
|
+
current_mtime = latest_mtime(expanded_path, dirs || [])
|
|
49
53
|
return [[], []] if current_mtime == -1 # path does not exist
|
|
50
54
|
return [entries, dirs] if cached_mtime == current_mtime
|
|
51
55
|
|
|
52
56
|
entries, dirs = scan!
|
|
53
|
-
store.set(
|
|
57
|
+
store.set(expanded_path, [current_mtime, entries, dirs])
|
|
54
58
|
[entries, dirs]
|
|
55
59
|
end
|
|
56
60
|
|
|
61
|
+
def expanded_path
|
|
62
|
+
File.expand_path(path)
|
|
63
|
+
end
|
|
64
|
+
|
|
57
65
|
private
|
|
58
66
|
|
|
59
67
|
def scan! # (expensive) returns [entries, dirs]
|
|
60
|
-
PathScanner.call(
|
|
68
|
+
PathScanner.call(expanded_path)
|
|
61
69
|
end
|
|
62
70
|
|
|
63
71
|
# last time a directory was modified in this subtree. +dirs+ should be a
|
|
@@ -83,15 +91,15 @@ module Bootsnap
|
|
|
83
91
|
VOLATILE = :volatile
|
|
84
92
|
|
|
85
93
|
# Built-in ruby lib stuff doesn't change, but things can occasionally be
|
|
86
|
-
# installed into sitedir, which
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
# installed into sitedir, which generally lives under libdir.
|
|
95
|
+
RUBY_LIBDIR = RbConfig::CONFIG['libdir']
|
|
96
|
+
RUBY_SITEDIR = RbConfig::CONFIG['sitedir']
|
|
89
97
|
|
|
90
98
|
def stability
|
|
91
99
|
@stability ||= begin
|
|
92
|
-
if Gem.path.detect { |p|
|
|
100
|
+
if Gem.path.detect { |p| expanded_path.start_with?(p.to_s) }
|
|
93
101
|
STABLE
|
|
94
|
-
elsif
|
|
102
|
+
elsif expanded_path.start_with?(RUBY_LIBDIR) && !expanded_path.start_with?(RUBY_SITEDIR)
|
|
95
103
|
STABLE
|
|
96
104
|
else
|
|
97
105
|
VOLATILE
|
|
@@ -3,8 +3,6 @@ require_relative '../load_path_cache'
|
|
|
3
3
|
module Bootsnap
|
|
4
4
|
module LoadPathCache
|
|
5
5
|
module PathScanner
|
|
6
|
-
RelativePathNotSupported = Class.new(StandardError)
|
|
7
|
-
|
|
8
6
|
REQUIRABLES_AND_DIRS = "/**/*{#{DOT_RB},#{DL_EXTENSIONS.join(',')},/}"
|
|
9
7
|
IS_DIR = %r{(.*)/\z}
|
|
10
8
|
NORMALIZE_NATIVE_EXTENSIONS = !DL_EXTENSIONS.include?(LoadPathCache::DOT_SO)
|
|
@@ -13,7 +11,6 @@ module Bootsnap
|
|
|
13
11
|
|
|
14
12
|
def self.call(path)
|
|
15
13
|
path = path.to_s
|
|
16
|
-
raise RelativePathNotSupported unless path.start_with?(SLASH)
|
|
17
14
|
|
|
18
15
|
relative_slice = (path.size + 1)..-1
|
|
19
16
|
# If the bundle path is a descendent of this path, we do additional
|
|
@@ -59,7 +59,7 @@ module Bootsnap
|
|
|
59
59
|
@data = begin
|
|
60
60
|
MessagePack.load(File.binread(@store_path))
|
|
61
61
|
# handle malformed data due to upgrade incompatability
|
|
62
|
-
rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError
|
|
62
|
+
rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
|
|
63
63
|
{}
|
|
64
64
|
end
|
|
65
65
|
end
|
data/lib/bootsnap/version.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
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: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Burke Libbey
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-
|
|
11
|
+
date: 2017-06-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|