awesome_spawn 1.3.0 → 1.4.0
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 +4 -4
- data/lib/awesome_spawn.rb +24 -13
- data/lib/awesome_spawn/command_line_builder.rb +13 -7
- data/lib/awesome_spawn/command_result_error.rb +4 -0
- data/lib/awesome_spawn/spec_helper.rb +54 -0
- data/lib/awesome_spawn/version.rb +1 -1
- data/spec/awesome_spawn_spec.rb +131 -113
- data/spec/command_line_builder_spec.rb +8 -0
- data/spec/command_result_error_spec.rb +4 -0
- data/spec/spec_helper.rb +4 -9
- metadata +19 -18
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 815be141f2f958bbb4ff8eb364d285cd6110d78b
         | 
| 4 | 
            +
              data.tar.gz: 322d170526af46c9ad840b69fe20f61794f46386
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 041a6034a9bf220ffc96511c370a03ed26cd9183efddff30f5bd4ffe8c8ce9af81a199e34c608b7862969f6f6e7eec026f0a1552b1321adee1f80e86e3196609
         | 
| 7 | 
            +
              data.tar.gz: abe800672e213bd32dc8d96baf82a311ab301a97ad303d5f500105cd0c179829b12fd98752872f14df34e236af13a315a476ee80926fb1b3ee83a733c178da79
         | 
    
        data/lib/awesome_spawn.rb
    CHANGED
    
    | @@ -50,30 +50,33 @@ module AwesomeSpawn | |
| 50 50 | 
             
              #   result.output
         | 
| 51 51 | 
             
              #   => "line1\nline2"
         | 
| 52 52 | 
             
              #
         | 
| 53 | 
            +
              # @example With environment variables passed in
         | 
| 54 | 
            +
              #   result = AwesomeSpawn.run('echo ABC=${ABC}', :env => {"ABC" => "abcde"})
         | 
| 55 | 
            +
              #   => #<AwesomeSpawn::CommandResult:0x007f9421a35590 @exit_status=0>
         | 
| 56 | 
            +
              #   result.output
         | 
| 57 | 
            +
              #   => "ABC=abcde\n"
         | 
| 58 | 
            +
              #
         | 
| 53 59 | 
             
              # @param [String] command The command to run
         | 
| 54 60 | 
             
              # @param [Hash] options The options for running the command.  Also accepts any
         | 
| 55 61 | 
             
              #   option that can be passed to Kernel.spawn, except `:in`, `:out` and `:err`.
         | 
| 56 62 | 
             
              # @option options [Hash,Array] :params The command line parameters. See
         | 
| 57 63 | 
             
              #   {#build_command_line} for how to specify params.
         | 
| 58 64 | 
             
              # @option options [String] :in_data Data to be passed on stdin.
         | 
| 65 | 
            +
              # @option options [Hash<String,String>] :env Additional environment variables for sub process
         | 
| 59 66 | 
             
              #
         | 
| 60 67 | 
             
              # @raise [NoSuchFileError] if the `command` is not found
         | 
| 61 68 | 
             
              # @return [CommandResult] the output stream, error stream, and exit status
         | 
| 62 69 | 
             
              # @see http://ruby-doc.org/core/Kernel.html#method-i-spawn Kernel.spawn
         | 
| 63 70 | 
             
              def run(command, options = {})
         | 
| 64 | 
            -
                 | 
| 65 | 
            -
                raise ArgumentError, "options cannot contain  | 
| 66 | 
            -
                 | 
| 67 | 
            -
             | 
| 68 | 
            -
                params  = options.delete(:params)
         | 
| 71 | 
            +
                bad_keys = (options.keys.flatten & [:in, :out, :err]).map { |k| ":#{k}" }
         | 
| 72 | 
            +
                raise ArgumentError, "options cannot contain #{bad_keys.join(", ")}" if bad_keys.any?
         | 
| 73 | 
            +
                env, command_line, options = parse_command_options(command, options)
         | 
| 74 | 
            +
             | 
| 69 75 | 
             
                if (in_data = options.delete(:in_data))
         | 
| 70 76 | 
             
                  options[:stdin_data] = in_data
         | 
| 71 77 | 
             
                end
         | 
| 72 78 |  | 
| 73 | 
            -
                output, error, status =  | 
| 74 | 
            -
                command_line = build_command_line(command, params)
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                output, error, status = launch(command_line, options)
         | 
| 79 | 
            +
                output, error, status = launch(env, command_line, options)
         | 
| 77 80 | 
             
              rescue Errno::ENOENT => err
         | 
| 78 81 | 
             
                raise NoSuchFileError.new(err.message) if NoSuchFileError.detected?(err.message)
         | 
| 79 82 | 
             
                raise
         | 
