class Bootsnap::LoadPathCache::Path
def entries_and_dirs(store)
Return a list of all the requirable files and all of the subdirectories
def entries_and_dirs(store) if stable? # the cached_mtime field is unused for 'stable' paths, but is # set to zero anyway, just in case we change the stability heuristics. _, entries, dirs = store.get(path) return [entries, dirs] if entries # cache hit entries, dirs = scan! store.set(path, [0, entries, dirs]) return [entries, dirs] end cached_mtime, entries, dirs = store.get(path) current_mtime = latest_mtime(path, dirs || []) return [[], []] if current_mtime == -1 # path does not exist return [entries, dirs] if cached_mtime == current_mtime entries, dirs = scan! store.set(path, [current_mtime, entries, dirs]) [entries, dirs] end
def initialize(path)
def initialize(path) @path = path.to_s end
def latest_mtime(path, dirs)
list of relative paths to directories under +path+. e.g. for /a/b and
last time a directory was modified in this subtree. +dirs+ should be a
def latest_mtime(path, dirs) max = -1 ["", *dirs].each do |dir| curr = begin File.mtime("#{path}/#{dir}").to_i rescue Errno::ENOENT -1 end max = curr if curr > max end max end
def non_directory?
def non_directory? !File.stat(path).directory? rescue Errno::ENOENT false end
def scan! # (expensive) returns [entries, dirs]
def scan! # (expensive) returns [entries, dirs] PathScanner.call(path) end
def stability
def stability @stability ||= begin if Gem.path.detect { |p| path.start_with?(p.to_s) } STABLE elsif path.start_with?(RUBY_PREFIX) && !path.start_with?(SITE_DIR) STABLE else VOLATILE end end end
def stable?
distribution. When adding or removing files in these paths, the cache
A path is considered 'stable' if it is part of a Gem.path or the ruby
def stable? stability == STABLE end
def volatile?
the ruby distribution root. These paths are scanned for new additions
A path is considered volatile if it doesn't live under a Gem.path or
def volatile? stability == VOLATILE end