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])


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`!



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

def buffered
  @buffered
end

#chdirString?



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

def chdir
  @chdir
end

#cli#parameters (readonly)



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`!



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')

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.



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