bootsnap 1.1.8 → 1.7.2

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