bootsnap 1.1.8-java → 1.5.0-java

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.
@@ -1,4 +1,5 @@
1
- require "mkmf"
1
+ # frozen_string_literal: true
2
+ require("mkmf")
2
3
  $CFLAGS << ' -O3 '
3
4
  $CFLAGS << ' -std=c99'
4
5
 
@@ -12,6 +13,7 @@ unless ['0', '', nil].include?(ENV['BOOTSNAP_PEDANTIC'])
12
13
 
13
14
  $CFLAGS << ' -Wno-unused-parameter' # VALUE self has to be there but we don't care what it is.
14
15
  $CFLAGS << ' -Wno-keyword-macro' # hiding return
16
+ $CFLAGS << ' -Wno-gcc-compat' # ruby.h 2.6.0 on macos 10.14, dunno
15
17
  end
16
18
 
17
19
  create_makefile("bootsnap/bootsnap")
data/lib/bootsnap.rb CHANGED
@@ -1,7 +1,9 @@
1
- require_relative 'bootsnap/version'
2
- require_relative 'bootsnap/bundler'
3
- require_relative 'bootsnap/load_path_cache'
4
- require_relative 'bootsnap/compile_cache'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative('bootsnap/version')
4
+ require_relative('bootsnap/bundler')
5
+ require_relative('bootsnap/load_path_cache')
6
+ require_relative('bootsnap/compile_cache')
5
7
 
6
8
  module Bootsnap
7
9
  InvalidConfiguration = Class.new(StandardError)
@@ -16,7 +18,7 @@ module Bootsnap
16
18
  compile_cache_yaml: true
17
19
  )
18
20
  if autoload_paths_cache && !load_path_cache
19
- raise InvalidConfiguration, "feature 'autoload_paths_cache' depends on feature 'load_path_cache'"
21
+ raise(InvalidConfiguration, "feature 'autoload_paths_cache' depends on feature 'load_path_cache'")
20
22
  end
21
23
 
22
24
  setup_disable_trace if disable_trace
@@ -35,6 +37,13 @@ module Bootsnap
35
37
  end
36
38
 
37
39
  def self.setup_disable_trace
38
- RubyVM::InstructionSequence.compile_option = { trace_instruction: false }
40
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
41
+ warn(
42
+ "from #{caller_locations(1, 1)[0]}: The 'disable_trace' method is not allowed with this Ruby version. " \
43
+ "current: #{RUBY_VERSION}, allowed version: < 2.5.0",
44
+ )
45
+ else
46
+ RubyVM::InstructionSequence.compile_option = { trace_instruction: false }
47
+ end
39
48
  end
40
49
  end
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  module Bootsnap
2
- module_function
3
+ extend(self)
3
4
 
4
5
  def bundler?
6
+ return false unless defined?(::Bundler)
7
+
5
8
  # Bundler environment variable
6
- ['BUNDLE_BIN_PATH', 'BUNDLE_GEMFILE'].each do |current|
9
+ %w(BUNDLE_BIN_PATH BUNDLE_GEMFILE).each do |current|
7
10
  return true if ENV.key?(current)
8
11
  end
9
-
12
+
10
13
  false
11
14
  end
12
15
  end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bootsnap'
