bootsnap 1.8.1 → 1.9.0

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: 4565db3033321cbf9866e33e0d42021d76f164974154bfb62dc9bcb02082763c
4
- data.tar.gz: 48424a914d66bebe2029e2bbdb86aef1c0d684a9a773f219a54b4c2675aec0b4
3
+ metadata.gz: 40e9beab427c546339a38041cdc59b826389b30d1976fb9586b6782daf728ed3
4
+ data.tar.gz: 1cfa891e84615fe3ed6d76a8c222420568c9ddb09077378199f6ba8862789d9f
5
5
  SHA512:
6
- metadata.gz: 05732a91a5437872eb83b96fcf1fa2db302acf599a53ca5a25c5ef9b628eef780051173f5081261a2491798ea71a005af180504da19707a09c52692eb01d65c3
7
- data.tar.gz: b19e9db48806a6cee08f9de5268c81fb235d577e8771f6acb238843a507856cb120fce3d63bec7d4664d4c88ea60f01ebb7acd8545ffa10291a3157dd25ebf89
6
+ metadata.gz: 5d74ccbd9cadf8fa00e6cef7c4159a34448a2f5e8fb0b94b6e63ee3b0032f1555ca613706821236965ad6f005f00eb305727e6eb62a6125c449a419bbb1db34a
7
+ data.tar.gz: 5a2e9d7e599797747370bbf3733ed442a795f69f040f2fa5db0736132de815a4c6a82254cf988602aec47c10fbfb73e696bf752581723a83b241a22f5d08b2c2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Unreleased
2
2
 
