Cleanup the rubocop config

Go back to rubocop 0.80 for Ruby 2.3 support.
Stop depending on the company style guide, as it needs a newer
rubocop.
This commit is contained in:
Jean Boussier 2022-01-13 10:05:07 +01:00
parent 12ee08bf86
commit b277e75e85
49 changed files with 790 additions and 800 deletions

View File

@ -1,13 +1,8 @@
inherit_from: .rubocop_todo.yml
inherit_gem:
rubocop-shopify: rubocop.yml
AllCops:
Exclude:
- 'vendor/**/*'
- 'tmp/**/*'
TargetRubyVersion: 2.5
TargetRubyVersion: 2.3
# This doesn't take into account retrying from an exception
Lint/SuppressedException:
@ -17,6 +12,149 @@ Lint/SuppressedException:
Style/EmptyLiteral:
Enabled: false
Style/EmptyMethod:
Enabled: false
# allow the use of globals which makes sense in a CLI app like this
Style/GlobalVars:
Enabled: false
Style/PercentLiteralDelimiters:
Enabled: false
Style/TrailingCommaInHashLiteral:
EnforcedStyleForMultiline: comma
Style/TrailingCommaInArguments:
EnforcedStyleForMultiline: comma
Layout/LineLength:
Max: 120
Style/TrailingCommaInArguments:
EnforcedStyleForMultiline: comma
Metrics/AbcSize:
Enabled: false
Metrics/MethodLength:
Enabled: false
Metrics/BlockLength:
Enabled: false
Metrics/ClassLength:
Enabled: false
Metrics/CyclomaticComplexity:
Enabled: false
Metrics/ModuleLength:
Enabled: false
Metrics/ParameterLists:
Enabled: false
Metrics/PerceivedComplexity:
Enabled: false
Naming/MethodName:
Exclude:
- 'test/**/*'
Layout/SpaceInsideHashLiteralBraces:
EnforcedStyle: no_space
Naming/RescuedExceptionsVariableName:
PreferredName: error
Bundler/OrderedGems:
Enabled: false
Gemspec/OrderedDependencies:
Enabled: false
Gemspec/DuplicatedAssignment:
Enabled: false
Layout/MultilineMethodCallIndentation:
EnforcedStyle: indented
Style/SymbolArray:
Enabled: false
Style/StderrPuts:
Enabled: false
Style/ModuleFunction:
Enabled: false
Style/IfUnlessModifier:
Enabled: false
Style/GuardClause:
Enabled: false
Layout/EndAlignment:
EnforcedStyleAlignWith: start_of_line
Layout/RescueEnsureAlignment:
Enabled: false
Layout/FirstHashElementIndentation:
EnforcedStyle: consistent
Style/NumericPredicate:
Enabled: false
Layout/SpaceInsideHashLiteralBraces:
EnforcedStyle: no_space
Lint/AssignmentInCondition:
AllowSafeAssignment: true
Lint/UnusedMethodArgument:
AllowUnusedKeywordArguments: true
Security/MarshalLoad:
Enabled: false
Security/YAMLLoad:
Enabled: false
Style/Alias:
EnforcedStyle: prefer_alias_method
Style/Documentation:
Enabled: false
Style/DoubleNegation:
Enabled: false
Style/CommentedKeyword:
Enabled: false
Naming/VariableNumber:
Enabled: false
Style/Next:
Enabled: false
Style/StringLiterals:
EnforcedStyle: double_quotes
Lint/RaiseException:
Enabled: true
Lint/StructNewOverride:
Enabled: true
Style/HashEachMethods:
Enabled: true
Style/HashTransformKeys:
Enabled: true
Style/HashTransformValues:
Enabled: true

View File

@ -1,213 +0,0 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2022-01-12 21:26:07 UTC using RuboCop version 1.24.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 1
# Configuration parameters: Include.
# Include: **/*.gemspec
Gemspec/DuplicatedAssignment:
Exclude:
- 'bootsnap.gemspec'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include.
# Include: **/*.gemspec
Gemspec/OrderedDependencies:
Exclude:
- 'bootsnap.gemspec'
# Offense count: 37
# Cop supports --auto-correct.
Layout/EmptyLineAfterMagicComment:
Enabled: false
# Offense count: 1
# Cop supports --auto-correct.
Layout/EmptyLines:
Exclude:
- 'lib/bootsnap.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment.
Layout/ExtraSpacing:
Exclude:
- 'lib/bootsnap/cli.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: aligned, indented
Layout/LineEndStringConcatenationIndentation:
Exclude:
- 'lib/bootsnap/compile_cache.rb'
- 'test/load_path_cache/realpath_cache_test.rb'
# Offense count: 3
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: aligned, indented
Layout/MultilineOperationIndentation:
Exclude:
- 'lib/bootsnap/compile_cache.rb'
- 'lib/bootsnap/load_path_cache.rb'
# Offense count: 1
# Cop supports --auto-correct.
Layout/RescueEnsureAlignment:
Exclude:
- 'lib/bootsnap/load_path_cache/path.rb'
# Offense count: 12
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces.
# SupportedStyles: space, no_space, compact
# SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceInsideHashLiteralBraces:
Exclude:
- 'test/compile_cache/json_test.rb'
- 'test/compile_cache/yaml_test.rb'
# Offense count: 5
# Configuration parameters: AllowSafeAssignment.
Lint/AssignmentInCondition:
Exclude:
- 'lib/bootsnap/cli.rb'
- 'lib/bootsnap/compile_cache/json.rb'
- 'lib/bootsnap/compile_cache/yaml.rb'
- 'lib/bootsnap/load_path_cache/loaded_features_index.rb'
# Offense count: 5
# Configuration parameters: IgnoredPatterns.
# SupportedStyles: snake_case, camelCase
Naming/MethodName:
EnforcedStyle: snake_case
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
# SupportedStyles: assign_to_condition, assign_inside_condition
Style/ConditionalAssignment:
Exclude:
- 'lib/bootsnap.rb'
# Offense count: 36
# Cop supports --auto-correct.
# Configuration parameters: IgnoreMacros, IgnoredMethods, IgnoredPatterns, IncludedMacros, AllowParenthesesInMultilineCall, AllowParenthesesInChaining, AllowParenthesesInCamelCaseMethod, AllowParenthesesInStringInterpolation, EnforcedStyle.
# SupportedStyles: require_parentheses, omit_parentheses
Style/MethodCallWithArgsParentheses:
Exclude:
- 'lib/bootsnap.rb'
- 'lib/bootsnap/cli.rb'
- 'test/cli_test.rb'
- 'test/compile_cache/json_test.rb'
- 'test/compile_cache/yaml_test.rb'
- 'test/compile_cache_test.rb'
- 'test/load_path_cache/cache_test.rb'
- 'test/load_path_cache/core_ext/kernel_require_test.rb'
- 'test/load_path_cache/store_test.rb'
- 'test/worker_pool_test.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: AllowedMethods.
# AllowedMethods: be, be_a, be_an, be_between, be_falsey, be_kind_of, be_instance_of, be_truthy, be_within, eq, eql, end_with, include, match, raise_error, respond_to, start_with
Style/NestedParenthesizedCalls:
Exclude:
- 'test/load_path_cache/core_ext/kernel_require_test.rb'
# Offense count: 3
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength.
# SupportedStyles: skip_modifier_ifs, always
Style/Next:
Exclude:
- 'lib/bootsnap/cli.rb'
# Offense count: 2
# Cop supports --auto-correct.
Style/RedundantBegin:
Exclude:
- 'lib/bootsnap/load_path_cache/path.rb'
- 'lib/bootsnap/load_path_cache/store.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/RedundantFreeze:
Exclude:
- 'lib/bootsnap/load_path_cache/store.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/RedundantParentheses:
Exclude:
- 'lib/bootsnap/load_path_cache/cache.rb'
# Offense count: 7
# Cop supports --auto-correct.
Style/RedundantSelf:
Exclude:
- 'lib/bootsnap/cli.rb'
- 'lib/bootsnap/compile_cache/json.rb'
- 'lib/bootsnap/compile_cache/yaml.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods.
# AllowedMethods: present?, blank?, presence, try, try!
Style/SafeNavigation:
Exclude:
- 'lib/bootsnap/compile_cache/json.rb'
- 'lib/bootsnap/compile_cache/yaml.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: RequireEnglish, EnforcedStyle.
# SupportedStyles: use_perl_names, use_english_names
Style/SpecialGlobalVars:
Exclude:
- 'test/worker_pool_test.rb'
# Offense count: 593
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiterals:
Enabled: false
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiteralsInInterpolation:
Exclude:
- 'test/load_path_cache/path_test.rb'
- 'test/load_path_cache/realpath_cache_test.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: .
# SupportedStyles: percent, brackets
Style/SymbolArray:
EnforcedStyle: percent
MinSize: 3
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInHashLiteral:
Exclude:
- 'bootsnap.gemspec'
# Offense count: 15
# Cop supports --auto-correct.
# Configuration parameters: MinSize, WordRegex.
# SupportedStyles: percent, brackets
Style/WordArray:
EnforcedStyle: percent

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
source 'https://rubygems.org'
source "https://rubygems.org"
# Specify your gem's dependencies in bootsnap.gemspec
gemspec
@ -9,7 +10,7 @@ if ENV["PSYCH_4"]
end
group :development do
gem 'rubocop'
gem 'rubocop-shopify', require: false
gem 'byebug', platform: :ruby
gem "rubocop", "0.81.0" # Ruby 2.3 support
gem "rubocop-shopify", require: false
gem "byebug", platform: :ruby
end

View File

@ -1,12 +1,13 @@
# frozen_string_literal: true
require('rake/extensiontask')
require('bundler/gem_tasks')
gemspec = Gem::Specification.load('bootsnap.gemspec')
require("rake/extensiontask")
require("bundler/gem_tasks")
gemspec = Gem::Specification.load("bootsnap.gemspec")
Rake::ExtensionTask.new do |ext|
ext.name = 'bootsnap'
ext.ext_dir = 'ext/bootsnap'
ext.lib_dir = 'lib/bootsnap'
ext.name = "bootsnap"
ext.ext_dir = "ext/bootsnap"
ext.lib_dir = "lib/bootsnap"
ext.gem_spec = gemspec
end

View File