4
+ require 'optparse'
5
+ require 'fileutils'
6
+
7
+ module Bootsnap
8
+ class CLI
9
+ unless Regexp.method_defined?(:match?)
10
+ module RegexpMatchBackport
11
+ refine Regepx do
12
+ def match?(string)
13
+ !!match(string)
14
+ end
15
+ end
16
+ end
17
+ using RegexpMatchBackport
18
+ end
19
+
20
+ attr_reader :cache_dir, :argv
21
+
22
+ attr_accessor :compile_gemfile, :exclude
23
+
24
+ def initialize(argv)
25
+ @argv = argv
26
+ self.cache_dir = 'tmp/cache'
27
+ self.compile_gemfile = false
28
+ self.exclude = nil
29
+ end
30
+
31
+ def precompile_command(*sources)
32
+ require 'bootsnap/compile_cache/iseq'
33
+
34
+ Bootsnap::CompileCache::ISeq.cache_dir = self.cache_dir
35
+
36
+ if compile_gemfile
37
+ sources += $LOAD_PATH
38
+ end
39
+
40
+ sources.map { |d| File.expand_path(d) }.each do |path|
41
+ if !exclude || !exclude.match?(path)
42
+ list_ruby_files(path).each do |ruby_file|
43
+ if !exclude || !exclude.match?(ruby_file)
44
+ CompileCache::ISeq.fetch(ruby_file, cache_dir: cache_dir)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ 0
50
+ end
51
+
52
+ dir_sort = begin
53
+ Dir['.', sort: false]
54
+ true
55
+ rescue ArgumentError, TypeError
56
+ false
57
+ end
58
+
59
+ if dir_sort
60
+ def list_ruby_files(path)
61
+ if File.directory?(path)
62
+ Dir[File.join(path, '**/*.rb'), sort: false]
63
+ elsif File.exist?(path)
64
+ [path]
65
+ else
66
+ []
67
+ end
68
+ end
69
+ else
70
+ def list_ruby_files(path)
71
+ if File.directory?(path)
72
+ Dir[File.join(path, '**/*.rb')]
73
+ elsif File.exist?(path)
74
+ [path]
75
+ else
76
+ []
77
+ end
78
+ end
79
+ end
80
+
81
+ def run
82
+ parser.parse!(argv)
83
+ command = argv.shift
84
+ method = "#{command}_command"
85
+ if respond_to?(method)
86
+ public_send(method, *argv)
87
+ else
88
+ invalid_usage!("Unknown command: #{command}")
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ def invalid_usage!(message)
95
+ STDERR.puts message
96
+ STDERR.puts
97
+ STDERR.puts parser
98
+ 1
99
+ end
100
+
101
+ def cache_dir=(dir)
102
+ @cache_dir = File.expand_path(File.join(dir, 'bootsnap-compile-cache'))
103
+ end
104
+
105
+ def parser
106
+ @parser ||= OptionParser.new do |opts|
107
+ opts.banner = "Usage: bootsnap COMMAND [ARGS]"
108
+ opts.separator ""
109
+ opts.separator "GLOBAL OPTIONS"
110
+ opts.separator ""
111
+
112
+ help = <<~EOS
113
+ Path to the bootsnap cache directory. Defaults to tmp/cache
114
+ EOS
115
+ opts.on('--cache-dir DIR', help.strip) do |dir|
116
+ self.cache_dir = dir
117
+ end
118
+
119
+ opts.separator ""
120
+ opts.separator "COMMANDS"
121
+ opts.separator ""
122
+ opts.separator " precompile [DIRECTORIES...]: Precompile all .rb files in the passed directories"
123
+
124
+ help = <<~EOS
125
+ Precompile the gems in Gemfile
126
+ EOS
127
+ opts.on('--gemfile', help) { self.compile_gemfile = true }
128
+
129
+ help = <<~EOS
130
+ Path pattern to not precompile. e.g. --exclude 'aws-sdk|google-api'
131
+ EOS
132
+ opts.on('--exclude PATTERN', help) { |pattern| self.exclude = Regexp.new(pattern) }
133
+ end
134
+ end
135
+ end
136
+ end
@@ -1,15 +1,43 @@
1
+ # frozen_string_literal: true
1
2
  module Bootsnap
2
3
  module CompileCache
4
+ Error = Class.new(StandardError)
5
+ PermissionError = Class.new(Error)
6
+
3
7
  def self.setup(cache_dir:, iseq:, yaml:)
4
8
  if iseq
5
- require_relative 'compile_cache/iseq'
6
- Bootsnap::CompileCache::ISeq.install!(cache_dir)
9
+ if supported?
10
+ require_relative('compile_cache/iseq')
11
+ Bootsnap::CompileCache::ISeq.install!(cache_dir)
12
+ elsif $VERBOSE
13
+ warn("[bootsnap/setup] bytecode caching is not supported on this implementation of Ruby")
14
+ end
7
15
  end
8
16
 
9
17
  if yaml
10
- require_relative 'compile_cache/yaml'
11
- Bootsnap::CompileCache::YAML.install!(cache_dir)
18
+ if supported?
19
+ require_relative('compile_cache/yaml')
20
+ Bootsnap::CompileCache::YAML.install!(cache_dir)
21
+ elsif $VERBOSE
22
+ warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
23
+ end
12
24
  end
13
25
  end
26
+
27
+ def self.permission_error(path)
28
+ cpath = Bootsnap::CompileCache::ISeq.cache_dir
29
+ raise(
30
+ PermissionError,
31
+ "bootsnap doesn't have permission to write cache entries in '#{cpath}' " \
32
+ "(or, less likely, doesn't have permission to read '#{path}')",
33
+ )
34
+ end
35
+
36
+ def self.supported?
37
+ # only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), Windows (RubyInstaller2) and >= 2.3.0
38
+ RUBY_ENGINE == 'ruby' &&
39
+ RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/ &&
40
+ Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
41
+ end
14
42
  end
