tty-command 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/CHANGELOG.md +15 -0
- data/README.md +61 -14
- data/appveyor.yml +3 -1
- data/examples/env.rb +1 -1
- data/examples/redirect_stdin.rb +1 -2
- data/lib/tty/command.rb +2 -1
- data/lib/tty/command/child_process.rb +14 -6
- data/lib/tty/command/cmd.rb +4 -0
- data/lib/tty/command/dry_runner.rb +1 -1
- data/lib/tty/command/printers/abstract.rb +6 -2
- data/lib/tty/command/printers/pretty.rb +12 -6
- data/lib/tty/command/printers/quiet.rb +17 -3
- data/lib/tty/command/process_runner.rb +41 -25
- data/lib/tty/command/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0da26e779e4608d8ea38cf75801e0afa682dfd14
|
4
|
+
data.tar.gz: 1a8f798ca2de05727cd9217a20314a9730763cd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c966cec07e3ded53c89a294291e4ae9b74cdc7c0c81fb9a5843cd26bb0d7846fe14d57ae4b44756f8b5567fe40163bc27d7e33f2fedecb9826e97892002b9ba
|
7
|
+
data.tar.gz: d098129b2cda2da46cab16cc33f1086f7f1aa163b6c6d6a4e4d2a62103ba9e626704bfc2f275e7e6583cbeab3ee5a9352de48135d214b491caaeae8f550e000d
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.8.0] - 2018-04-22
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add :output_only_on_error option by Iulian Onofrei(@revolter)
|
7
|
+
* Add :verbose flag to toggle warnings
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
* Change ProcessRunner to use waitpid2 api for direct status
|
11
|
+
* Change ProcessRunner stdout & stderr reading to use IO.select and be non-blocking
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
* Fix :timeout to raise when long running without input or output
|
15
|
+
* Fix ProcessRunner to ensure no zombie processes on timeouts
|
16
|
+
|
3
17
|
## [v0.7.0] - 2017-11-19
|
4
18
|
|
5
19
|
### Added
|
@@ -96,6 +110,7 @@
|
|
96
110
|
|
97
111
|
* Initial implementation and release
|
98
112
|
|
113
|
+
[v0.8.0]: https://github.com/piotrmurach/tty-command/compare/v0.7.0...v0.8.0
|
99
114
|
[v0.7.0]: https://github.com/piotrmurach/tty-command/compare/v0.6.0...v0.7.0
|
100
115
|
[v0.6.0]: https://github.com/piotrmurach/tty-command/compare/v0.5.0...v0.6.0
|
101
116
|
[v0.5.0]: https://github.com/piotrmurach/tty-command/compare/v0.4.0...v0.5.0
|
data/README.md
CHANGED
@@ -52,6 +52,8 @@ Or install it yourself as:
|
|
52
52
|
* [2.3. Logging](#23-logging)
|
53
53
|
* [2.3.1. Color](#231-color)
|
54
54
|
* [2.3.2. UUID](#232-uuid)
|
55
|
+
* [2.3.3. Only output on error](#233-only-output-on-error)
|
56
|
+
* [2.3.4. Verbose](#234-verbose)
|
55
57
|
* [2.4. Dry run](#24-dry-run)
|
56
58
|
* [2.5. Wait](#25-wait)
|
57
59
|
* [2.6. Test](#26-test)
|
@@ -82,6 +84,8 @@ Or install it yourself as:
|
|
82
84
|
Create a command instance and then run some commands:
|
83
85
|
|
84
86
|
```ruby
|
87
|
+
require 'tty-command'
|
88
|
+
|
85
89
|
cmd = TTY::Command.new
|
86
90
|
cmd.run('ls -la')
|
87
91
|
cmd.run('echo Hello!')
|
@@ -188,18 +192,59 @@ cmd = TTY::Command.new(color: true)
|
|
188
192
|
|
189
193
|
#### 2.3.1 Color
|
190
194
|
|
191
|
-
When using printers you can switch off coloring by using
|
195
|
+
When using printers you can switch off coloring by using `:color` option set to `false`.
|
192
196
|
|
193
197
|
#### 2.3.2 Uuid
|
194
198
|
|
195
|
-
By default when logging is enabled each log entry is prefixed by specific command run uuid number. This number can be switched off using
|
199
|
+
By default, when logging is enabled, each log entry is prefixed by specific command run uuid number. This number can be switched off using the `:uuid` option:
|
196
200
|
|
197
201
|
```ruby
|
198
|
-
cmd = TTY::Command.new
|
202
|
+
cmd = TTY::Command.new(uuid: false)
|
199
203
|
cmd.run('rm -R all_my_files')
|
200
204
|
# => rm -r all_my_files
|
201
205
|
```
|
202
206
|
|
207
|
+
#### 2.3.3 Only output on error
|
208
|
+
|
209
|
+
When using a command that can fail, setting `:only_output_on_error` option to `true` hides the output if the command succeeds:
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
cmd = TTY::Command.new
|
213
|
+
cmd.run('non_failing_command', only_output_on_error: true)
|
214
|
+
```
|
215
|
+
|
216
|
+
This will only print the `Running` and `Finished` lines, while:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
cmd.run('non_failing_command')
|
220
|
+
```
|
221
|
+
|
222
|
+
will also print any output that the `non_failing_command` might generate.
|
223
|
+
|
224
|
+
Running either:
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
cmd.run('failing_command', only_output_on_error: true)
|
228
|
+
```
|
229
|
+
|
230
|
+
either:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
cmd.run('failing_command')
|
234
|
+
```
|
235
|
+
|
236
|
+
will also print the output.
|
237
|
+
|
238
|
+
*Setting this option will cause the output to show at once, at the end of the command.*
|
239
|
+
|
240
|
+
#### 2.3.4 Verbose
|
241
|
+
|
242
|
+
By default commands will produce warnings when, for example `pty` option is not supported on a given platform. You can switch off such warnings with `:verbose` option set to `false`.
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
cmd.run("echo '\e[32mColors!\e[0m'", pty: true, verbose: false)
|
246
|
+
```
|
247
|
+
|
203
248
|
### 2.4 Dry run
|
204
249
|
|
205
250
|
Sometimes it can be useful to put your script into a "dry run" mode that prints commands without actually running them. To simulate execution of the command use the `:dry_run` option:
|
@@ -394,35 +439,37 @@ cmd.run("whilte test1; sleep1; done", timeout: 5, signal: :KILL)
|
|
394
439
|
|
395
440
|
#### 3.2.6 PTY(pseudo terminal)
|
396
441
|
|
397
|
-
The `:pty` configuration option causes the command to be executed in subprocess where each stream is a pseudo terminal
|
442
|
+
The `:pty` configuration option causes the command to be executed in subprocess where each stream is a `pseudo terminal`. By default this options is set to `false`.
|
443
|
+
|
444
|
+
If you require to interface with interactive subprocess then setting this option to `true` will enable a `pty` terminal device. For example, a command may emit colored output only if it is running via terminal device. You may also wish to run a program that waits for user input, and simulates typing in commands and reading responses.
|
445
|
+
|
446
|
+
This option will only work on systems that support BSD pty devices such as Linux or OS X, and it will gracefully fallback to non-pty device on all the other.
|
398
447
|
|
399
|
-
In order to run command in pseudo terminal
|
448
|
+
In order to run command in `pseudo terminal`, either set the flag globally for all commands:
|
400
449
|
|
401
450
|
```ruby
|
402
451
|
cmd = TTY::Command.new(pty: true)
|
403
452
|
```
|
404
453
|
|
405
|
-
or for each executed command
|
454
|
+
or individually for each executed command:
|
406
455
|
|
407
456
|
```ruby
|
408
457
|
cmd.run("echo 'hello'", pty: true)
|
409
458
|
```
|
410
459
|
|
411
|
-
Please note
|
460
|
+
Please note that setting `:pty` to `true` may change how the command behaves. It's important to understand the difference between `interactive` and `non-interactive` modes. For example, executing `git log` to view the commit history in default `non-interactive` mode:
|
412
461
|
|
413
462
|
```ruby
|
414
|
-
|
415
|
-
out # => "hello\n"
|
463
|
+
cmd.run("git log") # => finishes and produces full output
|
416
464
|
```
|
417
465
|
|
418
|
-
|
466
|
+
However, in `interactive` mode with `pty` flag on:
|
419
467
|
|
420
468
|
```ruby
|
421
|
-
|
422
|
-
out # => "hello\r\n"
|
469
|
+
cmd.run("git log", pty: true) # => uses pager and waits for user input (never returns)
|
423
470
|
```
|
424
471
|
|
425
|
-
In addition, any input to command may be echoed to the standard output.
|
472
|
+
In addition, when pty device is used, any input to command may be echoed to the standard output, as well as some redirets may not work.
|
426
473
|
|
427
474
|
#### 3.2.7 Current directory
|
428
475
|
|
@@ -588,4 +635,4 @@ The gem is available as open source under the terms of the [MIT License](http://
|
|
588
635
|
|
589
636
|
## Copyright
|
590
637
|
|
591
|
-
Copyright (c) 2016-
|
638
|
+
Copyright (c) 2016-2018 Piotr Murach. See LICENSE for further details.
|
data/appveyor.yml
CHANGED
data/examples/env.rb
CHANGED
data/examples/redirect_stdin.rb
CHANGED
data/lib/tty/command.rb
CHANGED
@@ -59,6 +59,7 @@ module TTY
|
|
59
59
|
@dry_run = options.fetch(:dry_run) { false }
|
60
60
|
@printer = use_printer(@printer_name, color: @color, uuid: @uuid)
|
61
61
|
@cmd_options = {}
|
62
|
+
@cmd_options[:verbose] = options.fetch(:verbose, true)
|
62
63
|
@cmd_options[:pty] = true if options[:pty]
|
63
64
|
@cmd_options[:binmode] = true if options[:binmode]
|
64
65
|
@cmd_options[:timeout] = options[:timeout] if options[:timeout]
|
@@ -203,7 +204,7 @@ module TTY
|
|
203
204
|
#
|
204
205
|
# @api private
|
205
206
|
def find_printer_class(name)
|
206
|
-
const_name = name.to_s.capitalize.to_sym
|
207
|
+
const_name = name.to_s.split('_').map(&:capitalize).join.to_sym
|
207
208
|
if const_name.empty? || !TTY::Command::Printers.const_defined?(const_name)
|
208
209
|
raise ArgumentError, %(Unknown printer type "#{name}")
|
209
210
|
end
|
@@ -25,8 +25,9 @@ module TTY
|
|
25
25
|
process_opts = normalize_redirect_options(cmd.options)
|
26
26
|
binmode = cmd.options[:binmode] || false
|
27
27
|
pty = cmd.options[:pty] || false
|
28
|
+
verbose = cmd.options[:verbose]
|
28
29
|
|
29
|
-
pty = try_loading_pty if pty
|
30
|
+
pty = try_loading_pty(verbose) if pty
|
30
31
|
require('pty') if pty # load within this scope
|
31
32
|
|
32
33
|
# Create pipes
|
@@ -65,8 +66,8 @@ module TTY
|
|
65
66
|
|
66
67
|
pid = Process.spawn(cmd.to_command, opts)
|
67
68
|
|
68
|
-
# close in parent process
|
69
|
-
|
69
|
+
# close streams in parent process talking to the child
|
70
|
+
close_fds(in_rd, out_wr, err_wr)
|
70
71
|
|
71
72
|
tuple = [pid, in_wr, out_rd, err_rd]
|
72
73
|
|
@@ -75,7 +76,7 @@ module TTY
|
|
75
76
|
return yield(*tuple)
|
76
77
|
ensure
|
77
78
|
# ensure parent pipes are closed
|
78
|
-
|
79
|
+
close_fds(in_wr, out_rd, err_rd)
|
79
80
|
end
|
80
81
|
else
|
81
82
|
tuple
|
@@ -83,16 +84,23 @@ module TTY
|
|
83
84
|
end
|
84
85
|
module_function :spawn
|
85
86
|
|
87
|
+
# Close all streams
|
88
|
+
# @api private
|
89
|
+
def close_fds(*fds)
|
90
|
+
fds.each { |fd| fd && !fd.closed? && fd.close }
|
91
|
+
end
|
92
|
+
module_function :close_fds
|
93
|
+
|
86
94
|
# Try loading pty module
|
87
95
|
#
|
88
96
|
# @return [Boolean]
|
89
97
|
#
|
90
98
|
# @api private
|
91
|
-
def try_loading_pty
|
99
|
+
def try_loading_pty(verbose = false)
|
92
100
|
require 'pty'
|
93
101
|
true
|
94
102
|
rescue LoadError
|
95
|
-
warn("Requested PTY device but the system doesn't support it.")
|
103
|
+
warn("Requested PTY device but the system doesn't support it.") if verbose
|
96
104
|
false
|
97
105
|
end
|
98
106
|
module_function :try_loading_pty
|
data/lib/tty/command/cmd.rb
CHANGED
@@ -22,6 +22,9 @@ module TTY
|
|
22
22
|
# @api public
|
23
23
|
attr_reader :uuid
|
24
24
|
|
25
|
+
# Flag that controls whether to print the output only on error or not
|
26
|
+
attr_reader :only_output_on_error
|
27
|
+
|
25
28
|
# Initialize a new Cmd object
|
26
29
|
#
|
27
30
|
# @api private
|
@@ -53,6 +56,7 @@ module TTY
|
|
53
56
|
@options = opts
|
54
57
|
|
55
58
|
@uuid = SecureRandom.uuid.split('-')[0]
|
59
|
+
@only_output_on_error = opts.fetch(:only_output_on_error) { false }
|
56
60
|
freeze
|
57
61
|
end
|
58
62
|
|
@@ -20,7 +20,7 @@ module TTY
|
|
20
20
|
cmd.to_command
|
21
21
|
message = "#{@printer.decorate('(dry run)', :blue)} " +
|
22
22
|
@printer.decorate(cmd.to_command, :yellow, :bold)
|
23
|
-
@printer.write(message, cmd.uuid)
|
23
|
+
@printer.write(cmd, message, cmd.uuid)
|
24
24
|
Result.new(0, '', '')
|
25
25
|
end
|
26
26
|
end # DryRunner
|
@@ -11,6 +11,7 @@ module TTY
|
|
11
11
|
def_delegators :@color, :decorate
|
12
12
|
|
13
13
|
attr_reader :output, :options
|
14
|
+
attr_accessor :out_data, :err_data
|
14
15
|
|
15
16
|
# Initialize a Printer object
|
16
17
|
#
|
@@ -21,8 +22,11 @@ module TTY
|
|
21
22
|
def initialize(output, options = {})
|
22
23
|
@output = output
|
23
24
|
@options = options
|
24
|
-
@enabled
|
25
|
+
@enabled = options.fetch(:color) { true }
|
25
26
|
@color = ::Pastel.new(output: output, enabled: @enabled)
|
27
|
+
|
28
|
+
@out_data = ''
|
29
|
+
@err_data = ''
|
26
30
|
end
|
27
31
|
|
28
32
|
def print_command_start(cmd, *args)
|
@@ -41,7 +45,7 @@ module TTY
|
|
41
45
|
write(args.join(' '))
|
42
46
|
end
|
43
47
|
|
44
|
-
def write(message)
|
48
|
+
def write(cmd, message)
|
45
49
|
raise NotImplemented, "Abstract printer cannot be used"
|
46
50
|
end
|
47
51
|
end # Abstract
|
@@ -14,38 +14,44 @@ module TTY
|
|
14
14
|
def print_command_start(cmd, *args)
|
15
15
|
message = ["Running #{decorate(cmd.to_command, :yellow, :bold)}"]
|
16
16
|
message << args.map(&:chomp).join(' ') unless args.empty?
|
17
|
-
write(message.join, cmd.uuid)
|
17
|
+
write(cmd, message.join, cmd.uuid)
|
18
18
|
end
|
19
19
|
|
20
20
|
def print_command_out_data(cmd, *args)
|
21
21
|
message = args.map(&:chomp).join(' ')
|
22
|
-
write("\t#{message}", cmd.uuid)
|
22
|
+
write(cmd, "\t#{message}", cmd.uuid, out_data)
|
23
23
|
end
|
24
24
|
|
25
25
|
def print_command_err_data(cmd, *args)
|
26
26
|
message = args.map(&:chomp).join(' ')
|
27
|
-
write("\t" + decorate(message, :red), cmd.uuid)
|
27
|
+
write(cmd, "\t" + decorate(message, :red), cmd.uuid, err_data)
|
28
28
|
end
|
29
29
|
|
30
30
|
def print_command_exit(cmd, status, runtime, *args)
|
31
|
+
unless !cmd.only_output_on_error || status.zero?
|
32
|
+
output << out_data
|
33
|
+
output << err_data
|
34
|
+
end
|
35
|
+
|
31
36
|
runtime = TIME_FORMAT % [runtime, pluralize(runtime, 'second')]
|
32
37
|
message = ["Finished in #{runtime}"]
|
33
38
|
message << " with exit status #{status}" if status
|
34
39
|
message << " (#{success_or_failure(status)})"
|
35
|
-
write(message.join, cmd.uuid)
|
40
|
+
write(cmd, message.join, cmd.uuid)
|
36
41
|
end
|
37
42
|
|
38
43
|
# Write message out to output
|
39
44
|
#
|
40
45
|
# @api private
|
41
|
-
def write(message, uuid = nil)
|
46
|
+
def write(cmd, message, uuid = nil, data = nil)
|
42
47
|
uuid_needed = options.fetch(:uuid) { true }
|
43
48
|
out = []
|
44
49
|
if uuid_needed
|
45
50
|
out << "[#{decorate(uuid, :green)}] " unless uuid.nil?
|
46
51
|
end
|
47
52
|
out << "#{message}\n"
|
48
|
-
|
53
|
+
target = (cmd.only_output_on_error && !data.nil?) ? data : output
|
54
|
+
target << out.join
|
49
55
|
end
|
50
56
|
|
51
57
|
private
|
@@ -12,12 +12,26 @@ module TTY
|
|
12
12
|
# quiet
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
15
|
+
def print_command_out_data(cmd, *args)
|
16
|
+
write(cmd, args.join(' '), out_data)
|
17
|
+
end
|
18
|
+
|
19
|
+
def print_command_err_data(cmd, *args)
|
20
|
+
write(cmd, args.join(' '), err_data)
|
21
|
+
end
|
22
|
+
|
23
|
+
def print_command_exit(cmd, status, *args)
|
24
|
+
unless !cmd.only_output_on_error || status.zero?
|
25
|
+
output << out_data
|
26
|
+
output << err_data
|
27
|
+
end
|
28
|
+
|
16
29
|
# quiet
|
17
30
|
end
|
18
31
|
|
19
|
-
def write(message)
|
20
|
-
|
32
|
+
def write(cmd, message, data = nil)
|
33
|
+
target = (cmd.only_output_on_error && !data.nil?) ? data : output
|
34
|
+
target << message
|
21
35
|
end
|
22
36
|
end # Progress
|
23
37
|
end # Printers
|
@@ -23,7 +23,8 @@ module TTY
|
|
23
23
|
@cmd = cmd
|
24
24
|
@timeout = cmd.options[:timeout]
|
25
25
|
@input = cmd.options[:input]
|
26
|
-
@signal = cmd.options[:signal] ||
|
26
|
+
@signal = cmd.options[:signal] || "SIGKILL"
|
27
|
+
@binmode = cmd.options[:binmode]
|
27
28
|
@printer = printer
|
28
29
|
@block = block
|
29
30
|
end
|
@@ -40,21 +41,19 @@ module TTY
|
|
40
41
|
def run!
|
41
42
|
@printer.print_command_start(cmd)
|
42
43
|
start = Time.now
|
43
|
-
runtime = 0.0
|
44
44
|
|
45
45
|
pid, stdin, stdout, stderr = ChildProcess.spawn(cmd)
|
46
46
|
|
47
47
|
# no input to write, close child's stdin pipe
|
48
48
|
stdin.close if (@input.nil? || @input.empty?) && !stdin.nil?
|
49
49
|
|
50
|
-
readers = [stdout, stderr]
|
51
50
|
writers = [@input && stdin].compact
|
52
51
|
|
53
52
|
while writers.any?
|
54
|
-
|
55
|
-
raise TimeoutExceeded if
|
53
|
+
ready = IO.select(nil, writers, writers, @timeout)
|
54
|
+
raise TimeoutExceeded if ready.nil?
|
56
55
|
|
57
|
-
write_stream(
|
56
|
+
write_stream(ready[1], writers)
|
58
57
|
end
|
59
58
|
|
60
59
|
stdout_data, stderr_data = read_streams(stdout, stderr)
|
@@ -67,6 +66,10 @@ module TTY
|
|
67
66
|
Result.new(status, stdout_data, stderr_data, runtime)
|
68
67
|
ensure
|
69
68
|
[stdin, stdout, stderr].each { |fd| fd.close if fd && !fd.closed? }
|
69
|
+
if pid # Ensure no zombie processes
|
70
|
+
::Process.detach(pid)
|
71
|
+
terminate(pid)
|
72
|
+
end
|
70
73
|
end
|
71
74
|
|
72
75
|
# Stop a process marked by pid
|
@@ -80,6 +83,9 @@ module TTY
|
|
80
83
|
|
81
84
|
private
|
82
85
|
|
86
|
+
# The buffer size for reading stdout and stderr
|
87
|
+
BUFSIZE = 3 * 1024
|
88
|
+
|
83
89
|
# @api private
|
84
90
|
def handle_timeout(runtime)
|
85
91
|
return unless @timeout
|
@@ -126,13 +132,13 @@ module TTY
|
|
126
132
|
stdout_data = []
|
127
133
|
stderr_data = Truncator.new
|
128
134
|
|
129
|
-
out_buffer = ->
|
135
|
+
out_buffer = ->(line) {
|
130
136
|
stdout_data << line
|
131
137
|
@printer.print_command_out_data(cmd, line)
|
132
138
|
@block.(line, nil) if @block
|
133
139
|
}
|
134
140
|
|
135
|
-
err_buffer = ->
|
141
|
+
err_buffer = ->(line) {
|
136
142
|
stderr_data << line
|
137
143
|
@printer.print_command_err_data(cmd, line)
|
138
144
|
@block.(nil, line) if @block
|
@@ -144,35 +150,45 @@ module TTY
|
|
144
150
|
stdout_thread.join
|
145
151
|
stderr_thread.join
|
146
152
|
|
147
|
-
|
153
|
+
encoding = @binmode ? Encoding::BINARY : Encoding::UTF_8
|
154
|
+
|
155
|
+
[
|
156
|
+
stdout_data.join.force_encoding(encoding),
|
157
|
+
stderr_data.read.dup.force_encoding(encoding)
|
158
|
+
]
|
148
159
|
end
|
149
160
|
|
150
161
|
def read_stream(stream, buffer)
|
151
162
|
Thread.new do
|
152
163
|
Thread.current[:cmd_start] = Time.now
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
164
|
+
readers = [stream]
|
165
|
+
|
166
|
+
while readers.any?
|
167
|
+
ready = IO.select(readers, nil, readers, @timeout)
|
168
|
+
raise TimeoutExceeded if ready.nil?
|
169
|
+
|
170
|
+
ready[0].each do |reader|
|
171
|
+
begin
|
172
|
+
line = reader.readpartial(BUFSIZE)
|
173
|
+
buffer.(line)
|
174
|
+
|
175
|
+
# control total time spent reading
|
176
|
+
runtime = Time.now - Thread.current[:cmd_start]
|
177
|
+
handle_timeout(runtime)
|
178
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
179
|
+
rescue EOFError, Errno::EPIPE, Errno::EIO # thrown by PTY
|
180
|
+
readers.delete(reader)
|
181
|
+
reader.close
|
182
|
+
end
|
160
183
|
end
|
161
|
-
rescue Errno::EIO
|
162
|
-
# GNU/Linux `gets` raises when PTY slave is closed
|
163
|
-
nil
|
164
|
-
rescue => err
|
165
|
-
raise err
|
166
|
-
ensure
|
167
|
-
stream.close
|
168
184
|
end
|
169
185
|
end
|
170
186
|
end
|
171
187
|
|
172
188
|
# @api private
|
173
189
|
def waitpid(pid)
|
174
|
-
::Process.
|
175
|
-
|
190
|
+
_pid, status = ::Process.waitpid2(pid, ::Process::WUNTRACED)
|
191
|
+
status.exitstatus || status.termsig if _pid
|
176
192
|
rescue Errno::ECHILD
|
177
193
|
# In JRuby, waiting on a finished pid raises.
|
178
194
|
end
|
data/lib/tty/command/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tty-command
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-04-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pastel
|