@ -1,8 +1,8 @@
# coding: utf-8
# frozen_string_literal: true
lib = File.expand_path('../lib', __FILE__)
lib = File.expand_path("lib", __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require('bootsnap/version')
require("bootsnap/version")
Gem::Specification.new do |spec|
spec.name = "bootsnap"
@ -17,30 +17,30 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/Shopify/bootsnap"
spec.metadata = {
'bug_tracker_uri' => 'https://github.com/Shopify/bootsnap/issues',
'changelog_uri' => 'https://github.com/Shopify/bootsnap/blob/main/CHANGELOG.md',
'source_code_uri' => 'https://github.com/Shopify/bootsnap',
'allowed_push_host' => 'https://rubygems.org'
"bug_tracker_uri" => "https://github.com/Shopify/bootsnap/issues",
"changelog_uri" => "https://github.com/Shopify/bootsnap/blob/main/CHANGELOG.md",
"source_code_uri" => "https://github.com/Shopify/bootsnap",
"allowed_push_host" => "https://rubygems.org",
}
spec.files = %x(git ls-files -z ext lib).split("\x0") + %w(CHANGELOG.md LICENSE.txt README.md)
spec.files = `git ls-files -z ext lib`.split("\x0") + %w(CHANGELOG.md LICENSE.txt README.md)
spec.require_paths = %w(lib)
spec.bindir = 'exe'
spec.bindir = "exe"
spec.executables = %w(bootsnap)
spec.required_ruby_version = '>= 2.3.0'
spec.required_ruby_version = ">= 2.3.0"
if RUBY_PLATFORM =~ /java/
spec.platform = 'java'
spec.platform = "java"
else
spec.platform = Gem::Platform::RUBY
spec.extensions = ['ext/bootsnap/extconf.rb']
spec.extensions = ["ext/bootsnap/extconf.rb"]
end
spec.add_development_dependency("bundler")
spec.add_development_dependency('rake')
spec.add_development_dependency('rake-compiler')
spec.add_development_dependency("rake")
spec.add_development_dependency("rake-compiler")
spec.add_development_dependency("minitest", "~> 5.0")
spec.add_development_dependency("mocha", "~> 1.2")

View File

@ -1,5 +1,5 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'bootsnap/cli'
require "bootsnap/cli"
exit Bootsnap::CLI.new(ARGV).run

View File

@ -1,22 +1,23 @@
# frozen_string_literal: true
require("mkmf")
if RUBY_ENGINE == 'ruby'
$CFLAGS << ' -O3 '
$CFLAGS << ' -std=c99'
if RUBY_ENGINE == "ruby"
$CFLAGS << " -O3 "
$CFLAGS << " -std=c99"
# ruby.h has some -Wpedantic fails in some cases
# (e.g. https://github.com/Shopify/bootsnap/issues/15)
unless ['0', '', nil].include?(ENV['BOOTSNAP_PEDANTIC'])
$CFLAGS << ' -Wall'
$CFLAGS << ' -Werror'
$CFLAGS << ' -Wextra'
$CFLAGS << ' -Wpedantic'
unless ["0", "", nil].include?(ENV["BOOTSNAP_PEDANTIC"])
$CFLAGS << " -Wall"
$CFLAGS << " -Werror"
$CFLAGS << " -Wextra"
$CFLAGS << " -Wpedantic"
$CFLAGS << ' -Wno-unused-parameter' # VALUE self has to be there but we don't care what it is.
$CFLAGS << ' -Wno-keyword-macro' # hiding return
$CFLAGS << ' -Wno-gcc-compat' # ruby.h 2.6.0 on macos 10.14, dunno
$CFLAGS << ' -Wno-compound-token-split-by-macro'
$CFLAGS << " -Wno-unused-parameter" # VALUE self has to be there but we don't care what it is.
$CFLAGS << " -Wno-keyword-macro" # hiding return
$CFLAGS << " -Wno-gcc-compat" # ruby.h 2.6.0 on macos 10.14, dunno
$CFLAGS << " -Wno-compound-token-split-by-macro"
end
create_makefile("bootsnap/bootsnap")

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
require_relative('bootsnap/version')
require_relative('bootsnap/bundler')
require_relative('bootsnap/load_path_cache')
require_relative('bootsnap/compile_cache')
require_relative("bootsnap/version")
require_relative("bootsnap/bundler")
require_relative("bootsnap/load_path_cache")
require_relative("bootsnap/compile_cache")
module Bootsnap
InvalidConfiguration = Class.new(StandardError)
@ -18,10 +18,10 @@ module Bootsnap
def self.logger=(logger)
@logger = logger
if logger.respond_to?(:debug)
self.instrumentation = ->(event, path) { @logger.debug("[Bootsnap] #{event} #{path}") }
self.instrumentation = if logger.respond_to?(:debug)
->(event, path) { @logger.debug("[Bootsnap] #{event} #{path}") }
else
self.instrumentation = ->(event, path) { @logger.call("[Bootsnap] #{event} #{path}") }
->(event, path) { @logger.call("[Bootsnap] #{event} #{path}") }
end
end
@ -62,13 +62,15 @@ module Bootsnap
"to turn `compile_cache_iseq` off on Ruby 2.5"
end
Bootsnap::LoadPathCache.setup(
cache_path: cache_dir + '/bootsnap/load-path-cache',
development_mode: development_mode,
) if load_path_cache
if load_path_cache
Bootsnap::LoadPathCache.setup(
cache_path: cache_dir + "/bootsnap/load-path-cache",
development_mode: development_mode,
)
end
Bootsnap::CompileCache.setup(
cache_dir: cache_dir + '/bootsnap/compile-cache',
cache_dir: cache_dir + "/bootsnap/compile-cache",
iseq: compile_cache_iseq,
yaml: compile_cache_yaml,
json: compile_cache_json,
@ -79,18 +81,18 @@ module Bootsnap
return @iseq_cache_supported if defined? @iseq_cache_supported
ruby_version = Gem::Version.new(RUBY_VERSION)
@iseq_cache_supported = ruby_version < Gem::Version.new('2.5.0') || ruby_version >= Gem::Version.new('2.6.0')
@iseq_cache_supported = ruby_version < Gem::Version.new("2.5.0") || ruby_version >= Gem::Version.new("2.6.0")
end
def self.default_setup
env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || ENV['ENV']
development_mode = ['', nil, 'development'].include?(env)
env = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || ENV["ENV"]
development_mode = ["", nil, "development"].include?(env)
unless ENV['DISABLE_BOOTSNAP']
cache_dir = ENV['BOOTSNAP_CACHE_DIR']
unless ENV["DISABLE_BOOTSNAP"]
cache_dir = ENV["BOOTSNAP_CACHE_DIR"]
unless cache_dir
config_dir_frame = caller.detect do |line|
line.include?('/config/')
line.include?("/config/")
end
unless config_dir_frame
@ -102,35 +104,34 @@ module Bootsnap
end
path = config_dir_frame.split(/:\d+:/).first
path = File.dirname(path) until File.basename(path) == 'config'
path = File.dirname(path) until File.basename(path) == "config"
app_root = File.dirname(path)
cache_dir = File.join(app_root, 'tmp', 'cache')
cache_dir = File.join(app_root, "tmp", "cache")
end
setup(
cache_dir: cache_dir,
development_mode: development_mode,
load_path_cache: !ENV['DISABLE_BOOTSNAP_LOAD_PATH_CACHE'],
compile_cache_iseq: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'] && iseq_cache_supported?,
compile_cache_yaml: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'],
compile_cache_json: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'],
cache_dir: cache_dir,
development_mode: development_mode,
load_path_cache: !ENV["DISABLE_BOOTSNAP_LOAD_PATH_CACHE"],
compile_cache_iseq: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"] && iseq_cache_supported?,
compile_cache_yaml: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
compile_cache_json: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
)
if ENV['BOOTSNAP_LOG']
if ENV["BOOTSNAP_LOG"]
log!
end
end
end
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
if RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
def self.absolute_path?(path)
path[1] == ':'
path[1] == ":"
end
else
def self.absolute_path?(path)
path.start_with?('/')
path.start_with?("/")
end
end
end

View File

@ -1,4 +1,5 @@
# frozen_string_literal: true
module Bootsnap
extend(self)

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true
require 'bootsnap'
require 'bootsnap/cli/worker_pool'
require 'optparse'
require 'fileutils'
require 'etc'
require "bootsnap"
require "bootsnap/cli/worker_pool"
require "optparse"
require "fileutils"
require "etc"
module Bootsnap
class CLI
@ -25,7 +25,7 @@ module Bootsnap
def initialize(argv)
@argv = argv
self.cache_dir = ENV.fetch('BOOTSNAP_CACHE_DIR', 'tmp/cache')
self.cache_dir = ENV.fetch("BOOTSNAP_CACHE_DIR", "tmp/cache")
self.compile_gemfile = false
self.exclude = nil
self.verbose = false
@ -36,16 +36,16 @@ module Bootsnap
end
def precompile_command(*sources)
require 'bootsnap/compile_cache/iseq'
require 'bootsnap/compile_cache/yaml'
require 'bootsnap/compile_cache/json'
require "bootsnap/compile_cache/iseq"
require "bootsnap/compile_cache/yaml"
require "bootsnap/compile_cache/json"
fix_default_encoding do
Bootsnap::CompileCache::ISeq.cache_dir = self.cache_dir
Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
Bootsnap::CompileCache::YAML.init!
Bootsnap::CompileCache::YAML.cache_dir = self.cache_dir
Bootsnap::CompileCache::YAML.cache_dir = cache_dir
Bootsnap::CompileCache::JSON.init!
Bootsnap::CompileCache::JSON.cache_dir = self.cache_dir
Bootsnap::CompileCache::JSON.cache_dir = cache_dir
@work_pool = WorkerPool.create(size: jobs, jobs: {
ruby: method(:precompile_ruby),
@ -61,7 +61,7 @@ module Bootsnap
if compile_gemfile
# Some gems embed their tests, they're very unlikely to be loaded, so not worth precompiling.
gem_exclude = Regexp.union([exclude, '/spec/', '/test/'].compact)
gem_exclude = Regexp.union([exclude, "/spec/", "/test/"].compact)
precompile_ruby_files($LOAD_PATH.map { |d| File.expand_path(d) }, exclude: gem_exclude)
# Gems that include JSON or YAML files usually don't put them in `lib/`.
@ -72,7 +72,7 @@ module Bootsnap
precompile_json_files(gem_paths, exclude: gem_exclude)
end
if exitstatus = @work_pool.shutdown
if (exitstatus = @work_pool.shutdown)
exit(exitstatus)
end
end
@ -89,7 +89,7 @@ module Bootsnap
if dir_sort
def list_files(path, pattern)
if File.directory?(path)
Dir[File.join(path, pattern), sort: false]
Dir[File.join(path, pattern), sort: false]
elsif File.exist?(path)
[path]
else
@ -99,7 +99,7 @@ module Bootsnap
else
def list_files(path, pattern)
if File.directory?(path)
Dir[File.join(path, pattern)]
Dir[File.join(path, pattern)]
elsif File.exist?(path)
[path]
else
@ -126,9 +126,9 @@ module Bootsnap
load_paths.each do |path|
if !exclude || !exclude.match?(path)
list_files(path, '**/*.{yml,yaml}').each do |yaml_file|
list_files(path, "**/*.{yml,yaml}").each do |yaml_file|
# We ignore hidden files to not match the various .ci.yml files
if !File.basename(yaml_file).start_with?('.') && (!exclude || !exclude.match?(yaml_file))
if !File.basename(yaml_file).start_with?(".") && (!exclude || !exclude.match?(yaml_file))
@work_pool.push(:yaml, yaml_file)
end
end
@ -149,9 +149,9 @@ module Bootsnap
load_paths.each do |path|
if !exclude || !exclude.match?(path)
list_files(path, '**/*.json').each do |json_file|
list_files(path, "**/*.json").each do |json_file|
# We ignore hidden files to not match the various .config.json files
if !File.basename(json_file).start_with?('.') && (!exclude || !exclude.match?(json_file))
if !File.basename(json_file).start_with?(".") && (!exclude || !exclude.match?(json_file))
@work_pool.push(:json, json_file)
end
end
@ -172,7 +172,7 @@ module Bootsnap
load_paths.each do |path|
if !exclude || !exclude.match?(path)
list_files(path, '**/*.rb').each do |ruby_file|
list_files(path, "**/*.rb").each do |ruby_file|
if !exclude || !exclude.match?(ruby_file)
@work_pool.push(:ruby, ruby_file)
end
@ -210,7 +210,7 @@ module Bootsnap
end
def cache_dir=(dir)
@cache_dir = File.expand_path(File.join(dir, 'bootsnap/compile-cache'))
@cache_dir = File.expand_path(File.join(dir, "bootsnap/compile-cache"))
end
def exclude_pattern(pattern)
@ -225,24 +225,24 @@ module Bootsnap
opts.separator "GLOBAL OPTIONS"
opts.separator ""
help = <<~EOS
help = <<~HELP
Path to the bootsnap cache directory. Defaults to tmp/cache
EOS
opts.on('--cache-dir DIR', help.strip) do |dir|
HELP
opts.on("--cache-dir DIR", help.strip) do |dir|
self.cache_dir = dir
end
help = <<~EOS
help = <<~HELP
Print precompiled paths.
EOS
opts.on('--verbose', '-v', help.strip) do
HELP
opts.on("--verbose", "-v", help.strip) do
self.verbose = true
end
help = <<~EOS
help = <<~HELP
Number of workers to use. Default to number of processors, set to 0 to disable multi-processing.
EOS
opts.on('--jobs JOBS', '-j', help.strip) do |jobs|
HELP
opts.on("--jobs JOBS", "-j", help.strip) do |jobs|
self.jobs = Integer(jobs)
end
@ -251,30 +251,30 @@ module Bootsnap
opts.separator ""
opts.separator " precompile [DIRECTORIES...]: Precompile all .rb files in the passed directories"
help = <<~EOS
help = <<~HELP
Precompile the gems in Gemfile
EOS
opts.on('--gemfile', help) { self.compile_gemfile = true }
HELP
opts.on("--gemfile", help) { self.compile_gemfile = true }
help = <<~EOS
help = <<~HELP
Path pattern to not precompile. e.g. --exclude 'aws-sdk|google-api'
EOS
opts.on('--exclude PATTERN', help) { |pattern| exclude_pattern(pattern) }
HELP
opts.on("--exclude PATTERN", help) { |pattern| exclude_pattern(pattern) }
help = <<~EOS
help = <<~HELP
Disable ISeq (.rb) precompilation.
EOS
opts.on('--no-iseq', help) { self.iseq = false }
HELP
opts.on("--no-iseq", help) { self.iseq = false }
help = <<~EOS
help = <<~HELP
Disable YAML precompilation.
EOS
opts.on('--no-yaml', help) { self.yaml = false }
HELP
opts.on("--no-yaml", help) { self.yaml = false }
help = <<~EOS
help = <<~HELP
Disable JSON precompilation.
EOS
opts.on('--no-json', help) { self.json = false }
HELP
opts.on("--no-json", help) { self.json = false }
end
end
end

View File

@ -63,6 +63,7 @@ module Bootsnap
loop do
job, *args = Marshal.load(@pipe_out)
return if job == :exit
@jobs.fetch(job).call(*args)
end
rescue IOError

View File

@ -1,4 +1,5 @@
# frozen_string_literal: true
module Bootsnap
module CompileCache
Error = Class.new(StandardError)
@ -7,7 +8,7 @@ module Bootsnap
def self.setup(cache_dir:, iseq:, yaml:, json:)
if iseq
if supported?
require_relative('compile_cache/iseq')
require_relative("compile_cache/iseq")
Bootsnap::CompileCache::ISeq.install!(cache_dir)
elsif $VERBOSE
warn("[bootsnap/setup] bytecode caching is not supported on this implementation of Ruby")
@ -16,7 +17,7 @@ module Bootsnap
if yaml
if supported?
require_relative('compile_cache/yaml')
require_relative("compile_cache/yaml")
Bootsnap::CompileCache::YAML.install!(cache_dir)
elsif $VERBOSE
warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
@ -25,7 +26,7 @@ module Bootsnap
if json
if supported?
require_relative('compile_cache/json')
require_relative("compile_cache/json")
Bootsnap::CompileCache::JSON.install!(cache_dir)
elsif $VERBOSE
warn("[bootsnap/setup] JSON parsing caching is not supported on this implementation of Ruby")
@ -44,9 +45,9 @@ module Bootsnap
def self.supported?
# only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), Windows (RubyInstaller2) and >= 2.3.0
RUBY_ENGINE == 'ruby' &&
RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/ &&
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
RUBY_ENGINE == "ruby" &&
RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/ &&
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
end
end
end

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true
require('bootsnap/bootsnap')
require('zlib')
require("bootsnap/bootsnap")
require("zlib")
module Bootsnap
module CompileCache
@ -23,27 +24,27 @@ module Bootsnap
iseq = begin
RubyVM::InstructionSequence.compile_file(path)
rescue SyntaxError
raise(Uncompilable, 'syntax error')
raise(Uncompilable, "syntax error")
end
begin
iseq.to_binary
rescue TypeError
raise(Uncompilable, 'ruby bug #18250')
raise(Uncompilable, "ruby bug #18250")
end
end
else
def self.input_to_storage(_, path)
RubyVM::InstructionSequence.compile_file(path).to_binary
rescue SyntaxError
raise(Uncompilable, 'syntax error')
raise(Uncompilable, "syntax error")
end
end
def self.storage_to_output(binary, _args)
RubyVM::InstructionSequence.load_from_binary(binary)
rescue RuntimeError => e
if e.message == 'broken binary format'
rescue RuntimeError => error
if error.message == "broken binary format"
STDERR.puts("[Bootsnap::CompileCache] warning: rejecting broken binary")
nil
else
@ -80,8 +81,8 @@ module Bootsnap
Bootsnap::CompileCache::ISeq.fetch(path.to_s)
rescue Errno::EACCES
Bootsnap::CompileCache.permission_error(path)
rescue RuntimeError => e
if e.message =~ /unmatched platform/
rescue RuntimeError => error
if error.message =~ /unmatched platform/
puts("unmatched platform for file #{path}")
end
raise

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require('bootsnap/bootsnap')
require("bootsnap/bootsnap")
module Bootsnap
module CompileCache
@ -13,7 +14,7 @@ module Bootsnap
end
def storage_to_output(data, kwargs)
if kwargs && kwargs.key?(:symbolize_names)
if kwargs&.key?(:symbolize_names)
kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
end
msgpack_factory.load(data, kwargs)
@ -40,22 +41,23 @@ module Bootsnap
end
def init!
require('json')
require('msgpack')
require("json")
require("msgpack")
self.msgpack_factory = MessagePack::Factory.new
self.supported_options = [:symbolize_names]
if ::JSON.parse('["foo"]', freeze: true).first.frozen?
self.supported_options = [:freeze]
end
self.supported_options.freeze
supported_options.freeze
end
end
module Patch
def load_file(path, *args)
return super if args.size > 1
if kwargs = args.first
if (kwargs = args.first)
return super unless kwargs.is_a?(Hash)
return super unless (kwargs.keys - ::Bootsnap::CompileCache::JSON.supported_options).empty?
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require('bootsnap/bootsnap')
require("bootsnap/bootsnap")
module Bootsnap
module CompileCache
@ -16,7 +17,7 @@ module Bootsnap
end
def storage_to_output(data, kwargs)
if kwargs && kwargs.key?(:symbolize_names)
if kwargs&.key?(:symbolize_names)
kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
end
msgpack_factory.load(data, kwargs)
@ -33,6 +34,7 @@ module Bootsnap
def strict_load(payload, *args)
ast = ::YAML.parse(payload)
return ast unless ast
strict_visitor.create(*args).visit(ast)
end
ruby2_keywords :strict_load if respond_to?(:ruby2_keywords, true)
@ -52,14 +54,14 @@ module Bootsnap
end
def init!
require('yaml')
require('msgpack')
require('date')
require("yaml")
require("msgpack")
require("date")
if Patch.method_defined?(:unsafe_load_file) && !::YAML.respond_to?(:unsafe_load_file)
Patch.send(:remove_method, :unsafe_load_file)
end
if Patch.method_defined?(:load_file) && ::YAML::VERSION >= '4'
if Patch.method_defined?(:load_file) && ::YAML::VERSION >= "4"
Patch.send(:remove_method, :load_file)
end
@ -74,7 +76,7 @@ module Bootsnap
MessagePack::Timestamp::TYPE, # or just -1
Time,
packer: MessagePack::Time::Packer,
unpacker: MessagePack::Time::Unpacker
unpacker: MessagePack::Time::Unpacker,
)
marshal_fallback = {
@ -94,14 +96,14 @@ module Bootsnap
self.supported_options = []
params = ::YAML.method(:load).parameters
if params.include?([:key, :symbolize_names])
self.supported_options << :symbolize_names
supported_options << :symbolize_names
end
if params.include?([:key, :freeze])
if factory.load(factory.dump('yaml'), freeze: true).frozen?
self.supported_options << :freeze
if factory.load(factory.dump("yaml"), freeze: true).frozen?
supported_options << :freeze
end
end
self.supported_options.freeze
supported_options.freeze
end
def strict_visitor
@ -110,6 +112,7 @@ module Bootsnap
if target.tag
raise Uncompilable, "YAML tags are not supported: #{target.tag}"
end
super
end
end
@ -119,7 +122,8 @@ module Bootsnap
module Patch
def load_file(path, *args)
return super if args.size > 1
if kwargs = args.first
if (kwargs = args.first)
return super unless kwargs.is_a?(Hash)
return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
end
@ -140,7 +144,8 @@ module Bootsnap
def unsafe_load_file(path, *args)
return super if args.size > 1
if kwargs = args.first
if (kwargs = args.first)
return super unless kwargs.is_a?(Hash)
return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
end

View File

@ -1,9 +1,10 @@
# frozen_string_literal: true
module Bootsnap
module ExplicitRequire
ARCHDIR = RbConfig::CONFIG['archdir']
RUBYLIBDIR = RbConfig::CONFIG['rubylibdir']
DLEXT = RbConfig::CONFIG['DLEXT']
ARCHDIR = RbConfig::CONFIG["archdir"]
RUBYLIBDIR = RbConfig::CONFIG["rubylibdir"]
DLEXT = RbConfig::CONFIG["DLEXT"]
def self.from_self(feature)
require_relative("../#{feature}")

View File

@ -5,9 +5,9 @@ module Bootsnap
ReturnFalse = Class.new(StandardError)
FallbackScan = Class.new(StandardError)
DOT_RB = '.rb'
DOT_SO = '.so'
SLASH = '/'
DOT_RB = ".rb"
DOT_SO = ".so"
SLASH = "/"
# If a NameError happens several levels deep, don't re-handle it
# all the way up the chain: mark it once and bubble it up without
@ -15,7 +15,7 @@ module Bootsnap
ERROR_TAG_IVAR = :@__bootsnap_rescued
DL_EXTENSIONS = ::RbConfig::CONFIG
.values_at('DLEXT', 'DLEXT2')
.values_at("DLEXT", "DLEXT2")
.reject { |ext| !ext || ext.empty? }
.map { |ext| ".#{ext}" }
.freeze
@ -42,24 +42,24 @@ module Bootsnap
@realpath_cache = RealpathCache.new
@load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
require_relative('load_path_cache/core_ext/kernel_require')
require_relative('load_path_cache/core_ext/loaded_features')
require_relative("load_path_cache/core_ext/kernel_require")
require_relative("load_path_cache/core_ext/loaded_features")
end
def supported?
RUBY_ENGINE == 'ruby' &&
RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/
RUBY_ENGINE == "ruby" &&
RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/
end
end
end
end
if Bootsnap::LoadPathCache.supported?
require_relative('load_path_cache/path_scanner')
require_relative('load_path_cache/path')
require_relative('load_path_cache/cache')
require_relative('load_path_cache/store')
require_relative('load_path_cache/change_observer')
require_relative('load_path_cache/loaded_features_index')
require_relative('load_path_cache/realpath_cache')
require_relative("load_path_cache/path_scanner")
require_relative("load_path_cache/path")
require_relative("load_path_cache/cache")
require_relative("load_path_cache/store")
require_relative("load_path_cache/change_observer")
require_relative("load_path_cache/loaded_features_index")
require_relative("load_path_cache/realpath_cache")
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
require_relative('../explicit_require')
require_relative("../explicit_require")
module Bootsnap
module LoadPathCache
@ -28,15 +28,16 @@ module Bootsnap
BUILTIN_FEATURES = $LOADED_FEATURES.each_with_object({}) do |feat, features|
# Builtin features are of the form 'enumerator.so'.
# All others include paths.
next unless feat.size < 20 && !feat.include?('/')
next unless feat.size < 20 && !feat.include?("/")
base = File.basename(feat, '.*') # enumerator.so -> enumerator
base = File.basename(feat, ".*") # enumerator.so -> enumerator
ext = File.extname(feat) # .so
features[feat] = nil # enumerator.so
features[base] = nil # enumerator
next unless [DOT_SO, *DL_EXTENSIONS].include?(ext)
DL_EXTENSIONS.each do |dl_ext|
features["#{base}#{dl_ext}"] = nil # enumerator.bundle
end
@ -50,7 +51,7 @@ module Bootsnap
return feature if Bootsnap.absolute_path?(feature)
if feature.start_with?('./', '../')
if feature.start_with?("./", "../")
return try_extensions ? expand_path(feature) : File.expand_path(feature).freeze
end
@ -64,7 +65,7 @@ module Bootsnap
# returns false as if it were already loaded; however, there is no
# file to find on disk. We've pre-built a list of these, and we
# return false if any of them is loaded.
raise(LoadPathCache::ReturnFalse, '', []) if BUILTIN_FEATURES.key?(feature)
raise(LoadPathCache::ReturnFalse, "", []) if BUILTIN_FEATURES.key?(feature)
# The feature wasn't found on our preliminary search through the index.
# We resolve this differently depending on what the extension was.
@ -73,13 +74,14 @@ module Bootsnap
# native dynamic extension, e.g. .bundle or .so), we know it was a
# failure and there's nothing more we can do to find the file.
# no extension, .rb, (.bundle or .so)
when '', *CACHED_EXTENSIONS
when "", *CACHED_EXTENSIONS
nil
# Ruby allows specifying native extensions as '.so' even when DLEXT
# is '.bundle'. This is where we handle that case.
when DOT_SO
x = search_index(feature[0..-4] + DLEXT)
return x if x
if DLEXT2
x = search_index(feature[0..-4] + DLEXT2)
return x if x
@ -87,7 +89,7 @@ module Bootsnap
else
# other, unknown extension. For example, `.rake`. Since we haven't
# cached these, we legitimately need to run the load path search.
raise(LoadPathCache::FallbackScan, '', [])
raise(LoadPathCache::FallbackScan, "", [])
end
end
@ -95,16 +97,18 @@ module Bootsnap
# cases where the file doesn't appear to be on the load path. We should
# be able to detect newly-created files without rebooting the
# application.
raise(LoadPathCache::FallbackScan, '', []) if @development_mode
raise(LoadPathCache::FallbackScan, "", []) if @development_mode
end
def unshift_paths(sender, *paths)
return unless sender == @path_obj
@mutex.synchronize { unshift_paths_locked(*paths) }
end
def push_paths(sender, *paths)
return unless sender == @path_obj
@mutex.synchronize { push_paths_locked(*paths) }
end
@ -137,6 +141,7 @@ module Bootsnap
p = Path.new(path)
@has_relative_paths = true if p.relative?
next if p.non_directory?
expanded_path = p.expanded_path
entries, dirs = p.entries_and_dirs(@store)
# push -> low precedence -> set only if unset
@ -151,6 +156,7 @@ module Bootsnap
paths.map(&:to_s).reverse_each do |path|
p = Path.new(path)
next if p.non_directory?
expanded_path = p.expanded_path
entries, dirs = p.entries_and_dirs(@store)
# unshift -> high precedence -> unconditional set
@ -173,56 +179,62 @@ module Bootsnap
end
if DLEXT2
def search_index(f, try_extensions: true)
def search_index(feature, try_extensions: true)
if try_extensions
try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f + DLEXT2) || try_index(f)
try_index(feature + DOT_RB) ||
try_index(feature + DLEXT) ||
try_index(feature + DLEXT2) ||
try_index(feature)
else
try_index(f)
try_index(feature)
end
end
def maybe_append_extension(f)
try_ext(f + DOT_RB) || try_ext(f + DLEXT) || try_ext(f + DLEXT2) || f
def maybe_append_extension(feature)
try_ext(feature + DOT_RB) ||
try_ext(feature + DLEXT) ||
try_ext(feature + DLEXT2) ||
feature
end
else
def search_index(f, try_extensions: true)
def search_index(feature, try_extensions: true)
if try_extensions
try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f)
try_index(feature + DOT_RB) || try_index(feature + DLEXT) || try_index(feature)
else
try_index(f)
try_index(feature)
end
end
def maybe_append_extension(f)
try_ext(f + DOT_RB) || try_ext(f + DLEXT) || f
def maybe_append_extension(feature)
try_ext(feature + DOT_RB) || try_ext(feature + DLEXT) || feature
end
end
s = rand.to_s.force_encoding(Encoding::US_ASCII).freeze
if s.respond_to?(:-@)
if (-s).equal?(s) && (-s.dup).equal?(s) || RUBY_VERSION >= '2.7'
def try_index(f)
if (p = @index[f])
-(File.join(p, f).freeze)
if (-s).equal?(s) && (-s.dup).equal?(s) || RUBY_VERSION >= "2.7"
def try_index(feature)
if (path = @index[feature])
-File.join(path, feature).freeze
end
end
else
def try_index(f)
if (p = @index[f])
-File.join(p, f).untaint
def try_index(feature)
if (path = @index[feature])
-File.join(path, feature).untaint
end
end
end
else
def try_index(f)
if (p = @index[f])
File.join(p, f)
def try_index(feature)
if (path = @index[feature])
File.join(path, feature)
end
end
end
def try_ext(f)
f if File.exist?(f)
def try_ext(feature)
feature if File.exist?(feature)
end
end
end

View File

@ -1,4 +1,5 @@
# frozen_string_literal: true
module Bootsnap
module LoadPathCache
module ChangeObserver
@ -57,6 +58,7 @@ module Bootsnap
def self.register(observer, arr)
return if arr.frozen? # can't register observer, but no need to.
arr.instance_variable_set(:@lpc_observer, observer)
arr.extend(ArrayMixin)
end

View File

@ -1,4 +1,5 @@
# frozen_string_literal: true
module Bootsnap
module LoadPathCache
module CoreExt
@ -13,7 +14,7 @@ module Bootsnap
end
module Kernel
module_function # rubocop:disable Style/ModuleFunction
module_function
alias_method(:require_without_bootsnap, :require)
@ -32,9 +33,9 @@ module Kernel
end
raise(Bootsnap::LoadPathCache::CoreExt.make_load_error(path))
rescue LoadError => e
e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
raise(e)
rescue LoadError => error
error.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
raise(error)
rescue Bootsnap::LoadPathCache::ReturnFalse
false
rescue Bootsnap::LoadPathCache::FallbackScan
@ -75,9 +76,9 @@ class Module
# added to $LOADED_FEATURES and won't be able to hook that modification
# since it's done in C-land.
autoload_without_bootsnap(const, Bootsnap::LoadPathCache.load_path_cache.find(path) || path)
rescue LoadError => e
e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
raise(e)
rescue LoadError => error
error.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
raise(error)
rescue Bootsnap::LoadPathCache::ReturnFalse
false
rescue Bootsnap::LoadPathCache::FallbackScan

View File

@ -1,4 +1,5 @@
# frozen_string_literal: true
class << $LOADED_FEATURES
alias_method(:delete_without_bootsnap, :delete)
def delete(key)

View File

@ -29,14 +29,15 @@ module Bootsnap
@mutex = Mutex.new
# In theory the user could mutate $LOADED_FEATURES and invalidate our
# cache. If this ever comes up in practice or if you, the
# enterprising reader, feels inclined to solve this problem we could
# cache. If this ever comes up in practice - or if you, the
# enterprising reader, feels inclined to solve this problem - we could
# parallel the work done with ChangeObserver on $LOAD_PATH to mirror
# updates to our @lfi.
$LOADED_FEATURES.each do |feat|
hash = feat.hash
$LOAD_PATH.each do |lpe|
next unless feat.start_with?(lpe)
# /a/b/lib/my/foo.rb
# ^^^^^^^^^
short = feat[(lpe.length + 1)..-1]
@ -93,7 +94,7 @@ module Bootsnap
ret = yield
long = $LOADED_FEATURES[len..-1].detect do |feat|
offset = 0
while offset = feat.index(short, offset)
while (offset = feat.index(short, offset))
if feat.index(".", offset + 1) && !feat.index("/", offset + 2)
break true
else
@ -128,7 +129,7 @@ module Bootsnap
private
STRIP_EXTENSION = /\.[^.]*?$/
STRIP_EXTENSION = /\.[^.]*?$/.freeze
private_constant(:STRIP_EXTENSION)
# Might Ruby automatically search for this extension if
@ -145,15 +146,15 @@ module Bootsnap
# with calling a Ruby file 'x.dylib.rb' and then requiring it as 'x.dylib'.)
#
# See <https://ruby-doc.org/core-2.6.4/Kernel.html#method-i-require>.
def extension_elidable?(f)
f.to_s.end_with?('.rb', '.so', '.o', '.dll', '.dylib')
def extension_elidable?(feature)
feature.to_s.end_with?(".rb", ".so", ".o", ".dll", ".dylib")
end
def strip_extension_if_elidable(f)
if extension_elidable?(f)
f.sub(STRIP_EXTENSION, '')
def strip_extension_if_elidable(feature)
if extension_elidable?(feature)
feature.sub(STRIP_EXTENSION, "")
else
f
feature
end
end
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require_relative('path_scanner')
require_relative("path_scanner")
module Bootsnap
module LoadPathCache
@ -43,6 +44,7 @@ module Bootsnap
# set to zero anyway, just in case we change the stability heuristics.
_, entries, dirs = store.get(expanded_path)
return [entries, dirs] if entries # cache hit
entries, dirs = scan!
store.set(expanded_path, [0, entries, dirs])
return [entries, dirs]
@ -93,8 +95,8 @@ module Bootsnap
# Built-in ruby lib stuff doesn't change, but things can occasionally be
# installed into sitedir, which generally lives under libdir.
RUBY_LIBDIR = RbConfig::CONFIG['libdir']
RUBY_SITEDIR = RbConfig::CONFIG['sitedir']
RUBY_LIBDIR = RbConfig::CONFIG["libdir"]
RUBY_SITEDIR = RbConfig::CONFIG["sitedir"]
def stability
@stability ||= begin

View File

@ -1,18 +1,18 @@
# frozen_string_literal: true
require_relative('../explicit_require')
require_relative("../explicit_require")
module Bootsnap
module LoadPathCache
module PathScanner
REQUIRABLE_EXTENSIONS = [DOT_RB] + DL_EXTENSIONS
NORMALIZE_NATIVE_EXTENSIONS = !DL_EXTENSIONS.include?(LoadPathCache::DOT_SO)
ALTERNATIVE_NATIVE_EXTENSIONS_PATTERN = /\.(o|bundle|dylib)\z/
ALTERNATIVE_NATIVE_EXTENSIONS_PATTERN = /\.(o|bundle|dylib)\z/.freeze
BUNDLE_PATH = if Bootsnap.bundler?
(Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze
else
''
""
end
class << self
@ -44,7 +44,8 @@ module Bootsnap
def walk(absolute_dir_path, relative_dir_path, &block)
Dir.foreach(absolute_dir_path) do |name|
next if name.start_with?('.')
next if name.start_with?(".")
relative_path = relative_dir_path ? File.join(relative_dir_path, name) : name
absolute_path = "#{absolute_dir_path}/#{name}"
@ -58,7 +59,7 @@ module Bootsnap
end
end
if RUBY_VERSION >= '3.1'
if RUBY_VERSION >= "3.1"
def os_path(path)
path.freeze
end

View File

@ -21,6 +21,7 @@ module Bootsnap
def find_file(name)
return File.realpath(name).freeze if File.exist?(name)
CACHED_EXTENSIONS.each do |ext|
filename = "#{name}#{ext}"
return File.realpath(filename).freeze if File.exist?(filename)

View File

@ -1,14 +1,15 @@
# frozen_string_literal: true
require_relative('../explicit_require')
Bootsnap::ExplicitRequire.with_gems('msgpack') { require('msgpack') }
Bootsnap::ExplicitRequire.from_rubylibdir('fileutils')
require_relative("../explicit_require")
Bootsnap::ExplicitRequire.with_gems("msgpack") { require("msgpack") }
Bootsnap::ExplicitRequire.from_rubylibdir("fileutils")
module Bootsnap
module LoadPathCache
class Store
VERSION_KEY = '__bootsnap_ruby_version__'
CURRENT_VERSION = "#{RUBY_REVISION}-#{RUBY_PLATFORM}".freeze
VERSION_KEY = "__bootsnap_ruby_version__"
CURRENT_VERSION = "#{RUBY_REVISION}-#{RUBY_PLATFORM}".freeze # rubocop:disable Style/RedundantFreeze
NestedTransactionError = Class.new(StandardError)
SetOutsideTransactionNotAllowed = Class.new(StandardError)
@ -26,6 +27,7 @@ module Bootsnap
def fetch(key)
raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
v = get(key)
unless v
@dirty = true
@ -37,6 +39,7 @@ module Bootsnap
def set(key, value)
raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
if value != @data[key]
@dirty = true
@data[key] = value
@ -45,6 +48,7 @@ module Bootsnap
def transaction
raise(NestedTransactionError) if @txn_mutex.owned?
@txn_mutex.synchronize do
begin
yield
@ -88,7 +92,7 @@ module Bootsnap
def dump_data
# Change contents atomically so other processes can't get invalid
# caches if they read at an inopportune time.
tmp = "#{@store_path}.#{Process.pid}.#{(rand * 100000).to_i}.tmp"
tmp = "#{@store_path}.#{Process.pid}.#{(rand * 100_000).to_i}.tmp"
FileUtils.mkpath(File.dirname(tmp))
exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY
# `encoding:` looks redundant wrt `binwrite`, but necessary on windows
@ -103,7 +107,7 @@ module Bootsnap
end
def default_data
{ VERSION_KEY => CURRENT_VERSION }
{VERSION_KEY => CURRENT_VERSION}
end
end
end

View File

@ -1,4 +1,5 @@
# frozen_string_literal: true
require_relative('../bootsnap')
require_relative("../bootsnap")
Bootsnap.default_setup

View File

@ -1,4 +1,5 @@
# frozen_string_literal: true
module Bootsnap
VERSION = "1.9.4"
end

View File

@ -1,17 +1,18 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
class BundlerTest < Minitest::Test
def test_bundler_with_bundle_bin_path_env
without_required_env_keys do
ENV['BUNDLE_BIN_PATH'] = 'foo'
ENV["BUNDLE_BIN_PATH"] = "foo"
assert_predicate(Bootsnap, :bundler?)
end
end
def test_bundler_with_bundle_gemfile_env
without_required_env_keys do
ENV['BUNDLE_GEMFILE'] = 'foo'
ENV["BUNDLE_GEMFILE"] = "foo"
assert_predicate(Bootsnap, :bundler?)
end
end

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true
require('test_helper')
require('bootsnap/cli')
require("test_helper")
require("bootsnap/cli")
module Bootsnap
class CLITest < Minitest::Test
@ -8,52 +9,52 @@ module Bootsnap
def setup
super
@cache_dir = File.expand_path('tmp/cache/bootsnap/compile-cache')
@cache_dir = File.expand_path("tmp/cache/bootsnap/compile-cache")
end
def test_precompile_single_file
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
CompileCache::ISeq.expects(:precompile).with(File.expand_path(path), cache_dir: @cache_dir)
assert_equal 0, CLI.new(['precompile', '-j', '0', path]).run
assert_equal 0, CLI.new(["precompile", "-j", "0", path]).run
end
def test_no_iseq
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
CompileCache::ISeq.expects(:precompile).never
assert_equal 0, CLI.new(['precompile', '-j', '0', '--no-iseq', path]).run
assert_equal 0, CLI.new(["precompile", "-j", "0", "--no-iseq", path]).run
end
def test_precompile_directory
path_a = Help.set_file('foo/a.rb', 'a = a = 3', 100)
path_b = Help.set_file('foo/b.rb', 'b = b = 3', 100)
path_a = Help.set_file("foo/a.rb", "a = a = 3", 100)
path_b = Help.set_file("foo/b.rb", "b = b = 3", 100)
CompileCache::ISeq.expects(:precompile).with(File.expand_path(path_a), cache_dir: @cache_dir)
CompileCache::ISeq.expects(:precompile).with(File.expand_path(path_b), cache_dir: @cache_dir)
assert_equal 0, CLI.new(['precompile', '-j', '0', 'foo']).run
assert_equal 0, CLI.new(["precompile", "-j", "0", "foo"]).run
end
def test_precompile_exclude
path_a = Help.set_file('foo/a.rb', 'a = a = 3', 100)
Help.set_file('foo/b.rb', 'b = b = 3', 100)
path_a = Help.set_file("foo/a.rb", "a = a = 3", 100)
Help.set_file("foo/b.rb", "b = b = 3", 100)
CompileCache::ISeq.expects(:precompile).with(File.expand_path(path_a), cache_dir: @cache_dir)
assert_equal 0, CLI.new(['precompile', '-j', '0', '--exclude', 'b.rb', 'foo']).run
assert_equal 0, CLI.new(["precompile", "-j", "0", "--exclude", "b.rb", "foo"]).run
end
def test_precompile_gemfile
assert_equal 0, CLI.new(['precompile', '--gemfile']).run
assert_equal 0, CLI.new(["precompile", "--gemfile"]).run
end
def test_precompile_yaml
path = Help.set_file('a.yaml', 'foo: bar', 100)
path = Help.set_file("a.yaml", "foo: bar", 100)
CompileCache::YAML.expects(:precompile).with(File.expand_path(path), cache_dir: @cache_dir)
assert_equal 0, CLI.new(['precompile', '-j', '0', path]).run
assert_equal 0, CLI.new(["precompile", "-j", "0", path]).run
end
def test_no_yaml
path = Help.set_file('a.yaml', 'foo: bar', 100)
path = Help.set_file("a.yaml", "foo: bar", 100)
CompileCache::YAML.expects(:precompile).never
assert_equal 0, CLI.new(['precompile', '-j', '0', '--no-yaml', path]).run
assert_equal 0, CLI.new(["precompile", "-j", "0", "--no-yaml", path]).run
end
end
end

View File

@ -1,11 +1,12 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
class CompileCacheISeqTest < Minitest::Test
include(TmpdirHelper)
def test_ruby_bug_18250
Help.set_file('a.rb', 'def foo(*); ->{ super }; end; def foo(**); ->{ super }; end', 100)
Bootsnap::CompileCache::ISeq.fetch('a.rb')
Help.set_file("a.rb", "def foo(*); ->{ super }; end; def foo(**); ->{ super }; end", 100)
Bootsnap::CompileCache::ISeq.fetch("a.rb")
end
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
class CompileCacheJSONTest < Minitest::Test
include(TmpdirHelper)
@ -7,7 +8,7 @@ class CompileCacheJSONTest < Minitest::Test
module FakeJson
Fallback = Class.new(StandardError)
class << self
def load_file(path, symbolize_names: false, freeze: false, fallback: nil)
def load_file(_path, symbolize_names: false, freeze: false, fallback: nil)
raise Fallback
end
end
@ -27,55 +28,55 @@ class CompileCacheJSONTest < Minitest::Test
}
JSON
expected = {
'foo' => 42,
'bar' => [1],
"foo" => 42,
"bar" => [1],
}
assert_equal expected, document
end
def test_load_file
Help.set_file('a.json', '{"foo": "bar"}', 100)
assert_equal({'foo' => 'bar'}, FakeJson.load_file('a.json'))
Help.set_file("a.json", '{"foo": "bar"}', 100)
assert_equal({"foo" => "bar"}, FakeJson.load_file("a.json"))
end
def test_load_file_symbolize_names
Help.set_file('a.json', '{"foo": "bar"}', 100)
FakeJson.load_file('a.json')
Help.set_file("a.json", '{"foo": "bar"}', 100)
FakeJson.load_file("a.json")
if ::Bootsnap::CompileCache::JSON.supported_options.include?(:symbolize_names)
2.times do
assert_equal({foo: 'bar'}, FakeJson.load_file('a.json', symbolize_names: true))
assert_equal({foo: "bar"}, FakeJson.load_file("a.json", symbolize_names: true))
end
else
assert_raises(FakeJson::Fallback) do # would call super
FakeJson.load_file('a.json', symbolize_names: true)
FakeJson.load_file("a.json", symbolize_names: true)
end
end
end
def test_load_file_freeze
Help.set_file('a.json', '["foo"]', 100)
FakeJson.load_file('a.json')
Help.set_file("a.json", '["foo"]', 100)
FakeJson.load_file("a.json")
if ::Bootsnap::CompileCache::JSON.supported_options.include?(:freeze)
2.times do
string = FakeJson.load_file('a.json', freeze: true).first
string = FakeJson.load_file("a.json", freeze: true).first
assert_equal("foo", string)
assert_predicate(string, :frozen?)
end
else
assert_raises(FakeJson::Fallback) do # would call super
FakeJson.load_file('a.json', freeze: true)
FakeJson.load_file("a.json", freeze: true)
end
end
end
def test_load_file_unknown_option
Help.set_file('a.json', '["foo"]', 100)
FakeJson.load_file('a.json')
Help.set_file("a.json", '["foo"]', 100)
FakeJson.load_file("a.json")
assert_raises(FakeJson::Fallback) do # would call super
FakeJson.load_file('a.json', fallback: true)
FakeJson.load_file("a.json", fallback: true)
end
end
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
class CompileCacheYAMLTest < Minitest::Test
include(TmpdirHelper)
@ -7,11 +8,11 @@ class CompileCacheYAMLTest < Minitest::Test
module FakeYaml
Fallback = Class.new(StandardError)
class << self
def load_file(path, symbolize_names: false, freeze: false, fallback: nil)
def load_file(_path, symbolize_names: false, freeze: false, fallback: nil)
raise Fallback
end
def unsafe_load_file(path, symbolize_names: false, freeze: false, fallback: nil)
def unsafe_load_file(_path, symbolize_names: false, freeze: false, fallback: nil)
raise Fallback
end
end
@ -31,7 +32,7 @@ class CompileCacheYAMLTest < Minitest::Test
YAML
expected = {
foo: 42,
'bar' => [1],
"bar" => [1],
}
assert_equal expected, document
end
@ -44,89 +45,89 @@ class CompileCacheYAMLTest < Minitest::Test
YAML
expected = {
foo: 42,
'bar' => [1],
"bar" => [1],
}
assert_equal expected, document
end
def test_yaml_tags
error = assert_raises Bootsnap::CompileCache::Uncompilable do
::Bootsnap::CompileCache::YAML.strict_load('!many Boolean')
::Bootsnap::CompileCache::YAML.strict_load("!many Boolean")
end
assert_equal "YAML tags are not supported: !many", error.message
error = assert_raises Bootsnap::CompileCache::Uncompilable do
::Bootsnap::CompileCache::YAML.strict_load('!ruby/object {}')
::Bootsnap::CompileCache::YAML.strict_load("!ruby/object {}")
end
assert_equal "YAML tags are not supported: !ruby/object", error.message
end
if YAML::VERSION >= '4'
if YAML::VERSION >= "4"
def test_load_psych_4
# Until we figure out a proper strategy, only `YAML.unsafe_load_file`
# is cached with Psych >= 4
Help.set_file('a.yml', "foo: &foo\n bar: 42\nplop:\n <<: *foo", 100)
Help.set_file("a.yml", "foo: &foo\n bar: 42\nplop:\n <<: *foo", 100)
assert_raises FakeYaml::Fallback do
FakeYaml.load_file('a.yml')
FakeYaml.load_file("a.yml")
end
end
else
def test_load_file
Help.set_file('a.yml', "---\nfoo: bar", 100)
assert_equal({'foo' => 'bar'}, FakeYaml.load_file('a.yml'))
Help.set_file("a.yml", "---\nfoo: bar", 100)
assert_equal({"foo" => "bar"}, FakeYaml.load_file("a.yml"))
end
def test_load_file_aliases
Help.set_file('a.yml', "foo: &foo\n bar: 42\nplop:\n <<: *foo", 100)
assert_equal({"foo" => { "bar" => 42 }, "plop" => { "bar" => 42} }, FakeYaml.load_file('a.yml'))
Help.set_file("a.yml", "foo: &foo\n bar: 42\nplop:\n <<: *foo", 100)
assert_equal({"foo" => {"bar" => 42}, "plop" => {"bar" => 42}}, FakeYaml.load_file("a.yml"))
end
def test_load_file_symbolize_names
Help.set_file('a.yml', "---\nfoo: bar", 100)
FakeYaml.load_file('a.yml')
Help.set_file("a.yml", "---\nfoo: bar", 100)
FakeYaml.load_file("a.yml")
if ::Bootsnap::CompileCache::YAML.supported_options.include?(:symbolize_names)
2.times do
assert_equal({foo: 'bar'}, FakeYaml.load_file('a.yml', symbolize_names: true))
assert_equal({foo: "bar"}, FakeYaml.load_file("a.yml", symbolize_names: true))
end
else
assert_raises(FakeYaml::Fallback) do # would call super
FakeYaml.load_file('a.yml', symbolize_names: true)
FakeYaml.load_file("a.yml", symbolize_names: true)
end
end
end
def test_load_file_freeze
Help.set_file('a.yml', "---\nfoo", 100)
FakeYaml.load_file('a.yml')
Help.set_file("a.yml", "---\nfoo", 100)
FakeYaml.load_file("a.yml")
if ::Bootsnap::CompileCache::YAML.supported_options.include?(:freeze)
2.times do
string = FakeYaml.load_file('a.yml', freeze: true)
string = FakeYaml.load_file("a.yml", freeze: true)
assert_equal("foo", string)
assert_predicate(string, :frozen?)
end
else
assert_raises(FakeYaml::Fallback) do # would call super
FakeYaml.load_file('a.yml', freeze: true)
FakeYaml.load_file("a.yml", freeze: true)
end
end
end
def test_load_file_unknown_option
Help.set_file('a.yml', "---\nfoo", 100)
FakeYaml.load_file('a.yml')
Help.set_file("a.yml", "---\nfoo", 100)
FakeYaml.load_file("a.yml")
assert_raises(FakeYaml::Fallback) do # would call super
FakeYaml.load_file('a.yml', fallback: true)
FakeYaml.load_file("a.yml", fallback: true)
end
end
end
if YAML.respond_to?(:unsafe_load_file)
def test_unsafe_load_file
Help.set_file('a.yml', "foo: &foo\n bar: 42\nplop:\n <<: *foo", 100)
assert_equal({"foo" => { "bar" => 42 }, "plop" => { "bar" => 42} }, FakeYaml.unsafe_load_file('a.yml'))
Help.set_file("a.yml", "foo: &foo\n bar: 42\nplop:\n <<: *foo", 100)
assert_equal({"foo" => {"bar" => 42}, "plop" => {"bar" => 42}}, FakeYaml.unsafe_load_file("a.yml"))
end
end
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
class CompileCacheHandlerErrorsTest < Minitest::Test
include(TmpdirHelper)
@ -10,16 +11,16 @@ class CompileCacheHandlerErrorsTest < Minitest::Test
# 3. exception
def test_input_to_storage_unexpected_type
path = Help.set_file('a.rb', 'a = 3', 100)
path = Help.set_file("a.rb", "a = 3", 100)
Bootsnap::CompileCache::ISeq.expects(:input_to_storage).returns(nil)
# this could be made slightly more obvious though.
assert_raises(TypeError) { load(path) }
end
def test_input_to_storage_invalid_instance_of_expected_type
path = Help.set_file('a.rb', 'a = 3', 100)
Bootsnap::CompileCache::ISeq.expects(:input_to_storage).returns('broken')
Bootsnap::CompileCache::ISeq.expects(:input_to_output).with('a = 3', nil).returns('whatever')
path = Help.set_file("a.rb", "a = 3", 100)
Bootsnap::CompileCache::ISeq.expects(:input_to_storage).returns("broken")
Bootsnap::CompileCache::ISeq.expects(:input_to_output).with("a = 3", nil).returns("whatever")
_, err = capture_subprocess_io do
load(path)
end
@ -27,14 +28,14 @@ class CompileCacheHandlerErrorsTest < Minitest::Test
end
def test_input_to_storage_raises
path = Help.set_file('a.rb', 'a = 3', 100)
path = Help.set_file("a.rb", "a = 3", 100)
klass = Class.new(StandardError)
Bootsnap::CompileCache::ISeq.expects(:input_to_storage).raises(klass, 'oops')
Bootsnap::CompileCache::ISeq.expects(:input_to_storage).raises(klass, "oops")
assert_raises(klass) { load(path) }
end
def test_storage_to_output_unexpected_type
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
Bootsnap::CompileCache::ISeq.expects(:storage_to_output).returns(Object.new)
# It seems like ruby doesn't really care.
load(path)
@ -45,16 +46,16 @@ class CompileCacheHandlerErrorsTest < Minitest::Test
# def test_storage_to_output_invalid_instance_of_expected_type
def test_storage_to_output_raises
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
klass = Class.new(StandardError)
Bootsnap::CompileCache::ISeq.expects(:storage_to_output).times(2).raises(klass, 'oops')
Bootsnap::CompileCache::ISeq.expects(:storage_to_output).times(2).raises(klass, "oops")
assert_raises(klass) { load(path) }
# called from two paths; this tests the second.
assert_raises(klass) { load(path) }
end
def test_input_to_output_unexpected_type
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
Bootsnap::CompileCache::ISeq.expects(:input_to_storage).raises(Bootsnap::CompileCache::Uncompilable)
Bootsnap::CompileCache::ISeq.expects(:input_to_output).returns(Object.new)
# It seems like ruby doesn't really care.
@ -66,10 +67,10 @@ class CompileCacheHandlerErrorsTest < Minitest::Test
# def test_input_to_output_invalid_instance_of_expected_type
def test_input_to_output_raises
path = Help.set_file('a.rb', 'a = 3', 100)
path = Help.set_file("a.rb", "a = 3", 100)
klass = Class.new(StandardError)
Bootsnap::CompileCache::ISeq.expects(:input_to_storage).raises(Bootsnap::CompileCache::Uncompilable)
Bootsnap::CompileCache::ISeq.expects(:input_to_output).raises(klass, 'oops')
Bootsnap::CompileCache::ISeq.expects(:input_to_output).raises(klass, "oops")
assert_raises(klass) { load(path) }
end
end

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require('test_helper')
require('tempfile')
require('tmpdir')
require('fileutils')
require("test_helper")
require("tempfile")
require("tmpdir")
require("fileutils")
class CompileCacheKeyFormatTest < Minitest::Test
FILE = File.expand_path(__FILE__)
@ -16,7 +17,7 @@ class CompileCacheKeyFormatTest < Minitest::Test
size: 16...24,
mtime: 24...32,
data_size: 32...40,
}
}.freeze
def test_key_version
key = cache_key_for_file(FILE)
@ -27,12 +28,12 @@ class CompileCacheKeyFormatTest < Minitest::Test
def test_key_compile_option_stable
k1 = cache_key_for_file(FILE)
k2 = cache_key_for_file(FILE)
RubyVM::InstructionSequence.compile_option = { tailcall_optimization: true }
RubyVM::InstructionSequence.compile_option = {tailcall_optimization: true}
k3 = cache_key_for_file(FILE)
assert_equal(k1[R[:compile_option]], k2[R[:compile_option]])
refute_equal(k1[R[:compile_option]], k3[R[:compile_option]])
ensure
RubyVM::InstructionSequence.compile_option = { tailcall_optimization: false }
RubyVM::InstructionSequence.compile_option = {tailcall_optimization: false}
end
def test_key_ruby_revision
@ -60,11 +61,11 @@ class CompileCacheKeyFormatTest < Minitest::Test
end
def test_fetch
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
target = 'NUL'
if RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
target = "NUL"
expected_file = "#{@tmp_dir}/36/9eba19c29ffe00"
else
target = '/dev/null'
target = "/dev/null"
expected_file = "#{@tmp_dir}/8c/d2d180bbd995df"
end
@ -80,7 +81,7 @@ class CompileCacheKeyFormatTest < Minitest::Test
def test_unexistent_fetch
assert_raises(Errno::ENOENT) do
Bootsnap::CompileCache::Native.fetch(@tmp_dir, '123', Bootsnap::CompileCache::ISeq, nil)
Bootsnap::CompileCache::Native.fetch(@tmp_dir, "123", Bootsnap::CompileCache::ISeq, nil)
end
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
class CompileCacheTest < Minitest::Test
include(TmpdirHelper)
@ -14,7 +15,7 @@ class CompileCacheTest < Minitest::Test
def test_coverage_running?
refute(Bootsnap::CompileCache::Native.coverage_running?)
require('coverage')
require("coverage")
begin
Coverage.start
assert(Bootsnap::CompileCache::Native.coverage_running?)
@ -24,7 +25,7 @@ class CompileCacheTest < Minitest::Test
end
def test_no_write_permission_to_cache
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
if RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
# Always pass this test on Windows because directories aren't read, only
# listed. You can restrict the ability to list directory contents on
# Windows or you can set ACLS on a folder such that it is not allowed to
@ -36,25 +37,25 @@ class CompileCacheTest < Minitest::Test
# read-only files.
pass
else
path = Help.set_file('a.rb', 'a = 3', 100)
path = Help.set_file("a.rb", "a = 3", 100)
folder = File.dirname(Help.cache_path(@tmp_dir, path))
FileUtils.mkdir_p(folder)
FileUtils.chmod(0400, folder)
FileUtils.chmod(0o400, folder)
load(path)
end
end
def test_can_open_read_only_cache
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
# Load once to create the cache file
load(path)
FileUtils.chmod(0400, path)
FileUtils.chmod(0o400, path)
# Loading again after the file is marked read-only should still succeed
load(path)
end
def test_file_is_only_read_once
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
storage = RubyVM::InstructionSequence.compile_file(path).to_binary
output = RubyVM::InstructionSequence.load_from_binary(storage)
# This doesn't really *prove* the file is only read once, but
@ -66,7 +67,7 @@ class CompileCacheTest < Minitest::Test
end
def test_raises_syntax_error
path = Help.set_file('a.rb', 'a = (3', 100)
path = Help.set_file("a.rb", "a = (3", 100)
assert_raises(SyntaxError) do
# SyntaxError emits directly to stderr in addition to raising, it seems.
capture_io { load(path) }
@ -74,19 +75,19 @@ class CompileCacheTest < Minitest::Test
end
def test_no_recache_when_mtime_and_size_same
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
storage = RubyVM::InstructionSequence.compile_file(path).to_binary
output = RubyVM::InstructionSequence.load_from_binary(storage)
Bootsnap::CompileCache::ISeq.expects(:input_to_storage).times(1).returns(storage)
Bootsnap::CompileCache::ISeq.expects(:storage_to_output).times(2).returns(output)
load(path)
Help.set_file(path, 'a = a = 4', 100)
Help.set_file(path, "a = a = 4", 100)
load(path)
end
def test_recache_when_mtime_different
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
storage = RubyVM::InstructionSequence.compile_file(path).to_binary
output = RubyVM::InstructionSequence.load_from_binary(storage)
# Totally lies the second time but that's not the point.
@ -94,12 +95,12 @@ class CompileCacheTest < Minitest::Test
Bootsnap::CompileCache::ISeq.expects(:storage_to_output).times(2).returns(output)
load(path)
Help.set_file(path, 'a = a = 2', 101)
Help.set_file(path, "a = a = 2", 101)
load(path)
end
def test_recache_when_size_different
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
storage = RubyVM::InstructionSequence.compile_file(path).to_binary
output = RubyVM::InstructionSequence.load_from_binary(storage)
# Totally lies the second time but that's not the point.
@ -107,27 +108,27 @@ class CompileCacheTest < Minitest::Test
Bootsnap::CompileCache::ISeq.expects(:storage_to_output).times(2).returns(output)
load(path)
Help.set_file(path, 'a = 33', 100)
Help.set_file(path, "a = 33", 100)
load(path)
end
def test_invalid_cache_file
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
cp = Help.cache_path(@tmp_dir, path)
FileUtils.mkdir_p(File.dirname(cp))
File.write(cp, 'nope')
File.write(cp, "nope")
load(path)
assert(File.size(cp) > 32) # cache was overwritten
end
def test_instrumentation_hit
path = Help.set_file('a.rb', 'a = a = 3', 100)
load(path)
file_path = Help.set_file("a.rb", "a = a = 3", 100)
load(file_path)
calls = []
Bootsnap.instrumentation = ->(event, path) { calls << [event, path] }
load(path)
load(file_path)
assert_equal [], calls
ensure
@ -135,29 +136,29 @@ class CompileCacheTest < Minitest::Test
end
def test_instrumentation_miss
path = Help.set_file('a.rb', 'a = a = 3', 100)
file_path = Help.set_file("a.rb", "a = a = 3", 100)
calls = []
Bootsnap.instrumentation = ->(event, path) { calls << [event, path] }
load(path)
load(file_path)
assert_equal [[:miss, 'a.rb']], calls
assert_equal [[:miss, "a.rb"]], calls
ensure
Bootsnap.instrumentation = nil
end
def test_instrumentation_stale
path = Help.set_file('a.rb', 'a = a = 3', 100)
load(path)
path = Help.set_file('a.rb', 'a = a = 4', 101)
file_path = Help.set_file("a.rb", "a = a = 3", 100)
load(file_path)
file_path = Help.set_file("a.rb", "a = a = 4", 101)
calls = []
Bootsnap.instrumentation = ->(event, path) { calls << [event, path] }
load(path)
load(file_path)
assert_equal [[:stale, 'a.rb']], calls
assert_equal [[:stale, "a.rb"]], calls
ensure
Bootsnap.instrumentation = nil
end

