tty-command 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|