Class: Audition::BundleSweep

Inherits:
Object
  • Object
show all
Defined in:
lib/audition/bundle_sweep.rb

Overview

Audits every gem in a Gemfile.lock and ranks the results: the "can my whole app move to Ractors" view. Static analysis runs in worker threads; dynamic probes are subprocesses, so they genuinely parallelize.

Defined Under Namespace

Classes: Row

Constant Summary collapse

CONCURRENCY =
4
VERDICT_ORDER =
{
  :not_ready => 0, :blocked => 1, :risky => 2, :ready => 3, nil => 4
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(lockfile:, static_only: false, timeout: 30, concurrency: CONCURRENCY) ⇒ BundleSweep

Returns a new instance of BundleSweep.

Parameters:

  • lockfile (String)

    path to a Gemfile.lock

  • static_only (Boolean) (defaults to: false)

    skip dynamic probes

  • timeout (Integer) (defaults to: 30)

    per-probe timeout in seconds

  • concurrency (Integer) (defaults to: CONCURRENCY)

    worker thread count



24
25
26
27
28
29
30
# File 'lib/audition/bundle_sweep.rb', line 24

def initialize(lockfile:, static_only: false, timeout: 30,
  concurrency: CONCURRENCY)
  @lockfile = lockfile
  @static_only = static_only
  @timeout = timeout
  @concurrency = concurrency
end

Instance Method Details

#rows(progress: nil) ⇒ Array<Row>

Audits every locked gem and ranks the results, worst first.

Parameters:

  • progress (Proc, nil) (defaults to: nil)

    called with (row, done, total) as each gem finishes

Returns:



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/audition/bundle_sweep.rb', line 37

def rows(progress: nil)
  gems = locked_gems
  queue = Thread::Queue.new
  gems.each { |g| queue << g }
  queue.close

  collected = []
  mutex = Thread::Mutex.new
  @concurrency.times.map do
    Thread.new do
      while (name, version = queue.pop)
        row = audit_gem(name, version)
        mutex.synchronize do
          collected << row
          progress&.call(row, collected.size, gems.size)
        end
      end
    end
  end.each(&:join)

  collected.sort_by do |row|
    [VERDICT_ORDER.fetch(row.verdict), -row.errors, row.name]
  end
end