bootsnap 1.9.4 → 1.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/exe/bootsnap +1 -1
- data/ext/bootsnap/bootsnap.c +38 -36
- 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 +29 -18
- 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: 7c66adff2d954aee5f0f0b6beae724c2ec1a2abedb6cc6ffd1b3eb84a0481acf
|
4
|
+
data.tar.gz: 91a512ba361da721632679a2942d84128fe301bfc0750b48ec3c98989433072b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74613cfa0f4b1b337cf60c2e60f8f51c8726321953addfc1166708af567bdae486ea38b5ff9f1ad63ec13bee2c7142be0cde9fd9d68bf2eca4c044936b575f17
|
7
|
+
data.tar.gz: 9449f4e75ebe813e5df1fd2c71c1e334853c67feaa0a4e5351a0bcc53d6479993ffc59b37412f81853dce6154e36a165e5e5fb6c311c2ef5cf561afc889a51e2
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.10.1
|
4
|
+
|
5
|
+
* Fix `Kernel#autoload`'s fallback path always bing executed.
|
6
|
+
* Consider `unlink` failing with `ENOENT` as a success.
|
7
|
+
|
8
|
+
# 1.10.0
|
9
|
+
|
10
|
+
* Delay requiring `FileUtils`. (#285)
|
11
|
+
`FileUtils` can be installed as a gem, so it's best to wait for bundler to have setup the load path before requiring it.
|
12
|
+
|
13
|
+
* Improve support of Psych 4. (#392)
|
14
|
+
Since `1.8.0`, `YAML.load_file` was no longer cached when Psych 4 was used. This is because `load_file` loads
|
15
|
+
in safe mode by default, so the Bootsnap cache could defeat that safety.
|
16
|
+
Now when precompiling YAML files, Bootsnap first try to parse them in safe mode, and if it can't fallback to unsafe mode,
|
17
|
+
and the cache contains a flag that records wether it was generated in safe mode or not.
|
18
|
+
`YAML.unsafe_load_file` will use safe caches just fine, but `YAML.load_file` will fallback to uncached YAML parsing
|
19
|
+
if the cache was generated using unsafe parsing.
|
20
|
+
|
21
|
+
* Minimize the Kernel.require extra stack frames. (#393)
|
22
|
+
This should reduce the noise generated by bootsnap on `LoadError`.
|
23
|
+
|
3
24
|
# 1.9.4
|
4
25
|
|
5
26
|
* 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
|
![How path searching works](https://cloud.githubusercontent.com/assets/3074765/25388270/670b5652-299b-11e7-87fb-975647f68981.png)
|
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,12 +782,20 @@ 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
|
-
|
780
|
-
|
793
|
+
/* If the cache was already deleted, it might be that another process did it before us.
|
794
|
+
* No point raising an error */
|
795
|
+
if (errno != ENOENT) {
|
796
|
+
errno_provenance = "bs_fetch:unlink";
|
797
|
+
goto fail_errno;
|
798
|
+
}
|
781
799
|
}
|
782
800
|
bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
|
783
801
|
if (exception_tag != 0) goto raise;
|
@@ -856,7 +874,7 @@ bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE handler)
|
|
856
874
|
|
857
875
|
/* If input_to_storage raised Bootsnap::CompileCache::Uncompilable, don't try
|
858
876
|
* to cache anything; just return false */
|
859
|
-
if (storage_data ==
|
877
|
+
if (storage_data == rb_cBootsnap_CompileCache_UNCOMPILABLE) {
|
860
878
|
goto fail;
|
861
879
|
}
|
862
880
|
/* If storage_data isn't a string, we can't cache it */
|
@@ -919,7 +937,7 @@ struct i2s_data {
|
|
919
937
|
};
|
920
938
|
|
921
939
|
static VALUE
|
922
|
-
|
940
|
+
try_storage_to_output(VALUE arg)
|
923
941
|
{
|
924
942
|
struct s2o_data * data = (struct s2o_data *)arg;
|
925
943
|
return rb_funcall(data->handler, rb_intern("storage_to_output"), 2, data->storage_data, data->args);
|
@@ -934,7 +952,7 @@ bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * outp
|
|
934
952
|
.args = args,
|
935
953
|
.storage_data = storage_data,
|
936
954
|
};
|
937
|
-
*output_data = rb_protect(
|
955
|
+
*output_data = rb_protect(try_storage_to_output, (VALUE)&s2o_data, &state);
|
938
956
|
return state;
|
939
957
|
}
|
940
958
|
|
@@ -963,22 +981,6 @@ try_input_to_storage(VALUE arg)
|
|
963
981
|
return rb_funcall(data->handler, rb_intern("input_to_storage"), 2, data->input_data, data->pathval);
|
964
982
|
}
|
965
983
|
|
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
984
|
static int
|
983
985
|
bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data)
|
984
986
|
{
|
@@ -988,6 +990,6 @@ bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval,
|
|
988
990
|
.input_data = input_data,
|
989
991
|
.pathval = pathval,
|
990
992
|
};
|
991
|
-
*storage_data = rb_protect(
|
993
|
+
*storage_data = rb_protect(try_input_to_storage, (VALUE)&i2s_data, &state);
|
992
994
|
return state;
|
993
995
|
}
|
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
|