bootsnap 1.7.0 → 1.7.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac5be912b9602b8b20f12255208a6a6d0373d64167092e3267b2494376f079f0
4
- data.tar.gz: 5f18b74f0c0670b86d40d4f41df87869ce5f145cbc3d71b64eddcee59b63fe12
3
+ metadata.gz: d5f10210480d5f0c9574fe970766d9ef4799e9a8a212f6ccafab6a61c2189481
4
+ data.tar.gz: 3502a4a6f2ab2614f470d1aaa4d648ec86ab0aebe9390074a71fc1b7544a9d1c
5
5
  SHA512:
6
- metadata.gz: e7abd18f5a495b63083d5b4ae9b105acc7f80c2813fa2c40594d2d34998037e6f433b91bf9ab24e021ca3d727368e5580972fc48b9382a86d30a45e03c8274f6
7
- data.tar.gz: 87aaef6229c936321f8940a28f453446a75fd2b6935e13872c1aa7455990c579c1f3f1ebea3ec6416e9f1b3af18c0468d2a1cae2bc4fafb44f4a2c972e4f4688
6
+ metadata.gz: 53975108838cdfe27d2b8c9e7b0ef1a25100e85ad691063d2dfd35e6db600bf5c76591aeaf51117651fab7c96779c6877a86984bfa97eb7152afecbd42d77828
7
+ data.tar.gz: 294d0cf74421f374dfde4bc551cdcb3a4f6dd4a971c0d50f3f03eb59c73ae75554689077af0cdc85aa7765aa8944e8e3edd919380fcfea9742bf7391d54756a8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Unreleased
2
2
 
