Class: Backticks::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/backticks/runner.rb

Overview

An easy-to-use interface for invoking commands and capturing their output. Instances of Runner can be interactive, which prints the command’s output to the terminal and also allows the user to interact with the command. By default commands are unbuffered, using a pseudoterminal to capture the output with no delay.

Constant Summary collapse

BUFFERED =

Default streams to buffer if someone calls bufferered= with Boolean.

[:stdin, :stdout, :stderr].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Runner

Create an instance of Runner.

Examples:

buffer stdout

Runner.new(buffered:[:stdout])

Parameters:

  • [#include?,Boolean] (Hash)

    a customizable set of options

  • [#parameters] (Hash)

    a customizable set of options

  • [Boolean] (Hash)

    a customizable set of options



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/backticks/runner.rb', line 55

def initialize(options={})
  options = {
    :buffered => false,
    :cli => Backticks::CLI::Getopt,
    :interactive => false,
  }.merge(options)

  @cli = options[:cli]
  @chdir = nil
  self.buffered = options[:buffered]
  self.interactive = options[:interactive]
end

Instance Attribute Details

#bufferedArray

List of I/O streams that should be captured using a pipe instead of a pseudoterminal.

When read, this attribute is always an Array of stream names from the set ‘[:stdin, :stdout, :stderr]`.

Note: if you set ‘interactive` to true, then stdin and stdout are unbuffered regardless of how you have set `buffered`!

Returns:

  • (Array)

    list of symbolic stream names



39
40
41
# File 'lib/backticks/runner.rb', line 39

def buffered
  @buffered
end

#chdirString?

Returns PWD for new child processes, default is Dir.pwd.

Returns:

  • (String, nil)

    PWD for new child processes, default is Dir.pwd



42
43
44
# File 'lib/backticks/runner.rb', line 42

def chdir
  @chdir
end

#cli#parameters (readonly)

Returns the CLI-translation object used by this runner.

Returns:

  • (#parameters)

    the CLI-translation object used by this runner



45
46
47
# File 'lib/backticks/runner.rb', line 45

def cli
  @cli
end

#interactiveBoolean

If true, commands will have their stdio streams tied to the parent process so the user can view their output and send input to them. Commands’ output is still captured normally when they are interactive.

Note: if you set ‘interactive` to true, then stdin and stdout will be unbuffered regardless of how you have set `buffered`!

Returns:

  • (Boolean)


27
28
29
# File 'lib/backticks/runner.rb', line 27

def interactive
  @interactive
end

Instance Method Details

#run(*sugar) ⇒ Command

Run a command whose parameters are expressed using some Rubyish sugar. This method accepts an arbitrary number of positional parameters; each parameter can be a Hash, an array, or a simple Object. Arrays and simple objects are appended to argv as words of the command; Hashes are translated to command-line options and then appended to argv.

Hashes are processed by @cli, defaulting to Backticks::CLI::Getopt and easily overridden by passing the ‘cli` option to #initialize.

Examples:

Run docker-compose with complex parameters

run('docker-compose', {file: 'joe.yml'}, 'up', {d:true}, 'mysvc')

Parameters:

  • sugar (Array)

    list of command words and options

Returns:

  • (Command)

    the running command

See Also:



102
103
104
# File 'lib/backticks/runner.rb', line 102

def run(*sugar)
  run_without_sugar(@cli.parameters(*sugar))
end

#run_without_sugar(argv) ⇒ Command

Run a command whose argv is specified in the same manner as Kernel#exec, with no Rubyish sugar.

Parameters:

  • argv (Array)

    command to run; argv is program name and the remaining elements are parameters and flags

Returns:

  • (Command)

    the running command



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/backticks/runner.rb', line 112

def run_without_sugar(argv)
  nopty = !defined?(PTY)

  stdin_r, stdin = if nopty || (buffered.include?(:stdin) && !interactive)
    IO.pipe
  else
    PTY.open
  end

  stdout, stdout_w = if nopty || (buffered.include?(:stdout) && !interactive)
    IO.pipe
  else
    PTY.open
  end

  stderr, stderr_w = if nopty || buffered.include?(:stderr)
    IO.pipe
  else
    PTY.open
  end

  dir = @chdir || Dir.pwd
  pid = spawn(*argv, in: stdin_r, out: stdout_w, err: stderr_w, chdir: dir)
  stdin_r.close
  stdout_w.close
  stderr_w.close
  unless interactive
    stdin.close
    stdin = nil
  end

  Command.new(pid, stdin, stdout, stderr, interactive:interactive)
end