awesome_spawn 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 495db35a5162aeca5013e1c52777938873956d4d
4
+ data.tar.gz: aaacd54a4c413f3f69bba0a52b52386041dc1e23
5
+ SHA512:
6
+ metadata.gz: 4b491f9bdcf6a10961ed3b38e22a66f2906e639b6f0eee2340151bda4c1bba929c46765245d1b6ea38b206a328567bd4d834ce36f5d4de7aa6ec9845c428319e
7
+ data.tar.gz: c291f6d3861399c95343a9f787db4ac2ccf36415c7dda00934e4d8df44e8bd79fa45639b4d7e63eb88b3c1f5074042534b43aef8ad3051c2c0abff289ef01e0d
data/lib/awesome_spawn.rb CHANGED
@@ -3,12 +3,19 @@ require "awesome_spawn/command_line_builder"
3
3
  require "awesome_spawn/command_result"
4
4
  require "awesome_spawn/command_result_error"
5
5
  require "awesome_spawn/no_such_file_error"
6
+ require "awesome_spawn/null_logger"
6
7
 
7
8
  require "open3"
8
9
 
9
10
  module AwesomeSpawn
10
11
  extend self
11
12
 
13
+ attr_writer :logger
14
+
15
+ def logger
16
+ @logger ||= NullLogger.new
17
+ end
18
+
12
19
  # Execute `command` synchronously via Kernel.spawn and gather the output
13
20
  # stream, error stream, and exit status in a {CommandResult}.
14
21
  #
@@ -45,11 +52,10 @@ module AwesomeSpawn
45
52
  #
46
53
  # @param [String] command The command to run
47
54
  # @param [Hash] options The options for running the command. Also accepts any
48
- # option that can be passed to Kernel.spawn, except `:out` and `:err`.
55
+ # option that can be passed to Kernel.spawn, except `:in`, `:out` and `:err`.
49
56
  # @option options [Hash,Array] :params The command line parameters. See
50
57
  # {#build_command_line} for how to specify params.
51
- # @option options [String] :in_data Data to be passed on stdin. If this option
52
- # is specified you cannot specify `:in`.
58
+ # @option options [String] :in_data Data to be passed on stdin.
53
59
  #
54
60
  # @raise [NoSuchFileError] if the `command` is not found
55
61
  # @return [CommandResult] the output stream, error stream, and exit status
@@ -57,20 +63,17 @@ module AwesomeSpawn
57
63
  def run(command, options = {})
58
64
  raise ArgumentError, "options cannot contain :out" if options.include?(:out)
59
65
  raise ArgumentError, "options cannot contain :err" if options.include?(:err)
60
- raise ArgumentError, "options cannot contain :in if :in_data is specified" if options.include?(:in) && options.include?(:in_data)
66
+ raise ArgumentError, "options cannot contain :in" if options.include?(:in)
61
67
  options = options.dup
62
68
  params = options.delete(:params)
63
- in_data = options.delete(:in_data)
69
+ if (in_data = options.delete(:in_data))
70
+ options[:stdin_data] = in_data
71
+ end
64
72
 
65
73
  output, error, status = "", "", nil
66
74
  command_line = build_command_line(command, params)
67
75
 
68
- begin
69
- output, error, status = launch(command_line, in_data, options)
70
- ensure
71
- output ||= ""
72
- error ||= ""
73
- end
76
+ output, error, status = launch(command_line, options)
74
77
  rescue Errno::ENOENT => err
75
78
  raise NoSuchFileError.new(err.message) if NoSuchFileError.detected?(err.message)
76
79
  raise
@@ -92,8 +95,10 @@ module AwesomeSpawn
92
95
  def run!(command, options = {})
93
96
  command_result = run(command, options)
94
97
 
95
- if command_result.exit_status != 0
98
+ if command_result.failure?
96
99
  message = "#{command} exit code: #{command_result.exit_status}"
100
+ logger.error("AwesomeSpawn: #{message}")
101
+ logger.error("AwesomeSpawn: #{command_result.error}")
97
102
  raise CommandResultError.new(message, command_result)
98
103
  end
99
104
 
@@ -107,10 +112,8 @@ module AwesomeSpawn
107
112
 
108
113
  private
109
114
 