3
+ # 1.7.4
4
+
5
+ * Stop raising errors when encoutering various file system errors. The cache is now best effort,
6
+ if somehow it can't be saved, bootsnapp will gracefully fallback to the original operation (e.g. `Kernel.require`).
7
+ (#353, #177, #262)
8
+
9
+ # 1.7.3
10
+
11
+ * Disable YAML precompilation when encountering YAML tags. (#351)
12
+
13
+ # 1.7.2
14
+
15
+ * Fix compatibility with msgpack < 1. (#349)
16
+
17
+ # 1.7.1
18
+
19
+ * Warn Ruby 2.5 users if they turn ISeq caching on. (#327, #244)
20
+ * Disable ISeq caching for the whole 2.5.x series again.
21
+ * Better handle hashing of Ruby strings. (#318)
22
+
3
23
  # 1.7.0
4
24
 
5
25
  * Fix detection of YAML files in gems.
@@ -105,8 +105,7 @@ static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handl
105
105
  static VALUE bs_rb_precompile(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler);
106
106
 
107
107
  /* Helpers */
108
- static uint64_t fnv1a_64(const char *str);
109
- static void bs_cache_path(const char * cachedir, const char * path, char (* cache_path)[MAX_CACHEPATH_SIZE]);
108
+ static void bs_cache_path(const char * cachedir, const VALUE path, char (* cache_path)[MAX_CACHEPATH_SIZE]);
110
109
  static int bs_read_key(int fd, struct bs_cache_key * key);
111
110
  static int cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2);
112
111
  static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args);
@@ -211,7 +210,7 @@ bs_compile_option_crc32_set(VALUE self, VALUE crc32_v)
211
210
  * - 32 bits doesn't feel collision-resistant enough; 64 is nice.
212
211
  */
213
212
  static uint64_t
214
- fnv1a_64_iter(uint64_t h, const char *str)
213
+ fnv1a_64_iter_cstr(uint64_t h, const char *str)
215
214
  {
216
215
  unsigned char *s = (unsigned char *)str;
217
216
 
@@ -224,7 +223,21 @@ fnv1a_64_iter(uint64_t h, const char *str)
224
223
  }
225
224
 
226
225
  static uint64_t
227
- fnv1a_64(const char *str)
226
+ fnv1a_64_iter(uint64_t h, const VALUE str)
227
+ {
228
+ unsigned char *s = (unsigned char *)RSTRING_PTR(str);
229
+ unsigned char *str_end = (unsigned char *)RSTRING_PTR(str) + RSTRING_LEN(str);
230
+
231
+ while (s < str_end) {
232
+ h ^= (uint64_t)*s++;
233
+ h += (h << 1) + (h << 4) + (h << 5) + (h << 7) + (h << 8) + (h << 40);
234
+ }
235
+
236
+ return h;
237
+ }
238
+
239
+ static uint64_t
240
+ fnv1a_64(const VALUE str)
228
241
  {
229
242
  uint64_t h = (uint64_t)0xcbf29ce484222325ULL;
230
243
  return fnv1a_64_iter(h, str);
@@ -245,7 +258,7 @@ get_ruby_revision(void)
245
258
  } else {
246
259
  uint64_t hash;
247
260
 
248
- hash = fnv1a_64(StringValueCStr(ruby_revision));
261
+ hash = fnv1a_64(ruby_revision);
249
262
  return (uint32_t)(hash >> 32);
250
263
  }
251
264
  }
@@ -265,19 +278,19 @@ get_ruby_platform(void)
265
278
  VALUE ruby_platform;
266
279
 
267
280
  ruby_platform = rb_const_get(rb_cObject, rb_intern("RUBY_PLATFORM"));
268
- hash = fnv1a_64(RSTRING_PTR(ruby_platform));
281
+ hash = fnv1a_64(ruby_platform);
269
282
 
270
283
  #ifdef _WIN32
271
284
  return (uint32_t)(hash >> 32) ^ (uint32_t)GetVersion();
272
285
  #elif defined(__GLIBC__)
273
- hash = fnv1a_64_iter(hash, gnu_get_libc_version());
286
+ hash = fnv1a_64_iter_cstr(hash, gnu_get_libc_version());
274
287
  return (uint32_t)(hash >> 32);
275
288
  #else
276
289
  struct utsname utsname;
277
290
 
278
291
  /* Not worth crashing if this fails; lose extra cache invalidation potential */
279
292
  if (uname(&utsname) >= 0) {
280
- hash = fnv1a_64_iter(hash, utsname.version);
293
+ hash = fnv1a_64_iter_cstr(hash, utsname.version);
281
294
  }
282
295
 
283
296
  return (uint32_t)(hash >> 32);
@@ -292,13 +305,13 @@ get_ruby_platform(void)
292
305
  * The path will look something like: <cachedir>/12/34567890abcdef
293
306
  */
294
307
  static void
295
- bs_cache_path(const char * cachedir, const char * path, char (* cache_path)[MAX_CACHEPATH_SIZE])
308
+ bs_cache_path(const char * cachedir, const VALUE path, char (* cache_path)[MAX_CACHEPATH_SIZE])
296
309
  {
297
310
  uint64_t hash = fnv1a_64(path);
298
311
  uint8_t first_byte = (hash >> (64 - 8));
299
312
  uint64_t remainder = hash & 0x00ffffffffffffff;
300
313
 
301
- sprintf(*cache_path, "%s/%02x/%014llx", cachedir, first_byte, remainder);
314
+ sprintf(*cache_path, "%s/%02"PRIx8"/%014"PRIx64, cachedir, first_byte, remainder);
302
315
  }
303
316
 
304
317
  /*
@@ -344,7 +357,7 @@ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler, VALUE arg
344
357
  char cache_path[MAX_CACHEPATH_SIZE];
345
358
 
346
359
  /* generate cache path to cache_path */
347
- bs_cache_path(cachedir, path, &cache_path);
360
+ bs_cache_path(cachedir, path_v, &cache_path);
348
361
 
349
362
  return bs_fetch(path, path_v, cache_path, handler, args);
350
363
  }
@@ -371,7 +384,7 @@ bs_rb_precompile(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
371
384
  char cache_path[MAX_CACHEPATH_SIZE];
372
385
 
373
386
  /* generate cache path to cache_path */
374
- bs_cache_path(cachedir, path, &cache_path);
387
+ bs_cache_path(cachedir, path_v, &cache_path);
375
388
 
376
389
  return bs_precompile(path, path_v, cache_path, handler);
377
390
  }
@@ -451,8 +464,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, const char ** errn
451
464
  fd = open(path, O_RDONLY);
452
465
  if (fd < 0) {
453
466
  *errno_provenance = "bs_fetch:open_cache_file:open";
454
- if (errno == ENOENT) return CACHE_MISS;
455
- return ERROR_WITH_ERRNO;
467
+ return CACHE_MISS;
456
468
  }
457
469
  #ifdef _WIN32
458
470
  setmode(fd, O_BINARY);
@@ -750,9 +762,11 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
750
762
  /* If storage_data isn't a string, we can't cache it */
751
763
  if (!RB_TYPE_P(storage_data, T_STRING)) goto invalid_type_storage_data;
752
764
 
753
- /* Write the cache key and storage_data to the cache directory */
754
- res = atomic_write_cache_file(cache_path, &current_key, storage_data, &errno_provenance);
755
- if (res < 0) goto fail_errno;
765
+ /* Attempt to write the cache key and storage_data to the cache directory.
766
+ * We do however ignore any failures to persist the cache, as it's better
767
+ * to move along, than to interrupt the process.
768
+ */
769
+ atomic_write_cache_file(cache_path, &current_key, storage_data, &errno_provenance);
756
770
 
757
771
  /* Having written the cache, now convert storage_data to output_data */
758
772
  exception_tag = bs_storage_to_output(handler, args, storage_data, &output_data);
@@ -1,19 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
  require("mkmf")
3
- $CFLAGS << ' -O3 '
4
- $CFLAGS << ' -std=c99'
5
3
 
6
- # ruby.h has some -Wpedantic fails in some cases
7
- # (e.g. https://github.com/Shopify/bootsnap/issues/15)
8
- unless ['0', '', nil].include?(ENV['BOOTSNAP_PEDANTIC'])
9
- $CFLAGS << ' -Wall'
10
- $CFLAGS << ' -Werror'
11
- $CFLAGS << ' -Wextra'
12
- $CFLAGS << ' -Wpedantic'
4
+ if RUBY_ENGINE == 'ruby'
5
+ $CFLAGS << ' -O3 '
6
+ $CFLAGS << ' -std=c99'
13
7
 
14
- $CFLAGS << ' -Wno-unused-parameter' # VALUE self has to be there but we don't care what it is.
15
- $CFLAGS << ' -Wno-keyword-macro' # hiding return
16
- $CFLAGS << ' -Wno-gcc-compat' # ruby.h 2.6.0 on macos 10.14, dunno
17
- end
8
+ # ruby.h has some -Wpedantic fails in some cases
9
+ # (e.g. https://github.com/Shopify/bootsnap/issues/15)
10
+ unless ['0', '', nil].include?(ENV['BOOTSNAP_PEDANTIC'])
11
+ $CFLAGS << ' -Wall'
12
+ $CFLAGS << ' -Werror'
13
+ $CFLAGS << ' -Wextra'
14
+ $CFLAGS << ' -Wpedantic'
15
+
16
+ $CFLAGS << ' -Wno-unused-parameter' # VALUE self has to be there but we don't care what it is.
17
+ $CFLAGS << ' -Wno-keyword-macro' # hiding return
18
+ $CFLAGS << ' -Wno-gcc-compat' # ruby.h 2.6.0 on macos 10.14, dunno
19
+ end
18
20
 
19
- create_makefile("bootsnap/bootsnap")
21
+ create_makefile("bootsnap/bootsnap")
22
+ else
23
+ File.write("Makefile", dummy_makefile($srcdir).join(""))
24
+ end
data/lib/bootsnap.rb CHANGED
@@ -54,6 +54,11 @@ module Bootsnap
54
54
  "If you use Ruby 2.5 or newer this option is useless, if not upgrading is recommended."
55
55
  end
56
56
 
57
+ if compile_cache_iseq && !iseq_cache_supported?
58
+ warn "Ruby 2.5 has a bug that break code tracing when code is loaded from cache. It is recommened " \
59
+ "to turn `compile_cache_iseq` off on Ruby 2.5"
60
+ end
61
+
57
62
  Bootsnap::LoadPathCache.setup(
58
63
  cache_path: cache_dir + '/bootsnap/load-path-cache',
59
64
  development_mode: development_mode,
@@ -66,6 +71,13 @@ module Bootsnap
66
71
  )
67
72
  end
68
73
 
74
+ def self.iseq_cache_supported?
75
+ return @iseq_cache_supported if defined? @iseq_cache_supported
76
+
77
+ ruby_version = Gem::Version.new(RUBY_VERSION)
78
+ @iseq_cache_supported = ruby_version < Gem::Version.new('2.5.0') || ruby_version >= Gem::Version.new('2.6.0')
79
+ end
80
+
69
81
  def self.default_setup
70
82
  env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || ENV['ENV']
71
83
  development_mode = ['', nil, 'development'].include?(env)
@@ -92,14 +104,12 @@ module Bootsnap
92
104
  cache_dir = File.join(app_root, 'tmp', 'cache')
93
105
  end
94
106
 
95
- ruby_version = Gem::Version.new(RUBY_VERSION)
96
- iseq_cache_enabled = ruby_version < Gem::Version.new('2.5.0') || ruby_version >= Gem::Version.new('2.5.4')
97
107
 
98
108
  setup(
99
109
  cache_dir: cache_dir,
100
110
  development_mode: development_mode,
101
111
  load_path_cache: !ENV['DISABLE_BOOTSNAP_LOAD_PATH_CACHE'],
102
- compile_cache_iseq: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'] && iseq_cache_enabled,
112
+ compile_cache_iseq: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'] && iseq_cache_supported?,
103
113
  compile_cache_yaml: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'],
104
114
  )
105
115
 
@@ -8,8 +8,7 @@ module Bootsnap
8
8
  attr_accessor(:msgpack_factory, :cache_dir, :supported_options)
9
9
 
10
10
  def input_to_storage(contents, _)
11
- raise(Uncompilable) if contents.index("!ruby/object")
12
- obj = ::YAML.load(contents)
11
+ obj = strict_load(contents)
13
12
  msgpack_factory.dump(obj)
14
13
  rescue NoMethodError, RangeError
15
14
  # The object included things that we can't serialize
@@ -27,6 +26,13 @@ module Bootsnap
27
26
  ::YAML.load(data, **(kwargs || {}))
28
27
  end
29
28
 
29
+ def strict_load(payload, *args)
30
+ ast = ::YAML.parse(payload)
31
+ return ast unless ast
32
+ strict_visitor.create(*args).visit(ast)
33
+ end
34
+ ruby2_keywords :strict_load if respond_to?(:ruby2_keywords, true)
35
+
30
36
  def precompile(path, cache_dir: YAML.cache_dir)
31
37
  Bootsnap::CompileCache::Native.precompile(
32
38
  cache_dir,
@@ -51,22 +57,25 @@ module Bootsnap
51
57
  # see: https://github.com/msgpack/msgpack-ruby/pull/122
52
58
  factory = MessagePack::Factory.new
53
59
  factory.register_type(0x00, Symbol)
54
- factory.register_type(
55
- MessagePack::Timestamp::TYPE, # or just -1
56
- Time,
57
- packer: MessagePack::Time::Packer,
58
- unpacker: MessagePack::Time::Unpacker
59
- )
60
60
 
61
- marshal_fallback = {
62
- packer: ->(value) { Marshal.dump(value) },
63
- unpacker: ->(payload) { Marshal.load(payload) },
64
- }
65
- {
66
- Date => 0x01,
67
- Regexp => 0x02,
68
- }.each do |type, code|
69
- factory.register_type(code, type, marshal_fallback)
61
+ if defined? MessagePack::Timestamp
62
+ factory.register_type(
63
+ MessagePack::Timestamp::TYPE, # or just -1
64
+ Time,
65
+ packer: MessagePack::Time::Packer,
66
+ unpacker: MessagePack::Time::Unpacker
67
+ )
68
+
69
+ marshal_fallback = {
70
+ packer: ->(value) { Marshal.dump(value) },
71
+ unpacker: ->(payload) { Marshal.load(payload) },
72
+ }
73
+ {
74
+ Date => 0x01,
75
+ Regexp => 0x02,
76
+ }.each do |type, code|
77
+ factory.register_type(code, type, marshal_fallback)
78
+ end
70
79
  end
71
80
 
72
81
  self.msgpack_factory = factory
@@ -83,6 +92,17 @@ module Bootsnap
83
92
  end
84
93
  self.supported_options.freeze
85
94
  end
95
+
96
+ def strict_visitor
97
+ self::NoTagsVisitor ||= Class.new(Psych::Visitors::ToRuby) do
98
+ def visit(target)
99
+ if target.tag
100
+ raise Uncompilable, "YAML tags are not supported: #{target.tag}"
101
+ end
102
+ super
103
+ end
104
+ end
105
+ end
86
106
  end
87
107
 
88
108
  module Patch
@@ -10,8 +10,8 @@ module Bootsnap
10
10
  def initialize(store, path_obj, development_mode: false)
11
11
  @development_mode = development_mode
12
12
  @store = store
13
- @mutex = defined?(::Mutex) ? ::Mutex.new : ::Thread::Mutex.new # TODO: Remove once Ruby 2.2 support is dropped.
14
- @path_obj = path_obj.map! { |f| File.exist?(f) ? File.realpath(f) : f }
13
+ @mutex = Mutex.new
14
+ @path_obj = path_obj.map! { |f| PathScanner.os_path(File.exist?(f) ? File.realpath(f) : f.dup) }
15
15
  @has_relative_paths = nil
16
16
  reinitialize
17
17
  end
@@ -178,25 +178,42 @@ module Bootsnap
178
178
 
179
179
  if DLEXT2
180
180
  def search_index(f)
181
- try_index("#{f}#{DOT_RB}") || try_index("#{f}#{DLEXT}") || try_index("#{f}#{DLEXT2}") || try_index(f)
181
+ try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f + DLEXT2) || try_index(f)
182
182
  end
183
183
 
184
184
  def maybe_append_extension(f)
185
- try_ext("#{f}#{DOT_RB}") || try_ext("#{f}#{DLEXT}") || try_ext("#{f}#{DLEXT2}") || f
185
+ try_ext(f + DOT_RB) || try_ext(f + DLEXT) || try_ext(f + DLEXT2) || f
186
186
  end
187
187
  else
188
188
  def search_index(f)
189
- try_index("#{f}#{DOT_RB}") || try_index("#{f}#{DLEXT}") || try_index(f)
189
+ try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f)
190
190
  end
