ed-precompiled_bootsnap 1.18.6-x86_64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +401 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +358 -0
  5. data/exe/bootsnap +5 -0
  6. data/ext/bootsnap/bootsnap.c +1135 -0
  7. data/ext/bootsnap/bootsnap.h +6 -0
  8. data/ext/bootsnap/extconf.rb +33 -0
  9. data/lib/bootsnap/3.0/bootsnap.so +0 -0
  10. data/lib/bootsnap/3.1/bootsnap.so +0 -0
  11. data/lib/bootsnap/3.2/bootsnap.so +0 -0
  12. data/lib/bootsnap/3.3/bootsnap.so +0 -0
  13. data/lib/bootsnap/3.4/bootsnap.so +0 -0
  14. data/lib/bootsnap/bootsnap.so +0 -0
  15. data/lib/bootsnap/bootsnap_ext.rb +7 -0
  16. data/lib/bootsnap/bundler.rb +16 -0
  17. data/lib/bootsnap/cli/worker_pool.rb +208 -0
  18. data/lib/bootsnap/cli.rb +285 -0
  19. data/lib/bootsnap/compile_cache/iseq.rb +123 -0
  20. data/lib/bootsnap/compile_cache/json.rb +89 -0
  21. data/lib/bootsnap/compile_cache/yaml.rb +337 -0
  22. data/lib/bootsnap/compile_cache.rb +52 -0
  23. data/lib/bootsnap/explicit_require.rb +56 -0
  24. data/lib/bootsnap/load_path_cache/cache.rb +244 -0
  25. data/lib/bootsnap/load_path_cache/change_observer.rb +84 -0
  26. data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +37 -0
  27. data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +19 -0
  28. data/lib/bootsnap/load_path_cache/loaded_features_index.rb +159 -0
  29. data/lib/bootsnap/load_path_cache/path.rb +136 -0
  30. data/lib/bootsnap/load_path_cache/path_scanner.rb +81 -0
  31. data/lib/bootsnap/load_path_cache/store.rb +132 -0
  32. data/lib/bootsnap/load_path_cache.rb +80 -0
  33. data/lib/bootsnap/setup.rb +5 -0
  34. data/lib/bootsnap/version.rb +5 -0
  35. data/lib/bootsnap.rb +164 -0
  36. metadata +96 -0
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../explicit_require"
4
+
5
+ module Bootsnap
6
+ module LoadPathCache
7
+ module PathScanner
8
+ REQUIRABLE_EXTENSIONS = [DOT_RB] + DL_EXTENSIONS
9
+ NORMALIZE_NATIVE_EXTENSIONS = !DL_EXTENSIONS.include?(LoadPathCache::DOT_SO)
10
+ ALTERNATIVE_NATIVE_EXTENSIONS_PATTERN = /\.(o|bundle|dylib)\z/.freeze
11
+
12
+ BUNDLE_PATH = if Bootsnap.bundler?
13
+ (Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze
14
+ else
15
+ ""
16
+ end
17
+
18
+ @ignored_directories = %w(node_modules)
19
+
20
+ class << self
21
+ attr_accessor :ignored_directories
22
+
23
+ def call(path)
24
+ path = File.expand_path(path.to_s).freeze
25
+ return [[], []] unless File.directory?(path)
26
+
27
+ # If the bundle path is a descendent of this path, we do additional
28
+ # checks to prevent recursing into the bundle path as we recurse
29
+ # through this path. We don't want to scan the bundle path because
30
+ # anything useful in it will be present on other load path items.
31
+ #
32
+ # This can happen if, for example, the user adds '.' to the load path,
33
+ # and the bundle path is '.bundle'.
34
+ contains_bundle_path = BUNDLE_PATH.start_with?(path)
35
+
36
+ dirs = []
37
+ requirables = []
38
+ walk(path, nil) do |relative_path, absolute_path, is_directory|
39
+ if is_directory
40
+ dirs << os_path(relative_path)
41
+ !contains_bundle_path || !absolute_path.start_with?(BUNDLE_PATH)
42
+ elsif relative_path.end_with?(*REQUIRABLE_EXTENSIONS)
43
+ requirables << os_path(relative_path)
44
+ end
45
+ end
46
+ [requirables, dirs]
47
+ end
48
+
49
+ def walk(absolute_dir_path, relative_dir_path, &block)
50
+ Dir.foreach(absolute_dir_path) do |name|
51
+ next if name.start_with?(".")
52
+
53
+ relative_path = relative_dir_path ? File.join(relative_dir_path, name) : name
54
+
55
+ absolute_path = "#{absolute_dir_path}/#{name}"
56
+ if File.directory?(absolute_path)
57
+ next if ignored_directories.include?(name) || ignored_directories.include?(absolute_path)
58
+
59
+ if yield relative_path, absolute_path, true
60
+ walk(absolute_path, relative_path, &block)
61
+ end
62
+ else
63
+ yield relative_path, absolute_path, false
64
+ end
65
+ end
66
+ end
67
+
68
+ if RUBY_VERSION >= "3.1"
69
+ def os_path(path)
70
+ path.freeze
71
+ end
72
+ else
73
+ def os_path(path)
74
+ path.force_encoding(Encoding::US_ASCII) if path.ascii_only?
75
+ path.freeze
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../explicit_require"
4
+
5
+ Bootsnap::ExplicitRequire.with_gems("msgpack") { require "msgpack" }
6
+
7
+ module Bootsnap
8
+ module LoadPathCache
9
+ class Store
10
+ VERSION_KEY = "__bootsnap_ruby_version__"
11
+ CURRENT_VERSION = "#{RUBY_REVISION}-#{RUBY_PLATFORM}".freeze # rubocop:disable Style/RedundantFreeze
12
+
13
+ NestedTransactionError = Class.new(StandardError)
14
+ SetOutsideTransactionNotAllowed = Class.new(StandardError)
15
+
16
+ def initialize(store_path, readonly: false)
17
+ @store_path = store_path
18
+ @txn_mutex = Mutex.new
19
+ @dirty = false
20
+ @readonly = readonly
21
+ load_data
22
+ end
23
+
24
+ def get(key)
25
+ @data[key]
26
+ end
27
+
28
+ def fetch(key)
29
+ raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
30
+
31
+ v = get(key)
32
+ unless v
33
+ v = yield
34
+ mark_for_mutation!
35
+ @data[key] = v
36
+ end
37
+ v
38
+ end
39
+
40
+ def set(key, value)
41
+ raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
42
+
43
+ if value != @data[key]
44
+ mark_for_mutation!
45
+ @data[key] = value
46
+ end
47
+ end
48
+
49
+ def transaction
50
+ raise(NestedTransactionError) if @txn_mutex.owned?
51
+
52
+ @txn_mutex.synchronize do
53
+ yield
54
+ ensure
55
+ commit_transaction
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def mark_for_mutation!
62
+ @dirty = true
63
+ @data = @data.dup if @data.frozen?
64
+ end
65
+
66
+ def commit_transaction
67
+ if @dirty && !@readonly
68
+ dump_data
69
+ @dirty = false
70
+ end
71
+ end
72
+
73
+ def load_data
74
+ @data = begin
75
+ data = File.open(@store_path, encoding: Encoding::BINARY) do |io|
76
+ MessagePack.load(io, freeze: true)
77
+ end
78
+ if data.is_a?(Hash) && data[VERSION_KEY] == CURRENT_VERSION
79
+ data
80
+ else
81
+ default_data
82
+ end
83
+ # handle malformed data due to upgrade incompatibility
84
+ rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
85
+ default_data
86
+ rescue ArgumentError => error
87
+ if error.message =~ /negative array size/
88
+ default_data
89
+ else
90
+ raise
91
+ end
92
+ end
93
+ end
94
+
95
+ def dump_data
96
+ # Change contents atomically so other processes can't get invalid
97
+ # caches if they read at an inopportune time.
98
+ tmp = "#{@store_path}.#{Process.pid}.#{(rand * 100_000).to_i}.tmp"
99
+ mkdir_p(File.dirname(tmp))
100
+ exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY
101
+ # `encoding:` looks redundant wrt `binwrite`, but necessary on windows
102
+ # because binary is part of mode.
103
+ File.open(tmp, mode: exclusive_write, encoding: Encoding::BINARY) do |io|
104
+ MessagePack.dump(@data, io)
105
+ end
106
+ File.rename(tmp, @store_path)
107
+ rescue Errno::EEXIST
108
+ retry
109
+ rescue SystemCallError
110
+ end
111
+
112
+ def default_data
113
+ {VERSION_KEY => CURRENT_VERSION}
114
+ end
115
+
116
+ def mkdir_p(path)
117
+ stack = []
118
+ until File.directory?(path)
119
+ stack.push path
120
+ path = File.dirname(path)
121
+ end
122
+ stack.reverse_each do |dir|
123
+ Dir.mkdir(dir)
124
+ rescue SystemCallError
125
+ # Check for broken symlinks. Calling File.realpath will raise Errno::ENOENT if that is the case
126
+ File.realpath(dir) if File.symlink?(dir)
127
+ raise unless File.directory?(dir)
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bootsnap
4
+ module LoadPathCache
5
+ FALLBACK_SCAN = BasicObject.new
6
+
7
+ DOT_RB = ".rb"
8
+ DOT_SO = ".so"
9
+ SLASH = "/"
10
+
11
+ DL_EXTENSIONS = ::RbConfig::CONFIG
12
+ .values_at("DLEXT", "DLEXT2")
13
+ .reject { |ext| !ext || ext.empty? }
14
+ .map { |ext| ".#{ext}" }
15
+ .freeze
16
+ DLEXT = DL_EXTENSIONS[0]
17
+ # This is nil on linux and darwin, but I think it's '.o' on some other
18
+ # platform. I'm not really sure which, but it seems better to replicate
19
+ # ruby's semantics as faithfully as possible.
20
+ DLEXT2 = DL_EXTENSIONS[1]
21
+
22
+ CACHED_EXTENSIONS = DLEXT2 ? [DOT_RB, DLEXT, DLEXT2] : [DOT_RB, DLEXT]
23
+
24
+ @enabled = false
25
+
26
+ class << self
27
+ attr_reader(:load_path_cache, :loaded_features_index, :enabled)
28
+ alias_method :enabled?, :enabled
29
+ remove_method(:enabled)
30
+
31
+ def setup(cache_path:, development_mode:, ignore_directories:, readonly: false)
32
+ unless supported?
33
+ warn("[bootsnap/setup] Load path caching is not supported on this implementation of Ruby") if $VERBOSE
34
+ return
35
+ end
36
+
37
+ store = Store.new(cache_path, readonly: readonly)
38
+
39
+ @loaded_features_index = LoadedFeaturesIndex.new
40
+
41
+ PathScanner.ignored_directories = ignore_directories if ignore_directories
42
+ @load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
43
+ @enabled = true
44
+ require_relative "load_path_cache/core_ext/kernel_require"
45
+ require_relative "load_path_cache/core_ext/loaded_features"
46
+ end
47
+
48
+ def unload!
49
+ @enabled = false
50
+ @loaded_features_index = nil
51
+ @realpath_cache = nil
52
+ @load_path_cache = nil
53
+ ChangeObserver.unregister($LOAD_PATH) if supported?
54
+ end
55
+
56
+ def supported?
57
+ if RUBY_PLATFORM.match?(/darwin|linux|bsd|mswin|mingw|cygwin/)
58
+ case RUBY_ENGINE
59
+ when "truffleruby"
60
+ # https://github.com/oracle/truffleruby/issues/3131
61
+ RUBY_ENGINE_VERSION >= "23.1.0"
62
+ when "ruby"
63
+ true
64
+ else
65
+ false
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ if Bootsnap::LoadPathCache.supported?
74
+ require_relative "load_path_cache/path_scanner"
75
+ require_relative "load_path_cache/path"
76
+ require_relative "load_path_cache/cache"
77
+ require_relative "load_path_cache/store"
78
+ require_relative "load_path_cache/change_observer"
79
+ require_relative "load_path_cache/loaded_features_index"
80
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../bootsnap"
4
+
5
+ Bootsnap.default_setup
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bootsnap
4
+ VERSION = "1.18.6"
5
+ end
data/lib/bootsnap.rb ADDED
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "bootsnap/version"
4
+ require_relative "bootsnap/bundler"
5
+ require_relative "bootsnap/load_path_cache"
6
+ require_relative "bootsnap/compile_cache"
7
+
8
+ module Bootsnap
9
+ InvalidConfiguration = Class.new(StandardError)
10
+
11
+ class << self
12
+ attr_reader :logger
13
+
14
+ def log_stats!
15
+ stats = {hit: 0, revalidated: 0, miss: 0, stale: 0}
16
+ self.instrumentation = ->(event, _path) { stats[event] += 1 }
17
+ Kernel.at_exit do
18
+ stats.each do |event, count|
19
+ $stderr.puts "bootsnap #{event}: #{count}"
20
+ end
21
+ end
22
+ end
23
+
24
+ def log!
25
+ self.logger = $stderr.method(:puts)
26
+ end
27
+
28
+ def logger=(logger)
29
+ @logger = logger
30
+ self.instrumentation = if logger.respond_to?(:debug)
31
+ ->(event, path) { @logger.debug("[Bootsnap] #{event} #{path}") unless event == :hit }
32
+ else
33
+ ->(event, path) { @logger.call("[Bootsnap] #{event} #{path}") unless event == :hit }
34
+ end
35
+ end
36
+
37
+ def instrumentation=(callback)
38
+ @instrumentation = callback
39
+ if respond_to?(:instrumentation_enabled=, true)
40
+ self.instrumentation_enabled = !!callback
41
+ end
42
+ end
43
+
44
+ def _instrument(event, path)
45
+ @instrumentation.call(event, path)
46
+ end
47
+
48
+ def setup(
49
+ cache_dir:,
50
+ development_mode: true,
51
+ load_path_cache: true,
52
+ ignore_directories: nil,
53
+ readonly: false,
54
+ revalidation: false,
55
+ compile_cache_iseq: true,
56
+ compile_cache_yaml: true,
57
+ compile_cache_json: true
58
+ )
59
+ if load_path_cache
60
+ Bootsnap::LoadPathCache.setup(
61
+ cache_path: "#{cache_dir}/bootsnap/load-path-cache",
62
+ development_mode: development_mode,
63
+ ignore_directories: ignore_directories,
64
+ readonly: readonly,
65
+ )
66
+ end
67
+
68
+ Bootsnap::CompileCache.setup(
69
+ cache_dir: "#{cache_dir}/bootsnap/compile-cache",
70
+ iseq: compile_cache_iseq,
71
+ yaml: compile_cache_yaml,
72
+ json: compile_cache_json,
73
+ readonly: readonly,
74
+ revalidation: revalidation,
75
+ )
76
+ end
77
+
78
+ def unload_cache!
79
+ LoadPathCache.unload!
80
+ end
81
+
82
+ def default_setup
83
+ env = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || ENV["ENV"]
84
+ development_mode = ["", nil, "development"].include?(env)
85
+
86
+ if enabled?("BOOTSNAP")
87
+ cache_dir = ENV["BOOTSNAP_CACHE_DIR"]
88
+ unless cache_dir
89
+ config_dir_frame = caller.detect do |line|
90
+ line.include?("/config/")
91
+ end
92
+
93
+ unless config_dir_frame
94
+ $stderr.puts("[bootsnap/setup] couldn't infer cache directory! Either:")
95
+ $stderr.puts("[bootsnap/setup] 1. require bootsnap/setup from your application's config directory; or")
96
+ $stderr.puts("[bootsnap/setup] 2. Define the environment variable BOOTSNAP_CACHE_DIR")
97
+
98
+ raise("couldn't infer bootsnap cache directory")
99
+ end
100
+
101
+ path = config_dir_frame.split(/:\d+:/).first
102
+ path = File.dirname(path) until File.basename(path) == "config"
103
+ app_root = File.dirname(path)
104
+
105
+ cache_dir = File.join(app_root, "tmp", "cache")
106
+ end
107
+
108
+ ignore_directories = if ENV.key?("BOOTSNAP_IGNORE_DIRECTORIES")
109
+ ENV["BOOTSNAP_IGNORE_DIRECTORIES"].split(",")
110
+ end
111
+
112
+ setup(
113
+ cache_dir: cache_dir,
114
+ development_mode: development_mode,
115
+ load_path_cache: enabled?("BOOTSNAP_LOAD_PATH_CACHE"),
116
+ compile_cache_iseq: enabled?("BOOTSNAP_COMPILE_CACHE"),
117
+ compile_cache_yaml: enabled?("BOOTSNAP_COMPILE_CACHE"),
118
+ compile_cache_json: enabled?("BOOTSNAP_COMPILE_CACHE"),
119
+ readonly: bool_env("BOOTSNAP_READONLY"),
120
+ revalidation: bool_env("BOOTSNAP_REVALIDATE"),
121
+ ignore_directories: ignore_directories,
122
+ )
123
+
124
+ if ENV["BOOTSNAP_LOG"]
125
+ log!
126
+ elsif ENV["BOOTSNAP_STATS"]
127
+ log_stats!
128
+ end
129
+ end
130
+ end
131
+
132
+ if RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
133
+ def absolute_path?(path)
134
+ path[1] == ":"
135
+ end
136
+ else
137
+ def absolute_path?(path)
138
+ path.start_with?("/")
139
+ end
140
+ end
141
+
142
+ # This is a semi-accurate ruby implementation of the native `rb_get_path(VALUE)` function.
143
+ # The native version is very intricate and may behave differently on windows etc.
144
+ # But we only use it for non-MRI platform.
145
+ def rb_get_path(fname)
146
+ path_path = fname.respond_to?(:to_path) ? fname.to_path : fname
147
+ String.try_convert(path_path) || raise(TypeError, "no implicit conversion of #{path_path.class} into String")
148
+ end
149
+
150
+ # Allow the C extension to redefine `rb_get_path` without warning.
151
+ alias_method :rb_get_path, :rb_get_path # rubocop:disable Lint/DuplicateMethods
152
+
153
+ private
154
+
155
+ def enabled?(key)
156
+ !ENV["DISABLE_#{key}"]
157
+ end
158
+
159
+ def bool_env(key, default: false)
160
+ value = ENV.fetch(key) { default }
161
+ !["0", "false", false].include?(value)
162
+ end
163
+ end
164
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ed-precompiled_bootsnap
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.18.6
5
+ platform: x86_64-linux
6
+ authors:
7
+ - Burke Libbey
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: msgpack
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.2'
26
+ description: Boot large ruby/rails apps faster
27
+ email:
28
+ - burke.libbey@shopify.com
29
+ executables:
30
+ - bootsnap
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - CHANGELOG.md
35
+ - LICENSE.txt
36
+ - README.md
37
+ - exe/bootsnap
38
+ - ext/bootsnap/bootsnap.c
39
+ - ext/bootsnap/bootsnap.h
40
+ - ext/bootsnap/extconf.rb
41
+ - lib/bootsnap.rb
42
+ - lib/bootsnap/3.0/bootsnap.so
43
+ - lib/bootsnap/3.1/bootsnap.so
44
+ - lib/bootsnap/3.2/bootsnap.so
45
+ - lib/bootsnap/3.3/bootsnap.so
46
+ - lib/bootsnap/3.4/bootsnap.so
47
+ - lib/bootsnap/bootsnap.so
48
+ - lib/bootsnap/bootsnap_ext.rb
49
+ - lib/bootsnap/bundler.rb
50
+ - lib/bootsnap/cli.rb
51
+ - lib/bootsnap/cli/worker_pool.rb
52
+ - lib/bootsnap/compile_cache.rb
53
+ - lib/bootsnap/compile_cache/iseq.rb
54
+ - lib/bootsnap/compile_cache/json.rb
55
+ - lib/bootsnap/compile_cache/yaml.rb
56
+ - lib/bootsnap/explicit_require.rb
57
+ - lib/bootsnap/load_path_cache.rb
58
+ - lib/bootsnap/load_path_cache/cache.rb
59
+ - lib/bootsnap/load_path_cache/change_observer.rb
60
+ - lib/bootsnap/load_path_cache/core_ext/kernel_require.rb
61
+ - lib/bootsnap/load_path_cache/core_ext/loaded_features.rb
62
+ - lib/bootsnap/load_path_cache/loaded_features_index.rb
63
+ - lib/bootsnap/load_path_cache/path.rb
64
+ - lib/bootsnap/load_path_cache/path_scanner.rb
65
+ - lib/bootsnap/load_path_cache/store.rb
66
+ - lib/bootsnap/setup.rb
67
+ - lib/bootsnap/version.rb
68
+ homepage: https://github.com/rails/bootsnap
69
+ licenses:
70
+ - MIT
71
+ metadata:
72
+ bug_tracker_uri: https://github.com/rails/bootsnap/issues
73
+ changelog_uri: https://github.com/rails/bootsnap/blob/main/CHANGELOG.md
74
+ source_code_uri: https://github.com/rails/bootsnap
75
+ allowed_push_host: https://rubygems.org
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '3.4'
84
+ - - "<"
85
+ - !ruby/object:Gem::Version
86
+ version: 3.5.dev
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubygems_version: 3.6.7
94
+ specification_version: 4
95
+ summary: Boot large ruby/rails apps faster
96
+ test_files: []