cocaine 0.5.7 → 0.5.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 183bb99b2dc331acae17ae06bba9497305f62871
4
- data.tar.gz: 7588340c94577ccc9cfbdb3061de34c0a0dbe7a7
3
+ metadata.gz: 4a7f83d9126ee8f5d25a7c78455dd6dff4b883c0
4
+ data.tar.gz: 062e9535def6a4af7f3c4b54ad4af777970e3d16
5
5
  SHA512:
6
- metadata.gz: 044ce7602066d9464d844aecd01219d9f6c1a0a37e6cd3ad0a72094edbf6812770c5e98ab2d6b125be3475d4dedc336a4c603a719f3dae1fb6de8a1a01210162
7
- data.tar.gz: fc8fa3d67672811b19145d4e1ef14f73d7965a2db6f4202ed2f98b8346b993521bbaf4e55d0aa2fcf18cee15cdc166813f67320b90e515033d4d2c2e5d52d594
6
+ metadata.gz: 23824efd971fc240abdf4a7892f923e3540dea7c1de8e524a3c45d8154c69c3526b3644920aa0c2dae946fb0c24e93366d59cfdbe44b3566be27a8e5c9eca443
7
+ data.tar.gz: b62558b1d765fa9da86d9cd2b70b62a9dc80eb6e99edc9582162b836035b128b8198a333baace2b731e6096764985012f24352f1930449bd8d63c2a95784db6e
@@ -3,3 +3,4 @@ rvm:
3
3
  - 2.0.0
4
4
  - 2.1.5
5
5
  - jruby-19mode
6
+ - rbx-2
data/NEWS.md CHANGED
@@ -1,3 +1,13 @@
1
+ New for 0.5.7:
2
+
3
+ * Feature: Allow collection of both STDOUT and STDERR.
4
+ * Improvement: Convert arguments to strings when possible
5
+
6
+ New for 0.5.6:
7
+
8
+ * Bug Fix: Java does not need to run commands with `env`
9
+ * Bug Fix: Found out we were rescuing the wrong error
10
+
1
11
  New for 0.5.5:
2
12
 
3
13
  * Bug Fix: Posix- and ProcessRunner respect paths *and* are thread safe!
@@ -3,6 +3,8 @@
3
3
  require 'rbconfig'
4
4
  require 'cocaine/os_detector'
5
5
  require 'cocaine/command_line'
6
+ require 'cocaine/command_line/output'
7
+ require 'cocaine/command_line/multi_pipe'
6
8
  require 'cocaine/command_line/runners'
7
9
  require 'cocaine/exceptions'
8
10
 
@@ -67,12 +67,11 @@ module Cocaine
67
67
  end
68
68
 
69
69
  def run(interpolations = {})
70
- output = ''
71
70
  @exit_status = nil
72
71
  begin
73
72
  full_command = command(interpolations)
74
73
  log("#{colored("Command")} :: #{full_command}")
75
- output = execute(full_command)
74
+ @output = execute(full_command)
76
75
  rescue Errno::ENOENT => e
77
76
  raise Cocaine::CommandNotFoundError, e.message
78
77
  ensure
@@ -86,12 +85,24 @@ module Cocaine
86
85
  unless @expected_outcodes.include?(@exit_status)
87
86
  message = [
88
87
  "Command '#{full_command}' returned #{@exit_status}. Expected #{@expected_outcodes.join(", ")}",
89
- "Here is the command output:\n",
90
- output
88
+ "Here is the command output: STDOUT:\n", command_output,
89
+ "\nSTDERR:\n", command_error_output
91
90
  ].join("\n")
92
91
  raise Cocaine::ExitStatusError, message
93
92
  end
94
- output
93
+ command_output
94
+ end
95
+
96
+ def command_output
97
+ output.output
98
+ end
99
+
100
+ def command_error_output
101
+ output.error_output
102
+ end
103
+
104
+ def output
105
+ @output || Output.new
95
106
  end
96
107
 
97
108
  private
@@ -166,11 +177,13 @@ module Cocaine
166
177
 