110
- def launch(command, in_data, spawn_options = {})
111
- spawn_options = spawn_options.merge(:stdin_data => in_data) if in_data
115
+ def launch(command, spawn_options = {})
112
116
  output, error, status = Open3.capture3(command, spawn_options)
113
- status &&= status.exitstatus
114
- return output, error, status
117
+ return output || "", error || "", status && status.exitstatus
115
118
  end
116
119
  end
@@ -0,0 +1,11 @@
1
+ require 'logger'
2
+
3
+ module AwesomeSpawn
4
+ class NullLogger < Logger
5
+ def initialize(*_args)
6
+ end
7
+
8
+ def add(*_args, &_block)
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,3 @@
1
1
  module AwesomeSpawn
2
- VERSION = "1.2.1"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -6,24 +6,38 @@ describe AwesomeSpawn do
6
6
 
7
7
  shared_examples_for "run" do
8
8
  context "options" do
9
+ it "params won't be modified" do
10
+ params = {:params => {:user => "bob"}}
11
+ orig_params = params.dup
12
+ allow(subject).to receive(:launch).with("true --user bob", {}).and_return(["", "", 0])
13
+ subject.send(run_method, "true", params)
14
+ expect(orig_params).to eq(params)
15
+ end
16
+
9
17
  it ":params won't be modified" do
10
18
  params = {:user => "bob"}
11
19
  orig_params = params.dup
12
- subject.stub(:launch => ["", "", 0])
20
+ allow(subject).to receive(:launch).with("true --user bob", {}).and_return(["", "", 0])
13
21
  subject.send(run_method, "true", :params => params)
14
22
  expect(orig_params).to eq(params)
15
23
  end
16
24
 
17
- it ":in_data cannot be passed with :in" do
18
- expect { subject.send(run_method, "true", :in_data => "XXXXX", :in => "/dev/null") } .to raise_error(ArgumentError)
25
+ it ":in is not supported" do
26
+ expect do
27
+ subject.send(run_method, "true", :in => "/dev/null")
28
+ end.to raise_error(ArgumentError, "options cannot contain :in")
19
29
  end
20
30
 
21
31
  it ":out is not supported" do
22
- expect { subject.send(run_method, "true", :out => "/dev/null") }.to raise_error(ArgumentError)
32
+ expect do
33
+ subject.send(run_method, "true", :out => "/dev/null")
34
+ end.to raise_error(ArgumentError, "options cannot contain :out")
23
35
  end
24
36
 
25
37
  it ":err is not supported" do
26
- expect { subject.send(run_method, "true", :err => "/dev/null") }.to raise_error(ArgumentError)
38
+ expect do
39
+ subject.send(run_method, "true", :err => "/dev/null")
40
+ end.to raise_error(ArgumentError, "options cannot contain :err")
27
41
  end
28
42
  end
29
43
 
@@ -53,7 +67,9 @@ describe AwesomeSpawn do
53
67
  end
54
68
 
55
69
  it "command bad" do
56
- expect { subject.send(run_method, "XXXXX --user=bob") }.to raise_error(Errno::ENOENT, "No such file or directory - XXXXX")
70
+ expect do
71
+ subject.send(run_method, "XXXXX --user=bob")
72
+ end.to raise_error(AwesomeSpawn::NoSuchFileError, "No such file or directory - XXXXX")
57
73
  end
58
74
 
59
75
  context "with option" do
@@ -70,6 +86,18 @@ describe AwesomeSpawn do
70
86
  end
71
87
  end
72
88
 
89
+ context "#exit_status" do
90
+ it "command ok exit ok" do
91
+ expect(subject.send(run_method, "echo", :params => %w(x)).command_line).to eq("echo x")
92
+ end
93
+
94
+ it "command ok exit bad" do
95
+ if run_method == "run"
96
+ expect(subject.send(run_method, "echo x && false").command_line).to eq("echo x && false")
97
+ end
98
+ end
99
+ end
100
+
73
101
  context "#exit_status" do
74
102
  it "command ok exit ok" do
75
103
  expect(subject.send(run_method, "true").exit_status).to eq(0)
@@ -88,9 +116,17 @@ describe AwesomeSpawn do
88
116
  it "command ok exit bad" do
89
117
  expect(subject.send(run_method, "echo 'bad' && false").output).to eq("bad\n") if run_method == "run"
