Class: TTY::Command::Window::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/tty/command/window/runner.rb

Overview

Spawns the child inside a PTY sized to the window, pumps its output into the block's emulator (and optional log/stream targets), enforces timeouts and builds the final TTY::Command::Result.

Constant Summary collapse

READ_CHUNK =
64 * 1024
SELECT_INTERVAL =
0.25
REAP_DEADLINE =

Post-pump reap budget. If the master closes but the child does not exit promptly (e.g. it double-forked or closed its stdio and kept running), we escalate to SIGKILL after this many seconds rather than blocking the caller forever.

2.0

Instance Method Summary collapse

Constructor Details

#initialize(cmd, options, coordinator, &stream_block) ⇒ Runner

Returns a new instance of Runner.

Parameters:

  • cmd (TTY::Command::Cmd)
  • options (WindowOptions)

    validated window options

  • coordinator (Coordinator)
  • stream_block (Proc, nil)

    yields (chunk, nil) like tty-command



25
26
27
28
29
30
# File 'lib/tty/command/window/runner.rb', line 25

def initialize(cmd, options, coordinator, &stream_block)
  @cmd = cmd
  @options = options
  @coordinator = coordinator
  @stream_block = stream_block
end

Instance Method Details

#run!TTY::Command::Result

Returns:

  • (TTY::Command::Result)


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/tty/command/window/runner.rb', line 33

def run!
  require "pty"
  rows = @options.lines
  width = @coordinator.width

  emulator = Emulator.new(
    rows: rows, cols: width,
    scrollback_limit: @options.scrollback,
    responder: ->(reply) { @session&.write(reply) }
  )
  @block = Block.new(
    emulator: emulator,
    title: @options.title,
    lines: rows,
    on_exit: @options.on_exit,
    interactive: @options.interactive?
  )
  @emulator = emulator

  @session = spawn_child(rows, width)
  started = clock
  # Only retain raw bytes when a capture mode actually consumes them.
  # For capture: :screen the emulator grid holds the final state; the
  # raw stream is dead weight and would grow unbounded on long runs
  # (see review/performance.md H5 / P0-1).
  @needs_raw = !@options.capture_screen?
  @raw = @needs_raw ? (+"").force_encoding(Encoding::BINARY) : nil
  @log = @options.output_log && File.open(@options.output_log, "wb")

  @coordinator.register(@block, child_session: @session)
  InputRouter.attach(@block, @session, @coordinator) if @options.interactive?

  write_initial_input
  timed_out = timed_out_pumping?
  status = reap(timed_out)
  runtime = clock - started

  finish(status, runtime, timed_out)
  raise TTY::Command::TimeoutExceeded if timed_out

  build_result(status, runtime)
ensure
  cleanup
end