15
43
  end
@@ -1,31 +1,41 @@
1
- require 'bootsnap/bootsnap'
2
- require 'zlib'
1
+ # frozen_string_literal: true
2
+ require('bootsnap/bootsnap')
3
+ require('zlib')
3
4
 
4
5
  module Bootsnap
5
6
  module CompileCache
6
7
  module ISeq
7
8
  class << self
8
- attr_accessor :cache_dir
9
+ attr_accessor(:cache_dir)
9
10
  end
10
11
 
11
- def self.input_to_storage(_, path)
12
+ def self.input_to_storage(_, path, _args)
12
13
  RubyVM::InstructionSequence.compile_file(path).to_binary
13
14
  rescue SyntaxError
14
- raise Uncompilable, 'syntax error'
15
+ raise(Uncompilable, 'syntax error')
15
16
  end
16
17
 
17
- def self.storage_to_output(binary)
18
+ def self.storage_to_output(binary, _args)
18
19
  RubyVM::InstructionSequence.load_from_binary(binary)
19
20
  rescue RuntimeError => e
20
21
  if e.message == 'broken binary format'
21
- STDERR.puts "[Bootsnap::CompileCache] warning: rejecting broken binary"
22
- return nil
22
+ STDERR.puts("[Bootsnap::CompileCache] warning: rejecting broken binary")
23
+ nil
23
24
  else
24
25
  raise
25
26
  end
26
27
  end
27
28
 
28
- def self.input_to_output(_)
29
+ def self.fetch(path, cache_dir: ISeq.cache_dir)
30
+ Bootsnap::CompileCache::Native.fetch(
31
+ cache_dir,
32
+ path.to_s,
33
+ Bootsnap::CompileCache::ISeq,
34
+ nil,
35
+ )
36
+ end
37
+
38
+ def self.input_to_output(_, _)
29
39
  nil # ruby handles this
30
40
  end
31
41
 
@@ -34,14 +44,12 @@ module Bootsnap
34
44
  # Having coverage enabled prevents iseq dumping/loading.
35
45
  return nil if defined?(Coverage) && Bootsnap::CompileCache::Native.coverage_running?
36
46
 
37
- Bootsnap::CompileCache::Native.fetch(
38
- Bootsnap::CompileCache::ISeq.cache_dir,
39
- path.to_s,
40
- Bootsnap::CompileCache::ISeq
41
- )
47
+ Bootsnap::CompileCache::ISeq.fetch(path.to_s)
48
+ rescue Errno::EACCES
49
+ Bootsnap::CompileCache.permission_error(path)
42
50
  rescue RuntimeError => e
43
51
  if e.message =~ /unmatched platform/
44
- puts "unmatched platform for file #{path}"
52
+ puts("unmatched platform for file #{path}")
45
53
  end
46
54
  raise
47
55
  end
@@ -57,12 +65,13 @@ module Bootsnap
57
65
  crc = Zlib.crc32(option.inspect)
58
66
  Bootsnap::CompileCache::Native.compile_option_crc32 = crc
59
67
  end
68
+ compile_option_updated
60
69
 
61
70
  def self.install!(cache_dir)
62
71
  Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
63
72
  Bootsnap::CompileCache::ISeq.compile_option_updated
64
73
  class << RubyVM::InstructionSequence
65
- prepend InstructionSequenceMixin
74
+ prepend(InstructionSequenceMixin)
66
75
  end
67
76
  end
68
77
  end
@@ -1,56 +1,89 @@
1
- require 'bootsnap/bootsnap'
1
+ # frozen_string_literal: true
2
+ require('bootsnap/bootsnap')
2
3
 
3
4
  module Bootsnap
4
5
  module CompileCache
5
6
  module YAML
6
7
  class << self
7
- attr_accessor :msgpack_factory
8
- end
8
+ attr_accessor(:msgpack_factory, :cache_dir, :supported_options)
9
9
 
