bootsnap 1.9.4 → 1.10.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 +16 -0
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/exe/bootsnap +1 -1
- data/ext/bootsnap/bootsnap.c +32 -34
- data/ext/bootsnap/extconf.rb +13 -11
- data/lib/bootsnap/bundler.rb +1 -0
- data/lib/bootsnap/cli/worker_pool.rb +1 -0
- data/lib/bootsnap/cli.rb +49 -49
- data/lib/bootsnap/compile_cache/iseq.rb +16 -11
- data/lib/bootsnap/compile_cache/json.rb +15 -8
- data/lib/bootsnap/compile_cache/yaml.rb +216 -78
- data/lib/bootsnap/compile_cache.rb +10 -7
- data/lib/bootsnap/explicit_require.rb +4 -3
- data/lib/bootsnap/load_path_cache/cache.rb +42 -30
- data/lib/bootsnap/load_path_cache/change_observer.rb +2 -0
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +30 -21
- data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +1 -0
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +31 -33
- data/lib/bootsnap/load_path_cache/path.rb +5 -3
- data/lib/bootsnap/load_path_cache/path_scanner.rb +6 -5
- data/lib/bootsnap/load_path_cache/realpath_cache.rb +1 -0
- data/lib/bootsnap/load_path_cache/store.rb +12 -7
- data/lib/bootsnap/load_path_cache.rb +15 -15
- data/lib/bootsnap/setup.rb +2 -1
- data/lib/bootsnap/version.rb +2 -1
- data/lib/bootsnap.rb +32 -31
- metadata +5 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96a4b41c02dc01b416bd262f43812b9541479330e4b073d428a6f0186fe07f9a
|
4
|
+
data.tar.gz: b221e0b0ce1da0552a7c08e1dd1ce84daab07129b834fd2bdec82f01a8645c50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27c071b0a4efceb864931a673f7889fc95110f1ed8de4b50c17c99ecd4d62230321d14a23f346129f1f2198dc6a3222370e5bf8f105f52299799ba78aa361741
|
7
|
+
data.tar.gz: d5546dd05eaf860178526dc3bdcd33546f80cdcc5ebdb748ebf0b1fe8b813efed15387ea5835f4ab846775261d6df05e4d15df28ff81abb04ab795232435a194
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.10.0
|
4
|
+
|
5
|
+
* Delay requiring `FileUtils`. (#285)
|
6
|
+
`FileUtils` can be installed as a gem, so it's best to wait for bundler to have setup the load path before requiring it.
|
7
|
+
|
8
|
+
* Improve support of Psych 4. (#392)
|
9
|
+
Since `1.8.0`, `YAML.load_file` was no longer cached when Psych 4 was used. This is because `load_file` loads
|
10
|
+
in safe mode by default, so the Bootsnap cache could defeat that safety.
|
11
|
+
Now when precompiling YAML files, Bootsnap first try to parse them in safe mode, and if it can't fallback to unsafe mode,
|
12
|
+
and the cache contains a flag that records wether it was generated in safe mode or not.
|
13
|
+
`YAML.unsafe_load_file` will use safe caches just fine, but `YAML.load_file` will fallback to uncached YAML parsing
|
14
|
+
if the cache was generated using unsafe parsing.
|
15
|
+
|
16
|
+
* Minimize the Kernel.require extra stack frames. (#393)
|
17
|
+
This should reduce the noise generated by bootsnap on `LoadError`.
|
18
|
+
|
3
19
|
# 1.9.4
|
4
20
|
|
5
21
|
* Ignore absolute paths in the loaded feature index. (#385)
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -41,7 +41,7 @@ getting progressively slower, this is almost certainly the cause.**
|
|
41
41
|
It's technically possible to simply specify `gem 'bootsnap', require: 'bootsnap/setup'`, but it's
|
42
42
|
important to load Bootsnap as early as possible to get maximum performance improvement.
|
43
43
|
|
44
|
-
You can see how this require works [here](https://github.com/Shopify/bootsnap/blob/
|
44
|
+
You can see how this require works [here](https://github.com/Shopify/bootsnap/blob/main/lib/bootsnap/setup.rb).
|
45
45
|
|
46
46
|
If you are not using Rails, or if you are but want more control over things, add this to your
|
47
47
|
application setup immediately after `require 'bundler/setup'` (i.e. as early as possible: the sooner
|
@@ -161,7 +161,7 @@ The only directories considered "stable" are things under the Ruby install prefi
|
|
161
161
|
"volatile".
|
162
162
|
|
163
163
|
In addition to the [`Bootsnap::LoadPathCache::Cache`
|
164
|
-
source](https://github.com/Shopify/bootsnap/blob/
|
164
|
+
source](https://github.com/Shopify/bootsnap/blob/main/lib/bootsnap/load_path_cache/cache.rb),
|
165
165
|
this diagram may help clarify how entry resolution works:
|
166
166
|
|
167
167
|

|
data/exe/bootsnap
CHANGED
data/ext/bootsnap/bootsnap.c
CHANGED
@@ -75,7 +75,7 @@ struct bs_cache_key {
|
|
75
75
|
STATIC_ASSERT(sizeof(struct bs_cache_key) == KEY_SIZE);
|
76
76
|
|
77
77
|
/* Effectively a schema version. Bumping invalidates all previous caches */
|
78
|
-
static const uint32_t current_version =
|
78
|
+
static const uint32_t current_version = 4;
|
79
79
|
|
80
80
|
/* hash of e.g. "x86_64-darwin17", invalidating when ruby is recompiled on a
|
81
81
|
* new OS ABI, etc. */
|
@@ -91,8 +91,7 @@ static mode_t current_umask;
|
|
91
91
|
static VALUE rb_mBootsnap;
|
92
92
|
static VALUE rb_mBootsnap_CompileCache;
|
93
93
|
static VALUE rb_mBootsnap_CompileCache_Native;
|
94
|
-
static VALUE
|
95
|
-
static ID uncompilable;
|
94
|
+
static VALUE rb_cBootsnap_CompileCache_UNCOMPILABLE;
|
96
95
|
static ID instrumentation_method;
|
97
96
|
static VALUE sym_miss;
|
98
97
|
static VALUE sym_stale;
|
@@ -120,10 +119,8 @@ static uint32_t get_ruby_platform(void);
|
|
120
119
|
* exception.
|
121
120
|
*/
|
122
121
|
static int bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * output_data);
|
123
|
-
static VALUE prot_storage_to_output(VALUE arg);
|
124
122
|
static VALUE prot_input_to_output(VALUE arg);
|
125
123
|
static void bs_input_to_output(VALUE handler, VALUE args, VALUE input_data, VALUE * output_data, int * exception_tag);
|
126
|
-
static VALUE prot_input_to_storage(VALUE arg);
|
127
124
|
static int bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data);
|
128
125
|
struct s2o_data;
|
129
126
|
struct i2o_data;
|
@@ -151,12 +148,12 @@ Init_bootsnap(void)
|
|
151
148
|
rb_mBootsnap = rb_define_module("Bootsnap");
|
152
149
|
rb_mBootsnap_CompileCache = rb_define_module_under(rb_mBootsnap, "CompileCache");
|
153
150
|
rb_mBootsnap_CompileCache_Native = rb_define_module_under(rb_mBootsnap_CompileCache, "Native");
|
154
|
-
|
151
|
+
rb_cBootsnap_CompileCache_UNCOMPILABLE = rb_const_get(rb_mBootsnap_CompileCache, rb_intern("UNCOMPILABLE"));
|
152
|
+
rb_global_variable(&rb_cBootsnap_CompileCache_UNCOMPILABLE);
|
155
153
|
|
156
154
|
current_ruby_revision = get_ruby_revision();
|
157
155
|
current_ruby_platform = get_ruby_platform();
|
158
156
|
|
159
|
-
uncompilable = rb_intern("__bootsnap_uncompilable__");
|
160
157
|
instrumentation_method = rb_intern("_instrument");
|
161
158
|
|
162
159
|
sym_miss = ID2SYM(rb_intern("miss"));
|
@@ -426,6 +423,7 @@ open_current_file(char * path, struct bs_cache_key * key, const char ** errno_pr
|
|
426
423
|
#define ERROR_WITH_ERRNO -1
|
427
424
|
#define CACHE_MISS -2
|
428
425
|
#define CACHE_STALE -3
|
426
|
+
#define CACHE_UNCOMPILABLE -4
|
429
427
|
|
430
428
|
/*
|
431
429
|
* Read the cache key from the given fd, which must have position 0 (e.g.
|
@@ -507,14 +505,14 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE *
|
|
507
505
|
if (data_size > 100000000000) {
|
508
506
|
*errno_provenance = "bs_fetch:fetch_cached_data:datasize";
|
509
507
|
errno = EINVAL; /* because wtf? */
|
510
|
-
ret =
|
508
|
+
ret = ERROR_WITH_ERRNO;
|
511
509
|
goto done;
|
512
510
|
}
|
513
511
|
data = ALLOC_N(char, data_size);
|
514
512
|
nread = read(fd, data, data_size);
|
515
513
|
if (nread < 0) {
|
516
514
|
*errno_provenance = "bs_fetch:fetch_cached_data:read";
|
517
|
-
ret =
|
515
|
+
ret = ERROR_WITH_ERRNO;
|
518
516
|
goto done;
|
519
517
|
}
|
520
518
|
if (nread != data_size) {
|
@@ -525,6 +523,10 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE *
|
|
525
523
|
storage_data = rb_str_new(data, data_size);
|
526
524
|
|
527
525
|
*exception_tag = bs_storage_to_output(handler, args, storage_data, output_data);
|
526
|
+
if (*output_data == rb_cBootsnap_CompileCache_UNCOMPILABLE) {
|
527
|
+
ret = CACHE_UNCOMPILABLE;
|
528
|
+
goto done;
|
529
|
+
}
|
528
530
|
ret = 0;
|
529
531
|
done:
|
530
532
|
if (data != NULL) xfree(data);
|
@@ -737,7 +739,15 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
737
739
|
&output_data, &exception_tag, &errno_provenance
|
738
740
|
);
|
739
741
|
if (exception_tag != 0) goto raise;
|
740
|
-
else if (res ==
|
742
|
+
else if (res == CACHE_UNCOMPILABLE) {
|
743
|
+
/* If fetch_cached_data returned `Uncompilable` we fallback to `input_to_output`
|
744
|
+
This happens if we have say, an unsafe YAML cache, but try to load it in safe mode */
|
745
|
+
if (bs_read_contents(current_fd, current_key.size, &contents, &errno_provenance) < 0) goto fail_errno;
|
746
|
+
input_data = rb_str_new(contents, current_key.size);
|
747
|
+
bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
|
748
|
+
if (exception_tag != 0) goto raise;
|
749
|
+
goto succeed;
|
750
|
+
} else if (res == CACHE_MISS || res == CACHE_STALE) valid_cache = 0;
|
741
751
|
else if (res == ERROR_WITH_ERRNO) goto fail_errno;
|
742
752
|
else if (!NIL_P(output_data)) goto succeed; /* fast-path, goal */
|
743
753
|
}
|
@@ -754,7 +764,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
754
764
|
if (exception_tag != 0) goto raise;
|
755
765
|
/* If input_to_storage raised Bootsnap::CompileCache::Uncompilable, don't try
|
756
766
|
* to cache anything; just return input_to_output(input_data) */
|
757
|
-
if (storage_data ==
|
767
|
+
if (storage_data == rb_cBootsnap_CompileCache_UNCOMPILABLE) {
|
758
768
|
bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
|
759
769
|
if (exception_tag != 0) goto raise;
|
760
770
|
goto succeed;
|
@@ -772,9 +782,13 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
772
782
|
exception_tag = bs_storage_to_output(handler, args, storage_data, &output_data);
|
773
783
|
if (exception_tag != 0) goto raise;
|
774
784
|
|
775
|
-
|
776
|
-
|
777
|
-
|
785
|
+
if (output_data == rb_cBootsnap_CompileCache_UNCOMPILABLE) {
|
786
|
+
/* If storage_to_output returned `Uncompilable` we fallback to `input_to_output` */
|
787
|
+
bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
|
788
|
+
if (exception_tag != 0) goto raise;
|
789
|
+
} else if (NIL_P(output_data)) {
|
790
|
+
/* If output_data is nil, delete the cache entry and generate the output
|
791
|
+
* using input_to_output */
|
778
792
|
if (unlink(cache_path) < 0) {
|
779
793
|
errno_provenance = "bs_fetch:unlink";
|
780
794
|
goto fail_errno;
|
@@ -856,7 +870,7 @@ bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE handler)
|
|
856
870
|
|
857
871
|
/* If input_to_storage raised Bootsnap::CompileCache::Uncompilable, don't try
|
858
872
|
* to cache anything; just return false */
|
859
|
-
if (storage_data ==
|
873
|
+
if (storage_data == rb_cBootsnap_CompileCache_UNCOMPILABLE) {
|
860
874
|
goto fail;
|
861
875
|
}
|
862
876
|
/* If storage_data isn't a string, we can't cache it */
|
@@ -919,7 +933,7 @@ struct i2s_data {
|
|
919
933
|
};
|
920
934
|
|
921
935
|
static VALUE
|
922
|
-
|
936
|
+
try_storage_to_output(VALUE arg)
|
923
937
|
{
|
924
938
|
struct s2o_data * data = (struct s2o_data *)arg;
|
925
939
|
return rb_funcall(data->handler, rb_intern("storage_to_output"), 2, data->storage_data, data->args);
|
@@ -934,7 +948,7 @@ bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * outp
|
|
934
948
|
.args = args,
|
935
949
|
.storage_data = storage_data,
|
936
950
|
};
|
937
|
-
*output_data = rb_protect(
|
951
|
+
*output_data = rb_protect(try_storage_to_output, (VALUE)&s2o_data, &state);
|
938
952
|
return state;
|
939
953
|
}
|
940
954
|
|
@@ -963,22 +977,6 @@ try_input_to_storage(VALUE arg)
|
|
963
977
|
return rb_funcall(data->handler, rb_intern("input_to_storage"), 2, data->input_data, data->pathval);
|
964
978
|
}
|
965
979
|
|
966
|
-
static VALUE
|
967
|
-
rescue_input_to_storage(VALUE arg, VALUE e)
|
968
|
-
{
|
969
|
-
return uncompilable;
|
970
|
-
}
|
971
|
-
|
972
|
-
static VALUE
|
973
|
-
prot_input_to_storage(VALUE arg)
|
974
|
-
{
|
975
|
-
struct i2s_data * data = (struct i2s_data *)arg;
|
976
|
-
return rb_rescue2(
|
977
|
-
try_input_to_storage, (VALUE)data,
|
978
|
-
rescue_input_to_storage, Qnil,
|
979
|
-
rb_eBootsnap_CompileCache_Uncompilable, 0);
|
980
|
-
}
|
981
|
-
|
982
980
|
static int
|
983
981
|
bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data)
|
984
982
|
{
|
@@ -988,6 +986,6 @@ bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval,
|
|
988
986
|
.input_data = input_data,
|
989
987
|
.pathval = pathval,
|
990
988
|
};
|
991
|
-
*storage_data = rb_protect(
|
989
|
+
*storage_data = rb_protect(try_input_to_storage, (VALUE)&i2s_data, &state);
|
992
990
|
return state;
|
993
991
|
}
|
data/ext/bootsnap/extconf.rb
CHANGED
@@ -1,21 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require("mkmf")
|
3
4
|
|
4
|
-
if RUBY_ENGINE ==
|
5
|
-
$CFLAGS <<
|
6
|
-
$CFLAGS <<
|
5
|
+
if RUBY_ENGINE == "ruby"
|
6
|
+
$CFLAGS << " -O3 "
|
7
|
+
$CFLAGS << " -std=c99"
|
7
8
|
|
8
9
|
# ruby.h has some -Wpedantic fails in some cases
|
9
10
|
# (e.g. https://github.com/Shopify/bootsnap/issues/15)
|
10
|
-
unless [
|
11
|
-
$CFLAGS <<
|
12
|
-
$CFLAGS <<
|
13
|
-
$CFLAGS <<
|
14
|
-
$CFLAGS <<
|
11
|
+
unless ["0", "", nil].include?(ENV["BOOTSNAP_PEDANTIC"])
|
12
|
+
$CFLAGS << " -Wall"
|
13
|
+
$CFLAGS << " -Werror"
|
14
|
+
$CFLAGS << " -Wextra"
|
15
|
+
$CFLAGS << " -Wpedantic"
|
15
16
|
|
16
|
-
$CFLAGS <<
|
17
|
-
$CFLAGS <<
|
18
|
-
$CFLAGS <<
|
17
|
+
$CFLAGS << " -Wno-unused-parameter" # VALUE self has to be there but we don't care what it is.
|
18
|
+
$CFLAGS << " -Wno-keyword-macro" # hiding return
|
19
|
+
$CFLAGS << " -Wno-gcc-compat" # ruby.h 2.6.0 on macos 10.14, dunno
|
20
|
+
$CFLAGS << " -Wno-compound-token-split-by-macro"
|
19
21
|
end
|
20
22
|
|
21
23
|
create_makefile("bootsnap/bootsnap")
|
data/lib/bootsnap/bundler.rb
CHANGED
data/lib/bootsnap/cli.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
3
|
+
require "bootsnap"
|
4
|
+
require "bootsnap/cli/worker_pool"
|
5
|
+
require "optparse"
|
6
|
+
require "fileutils"
|
7
|
+
require "etc"
|
8
8
|
|
9
9
|
module Bootsnap
|
10
10
|
class CLI
|
@@ -25,7 +25,7 @@ module Bootsnap
|
|
25
25
|
|
26
26
|
def initialize(argv)
|
27
27
|
@argv = argv
|
28
|
-
self.cache_dir = ENV.fetch(
|
28
|
+
self.cache_dir = ENV.fetch("BOOTSNAP_CACHE_DIR", "tmp/cache")
|
29
29
|
self.compile_gemfile = false
|
30
30
|
self.exclude = nil
|
31
31
|
self.verbose = false
|
@@ -36,16 +36,16 @@ module Bootsnap
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def precompile_command(*sources)
|
39
|
-
require
|
40
|
-
require
|
41
|
-
require
|
39
|
+
require "bootsnap/compile_cache/iseq"
|
40
|
+
require "bootsnap/compile_cache/yaml"
|
41
|
+
require "bootsnap/compile_cache/json"
|
42
42
|
|
43
43
|
fix_default_encoding do
|
44
|
-
Bootsnap::CompileCache::ISeq.cache_dir =
|
44
|
+
Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
|
45
45
|
Bootsnap::CompileCache::YAML.init!
|
46
|
-
Bootsnap::CompileCache::YAML.cache_dir =
|
46
|
+
Bootsnap::CompileCache::YAML.cache_dir = cache_dir
|
47
47
|
Bootsnap::CompileCache::JSON.init!
|
48
|
-
Bootsnap::CompileCache::JSON.cache_dir =
|
48
|
+
Bootsnap::CompileCache::JSON.cache_dir = cache_dir
|
49
49
|
|
50
50
|
@work_pool = WorkerPool.create(size: jobs, jobs: {
|
51
51
|
ruby: method(:precompile_ruby),
|
@@ -61,7 +61,7 @@ module Bootsnap
|
|
61
61
|
|
62
62
|
if compile_gemfile
|
63
63
|
# Some gems embed their tests, they're very unlikely to be loaded, so not worth precompiling.
|
64
|
-
gem_exclude = Regexp.union([exclude,
|
64
|
+
gem_exclude = Regexp.union([exclude, "/spec/", "/test/"].compact)
|
65
65
|
precompile_ruby_files($LOAD_PATH.map { |d| File.expand_path(d) }, exclude: gem_exclude)
|
66
66
|
|
67
67
|
# Gems that include JSON or YAML files usually don't put them in `lib/`.
|
@@ -72,7 +72,7 @@ module Bootsnap
|
|
72
72
|
precompile_json_files(gem_paths, exclude: gem_exclude)
|
73
73
|
end
|
74
74
|
|
75
|
-
if exitstatus = @work_pool.shutdown
|
75
|
+
if (exitstatus = @work_pool.shutdown)
|
76
76
|
exit(exitstatus)
|
77
77
|
end
|
78
78
|
end
|
@@ -89,7 +89,7 @@ module Bootsnap
|
|
89
89
|
if dir_sort
|
90
90
|
def list_files(path, pattern)
|
91
91
|
if File.directory?(path)
|
92
|
-
Dir[File.join(path,
|
92
|
+
Dir[File.join(path, pattern), sort: false]
|
93
93
|
elsif File.exist?(path)
|
94
94
|
[path]
|
95
95
|
else
|
@@ -99,7 +99,7 @@ module Bootsnap
|
|
99
99
|
else
|
100
100
|
def list_files(path, pattern)
|
101
101
|
if File.directory?(path)
|
102
|
-
Dir[File.join(path,
|
102
|
+
Dir[File.join(path, pattern)]
|
103
103
|
elsif File.exist?(path)
|
104
104
|
[path]
|
105
105
|
else
|
@@ -126,9 +126,9 @@ module Bootsnap
|
|
126
126
|
|
127
127
|
load_paths.each do |path|
|
128
128
|
if !exclude || !exclude.match?(path)
|
129
|
-
list_files(path,
|
129
|
+
list_files(path, "**/*.{yml,yaml}").each do |yaml_file|
|
130
130
|
# We ignore hidden files to not match the various .ci.yml files
|
131
|
-
if !File.basename(yaml_file).start_with?(
|
131
|
+
if !File.basename(yaml_file).start_with?(".") && (!exclude || !exclude.match?(yaml_file))
|
132
132
|
@work_pool.push(:yaml, yaml_file)
|
133
133
|
end
|
134
134
|
end
|
@@ -138,7 +138,7 @@ module Bootsnap
|
|
138
138
|
|
139
139
|
def precompile_yaml(*yaml_files)
|
140
140
|
Array(yaml_files).each do |yaml_file|
|
141
|
-
if CompileCache::YAML.precompile(yaml_file
|
141
|
+
if CompileCache::YAML.precompile(yaml_file)
|
142
142
|
STDERR.puts(yaml_file) if verbose
|
143
143
|
end
|
144
144
|
end
|
@@ -149,9 +149,9 @@ module Bootsnap
|
|
149
149
|
|
150
150
|
load_paths.each do |path|
|
151
151
|
if !exclude || !exclude.match?(path)
|
152
|
-
list_files(path,
|
152
|
+
list_files(path, "**/*.json").each do |json_file|
|
153
153
|
# We ignore hidden files to not match the various .config.json files
|
154
|
-
if !File.basename(json_file).start_with?(
|
154
|
+
if !File.basename(json_file).start_with?(".") && (!exclude || !exclude.match?(json_file))
|
155
155
|
@work_pool.push(:json, json_file)
|
156
156
|
end
|
157
157
|
end
|
@@ -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 CompileCache::JSON.precompile(json_file
|
164
|
+
if CompileCache::JSON.precompile(json_file)
|
165
165
|
STDERR.puts(json_file) if verbose
|
166
166
|
end
|
167
167
|
end
|
@@ -172,7 +172,7 @@ module Bootsnap
|
|
172
172
|
|
173
173
|
load_paths.each do |path|
|
174
174
|
if !exclude || !exclude.match?(path)
|
175
|
-
list_files(path,
|
175
|
+
list_files(path, "**/*.rb").each do |ruby_file|
|
176
176
|
if !exclude || !exclude.match?(ruby_file)
|
177
177
|
@work_pool.push(:ruby, ruby_file)
|
178
178
|
end
|
@@ -183,7 +183,7 @@ module Bootsnap
|
|
183
183
|
|
184
184
|
def precompile_ruby(*ruby_files)
|
185
185
|
Array(ruby_files).each do |ruby_file|
|
186
|
-
if CompileCache::ISeq.precompile(ruby_file
|
186
|
+
if CompileCache::ISeq.precompile(ruby_file)
|
187
187
|
STDERR.puts(ruby_file) if verbose
|
188
188
|
end
|
189
189
|
end
|
@@ -210,7 +210,7 @@ module Bootsnap
|
|
210
210
|
end
|
211
211
|
|
212
212
|
def cache_dir=(dir)
|
213
|
-
@cache_dir = File.expand_path(File.join(dir,
|
213
|
+
@cache_dir = File.expand_path(File.join(dir, "bootsnap/compile-cache"))
|
214
214
|
end
|
215
215
|
|
216
216
|
def exclude_pattern(pattern)
|
@@ -225,24 +225,24 @@ module Bootsnap
|
|
225
225
|
opts.separator "GLOBAL OPTIONS"
|
226
226
|
opts.separator ""
|
227
227
|
|
228
|
-
help = <<~
|
228
|
+
help = <<~HELP
|
229
229
|
Path to the bootsnap cache directory. Defaults to tmp/cache
|
230
|
-
|
231
|
-
opts.on(
|
230
|
+
HELP
|
231
|
+
opts.on("--cache-dir DIR", help.strip) do |dir|
|
232
232
|
self.cache_dir = dir
|
233
233
|
end
|
234
234
|
|
235
|
-
help = <<~
|
235
|
+
help = <<~HELP
|
236
236
|
Print precompiled paths.
|
237
|
-
|
238
|
-
opts.on(
|
237
|
+
HELP
|
238
|
+
opts.on("--verbose", "-v", help.strip) do
|
239
239
|
self.verbose = true
|
240
240
|
end
|
241
241
|
|
242
|
-
help = <<~
|
242
|
+
help = <<~HELP
|
243
243
|
Number of workers to use. Default to number of processors, set to 0 to disable multi-processing.
|
244
|
-
|
245
|
-
opts.on(
|
244
|
+
HELP
|
245
|
+
opts.on("--jobs JOBS", "-j", help.strip) do |jobs|
|
246
246
|
self.jobs = Integer(jobs)
|
247
247
|
end
|
248
248
|
|
@@ -251,30 +251,30 @@ module Bootsnap
|
|
251
251
|
opts.separator ""
|
252
252
|
opts.separator " precompile [DIRECTORIES...]: Precompile all .rb files in the passed directories"
|
253
253
|
|
254
|
-
help = <<~
|
254
|
+
help = <<~HELP
|
255
255
|
Precompile the gems in Gemfile
|
256
|
-
|
257
|
-
opts.on(
|
256
|
+
HELP
|
257
|
+
opts.on("--gemfile", help) { self.compile_gemfile = true }
|
258
258
|
|
259
|
-
help = <<~
|
259
|
+
help = <<~HELP
|
260
260
|
Path pattern to not precompile. e.g. --exclude 'aws-sdk|google-api'
|
261
|
-
|
262
|
-
opts.on(
|
261
|
+
HELP
|
262
|
+
opts.on("--exclude PATTERN", help) { |pattern| exclude_pattern(pattern) }
|
263
263
|
|
264
|
-
help = <<~
|
264
|
+
help = <<~HELP
|
265
265
|
Disable ISeq (.rb) precompilation.
|
266
|
-
|
267
|
-
opts.on(
|
266
|
+
HELP
|
267
|
+
opts.on("--no-iseq", help) { self.iseq = false }
|
268
268
|
|
269
|
-
help = <<~
|
269
|
+
help = <<~HELP
|
270
270
|
Disable YAML precompilation.
|
271
|
-
|
272
|
-
opts.on(
|
271
|
+
HELP
|
272
|
+
opts.on("--no-yaml", help) { self.yaml = false }
|
273
273
|
|
274
|
-
help = <<~
|
274
|
+
help = <<~HELP
|
275
275
|
Disable JSON precompilation.
|
276
|
-
|
277
|
-
opts.on(
|
276
|
+
HELP
|
277
|
+
opts.on("--no-json", help) { self.json = false }
|
278
278
|
end
|
279
279
|
end
|
280
280
|
end
|
@@ -1,12 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require(
|
2
|
+
|
3
|
+
require("bootsnap/bootsnap")
|
4
|
+
require("zlib")
|
4
5
|
|
5
6
|
module Bootsnap
|
6
7
|
module CompileCache
|
7
8
|
module ISeq
|
8
9
|
class << self
|
9
|
-
|
10
|
+
attr_reader(:cache_dir)
|
11
|
+
|
12
|
+
def cache_dir=(cache_dir)
|
13
|
+
@cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}iseq" : "#{cache_dir}-iseq"
|
14
|
+
end
|
10
15
|
end
|
11
16
|
|
12
17
|
has_ruby_bug_18250 = begin # https://bugs.ruby-lang.org/issues/18250
|
@@ -23,27 +28,27 @@ module Bootsnap
|
|
23
28
|
iseq = begin
|
24
29
|
RubyVM::InstructionSequence.compile_file(path)
|
25
30
|
rescue SyntaxError
|
26
|
-
|
31
|
+
return UNCOMPILABLE # syntax error
|
27
32
|
end
|
28
33
|
|
29
34
|
begin
|
30
35
|
iseq.to_binary
|
31
36
|
rescue TypeError
|
32
|
-
|
37
|
+
return UNCOMPILABLE # ruby bug #18250
|
33
38
|
end
|
34
39
|
end
|
35
40
|
else
|
36
41
|
def self.input_to_storage(_, path)
|
37
42
|
RubyVM::InstructionSequence.compile_file(path).to_binary
|
38
43
|
rescue SyntaxError
|
39
|
-
|
44
|
+
return UNCOMPILABLE # syntax error
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
43
48
|
def self.storage_to_output(binary, _args)
|
44
49
|
RubyVM::InstructionSequence.load_from_binary(binary)
|
45
|
-
rescue RuntimeError =>
|
46
|
-
if
|
50
|
+
rescue RuntimeError => error
|
51
|
+
if error.message == "broken binary format"
|
47
52
|
STDERR.puts("[Bootsnap::CompileCache] warning: rejecting broken binary")
|
48
53
|
nil
|
49
54
|
else
|
@@ -60,7 +65,7 @@ module Bootsnap
|
|
60
65
|
)
|
61
66
|
end
|
62
67
|
|
63
|
-
def self.precompile(path
|
68
|
+
def self.precompile(path)
|
64
69
|
Bootsnap::CompileCache::Native.precompile(
|
65
70
|
cache_dir,
|
66
71
|
path.to_s,
|
@@ -80,8 +85,8 @@ module Bootsnap
|
|
80
85
|
Bootsnap::CompileCache::ISeq.fetch(path.to_s)
|
81
86
|
rescue Errno::EACCES
|
82
87
|
Bootsnap::CompileCache.permission_error(path)
|
83
|
-
rescue RuntimeError =>
|
84
|
-
if
|
88
|
+
rescue RuntimeError => error
|
89
|
+
if error.message =~ /unmatched platform/
|
85
90
|
puts("unmatched platform for file #{path}")
|
86
91
|
end
|
87
92
|
raise
|
@@ -1,11 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require("bootsnap/bootsnap")
|
3
4
|
|
4
5
|
module Bootsnap
|
5
6
|
module CompileCache
|
6
7
|
module JSON
|
7
8
|
class << self
|
8
|
-
attr_accessor(:msgpack_factory, :
|
9
|
+
attr_accessor(:msgpack_factory, :supported_options)
|
10
|
+
attr_reader(:cache_dir)
|
11
|
+
|
12
|
+
def cache_dir=(cache_dir)
|
13
|
+
@cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}json" : "#{cache_dir}-json"
|
14
|
+
end
|
9
15
|
|
10
16
|
def input_to_storage(payload, _)
|
11
17
|
obj = ::JSON.parse(payload)
|
@@ -13,7 +19,7 @@ module Bootsnap
|
|
13
19
|
end
|
14
20
|
|
15
21
|
def storage_to_output(data, kwargs)
|
16
|
-
if kwargs
|
22
|
+
if kwargs&.key?(:symbolize_names)
|
17
23
|
kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
|
18
24
|
end
|
19
25
|
msgpack_factory.load(data, kwargs)
|
@@ -23,7 +29,7 @@ module Bootsnap
|
|
23
29
|
::JSON.parse(data, **(kwargs || {}))
|
24
30
|
end
|
25
31
|
|
26
|
-
def precompile(path
|
32
|
+
def precompile(path)
|
27
33
|
Bootsnap::CompileCache::Native.precompile(
|
28
34
|
cache_dir,
|
29
35
|
path.to_s,
|
@@ -40,22 +46,23 @@ module Bootsnap
|
|
40
46
|
end
|
41
47
|
|
42
48
|
def init!
|
43
|
-
require(
|
44
|
-
require(
|
49
|
+
require("json")
|
50
|
+
require("msgpack")
|
45
51
|
|
46
52
|
self.msgpack_factory = MessagePack::Factory.new
|
47
53
|
self.supported_options = [:symbolize_names]
|
48
54
|
if ::JSON.parse('["foo"]', freeze: true).first.frozen?
|
49
55
|
self.supported_options = [:freeze]
|
50
56
|
end
|
51
|
-
|
57
|
+
supported_options.freeze
|
52
58
|
end
|
53
59
|
end
|
54
60
|
|
55
61
|
module Patch
|
56
62
|
def load_file(path, *args)
|
57
63
|
return super if args.size > 1
|
58
|
-
|
64
|
+
|
65
|
+
if (kwargs = args.first)
|
59
66
|
return super unless kwargs.is_a?(Hash)
|
60
67
|
return super unless (kwargs.keys - ::Bootsnap::CompileCache::JSON.supported_options).empty?
|
61
68
|
end
|