bootsnap 1.4.6 → 1.4.7

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: 2d4f38db9a609c2adb0a0ede991bd993dff7ae59885cb1722eb699658211fd96
4
- data.tar.gz: 9f363c21a154e123693f18e48073451c6cfe6c05ec378c980e6ef770f01e658c
3
+ metadata.gz: 3678f8871286d394bbfc31303d0123aae9374370aeda42701336206293447f9a
4
+ data.tar.gz: 88a8005d7a4fac49b6a1dde52e2d2ec891fd5fa35766cdfb46f52c83cf441b25
5
5
  SHA512:
6
- metadata.gz: 925f595e21911c61ff7cf3a86cb055d25e56bb65a8a6437c513f25bfea3aec6c086259808b5aed3289e5d82f66706f98314f31d2ff3886d85edeb47085d6a918
7
- data.tar.gz: 31507ba8393d47361f8332064a9a39220392a4242e1f3f3c3a88c4de032b51eb8aab8d3769869fec7f9da55400ce773c42aecc52604d5293c9ff7ea3f9f40e54
6
+ metadata.gz: 1025b1d2a7b60083e6e7bf460cf4aae1ad1c6b2376e024fae199ea0728837b897f417e89b30fcfb3a7fb3260993846566df0537523ee8f703f7bc7d5c1590ace
7
+ data.tar.gz: 64686090f0dcf1c8835b59690e700b0abd394edf399733cd2ca53d952bdd5f1cc3109d381bac8079f3e64e9c9e12913e132e1fdf07ea3262891914cef4f9c299
@@ -8,7 +8,7 @@ AllCops:
8
8
  TargetRubyVersion: '2.3'
9
9
 
10
10
  # This doesn't take into account retrying from an exception
11
- Lint/HandleExceptions:
11
+ Lint/SuppressedException:
12
12
  Enabled: false
13
13
 
14
14
  # allow String.new to create mutable strings
@@ -6,8 +6,10 @@ os:
6
6
  - osx
7
7
 
8
8
  rvm:
9
- - ruby-2.4
10
- - ruby-2.5
9
+ - '2.4'
10
+ - '2.5'
11
+ - '2.6'
12
+ - '2.7'
11
13
  - ruby-head
12
14
 
13
15
  matrix:
@@ -17,5 +19,7 @@ matrix:
17
19
  - rvm: jruby
18
20
  os: linux
19
21
  env: MINIMAL_SUPPORT=1
20
-
22
+ - rvm: truffleruby
23
+ os: linux
24
+ env: MINIMAL_SUPPORT=1
21
25
  script: bin/ci
@@ -1,3 +1,22 @@
1
+ # 1.4.7
2
+
3
+ * Various performance enhancements
4
+ * Fix race condition in heavy concurrent load scenarios that would cause bootsnap to raise
5
+
6
+ # 1.4.6
7
+
8
+ * Fix bug that was erroneously considering that files containing `.` in the names were being
9
+ required if a different file with the same name was already being required
10
+
11
+ Example:
12
+
13
+ require 'foo'
14
+ require 'foo.en'
15
+
16
+ Before bootsnap was considering `foo.en` to be the same file as `foo`
17
+
18
+ * Use glibc as part of the ruby_platform cache key
19
+
1
20
  # 1.4.5
2
21
 
3
22
  * MRI 2.7 support
data/Rakefile CHANGED
@@ -10,4 +10,8 @@ Rake::ExtensionTask.new do |ext|
10
10
  ext.gem_spec = gemspec
11
11
  end
12
12
 
13
- task(default: :compile)
13
+ task :test do
14
+ sh 'bin/testunit'
15
+ end
16
+
17
+ task(default: %i(compile test))
data/bin/ci CHANGED
@@ -5,6 +5,5 @@ set -euxo pipefail
5
5
  if [[ "${MINIMAL_SUPPORT-0}" -eq 1 ]]; then