191
191
 
192
192
  def maybe_append_extension(f)
193
- try_ext("#{f}#{DOT_RB}") || try_ext("#{f}#{DLEXT}") || f
193
+ try_ext(f + DOT_RB) || try_ext(f + DLEXT) || f
194
194
  end
195
195
  end
196
196
 
197
- def try_index(f)
198
- if (p = @index[f])
199
- "#{p}/#{f}"
197
+ s = rand.to_s.force_encoding(Encoding::US_ASCII).freeze
198
+ if s.respond_to?(:-@)
199
+ if (-s).equal?(s) && (-s.dup).equal?(s)
200
+ def try_index(f)
201
+ if (p = @index[f])
202
+ -(File.join(p, f).freeze)
203
+ end
204
+ end
205
+ else
206
+ def try_index(f)
207
+ if (p = @index[f])
208
+ -File.join(p, f).untaint
209
+ end
210
+ end
211
+ end
212
+ else
213
+ def try_index(f)
214
+ if (p = @index[f])
215
+ File.join(p, f)
216
+ end
200
217
  end
201
218
  end
202
219
 
@@ -26,7 +26,7 @@ module Bootsnap
26
26
  class LoadedFeaturesIndex
27
27
  def initialize
28
28
  @lfi = {}
29
- @mutex = defined?(::Mutex) ? ::Mutex.new : ::Thread::Mutex.new # TODO: Remove once Ruby 2.2 support is dropped.
29
+ @mutex = Mutex.new
30
30
 
