bootsnap 1.9.1 → 1.10.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +70 -3
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/exe/bootsnap +1 -1
- data/ext/bootsnap/bootsnap.c +39 -37
- 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 +42 -12
- data/lib/bootsnap/compile_cache/json.rb +18 -9
- data/lib/bootsnap/compile_cache/yaml.rb +264 -77
- data/lib/bootsnap/compile_cache.rb +13 -7
- data/lib/bootsnap/explicit_require.rb +4 -3
- data/lib/bootsnap/load_path_cache/cache.rb +57 -41
- data/lib/bootsnap/load_path_cache/change_observer.rb +2 -0
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +33 -65
- data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +1 -0
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +32 -21
- 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 +24 -7
- data/lib/bootsnap/load_path_cache.rb +16 -22
- data/lib/bootsnap/setup.rb +2 -1
- data/lib/bootsnap/version.rb +2 -1
- data/lib/bootsnap.rb +103 -92
- 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: 3dfd9cfb2cde26fc31c82206b73f3940b4b46903a3fa73d0f3f1a4c4a90c6984
|
4
|
+
data.tar.gz: 6dd8acfb2676a2585eb320ed50ba0ddb9f9c847fb415bcda824c7ebff0cce752
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 219a84be718e4ac5681621739b6f9400d77a16dee631bdc286adad87c0ddf99cc581da7281150add34075c08c59832df2a468524656d2f1ac36ac1613be051bb
|
7
|
+
data.tar.gz: 0e407a034fd081c9e506637e0997d0c2cc0eea312be798f6fd0d573173699f906f1b43a1f3d37ff64ee6efb2f9257228c6c4e7663b7337bfc49d99e5089fccb9
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,72 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.10.3
|
4
|
+
|
5
|
+
* Fix Regexp and Date type support in YAML compile cache. (#400)
|
6
|
+
|
7
|
+
* Improve the YAML compile cache to support `UTF-8` symbols. (#398, #399)
|
8
|
+
[The default `MessagePack` symbol serializer assumes all symbols are ASCII](https://github.com/msgpack/msgpack-ruby/pull/211),
|
9
|
+
because of this, non-ASCII compatible symbol would be restored with `ASCII_8BIT` encoding (AKA `BINARY`).
|
10
|
+
Bootsnap now properly cache them in `UTF-8`.
|
11
|
+
|
12
|
+
Note that the above only apply for actual YAML symbols (e..g `--- :foo`).
|
13
|
+
The issue is still present for string keys parsed with `YAML.load_file(..., symbolize_names: true)`, that is a bug
|
14
|
+
in `msgpack` that will hopefully be solved soon, see: https://github.com/msgpack/msgpack-ruby/pull/246
|
15
|
+
|
16
|
+
* Entirely disable the YAML compile cache if `Encoding.default_internal` is set to an encoding not supported by `msgpack`. (#398)
|
17
|
+
`Psych` coerce strings to `Encoding.default_internal`, but `MessagePack` doesn't. So in this scenario we can't provide
|
18
|
+
YAML caching at all without returning the strings in the wrong encoding.
|
19
|
+
This never came up in practice but might as well be safe.
|
20
|
+
|
21
|
+
# 1.10.2
|
22
|
+
|
23
|
+
* Reduce the `Kernel.require` extra stack frames some more. Now bootsnap should only add one extra frame per `require` call.
|
24
|
+
|
25
|
+
* Better check `freeze` option support in JSON compile cache.
|
26
|
+
Previously `JSON.load_file(..., freeze: true)` would be cached even when the msgpack version is missing support for it.
|
27
|
+
|
28
|
+
# 1.10.1
|
29
|
+
|
30
|
+
* Fix `Kernel#autoload`'s fallback path always being executed.
|
31
|
+
|
32
|
+
* Consider `unlink` failing with `ENOENT` as a success.
|
33
|
+
|
34
|
+
# 1.10.0
|
35
|
+
|
36
|
+
* Delay requiring `FileUtils`. (#285)
|
37
|
+
`FileUtils` can be installed as a gem, so it's best to wait for bundler to have setup the load path before requiring it.
|
38
|
+
|
39
|
+
* Improve support of Psych 4. (#392)
|
40
|
+
Since `1.8.0`, `YAML.load_file` was no longer cached when Psych 4 was used. This is because `load_file` loads
|
41
|
+
in safe mode by default, so the Bootsnap cache could defeat that safety.
|
42
|
+
Now when precompiling YAML files, Bootsnap first try to parse them in safe mode, and if it can't fallback to unsafe mode,
|
43
|
+
and the cache contains a flag that records whether it was generated in safe mode or not.
|
44
|
+
`YAML.unsafe_load_file` will use safe caches just fine, but `YAML.load_file` will fallback to uncached YAML parsing
|
45
|
+
if the cache was generated using unsafe parsing.
|
46
|
+
|
47
|
+
* Minimize the Kernel.require extra stack frames. (#393)
|
48
|
+
This should reduce the noise generated by bootsnap on `LoadError`.
|
49
|
+
|
50
|
+
# 1.9.4
|
51
|
+
|
52
|
+
* Ignore absolute paths in the loaded feature index. (#385)
|
53
|
+
This fixes a compatibility issue with Zeitwerk when Zeitwerk is loaded before bootsnap. It also should
|
54
|
+
reduce the memory usage and improve load performance of Zeitwerk managed files.
|
55
|
+
|
56
|
+
* Automatically invalidate the load path cache whenever the Ruby version change. (#387)
|
57
|
+
This is to avoid issues in case the same installation path is re-used for subsequent ruby patch releases.
|
58
|
+
|
59
|
+
# 1.9.3
|
60
|
+
|
61
|
+
* Only disable the compile cache for source files impacted by [Ruby 3.0.3 [Bug 18250]](https://bugs.ruby-lang.org/issues/18250).
|
62
|
+
This should keep the performance loss to a minimum.
|
63
|
+
|
64
|
+
# 1.9.2
|
65
|
+
|
66
|
+
* Disable compile cache if [Ruby 3.0.3's ISeq cache bug](https://bugs.ruby-lang.org/issues/18250) is detected.
|
67
|
+
AKA `iseq.rb:13 to_binary: wrong argument type false (expected Symbol)`
|
68
|
+
* Fix `Kernel.load` behavior: before `load 'a'` would load `a.rb` (and other tried extensions) and wouldn't load `a` unless `development_mode: true`, now only `a` would be loaded and files with extensions wouldn't be.
|
69
|
+
|
3
70
|
# 1.9.1
|
4
71
|
|
5
72
|
* Removed a forgotten debug statement in JSON precompilation.
|
@@ -14,7 +81,7 @@
|
|
14
81
|
|
15
82
|
# 1.8.0
|
16
83
|
|
17
|
-
* Improve support for
|
84
|
+
* Improve support for Psych 4. (#368)
|
18
85
|
|
19
86
|
# 1.7.7
|
20
87
|
|
@@ -32,8 +99,8 @@
|
|
32
99
|
|
33
100
|
# 1.7.4
|
34
101
|
|
35
|
-
* Stop raising errors when
|
36
|
-
if somehow it can't be saved,
|
102
|
+
* Stop raising errors when encountering various file system errors. The cache is now best effort,
|
103
|
+
if somehow it can't be saved, bootsnap will gracefully fallback to the original operation (e.g. `Kernel.require`).
|
37
104
|
(#353, #177, #262)
|
38
105
|
|
39
106
|
# 1.7.3
|
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
@@ -2,7 +2,7 @@
|
|
2
2
|
* Suggested reading order:
|
3
3
|
* 1. Skim Init_bootsnap
|
4
4
|
* 2. Skim bs_fetch
|
5
|
-
* 3. The rest of
|
5
|
+
* 3. The rest of everyrything
|
6
6
|
*
|
7
7
|
* Init_bootsnap sets up the ruby objects and binds bs_fetch to
|
8
8
|
* Bootsnap::CompileCache::Native.fetch.
|
@@ -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
|