6
6
  exec bin/test-minimal-support
7
7
  else
8
- rake
9
- exec bin/testunit
8
+ exec rake
10
9
  fi
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
37
37
  end
38
38
 
39
39
  spec.add_development_dependency("bundler")
40
- spec.add_development_dependency('rake', '~> 10.0')
40
+ spec.add_development_dependency('rake')
41
41
  spec.add_development_dependency('rake-compiler', '~> 0')
42
42
  spec.add_development_dependency("minitest", "~> 5.0")
43
43
  spec.add_development_dependency("mocha", "~> 1.2")
@@ -32,6 +32,8 @@
32
32
 
33
33
  #define KEY_SIZE 64
34
34
 
35
+ #define MAX_CREATE_TEMPFILE_ATTEMPT 3
36
+
35
37
  /*
36
38
  * An instance of this key is written as the first 64 bytes of each cache file.
37
39
  * The mtime and size members track whether the file contents have changed, and
@@ -499,25 +501,32 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, cons
499
501
  {
500
502
  char template[MAX_CACHEPATH_SIZE + 20];
501
503
  char * tmp_path;
502
- int fd, ret;
504
+ int fd, ret, attempt;
503
505
  ssize_t nwrite;
504
506
 
505
- tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
506
- strcat(tmp_path, ".tmp.XXXXXX");
507
+ for (attempt = 0; attempt < MAX_CREATE_TEMPFILE_ATTEMPT; ++attempt) {
508
+ tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
509
+ strcat(tmp_path, ".tmp.XXXXXX");
507
510
 
508
- // mkstemp modifies the template to be the actual created path
509
- fd = mkstemp(tmp_path);
510
- if (fd < 0) {
511
- if (mkpath(tmp_path, 0775) < 0) {
511
+ // mkstemp modifies the template to be the actual created path
512
+ fd = mkstemp(tmp_path);
513
+ if (fd > 0) break;
514
+
515
+ if (attempt == 0 && mkpath(tmp_path, 0775) < 0) {
512
516
  *errno_provenance = "bs_fetch:atomic_write_cache_file:mkpath";
513
517
  return -1;
514
518
  }
515
- fd = open(tmp_path, O_WRONLY | O_CREAT, 0664);
516
- if (fd < 0) {
517
- *errno_provenance = "bs_fetch:atomic_write_cache_file:open";
518
- return -1;
519
- }
520
519
  }
520
+ if (fd < 0) {
521
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:mkstemp";
522
+ return -1;
523
+ }
524
+
525
+ if (chmod(tmp_path, 0644) < 0) {
526
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:chmod";
527
+ return -1;
528
+ }
529
+
521
530
  #ifdef _WIN32
522
531
  setmode(fd, O_BINARY);
523
532
  #endif
@@ -800,7 +809,7 @@ try_input_to_storage(VALUE arg)
800
809
  }
801
810
 
802
811
  static VALUE
803
- rescue_input_to_storage(VALUE arg)
812
+ rescue_input_to_storage(VALUE arg, VALUE e)
804
813
  {
805
814
  return uncompilable;
806
815
  }
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative('bootsnap/version')
3
4
  require_relative('bootsnap/bundler')
4
5
  require_relative('bootsnap/load_path_cache')
@@ -46,7 +46,7 @@ module Bootsnap
46
46
  # loadpath.
47
47
  def find(feature)
48
48
  reinitialize if (@has_relative_paths && dir_changed?) || stale?
49
- feature = feature.to_s
49
+ feature = feature.to_s.freeze
50
50
  return feature if absolute_path?(feature)
51
51
  return expand_path(feature) if feature.start_with?('./')
52
52
  @mutex.synchronize do
@@ -178,25 +178,25 @@ 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
197
  def try_index(f)
198
198
  if (p = @index[f])
199
- p + '/' + f
199
+ "#{p}/#{f}"
200
200
  end
201
201
  end
202
202
 
@@ -26,7 +26,7 @@ module Bootsnap
26
26
  super
27
27
  end
28
28
 
29
- # uniq! keeps the first occurance of each path, otherwise preserving
29
+ # uniq! keeps the first occurrence of each path, otherwise preserving
30
30
  # order, preserving the effective load path
31
31
  def uniq!(*args)
32
32
  ret = super
@@ -56,7 +56,7 @@ module Kernel
56
56
  end
57
57
 
58
58
  # load also allows relative paths from pwd even when not in $:
59
- if File.exist?(relative = File.expand_path(path))
59
+ if File.exist?(relative = File.expand_path(path).freeze)
60
60
  return load_without_bootsnap(relative, wrap)
61
61
  end
62
62
 
@@ -99,7 +99,7 @@ module Bootsnap
99
99
  altname = if extension_elidable?(short)
100
100
  # Strip the extension off, e.g. 'bundler.rb' -> 'bundler'.
101
101
  strip_extension_if_elidable(short)
102
- elsif long && (ext = File.extname(long))
102
+ elsif long && (ext = File.extname(long.freeze))
103
103
  # We already know the extension of the actual file this
104
104
  # resolves to, so put that back on.
105
105
  short + ext
@@ -129,7 +129,7 @@ module Bootsnap
129
129
  # to name files in a way that assumes otherwise.
130
130
  # (E.g. It's unlikely that someone will know that their code
131
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'.)
132
+ # with calling a Ruby file 'x.dylib.rb' and then requiring it as 'x.dylib'.)
133
133
  #
134
134
  # See <https://ruby-doc.org/core-2.6.4/Kernel.html#method-i-require>.
135
135
  def extension_elidable?(f)
@@ -21,7 +21,7 @@ module Bootsnap
21
21
  attr_reader(:path)
22
22
 
23
23
  def initialize(path)
24
- @path = path.to_s
24
+ @path = path.to_s.freeze
25
25
  end
26
26
 
27
27
  # True if the path exists, but represents a non-directory object
@@ -60,7 +60,7 @@ module Bootsnap
60
60
  end
61
61
 
62
62
  def expanded_path
63
- File.expand_path(path)
63
+ File.expand_path(path).freeze
64
64
  end
65
65
 
66
66
  private
@@ -5,7 +5,6 @@ require_relative('../explicit_require')
5
5
  module Bootsnap
6
6
  module LoadPathCache
7
7
  module PathScanner
8
- ALL_FILES = "/{,**/*/**/}*"
9
8
  REQUIRABLE_EXTENSIONS = [DOT_RB] + DL_EXTENSIONS
10
9
  NORMALIZE_NATIVE_EXTENSIONS = !DL_EXTENSIONS.include?(LoadPathCache::DOT_SO)
11
10
  ALTERNATIVE_NATIVE_EXTENSIONS_PATTERN = /\.(o|bundle|dylib)\z/
@@ -16,34 +15,48 @@ module Bootsnap
16
15
  ''
17
16
  end
18
17
 
19
- def self.call(path)
20
- path = path.to_s
21
-
22
- relative_slice = (path.size + 1)..-1
23
- # If the bundle path is a descendent of this path, we do additional
24
- # checks to prevent recursing into the bundle path as we recurse
25
- # through this path. We don't want to scan the bundle path because
26
- # anything useful in it will be present on other load path items.
27
- #
28
- # This can happen if, for example, the user adds '.' to the load path,
29
- # and the bundle path is '.bundle'.
30
- contains_bundle_path = BUNDLE_PATH.start_with?(path)
31
-
32
- dirs = []
33
- requirables = []
34
-
35
- Dir.glob(path + ALL_FILES).each do |absolute_path|
36
- next if contains_bundle_path && absolute_path.start_with?(BUNDLE_PATH)
37
- relative_path = absolute_path.slice(relative_slice)
38
-
39
- if File.directory?(absolute_path)
40
- dirs << relative_path
41
- elsif REQUIRABLE_EXTENSIONS.include?(File.extname(relative_path))
42
- requirables << relative_path
18
+ class << self
19
+ def call(path)
20
+ path = File.expand_path(path.to_s).freeze
21
+ return [[], []] unless File.directory?(path)
22
+
23
+ # If the bundle path is a descendent of this path, we do additional
24
+ # checks to prevent recursing into the bundle path as we recurse
25
+ # through this path. We don't want to scan the bundle path because
26
+ # anything useful in it will be present on other load path items.
27
+ #
28
+ # This can happen if, for example, the user adds '.' to the load path,
29
+ # and the bundle path is '.bundle'.
30
+ contains_bundle_path = BUNDLE_PATH.start_with?(path)
31
+
32
+ dirs = []
33
+ requirables = []
34
+ walk(path, nil) do |relative_path, absolute_path, is_directory|
35
+ if is_directory
36
+ dirs << relative_path
37
+ !contains_bundle_path || !absolute_path.start_with?(BUNDLE_PATH)
38
+ elsif relative_path.end_with?(*REQUIRABLE_EXTENSIONS)
39
+ requirables << relative_path
40
+ end
43
41
  end
42
+ [requirables, dirs]
44
43
  end
45
44
 
46
- [requirables, dirs]
45
+ def walk(absolute_dir_path, relative_dir_path, &block)
46
+ Dir.foreach(absolute_dir_path) do |name|
47
+ next if name.start_with?('.')
48
+ relative_path = relative_dir_path ? "#{relative_dir_path}/#{name}" : name.freeze
49
+
50
+ absolute_path = "#{absolute_dir_path}/#{name}"
51
+ if File.directory?(absolute_path)
52
+ if yield relative_path, absolute_path, true
53
+ walk(absolute_path, relative_path, &block)
54
+ end
55
+ else
56
+ yield relative_path, absolute_path, false
57
+ end
58
+ end
59
+ end
47
60
  end
48
61
  end
49
62
  end
@@ -15,15 +15,15 @@ module Bootsnap
15
15
 
16
16
  def realpath(caller_location, path)
17
17
  base = File.dirname(caller_location)
18
- file = find_file(File.expand_path(path, base))
19
- dir = File.dirname(file)
20
- File.join(dir, File.basename(file))
18
+ abspath = File.expand_path(path, base).freeze
19
+ find_file(abspath)
21
20
  end
22
21
 
23
22
  def find_file(name)
24
- ['', *CACHED_EXTENSIONS].each do |ext|
23
+ return File.realpath(name).freeze if File.exist?(name)
24
+ CACHED_EXTENSIONS.each do |ext|
25
25
  filename = "#{name}#{ext}"
26
- return File.realpath(filename) if File.exist?(filename)
26
+ return File.realpath(filename).freeze if File.exist?(filename)
27
27
  end
28
28
  name
29
29
  end
@@ -64,7 +64,7 @@ module Bootsnap
64
64
  def load_data
65
65
  @data = begin
66
66
  MessagePack.load(File.binread(@store_path))
67
- # handle malformed data due to upgrade incompatability
67
+ # handle malformed data due to upgrade incompatibility
68
68
  rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
69
69
  {}
70
70
  rescue ArgumentError => e
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Bootsnap
3
- VERSION = "1.4.6"
3
+ VERSION = "1.4.7"
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.4.6
4
+ version: 1.4.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Burke Libbey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-24 00:00:00.000000000 Z
11
+ date: 2020-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake-compiler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -167,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
167
  - !ruby/object:Gem::Version
168
168
  version: '0'
169
169
  requirements: []
170
- rubygems_version: 3.0.6
170
+ rubygems_version: 3.0.2
171
171
  signing_key:
172
172
  specification_version: 4
173
173
  summary: Boot large ruby/rails apps faster