90
118
  end
119
+
120
+ it "has output even though output redirected to stderr" do
121
+ expect(subject.send(run_method, "echo \"Hello World\" >&2").output).to eq("")
122
+ end
91
123
  end
92
124
 
93
125
  context "#error" do
126
+ it "has error even though no error" do
127
+ expect(subject.send(run_method, "echo", :params => ["Hello World"]).error).to eq("")
128
+ end
129
+
94
130
  it "command ok exit ok" do
95
131
  expect(subject.send(run_method, "echo \"Hello World\" >&2").error).to eq("Hello World\n")
96
132
  end
@@ -102,6 +138,16 @@ describe AwesomeSpawn do
102
138
  end
103
139
  end
104
140
 
141
+ context ".build_command_line" do
142
+ it "should handle single parameter" do
143
+ expect(subject.build_command_line("cmd")).to eq("cmd")
144
+ end
145
+
146
+ it "should handle multi parameter" do
147
+ expect(subject.build_command_line("cmd", :status => true)).to eq("cmd --status true")
148
+ end
149
+ end
150
+
105
151
  context ".run" do
106
152
  include_examples "run" do
107
153
  let(:run_method) {"run"}
@@ -16,6 +16,14 @@ describe AwesomeSpawn::CommandLineBuilder do
16
16
  expect(subject.build("true", nil)).to eq "true"
17
17
  end
18
18
 
19
+ it "with empty" do
20
+ expect(subject.build("true", "")).to eq "true"
21
+ end
22
+
23
+ it "with empty" do
24
+ expect(subject.build("true", [])).to eq "true"
25
+ end
26
+
19
27
  it "with Pathname command" do
20
28
  actual = subject.build(Pathname.new("/usr/bin/ruby"))
21
29
  expect(actual).to eq "/usr/bin/ruby"
@@ -197,6 +205,10 @@ describe AwesomeSpawn::CommandLineBuilder do
197
205
  assert_params([["--abc", ["def", "ghi"]]], "--abc def ghi")
198
206
  end
199
207
 
208
+ it "with value as Array and extra nils" do
209
+ assert_params([["--abc", [nil, "def", nil, "ghi", nil]]], "--abc def ghi")
210
+ end
211
+
200
212
  it "with value as flattened Array" do
201
213
  assert_params([["--abc", "def", "ghi"]], "--abc def ghi")
202
214
  end
@@ -250,6 +262,11 @@ describe AwesomeSpawn::CommandLineBuilder do
250
262
  assert_params(params, expected)
251
263
  end
252
264
 
265
+ it "as mixed Array" do
266
+ params = ["log", "feature", "-E", :oneline, :grep, "abc"]
267
+ assert_params(params, expected)
268
+ end
269
+
253
270
  it "as mixed Array with nested Hashes" do
254
271
  params = ["log", "feature", "-E", :oneline, {:grep => "abc"}]
255
272
  assert_params(params, expected)
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe AwesomeSpawn::CommandResultError do
4
+ context "basic false command" do
5
+ before { enable_spawning }
6
+ subject do
7
+ begin
8
+ AwesomeSpawn.run!("false")
9
+ rescue => e
10
+ return e
11
+ end
12
+ end
13
+
14
+ it { expect(subject.message).to eq("false exit code: 1") }
15
+ it { expect(subject.result).to be_a_failure }
16
+ end
17
+ end
@@ -1,23 +1,38 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe AwesomeSpawn::CommandResult do
4
- context "#inspect" do
5
- it "will not display sensitive information" do
6
- str = described_class.new("aaa", "bbb", "ccc", 0).inspect
4
+ context "succeeding object" do
5
+ subject { described_class.new("aaa", "bbb", "ccc", 0) }
7
6
 