31
31
  # In theory the user could mutate $LOADED_FEATURES and invalidate our
32
32
  # cache. If this ever comes up in practice — or if you, the
@@ -33,10 +33,10 @@ module Bootsnap
33
33
  requirables = []
34
34
  walk(path, nil) do |relative_path, absolute_path, is_directory|
35
35
  if is_directory
36
- dirs << relative_path
36
+ dirs << os_path(relative_path)
37
37
  !contains_bundle_path || !absolute_path.start_with?(BUNDLE_PATH)
38
38
  elsif relative_path.end_with?(*REQUIRABLE_EXTENSIONS)
39
- requirables << relative_path
39
+ requirables << os_path(relative_path)
40
40
  end
41
41
  end
42
42
  [requirables, dirs]
@@ -45,7 +45,7 @@ module Bootsnap
45
45
  def walk(absolute_dir_path, relative_dir_path, &block)
46
46
  Dir.foreach(absolute_dir_path) do |name|
47
47
  next if name.start_with?('.')
48
- relative_path = relative_dir_path ? "#{relative_dir_path}/#{name}" : name.freeze
48
+ relative_path = relative_dir_path ? File.join(relative_dir_path, name) : name
49
49
 
50
50
  absolute_path = "#{absolute_dir_path}/#{name}"
