Class: Toys::Utils::Exec::Controller

Inherits:
Object
  • Object
show all
Defined in:
lib/toys/utils/exec.rb

Overview

An object that controls a subprocess. This object is returned from an execution running in the background, or is yielded to a control block for an execution running in the foreground. You may use this object to interact with the subcommand's streams, send signals to the process, and get its result.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#errIO? (readonly)

The subcommand's standard error stream (which can be read from).

Returns:

  • (IO)

    if the command was configured with err: :controller

  • (nil)

    if the command was not configured with err: :controller



454
455
456
# File 'lib/toys/utils/exec.rb', line 454

def err
  @err
end

#exceptionException? (readonly)

The exception raised when the process failed to start.

Exactly one of exception and pid will be non-nil.

Returns:

  • (Exception)

    if the process failed to start.

  • (nil)

    if the process start was successful.



474
475
476
# File 'lib/toys/utils/exec.rb', line 474

def exception
  @exception
end

#inIO? (readonly)

The subcommand's standard input stream (which can be written to).

Returns:

  • (IO)

    if the command was configured with in: :controller

  • (nil)

    if the command was not configured with in: :controller



436
437
438
# File 'lib/toys/utils/exec.rb', line 436

def in
  @in
end

#nameObject (readonly)

The subcommand's name.

Returns:

  • (Object)


427
428
429
# File 'lib/toys/utils/exec.rb', line 427

def name
  @name
end

#outIO? (readonly)

The subcommand's standard output stream (which can be read from).

Returns:

  • (IO)

    if the command was configured with out: :controller

  • (nil)

    if the command was not configured with out: :controller



445
446
447
# File 'lib/toys/utils/exec.rb', line 445

def out
  @out
end

#pidInteger? (readonly)

The process ID.

Exactly one of exception and pid will be non-nil.

Returns:

  • (Integer)

    if the process start was successful

  • (nil)

    if the process could not be started.



464
465
466
# File 'lib/toys/utils/exec.rb', line 464

def pid
  @pid
end

Instance Method Details

#capture(which) ⇒ self

Captures the remaining data in the given stream. After calling this, do not read directly from the stream.

Parameters:

  • which (:out, :err)

    Which stream to capture

Returns:

  • (self)


483
484
485
486
487
488
489
490
491
492
493
# File 'lib/toys/utils/exec.rb', line 483

def capture(which)
  stream = stream_for(which)
  @join_threads << ::Thread.new do
    begin
      @captures[which] = stream.read
    ensure
      stream.close
    end
  end
  self
end

#capture_errself

Captures the remaining data in the standard error stream. After calling this, do not read directly from the stream.

Returns:

  • (self)


511
512
513
# File 'lib/toys/utils/exec.rb', line 511

def capture_err
  capture(:err)
end

#capture_outself

Captures the remaining data in the standard output stream. After calling this, do not read directly from the stream.

Returns:

  • (self)


501
502
503
# File 'lib/toys/utils/exec.rb', line 501

def capture_out
  capture(:out)
end

#executing?Boolean

Determine whether the subcommand is still executing

Returns:

  • (Boolean)


627
628
629
# File 'lib/toys/utils/exec.rb', line 627

def executing?
  @wait_thread&.status ? true : false
end

#kill(sig) ⇒ self Also known as: signal

Send the given signal to the process. The signal may be specified by name or number.

Parameters:

  • sig (Integer, String)

    The signal to send.

Returns:

  • (self)


616
617
618
619
# File 'lib/toys/utils/exec.rb', line 616

def kill(sig)
  ::Process.kill(sig, pid) if pid
  self
end

#redirect(which, io, *io_args) ⇒ self

Redirects the remainder of the given stream.

You may specify the stream as an IO or IO-like object, or as a file specified by its path. If specifying a file, you may optionally provide the mode and permissions for the call to File#open. You can also specify the value :null to indicate the null file.

After calling this, do not interact directly with the stream.

Parameters:

  • which (:in, :out, :err)

    Which stream to redirect

  • io (IO, StringIO, String, :null)

    Where to redirect the stream

  • io_args (Object...)

    The mode and permissions for opening the file, if redirecting to/from a file.

Returns:

  • (self)


531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
# File 'lib/toys/utils/exec.rb', line 531

def redirect(which, io, *io_args)
  io = ::File::NULL if io == :null
  if io.is_a?(::String)
    io_args = which == :in ? ["r"] : ["w"] if io_args.empty?
    io = ::File.open(io, *io_args)
  end
  stream = stream_for(which, allow_in: true)
  @join_threads << ::Thread.new do
    begin
      if which == :in
        ::IO.copy_stream(io, stream)
      else
        ::IO.copy_stream(stream, io)
      end
    ensure
      stream.close
      io.close
    end
  end
  self
end

#redirect_err(io, *io_args) ⇒ self

Redirects the remainder of the standard error stream.

You may specify the stream as an IO or IO-like object, or as a file specified by its path. If specifying a file, you may optionally provide the mode and permissions for the call to File#open.

After calling this, do not interact directly with the stream.

Parameters:

  • io (IO, StringIO, String)

    Where to redirect the stream

  • io_args (Object...)

    The mode and permissions for opening the file, if redirecting to a file.

Returns:

  • (self)


605
606
607
# File 'lib/toys/utils/exec.rb', line 605

def redirect_err(io, *io_args)
  redirect(:err, io, *io_args)
end

#redirect_in(io, *io_args) ⇒ self

Redirects the remainder of the standard input stream.

You may specify the stream as an IO or IO-like object, or as a file specified by its path. If specifying a file, you may optionally provide the mode and permissions for the call to File#open. You can also specify the value :null to indicate the null file.

After calling this, do not interact directly with the stream.

Parameters:

  • io (IO, StringIO, String, :null)

    Where to redirect the stream

  • io_args (Object...)

    The mode and permissions for opening the file, if redirecting from a file.

Returns:

  • (self)


568
569
570
# File 'lib/toys/utils/exec.rb', line 568

def redirect_in(io, *io_args)
  redirect(:in, io, *io_args)
end

#redirect_out(io, *io_args) ⇒ self

Redirects the remainder of the standard output stream.

You may specify the stream as an IO or IO-like object, or as a file specified by its path. If specifying a file, you may optionally provide the mode and permissions for the call to File#open. You can also specify the value :null to indicate the null file.

After calling this, do not interact directly with the stream.

Parameters:

  • io (IO, StringIO, String, :null)

    Where to redirect the stream

  • io_args (Object...)

    The mode and permissions for opening the file, if redirecting to a file.

Returns:

  • (self)


587
588
589
# File 'lib/toys/utils/exec.rb', line 587

def redirect_out(io, *io_args)
  redirect(:out, io, *io_args)
end

#result(timeout: nil) ⇒ Toys::Utils::Exec::Result?

Wait for the subcommand to complete, and return a result object.

Parameters:

  • timeout (Numeric, nil) (defaults to: nil)

    The timeout in seconds, or nil to wait indefinitely.

Returns:



639
640
641
642
643
644
645
646
647
# File 'lib/toys/utils/exec.rb', line 639

def result(timeout: nil)
  return nil if @wait_thread && !@wait_thread.join(timeout)
  @result ||= begin
    close_streams
    @join_threads.each(&:join)
    Result.new(name, @captures[:out], @captures[:err], @wait_thread&.value, @exception)
          .tap { |result| @result_callback&.call(result) }
  end
end