cocaine 0.5.7 → 0.5.8

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 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