Module: Bootsnap::LoadPathCache::PathScanner

Defined in:
lib/bootsnap/load_path_cache/path_scanner.rb

Constant Summary collapse

REQUIRABLE_EXTENSIONS =
[DOT_RB] + DL_EXTENSIONS
BUNDLE_PATH =
if Bootsnap.bundler?
  (Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze
else
  ""
end

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.ignored_directoriesObject

Returns the value of attribute ignored_directories.



19
20
21
# File 'lib/bootsnap/load_path_cache/path_scanner.rb', line 19

def ignored_directories
  @ignored_directories
end

Class Method Details

.ruby_call(path) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/bootsnap/load_path_cache/path_scanner.rb', line 21

def ruby_call(path)
  path = File.expand_path(path.to_s).freeze
  return [] unless File.directory?(path)

  # If the bundle path is a descendent of this path, we do additional
  # checks to prevent recursing into the bundle path as we recurse
  # through this path. We don't want to scan the bundle path because
  # anything useful in it will be present on other load path items.
  #
  # This can happen if, for example, the user adds '.' to the load path,
  # and the bundle path is '.bundle'.
  contains_bundle_path = BUNDLE_PATH.start_with?(path)

  requirables = []
  walk(path, nil) do |relative_path, absolute_path, is_directory|
    if is_directory
      !contains_bundle_path || !absolute_path.start_with?(BUNDLE_PATH)
    elsif relative_path.end_with?(*REQUIRABLE_EXTENSIONS)
      requirables << relative_path.freeze
    end
  end
  requirables
end

.walk(absolute_dir_path, relative_dir_path, &block) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/bootsnap/load_path_cache/path_scanner.rb', line 45

def walk(absolute_dir_path, relative_dir_path, &block)
  Dir.foreach(absolute_dir_path) do |name|
    next if name.start_with?(".")

    relative_path = relative_dir_path ? File.join(relative_dir_path, name) : name

    absolute_path = "#{absolute_dir_path}/#{name}"
    if File.directory?(absolute_path)
      next if ignored_directories.include?(name) || ignored_directories.include?(absolute_path)

      if yield relative_path, absolute_path, true
        walk(absolute_path, relative_path, &block)
      end
    else
      yield relative_path, absolute_path, false
    end
  end
end

Instance Method Details

#native_call(root_path) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/bootsnap/load_path_cache/path_scanner.rb', line 69

def native_call(root_path)
  # NOTE: if https://bugs.ruby-lang.org/issues/21800 is accepted we should be able
  # to have similar performance with pure Ruby

  # If the bundle path is a descendent of this path, we do additional
  # checks to prevent recursing into the bundle path as we recurse
  # through this path. We don't want to scan the bundle path because
  # anything useful in it will be present on other load path items.
  #
  # This can happen if, for example, the user adds '.' to the load path,
  # and the bundle path is '.bundle'.
  contains_bundle_path = BUNDLE_PATH.start_with?(root_path)

  all_requirables, queue = Native.scan_dir(root_path)
  all_requirables.each(&:freeze)

  queue.reject! do |dir|
    ignored_directories.include?(dir) ||
      (contains_bundle_path && dir.start_with?(BUNDLE_PATH))
  end

  while (path = queue.pop)
    requirables, dirs = Native.scan_dir(File.join(root_path, path))
    dirs.reject! { |dir| ignored_directories.include?(dir) }
    dirs.map! { |f| File.join(path, f).freeze }
    requirables.map! { |f| File.join(path, f).freeze }

    if contains_bundle_path
      dirs.reject! { |dir| dir.start_with?(BUNDLE_PATH) }
    end

    all_requirables.concat(requirables)
    queue.concat(dirs)
  end

  all_requirables
end