bootsnap 1.7.0 → 1.7.4

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: 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