| @@ -96,7 +99,7 @@ module AwesomeSpawn | |
| 96 99 | 
             
                command_result = run(command, options)
         | 
| 97 100 |  | 
| 98 101 | 
             
                if command_result.failure?
         | 
| 99 | 
            -
                  message =  | 
| 102 | 
            +
                  message = CommandResultError.default_message(command, command_result.exit_status)
         | 
| 100 103 | 
             
                  logger.error("AwesomeSpawn: #{message}")
         | 
| 101 104 | 
             
                  logger.error("AwesomeSpawn: #{command_result.error}")
         | 
| 102 105 | 
             
                  raise CommandResultError.new(message, command_result)
         | 
| @@ -112,8 +115,16 @@ module AwesomeSpawn | |
| 112 115 |  | 
| 113 116 | 
             
              private
         | 
| 114 117 |  | 
| 115 | 
            -
              def launch(command, spawn_options | 
| 116 | 
            -
                output, error, status = Open3.capture3(command, spawn_options)
         | 
| 117 | 
            -
                return output | 
| 118 | 
            +
              def launch(env, command, spawn_options)
         | 
| 119 | 
            +
                output, error, status = Open3.capture3(env, command, spawn_options)
         | 
| 120 | 
            +
                return output, error, status && status.exitstatus
         | 
| 121 | 
            +
              end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
              def parse_command_options(command, options)
         | 
| 124 | 
            +
                options = options.dup
         | 
| 125 | 
            +
                params  = options.delete(:params)
         | 
| 126 | 
            +
                env = options.delete(:env) || {}
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                [env, build_command_line(command, params), options]
         | 
| 118 129 | 
             
              end
         | 
| 119 130 | 
             
            end
         | 
| @@ -10,6 +10,11 @@ module AwesomeSpawn | |
| 10 10 | 
             
                #   prevent command line injection.  Keys as Symbols are prefixed with `--`,
         | 
| 11 11 | 
             
                #   and `_` is replaced with `-`.
         | 
| 12 12 | 
             
                #
         | 
| 13 | 
            +
                #   - `{:k => "value"}`              generates `-k value`
         | 
| 14 | 
            +
                #   - `[[:k, "value"]]`              generates `-k value`
         | 
| 15 | 
            +
                #   - `{:k => "value"}`              generates `-k=value`
         | 
| 16 | 
            +
                #   - `[[:k=, "value"]]`             generates `-k=value` <br /><br />
         | 
| 17 | 
            +
                #
         | 
| 13 18 | 
             
                #   - `{:key => "value"}`            generates `--key value`
         | 
| 14 19 | 
             
                #   - `[[:key, "value"]]`            generates `--key value`
         | 
| 15 20 | 
             
                #   - `{:key= => "value"}`           generates `--key=value`
         | 
| @@ -54,7 +59,7 @@ module AwesomeSpawn | |
| 54 59 |  | 
| 55 60 | 
             
                def sanitize(params)
         | 
| 56 61 | 
             
                  return [] if params.nil? || params.empty?
         | 
| 57 | 
            -
                  sanitize_associative_array(params | 
| 62 | 
            +
                  sanitize_associative_array(params)
         | 
| 58 63 | 
             
                end
         | 
| 59 64 |  | 
| 60 65 | 
             
                def sanitize_associative_array(assoc_array)
         | 
| @@ -66,8 +71,8 @@ module AwesomeSpawn | |
| 66 71 | 
             
                def sanitize_item(item)
         | 
| 67 72 | 
             
                  case item
         | 
| 68 73 | 
             
                  when Array then sanitize_key_values(item[0], item[1..-1])
         | 
| 69 | 
            -
                  when Hash  then sanitize_associative_array(item | 
| 70 | 
            -
                  else            sanitize_key_values(item,  | 
| 74 | 
            +
                  when Hash  then sanitize_associative_array(item)
         | 
| 75 | 
            +
                  else            sanitize_key_values(item, nil)
         | 
| 71 76 | 
             
                  end
         | 
| 72 77 | 
             
                end
         | 
| 73 78 |  | 
| @@ -78,12 +83,11 @@ module AwesomeSpawn | |
| 78 83 | 
             
                KEY_REGEX = /^((?:--?)?)(.+?)(=?)$/
         | 
| 79 84 |  | 
| 80 85 | 
             
                def sanitize_key(key)
         | 
| 81 | 
            -
                  return key if key.nil?
         | 
| 86 | 
            +
                  return key if key.nil? || key.empty?
         | 
| 82 87 | 
             
                  key = convert_symbol_key(key) if key.kind_of?(Symbol)
         | 
| 83 88 |  | 
| 84 89 | 
             
                  case key
         | 
| 85 90 | 
             
                  when String
         | 
| 86 | 
            -
                    return key if key.empty?
         | 
| 87 91 | 
             
                    prefix, key, suffix = KEY_REGEX.match(key)[1..3]
         | 
| 88 92 | 
             
                    "#{prefix}#{sanitize_value(key)}#{suffix}"
         | 
| 89 93 | 
             
                  else
         | 
| @@ -92,13 +96,15 @@ module AwesomeSpawn | |
| 92 96 | 
             
                end
         | 
| 93 97 |  | 
| 94 98 | 
             
                def convert_symbol_key(key)
         | 
| 95 | 
            -
                   | 
| 99 | 
            +
                  key = key.to_s
         | 
| 100 | 
            +
                  dash = key =~ /^.=?$/ ? "-" : "--"
         | 
| 101 | 
            +
                  "#{dash}#{key.tr("_", "-")}"
         | 
| 96 102 | 
             
                end
         | 
| 97 103 |  | 
| 98 104 | 
             
                def sanitize_value(value)
         | 
| 99 105 | 
             
                  case value
         | 
| 100 106 | 
             
                  when Enumerable
         | 
| 101 | 
            -
                    value. | 
| 107 | 
            +
                    value.collect { |i| sanitize_value(i) }.compact
         | 
| 102 108 | 
             
                  when NilClass
         | 
| 103 109 | 
             
                    value
         | 
| 104 110 | 
             
                  else
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            require 'awesome_spawn'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module AwesomeSpawn
         | 
| 4 | 
            +
              module SpecHelper
         | 
| 5 | 
            +
                def disable_spawning
         | 
| 6 | 
            +
                  allow(Open3).to receive(:capture3)
         | 
| 7 | 
            +
                    .and_raise("Spawning is not permitted in specs.  Please change your spec to use expectations/stubs.")
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def enable_spawning
         | 
| 11 | 
            +
                  allow(Open3).to receive(:capture3).and_call_original
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def stub_good_run
         | 
| 15 | 
            +
                  stub_run(:good, :run, command, options)
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def stub_bad_run
         | 
| 19 | 
            +
                  stub_run(:bad, :run, command, options)
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def stub_good_run!(command, options = {})
         | 
| 23 | 
            +
                  stub_run(:good, :run!, command, options)
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def stub_bad_run!(command, options = {})
         | 
| 27 | 
            +
                  stub_run(:bad, :run!, command, options)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                private
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def stub_run(mode, method, command, options)
         | 
| 33 | 
            +
                  output = options[:output] || ""
         | 
| 34 | 
            +
                  error  = options[:error]  || (mode == :bad ? "Failure" : "")
         | 
| 35 | 
            +
                  exit_status = options[:exit_status] || (mode == :bad ? 1 : 0)
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  params = options[:params]
         | 
| 38 | 
            +
                  command_line = AwesomeSpawn.build_command_line(command, params)
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  args = [command]
         | 
| 41 | 
            +
                  args << {:params => params} if params
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  result = CommandResult.new(command_line, output, error, exit_status)
         | 
| 44 | 
            +
                  if method == :run! && mode == :bad
         | 
| 45 | 
            +
                    error_message = CommandResultError.default_message(command, exit_status)
         | 
| 46 | 
            +
                    error = CommandResultError.new(error_message, result)
         | 
| 47 | 
            +
                    expect(AwesomeSpawn).to receive(method).with(*args).and_raise(error)
         | 
| 48 | 
            +
                  else
         | 
| 49 | 
            +
                    expect(AwesomeSpawn).to receive(method).with(*args).and_return(result)
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                  result
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
    
        data/spec/awesome_spawn_spec.rb
    CHANGED
    
    | @@ -4,159 +4,177 @@ require 'pathname' # For Pathname specific specs | |
| 4 4 | 
             
            describe AwesomeSpawn do
         | 
| 5 5 | 
             
              subject { described_class }
         | 
| 6 6 |  | 
| 7 | 
            -
              shared_examples_for " | 
| 8 | 
            -
                 | 
| 9 | 
            -
                   | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 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
         | 
| 7 | 
            +
              shared_examples_for "parses" do
         | 
| 8 | 
            +
                it "supports no options" do
         | 
| 9 | 
            +
                  allow(subject).to receive(:launch).with({}, "true", {}).and_return(["", "", 0])
         | 
| 10 | 
            +
                  subject.send(run_method, "true")
         | 
| 11 | 
            +
                end
         | 
| 16 12 |  | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
                    subject.send(run_method, "true", :params => params)
         | 
| 22 | 
            -
                    expect(orig_params).to eq(params)
         | 
| 23 | 
            -
                  end
         | 
| 13 | 
            +
                it "supports option :params and :env" do
         | 
| 14 | 
            +
                  allow(subject).to receive(:launch).with({"VAR" => "x"}, "true --user bob", {}).and_return(["", "", 0])
         | 
| 15 | 
            +
                  subject.send(run_method, "true", :params => {:user => "bob"}, :env => {"VAR" => "x"})
         | 
| 16 | 
            +
                end
         | 
| 24 17 |  | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
                   | 
| 18 | 
            +
                it "wont modify passed in options" do
         | 
| 19 | 
            +
                  options      = {:params => {:user => "bob"}}
         | 
| 20 | 
            +
                  orig_options = options.dup
         | 
| 21 | 
            +
                  allow(subject).to receive(:launch).with({}, "true --user bob", {}).and_return(["", "", 0])
         | 
| 22 | 
            +
                  subject.send(run_method, "true", options)
         | 
| 23 | 
            +
                  expect(orig_options).to eq(options)
         | 
| 24 | 
            +
                end
         | 
| 30 25 |  | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
                   | 
| 26 | 
            +
                it "wont modify passed in options[:params]" do
         | 
| 27 | 
            +
                  params      = {:user => "bob"}
         | 
| 28 | 
            +
                  orig_params = params.dup
         | 
| 29 | 
            +
                  allow(subject).to receive(:launch).with({}, "true --user bob", {}).and_return(["", "", 0])
         | 
| 30 | 
            +
                  subject.send(run_method, "true", :params => params)
         | 
| 31 | 
            +
                  expect(orig_params).to eq(params)
         | 
| 32 | 
            +
                end
         | 
| 36 33 |  | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
                  end
         | 
| 34 | 
            +
                it "warns about option :in" do
         | 
| 35 | 
            +
                  expect do
         | 
| 36 | 
            +
                    subject.send(run_method, "true", :in => "/dev/null")
         | 
| 37 | 
            +
                  end.to raise_error(ArgumentError, "options cannot contain :in")
         | 
| 42 38 | 
             
                end
         | 
| 43 39 |  | 
| 44 | 
            -
                 | 
| 45 | 
            -
                   | 
| 46 | 
            -
                     | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 40 | 
            +
                it "warns about option :out" do
         | 
| 41 | 
            +
                  expect do
         | 
| 42 | 
            +
                    subject.send(run_method, "true", :out => "/dev/null")
         | 
| 43 | 
            +
                  end.to raise_error(ArgumentError, "options cannot contain :out")
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                it "warns about option :err" do
         | 
| 47 | 
            +
                  expect do
         | 
| 48 | 
            +
                    subject.send(run_method, "true", :err => "/dev/null")
         | 
| 49 | 
            +
                  end.to raise_error(ArgumentError, "options cannot contain :err")
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                it "warns about option :err when in an array" do
         | 
| 53 | 
            +
                  expect do
         | 
| 54 | 
            +
                    subject.send(run_method, "true", [:err, :out, 3] => "/dev/null")
         | 
| 55 | 
            +
                  end.to raise_error(ArgumentError, "options cannot contain :err, :out")
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              shared_examples_for "executes" do
         | 
| 60 | 
            +
                before do
         | 
| 61 | 
            +
                  # Re-enable actual spawning just for these specs.
         | 
| 62 | 
            +
                  enable_spawning
         | 
| 63 | 
            +
                end
         | 
| 49 64 |  | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 65 | 
            +
                it "runs command" do
         | 
| 66 | 
            +
                  expect(subject.send(run_method, "true")).to be_kind_of AwesomeSpawn::CommandResult
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                it "detects bad commands" do
         | 
| 70 | 
            +
                  expect do
         | 
| 71 | 
            +
                    subject.send(run_method, "XXXXX --user=bob")
         | 
| 72 | 
            +
                  end.to raise_error(AwesomeSpawn::NoSuchFileError, "No such file or directory - XXXXX")
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                describe "parameters" do
         | 
| 76 | 
            +
                  it "changes directory" do
         | 
| 77 | 
            +
                    result = subject.send(run_method, "pwd", :chdir => "..")
         | 
| 78 | 
            +
                    expect(result.exit_status).to  eq(0)
         | 
| 79 | 
            +
                    expect(result.output.chomp).to eq(File.expand_path("..", Dir.pwd))
         | 
| 52 80 | 
             
                  end
         | 
| 53 81 |  | 
| 54 | 
            -
                  it " | 
| 55 | 
            -
                     | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
                      # raise_error with do/end block notation is broken in rspec-expectations 2.14.x
         | 
| 59 | 
            -
                      # and has been fixed in master but not yet released.
         | 
| 60 | 
            -
                      # See: https://github.com/rspec/rspec-expectations/commit/b0df827f4c12870aa4df2f20a817a8b01721a6af
         | 
| 61 | 
            -
                      expect { subject.send(run_method, "false") }.to raise_error {|e| error = e }
         | 
| 62 | 
            -
                      expect(error).to be_kind_of AwesomeSpawn::CommandResultError
         | 
| 63 | 
            -
                      expect(error.result).to be_kind_of AwesomeSpawn::CommandResult
         | 
| 64 | 
            -
                    else
         | 
| 65 | 
            -
                      expect { subject.send(run_method, "false") }.to_not raise_error
         | 
| 66 | 
            -
                    end
         | 
| 82 | 
            +
                  it "passes input" do
         | 
| 83 | 
            +
                    result = subject.send(run_method, "cat", :in_data => "line1\nline2")
         | 
| 84 | 
            +
                    expect(result.exit_status).to eq(0)
         | 
| 85 | 
            +
                    expect(result.output).to      eq("line1\nline2")
         | 
| 67 86 | 
             
                  end
         | 
| 68 87 |  | 
| 69 | 
            -
                  it " | 
| 70 | 
            -
                     | 
| 71 | 
            -
             | 
| 72 | 
            -
                     | 
| 88 | 
            +
                  it "sets environment" do
         | 
| 89 | 
            +
                    result = subject.send(run_method, "echo ${ABC}", :env => {"ABC" => "yay!"})
         | 
| 90 | 
            +
                    expect(result.exit_status).to eq(0)
         | 
| 91 | 
            +
                    expect(result.output).to      eq("yay!\n")
         | 
| 73 92 | 
             
                  end
         | 
| 93 | 
            +
                end
         | 
| 74 94 |  | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
                      expect(result.exit_status).to  eq(0)
         | 
| 79 | 
            -
                      expect(result.output.chomp).to eq(File.expand_path("..", Dir.pwd))
         | 
| 80 | 
            -
                    end
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                    it ":in_data" do
         | 
| 83 | 
            -
                      result = subject.send(run_method, "cat", :in_data => "line1\nline2")
         | 
| 84 | 
            -
                      expect(result.exit_status).to eq(0)
         | 
| 85 | 
            -
                      expect(result.output).to      eq("line1\nline2")
         | 
| 86 | 
            -
                    end
         | 
| 95 | 
            +
                describe "result" do
         | 
| 96 | 
            +
                  it "contains #command_line" do
         | 
| 97 | 
            +
                    expect(subject.send(run_method, "echo", :params => %w(x)).command_line).to eq("echo x")
         | 
| 87 98 | 
             
                  end
         | 
| 88 99 |  | 
| 89 | 
            -
                   | 
| 90 | 
            -
                     | 
| 91 | 
            -
             | 
| 92 | 
            -
                    end
         | 
| 100 | 
            +
                  it "contains #exit_status" do
         | 
| 101 | 
            +
                    expect(subject.send(run_method, "true").exit_status).to eq(0)
         | 
| 102 | 
            +
                  end
         | 
| 93 103 |  | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
                        expect(subject.send(run_method, "echo x && false").command_line).to eq("echo x && false")
         | 
| 97 | 
            -
                      end
         | 
| 98 | 
            -
                    end
         | 
| 104 | 
            +
                  it "contains #output" do
         | 
| 105 | 
            +
                    expect(subject.send(run_method, "echo \"Hello World\"").output).to eq("Hello World\n")
         | 
| 99 106 | 
             
                  end
         | 
| 100 107 |  | 
| 101 | 
            -
                   | 
| 102 | 
            -
                     | 
| 103 | 
            -
             | 
| 104 | 
            -
                    end
         | 
| 108 | 
            +
                  it "contains #output when output redirected to stderr)" do
         | 
| 109 | 
            +
                    expect(subject.send(run_method, "echo \"Hello World\" >&2").output).to eq("")
         | 
| 110 | 
            +
                  end
         | 
| 105 111 |  | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
                    end
         | 
| 112 | 
            +
                  it "contains #error when no error" do
         | 
| 113 | 
            +
                    expect(subject.send(run_method, "echo", :params => ["Hello World"]).error).to eq("")
         | 
| 109 114 | 
             
                  end
         | 
| 110 115 |  | 
| 111 | 
            -
                   | 
| 112 | 
            -
                     | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 116 | 
            +
                  it "contains #error" do
         | 
| 117 | 
            +
                    expect(subject.send(run_method, "echo \"Hello World\" >&2").error).to eq("Hello World\n")
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
              end
         | 
| 115 121 |  | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 122 | 
            +
              shared_examples_for "executes with failures" do
         | 
| 123 | 
            +
                context "result with a bad command" do
         | 
| 124 | 
            +
                  before do
         | 
| 125 | 
            +
                    # Re-enable actual spawning just for these specs.
         | 
| 126 | 
            +
                    enable_spawning
         | 
| 127 | 
            +
                  end
         | 
| 119 128 |  | 
| 120 | 
            -
             | 
| 121 | 
            -
             | 
| 122 | 
            -
                    end
         | 
| 129 | 
            +
                  it "contains #command_line" do
         | 
| 130 | 
            +
                    expect(subject.send(run_method, "echo x && false").command_line).to eq("echo x && false")
         | 
| 123 131 | 
             
                  end
         | 
| 124 132 |  | 
| 125 | 
            -
                   | 
| 126 | 
            -
                     | 
| 127 | 
            -
             | 
| 128 | 
            -
                    end
         | 
| 133 | 
            +
                  it "contains #exit_status" do
         | 
| 134 | 
            +
                    expect(subject.send(run_method, "false").exit_status).to eq(1)
         | 
| 135 | 
            +
                  end
         | 
| 129 136 |  | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 137 | 
            +
                  it "contains #output" do
         | 
| 138 | 
            +
                    expect(subject.send(run_method, "echo 'bad' && false").output).to eq("bad\n")
         | 
| 139 | 
            +
                  end
         | 
| 133 140 |  | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 136 | 
            -
                    end
         | 
| 141 | 
            +
                  it "contains #error" do
         | 
| 142 | 
            +
                    expect(subject.send(run_method, "echo 'bad' >&2 && false").error).to eq("bad\n")
         | 
| 137 143 | 
             
                  end
         | 
| 138 144 | 
             
                end
         | 
| 139 145 | 
             
              end
         | 
| 140 146 |  | 
| 141 | 
            -
               | 
| 142 | 
            -
                it " | 
| 147 | 
            +
              describe ".build_command_line" do
         | 
| 148 | 
            +
                it "supports no parameters" do
         | 
| 143 149 | 
             
                  expect(subject.build_command_line("cmd")).to eq("cmd")
         | 
| 144 150 | 
             
                end
         | 
| 145 151 |  | 
| 146 | 
            -
                it " | 
| 152 | 
            +
                it "supports single long parameter" do
         | 
| 147 153 | 
             
                  expect(subject.build_command_line("cmd", :status => true)).to eq("cmd --status true")
         | 
| 148 154 | 
             
                end
         | 
| 149 | 
            -
              end
         | 
| 150 155 |  | 
| 151 | 
            -
             | 
| 152 | 
            -
             | 
| 153 | 
            -
                  let(:run_method) {"run"}
         | 
| 156 | 
            +
                it "supports multiple long parameters" do
         | 
| 157 | 
            +
                  expect(subject.build_command_line("cmd", :status => true, :fast => false)).to eq("cmd --status true --fast false")
         | 
| 154 158 | 
             
                end
         | 
| 155 159 | 
             
              end
         | 
| 156 160 |  | 
| 157 | 
            -
               | 
| 158 | 
            -
                 | 
| 159 | 
            -
             | 
| 161 | 
            +
              describe ".run" do
         | 
| 162 | 
            +
                let(:run_method) { "run" }
         | 
| 163 | 
            +
                include_examples "parses"
         | 
| 164 | 
            +
                include_examples "executes"
         | 
| 165 | 
            +
                include_examples "executes with failures"
         | 
| 166 | 
            +
              end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
              describe ".run!" do
         | 
| 169 | 
            +
                let(:run_method) { "run!" }
         | 
| 170 | 
            +
                include_examples "parses"
         | 
| 171 | 
            +
                include_examples "executes"
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                it "raises errors on failure" do
         | 
| 174 | 
            +
                  expect { subject.send(run_method, "false") }.to raise_error do |error|
         | 
| 175 | 
            +
                    expect(error).to be_kind_of AwesomeSpawn::CommandResultError
         | 
| 176 | 
            +
                    expect(error.result).to be_kind_of AwesomeSpawn::CommandResult
         | 
| 177 | 
            +
                  end
         | 
| 160 178 | 
             
                end
         | 
| 161 179 | 
             
              end
         | 
| 162 180 | 
             
            end
         | 
| @@ -47,6 +47,14 @@ describe AwesomeSpawn::CommandLineBuilder do | |
| 47 47 | 
             
                    assert_params({"--user=" => "bob"}, "--user=bob")
         | 
| 48 48 | 
             
                  end
         | 
| 49 49 |  | 
| 50 | 
            +
                  it "with single letter symbol" do
         | 
| 51 | 
            +
                    assert_params({:a => "val"}, "-a val")
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  it "with single letter symbol" do
         | 
| 55 | 
            +
                    assert_params({:a= => "val"}, "-a=val")
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 50 58 | 
             
                  it "with value requiring sanitization" do
         | 
| 51 59 | 
             
                    assert_params({"--pass" => "P@$s w0rd%"}, "--pass P@\\$s\\ w0rd\\%")
         | 
| 52 60 | 
             
                  end
         | 
| @@ -14,4 +14,8 @@ describe AwesomeSpawn::CommandResultError do | |
| 14 14 | 
             
                it { expect(subject.message).to eq("false exit code: 1") }
         | 
| 15 15 | 
             
                it { expect(subject.result).to be_a_failure }
         | 
| 16 16 | 
             
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              it ".default_message" do
         | 
| 19 | 
            +
                expect(described_class.default_message("some message", 123)).to eq "some message exit code: 123"
         | 
| 20 | 
            +
              end
         | 
| 17 21 | 
             
            end
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -4,6 +4,9 @@ | |
| 4 4 | 
             
            # loaded once.
         | 
| 5 5 | 
             
            #
         | 
| 6 6 | 
             
            # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'awesome_spawn/spec_helper'
         | 
| 9 | 
            +
             | 
| 7 10 | 
             
            RSpec.configure do |config|
         | 
| 8 11 | 
             
              config.run_all_when_everything_filtered = true
         | 
| 9 12 | 
             
              config.filter_run :focus
         | 
| @@ -14,18 +17,10 @@ RSpec.configure do |config| | |
| 14 17 | 
             
              #     --seed 1234
         | 
| 15 18 | 
             
              config.order = 'random'
         | 
| 16 19 |  | 
| 20 | 
            +
              include AwesomeSpawn::SpecHelper
         | 
| 17 21 | 
             
              config.before { disable_spawning }
         | 
| 18 22 | 
             
            end
         | 
| 19 23 |  | 
| 20 | 
            -
            def disable_spawning
         | 
| 21 | 
            -
              allow(Open3).to receive(:capture3)
         | 
| 22 | 
            -
                .and_raise("Spawning is not permitted in specs.  Please change your spec to use expectations/stubs.")
         | 
| 23 | 
            -
            end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
            def enable_spawning
         | 
| 26 | 
            -
              allow(Open3).to receive(:capture3).and_call_original
         | 
| 27 | 
            -
            end
         | 
| 28 | 
            -
             | 
| 29 24 | 
             
            begin
         | 
| 30 25 | 
             
              require 'coveralls'
         | 
| 31 26 | 
             
              Coveralls.wear!
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: awesome_spawn
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.4.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Jason Frey
         | 
| @@ -11,62 +11,62 @@ authors: | |
| 11 11 | 
             
            autorequire: 
         | 
| 12 12 | 
             
            bindir: bin
         | 
| 13 13 | 
             
            cert_chain: []
         | 
| 14 | 
            -
            date:  | 
| 14 | 
            +
            date: 2016-01-26 00:00:00.000000000 Z
         | 
| 15 15 | 
             
            dependencies:
         | 
| 16 16 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 17 17 | 
             
              name: bundler
         | 
| 18 18 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 19 19 | 
             
                requirements:
         | 
| 20 | 
            -
                - - ~>
         | 
| 20 | 
            +
                - - "~>"
         | 
| 21 21 | 
             
                  - !ruby/object:Gem::Version
         | 
| 22 22 | 
             
                    version: '1.3'
         | 
| 23 23 | 
             
              type: :development
         | 
| 24 24 | 
             
              prerelease: false
         | 
| 25 25 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 26 26 | 
             
                requirements:
         | 
| 27 | 
            -
                - - ~>
         | 
| 27 | 
            +
                - - "~>"
         | 
| 28 28 | 
             
                  - !ruby/object:Gem::Version
         | 
| 29 29 | 
             
                    version: '1.3'
         | 
| 30 30 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 31 31 | 
             
              name: rake
         | 
| 32 32 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 33 33 | 
             
                requirements:
         | 
| 34 | 
            -
                - -  | 
| 34 | 
            +
                - - ">="
         | 
| 35 35 | 
             
                  - !ruby/object:Gem::Version
         | 
| 36 36 | 
             
                    version: '0'
         | 
| 37 37 | 
             
              type: :development
         | 
| 38 38 | 
             
              prerelease: false
         | 
| 39 39 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 40 40 | 
             
                requirements:
         | 
| 41 | 
            -
                - -  | 
| 41 | 
            +
                - - ">="
         | 
| 42 42 | 
             
                  - !ruby/object:Gem::Version
         | 
| 43 43 | 
             
                    version: '0'
         | 
| 44 44 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 45 45 | 
             
              name: rspec
         | 
| 46 46 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 47 47 | 
             
                requirements:
         | 
| 48 | 
            -
                - -  | 
| 48 | 
            +
                - - ">="
         | 
| 49 49 | 
             
                  - !ruby/object:Gem::Version
         | 
| 50 50 | 
             
                    version: '0'
         | 
| 51 51 | 
             
              type: :development
         | 
| 52 52 | 
             
              prerelease: false
         | 
| 53 53 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 54 54 | 
             
                requirements:
         | 
| 55 | 
            -
                - -  | 
| 55 | 
            +
                - - ">="
         | 
| 56 56 | 
             
                  - !ruby/object:Gem::Version
         | 
| 57 57 | 
             
                    version: '0'
         | 
| 58 58 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 59 59 | 
             
              name: coveralls
         | 
| 60 60 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 61 61 | 
             
                requirements:
         | 
| 62 | 
            -
                - -  | 
| 62 | 
            +
                - - ">="
         | 
| 63 63 | 
             
                  - !ruby/object:Gem::Version
         | 
| 64 64 | 
             
                    version: '0'
         | 
| 65 65 | 
             
              type: :development
         | 
| 66 66 | 
             
              prerelease: false
         | 
| 67 67 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 68 68 | 
             
                requirements:
         | 
| 69 | 
            -
                - -  | 
| 69 | 
            +
                - - ">="
         | 
| 70 70 | 
             
                  - !ruby/object:Gem::Version
         | 
| 71 71 | 
             
                    version: '0'
         | 
| 72 72 | 
             
            description: AwesomeSpawn is a module that provides some useful features over Ruby's
         | 
| @@ -80,23 +80,24 @@ executables: [] | |
| 80 80 | 
             
            extensions: []
         | 
| 81 81 | 
             
            extra_rdoc_files: []
         | 
| 82 82 | 
             
            files:
         | 
| 83 | 
            +
            - ".rspec"
         | 
| 84 | 
            +
            - ".yardopts"
         | 
| 85 | 
            +
            - LICENSE.txt
         | 
| 86 | 
            +
            - README.md
         | 
| 83 87 | 
             
            - lib/awesome_spawn.rb
         | 
| 84 88 | 
             
            - lib/awesome_spawn/command_line_builder.rb
         | 
| 85 89 | 
             
            - lib/awesome_spawn/command_result.rb
         | 
| 86 90 | 
             
            - lib/awesome_spawn/command_result_error.rb
         | 
| 87 91 | 
             
            - lib/awesome_spawn/no_such_file_error.rb
         | 
| 88 92 | 
             
            - lib/awesome_spawn/null_logger.rb
         | 
| 93 | 
            +
            - lib/awesome_spawn/spec_helper.rb
         | 
| 89 94 | 
             
            - lib/awesome_spawn/version.rb
         | 
| 90 | 
            -
            - .yardopts
         | 
| 91 | 
            -
            - README.md
         | 
| 92 | 
            -
            - LICENSE.txt
         | 
| 93 95 | 
             
            - spec/awesome_spawn_spec.rb
         | 
| 94 96 | 
             
            - spec/command_line_builder_spec.rb
         | 
| 95 97 | 
             
            - spec/command_result_error_spec.rb
         | 
| 96 98 | 
             
            - spec/command_result_spec.rb
         | 
| 97 99 | 
             
            - spec/no_such_file_error_spec.rb
         | 
| 98 100 | 
             
            - spec/spec_helper.rb
         | 
| 99 | 
            -
            - .rspec
         | 
| 100 101 | 
             
            homepage: https://github.com/ManageIQ/awesome_spawn
         | 
| 101 102 | 
             
            licenses:
         | 
| 102 103 | 
             
            - MIT
         | 
| @@ -107,17 +108,17 @@ require_paths: | |
| 107 108 | 
             
            - lib
         | 
| 108 109 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 109 110 | 
             
              requirements:
         | 
| 110 | 
            -
              - -  | 
| 111 | 
            +
              - - ">="
         | 
| 111 112 | 
             
                - !ruby/object:Gem::Version
         | 
| 112 113 | 
             
                  version: '0'
         | 
| 113 114 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 114 115 | 
             
              requirements:
         | 
| 115 | 
            -
              - -  | 
| 116 | 
            +
              - - ">="
         | 
| 116 117 | 
             
                - !ruby/object:Gem::Version
         | 
| 117 118 | 
             
                  version: '0'
         | 
| 118 119 | 
             
            requirements: []
         | 
| 119 120 | 
             
            rubyforge_project: 
         | 
| 120 | 
            -
            rubygems_version: 2. | 
| 121 | 
            +
            rubygems_version: 2.4.5.1
         | 
| 121 122 | 
             
            signing_key: 
         | 
| 122 123 | 
             
            specification_version: 4
         | 
| 123 124 | 
             
            summary: AwesomeSpawn is a module that provides some useful features over Ruby's Kernel.spawn.
         | 
| @@ -128,4 +129,4 @@ test_files: | |
| 128 129 | 
             
            - spec/command_result_spec.rb
         | 
| 129 130 | 
             
            - spec/no_such_file_error_spec.rb
         | 
| 130 131 | 
             
            - spec/spec_helper.rb
         | 
| 131 | 
            -
            - .rspec
         | 
| 132 | 
            +
            - ".rspec"
         |