3
+ # 1.9.0
4
+
5
+ * Added a compilation cache for `JSON.load_file`. (#370)
6
+
3
7
  # 1.8.1
4
8
 
5
9
  * Fixed support for older Psych. (#369)
data/lib/bootsnap/cli.rb CHANGED
@@ -21,7 +21,7 @@ module Bootsnap
21
21
 
22
22
  attr_reader :cache_dir, :argv
23
23
 
24
- attr_accessor :compile_gemfile, :exclude, :verbose, :iseq, :yaml, :jobs
24
+ attr_accessor :compile_gemfile, :exclude, :verbose, :iseq, :yaml, :json, :jobs
25
25
 
26
26
  def initialize(argv)
27
27
  @argv = argv
@@ -32,37 +32,44 @@ module Bootsnap
32
32
  self.jobs = Etc.nprocessors
33
33
  self.iseq = true
34
34
  self.yaml = true
35
+ self.json = true
35
36
  end
36
37
 
37
38
  def precompile_command(*sources)
38
39
  require 'bootsnap/compile_cache/iseq'
39
40
  require 'bootsnap/compile_cache/yaml'
41
+ require 'bootsnap/compile_cache/json'
40
42
 
41
43
  fix_default_encoding do
42
44
  Bootsnap::CompileCache::ISeq.cache_dir = self.cache_dir
43
45
  Bootsnap::CompileCache::YAML.init!
44
46
  Bootsnap::CompileCache::YAML.cache_dir = self.cache_dir
47
+ Bootsnap::CompileCache::JSON.init!
48
+ Bootsnap::CompileCache::JSON.cache_dir = self.cache_dir
45
49
 
46
50
  @work_pool = WorkerPool.create(size: jobs, jobs: {
47
51
  ruby: method(:precompile_ruby),
48
52
  yaml: method(:precompile_yaml),
53
+ json: method(:precompile_json),
49
54
  })
50
55
  @work_pool.spawn
51
56
 
52
57
  main_sources = sources.map { |d| File.expand_path(d) }
53
58
  precompile_ruby_files(main_sources)
54
59
  precompile_yaml_files(main_sources)
60
+ precompile_json_files(main_sources)
55
61
 
56
62
  if compile_gemfile
57
63
  # Some gems embed their tests, they're very unlikely to be loaded, so not worth precompiling.
58
64
  gem_exclude = Regexp.union([exclude, '/spec/', '/test/'].compact)
59
65
  precompile_ruby_files($LOAD_PATH.map { |d| File.expand_path(d) }, exclude: gem_exclude)
60
66
 
61
- # Gems that include YAML files usually don't put them in `lib/`.
67
+ # Gems that include JSON or YAML files usually don't put them in `lib/`.
62
68
  # So we look at the gem root.
63
69
  gem_pattern = %r{^#{Regexp.escape(Bundler.bundle_path.to_s)}/?(?:bundler/)?gems\/[^/]+}
64
70
  gem_paths = $LOAD_PATH.map { |p| p[gem_pattern] }.compact.uniq
65
71
  precompile_yaml_files(gem_paths, exclude: gem_exclude)
72
+ precompile_json_files(gem_paths, exclude: gem_exclude)
66
73
  end
67
74
 
68
75
  if exitstatus = @work_pool.shutdown
@@ -137,6 +144,29 @@ module Bootsnap
137
144
  end
138
145
  end
139
146
 
147
+ def precompile_json_files(load_paths, exclude: self.exclude)
148
+ return unless json
149
+
150
+ load_paths.each do |path|
151
+ if !exclude || !exclude.match?(path)
152
+ list_files(path, '**/*.json').each do |json_file|
153
+ # We ignore hidden files to not match the various .config.json files
154
+ if !File.basename(json_file).start_with?('.') && (!exclude || !exclude.match?(json_file))
155
+ @work_pool.push(:json, json_file)
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ def precompile_json(*json_files)
163
+ Array(json_files).each do |json_file|
164
+ if p(CompileCache::JSON.precompile(json_file, cache_dir: cache_dir))
165
+ STDERR.puts(json_file) if verbose
166
+ end
167
+ end
168
+ end
169
+
140
170
  def precompile_ruby_files(load_paths, exclude: self.exclude)
141
171
  return unless iseq
142
172
 
@@ -240,6 +270,11 @@ module Bootsnap
240
270
  Disable YAML precompilation.
241
271
  EOS
242
272
  opts.on('--no-yaml', help) { self.yaml = false }
273
+
274
+ help = <<~EOS
275
+ Disable JSON precompilation.
276
+ EOS
277
+ opts.on('--no-json', help) { self.json = false }
243
278
  end
244
279
  end
245
280
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+ require('bootsnap/bootsnap')
3
+
4
+ module Bootsnap
5
+ module CompileCache
6
+ module JSON
7
+ class << self
8
+ attr_accessor(:msgpack_factory, :cache_dir, :supported_options)
9
+
10
+ def input_to_storage(payload, _)
11
+ obj = ::JSON.parse(payload)
12
+ msgpack_factory.dump(obj)
13
+ end
14
+
15
+ def storage_to_output(data, kwargs)
16
+ if kwargs && kwargs.key?(:symbolize_names)
17
+ kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
18
+ end
19
+ msgpack_factory.load(data, kwargs)
20
+ end
21
+
22
+ def input_to_output(data, kwargs)
23
+ ::JSON.parse(data, **(kwargs || {}))
24
+ end
25
+
26
+ def precompile(path, cache_dir: self.cache_dir)
27
+ Bootsnap::CompileCache::Native.precompile(
28
+ cache_dir,
29
+ path.to_s,
30
+ self,
31
+ )
32
+ end
33
+
34
+ def install!(cache_dir)
35
+ self.cache_dir = cache_dir
36
+ init!
37
+ if ::JSON.respond_to?(:load_file)
38
+ ::JSON.singleton_class.prepend(Patch)
39
+ end
40
+ end
41
+
42
+ def init!
43
+ require('json')
44
+ require('msgpack')
45
+
46
+ self.msgpack_factory = MessagePack::Factory.new
47
+ self.supported_options = [:symbolize_names]
48
+ if ::JSON.parse('["foo"]', freeze: true).first.frozen?
49
+ self.supported_options = [:freeze]
50
+ end
51
+ self.supported_options.freeze
52
+ end
53
+ end
54
+
55
+ module Patch
56
+ def load_file(path, *args)
57
+ return super if args.size > 1
58
+ if kwargs = args.first
59
+ return super unless kwargs.is_a?(Hash)
60
+ return super unless (kwargs.keys - ::Bootsnap::CompileCache::JSON.supported_options).empty?
61
+ end
62
+
63
+ begin
64
+ ::Bootsnap::CompileCache::Native.fetch(
65
+ Bootsnap::CompileCache::JSON.cache_dir,
66
+ File.realpath(path),
67
+ ::Bootsnap::CompileCache::JSON,
68
+ kwargs,
69
+ )
70
+ rescue Errno::EACCES
71
+ ::Bootsnap::CompileCache.permission_error(path)
72
+ end
73
+ end
74
+
75
+ ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -4,7 +4,7 @@ module Bootsnap
4
4
  Error = Class.new(StandardError)
5
5
  PermissionError = Class.new(Error)
6
6
 
7
- def self.setup(cache_dir:, iseq:, yaml:)
7
+ def self.setup(cache_dir:, iseq:, yaml:, json:)
8
8
  if iseq
9
9
  if supported?
10
10
  require_relative('compile_cache/iseq')
@@ -22,6 +22,15 @@ module Bootsnap
22
22
  warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
23
23
  end
24
24
  end
25
+
26
+ if json
27
+ if supported?
28
+ require_relative('compile_cache/json')
29
+ Bootsnap::CompileCache::JSON.install!(cache_dir)
30
+ elsif $VERBOSE
31
+ warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
32
+ end
33
+ end
25
34
  end
26
35
 
27
36
  def self.permission_error(path)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Bootsnap
3
- VERSION = "1.8.1"
3
+ VERSION = "1.9.0"
4
4
  end
data/lib/bootsnap.rb CHANGED
@@ -43,7 +43,8 @@ module Bootsnap
43
43
  autoload_paths_cache: nil,
44
44
  disable_trace: nil,
45
45
  compile_cache_iseq: true,
46
- compile_cache_yaml: true
46
+ compile_cache_yaml: true,
47
+ compile_cache_json: true
47
48
  )
48
49
  unless autoload_paths_cache.nil?
49
50
  warn "[DEPRECATED] Bootsnap's `autoload_paths_cache:` option is deprecated and will be removed. " \
@@ -69,7 +70,8 @@ module Bootsnap
69
70
  Bootsnap::CompileCache.setup(
70
71
  cache_dir: cache_dir + '/bootsnap/compile-cache',
71
72
  iseq: compile_cache_iseq,
72
- yaml: compile_cache_yaml
73
+ yaml: compile_cache_yaml,
74
+ json: compile_cache_json,
73
75
  )
74
76
  end
75
77
 
@@ -113,6 +115,7 @@ module Bootsnap
113
115
  load_path_cache: !ENV['DISABLE_BOOTSNAP_LOAD_PATH_CACHE'],
114
116
  compile_cache_iseq: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'] && iseq_cache_supported?,
115
117
  compile_cache_yaml: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'],
118
+ compile_cache_json: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'],
116
119
  )
117
120
 
118
121
  if ENV['BOOTSNAP_LOG']
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.8.1
4
+ version: 1.9.0
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-08-27 00:00:00.000000000 Z
11
+ date: 2021-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -116,6 +116,7 @@ files:
116
116
  - lib/bootsnap/cli/worker_pool.rb
117
117
  - lib/bootsnap/compile_cache.rb
118
118
  - lib/bootsnap/compile_cache/iseq.rb
119
+ - lib/bootsnap/compile_cache/json.rb
119
120
  - lib/bootsnap/compile_cache/yaml.rb
120
121
  - lib/bootsnap/explicit_require.rb
121
122
  - lib/bootsnap/load_path_cache.rb