tty-command 0.8.1 → 0.8.2

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