167
178
  def shell_quote(string)
168
179
  return "" if string.nil?
180
+ string = string.to_s if string.respond_to? :to_s
181
+
169
182
  if OS.unix?
170
183
  if string.empty?
171
184
  "''"
172
185
  else
173
- string.split("'").map{|m| "'#{m}'" }.join("\\'")
186
+ string.split("'", -1).map{|m| "'#{m}'" }.join("\\'")
174
187
  end
175
188
  else
176
189
  %{"#{string}"}
@@ -0,0 +1,50 @@
1
+ module Cocaine
2
+ class CommandLine
3
+ class MultiPipe
4
+ def initialize
5
+ @stdout_in, @stdout_out = IO.pipe
6
+ @stderr_in, @stderr_out = IO.pipe
7
+ end
8
+
9
+ def pipe_options
10
+ { out: @stdout_out, err: @stderr_out }
11
+ end
12
+
13
+ def output
14
+ Output.new(@stdout_output, @stderr_output)
15
+ end
16
+
17
+ def read_and_then(&block)
18
+ close_write
19
+ read
20
+ block.call
21
+ close_read
22
+ end
23
+
24
+ private
25
+
26
+ def close_write
27
+ @stdout_out.close
28
+ @stderr_out.close
29
+ end
30
+
31
+ def read
32
+ @stdout_output = read_stream(@stdout_in)
33
+ @stderr_output = read_stream(@stderr_in)
34
+ end
35
+
36
+ def close_read
37
+ @stdout_in.close
38
+ @stderr_in.close
39
+ end
40
+
41
+ def read_stream(io)
42
+ result = ""
43
+ while partial_result = io.read(8192)
44
+ result << partial_result
45
+ end
46
+ result
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ class Cocaine::CommandLine::Output
2
+ def initialize(output = nil, error_output = nil)
3
+ @output = output
4
+ @error_output = error_output
5
+ end
6
+
7
+ attr_reader :output, :error_output
8
+
9
+ def to_s
10
+ output.to_s
11
+ end
12
+ end
@@ -15,7 +15,7 @@ module Cocaine
15
15
 
16
16
  def call(command, env = {}, options = {})
17
17
  with_modified_environment(env) do
18
- `#{command}`
18
+ Output.new(`#{command}`)
19
19
  end
20
20
  end
21
21
 
@@ -19,13 +19,12 @@ module Cocaine
19
19
 
20
20
  def call(command, env = {}, options = {})
21
21
  commands << [command, env]
22
- ""
22
+ Output.new("")
23
23
  end
24
24
 
25
25
  def ran?(predicate_command)
26
- @commands.any?{|(command, env)| command =~ Regexp.new(predicate_command) }
26
+ @commands.any?{|(command, _)| command =~ Regexp.new(predicate_command) }
27
27
  end
28
-
29
28
  end
30
29
  end
31
30
  end
@@ -14,7 +14,7 @@ module Cocaine
14
14
  def call(command, env = {}, options = {})
15
15
  with_modified_environment(env) do
16
16
  IO.popen(command, "r", options) do |pipe|
17
- pipe.read
17
+ Output.new(pipe.read)
18
18
  end
19
19
  end
20
20
  end
@@ -18,17 +18,12 @@ module Cocaine
18
18
  end
19
19
 
20
20
  def call(command, env = {}, options = {})
21
- input, output = IO.pipe
22
- options[:out] = output
23
- pid = spawn(env, command, options)
24
- output.close
25
- result = ""
26
- while partial_result = input.read(8192)
27
- result << partial_result
21
+ pipe = MultiPipe.new
22
+ pid = spawn(env, command, options.merge(pipe.pipe_options))
23
+ pipe.read_and_then do
24
+ waitpid(pid)
28
25
  end
29
- waitpid(pid)
30
- input.close
31
- result
26
+ pipe.output
32
27
  end
33
28
 
34
29
  private
@@ -16,14 +16,12 @@ module Cocaine
16
16
  end
17
17
 
18
18
  def call(command, env = {}, options = {})
