tty-command 0.8.1 → 0.8.2

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.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +9 -0
  3. data/examples/bash.rb +2 -2
  4. data/examples/basic.rb +2 -2
  5. data/examples/env.rb +3 -3
  6. data/examples/logger.rb +2 -2
  7. data/examples/output.rb +2 -2
  8. data/examples/pty.rb +3 -1
  9. data/examples/redirect_stderr.rb +2 -2
  10. data/examples/redirect_stdin.rb +2 -2
  11. data/examples/redirect_stdout.rb +2 -2
  12. data/examples/stdin_input.rb +2 -2
  13. data/examples/threaded.rb +3 -1
  14. data/examples/timeout.rb +7 -3
  15. data/examples/timeout_input.rb +2 -2
  16. data/examples/wait.rb +2 -2
  17. data/lib/tty/command/process_runner.rb +3 -0
  18. data/lib/tty/command/version.rb +1 -1
  19. data/spec/spec_helper.rb +78 -0
  20. data/spec/unit/binmode_spec.rb +27 -0
  21. data/spec/unit/cmd_spec.rb +152 -0
  22. data/spec/unit/dry_run_spec.rb +42 -0
  23. data/spec/unit/exit_error_spec.rb +25 -0
  24. data/spec/unit/input_spec.rb +11 -0
  25. data/spec/unit/output_spec.rb +25 -0
  26. data/spec/unit/printer_spec.rb +50 -0
  27. data/spec/unit/printers/custom_spec.rb +48 -0
  28. data/spec/unit/printers/null_spec.rb +36 -0
  29. data/spec/unit/printers/pretty_spec.rb +172 -0
  30. data/spec/unit/printers/progress_spec.rb +45 -0
  31. data/spec/unit/printers/quiet_spec.rb +71 -0
  32. data/spec/unit/pty_spec.rb +60 -0
  33. data/spec/unit/redirect_spec.rb +104 -0
  34. data/spec/unit/result_spec.rb +64 -0
  35. data/spec/unit/ruby_spec.rb +20 -0
  36. data/spec/unit/run_spec.rb +161 -0
  37. data/spec/unit/test_spec.rb +11 -0
  38. data/spec/unit/timeout_spec.rb +36 -0
  39. data/spec/unit/truncator_spec.rb +73 -0
  40. data/tty-command.gemspec +1 -1
  41. metadata +24 -10
  42. data/.gitignore +0 -9
  43. data/.rspec +0 -4
  44. data/.travis.yml +0 -29
  45. data/CODE_OF_CONDUCT.md +0 -49
  46. data/Gemfile +0 -14
  47. data/appveyor.yml +0 -26
  48. data/benchmarks/memory.rb +0 -11
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Command::Printers::Quiet do
4
+ let(:output) { StringIO.new }
5
+
6
+ it "doesn't print command start or exit" do
7
+ printer = TTY::Command::Printers::Quiet.new(output)
8
+ cmd = TTY::Command::Cmd.new("echo hello")
9
+
10
+ printer.print_command_start(cmd)
11
+ printer.print_command_exit(cmd, 0)
12
+ output.rewind
13
+
14
+ expect(output.string).to be_empty
15
+ end
16
+
17
+ it "prints command stdout data" do
18
+ printer = TTY::Command::Printers::Quiet.new(output)
19
+ cmd = TTY::Command::Cmd.new("echo hello")
20
+
21
+ printer.print_command_out_data(cmd, 'hello', 'world')
22
+ output.rewind
23
+
24
+ expect(output.string).to eq("hello world")
25
+ end
26
+
27
+ it "prints command stderr data" do
28
+ printer = TTY::Command::Printers::Quiet.new(output)
29
+ cmd = TTY::Command::Cmd.new("echo hello")
30
+
31
+ printer.print_command_err_data(cmd, 'hello', 'world')
32
+ output.rewind
33
+
34
+ expect(output.string).to eq("hello world")
35
+ end
36
+
37
+ it "doesn't print output on success when only_output_on_error is true" do
38
+ zero_exit = fixtures_path('zero_exit')
39
+ printer = TTY::Command::Printers::Quiet
40
+ cmd = TTY::Command.new(output: output, printer: printer)
41
+
42
+ cmd.run!(:ruby, zero_exit, only_output_on_error: true)
43
+ cmd.run!(:ruby, zero_exit)
44
+
45
+ output.rewind
46
+
47
+ lines = output.readlines.map(&:chomp)
48
+
49
+ expect(lines).to eq([
50
+ "yess"
51
+ ])
52
+ end
53
+
54
+ it "prints output on error when only_output_on_error is true" do
55
+ non_zero_exit = fixtures_path('non_zero_exit')
56
+ printer = TTY::Command::Printers::Quiet
57
+ cmd = TTY::Command.new(output: output, printer: printer)
58
+
59
+ cmd.run!(:ruby, non_zero_exit, only_output_on_error: true)
60
+ cmd.run!(:ruby, non_zero_exit)
61
+
62
+ output.rewind
63
+
64
+ lines = output.readlines.map(&:chomp)
65
+
66
+ expect(lines).to eq([
67
+ "nooo",
68
+ "nooo"
69
+ ])
70
+ end
71
+ end
@@ -0,0 +1,60 @@
1
+ RSpec.describe TTY::Command, ':pty' do
2
+ it "executes command in pseudo terminal mode as global option",
3
+ unless: RSpec::Support::OS.windows? do
4
+
5
+ color_cli = fixtures_path('color')
6
+ output = StringIO.new
7
+ cmd = TTY::Command.new(output: output, pty: true)
8
+
9
+ out, err = cmd.run(color_cli)
10
+
11
+ expect(err).to eq('')
12
+ expect(out).to eq("\e[32mcolored\e[0m\n")
13
+ end
14
+
15
+ it "executes command in pseudo terminal mode as command option",
16
+ unless: RSpec::Support::OS.windows? do
17
+
18
+ color_cli = fixtures_path('color')
19
+ output = StringIO.new
20
+ cmd = TTY::Command.new(output: output)
21
+
22
+ out, err = cmd.run(color_cli, pty: true)
23
+
24
+ expect(err).to eq('')
25
+ expect(out).to eq("\e[32mcolored\e[0m\n")
26
+ end
27
+
28
+ it "logs phased output in pseudo terminal mode",
29
+ unless: RSpec::Support::OS.windows? do
30
+
31
+ phased_output = fixtures_path('phased_output')
32
+ uuid= 'xxxx'
33
+ allow(SecureRandom).to receive(:uuid).and_return(uuid)
34
+ output = StringIO.new
35
+ cmd = TTY::Command.new(output: output)
36
+
37
+ out, err = cmd.run("ruby #{phased_output}", pty: true)
38
+
39
+ expect(out).to eq('.' * 10)
40
+ expect(err).to eq('')
41
+
42
+ output.rewind
43
+ lines = output.readlines
44
+ lines.last.gsub!(/\d+\.\d+/, 'x')
45
+ expect(lines).to eq([
46
+ "[\e[32m#{uuid}\e[0m] Running \e[33;1mruby #{phased_output}\e[0m\n",
47
+ "[\e[32m#{uuid}\e[0m] \t.\n",
48
+ "[\e[32m#{uuid}\e[0m] \t.\n",
49
+ "[\e[32m#{uuid}\e[0m] \t.\n",
50
+ "[\e[32m#{uuid}\e[0m] \t.\n",
51
+ "[\e[32m#{uuid}\e[0m] \t.\n",
52
+ "[\e[32m#{uuid}\e[0m] \t.\n",
53
+ "[\e[32m#{uuid}\e[0m] \t.\n",
54
+ "[\e[32m#{uuid}\e[0m] \t.\n",
55
+ "[\e[32m#{uuid}\e[0m] \t.\n",
56
+ "[\e[32m#{uuid}\e[0m] \t.\n",
57
+ "[\e[32m#{uuid}\e[0m] Finished in x seconds with exit status 0 (\e[32;1msuccessful\e[0m)\n"
58
+ ])
59
+ end
60
+ end
@@ -0,0 +1,104 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ RSpec.describe TTY::Command, 'redirect' do
5
+ it "accepts standard shell redirects" do
6
+ output = StringIO.new
7
+ command = TTY::Command.new(output: output)
8
+
9
+ out, err = command.run("echo hello 1>& 2")
10
+
11
+ expect(out).to eq("")
12
+ expect(err).to match(%r{hello\s*\n})
13
+ end
14
+
15
+ it "redirects :out -> :err" do
16
+ output = StringIO.new
17
+ cmd = TTY::Command.new(output: output)
18
+
19
+ out, err = cmd.run("echo hello", :out => :err)
20
+
21
+ expect(out).to be_empty
22
+ expect(err.chomp).to eq("hello")
23
+ end
24
+
25
+ it "redirects :stdout -> :stderr" do
26
+ output = StringIO.new
27
+ cmd = TTY::Command.new(output: output)
28
+
29
+ out, err = cmd.run("echo hello", :stdout => :stderr)
30
+
31
+ expect(out).to be_empty
32
+ expect(err.chomp).to eq("hello")
33
+ end
34
+
35
+ it "redirects 1 -> 2" do
36
+ output = StringIO.new
37
+ cmd = TTY::Command.new(output: output)
38
+
39
+ out, err = cmd.run("echo hello", 1 => 2)
40
+
41
+ expect(out).to be_empty
42
+ expect(err.chomp).to eq("hello")
43
+ end
44
+
45
+ it "redirects STDOUT -> :err" do
46
+ output = StringIO.new
47
+ cmd = TTY::Command.new(output: output)
48
+
49
+ out, err = cmd.run("echo hello", STDOUT => :err)
50
+
51
+ expect(out).to be_empty
52
+ expect(err.chomp).to eq("hello")
53
+ end
54
+
55
+ it "redirects STDOUT -> '/dev/null" do
56
+ output = StringIO.new
57
+ cmd = TTY::Command.new(output: output)
58
+
59
+ out, _ = cmd.run('echo hello', :out => IO::NULL)
60
+
61
+ expect(out).to eq("")
62
+ end
63
+
64
+ it "redirects to a file", type: :cli do
65
+ file = tmp_path('log')
66
+ output = StringIO.new
67
+ cmd = TTY::Command.new(output: output)
68
+
69
+ out, err = cmd.run('echo hello', :out => file)
70
+
71
+ expect(out).to be_empty
72
+ expect(err).to be_empty
73
+ expect(File.read(file)).to eq("hello\n")
74
+ end
75
+
76
+ it "redirects to a file as an array value", type: :cli do
77
+ file = tmp_path('log')
78
+ output = StringIO.new
79
+ cmd = TTY::Command.new(output: output)
80
+
81
+ expect(File.writable?(file)).to eq(false)
82
+ out, err = cmd.run('echo hello', :out => [file, 'w', 0600])
83
+
84
+ expect(out).to be_empty
85
+ expect(err).to be_empty
86
+ expect(File.read(file)).to eq("hello\n")
87
+ expect(File.writable?(file)).to eq(true)
88
+ unless RSpec::Support::OS.windows?
89
+ expect(File.stat(file).mode.to_s(8)[2..5]).to eq('0600')
90
+ end
91
+ end
92
+
93
+ it "redirects multiple fds to a file", type: :cli do
94
+ file = tmp_path('log')
95
+ output = StringIO.new
96
+ cmd = TTY::Command.new(output: output)
97
+
98
+ out, err = cmd.run('echo hello', [:out, :err] => file)
99
+
100
+ expect(out).to be_empty
101
+ expect(err).to be_empty
102
+ expect(File.read(file)).to eq("hello\n")
103
+ end
104
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Command::Result do
4
+ it "exits successfully" do
5
+ result = TTY::Command::Result.new(0, '', '')
6
+ expect(result.exited?).to eq(true)
7
+ expect(result.success?).to eq(true)
8
+ end
9
+
10
+ it "exist with non-zero code" do
11
+ result = TTY::Command::Result.new(127, '', '')
12
+ expect(result.exited?).to eq(true)
13
+ expect(result.success?).to eq(false)
14
+ end
15
+
16
+ it "accesses exit code" do
17
+ result = TTY::Command::Result.new(127, '', '')
18
+ expect(result.to_i).to eq(127)
19
+ expect(result.to_s).to eq('127')
20
+ end
21
+
22
+ it "provides runtime" do
23
+ result = TTY::Command::Result.new(0, '', '', 5.4)
24
+ expect(result.runtime).to eq(5.4)
25
+ end
26
+
27
+ it "doesn't exit" do
28
+ result = TTY::Command::Result.new(nil, '', '')
29
+ expect(result.exited?).to eq(false)
30
+ expect(result.success?).to eq(false)
31
+ end
32
+
33
+ it "reads stdout" do
34
+ result = TTY::Command::Result.new(0, 'foo', '')
35
+ expect(result.out).to eq('foo')
36
+ end
37
+
38
+ it "isn't equivalent with another object" do
39
+ result = TTY::Command::Result.new(0, '', '')
40
+ expect(result).to_not eq(:other)
41
+ end
42
+
43
+ it "is the same with equivalent object" do
44
+ result_foo = TTY::Command::Result.new(0, 'foo', 'bar')
45
+ result_bar = TTY::Command::Result.new(0, 'foo', 'bar')
46
+ expect(result_foo).to eq(result_bar)
47
+ end
48
+
49
+ it "iterates over output with default delimiter" do
50
+ result = TTY::Command::Result.new(0, "line1\nline2\nline3", '')
51
+ expect(result.to_a).to eq(['line1', 'line2', 'line3'])
52
+ end
53
+
54
+ it "iterates over output with global delimiter" do
55
+ allow(TTY::Command).to receive(:record_separator).and_return("\t")
56
+ result = TTY::Command::Result.new(0, "line1\tline2\tline3", '')
57
+ expect(result.each.to_a).to eq(['line1', 'line2', 'line3'])
58
+ end
59
+
60
+ it "iterates over output with argument delimiter" do
61
+ result = TTY::Command::Result.new(0, "line1\tline2\tline3", '')
62
+ expect(result.each("\t").to_a).to eq(['line1', 'line2', 'line3'])
63
+ end
64
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Command, '#ruby' do
4
+ it "runs ruby with a single string argument" do
5
+ output = StringIO.new
6
+ cmd = TTY::Command.new(output: output)
7
+ out, err = cmd.ruby %q{-e "puts 'Hello World'"}
8
+ expect(out.chomp).to eq("Hello World")
9
+ expect(err).to be_empty unless jruby?
10
+ end
11
+
12
+ it "runs ruby with multiple arguments" do
13
+ output = StringIO.new
14
+ cmd = TTY::Command.new(output: output)
15
+ result = double(:success? => true)
16
+ allow(cmd).to receive(:run).with(TTY::Command::RUBY,
17
+ 'script.rb', 'foo', 'bar', {}).and_return(result)
18
+ expect(cmd.ruby('script.rb', 'foo', 'bar')).to eq(result)
19
+ end
20
+ end
@@ -0,0 +1,161 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Command, '#run' do
4
+ it 'runs command and prints to stdout' do
5
+ output = StringIO.new
6
+ command = TTY::Command.new(output: output)
7
+
8
+ out, err = command.run(:echo, 'hello')
9
+
10
+ expect(out.chomp).to eq("hello")
11
+ expect(err).to eq("")
12
+ end
13
+
14
+ it 'runs command successfully with logging' do
15
+ output = StringIO.new
16
+ uuid= 'xxxx'
17
+ allow(SecureRandom).to receive(:uuid).and_return(uuid)
18
+ command = TTY::Command.new(output: output)
19
+
20
+ command.run(:echo, 'hello')
21
+
22
+ output.rewind
23
+ lines = output.readlines
24
+ lines.last.gsub!(/\d+\.\d+/, 'x')
25
+ expect(lines).to eq([
26
+ "[\e[32m#{uuid}\e[0m] Running \e[33;1mecho hello\e[0m\n",
27
+ "[\e[32m#{uuid}\e[0m] \thello\n",
28
+ "[\e[32m#{uuid}\e[0m] Finished in x seconds with exit status 0 (\e[32;1msuccessful\e[0m)\n"
29
+ ])
30
+ end
31
+
32
+ it 'runs command successfully with logging without color' do
33
+ output = StringIO.new
34
+ uuid= 'xxxx'
35
+ allow(SecureRandom).to receive(:uuid).and_return(uuid)
36
+ command = TTY::Command.new(output: output, color: false)
37
+
38
+ command.run(:echo, 'hello')
39
+
40
+ output.rewind
41
+ lines = output.readlines
42
+ lines.last.gsub!(/\d+\.\d+/, 'x')
43
+ expect(lines).to eq([
44
+ "[#{uuid}] Running echo hello\n",
45
+ "[#{uuid}] \thello\n",
46
+ "[#{uuid}] Finished in x seconds with exit status 0 (successful)\n"
47
+ ])
48
+ end
49
+
50
+ it 'runs command successfully with logging without uuid set globally' do
51
+ output = StringIO.new
52
+ command = TTY::Command.new(output: output, uuid: false)
53
+
54
+ command.run(:echo, 'hello')
55
+ output.rewind
56
+
57
+ lines = output.readlines
58
+ lines.last.gsub!(/\d+\.\d+/, 'x')
59
+ expect(lines).to eq([
60
+ "Running \e[33;1mecho hello\e[0m\n",
61
+ "\thello\n",
62
+ "Finished in x seconds with exit status 0 (\e[32;1msuccessful\e[0m)\n"
63
+ ])
64
+ end
65
+
66
+ it 'runs command successfully with logging without uuid set locally' do
67
+ output = StringIO.new
68
+ command = TTY::Command.new(output: output)
69
+
70
+ command.run(:echo, 'hello', uuid: false)
71
+ output.rewind
72
+
73
+ lines = output.readlines
74
+ lines.last.gsub!(/\d+\.\d+/, 'x')
75
+ expect(lines).to eq([
76
+ "Running \e[33;1mecho hello\e[0m\n",
77
+ "\thello\n",
78
+ "Finished in x seconds with exit status 0 (\e[32;1msuccessful\e[0m)\n"
79
+ ])
80
+ end
81
+
82
+ it "runs command and fails with logging" do
83
+ non_zero_exit = fixtures_path('non_zero_exit')
84
+ output = StringIO.new
85
+ uuid= 'xxxx'
86
+ allow(SecureRandom).to receive(:uuid).and_return(uuid)
87
+ command = TTY::Command.new(output: output)
88
+
89
+ command.run!("ruby #{non_zero_exit}")
90
+
91
+ output.rewind
92
+ lines = output.readlines
93
+ lines.last.gsub!(/\d+\.\d+/, 'x')
94
+ expect(lines).to eq([
95
+ "[\e[32m#{uuid}\e[0m] Running \e[33;1mruby #{non_zero_exit}\e[0m\n",
96
+ "[\e[32m#{uuid}\e[0m] \tnooo\n",
97
+ "[\e[32m#{uuid}\e[0m] Finished in x seconds with exit status 1 (\e[31;1mfailed\e[0m)\n"
98
+ ])
99
+ end
100
+
101
+ it "raises ExitError on command failure" do
102
+ non_zero_exit = fixtures_path('non_zero_exit')
103
+ output = StringIO.new
104
+ command = TTY::Command.new(output: output)
105
+
106
+ expect {
107
+ command.run("ruby #{non_zero_exit}")
108
+ }.to raise_error(TTY::Command::ExitError,
109
+ ["Running `ruby #{non_zero_exit}` failed with",
110
+ " exit status: 1",
111
+ " stdout: nooo",
112
+ " stderr: Nothing written\n"].join("\n")
113
+ )
114
+ end
115
+
116
+ it "streams output data" do
117
+ stream = fixtures_path('stream')
118
+ out_stream = StringIO.new
119
+ command = TTY::Command.new(output: out_stream)
120
+ output = ''
121
+ error = ''
122
+ command.run("ruby #{stream}") do |out, err|
123
+ output << out if out
124
+ error << err if err
125
+ end
126
+ expect(output.gsub(/\r\n|\n/,'')).to eq("hello 1hello 2hello 3")
127
+ expect(error).to eq('')
128
+ end
129
+
130
+ it "preserves ANSI codes" do
131
+ output = StringIO.new
132
+ command = TTY::Command.new(output: output, printer: :quiet)
133
+
134
+ out, _ = command.run("echo \e[35mhello\e[0m")
135
+
136
+ expect(out.chomp).to eq("\e[35mhello\e[0m")
137
+ expect(output.string.chomp).to eq("\e[35mhello\e[0m")
138
+ end
139
+
140
+ it "logs phased output in one line" do
141
+ phased_output = fixtures_path('phased_output')
142
+ uuid= 'xxxx'
143
+ allow(SecureRandom).to receive(:uuid).and_return(uuid)
144
+ output = StringIO.new
145
+ cmd = TTY::Command.new(output: output)
146
+
147
+ out, err = cmd.run("ruby #{phased_output}")
148
+
149
+ expect(out).to eq('.' * 10)
150
+ expect(err).to eq('')
151
+
152
+ output.rewind
153
+ lines = output.readlines
154
+ lines.last.gsub!(/\d+\.\d+/, 'x')
155
+ expect(lines).to eq([
156
+ "[\e[32m#{uuid}\e[0m] Running \e[33;1mruby #{phased_output}\e[0m\n",
157
+ "[\e[32m#{uuid}\e[0m] \t..........\n",
158
+ "[\e[32m#{uuid}\e[0m] Finished in x seconds with exit status 0 (\e[32;1msuccessful\e[0m)\n"
159
+ ])
160
+ end
161
+ end