bootsnap 1.4.3 → 1.4.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dcfde20655817d38584e7bb6181dfa1a0e449727f04b0f74dec2b0896c6a0080
4
- data.tar.gz: a0fb770ce0b63970d571ae0de6c55d3c2a67745365410405227984119f389661
3
+ metadata.gz: 2d4f38db9a609c2adb0a0ede991bd993dff7ae59885cb1722eb699658211fd96
4
+ data.tar.gz: 9f363c21a154e123693f18e48073451c6cfe6c05ec378c980e6ef770f01e658c
5
5
  SHA512:
6
- metadata.gz: 37ffec1d9c0475149010ba8f361b306c3b4bdd631b2a8d1365c97ea94e40ae4e2af237f37f20a107707ab2735810a3e8fd9a55f00e277633d5c169e1e8d03d71
7
- data.tar.gz: 2855cdfeb7eb491ba0e8b4dc7ddfba0a4a203afcdf4f0557240fc576cd9fe99e6f26210a23573f0aa5f5b23a551d588dd6c38b032d7464545cadde71f99c0f08
6
+ metadata.gz: 925f595e21911c61ff7cf3a86cb055d25e56bb65a8a6437c513f25bfea3aec6c086259808b5aed3289e5d82f66706f98314f31d2ff3886d85edeb47085d6a918
7
+ data.tar.gz: 31507ba8393d47361f8332064a9a39220392a4242e1f3f3c3a88c4de032b51eb8aab8d3769869fec7f9da55400ce773c42aecc52604d5293c9ff7ea3f9f40e54
@@ -5,7 +5,7 @@ AllCops:
5
5
  Exclude:
6
6
  - 'vendor/**/*'
7
7
  - 'tmp/**/*'
8
- TargetRubyVersion: '2.2'
8
+ TargetRubyVersion: '2.3'
9
9
 
10
10
  # This doesn't take into account retrying from an exception
11
11
  Lint/HandleExceptions:
@@ -1,3 +1,12 @@
1
+ # 1.4.5
2
+
3
+ * MRI 2.7 support
4
+ * Fixed concurrency bugs
5
+
6
+ # 1.4.4
7
+
8
+ * Disable ISeq cache in `bootsnap/setup` by default in Ruby 2.5
9
+
1
10
  # 1.4.3
2
11
 
3
12
  * Fix some cache permissions and umask issues after switch to mkstemp
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  source 'https://rubygems.org'
2
3
 
3
4
  # Specify your gem's dependencies in bootsnap.gemspec
@@ -152,7 +152,7 @@ close n
152
152
  Bootsnap は、64バイトのヘッダーとそれに続くキャッシュの内容を含んだキャッシュファイルを書き込みます。ヘッダーは、次のいくつかのフィールドで構成されるキャッシュキーです。
153
153
 
154
154
  - `version`、Bootsnapにハードコードされる基本的なスキーマのバージョン
155
- - `os_version`、(macOS, BSDの) 現在のカーネルバージョンか (Linuxの) glibc のバージョンのハッシュ
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
- * `os_version`, A hash of the current kernel version (on macOS, BSD) or glibc version (on Linux);
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
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require('rake/extensiontask')
2
3
  require('bundler/gem_tasks')
3
4
 
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require("bundler/setup")
4
5
  require("bootsnap")
@@ -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.0.0'
30
+ spec.required_ruby_version = '>= 2.3.0'
30
31
 
31
32
  if RUBY_PLATFORM =~ /java/
32
33
  spec.platform = 'java'
@@ -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 ** cache_path);
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 = FIX2INT(rb_const_get(rb_cObject, rb_intern("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 ** cache_path)
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
- { /* generate cache path to cache_path */
291
- char * tmp = (char *)&cache_path;
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 = (char *)"bs_fetch:open_current_file:open";
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 = (char *)"bs_fetch:open_current_file:fstat";
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 = (char *)"bs_fetch:open_cache_file:open";
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 = (char *)"bs_fetch:open_cache_file:read";
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 = (char *)"bs_fetch:fetch_cached_data:datasize";
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 = (char *)"bs_fetch:fetch_cached_data:read";
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 = (char *)"bs_fetch:atomic_write_cache_file:mkpath";
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 = (char *)"bs_fetch:atomic_write_cache_file:open";
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 = (char *)"bs_fetch:atomic_write_cache_file:write";
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 = (char *)"bs_fetch:atomic_write_cache_file:keysize";
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 = (char *)"bs_fetch:atomic_write_cache_file:writelength";
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 = (char *)"bs_fetch:atomic_write_cache_file:rename";
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 = (char *)"bs_fetch:atomic_write_cache_file:chmod";
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 = (char *)"bs_fetch:bs_read_contents:read";
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 = (char *)"bs_fetch:unlink";
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);
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require("mkmf")
2
3
  $CFLAGS << ' -O3 '
3
4
  $CFLAGS << ' -std=c99'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_relative('bootsnap/version')
2
3
  require_relative('bootsnap/bundler')
3
4
  require_relative('bootsnap/load_path_cache')
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Bootsnap
2
3
  extend(self)
3
4
 
@@ -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 permisison to read '#{path}')",
32
+ "(or, less likely, doesn't have permission to read '#{path}')",
32
33
  )
33
34
  end
34
35
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require('bootsnap/bootsnap')
2
3
  require('zlib')
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require('bootsnap/bootsnap')
2
3
 
3
4
  module Bootsnap
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Bootsnap
2
3
  module ExplicitRequire
3
4
  ARCHDIR = RbConfig::CONFIG['archdir']
@@ -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 # rubocop:disable Performance/CaseWhenSplat
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] ||= path }
147
+ dirs.each { |dir| @dirs[dir] ||= path }
148
148
  entries.each { |rel| @index[rel] ||= expanded_path }
149
149
  end
150
150
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Bootsnap
2
3
  module LoadPathCache
3
4
  module ChangeObserver
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Bootsnap
2
3
  module LoadPathCache
3
4
  module CoreExt
@@ -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
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  class << $LOADED_FEATURES
2
3
  alias_method(:delete_without_bootsnap, :delete)
3
4
  def delete(key)
@@ -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 = strip_extension(short)
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
- # do we have 'bundler' or 'bundler.rb'?
98
- altname = if File.extname(short) != ''
99
- # strip the path from 'bundler.rb' -> 'bundler'
100
- strip_extension(short)
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
- # get the extension from the expanded path if given
103
- # 'bundler' + '.rb'
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
- def strip_extension(f)
121
- f.sub(STRIP_EXTENSION, '')
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('path_scanner')
2
3
 
3
4
  module Bootsnap
@@ -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
- @in_txn = false
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 @in_txn
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 @in_txn
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 @in_txn
44
- @in_txn = true
45
- yield
46
- ensure
47
- commit_transaction
48
- @in_txn = false
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
- # handle malformed data due to upgrade incompatability
64
- rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
65
- {}
66
- rescue ArgumentError => e
67
- e.message =~ /negative array size/ ? {} : raise
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
 
@@ -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: true,
37
+ compile_cache_iseq: iseq_cache_enabled,
34
38
  compile_cache_yaml: true,
35
39
  )
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Bootsnap
2
- VERSION = "1.4.3"
3
+ VERSION = "1.4.6"
3
4
  end
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.3
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: 2019-04-08 00:00:00.000000000 Z
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.0.0
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.2
170
+ rubygems_version: 3.0.6
171
171
  signing_key:
172
172
  specification_version: 4
173
173
  summary: Boot large ruby/rails apps faster