19
- input, output = IO.pipe
20
- options[:out] = output
21
- pid = spawn(env, command, options)
22
- output.close
23
- result = input.read
24
- waitpid(pid)
25
- input.close
26
- result
19
+ pipe = MultiPipe.new
20
+ pid = spawn(env, command, options.merge(pipe.pipe_options))
21
+ pipe.read_and_then do
22
+ waitpid(pid)
23
+ end
24
+ pipe.output
27
25
  end
28
26
 
29
27
  private
@@ -1,5 +1,5 @@
1
1
  # coding: UTF-8
2
2
 
3
3
  module Cocaine
4
- VERSION = "0.5.7".freeze
4
+ VERSION = "0.5.8".freeze
5
5
  end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cocaine::CommandLine::Output do
4
+ it 'holds an input and error stream' do
5
+ output = Cocaine::CommandLine::Output.new(:a, :b)
6
+ expect(output.output).to eq :a
7
+ expect(output.error_output).to eq :b
8
+ end
9
+
10
+ it 'calls #to_s on the output when you call #to_s on it' do
11
+ output = Cocaine::CommandLine::Output.new(:a, :b)
12
+ expect(output.to_s).to eq 'a'
13
+ end
14
+ end
@@ -4,12 +4,14 @@ describe Cocaine::CommandLine::BackticksRunner do
4
4
  if Cocaine::CommandLine::BackticksRunner.supported?
5
5
  it_behaves_like 'a command that does not block'
6
6
 
7
- it 'runs the command given' do
8
- subject.call("echo hello").should == "hello\n"
7
+ it 'runs the command given and captures the output in an Output' do
8
+ output = subject.call("echo hello")
9
+ expect(output).to have_output "hello\n"
9
10
  end
10
11
 
11
12
  it 'modifies the environment and runs the command given' do
12
- subject.call("echo $yes", {"yes" => "no"}).should == "no\n"
13
+ output = subject.call("echo $yes", {"yes" => "no"})
14
+ expect(output).to have_output "no\n"
13
15
  end
14
16
 
15
17
  it 'sets the exitstatus when a command completes' do
@@ -4,12 +4,14 @@ describe Cocaine::CommandLine::PopenRunner do
4
4
  if Cocaine::CommandLine::PopenRunner.supported?
5
5
  it_behaves_like 'a command that does not block'
6
6
 
7
- it 'runs the command given' do
8
- subject.call("echo hello").should == "hello\n"
7
+ it 'runs the command given and captures the output in an Output' do
8
+ output = subject.call("echo hello")
9
+ expect(output).to have_output "hello\n"
9
10
  end
10
11
 
11
12
  it 'modifies the environment and runs the command given' do
12
- subject.call("echo $yes", {"yes" => "no"}).should == "no\n"
13
+ output = subject.call("echo $yes", {"yes" => "no"})
14
+ expect(output).to have_output "no\n"
13
15
  end
14
16
 
15
17
  it 'sets the exitstatus when a command completes' do
@@ -4,12 +4,19 @@ describe Cocaine::CommandLine::PosixRunner do
4
4
  if Cocaine::CommandLine::PosixRunner.supported?
5
5
  it_behaves_like 'a command that does not block'
6
6
 
7
- it 'runs the command given' do
8
- subject.call("echo hello").should == "hello\n"
7
+ it 'runs the command given and captures the output' do
8
+ output = subject.call("echo hello")
9
+ expect(output).to have_output "hello\n"
10
+ end
11
+
12
+ it 'runs the command given and captures the error output' do
13
+ output = subject.call("echo hello 1>&2")
14
+ expect(output).to have_error_output "hello\n"
9
15
  end
10
16
 
11
17
  it 'modifies the environment and runs the command given' do
12
- subject.call("echo $yes", {"yes" => "no"}).should == "no\n"
18
+ output = subject.call("echo $yes", {"yes" => "no"})
19
+ expect(output).to have_output "no\n"
13
20
  end
14
21
 
15
22
  it 'sets the exitstatus when a command completes' do
@@ -18,5 +25,16 @@ describe Cocaine::CommandLine::PosixRunner do
18
25
  subject.call("ruby -e 'exit 5'")
19
26
  $?.exitstatus.should == 5
20
27
  end
28
+
29
+ it "runs the command it's given and allows access to stderr afterwards" do
30
+ cmd = Cocaine::CommandLine.new(
31
+ "ruby",
32
+ "-e '$stdout.puts %{hello}; $stderr.puts %{goodbye}'",
33
+ :swallow_stderr => false
34
+ )
35
+ cmd.run
36
+ expect(cmd.command_output).to eq "hello\n"
37
+ expect(cmd.command_error_output).to eq "goodbye\n"
38
+ end
21
39
  end
22
40
  end
@@ -4,12 +4,19 @@ describe Cocaine::CommandLine::ProcessRunner do
4
4
  if Cocaine::CommandLine::ProcessRunner.supported?
5
5
  it_behaves_like "a command that does not block"
6
6
 
7
- it 'runs the command given' do
8
- subject.call("echo hello").should == "hello\n"
7
+ it 'runs the command given and captures the output' do
8
+ output = subject.call("echo hello")
9
+ expect(output).to have_output "hello\n"
10
+ end
11
+
12
+ it 'runs the command given and captures the error output' do
13
+ output = subject.call("echo hello 1>&2")
14
+ expect(output).to have_error_output "hello\n"
9
15
  end
10
16
 
11
17
  it 'modifies the environment and runs the command given' do
12
- subject.call("echo $yes", {"yes" => "no"}).should == "no\n"
18
+ output = subject.call("echo $yes", {"yes" => "no"})
19
+ expect(output).to have_output "no\n"
13
20
  end
14
21
 
15
22
  it 'sets the exitstatus when a command completes' do
@@ -18,5 +25,16 @@ describe Cocaine::CommandLine::ProcessRunner do
18
25
  subject.call("ruby -e 'exit 5'")
19
26
  $?.exitstatus.should == 5
20
27
  end
28
+
29
+ it "runs the command it's given and allows access to stderr afterwards" do
30
+ cmd = Cocaine::CommandLine.new(
31
+ "ruby",
32
+ "-e '$stdout.puts %{hello}; $stderr.puts %{goodbye}'",
33
+ :swallow_stderr => false
34
+ )
35
+ cmd.run
36
+ expect(cmd.command_output).to eq "hello\n"
37
+ expect(cmd.command_error_output).to eq "goodbye\n"
38
+ end
21
39
  end
22
40
  end
@@ -95,8 +95,8 @@ describe Cocaine::CommandLine do
95
95
  cmd = Cocaine::CommandLine.new("convert",
96
96
  ":one :two",
97
97
  :swallow_stderr => false)
98
- command_string = cmd.command(:one => "`rm -rf`.jpg", :two => "ha'ha.png")
99
- command_string.should == "convert '`rm -rf`.jpg' 'ha'\\''ha.png'"
98
+ command_string = cmd.command(:one => "`rm -rf`.jpg", :two => "ha'ha.png'")
99
+ command_string.should == "convert '`rm -rf`.jpg' 'ha'\\''ha.png'\\'''"
100
100
  end
101
101
 
102
102
  it 'cannot recursively introduce a place where user-supplied commands can run' do
@@ -126,6 +126,12 @@ describe Cocaine::CommandLine do
126
126
  cmd.command.should == "convert 'a.jpg' xc:black 'b.jpg'"
127
127
  end
128
128
 
129
+ it 'handles symbols in user supplied values' do
130
+ cmd = Cocaine::CommandLine.new("echo", ":foo")
131
+ command_string = cmd.command(:foo => :bar)
132
+ command_string.should == "echo 'bar'"
133
+ end
134
+
129
135
  it "can redirect stderr to the bit bucket if requested" do
130
136
  cmd = Cocaine::CommandLine.new("convert",
131
137
  "a.jpg b.png",
@@ -143,12 +149,15 @@ describe Cocaine::CommandLine do
143
149
  cmd.command.should == "convert a.jpg b.png 2>NUL"
144
150
  end
145
151
 
146
- it "runs the command it's given and return the output" do
147
- cmd = Cocaine::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
148
- cmd.stubs(:execute).with("convert a.jpg b.png").returns(:correct_value)
149
- with_exitstatus_returning(0) do
150
- cmd.run.should == :correct_value
151
- end
152
+ it "runs the command it's given and returns the output" do
153
+ cmd = Cocaine::CommandLine.new("echo", "hello", :swallow_stderr => false)
154
+ expect(cmd.run).to eq "hello\n"
155
+ end
156
+
157
+ it "runs the command it's given and allows access to stdout afterwards" do
158
+ cmd = Cocaine::CommandLine.new("echo", "hello", :swallow_stderr => false)
159
+ cmd.run
160
+ expect(cmd.command_output).to eq "hello\n"
152
161
  end
153
162
 
154
163
  it "colorizes the output to a tty" do
@@ -1,47 +1,40 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "When an error happens" do
4
- it "raises a CommandLineError if the result code from the command isn't expected" do
5
- cmd = Cocaine::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
6
- cmd.stubs(:execute).with("convert a.jpg b.png").returns(:correct_value)
4
+ it "raises a CommandLineError if the result code command isn't expected" do
5
+ cmd = Cocaine::CommandLine.new("echo", "hello")
6
+ cmd.stubs(:execute)
7
7
  with_exitstatus_returning(1) do
8
- lambda do
9
- cmd.run
10
- end.should raise_error(Cocaine::CommandLineError)
8
+ lambda { cmd.run }.should raise_error(Cocaine::CommandLineError)
11
9
  end
12
10
  end
13
11
 
14
12
  it "does not raise if the result code is expected, even if nonzero" do
15
- cmd = Cocaine::CommandLine.new("convert",
16
- "a.jpg b.png",
17
- :expected_outcodes => [0, 1],
18
- :swallow_stderr => false)
19
- cmd.stubs(:execute).with("convert a.jpg b.png").returns(:correct_value)
13
+ cmd = Cocaine::CommandLine.new("echo", "hello", expected_outcodes: [0, 1])
14
+ cmd.stubs(:execute)
20
15
  with_exitstatus_returning(1) do
21
- lambda do
22
- cmd.run
23
- end.should_not raise_error
16
+ lambda { cmd.run }.should_not raise_error
24
17
  end
25
18
  end
26
19
 
27
20
  it "adds command output to exception message if the result code is nonzero" do
28
- cmd = Cocaine::CommandLine.new("convert",
29
- "a.jpg b.png",
30
- :swallow_stderr => false)
21
+ cmd = Cocaine::CommandLine.new("echo", "hello")
31
22
  error_output = "Error 315"
32
- cmd.stubs(:execute).with("convert a.jpg b.png").returns(error_output)
23
+ cmd.
24
+ stubs(:execute).
25
+ returns(Cocaine::CommandLine::Output.new("", error_output))
33
26
  with_exitstatus_returning(1) do
34
27
  begin
35
28
  cmd.run
36
29
  rescue Cocaine::ExitStatusError => e
37
- e.message.should =~ /#{error_output}/
30
+ e.message.should =~ /STDERR:\s+#{error_output}/
38
31
  end
39
32
  end
40
33
  end
41
34
 
42
- it 'passes error message to the exception when command fails with Errno::ENOENT' do
35
+ it 'passes the error message to the exception when command is not found' do
43
36
  cmd = Cocaine::CommandLine.new('test', '')
44
- cmd.stubs(:execute).with('test').raises(Errno::ENOENT.new("not found"))
37
+ cmd.stubs(:execute).raises(Errno::ENOENT.new("not found"))
45
38
  begin
46
39
  cmd.run
47
40
  rescue Cocaine::CommandNotFoundError => e
@@ -58,7 +51,7 @@ describe "When an error happens" do
58
51
  cmd.exit_status.should == 1
59
52
  end
60
53
 
61
- it "does not blow up if running the command errored before the actual execution" do
54
+ it "does not blow up if running the command errored before execution" do
62
55
  assuming_no_processes_have_been_run
63
56
  command = Cocaine::CommandLine.new("echo", ":hello_world")
64
57
  command.stubs(:command).raises("An Error")
@@ -6,6 +6,7 @@ require 'timeout'
6
6
  require 'tempfile'
7
7
  require 'pry'
8
8
  require 'thread'
9
+ require 'pathname'
9
10
 
10
11
  begin; require 'active_support/logger'; rescue LoadError; end
11
12
  begin; require 'active_support/buffered_logger'; rescue LoadError; end
@@ -0,0 +1,11 @@
1
+ RSpec::Matchers.define :have_output do |expected|
2
+ match do |actual|
3
+ actual.output == expected
4
+ end
5
+ end
6
+
7
+ RSpec::Matchers.define :have_error_output do |expected|
8
+ match do |actual|
9
+ actual.error_output == expected
10
+ end
11
+ end
@@ -6,7 +6,7 @@ shared_examples_for "a command that does not block" do
6
6
  Timeout.timeout(5) do
7
7
  output = subject.call("cat '#{garbage_file.path}'")
8
8
  $?.exitstatus.should == 0
9
- output.length.should == 10 * 1024 * 1024
9
+ output.output.length.should == 10 * 1024 * 1024
10
10
  end
11
11
 
12
12
  garbage_file.close
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocaine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.7
4
+ version: 0.5.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Yurek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-02 00:00:00.000000000 Z
11
+ date: 2015-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control
@@ -137,6 +137,8 @@ files:
137
137
  - cocaine.gemspec
138
138
  - lib/cocaine.rb
139
139
  - lib/cocaine/command_line.rb
140
+ - lib/cocaine/command_line/multi_pipe.rb
141
+ - lib/cocaine/command_line/output.rb
140
142
  - lib/cocaine/command_line/runners.rb
141
143
  - lib/cocaine/command_line/runners/backticks_runner.rb
142
144
  - lib/cocaine/command_line/runners/fake_runner.rb
@@ -146,6 +148,7 @@ files:
146
148
  - lib/cocaine/exceptions.rb
147
149
  - lib/cocaine/os_detector.rb
148
150
  - lib/cocaine/version.rb
151
+ - spec/cocaine/command_line/output_spec.rb
149
152
  - spec/cocaine/command_line/runners/backticks_runner_spec.rb
150
153
  - spec/cocaine/command_line/runners/fake_runner_spec.rb
151
154
  - spec/cocaine/command_line/runners/popen_runner_spec.rb
@@ -157,6 +160,7 @@ files:
157
160
  - spec/cocaine/runners_spec.rb
158
161
  - spec/spec_helper.rb
159
162
  - spec/support/fake_logger.rb
163
+ - spec/support/have_output.rb
160
164
  - spec/support/nonblocking_examples.rb
161
165
  - spec/support/stub_os.rb
162
166
  - spec/support/unsetting_exitstatus.rb
@@ -181,11 +185,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
185
  version: '0'
182
186
  requirements: []
183
187
  rubyforge_project:
184
- rubygems_version: 2.2.2
188
+ rubygems_version: 2.4.8
185
189
  signing_key:
186
190
  specification_version: 4
187
191
  summary: A small library for doing (command) lines
188
192
  test_files:
193
+ - spec/cocaine/command_line/output_spec.rb
189
194
  - spec/cocaine/command_line/runners/backticks_runner_spec.rb
190
195
  - spec/cocaine/command_line/runners/fake_runner_spec.rb
191
196
  - spec/cocaine/command_line/runners/popen_runner_spec.rb
@@ -197,6 +202,7 @@ test_files:
197
202
  - spec/cocaine/runners_spec.rb
198
203
  - spec/spec_helper.rb
199
204
  - spec/support/fake_logger.rb
205
+ - spec/support/have_output.rb
200
206
  - spec/support/nonblocking_examples.rb
201
207
  - spec/support/stub_os.rb
202
208
  - spec/support/unsetting_exitstatus.rb