View File

@ -1,11 +1,12 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
class HelperTest < MiniTest::Test
include(TmpdirHelper)
def test_validate_cache_path
path = Help.set_file('a.rb', 'a = a = 3', 100)
path = Help.set_file("a.rb", "a = a = 3", 100)
cp = Help.cache_path(@tmp_dir, path)
load(path)
assert_equal(true, File.file?(cp))

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
module Bootsnap
module LoadPathCache
@ -28,31 +29,31 @@ module Bootsnap
# versions aren't a big deal, but feel free to fix the test.
def test_builtin_features
cache = Cache.new(NullCache, [])
assert_raises(ReturnFalse) { cache.find('thread') }
assert_raises(ReturnFalse) { cache.find('thread.rb') }
assert_raises(ReturnFalse) { cache.find('enumerator') }
assert_raises(ReturnFalse) { cache.find('enumerator.so') }
assert_raises(ReturnFalse) { cache.find("thread") }
assert_raises(ReturnFalse) { cache.find("thread.rb") }
assert_raises(ReturnFalse) { cache.find("enumerator") }
assert_raises(ReturnFalse) { cache.find("enumerator.so") }
if RUBY_PLATFORM =~ /darwin/
assert_raises(ReturnFalse) { cache.find('enumerator.bundle') }
assert_raises(ReturnFalse) { cache.find("enumerator.bundle") }
else
assert_raises(FallbackScan) { cache.find('enumerator.bundle') }
assert_raises(FallbackScan) { cache.find("enumerator.bundle") }
end
bundle = RUBY_PLATFORM =~ /darwin/ ? 'bundle' : 'so'
bundle = RUBY_PLATFORM =~ /darwin/ ? "bundle" : "so"
refute(cache.find('thread.' + bundle))
refute(cache.find('enumerator.rb'))
refute(cache.find('encdb.' + bundle))
refute(cache.find("thread." + bundle))
refute(cache.find("enumerator.rb"))
refute(cache.find("encdb." + bundle))
end
def test_simple
po = [@dir1]
cache = Cache.new(NullCache, po)
assert_equal("#{@dir1}/a.rb", cache.find('a'))
refute(cache.find('a', try_extensions: false))
assert_equal("#{@dir1}/a.rb", cache.find("a"))
refute(cache.find("a", try_extensions: false))
cache.push_paths(po, @dir2)
assert_equal("#{@dir2}/b.rb", cache.find('b'))
refute(cache.find('b', try_extensions: false))
assert_equal("#{@dir2}/b.rb", cache.find("b"))
refute(cache.find("b", try_extensions: false))
end
def test_extension_append_for_relative_paths
@ -60,35 +61,35 @@ module Bootsnap
cache = Cache.new(NullCache, po)
dir1_basename = File.basename(@dir1)
Dir.chdir(@dir1) do
assert_equal("#{@dir1}/a.rb", cache.find('./a'))
assert_equal("#{@dir1}/a", cache.find('./a', try_extensions: false))
assert_equal("#{@dir1}/a.rb", cache.find("./a"))
assert_equal("#{@dir1}/a", cache.find("./a", try_extensions: false))
assert_equal("#{@dir1}/a.rb", cache.find("../#{dir1_basename}/a"))
assert_equal("#{@dir1}/a", cache.find("../#{dir1_basename}/a", try_extensions: false))
assert_equal("#{@dir1}/dl#{DLEXT}", cache.find('./dl'))
assert_equal("#{@dir1}/dl", cache.find('./dl', try_extensions: false))
assert_equal("#{@dir1}/enoent", cache.find('./enoent'))
assert_equal("#{@dir1}/enoent", cache.find('./enoent', try_extensions: false))
assert_equal("#{@dir1}/dl#{DLEXT}", cache.find("./dl"))
assert_equal("#{@dir1}/dl", cache.find("./dl", try_extensions: false))
assert_equal("#{@dir1}/enoent", cache.find("./enoent"))
assert_equal("#{@dir1}/enoent", cache.find("./enoent", try_extensions: false))
end
end
def test_unshifted_paths_have_higher_precedence
po = [@dir1]
cache = Cache.new(NullCache, po)
assert_equal("#{@dir1}/conflict.rb", cache.find('conflict'))
assert_equal("#{@dir1}/conflict.rb", cache.find('conflict.rb', try_extensions: false))
assert_equal("#{@dir1}/conflict.rb", cache.find("conflict"))
assert_equal("#{@dir1}/conflict.rb", cache.find("conflict.rb", try_extensions: false))
cache.unshift_paths(po, @dir2)
assert_equal("#{@dir2}/conflict.rb", cache.find('conflict'))
assert_equal("#{@dir2}/conflict.rb", cache.find('conflict.rb', try_extensions: false))
assert_equal("#{@dir2}/conflict.rb", cache.find("conflict"))
assert_equal("#{@dir2}/conflict.rb", cache.find("conflict.rb", try_extensions: false))
end
def test_pushed_paths_have_lower_precedence
po = [@dir1]
cache = Cache.new(NullCache, po)
assert_equal("#{@dir1}/conflict.rb", cache.find('conflict'))
assert_equal("#{@dir1}/conflict.rb", cache.find('conflict.rb', try_extensions: false))
assert_equal("#{@dir1}/conflict.rb", cache.find("conflict"))
assert_equal("#{@dir1}/conflict.rb", cache.find("conflict.rb", try_extensions: false))
cache.push_paths(po, @dir2)
assert_equal("#{@dir1}/conflict.rb", cache.find('conflict'))
assert_equal("#{@dir1}/conflict.rb", cache.find('conflict.rb', try_extensions: false))
assert_equal("#{@dir1}/conflict.rb", cache.find("conflict"))
assert_equal("#{@dir1}/conflict.rb", cache.find("conflict.rb", try_extensions: false))
end
def test_directory_caching
@ -100,8 +101,8 @@ module Bootsnap
def test_extension_permutations
cache = Cache.new(NullCache, [@dir1])
assert_equal("#{@dir1}/dl#{DLEXT}", cache.find('dl'))
refute(cache.find('dl', try_extensions: false))
assert_equal("#{@dir1}/dl#{DLEXT}", cache.find("dl"))
refute(cache.find("dl", try_extensions: false))
assert_equal("#{@dir1}/dl#{DLEXT}", cache.find("dl#{DLEXT}"))
assert_equal("#{@dir1}/both.rb", cache.find("both"))
refute(cache.find("both", try_extensions: false))
@ -114,14 +115,14 @@ module Bootsnap
def test_relative_paths_rescanned
Dir.chdir(@dir2) do
cache = Cache.new(NullCache, %w(foo))
refute(cache.find('bar/baz'))
refute(cache.find("bar/baz"))
Dir.chdir(@dir1) do
# one caveat here is that you get the actual path back when
# resolving relative paths. On darwin, this means that
# /var/folders/... comes back as /private/var/folders/... -- In
# production, this should be fine, but for this test to pass, we
# have to resolve it.
assert_equal(File.realpath("#{@dir1}/foo/bar/baz.rb"), cache.find('bar/baz'))
assert_equal(File.realpath("#{@dir1}/foo/bar/baz.rb"), cache.find("bar/baz"))
end
end
end
@ -136,14 +137,14 @@ module Bootsnap
FileUtils.touch("#{@dir1}/new.rb")
dev_no_cache.stubs(:now).returns(time + 31)
refute(dev_no_cache.find('new'))
refute(dev_no_cache.find("new"))
dev_yes_cache.stubs(:now).returns(time + 28)
assert_raises(Bootsnap::LoadPathCache::FallbackScan) do
dev_yes_cache.find('new')
dev_yes_cache.find("new")
end
dev_yes_cache.stubs(:now).returns(time + 31)
assert(dev_yes_cache.find('new'))
assert(dev_yes_cache.find("new"))
end
def test_path_obj_equal?
@ -152,35 +153,35 @@ module Bootsnap
path_obj.unshift(@dir1)
assert_equal("#{@dir1}/a.rb", cache.find('a'))
assert_equal("#{@dir1}/a.rb", cache.find("a"))
end
if RUBY_VERSION >= '2.5' && !(RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
if RUBY_VERSION >= "2.5" && RbConfig::CONFIG["host_os"] !~ /mswin|mingw|cygwin/
# https://github.com/ruby/ruby/pull/4061
# https://bugs.ruby-lang.org/issues/17517
OS_ASCII_PATH_ENCODING = RUBY_VERSION >= '3.1' ? Encoding::UTF_8 : Encoding::US_ASCII
OS_ASCII_PATH_ENCODING = RUBY_VERSION >= "3.1" ? Encoding::UTF_8 : Encoding::US_ASCII
def test_path_encoding
po = [@dir1]
cache = Cache.new(NullCache, po)
path = cache.find('a')
path = cache.find("a")
assert_equal("#{@dir1}/a.rb", path)
require path
internal_path = $LOADED_FEATURES.last
assert_equal(OS_ASCII_PATH_ENCODING, internal_path.encoding)
assert_equal(OS_ASCII_PATH_ENCODING, path.encoding)
File.write(path, '')
File.write(path, "")
assert_same path, internal_path
utf8_path = cache.find('béé')
utf8_path = cache.find("béé")
require utf8_path
internal_utf8_path = $LOADED_FEATURES.last
assert_equal("#{@dir1}/béé.rb", utf8_path)
assert_equal(Encoding::UTF_8, internal_utf8_path.encoding)
assert_equal(Encoding::UTF_8, utf8_path.encoding)
File.write(utf8_path, '')
File.write(utf8_path, "")
assert_same utf8_path, internal_utf8_path
end
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
module Bootsnap
module LoadPathCache
@ -11,34 +12,34 @@ module Bootsnap
end
def test_observes_changes
@observer.expects(:push_paths).with(@arr, 'a')
@arr << 'a'
@observer.expects(:push_paths).with(@arr, "a")
@arr << "a"
@observer.expects(:push_paths).with(@arr, 'b', 'c')
@arr.push('b', 'c')
@observer.expects(:push_paths).with(@arr, "b", "c")
@arr.push("b", "c")
@observer.expects(:push_paths).with(@arr, 'd', 'e')
@arr.append('d', 'e')
@observer.expects(:push_paths).with(@arr, "d", "e")
@arr.append("d", "e")
@observer.expects(:unshift_paths).with(@arr, 'f', 'g')
@arr.unshift('f', 'g')
@observer.expects(:unshift_paths).with(@arr, "f", "g")
@arr.unshift("f", "g")
@observer.expects(:push_paths).with(@arr, 'h', 'i')
@observer.expects(:push_paths).with(@arr, "h", "i")
@arr.concat(%w(h i))
@observer.expects(:unshift_paths).with(@arr, 'j', 'k')
@arr.prepend('j', 'k')
@observer.expects(:unshift_paths).with(@arr, "j", "k")
@arr.prepend("j", "k")
end
def test_reinitializes_on_aggressive_modifications
@observer.expects(:push_paths).with(@arr, 'a', 'b', 'c')
@arr.push('a', 'b', 'c')
@observer.expects(:push_paths).with(@arr, "a", "b", "c")
@arr.push("a", "b", "c")
@observer.expects(:reinitialize).times(4)
@arr.delete(3)
@arr.compact!
@arr.map!(&:upcase)
assert_equal('C', @arr.pop)
assert_equal("C", @arr.pop)
assert_equal(%w(A B), @arr)
end
@ -50,8 +51,8 @@ module Bootsnap
def test_register_twice_observes_once
ChangeObserver.register(@observer, @arr)
@observer.expects(:push_paths).with(@arr, 'a').once
@arr << 'a'
@observer.expects(:push_paths).with(@arr, "a").once
@arr << "a"
assert_equal(%w(a), @arr)
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
module Bootsnap
module KernelRequireTest
@ -24,10 +25,10 @@ module Bootsnap
end
def test_no_exstensions_for_kernel_load
assert_raises(LoadError) { load 'a' }
assert(load 'no_ext')
assert_raises(LoadError) { load "a" }
assert(load("no_ext"))
Dir.chdir(@dir2)
assert(load 'loads.rb')
assert(load("loads.rb"))
end
end
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
module Bootsnap
module LoadPathCache
@ -11,35 +12,35 @@ module Bootsnap
end
def test_successful_addition
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
@index.register('bundler', '/a/b/bundler.rb') {}
assert(@index.key?('bundler'))
assert(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
@index.register("bundler", "/a/b/bundler.rb") {}
assert(@index.key?("bundler"))
assert(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
end
def test_no_add_on_raise
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
assert_raises(RuntimeError) do
@index.register('bundler', '/a/b/bundler.rb') { raise }
@index.register("bundler", "/a/b/bundler.rb") { raise }
end
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
end
def test_infer_base_from_ext
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
@index.register('bundler.rb') {}
assert(@index.key?('bundler'))
assert(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
@index.register("bundler.rb") {}
assert(@index.key?("bundler"))
assert(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
end
def test_only_strip_elidable_ext
@ -48,95 +49,95 @@ module Bootsnap
#
# E.g. 'descriptor.pb.rb' if required via 'descriptor.pb'
# should never be shortened to merely 'descriptor'!
refute(@index.key?('descriptor.pb'))
refute(@index.key?('descriptor.pb.rb'))
refute(@index.key?('descriptor.rb'))
refute(@index.key?('descriptor'))
refute(@index.key?('foo'))
@index.register('descriptor.pb.rb') {}
assert(@index.key?('descriptor.pb'))
assert(@index.key?('descriptor.pb.rb'))
refute(@index.key?('descriptor.rb'))
refute(@index.key?('descriptor'))
refute(@index.key?('foo'))
refute(@index.key?("descriptor.pb"))
refute(@index.key?("descriptor.pb.rb"))
refute(@index.key?("descriptor.rb"))
refute(@index.key?("descriptor"))
refute(@index.key?("foo"))
@index.register("descriptor.pb.rb") {}
assert(@index.key?("descriptor.pb"))
assert(@index.key?("descriptor.pb.rb"))
refute(@index.key?("descriptor.rb"))
refute(@index.key?("descriptor"))
refute(@index.key?("foo"))
end
def test_shared_library_ext_considered_elidable
# Check that '.dylib' (token shared library extension) is treated as elidable,
# and doesn't get mixed up with Ruby '.rb' files.
refute(@index.key?('libgit2.dylib'))
refute(@index.key?('libgit2.dylib.rb'))
refute(@index.key?('descriptor.rb'))
refute(@index.key?('descriptor'))
refute(@index.key?('foo'))
@index.register('libgit2.dylib') {}
assert(@index.key?('libgit2.dylib'))
refute(@index.key?('libgit2.dylib.rb'))
refute(@index.key?('libgit2.rb'))
refute(@index.key?('foo'))
refute(@index.key?("libgit2.dylib"))
refute(@index.key?("libgit2.dylib.rb"))
refute(@index.key?("descriptor.rb"))
refute(@index.key?("descriptor"))
refute(@index.key?("foo"))
@index.register("libgit2.dylib") {}
assert(@index.key?("libgit2.dylib"))
refute(@index.key?("libgit2.dylib.rb"))
refute(@index.key?("libgit2.rb"))
refute(@index.key?("foo"))
end
def test_cannot_infer_ext_from_base # Current limitation
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
@index.register('bundler') {}
assert(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
@index.register("bundler") {}
assert(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
end
def test_purge_loaded_feature
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
@index.register('bundler', '/a/b/bundler.rb') {}
assert(@index.key?('bundler'))
assert(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
@index.purge('/a/b/bundler.rb')
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
@index.register("bundler", "/a/b/bundler.rb") {}
assert(@index.key?("bundler"))
assert(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
@index.purge("/a/b/bundler.rb")
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
end
def test_purge_multi_loaded_feature
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
@index.register('bundler', '/a/b/bundler.rb') {}
assert(@index.key?('bundler'))
assert(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
@index.purge_multi(['/a/b/bundler.rb', '/a/b/does-not-exist.rb'])
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
@index.register("bundler", "/a/b/bundler.rb") {}
assert(@index.key?("bundler"))
assert(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
@index.purge_multi(["/a/b/bundler.rb", "/a/b/does-not-exist.rb"])
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
end
def test_register_finds_correct_feature
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
@index.register('bundler', nil) { $LOADED_FEATURES << '/a/b/bundler.rb' }
assert(@index.key?('bundler'))
assert(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
@index.purge('/a/b/bundler.rb')
refute(@index.key?('bundler'))
refute(@index.key?('bundler.rb'))
refute(@index.key?('foo'))
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
@index.register("bundler", nil) { $LOADED_FEATURES << "/a/b/bundler.rb" }
assert(@index.key?("bundler"))
assert(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
@index.purge("/a/b/bundler.rb")
refute(@index.key?("bundler"))
refute(@index.key?("bundler.rb"))
refute(@index.key?("foo"))
end
def test_derives_initial_state_from_loaded_features
index = LoadedFeaturesIndex.new
assert(index.key?('minitest/autorun'))
assert(index.key?('minitest/autorun.rb'))
refute(index.key?('minitest/autorun.so'))
assert(index.key?("minitest/autorun"))
assert(index.key?("minitest/autorun.rb"))
refute(index.key?("minitest/autorun.so"))
end
def test_works_with_pathname
path = 'bundler.rb'
path = "bundler.rb"
pathname = Pathname.new(path)
@index.register(pathname, path) { true }
assert(@index.key?(pathname))

View File

@ -1,11 +1,12 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
module Bootsnap
module LoadPathCache
class PathScannerTest < MiniTest::Test
DLEXT = RbConfig::CONFIG['DLEXT']
OTHER_DLEXT = DLEXT == 'bundle' ? 'so' : 'bundle'
DLEXT = RbConfig::CONFIG["DLEXT"]
OTHER_DLEXT = DLEXT == "bundle" ? "so" : "bundle"
def test_scans_requirables_and_dirs
Dir.mktmpdir do |dir|

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true
require('test_helper')
require('bootsnap/load_path_cache')
require("test_helper")
require("bootsnap/load_path_cache")
module Bootsnap
module LoadPathCache
@ -10,17 +11,17 @@ module Bootsnap
end
def test_stability
require('time')
require("time")
time_file = Time.method(:rfc2822).source_location[0]
volatile = Path.new(__FILE__)
stable = Path.new(time_file)
unknown = Path.new('/who/knows')
lib = Path.new(RbConfig::CONFIG['libdir'] + '/a')
site = Path.new(RbConfig::CONFIG['sitedir'] + '/b')
absolute_prefix = RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/ ? ENV['SystemDrive'] : ''
bundler = Path.new(absolute_prefix + '/bp/3')
unknown = Path.new("/who/knows")
lib = Path.new(RbConfig::CONFIG["libdir"] + "/a")
site = Path.new(RbConfig::CONFIG["sitedir"] + "/b")
absolute_prefix = RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/ ? ENV["SystemDrive"] : ""
bundler = Path.new(absolute_prefix + "/bp/3")
Bundler.stubs(:bundle_path).returns(absolute_prefix + '/bp')
Bundler.stubs(:bundle_path).returns(absolute_prefix + "/bp")
assert(stable.stable?, "The stable path #{stable.path.inspect} was unexpectedly not stable.")
refute(stable.volatile?, "The stable path #{stable.path.inspect} was unexpectedly volatile.")
@ -35,17 +36,17 @@ module Bootsnap
end
def test_non_directory?
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
refute(Path.new('c:/dev').non_directory?)
refute(Path.new('c:/nope').non_directory?)
if RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
refute(Path.new("c:/dev").non_directory?)
refute(Path.new("c:/nope").non_directory?)
# there isn't a direct analog i could think of
# assert(Path.new('/dev/null').non_directory?)
assert(Path.new("#{ENV['WinDir']}/System32/Drivers/Etc/hosts").non_directory?)
else
refute(Path.new('/dev').non_directory?)
refute(Path.new('/nope').non_directory?)
assert(Path.new('/dev/null').non_directory?)
assert(Path.new('/etc/hosts').non_directory?)
refute(Path.new("/dev").non_directory?)
refute(Path.new("/nope").non_directory?)
assert(Path.new("/dev/null").non_directory?)
assert(Path.new("/etc/hosts").non_directory?)
end
end

View File

@ -1,11 +1,11 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
module Bootsnap
module LoadPathCache
class RealpathCacheTest < MiniTest::Test
EXTENSIONS = ['', *CACHED_EXTENSIONS]
EXTENSIONS = ["", *CACHED_EXTENSIONS].freeze
def setup
@cache = RealpathCache.new
@ -16,13 +16,13 @@ module Bootsnap
@symlinked_dir = "#{@base_dir}/symlink"
FileUtils.ln_s(@absolute_dir, @symlinked_dir)
real_caller = File.new("#{@absolute_dir}/real_caller.rb", 'w').tap(&:close).path
real_caller = File.new("#{@absolute_dir}/real_caller.rb", "w").tap(&:close).path
symlinked_caller = "#{@absolute_dir}/symlinked_caller.rb"
FileUtils.ln_s(real_caller, symlinked_caller)
EXTENSIONS.each do |ext|
real_required = File.new("#{@absolute_dir}/real_required#{ext}", 'w').tap(&:close).path
real_required = File.new("#{@absolute_dir}/real_required#{ext}", "w").tap(&:close).path
symlinked_required = "#{@absolute_dir}/symlinked_required#{ext}"
FileUtils.ln_s(real_required, symlinked_required)
@ -40,9 +40,11 @@ module Bootsnap
end
end
variants = %w(absolute symlink).product(%w(absolute symlink),
variants = %w(absolute symlink).product(
%w(absolute symlink),
%w(real_caller symlinked_caller),
%w(real_required symlinked_required))
%w(real_required symlinked_required),
)
variants.each do |caller_dir, required_dir, caller_file, required_file|
method_name = "test_with_#{caller_dir}_caller_dir_" \

View File

@ -1,7 +1,8 @@
# frozen_string_literal: true
require('test_helper')
require('tmpdir')
require('fileutils')
require("test_helper")
require("tmpdir")
require("fileutils")
module Bootsnap
module LoadPathCache
@ -19,36 +20,36 @@ module Bootsnap
attr_reader(:store)
def test_persistence
store.transaction { store.set('a', 'b') }
store.transaction { store.set("a", "b") }
store2 = Store.new(@path)
assert_equal('b', store2.get('a'))
assert_equal("b", store2.get("a"))
end
def test_modification
store.transaction { store.set('a', 'b') }
store.transaction { store.set("a", "b") }
store2 = Store.new(@path)
assert_equal('b', store2.get('a'))
store.transaction { store.set('a', 'c') }
assert_equal("b", store2.get("a"))
store.transaction { store.set("a", "c") }
store3 = Store.new(@path)
assert_equal('c', store3.get('a'))
assert_equal("c", store3.get("a"))
end
def test_stores_arrays
store.transaction { store.set('a', [1234, %w(a b)]) }
store.transaction { store.set("a", [1234, %w(a b)]) }
store2 = Store.new(@path)
assert_equal([1234, %w(a b)], store2.get('a'))
assert_equal([1234, %w(a b)], store2.get("a"))
end
def test_transaction_required_to_set
assert_raises(Store::SetOutsideTransactionNotAllowed) do
store.set('a', 'b')
store.set("a", "b")
end
assert_raises(Store::SetOutsideTransactionNotAllowed) do
store.fetch('a') { 'b' }
store.fetch("a") { "b" }
end
end
@ -59,35 +60,35 @@ module Bootsnap
end
def test_no_commit_unless_dirty
store.transaction { store.set('a', nil) }
store.transaction { store.set("a", nil) }
refute(File.exist?(@path))
store.transaction { store.set('a', 1) }
store.transaction { store.set("a", 1) }
assert(File.exist?(@path))
end
def test_retry_on_collision
retries = sequence('retries')
retries = sequence("retries")
MessagePack.expects(:dump).in_sequence(retries).raises(Errno::EEXIST.new("File exists @ rb_sysopen"))
MessagePack.expects(:dump).in_sequence(retries).returns(1)
FileUtils.expects(:mv).in_sequence(retries)
store.transaction { store.set('a', 1) }
store.transaction { store.set("a", 1) }
end
def test_ignore_read_only_filesystem
MessagePack.expects(:dump).raises(Errno::EROFS.new("Read-only file system @ rb_sysopen"))
store.transaction { store.set('a', 1) }
store.transaction { store.set("a", 1) }
refute(File.exist?(@path))
end
def test_bust_cache_on_ruby_change
store.transaction { store.set('a', 'b') }
store.transaction { store.set("a", "b") }
assert_equal 'b', Store.new(@path).get('a')
assert_equal "b", Store.new(@path).get("a")
stub_const(Store, :CURRENT_VERSION, "foobar") do
assert_nil Store.new(@path).get('a')
assert_nil Store.new(@path).get("a")
end
end

View File

@ -1,3 +1,4 @@
# frozen_string_literal: true
require('bundler/setup')
require('bootsnap/setup')
require("bundler/setup")
require("bootsnap/setup")

View File

@ -1,12 +1,13 @@
# frozen_string_literal: true
require('test_helper')
require("test_helper")
module Bootsnap
class SetupTest < Minitest::Test
def setup
@_old_env = ENV.to_h
@tmp_dir = Dir.mktmpdir('bootsnap-test')
ENV['BOOTSNAP_CACHE_DIR'] = @tmp_dir
@tmp_dir = Dir.mktmpdir("bootsnap-test")
ENV["BOOTSNAP_CACHE_DIR"] = @tmp_dir
end
def teardown
@ -27,7 +28,7 @@ module Bootsnap
end
def test_default_setup_with_ENV_not_dev
ENV['ENV'] = 'something'
ENV["ENV"] = "something"
Bootsnap.expects(:setup).with(
cache_dir: @tmp_dir,
@ -42,7 +43,7 @@ module Bootsnap
end
def test_default_setup_with_DISABLE_BOOTSNAP_LOAD_PATH_CACHE
ENV['DISABLE_BOOTSNAP_LOAD_PATH_CACHE'] = 'something'
ENV["DISABLE_BOOTSNAP_LOAD_PATH_CACHE"] = "something"
Bootsnap.expects(:setup).with(
cache_dir: @tmp_dir,
@ -57,7 +58,7 @@ module Bootsnap
end
def test_default_setup_with_DISABLE_BOOTSNAP_COMPILE_CACHE
ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'] = 'something'
ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"] = "something"
Bootsnap.expects(:setup).with(
cache_dir: @tmp_dir,
@ -72,14 +73,14 @@ module Bootsnap
end
def test_default_setup_with_DISABLE_BOOTSNAP
ENV['DISABLE_BOOTSNAP'] = 'something'
ENV["DISABLE_BOOTSNAP"] = "something"
Bootsnap.expects(:setup).never
Bootsnap.default_setup
end
def test_default_setup_with_BOOTSNAP_LOG
ENV['BOOTSNAP_LOG'] = 'something'
ENV["BOOTSNAP_LOG"] = "something"
Bootsnap.expects(:setup).with(
cache_dir: @tmp_dir,

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
if defined? Warning
if Warning.respond_to?(:[]=)
@ -7,18 +8,18 @@ if defined? Warning
end
end
require('bundler/setup')
require('bootsnap')
require('bootsnap/compile_cache/yaml')
require('bootsnap/compile_cache/json')
require("bundler/setup")
require("bootsnap")
require("bootsnap/compile_cache/yaml")
require("bootsnap/compile_cache/json")
require('tmpdir')
require('fileutils')
require("tmpdir")
require("fileutils")
require('minitest/autorun')
require('mocha/minitest')
require("minitest/autorun")
require("mocha/minitest")
cache_dir = File.expand_path('../../tmp/bootsnap/compile-cache', __FILE__)
cache_dir = File.expand_path("../tmp/bootsnap/compile-cache", __dir__)
Bootsnap::CompileCache.setup(cache_dir: cache_dir, iseq: true, yaml: false, json: false)
if GC.respond_to?(:verify_compaction_references)
@ -28,16 +29,16 @@ if GC.respond_to?(:verify_compaction_references)
end
module TestHandler
def self.input_to_storage(_i, p)
'neato ' + p
def self.input_to_storage(_input, path)
"neato " + path
end
def self.storage_to_output(d, _a)
d.upcase
def self.storage_to_output(data, _kwargs)
data.upcase
end
def self.input_to_output(_d, _a)
raise('but why tho')
def self.input_to_output(_data, _kwargs)
raise("but why tho")
end
end
@ -67,7 +68,7 @@ module MiniTest
hash ^= fnv1a_64(args_key)
end
hex = hash.to_s(16).rjust(16, '0')
hex = hash.to_s(16).rjust(16, "0")
"#{dir}/#{hex[0..1]}/#{hex[2..-1]}"
end
@ -95,7 +96,7 @@ module TmpdirHelper
def setup
super
@prev_dir = Dir.pwd
@tmp_dir = Dir.mktmpdir('bootsnap-test')
@tmp_dir = Dir.mktmpdir("bootsnap-test")
Dir.chdir(@tmp_dir)
@prev = Bootsnap::CompileCache::ISeq.cache_dir
Bootsnap::CompileCache::ISeq.cache_dir = @tmp_dir

View File

@ -1,20 +1,21 @@
# frozen_string_literal: true
require('test_helper')
require('bootsnap/cli')
require("test_helper")
require("bootsnap/cli")
module Bootsnap
class WorkerPoolTestTest < Minitest::Test
def test_dispatch
@pool = CLI::WorkerPool.create(size: 2, jobs: { touch: ->(path) { File.write(path, $$.to_s) } })
@pool = CLI::WorkerPool.create(size: 2, jobs: {touch: ->(path) { File.write(path, Process.pid.to_s) }})
@pool.spawn
Dir.mktmpdir('bootsnap-test') do |tmpdir|
Dir.mktmpdir("bootsnap-test") do |tmpdir|
10.times do |i|
@pool.push(:touch, File.join(tmpdir, i.to_s))
end
@pool.shutdown
files = Dir.chdir(tmpdir) { Dir['*'] }.sort
files = Dir.chdir(tmpdir) { Dir["*"] }.sort
assert_equal 10.times.map(&:to_s), files
end
end