51
51
  if File.directory?(absolute_path)
@@ -57,6 +57,17 @@ module Bootsnap
57
57
  end
58
58
  end
59
59
  end
60
+
61
+ if RUBY_VERSION >= '3.1'
62
+ def os_path(path)
63
+ path.freeze
64
+ end
65
+ else
66
+ def os_path(path)
67
+ path.force_encoding(Encoding::US_ASCII) if path.ascii_only?
68
+ path.freeze
69
+ end
70
+ end
60
71
  end
61
72
  end
62
73
  end
@@ -12,8 +12,7 @@ module Bootsnap
12
12
 
13
13
  def initialize(store_path)
14
14
  @store_path = store_path
15
- # TODO: Remove conditional once Ruby 2.2 support is dropped.
16
- @txn_mutex = defined?(::Mutex) ? ::Mutex.new : ::Thread::Mutex.new
15
+ @txn_mutex = Mutex.new
17
16
  @dirty = false
18
17
  load_data
19
18
  end
@@ -63,12 +62,18 @@ module Bootsnap
63
62
 
64
63
  def load_data
65
64
  @data = begin
66
- MessagePack.load(File.binread(@store_path))
67
- # handle malformed data due to upgrade incompatibility
68
- rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
69
- {}
70
- rescue ArgumentError => e
71
- e.message =~ /negative array size/ ? {} : raise
65
+ File.open(@store_path, encoding: Encoding::BINARY) do |io|
66
+ MessagePack.load(io)
67
+ end
68
+ # handle malformed data due to upgrade incompatibility
69
+ rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
70
+ {}
71
+ rescue ArgumentError => error
72
+ if error.message =~ /negative array size/
73
+ {}
74
+ else
75
+ raise
76
+ end
72
77
  end
73
78
  end
74
79
 
@@ -80,7 +85,9 @@ module Bootsnap
80
85
  exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY
81
86
  # `encoding:` looks redundant wrt `binwrite`, but necessary on windows
82
87
  # because binary is part of mode.
83
- File.binwrite(tmp, MessagePack.dump(@data), mode: exclusive_write, encoding: Encoding::BINARY)
88
+ File.open(tmp, mode: exclusive_write, encoding: Encoding::BINARY) do |io|
89
+ MessagePack.dump(@data, io, freeze: true)
90
+ end
84
91
  FileUtils.mv(tmp, @store_path)
85
92
  rescue Errno::EEXIST
86
93
  retry
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Bootsnap
3
- VERSION = "1.7.0"
3
+ VERSION = "1.7.4"
4
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.7.0
4
+ version: 1.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Burke Libbey
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-01 00:00:00.000000000 Z
11
+ date: 2021-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler