bootsnap 1.1.8 → 1.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +121 -0
  3. data/README.md +72 -14
  4. data/exe/bootsnap +5 -0
  5. data/ext/bootsnap/bootsnap.c +283 -105
  6. data/ext/bootsnap/extconf.rb +21 -14
  7. data/lib/bootsnap.rb +95 -14
  8. data/lib/bootsnap/bundler.rb +6 -3
  9. data/lib/bootsnap/cli.rb +246 -0
  10. data/lib/bootsnap/cli/worker_pool.rb +131 -0
  11. data/lib/bootsnap/compile_cache.rb +32 -4
  12. data/lib/bootsnap/compile_cache/iseq.rb +32 -15
  13. data/lib/bootsnap/compile_cache/yaml.rb +97 -40
  14. data/lib/bootsnap/explicit_require.rb +2 -1
  15. data/lib/bootsnap/load_path_cache.rb +33 -20
  16. data/lib/bootsnap/load_path_cache/cache.rb +65 -29
  17. data/lib/bootsnap/load_path_cache/change_observer.rb +36 -29
  18. data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +70 -53
  19. data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +18 -0
  20. data/lib/bootsnap/load_path_cache/loaded_features_index.rb +148 -0
  21. data/lib/bootsnap/load_path_cache/path.rb +8 -7
  22. data/lib/bootsnap/load_path_cache/path_scanner.rb +61 -39
  23. data/lib/bootsnap/load_path_cache/realpath_cache.rb +32 -0
  24. data/lib/bootsnap/load_path_cache/store.rb +27 -14
  25. data/lib/bootsnap/setup.rb +3 -40
  26. data/lib/bootsnap/version.rb +2 -1
  27. metadata +26 -29
  28. data/.gitignore +0 -17
  29. data/.rubocop.yml +0 -20
  30. data/.travis.yml +0 -4
  31. data/CODE_OF_CONDUCT.md +0 -74
  32. data/CONTRIBUTING.md +0 -21
  33. data/Gemfile +0 -8
  34. data/Rakefile +0 -11
  35. data/bin/console +0 -14
  36. data/bin/setup +0 -8
  37. data/bin/testunit +0 -8
  38. data/bootsnap.gemspec +0 -39
  39. data/dev.yml +0 -10
  40. data/lib/bootsnap/load_path_cache/core_ext/active_support.rb +0 -75
@@ -1,51 +1,73 @@
1
- require_relative '../explicit_require'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative('../explicit_require')
2
4
 
3
5
  module Bootsnap
4
6
  module LoadPathCache
5
7
  module PathScanner
6
- # Glob pattern to find requirable files and subdirectories in given path.
7
- # It expands to:
8
- #
9
- # * `/*{.rb,.so,/}` - It matches requirable files, directories and
10
- # symlinks to directories at given path.
11
- # * `/*/**/*{.rb,.so,/}` - It matches requirable files and
12
- # subdirectories in any (even symlinked) directory at given path at
13
- # any directory tree depth.
14
- #
15
- REQUIRABLES_AND_DIRS = "/{,*/**/}*{#{DOT_RB},#{DL_EXTENSIONS.join(',')},/}"
8
+ REQUIRABLE_EXTENSIONS = [DOT_RB] + DL_EXTENSIONS
16
9
  NORMALIZE_NATIVE_EXTENSIONS = !DL_EXTENSIONS.include?(LoadPathCache::DOT_SO)
17
10
  ALTERNATIVE_NATIVE_EXTENSIONS_PATTERN = /\.(o|bundle|dylib)\z/
18
- BUNDLE_PATH = Bootsnap.bundler? ?
19
- (Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze : ''.freeze
20
-
21
- def self.call(path)
22
- path = path.to_s
23
-
24
- relative_slice = (path.size + 1)..-1
25
- # If the bundle path is a descendent of this path, we do additional
26
- # checks to prevent recursing into the bundle path as we recurse
27
- # through this path. We don't want to scan the bundle path because
28
- # anything useful in it will be present on other load path items.
29
- #
30
- # This can happen if, for example, the user adds '.' to the load path,
31
- # and the bundle path is '.bundle'.
32
- contains_bundle_path = BUNDLE_PATH.start_with?(path)
33
-
34
- dirs = []
35
- requirables = []
36
-
37
- Dir.glob(path + REQUIRABLES_AND_DIRS).each do |absolute_path|
38
- next if contains_bundle_path && absolute_path.start_with?(BUNDLE_PATH)
39
- relative_path = absolute_path.slice!(relative_slice)
40
-
41
- if relative_path.end_with?('/')
42
- dirs << relative_path[0..-2]
43
- else
44
- requirables << relative_path
11
+
12
+ BUNDLE_PATH = if Bootsnap.bundler?
13
+ (Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze
14
+ else
15
+ ''
16
+ end
17
+
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 << os_path(relative_path)
37
+ !contains_bundle_path || !absolute_path.start_with?(BUNDLE_PATH)
38
+ elsif relative_path.end_with?(*REQUIRABLE_EXTENSIONS)
39
+ requirables << os_path(relative_path)
40
+ end
45
41
  end
42
+ [requirables, dirs]
46
43
  end
47
44
 
48
- [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 ? File.join(relative_dir_path, name) : name
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
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
49
71
  end
50
72
  end
51
73
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bootsnap
4
+ module LoadPathCache
5
+ class RealpathCache
6
+ def initialize
7
+ @cache = Hash.new { |h, k| h[k] = realpath(*k) }
8
+ end
9
+
10
+ def call(*key)
11
+ @cache[key]
12
+ end
13
+
14
+ private
15
+
16
+ def realpath(caller_location, path)
17
+ base = File.dirname(caller_location)
18
+ abspath = File.expand_path(path, base).freeze
19
+ find_file(abspath)
20
+ end
21
+
22
+ def find_file(name)
23
+ return File.realpath(name).freeze if File.exist?(name)
24
+ CACHED_EXTENSIONS.each do |ext|
25
+ filename = "#{name}#{ext}"
26
+ return File.realpath(filename).freeze if File.exist?(filename)
27
+ end
28
+ name
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,6 +1,7 @@
1
- require_relative '../explicit_require'
1
+ # frozen_string_literal: true
2
+ require_relative('../explicit_require')
2
3
 
3
- Bootsnap::ExplicitRequire.with_gems('msgpack') { require 'msgpack' }
4
+ Bootsnap::ExplicitRequire.with_gems('msgpack') { require('msgpack') }
4
5
  Bootsnap::ExplicitRequire.from_rubylibdir('fileutils')
5
6
 
6
7
  module Bootsnap
@@ -11,7 +12,7 @@ module Bootsnap
11
12
 
12
13
  def initialize(store_path)
13
14
  @store_path = store_path
14
- @in_txn = false
15
+ @txn_mutex = Mutex.new
15
16
  @dirty = false
16
17
  load_data
17
18
  end
@@ -21,7 +22,7 @@ module Bootsnap
21
22
  end
22
23
 
23
24
  def fetch(key)
24
- raise SetOutsideTransactionNotAllowed unless @in_txn
25
+ raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
25
26
  v = get(key)
26
27
  unless v
27
28
  @dirty = true
@@ -32,7 +33,7 @@ module Bootsnap
32
33
  end
33
34
 
34
35
  def set(key, value)
35
- raise SetOutsideTransactionNotAllowed unless @in_txn
36
+ raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
36
37
  if value != @data[key]
37
38
  @dirty = true
38
39
  @data[key] = value
@@ -40,12 +41,14 @@ module Bootsnap
40
41
  end
41
42
 
42
43
  def transaction
43
- raise NestedTransactionError if @in_txn
44
- @in_txn = true
45
- yield
46
- ensure
47
- commit_transaction
48
- @in_txn = false
44
+ raise(NestedTransactionError) if @txn_mutex.owned?
45
+ @txn_mutex.synchronize do
46
+ begin
47
+ yield
48
+ ensure
49
+ commit_transaction
50
+ end
51
+ end
49
52
  end
50
53
 
51
54
  private
@@ -59,10 +62,18 @@ module Bootsnap
59
62
 
60
63
  def load_data
61
64
  @data = begin
62
- MessagePack.load(File.binread(@store_path))
63
- # handle malformed data due to upgrade incompatability
65
+ File.open(@store_path, encoding: Encoding::BINARY) do |io|
66
+ MessagePack.load(io)
67
+ end
68
+ # handle malformed data due to upgrade incompatibility
64
69
  rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
65
70
  {}
71
+ rescue ArgumentError => error
72
+ if error.message =~ /negative array size/
73
+ {}
74
+ else
75
+ raise
76
+ end
66
77
  end
67
78
  end
68
79
 
@@ -74,7 +85,9 @@ module Bootsnap
74
85
  exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY
75
86
  # `encoding:` looks redundant wrt `binwrite`, but necessary on windows
76
87
  # because binary is part of mode.
77
- 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
78
91
  FileUtils.mv(tmp, @store_path)
79
92
  rescue Errno::EEXIST
80
93
  retry
@@ -1,41 +1,4 @@
1
- require_relative '../bootsnap'
1
+ # frozen_string_literal: true
2
+ require_relative('../bootsnap')
2
3
 
3
- env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || ENV['ENV']
4
- development_mode = ['', nil, 'development'].include?(env)
5
-
6
- # only enable on 'ruby' (MRI), POSIX (darin, linux, *bsd), and >= 2.3.0
7
- enable_cc =
8
- RUBY_ENGINE == 'ruby' &&
9
- RUBY_PLATFORM =~ /darwin|linux|bsd/ &&
10
- Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
11
-
12
- cache_dir = ENV['BOOTSNAP_CACHE_DIR']
13
- unless cache_dir
14
- config_dir_frame = caller.detect do |line|
15
- line.include?('/config/')
16
- end
17
-
18
- unless config_dir_frame
19
- $stderr.puts "[bootsnap/setup] couldn't infer cache directory! Either:"
20
- $stderr.puts "[bootsnap/setup] 1. require bootsnap/setup from your application's config directory; or"
21
- $stderr.puts "[bootsnap/setup] 2. Define the environment variable BOOTSNAP_CACHE_DIR"
22
-
23
- raise "couldn't infer bootsnap cache directory"
24
- end
25
-
26
- path = config_dir_frame.split(/:\d+:/).first
27
- path = File.dirname(path) until File.basename(path) == 'config'
28
- app_root = File.dirname(path)
29
-
30
- cache_dir = File.join(app_root, 'tmp', 'cache')
31
- end
32
-
33
- Bootsnap.setup(
34
- cache_dir: cache_dir,
35
- development_mode: development_mode,
36
- load_path_cache: true,
37
- autoload_paths_cache: true, # assume rails. open to PRs to impl. detection
38
- disable_trace: false,
39
- compile_cache_iseq: enable_cc,
40
- compile_cache_yaml: enable_cc
41
- )
4
+ Bootsnap.default_setup
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Bootsnap
2
- VERSION = "1.1.8"
3
+ VERSION = "1.7.2"
3
4
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bootsnap
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.8
4
+ version: 1.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Burke Libbey
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-05 00:00:00.000000000 Z
11
+ date: 2021-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
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
@@ -97,31 +97,23 @@ dependencies:
97
97
  description: Boot large ruby/rails apps faster
98
98
  email:
99
99
  - burke.libbey@shopify.com
100
- executables: []
100
+ executables:
101
+ - bootsnap
101
102
  extensions:
102
103
  - ext/bootsnap/extconf.rb
103
104
  extra_rdoc_files: []
104
105
  files:
105
- - ".gitignore"
106
- - ".rubocop.yml"
107
- - ".travis.yml"
108
106
  - CHANGELOG.md
109
- - CODE_OF_CONDUCT.md
110
- - CONTRIBUTING.md
111
- - Gemfile
112
107
  - LICENSE.txt
113
108
  - README.md
114
- - Rakefile
115
- - bin/console
116
- - bin/setup
117
- - bin/testunit
118
- - bootsnap.gemspec
119
- - dev.yml
109
+ - exe/bootsnap
120
110
  - ext/bootsnap/bootsnap.c
121
111
  - ext/bootsnap/bootsnap.h
122
112
  - ext/bootsnap/extconf.rb
123
113
  - lib/bootsnap.rb
124
114
  - lib/bootsnap/bundler.rb
115
+ - lib/bootsnap/cli.rb
116
+ - lib/bootsnap/cli/worker_pool.rb
125
117
  - lib/bootsnap/compile_cache.rb
126
118
  - lib/bootsnap/compile_cache/iseq.rb
127
119
  - lib/bootsnap/compile_cache/yaml.rb
@@ -129,17 +121,23 @@ files:
129
121
  - lib/bootsnap/load_path_cache.rb
130
122
  - lib/bootsnap/load_path_cache/cache.rb
131
123
  - lib/bootsnap/load_path_cache/change_observer.rb
132
- - lib/bootsnap/load_path_cache/core_ext/active_support.rb
133
124
  - lib/bootsnap/load_path_cache/core_ext/kernel_require.rb
125
+ - lib/bootsnap/load_path_cache/core_ext/loaded_features.rb
126
+ - lib/bootsnap/load_path_cache/loaded_features_index.rb
134
127
  - lib/bootsnap/load_path_cache/path.rb
135
128
  - lib/bootsnap/load_path_cache/path_scanner.rb
129
+ - lib/bootsnap/load_path_cache/realpath_cache.rb
136
130
  - lib/bootsnap/load_path_cache/store.rb
137
131
  - lib/bootsnap/setup.rb
138
132
  - lib/bootsnap/version.rb
139
133
  homepage: https://github.com/Shopify/bootsnap
140
134
  licenses:
141
135
  - MIT
142
- metadata: {}
136
+ metadata:
137
+ bug_tracker_uri: https://github.com/Shopify/bootsnap/issues
138
+ changelog_uri: https://github.com/Shopify/bootsnap/blob/master/CHANGELOG.md
139
+ source_code_uri: https://github.com/Shopify/bootsnap
140
+ allowed_push_host: https://rubygems.org
143
141
  post_install_message:
144
142
  rdoc_options: []
145
143
  require_paths:
@@ -148,15 +146,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
146
  requirements:
149
147
  - - ">="
150
148
  - !ruby/object:Gem::Version
151
- version: 2.0.0
149
+ version: 2.3.0
152
150
  required_rubygems_version: !ruby/object:Gem::Requirement
153
151
  requirements:
154
152
  - - ">="
155
153
  - !ruby/object:Gem::Version
156
154
  version: '0'
157
155
  requirements: []
158
- rubyforge_project:
159
- rubygems_version: 2.6.14
156
+ rubygems_version: 3.0.3
160
157
  signing_key:
161
158
  specification_version: 4
162
159
  summary: Boot large ruby/rails apps faster
data/.gitignore DELETED
@@ -1,17 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- *.bundle
11
- *.so
12
- *.o
13
- *.a
14
- *.gem
15
- *.db
16
- mkmf.log
17
- .rubocop-*
data/.rubocop.yml DELETED
@@ -1,20 +0,0 @@
1
- inherit_from:
2
- - http://shopify.github.io/ruby-style-guide/rubocop.yml
3
-
4
- AllCops:
5
- Exclude:
6
- - 'vendor/**/*'
7
- - 'tmp/**/*'
8
- TargetRubyVersion: '2.2'
9
-
10
- # This doesn't take into account retrying from an exception
11
- Lint/HandleExceptions:
12
- Enabled: false
13
-
14
- # allow String.new to create mutable strings
15
- Style/EmptyLiteral:
16
- Enabled: false
17
-
18
- # allow the use of globals which makes sense in a CLI app like this
19
- Style/GlobalVars:
20
- Enabled: false