8
- expect(str).to_not include("aaa")
9
- expect(str).to_not include("bbb")
10
- expect(str).to_not include("ccc")
7
+ it "should set attributes" do
8
+ expect(subject.command_line).to eq("aaa")
9
+ expect(subject.output).to eq("bbb")
10
+ expect(subject.error).to eq("ccc")
11
+ expect(subject.exit_status).to eq(0)
12
+ expect(subject.inspect).to match(/^#<AwesomeSpawn::CommandResult:[0-9a-fx]+ @exit_status=0>$/)
11
13
  end
12
14
 
13
- it "will know if a command succeeded" do
14
- expect(described_class.new("c", "o", "e", 0)).to be_a_success
15
- expect(described_class.new("c", "o", "e", 0)).not_to be_a_failure
15
+ it "should not display sensitive information" do
16
+ expect(subject.inspect).to_not include("aaa")
17
+ expect(subject.inspect).to_not include("bbb")
18
+ expect(subject.inspect).to_not include("ccc")
16
19
  end
17
20
 
18
- it "will know if a command failed" do
19
- expect(described_class.new("c", "o", "e", 1)).to be_a_failure
20
- expect(described_class.new("c", "o", "e", 1)).not_to be_a_success
21
- end
21
+ it { expect(subject).to be_a_success }
22
+ it { expect(subject).not_to be_a_failure }
23
+ end
24
+
25
+ context "failing object" do
26
+ subject { described_class.new("aaa", "bbb", "ccc", 1) }
27
+
28
+ it { expect(subject).not_to be_a_success }
29
+ it { expect(subject).to be_a_failure }
30
+ end
31
+
32
+ context "another failing object" do
33
+ subject { described_class.new("aaa", "bbb", "ccc", 100) }
34
+
35
+ it { expect(subject).not_to be_a_success }
36
+ it { expect(subject).to be_a_failure }
22
37
  end
23
38
  end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe AwesomeSpawn::NoSuchFileError do
4
+ before do
5
+ enable_spawning
6
+ end
7
+
8
+ context "single word command" do
9
+ subject { caught_exception_for("falsey") }
10
+ it { expect(subject.message).to eq("No such file or directory - falsey") }
11
+ it { expect(subject.to_s).to eq("No such file or directory - falsey") }
12
+ it { expect(subject).to be_a(described_class) }
13
+ end
14
+
15
+ context "multi word command" do
16
+ subject { caught_exception_for(" flat --arg 1 --arg 2") }
17
+ it { expect(subject.message).to eq("No such file or directory - flat") }
18
+ it { expect(subject.to_s).to eq("No such file or directory - flat") }
19
+ it { expect(subject).to be_a(described_class) }
20
+ end
21
+
22
+ def caught_exception_for(command)
23
+ AwesomeSpawn.run!(command)
24
+ rescue => e
25
+ return e
26
+ end
27
+ end
data/spec/spec_helper.rb CHANGED
@@ -5,7 +5,6 @@
5
5
  #
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
7
  RSpec.configure do |config|
8
- config.treat_symbols_as_metadata_keys_with_true_values = true
9
8
  config.run_all_when_everything_filtered = true
10
9
  config.filter_run :focus
11
10
 
@@ -19,11 +18,12 @@ RSpec.configure do |config|
19
18
  end
20
19
 
21
20
  def disable_spawning
22
- Open3.stub(:capture3).and_raise("Spawning is not permitted in specs. Please change your spec to use expectations/stubs.")
21
+ allow(Open3).to receive(:capture3)
22
+ .and_raise("Spawning is not permitted in specs. Please change your spec to use expectations/stubs.")
23
23
  end
24
24
 
25
25
  def enable_spawning
26
- Open3.stub(:capture3).and_call_original
26
+ allow(Open3).to receive(:capture3).and_call_original
27
27
  end
28
28
 
29
29
  begin
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: awesome_spawn
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
5
- prerelease:
4
+ version: 1.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jason Frey
@@ -12,12 +11,11 @@ authors:
12
11
  autorequire:
13
12
  bindir: bin
14
13
  cert_chain: []
15
- date: 2014-07-17 00:00:00.000000000 Z
14
+ date: 2015-01-28 00:00:00.000000000 Z
16
15
  dependencies:
17
16
  - !ruby/object:Gem::Dependency
18
17
  name: bundler
19
18
  requirement: !ruby/object:Gem::Requirement
20
- none: false
21
19
  requirements:
22
20
  - - ~>
23
21
  - !ruby/object:Gem::Version
@@ -25,7 +23,6 @@ dependencies:
25
23
  type: :development
26
24
  prerelease: false
27
25
  version_requirements: !ruby/object:Gem::Requirement
28
- none: false
29
26
  requirements:
30
27
  - - ~>
31
28
  - !ruby/object:Gem::Version
@@ -33,49 +30,43 @@ dependencies:
33
30
  - !ruby/object:Gem::Dependency
34
31
  name: rake
35
32
  requirement: !ruby/object:Gem::Requirement
36
- none: false
37
33
  requirements:
38
- - - ! '>='
34
+ - - '>='
39
35
  - !ruby/object:Gem::Version
40
36
  version: '0'
41
37
  type: :development
42
38
  prerelease: false
43
39
  version_requirements: !ruby/object:Gem::Requirement
44
- none: false
45
40
  requirements:
46
- - - ! '>='
41
+ - - '>='
47
42
  - !ruby/object:Gem::Version
48
43
  version: '0'
49
44
  - !ruby/object:Gem::Dependency
50
45
  name: rspec
51
46
  requirement: !ruby/object:Gem::Requirement
52
- none: false
53
47
  requirements:
54
- - - ! '>='
48
+ - - '>='
55
49
  - !ruby/object:Gem::Version
56
50
  version: '0'
57
51
  type: :development
58
52
  prerelease: false
59
53
  version_requirements: !ruby/object:Gem::Requirement
60
- none: false
61
54
  requirements:
62
- - - ! '>='
55
+ - - '>='
63
56
  - !ruby/object:Gem::Version
64
57
  version: '0'
65
58
  - !ruby/object:Gem::Dependency
66
59
  name: coveralls
67
60
  requirement: !ruby/object:Gem::Requirement
68
- none: false
69
61
  requirements:
70
- - - ! '>='
62
+ - - '>='
71
63
  - !ruby/object:Gem::Version
72
64
  version: '0'
73
65
  type: :development
74
66
  prerelease: false
75
67
  version_requirements: !ruby/object:Gem::Requirement
76
- none: false
77
68
  requirements:
78
- - - ! '>='
69
+ - - '>='
79
70
  - !ruby/object:Gem::Version
80
71
  version: '0'
81
72
  description: AwesomeSpawn is a module that provides some useful features over Ruby's
@@ -94,43 +85,47 @@ files:
94
85
  - lib/awesome_spawn/command_result.rb
95
86
  - lib/awesome_spawn/command_result_error.rb
96
87
  - lib/awesome_spawn/no_such_file_error.rb
88
+ - lib/awesome_spawn/null_logger.rb
97
89
  - lib/awesome_spawn/version.rb
98
90
  - .yardopts
99
91
  - README.md
100
92
  - LICENSE.txt
101
93
  - spec/awesome_spawn_spec.rb
102
94
  - spec/command_line_builder_spec.rb
95
+ - spec/command_result_error_spec.rb
103
96
  - spec/command_result_spec.rb
97
+ - spec/no_such_file_error_spec.rb
104
98
  - spec/spec_helper.rb
105
99
  - .rspec
106
100
  homepage: https://github.com/ManageIQ/awesome_spawn
107
101
  licenses:
108
102
  - MIT
103
+ metadata: {}
109
104
  post_install_message:
110
105
  rdoc_options: []
111
106
  require_paths:
112
107
  - lib
113
108
  required_ruby_version: !ruby/object:Gem::Requirement
114
- none: false
115
109
  requirements:
116
- - - ! '>='
110
+ - - '>='
117
111
  - !ruby/object:Gem::Version
118
112
  version: '0'
119
113
  required_rubygems_version: !ruby/object:Gem::Requirement
120
- none: false
121
114
  requirements:
122
- - - ! '>='
115
+ - - '>='
123
116
  - !ruby/object:Gem::Version
124
117
  version: '0'
125
118
  requirements: []
126
119
  rubyforge_project:
127
- rubygems_version: 1.8.23.2
120
+ rubygems_version: 2.0.14
128
121
  signing_key:
129
- specification_version: 3
122
+ specification_version: 4
130
123
  summary: AwesomeSpawn is a module that provides some useful features over Ruby's Kernel.spawn.
131
124
  test_files:
132
125
  - spec/awesome_spawn_spec.rb
133
126
  - spec/command_line_builder_spec.rb
127
+ - spec/command_result_error_spec.rb
134
128
  - spec/command_result_spec.rb
129
+ - spec/no_such_file_error_spec.rb
135
130
  - spec/spec_helper.rb
136
131
  - .rspec