Class: Bundler::Spinel::Ledger
- Inherits:
-
Object
- Object
- Bundler::Spinel::Ledger
- Defined in:
- lib/bundler/spinel/ledger.rb
Overview
Append-only JSONL record of compatibility verdicts, one line per ‘(gem, version, engine_rev)`. The single source of truth that the lock-time gate, the curated-source whitelist, and the platform-variant opt-in are all views over.
Append-only because verdicts are facts-as-of-a-rev: we never mutate history, we add a newer probe. ‘lookup` returns the most recent matching line, so a re-probe naturally supersedes an older one.
Defined Under Namespace
Classes: Verdict
Constant Summary collapse
- DEFAULT_PATH =
File.("../../../ledger/compat.jsonl", __dir__)
Instance Attribute Summary collapse
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Instance Method Summary collapse
- #build(gem:, version:, rev:, verdict:, reasons: [], risks: [], probe: "compile") ⇒ Object
- #each ⇒ Object
-
#initialize(path: ENV.fetch("SPINEL_COMPAT_LEDGER", DEFAULT_PATH)) ⇒ Ledger
constructor
A new instance of Ledger.
-
#known_gems ⇒ Object
Every distinct (gem, version) the ledger has ever seen — the candidate set for a forward-compat re-probe sweep under a new rev.
-
#lookup(gem, version, rev) ⇒ Object
Most recent verdict for this exact triple, or nil.
-
#record(verdict) ⇒ Object
Thread-safe: the survey probes gems in parallel and records from many threads.
Constructor Details
#initialize(path: ENV.fetch("SPINEL_COMPAT_LEDGER", DEFAULT_PATH)) ⇒ Ledger
Returns a new instance of Ledger.
45 46 47 48 |
# File 'lib/bundler/spinel/ledger.rb', line 45 def initialize(path: ENV.fetch("SPINEL_COMPAT_LEDGER", DEFAULT_PATH)) @path = path @write_mutex = Mutex.new end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
43 44 45 |
# File 'lib/bundler/spinel/ledger.rb', line 43 def path @path end |
Instance Method Details
#build(gem:, version:, rev:, verdict:, reasons: [], risks: [], probe: "compile") ⇒ Object
94 95 96 97 98 99 100 |
# File 'lib/bundler/spinel/ledger.rb', line 94 def build(gem:, version:, rev:, verdict:, reasons: [], risks: [], probe: "compile") Verdict.new( gem: gem, version: version, rev: rev, verdict: verdict, reasons: reasons, risks: risks, probe: probe, at: Time.now.utc.iso8601 ) end |
#each ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/bundler/spinel/ledger.rb', line 77 def each return enum_for(:each) unless block_given? return unless File.exist?(@path) File.foreach(@path) do |line| line = line.strip next if line.empty? h = JSON.parse(line) yield Verdict.new( gem: h["gem"], version: h["version"], rev: h["rev"], verdict: h["verdict"], reasons: h["reasons"] || [], risks: h["risks"] || [], probe: h["probe"], at: h["at"] ) end end |
#known_gems ⇒ Object
Every distinct (gem, version) the ledger has ever seen — the candidate set for a forward-compat re-probe sweep under a new rev.
71 72 73 74 75 |
# File 'lib/bundler/spinel/ledger.rb', line 71 def known_gems seen = {} each { |v| seen[[v.gem, v.version]] = true } seen.keys end |
#lookup(gem, version, rev) ⇒ Object
Most recent verdict for this exact triple, or nil.
63 64 65 66 67 |
# File 'lib/bundler/spinel/ledger.rb', line 63 def lookup(gem, version, rev) result = nil each { |v| result = v if v.gem == gem && v.version == version && v.rev == rev } result end |
#record(verdict) ⇒ Object
Thread-safe: the survey probes gems in parallel and records from many threads. One ‘write` of the whole line under O_APPEND is a single atomic syscall, so a concurrent `each`/`lookup` reader never sees a torn line; the mutex just serialises writers among themselves.
54 55 56 57 58 59 60 |
# File 'lib/bundler/spinel/ledger.rb', line 54 def record(verdict) FileUtils.mkdir_p(File.dirname(@path)) @write_mutex.synchronize do File.open(@path, "a") { |f| f.write("#{verdict.to_line}\n") } end verdict end |