Class: Ibex::Configuration::Report
- Inherits:
-
Object
- Object
- Ibex::Configuration::Report
- Defined in:
- lib/ibex/configuration/explanation.rb,
sig/ibex/configuration/explanation.rbs
Overview
Deterministic, static-no-user-code explanation of every registered setting.
Instance Attribute Summary collapse
- #conflicts ⇒ Array[ConflictRecord] readonly
- #explanations ⇒ Array[Explanation] readonly
- #input ⇒ Input readonly
Instance Method Summary collapse
- #cli_evidence(key, raw, conflicting:) ⇒ Evidence
- #display(value) ⇒ String
-
#dump ⇒ String
Deterministic JSON independent of caller hash insertion order.
- #explanation(value, cli, conflict: nil) ⇒ Explanation
-
#initialize(input, cli: {}) ⇒ Report
constructor
A new instance of Report.
- #location_label(location) ⇒ String
- #render_explanation(entry) ⇒ Array[String]
- #render_text ⇒ String
- #resolve_key(key, cli) ⇒ Value
- #success? ⇒ Boolean
- #to_h ⇒ Hash[String, json_value]
Constructor Details
#initialize(input, cli: {}) ⇒ Report
Returns a new instance of Report.
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/ibex/configuration/explanation.rb', line 301 def initialize(input, cli: {}) raise ArgumentError, "configuration report input must be a Configuration::Input" unless input.is_a?(Input) cli.each_key { |name| Registry.fetch(name) } @input = input conflicts = [] #: Array[ConflictRecord] @explanations = Registry.keys.sort_by(&:name).map do |key| value = resolve_key(key, cli) explanation(value, cli) rescue Conflict => e record = ConflictRecord.new(e) conflicts << record explanation(e.declared, cli, conflict: record) end.freeze @conflicts = conflicts.freeze freeze end |
Instance Attribute Details
#conflicts ⇒ Array[ConflictRecord] (readonly)
298 299 300 |
# File 'lib/ibex/configuration/explanation.rb', line 298 def conflicts @conflicts end |
#explanations ⇒ Array[Explanation] (readonly)
297 298 299 |
# File 'lib/ibex/configuration/explanation.rb', line 297 def explanations @explanations end |
#input ⇒ Input (readonly)
296 297 298 |
# File 'lib/ibex/configuration/explanation.rb', line 296 def input @input end |
Instance Method Details
#cli_evidence(key, raw, conflicting:) ⇒ Evidence
380 381 382 383 384 385 386 387 388 389 390 391 392 |
# File 'lib/ibex/configuration/explanation.rb', line 380 def cli_evidence(key, raw, conflicting:) value = key.validate(raw) grammar = @input.grammar_values status = conflicting ? :conflicting : :accepted reason = if conflicting "conflicts with the fixed grammar contract and was not selected" elsif grammar.key?(key.name) && grammar.fetch(key.name) == value "matches the fixed grammar contract" else "selected canonical command-line request" end Evidence.new(key, source: :cli, value: value, status: status, reason: reason) end |
#display(value) ⇒ String
395 396 397 |
# File 'lib/ibex/configuration/explanation.rb', line 395 def display(value) value.nil? ? "null" : value.to_s end |
#dump ⇒ String
Deterministic JSON independent of caller hash insertion order.
340 341 342 |
# File 'lib/ibex/configuration/explanation.rb', line 340 def dump "#{JSON.generate(to_h)}\n" end |
#explanation(value, cli, conflict: nil) ⇒ Explanation
368 369 370 371 372 373 374 375 376 377 |
# File 'lib/ibex/configuration/explanation.rb', line 368 def explanation(value, cli, conflict: nil) key = value.key evidence = @input.evidence.fetch(key.name, []).dup evidence << cli_evidence(key, cli.fetch(key.name), conflicting: !conflict.nil?) if cli.key?(key.name) recording = @input.recordings.fetch( key.name, Recording.new(:not_applicable, "this setting has no historical source contract in this input") ) Explanation.new(value, evidence: evidence, recording: recording) end |
#location_label(location) ⇒ String
400 401 402 |
# File 'lib/ibex/configuration/explanation.rb', line 400 def location_label(location) "#{location.file || '(source)'}:#{location.line}:#{location.column}" end |
#render_explanation(entry) ⇒ Array[String]
405 406 407 408 409 410 411 412 413 414 415 416 417 418 |
# File 'lib/ibex/configuration/explanation.rb', line 405 def render_explanation(entry) value = entry.value lines = [ "#{value.key.name}=#{display(value.value)} owner=#{value.key.owner_name} " \ "origin=#{value.origin.label} policy=#{value.key.policy} " \ "#{value.explicit ? 'explicit' : 'implicit'} #{value.canonical ? 'canonical' : 'noncanonical'}", " recording=#{entry.recording.state}: #{entry.recording.reason}" ] entry.evidence.each do |evidence| location = evidence.location ? " at #{location_label(evidence.location)}" : "" lines << " #{evidence.status} #{evidence.source}=#{display(evidence.value)}#{location}: #{evidence.reason}" end lines end |
#render_text ⇒ String
345 346 347 348 349 350 |
# File 'lib/ibex/configuration/explanation.rb', line 345 def render_text lines = ["configuration status=#{success? ? 'ok' : 'conflict'} (static-no-user-code): #{@input.path}"] @explanations.each { |entry| lines.concat(render_explanation(entry)) } @conflicts.each { |conflict| lines << "conflict: #{conflict.}" } "#{lines.join("\n")}\n" end |
#resolve_key(key, cli) ⇒ Value
355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/ibex/configuration/explanation.rb', line 355 def resolve_key(key, cli) name = key.name grammar = {} #: Hash[String, config_value] grammar[name] = @input.grammar_values.fetch(name) if @input.grammar_values.key?(name) request = {} #: Hash[String, config_value] request[name] = cli.fetch(name) if cli.key?(name) locations = {} #: Hash[Symbol, Hash[String, Location]] locations[:grammar] = { name => @input.grammar_locations.fetch(name) } \ if @input.grammar_locations.key?(name) Resolver.new(keys: [key], grammar: grammar, cli: request, locations: locations).values.fetch(0) end |
#success? ⇒ Boolean
321 322 323 |
# File 'lib/ibex/configuration/explanation.rb', line 321 def success? @conflicts.empty? end |
#to_h ⇒ Hash[String, json_value]
326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/ibex/configuration/explanation.rb', line 326 def to_h { "ibex_report" => "configuration", "schema_version" => 1, "trust" => "static-no-user-code", "status" => success? ? "ok" : "conflict", "input" => @input.to_h, "configuration" => @explanations.map(&:to_h), "conflicts" => @conflicts.map(&:to_h) } end |