bootsnap 1.4.3 → 1.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -0
- data/README.jp.md +1 -1
- data/README.md +1 -1
- data/Rakefile +1 -0
- data/bin/console +1 -0
- data/bootsnap.gemspec +2 -1
- data/ext/bootsnap/bootsnap.c +55 -30
- data/ext/bootsnap/extconf.rb +1 -0
- data/lib/bootsnap.rb +1 -0
- data/lib/bootsnap/bundler.rb +1 -0
- data/lib/bootsnap/compile_cache.rb +2 -1
- data/lib/bootsnap/compile_cache/iseq.rb +1 -0
- data/lib/bootsnap/compile_cache/yaml.rb +1 -0
- data/lib/bootsnap/explicit_require.rb +1 -0
- data/lib/bootsnap/load_path_cache/cache.rb +2 -2
- data/lib/bootsnap/load_path_cache/change_observer.rb +1 -0
- data/lib/bootsnap/load_path_cache/core_ext/active_support.rb +1 -0
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +2 -1
- data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +1 -0
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +32 -9
- data/lib/bootsnap/load_path_cache/path.rb +1 -0
- data/lib/bootsnap/load_path_cache/store.rb +18 -14
- data/lib/bootsnap/setup.rb +5 -1
- data/lib/bootsnap/version.rb +2 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d4f38db9a609c2adb0a0ede991bd993dff7ae59885cb1722eb699658211fd96
|
4
|
+
data.tar.gz: 9f363c21a154e123693f18e48073451c6cfe6c05ec378c980e6ef770f01e658c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 925f595e21911c61ff7cf3a86cb055d25e56bb65a8a6437c513f25bfea3aec6c086259808b5aed3289e5d82f66706f98314f31d2ff3886d85edeb47085d6a918
|
7
|
+
data.tar.gz: 31507ba8393d47361f8332064a9a39220392a4242e1f3f3c3a88c4de032b51eb8aab8d3769869fec7f9da55400ce773c42aecc52604d5293c9ff7ea3f9f40e54
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/README.jp.md
CHANGED
@@ -152,7 +152,7 @@ close n
|
|
152
152
|
Bootsnap は、64バイトのヘッダーとそれに続くキャッシュの内容を含んだキャッシュファイルを書き込みます。ヘッダーは、次のいくつかのフィールドで構成されるキャッシュキーです。
|
153
153
|
|
154
154
|
- `version`、Bootsnapにハードコードされる基本的なスキーマのバージョン
|
155
|
-
- `
|
155
|
+
- `ruby_platform`、`RUBY_PLATFORM`(x86_64-linux-gnuなど)変数とglibcバージョン(Linuxの場合)またはOSバージョン(BSD、macOSの場合は` uname -v`)のハッシュ
|
156
156
|
- `compile_option`、`RubyVM::InstructionSequence.compile_option` の返り値
|
157
157
|
- `ruby_revision`、コンパイルされたRubyのバージョン
|
158
158
|
- `size`、ソースファイルのサイズ
|
data/README.md
CHANGED
@@ -214,7 +214,7 @@ Bootsnap writes a cache file containing a 64 byte header followed by the cache c
|
|
214
214
|
is a cache key including several fields:
|
215
215
|
|
216
216
|
* `version`, hardcoded in bootsnap. Essentially a schema version;
|
217
|
-
* `
|
217
|
+
* `ruby_platform`, A hash of `RUBY_PLATFORM` (e.g. x86_64-linux-gnu) variable and glibc version (on Linux) or OS version (`uname -v` on BSD, macOS)
|
218
218
|
* `compile_option`, which changes with `RubyVM::InstructionSequence.compile_option` does;
|
219
219
|
* `ruby_revision`, the version of Ruby this was compiled with;
|
220
220
|
* `size`, the size of the source file;
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
data/bootsnap.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require('bootsnap/version')
|
@@ -26,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
26
27
|
end
|
27
28
|
spec.require_paths = %w(lib)
|
28
29
|
|
29
|
-
spec.required_ruby_version = '>= 2.
|
30
|
+
spec.required_ruby_version = '>= 2.3.0'
|
30
31
|
|
31
32
|
if RUBY_PLATFORM =~ /java/
|
32
33
|
spec.platform = 'java'
|
data/ext/bootsnap/bootsnap.c
CHANGED
@@ -21,6 +21,9 @@
|
|
21
21
|
#ifndef _WIN32
|
22
22
|
#include <sys/utsname.h>
|
23
23
|
#endif
|
24
|
+
#ifdef __GLIBC__
|
25
|
+
#include <gnu/libc-version.h>
|
26
|
+
#endif
|
24
27
|
|
25
28
|
/* 1000 is an arbitrary limit; FNV64 plus some slashes brings the cap down to
|
26
29
|
* 981 for the cache dir */
|
@@ -90,12 +93,13 @@ static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handl
|
|
90
93
|
|
91
94
|
/* Helpers */
|
92
95
|
static uint64_t fnv1a_64(const char *str);
|
93
|
-
static void bs_cache_path(const char * cachedir, const char * path, char
|
96
|
+
static void bs_cache_path(const char * cachedir, const char * path, char (* cache_path)[MAX_CACHEPATH_SIZE]);
|
94
97
|
static int bs_read_key(int fd, struct bs_cache_key * key);
|
95
98
|
static int cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2);
|
96
99
|
static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler);
|
97
|
-
static int open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenance);
|
98
|
-
static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, char ** errno_provenance);
|
100
|
+
static int open_current_file(char * path, struct bs_cache_key * key, const char ** errno_provenance);
|
101
|
+
static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, const char ** errno_provenance);
|
102
|
+
static uint32_t get_ruby_revision(void);
|
99
103
|
static uint32_t get_ruby_platform(void);
|
100
104
|
|
101
105
|
/*
|
@@ -136,7 +140,7 @@ Init_bootsnap(void)
|
|
136
140
|
rb_mBootsnap_CompileCache_Native = rb_define_module_under(rb_mBootsnap_CompileCache, "Native");
|
137
141
|
rb_eBootsnap_CompileCache_Uncompilable = rb_define_class_under(rb_mBootsnap_CompileCache, "Uncompilable", rb_eStandardError);
|
138
142
|
|
139
|
-
current_ruby_revision =
|
143
|
+
current_ruby_revision = get_ruby_revision();
|
140
144
|
current_ruby_platform = get_ruby_platform();
|
141
145
|
|
142
146
|
uncompilable = rb_intern("__bootsnap_uncompilable__");
|
@@ -196,6 +200,26 @@ fnv1a_64(const char *str)
|
|
196
200
|
return fnv1a_64_iter(h, str);
|
197
201
|
}
|
198
202
|
|
203
|
+
/*
|
204
|
+
* Ruby's revision may be Integer or String. CRuby 2.7 or later uses
|
205
|
+
* Git commit ID as revision. It's String.
|
206
|
+
*/
|
207
|
+
static uint32_t
|
208
|
+
get_ruby_revision(void)
|
209
|
+
{
|
210
|
+
VALUE ruby_revision;
|
211
|
+
|
212
|
+
ruby_revision = rb_const_get(rb_cObject, rb_intern("RUBY_REVISION"));
|
213
|
+
if (RB_TYPE_P(ruby_revision, RUBY_T_FIXNUM)) {
|
214
|
+
return FIX2INT(ruby_revision);
|
215
|
+
} else {
|
216
|
+
uint64_t hash;
|
217
|
+
|
218
|
+
hash = fnv1a_64(StringValueCStr(ruby_revision));
|
219
|
+
return (uint32_t)(hash >> 32);
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
199
223
|
/*
|
200
224
|
* When ruby's version doesn't change, but it's recompiled on a different OS
|
201
225
|
* (or OS version), we need to invalidate the cache.
|
@@ -215,6 +239,9 @@ get_ruby_platform(void)
|
|
215
239
|
|
216
240
|
#ifdef _WIN32
|
217
241
|
return (uint32_t)(hash >> 32) ^ (uint32_t)GetVersion();
|
242
|
+
#elif defined(__GLIBC__)
|
243
|
+
hash = fnv1a_64_iter(hash, gnu_get_libc_version());
|
244
|
+
return (uint32_t)(hash >> 32);
|
218
245
|
#else
|
219
246
|
struct utsname utsname;
|
220
247
|
|
@@ -235,7 +262,7 @@ get_ruby_platform(void)
|
|
235
262
|
* The path will look something like: <cachedir>/12/34567890abcdef
|
236
263
|
*/
|
237
264
|
static void
|
238
|
-
bs_cache_path(const char * cachedir, const char * path, char
|
265
|
+
bs_cache_path(const char * cachedir, const char * path, char (* cache_path)[MAX_CACHEPATH_SIZE])
|
239
266
|
{
|
240
267
|
uint64_t hash = fnv1a_64(path);
|
241
268
|
|
@@ -287,10 +314,8 @@ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
|
|
287
314
|
char * path = RSTRING_PTR(path_v);
|
288
315
|
char cache_path[MAX_CACHEPATH_SIZE];
|
289
316
|
|
290
|
-
|
291
|
-
|
292
|
-
bs_cache_path(cachedir, path, &tmp);
|
293
|
-
}
|
317
|
+
/* generate cache path to cache_path */
|
318
|
+
bs_cache_path(cachedir, path, &cache_path);
|
294
319
|
|
295
320
|
return bs_fetch(path, path_v, cache_path, handler);
|
296
321
|
}
|
@@ -300,14 +325,14 @@ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
|
|
300
325
|
* was loaded.
|
301
326
|
*/
|
302
327
|
static int
|
303
|
-
open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenance)
|
328
|
+
open_current_file(char * path, struct bs_cache_key * key, const char ** errno_provenance)
|
304
329
|
{
|
305
330
|
struct stat statbuf;
|
306
331
|
int fd;
|
307
332
|
|
308
333
|
fd = open(path, O_RDONLY);
|
309
334
|
if (fd < 0) {
|
310
|
-
*errno_provenance =
|
335
|
+
*errno_provenance = "bs_fetch:open_current_file:open";
|
311
336
|
return fd;
|
312
337
|
}
|
313
338
|
#ifdef _WIN32
|
@@ -315,7 +340,7 @@ open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenan
|
|
315
340
|
#endif
|
316
341
|
|
317
342
|
if (fstat(fd, &statbuf) < 0) {
|
318
|
-
*errno_provenance =
|
343
|
+
*errno_provenance = "bs_fetch:open_current_file:fstat";
|
319
344
|
close(fd);
|
320
345
|
return -1;
|
321
346
|
}
|
@@ -361,13 +386,13 @@ bs_read_key(int fd, struct bs_cache_key * key)
|
|
361
386
|
* - ERROR_WITH_ERRNO (-1, errno is set)
|
362
387
|
*/
|
363
388
|
static int
|
364
|
-
open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_provenance)
|
389
|
+
open_cache_file(const char * path, struct bs_cache_key * key, const char ** errno_provenance)
|
365
390
|
{
|
366
391
|
int fd, res;
|
367
392
|
|
368
393
|
fd = open(path, O_RDONLY);
|
369
394
|
if (fd < 0) {
|
370
|
-
*errno_provenance =
|
395
|
+
*errno_provenance = "bs_fetch:open_cache_file:open";
|
371
396
|
if (errno == ENOENT) return CACHE_MISSING_OR_INVALID;
|
372
397
|
return ERROR_WITH_ERRNO;
|
373
398
|
}
|
@@ -377,7 +402,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_prov
|
|
377
402
|
|
378
403
|
res = bs_read_key(fd, key);
|
379
404
|
if (res < 0) {
|
380
|
-
*errno_provenance =
|
405
|
+
*errno_provenance = "bs_fetch:open_cache_file:read";
|
381
406
|
close(fd);
|
382
407
|
return res;
|
383
408
|
}
|
@@ -401,7 +426,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_prov
|
|
401
426
|
* or exception, will be the final data returnable to the user.
|
402
427
|
*/
|
403
428
|
static int
|
404
|
-
fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, char ** errno_provenance)
|
429
|
+
fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, const char ** errno_provenance)
|
405
430
|
{
|
406
431
|
char * data = NULL;
|
407
432
|
ssize_t nread;
|
@@ -410,7 +435,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data,
|
|
410
435
|
VALUE storage_data;
|
411
436
|
|
412
437
|
if (data_size > 100000000000) {
|
413
|
-
*errno_provenance =
|
438
|
+
*errno_provenance = "bs_fetch:fetch_cached_data:datasize";
|
414
439
|
errno = EINVAL; /* because wtf? */
|
415
440
|
ret = -1;
|
416
441
|
goto done;
|
@@ -418,7 +443,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data,
|
|
418
443
|
data = ALLOC_N(char, data_size);
|
419
444
|
nread = read(fd, data, data_size);
|
420
445
|
if (nread < 0) {
|
421
|
-
*errno_provenance =
|
446
|
+
*errno_provenance = "bs_fetch:fetch_cached_data:read";
|
422
447
|
ret = -1;
|
423
448
|
goto done;
|
424
449
|
}
|
@@ -470,7 +495,7 @@ mkpath(char * file_path, mode_t mode)
|
|
470
495
|
* path.
|
471
496
|
*/
|
472
497
|
static int
|
473
|
-
atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char ** errno_provenance)
|
498
|
+
atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, const char ** errno_provenance)
|
474
499
|
{
|
475
500
|
char template[MAX_CACHEPATH_SIZE + 20];
|
476
501
|
char * tmp_path;
|
@@ -484,12 +509,12 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
|
|
484
509
|
fd = mkstemp(tmp_path);
|
485
510
|
if (fd < 0) {
|
486
511
|
if (mkpath(tmp_path, 0775) < 0) {
|
487
|
-
*errno_provenance =
|
512
|
+
*errno_provenance = "bs_fetch:atomic_write_cache_file:mkpath";
|
488
513
|
return -1;
|
489
514
|
}
|
490
515
|
fd = open(tmp_path, O_WRONLY | O_CREAT, 0664);
|
491
516
|
if (fd < 0) {
|
492
|
-
*errno_provenance =
|
517
|
+
*errno_provenance = "bs_fetch:atomic_write_cache_file:open";
|
493
518
|
return -1;
|
494
519
|
}
|
495
520
|
}
|
@@ -500,11 +525,11 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
|
|
500
525
|
key->data_size = RSTRING_LEN(data);
|
501
526
|
nwrite = write(fd, key, KEY_SIZE);
|
502
527
|
if (nwrite < 0) {
|
503
|
-
*errno_provenance =
|
528
|
+
*errno_provenance = "bs_fetch:atomic_write_cache_file:write";
|
504
529
|
return -1;
|
505
530
|
}
|
506
531
|
if (nwrite != KEY_SIZE) {
|
507
|
-
*errno_provenance =
|
532
|
+
*errno_provenance = "bs_fetch:atomic_write_cache_file:keysize";
|
508
533
|
errno = EIO; /* Lies but whatever */
|
509
534
|
return -1;
|
510
535
|
}
|
@@ -512,7 +537,7 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
|
|
512
537
|
nwrite = write(fd, RSTRING_PTR(data), RSTRING_LEN(data));
|
513
538
|
if (nwrite < 0) return -1;
|
514
539
|
if (nwrite != RSTRING_LEN(data)) {
|
515
|
-
*errno_provenance =
|
540
|
+
*errno_provenance = "bs_fetch:atomic_write_cache_file:writelength";
|
516
541
|
errno = EIO; /* Lies but whatever */
|
517
542
|
return -1;
|
518
543
|
}
|
@@ -520,12 +545,12 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
|
|
520
545
|
close(fd);
|
521
546
|
ret = rename(tmp_path, path);
|
522
547
|
if (ret < 0) {
|
523
|
-
*errno_provenance =
|
548
|
+
*errno_provenance = "bs_fetch:atomic_write_cache_file:rename";
|
524
549
|
return -1;
|
525
550
|
}
|
526
551
|
ret = chmod(path, 0664 & ~current_umask);
|
527
552
|
if (ret < 0) {
|
528
|
-
*errno_provenance =
|
553
|
+
*errno_provenance = "bs_fetch:atomic_write_cache_file:chmod";
|
529
554
|
}
|
530
555
|
return ret;
|
531
556
|
}
|
@@ -534,13 +559,13 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
|
|
534
559
|
/* Read contents from an fd, whose contents are asserted to be +size+ bytes
|
535
560
|
* long, into a buffer */
|
536
561
|
static ssize_t
|
537
|
-
bs_read_contents(int fd, size_t size, char ** contents, char ** errno_provenance)
|
562
|
+
bs_read_contents(int fd, size_t size, char ** contents, const char ** errno_provenance)
|
538
563
|
{
|
539
564
|
ssize_t nread;
|
540
565
|
*contents = ALLOC_N(char, size);
|
541
566
|
nread = read(fd, *contents, size);
|
542
567
|
if (nread < 0) {
|
543
|
-
*errno_provenance =
|
568
|
+
*errno_provenance = "bs_fetch:bs_read_contents:read";
|
544
569
|
}
|
545
570
|
return nread;
|
546
571
|
}
|
@@ -596,7 +621,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
|
|
596
621
|
char * contents = NULL;
|
597
622
|
int cache_fd = -1, current_fd = -1;
|
598
623
|
int res, valid_cache = 0, exception_tag = 0;
|
599
|
-
char * errno_provenance = NULL;
|
624
|
+
const char * errno_provenance = NULL;
|
600
625
|
|
601
626
|
VALUE input_data; /* data read from source file, e.g. YAML or ruby source */
|
602
627
|
VALUE storage_data; /* compiled data, e.g. msgpack / binary iseq */
|
@@ -664,7 +689,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
|
|
664
689
|
* using input_to_output */
|
665
690
|
if (NIL_P(output_data)) {
|
666
691
|
if (unlink(cache_path) < 0) {
|
667
|
-
errno_provenance =
|
692
|
+
errno_provenance = "bs_fetch:unlink";
|
668
693
|
goto fail_errno;
|
669
694
|
}
|
670
695
|
bs_input_to_output(handler, input_data, &output_data, &exception_tag);
|
data/ext/bootsnap/extconf.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
data/lib/bootsnap/bundler.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Bootsnap
|
2
3
|
module CompileCache
|
3
4
|
Error = Class.new(StandardError)
|
@@ -28,7 +29,7 @@ module Bootsnap
|
|
28
29
|
raise(
|
29
30
|
PermissionError,
|
30
31
|
"bootsnap doesn't have permission to write cache entries in '#{cpath}' " \
|
31
|
-
"(or, less likely, doesn't have
|
32
|
+
"(or, less likely, doesn't have permission to read '#{path}')",
|
32
33
|
)
|
33
34
|
end
|
34
35
|
|
@@ -67,7 +67,7 @@ module Bootsnap
|
|
67
67
|
# native dynamic extension, e.g. .bundle or .so), we know it was a
|
68
68
|
# failure and there's nothing more we can do to find the file.
|
69
69
|
# no extension, .rb, (.bundle or .so)
|
70
|
-
when '', *CACHED_EXTENSIONS
|
70
|
+
when '', *CACHED_EXTENSIONS
|
71
71
|
nil
|
72
72
|
# Ruby allows specifying native extensions as '.so' even when DLEXT
|
73
73
|
# is '.bundle'. This is where we handle that case.
|
@@ -144,7 +144,7 @@ module Bootsnap
|
|
144
144
|
expanded_path = p.expanded_path
|
145
145
|
entries, dirs = p.entries_and_dirs(@store)
|
146
146
|
# push -> low precedence -> set only if unset
|
147
|
-
dirs.each { |dir| @dirs[dir]
|
147
|
+
dirs.each { |dir| @dirs[dir] ||= path }
|
148
148
|
entries.each { |rel| @index[rel] ||= expanded_path }
|
149
149
|
end
|
150
150
|
end
|
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Bootsnap
|
2
3
|
module LoadPathCache
|
3
4
|
module CoreExt
|
4
5
|
def self.make_load_error(path)
|
5
|
-
err = LoadError.new("cannot load such file -- #{path}")
|
6
|
+
err = LoadError.new(+"cannot load such file -- #{path}")
|
6
7
|
err.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
|
7
8
|
err.define_singleton_method(:path) { path }
|
8
9
|
err
|
@@ -40,7 +40,7 @@ module Bootsnap
|
|
40
40
|
# /a/b/lib/my/foo.rb
|
41
41
|
# ^^^^^^^^^
|
42
42
|
short = feat[(lpe.length + 1)..-1]
|
43
|
-
stripped =
|
43
|
+
stripped = strip_extension_if_elidable(short)
|
44
44
|
@lfi[short] = hash
|
45
45
|
@lfi[stripped] = hash
|
46
46
|
end
|
@@ -94,13 +94,14 @@ module Bootsnap
|
|
94
94
|
|
95
95
|
hash = long.hash
|
96
96
|
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
97
|
+
# Do we have a filename with an elidable extension, e.g.,
|
98
|
+
# 'bundler.rb', or 'libgit2.so'?
|
99
|
+
altname = if extension_elidable?(short)
|
100
|
+
# Strip the extension off, e.g. 'bundler.rb' -> 'bundler'.
|
101
|
+
strip_extension_if_elidable(short)
|
101
102
|
elsif long && (ext = File.extname(long))
|
102
|
-
#
|
103
|
-
#
|
103
|
+
# We already know the extension of the actual file this
|
104
|
+
# resolves to, so put that back on.
|
104
105
|
short + ext
|
105
106
|
end
|
106
107
|
|
@@ -117,8 +118,30 @@ module Bootsnap
|
|
117
118
|
STRIP_EXTENSION = /\.[^.]*?$/
|
118
119
|
private_constant(:STRIP_EXTENSION)
|
119
120
|
|
120
|
-
|
121
|
-
|
121
|
+
# Might Ruby automatically search for this extension if
|
122
|
+
# someone tries to 'require' the file without it? E.g. Ruby
|
123
|
+
# will implicitly try 'x.rb' if you ask for 'x'.
|
124
|
+
#
|
125
|
+
# This is complex and platform-dependent, and the Ruby docs are a little
|
126
|
+
# handwavy about what will be tried when and in what order.
|
127
|
+
# So optimistically pretend that all known elidable extensions
|
128
|
+
# will be tried on all platforms, and that people are unlikely
|
129
|
+
# to name files in a way that assumes otherwise.
|
130
|
+
# (E.g. It's unlikely that someone will know that their code
|
131
|
+
# will _never_ run on MacOS, and therefore think they can get away
|
132
|
+
# with callling a Ruby file 'x.dylib.rb' and then requiring it as 'x.dylib'.)
|
133
|
+
#
|
134
|
+
# See <https://ruby-doc.org/core-2.6.4/Kernel.html#method-i-require>.
|
135
|
+
def extension_elidable?(f)
|
136
|
+
f.to_s.end_with?('.rb', '.so', '.o', '.dll', '.dylib')
|
137
|
+
end
|
138
|
+
|
139
|
+
def strip_extension_if_elidable(f)
|
140
|
+
if extension_elidable?(f)
|
141
|
+
f.sub(STRIP_EXTENSION, '')
|
142
|
+
else
|
143
|
+
f
|
144
|
+
end
|
122
145
|
end
|
123
146
|
end
|
124
147
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative('../explicit_require')
|
2
3
|
|
3
4
|
Bootsnap::ExplicitRequire.with_gems('msgpack') { require('msgpack') }
|
@@ -11,7 +12,8 @@ module Bootsnap
|
|
11
12
|
|
12
13
|
def initialize(store_path)
|
13
14
|
@store_path = store_path
|
14
|
-
|
15
|
+
# TODO: Remove conditional once Ruby 2.2 support is dropped.
|
16
|
+
@txn_mutex = defined?(::Mutex) ? ::Mutex.new : ::Thread::Mutex.new
|
15
17
|
@dirty = false
|
16
18
|
load_data
|
17
19
|
end
|
@@ -21,7 +23,7 @@ module Bootsnap
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def fetch(key)
|
24
|
-
raise(SetOutsideTransactionNotAllowed) unless @
|
26
|
+
raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
|
25
27
|
v = get(key)
|
26
28
|
unless v
|
27
29
|
@dirty = true
|
@@ -32,7 +34,7 @@ module Bootsnap
|
|
32
34
|
end
|
33
35
|
|
34
36
|
def set(key, value)
|
35
|
-
raise(SetOutsideTransactionNotAllowed) unless @
|
37
|
+
raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
|
36
38
|
if value != @data[key]
|
37
39
|
@dirty = true
|
38
40
|
@data[key] = value
|
@@ -40,12 +42,14 @@ module Bootsnap
|
|
40
42
|
end
|
41
43
|
|
42
44
|
def transaction
|
43
|
-
raise(NestedTransactionError) if @
|
44
|
-
@
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
raise(NestedTransactionError) if @txn_mutex.owned?
|
46
|
+
@txn_mutex.synchronize do
|
47
|
+
begin
|
48
|
+
yield
|
49
|
+
ensure
|
50
|
+
commit_transaction
|
51
|
+
end
|
52
|
+
end
|
49
53
|
end
|
50
54
|
|
51
55
|
private
|
@@ -60,11 +64,11 @@ module Bootsnap
|
|
60
64
|
def load_data
|
61
65
|
@data = begin
|
62
66
|
MessagePack.load(File.binread(@store_path))
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
67
|
+
# handle malformed data due to upgrade incompatability
|
68
|
+
rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
|
69
|
+
{}
|
70
|
+
rescue ArgumentError => e
|
71
|
+
e.message =~ /negative array size/ ? {} : raise
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
data/lib/bootsnap/setup.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative('../bootsnap')
|
2
3
|
|
3
4
|
env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || ENV['ENV']
|
@@ -24,12 +25,15 @@ unless cache_dir
|
|
24
25
|
cache_dir = File.join(app_root, 'tmp', 'cache')
|
25
26
|
end
|
26
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
|
+
|
27
31
|
Bootsnap.setup(
|
28
32
|
cache_dir: cache_dir,
|
29
33
|
development_mode: development_mode,
|
30
34
|
load_path_cache: true,
|
31
35
|
autoload_paths_cache: true, # assume rails. open to PRs to impl. detection
|
32
36
|
disable_trace: false,
|
33
|
-
compile_cache_iseq:
|
37
|
+
compile_cache_iseq: iseq_cache_enabled,
|
34
38
|
compile_cache_yaml: true,
|
35
39
|
)
|
data/lib/bootsnap/version.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: 1.4.
|
4
|
+
version: 1.4.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -160,14 +160,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
160
160
|
requirements:
|
161
161
|
- - ">="
|
162
162
|
- !ruby/object:Gem::Version
|
163
|
-
version: 2.
|
163
|
+
version: 2.3.0
|
164
164
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
165
|
requirements:
|
166
166
|
- - ">="
|
167
167
|
- !ruby/object:Gem::Version
|
168
168
|
version: '0'
|
169
169
|
requirements: []
|
170
|
-
rubygems_version: 3.0.
|
170
|
+
rubygems_version: 3.0.6
|
171
171
|
signing_key:
|
172
172
|
specification_version: 4
|
173
173
|
summary: Boot large ruby/rails apps faster
|