Class: CommandRunner

Inherits:
Object
  • Object
show all
Defined in:
lib/generators/ruby_cms/templates/services/command_runner.rb

Overview

Runs whitelisted Rake tasks and reads log tails for the admin Commands UI.

Class Method Summary collapse

Class Method Details

.run_rake(task, params: {}) ⇒ Hash

Returns { output:, exit_status:, duration_ms:, argv: }.

Parameters:

  • task (String)

    rake task, e.g. "ruby_cms:sync_content_blocks"

  • params (Hash) (defaults to: {})

    free-form key=>value passed to the task as ENV vars (uppercased). Boolean true → "1", false/nil/blank → not set.

Returns:

  • (Hash)

    { output:, exit_status:, duration_ms:, argv: }



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/generators/ruby_cms/templates/services/command_runner.rb', line 12

def run_rake(task, params: {})
  raise ArgumentError, "rake task blank" if task.to_s.strip.blank?

  env = { "RAILS_ENV" => Rails.env.to_s }.merge(env_from_params(params))
  argv = [ "bundle", "exec", "rake", task.to_s ]
  started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  stdout_and_stderr, status = Open3.capture2e(env, *argv, chdir: Rails.root.to_s)
  duration_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started) * 1000).to_i
  text = <<~TEXT.strip
    $ #{cli_preview(argv, params)}
    (exit #{status.exitstatus})

    #{stdout_and_stderr}
  TEXT
  { output: text, exit_status: status.exitstatus.to_i, duration_ms: duration_ms, argv: argv }
rescue Errno::ENOENT => e
  { output: "Failed to run command: #{e.message}", exit_status: -1, duration_ms: 0, argv: [] }
end

.tail_log(lines: 400, max_bytes: 512 * 1024) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/generators/ruby_cms/templates/services/command_runner.rb', line 65

def tail_log(lines: 400, max_bytes: 512 * 1024)
  path = Rails.root.join("log", "#{Rails.env}.log")
  return "(Log file not found: #{path})" unless path.file?

  File.open(path, "rb") do |f|
    size = f.size
    f.seek([ 0, size - max_bytes ].max)
    chunk = f.read
    chunk.lines.last(lines.to_i.clamp(1, 10_000)).join
  end
rescue StandardError => e
  "(Could not read log: #{e.message})"
end