Class: Whodunit::Chronicles::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/whodunit/chronicles/cli.rb,
sig/whodunit/chronicles/cli.rbs

Overview

Small operational command-line interface for ledger lifecycle tasks.

The CLI owns book preparation, migration-like operations, index creation, verification, and status checks. The runtime chronicler only appends entries into a ledger it has been handed.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv:, out:, err:) ⇒ CLI

Create a CLI instance.

Parameters:

  • argv (Array<String>)

    command-line arguments

  • out (#puts)

    output stream

  • err (#puts)

    error stream

  • argv: (Array[String])
  • out: (Object)
  • err: (Object)


31
32
33
34
35
# File 'lib/whodunit/chronicles/cli.rb', line 31

def initialize(argv:, out:, err:)
  @argv = argv.dup
  @out = out
  @err = err
end

Class Method Details

.run(argv, out: $stdout, err: $stderr) ⇒ Integer

Run a command with argv-style arguments.

Parameters:

  • argv (Array<String>)

    command-line arguments

  • out (#puts) (defaults to: $stdout)

    output stream

  • err (#puts) (defaults to: $stderr)

    error stream

  • out: (Object) (defaults to: $stdout)
  • err: (Object) (defaults to: $stderr)

Returns:

  • (Integer)

    process-style exit code



22
23
24
# File 'lib/whodunit/chronicles/cli.rb', line 22

def self.run(argv, out: $stdout, err: $stderr)
  new(argv: argv, out: out, err: err).run
end

Instance Method Details

#ensure_supported!(ledger, method_name) ⇒ true

Ensure a ledger supports an operational method.

Parameters:

  • ledger (Object)
  • method_name (Symbol)

Returns:

  • (true)

Raises:



110
111
112
113
114
# File 'lib/whodunit/chronicles/cli.rb', line 110

def ensure_supported!(ledger, method_name)
  return true if ledger.respond_to?(method_name)

  raise LedgerError, "ledger does not support #{method_name}"
end

#execute_ledger_command(ledger, command, options) ⇒ Integer

Execute a ledger lifecycle command.

Parameters:

  • ledger (Object)
  • command (String)
  • options (Array[String])

Returns:

  • (Integer)


59
60
61
62
63
64
65
66
67
68
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
# File 'lib/whodunit/chronicles/cli.rb', line 59

def execute_ledger_command(ledger, command, options)
  case command
  when 'prepare'
    return usage(1) unless options.empty?

    ensure_supported!(ledger, :prepare!)
    ledger.prepare!
    @out.puts('prepared')
  when 'migrate'
    return usage(1) unless options.empty?

    ensure_supported!(ledger, :migrate!)
    ledger.migrate!
    @out.puts('migrated')
  when 'ensure-indexes', 'indexes'
    return usage(1) unless options.empty?

    ensure_supported!(ledger, :ensure_indexes!)
    ledger.ensure_indexes!
    @out.puts('indexes ensured')
  when 'verify'
    return usage(1) unless options.empty?

    ensure_supported!(ledger, :verify)
    raise LedgerError, 'ledger verification failed' unless ledger.verify

    @out.puts('verified')
  when 'status'
    return usage(1) unless options.empty? || options == ['--json']

    ensure_supported!(ledger, :status)
    @out.puts(format_status(ledger.status, options))
  else
    return usage(1)
  end
  0
end

#format_status(status, options) ⇒ String

Format status for humans.

Parameters:

  • status (Hash[untyped, untyped])
  • options (Array[String])

Returns:

  • (String)


103
104
105
106
107
# File 'lib/whodunit/chronicles/cli.rb', line 103

def format_status(status, options)
  return JSON.pretty_generate(status) if options == ['--json']

  status.map { |key, value| "#{key}: #{value.inspect}" }.join("\n")
end

#load_config(path) ⇒ Hash[untyped, untyped]

Load YAML configuration from disk.

Parameters:

  • path (String)

Returns:

  • (Hash[untyped, untyped])


98
99
100
# File 'lib/whodunit/chronicles/cli.rb', line 98

def load_config(path)
  YAML.safe_load_file(path, permitted_classes: [Symbol], aliases: false) || {}
end

#runInteger

Execute the requested command.

Returns:

  • (Integer)

    process-style exit code



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/whodunit/chronicles/cli.rb', line 40

def run
  return usage(0) if @argv.empty? || @argv.first == 'help'

  namespace = @argv.shift
  command = @argv.shift
  config_path = @argv.shift
  options = @argv.dup
  return usage(1) unless namespace == 'ledger' && command && config_path

  ledger = LedgerFactory.build(load_config(config_path))
  execute_ledger_command(ledger, command, options)
rescue StandardError => e
  @err.puts(e.message)
  1
end

#usage(code) ⇒ Integer

Print usage information.

Parameters:

  • code (Integer)

Returns:

  • (Integer)


117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/whodunit/chronicles/cli.rb', line 117

def usage(code)
  @out.puts(<<~TEXT)
    Usage:
      whodunit-chronicles ledger prepare CONFIG
      whodunit-chronicles ledger migrate CONFIG
      whodunit-chronicles ledger ensure-indexes CONFIG
      whodunit-chronicles ledger verify CONFIG
      whodunit-chronicles ledger status CONFIG
      whodunit-chronicles ledger status CONFIG --json
  TEXT
  code
end