10
- def self.input_to_storage(contents, _)
11
- raise Uncompilable if contents.index("!ruby/object")
12
- obj = ::YAML.load(contents)
13
- msgpack_factory.packer.write(obj).to_s
14
- rescue NoMethodError, RangeError
15
- # if the object included things that we can't serialize, fall back to
16
- # Marshal. It's a bit slower, but can encode anything yaml can.
17
- # NoMethodError is unexpected types; RangeError is Bignums
18
- return Marshal.dump(obj)
19
- end
10
+ def input_to_storage(contents, _, kwargs)
11
+ raise(Uncompilable) if contents.index("!ruby/object")
12
+ obj = ::YAML.load(contents, **(kwargs || {}))
13
+ msgpack_factory.dump(obj)
14
+ rescue NoMethodError, RangeError
15
+ # if the object included things that we can't serialize, fall back to
16
+ # Marshal. It's a bit slower, but can encode anything yaml can.
17
+ # NoMethodError is unexpected types; RangeError is Bignums
18
+ Marshal.dump(obj)
19
+ end
20
20
 
21
- def self.storage_to_output(data)
22
- # This could have a meaning in messagepack, and we're being a little lazy
23
- # about it. -- but a leading 0x04 would indicate the contents of the YAML
24
- # is a positive integer, which is rare, to say the least.
25
- if data[0] == 0x04.chr && data[1] == 0x08.chr
26
- Marshal.load(data)
27
- else
28
- msgpack_factory.unpacker.feed(data).read
21
+ def storage_to_output(data, kwargs)
22
+ # This could have a meaning in messagepack, and we're being a little lazy
23
+ # about it. -- but a leading 0x04 would indicate the contents of the YAML
24
+ # is a positive integer, which is rare, to say the least.
25
+ if data[0] == 0x04.chr && data[1] == 0x08.chr
26
+ Marshal.load(data)
27
+ else
28
+ msgpack_factory.load(data, **(kwargs || {}))
29
+ end
29
30
  end
30
- end
31
31
 
32
- def self.input_to_output(data)
33
- ::YAML.load(data)
32
+ def input_to_output(data, kwargs)
33
+ ::YAML.load(data, **(kwargs || {}))
34
+ end
35
+
36
+ def install!(cache_dir)
37
+ self.cache_dir = cache_dir
38
+ init!
39
+ ::YAML.singleton_class.prepend(Patch)
40
+ end
41
+
42
+ def init!
43
+ require('yaml')
44
+ require('msgpack')
45
+
46
+ # MessagePack serializes symbols as strings by default.
47
+ # We want them to roundtrip cleanly, so we use a custom factory.
48
+ # see: https://github.com/msgpack/msgpack-ruby/pull/122
49
+ factory = MessagePack::Factory.new
50
+ factory.register_type(0x00, Symbol)
51
+ self.msgpack_factory = factory
52
+
53
+ self.supported_options = []
54
+ params = ::YAML.method(:load).parameters
55
+ if params.include?([:key, :symbolize_names])
56
+ self.supported_options << :symbolize_names
57
+ end
58
+ if params.include?([:key, :freeze])
59
+ if factory.load(factory.dump('yaml'), freeze: true).frozen?
60
+ self.supported_options << :freeze
61
+ end
62
+ end
63
+ self.supported_options.freeze
64
+ end
34
65
  end
35
66
 
36
- def self.install!(cache_dir)
37
- require 'yaml'
38
- require 'msgpack'
39
-
40
- # MessagePack serializes symbols as strings by default.
41
- # We want them to roundtrip cleanly, so we use a custom factory.
42
- # see: https://github.com/msgpack/msgpack-ruby/pull/122
43
- factory = MessagePack::Factory.new
44
- factory.register_type(0x00, Symbol)
45
- Bootsnap::CompileCache::YAML.msgpack_factory = factory
46
-
47
- klass = class << ::YAML; self; end
48
- klass.send(:define_method, :load_file) do |path|
49
- Bootsnap::CompileCache::Native.fetch(
50
- cache_dir,
51
- path.to_s,
52
- Bootsnap::CompileCache::YAML
53
- )
67
+ module Patch
68
+ extend self
69
+
70
+ def load_file(path, *args)
71
+ return super if args.size > 1
72
+ if kwargs = args.first
73
+ return super unless kwargs.is_a?(Hash)
74
+ return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
75
+ end
76
+
77
+ begin
78
+ ::Bootsnap::CompileCache::Native.fetch(
79
+ Bootsnap::CompileCache::YAML.cache_dir,
80
+ path,
81
+ ::Bootsnap::CompileCache::YAML,
82
+ kwargs,
83
+ )
84
+ rescue Errno::EACCES
85
+ ::Bootsnap::CompileCache.permission_error(path)
86
+ end
54
87
  end
55
88
  end
56
89
  end