Module: Bundler::Codegraph

Defined in:
lib/bundler/codegraph.rb,
lib/bundler/codegraph/lock.rb,
lib/bundler/codegraph/config.rb,
lib/bundler/codegraph/command.rb,
lib/bundler/codegraph/indexer.rb,
lib/bundler/codegraph/version.rb,
lib/bundler/codegraph/backfill.rb,
lib/bundler/codegraph/error_log.rb,
lib/bundler/codegraph/subprocess.rb,
lib/bundler/codegraph/runtime_dir.rb

Overview

Bundler plugin building a CodeGraph index inside every gem it installs, so that an agent can query a dependency's source through codegraph explore --path <gem> instead of reading its files by hand.

Defined Under Namespace

Modules: Lock, RuntimeDir, Subprocess, VERSION Classes: Backfill, Command, Config, ErrorLog, Indexer

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.pending ⇒ Object (readonly)

Returns the value of attribute pending.



25
26
27
# File 'lib/bundler/codegraph.rb', line 25

def pending
  @pending
end

Class Method Details

.after_install(spec_install, root: nil) ⇒ nil

Entry point wired to Bundler's after-install hook, which fires from the install workers themselves. Indexing there would hold a worker for as long as codegraph runs, and stall the rest of the install behind it: the gem is only queued, and after_install_all indexes the queue once installing is over.

Swallows everything: the hook also fires for failed installs, and a broken index must never be the reason a bundle install aborts.

Parameters:

  • spec_install (Bundler::ParallelInstaller::SpecInstallation)
  • root (Pathname, String, nil) (defaults to: nil) —

    root of the project being installed, Bundler.root by default — resolved in the body, where the rescue covers it, never as a keyword default, which is evaluated outside it

Returns:

  • (nil)


42
43
44
45
46
47
48
49
50
# File 'lib/bundler/codegraph.rb', line 42

def self.after_install(spec_install, root: nil)
  return unless spec_install.respond_to?(:installed?) && spec_install.installed?

  spec = spec_install.spec
  pending << spec if dependency?(spec, root || Bundler.root)
  nil
rescue StandardError
  nil
end

.after_install_all(config: nil, shell: nil) ⇒ Hash{Symbol => Integer}?

Entry point wired to Bundler's after-install-all hook, fired once every gem is installed — and not at all when the install fails, in which case bundle codegraph-index picks up whatever was left unindexed.

Swallows everything, for the same reason as after_install, but warns about each gem that failed to index, pointing at codegraph's error output.

Parameters:

  • config (Config, nil) (defaults to: nil) —

    read from the environment by default

  • shell (#warn, nil) (defaults to: nil) —

    Bundler's UI by default; both are resolved in the body, where the rescue covers them

Returns:

  • (Hash{Symbol => Integer}, nil) —

    number of gems per resulting status



63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/bundler/codegraph.rb', line 63

def self.after_install_all(config: nil, shell: nil)
  config ||= Config.new
  shell  ||= Bundler.ui
  specs = []
  specs << pending.pop until pending.empty?
  warn_untrusted_runtime_dir(shell, config) unless specs.empty?
  # Bundler fires `after-install` for every gem on every `bundle install`:
  # a gem codegraph fails on is not retried each time, only once it changes
  # or when `bundle codegraph-index` runs.
  Backfill.new(specs, config: config, skip_failed: true, reporter: reporter_for(shell)).call
rescue StandardError
  nil
end

.dependency?(spec, root) ⇒ Boolean

Whether a spec of the bundle is a dependency worth indexing. bundler itself lives in the Ruby installation, outside the bundle. A project declaring gemspec gets its own spec back as a path: source rooted at the project directory, which is the project, not a dependency: it is told by its Bundler::Source::Gemspec source, since the Gemfile need not sit at the root (Appraisal's gemfiles/*.gemfile use gemspec path: '../'), and by its path for specs that carry no source.

Parameters:

  • spec (#name, #full_gem_path)
  • root (Pathname, String) —

    root of the project

Returns:

  • (Boolean)


122
123
124
125
126
# File 'lib/bundler/codegraph.rb', line 122

def self.dependency?(spec, root)
  return false if spec.name == 'bundler' || own_gemspec?(spec)

  File.expand_path(spec.full_gem_path) != File.expand_path(root.to_s)
end

.gem_version ⇒ Object



6
7
8
# File 'lib/bundler/codegraph/version.rb', line 6

def self.gem_version
  Gem::Version.new VERSION::STRING
end

.warn_untrusted_runtime_dir(shell, config) ⇒ Object

Without a trusted runtime directory the lock and the error logs are both off; say so once rather than let it pass unnoticed — as long as there is any indexing to run at all.



105
106
107
108
109
110
# File 'lib/bundler/codegraph.rb', line 105

def self.warn_untrusted_runtime_dir(shell, config)
  return if config.disabled? || !config.executable || RuntimeDir.path

  shell.warn("bundler-codegraph: #{RuntimeDir.candidate} is not a private directory, " \
             'so indexing runs unserialized and without error logs')
end