evrone-common-spawn 0.0.1

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: e1b7c8972a1a7909719acde920d17104b4e6d382
4
+ data.tar.gz: aed3543ae957e4b8ef85a8417237d1684e659086
5
+ SHA512:
6
+ metadata.gz: fe6a1c24b8657dfc8527c1f8d76558ee2f540675b433c7a483f0d3bfde6aa74bef00d6b0e50a1cc4e9aae61dce6b6fa41b42ab2cf425a182aa56b26fa6412c30
7
+ data.tar.gz: 661353e09d8e41de56e4ad0d88358ef80306be4f3dba615d9f3ebaa9881c5aff0a4bbf17344b00fae1c65bbaa35f05287e02c9ce2922cfe43ba78d9ce362f992
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --order=rand
3
+ -fd
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
4
+ before_install:
5
+ - echo 'travis:travis' | sudo chpasswd
6
+ - echo 'PasswordAuthentication yes' | sudo tee -a /etc/ssh/sshd_config
7
+ - sudo service ssh restart
8
+ before_script:
9
+ - export SSH_USER=travis
10
+ - export SSH_PASS=travis
11
+ - export SSH_HOST=localhost
12
+ script: bundle exec rake SPEC_OPTS='-fd --color --order=rand'
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in evrone-common-spawn.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Dmitry Galinsky
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # Evrone::Common::Spawn
2
+
3
+ This gem helps to spawn system, ssh processes, capturing output in realtime,
4
+ allow to set temeouts and read timeouts.
5
+
6
+ * [![Build Status](https://travis-ci.org/evrone/evrone-common-spawn.png)](https://travis-ci.org/evrone/evrone-common-spawn)
7
+ * [![Code Climate](https://codeclimate.com/github/evrone/evrone-common-spawn.png)](https://codeclimate.com/github/evrone/evrone-common-spawn)
8
+
9
+ ## Requirements
10
+
11
+ MRI 1.9.3 or 2.0.0.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ gem 'evrone-common-spawn'
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install evrone-common-spawn
26
+
27
+ ## Quick Start
28
+
29
+ Below is a small snippet that demonstrates how to use
30
+
31
+ ```ruby
32
+ # Spawn system processes example
33
+
34
+ include Evrone::Common::Spawn
35
+
36
+ spawn "ls -la" do |output|
37
+ print output
38
+ # prints directory listing
39
+ end
40
+
41
+ spawn({'ENV_VAR' => 'VALUE'}, "echo $VALUE", timeout: 10) do |output|
42
+ print output
43
+ # its print "VALUE\n"
44
+ end
45
+ ```
46
+
47
+
48
+ ```ruby
49
+ # Spawn remote processes example
50
+
51
+ open_ssh('localhost', 'user') do |ssh|
52
+ ssh.spawn("ls -la") do |output|
53
+ print output
54
+ # prints directory listing
55
+ end
56
+
57
+ spawn({'ENV_VAR' => 'VALUE'}, "echo $VALUE", read_timeout: 10) do |output|
58
+ print output
59
+ # its print "VALUE\n"
60
+ end
61
+ end
62
+
63
+ ```
64
+
65
+ ### Timeouts
66
+
67
+ When timeout happened, spawn raises ```Evrone::Common::Spawn::TimeoutError``` or
68
+ ```Evrone::Common::Spawn::ReadTimeoutError```, both exception classes inherited
69
+ from Timeout::Error
70
+
71
+ ### Return values
72
+
73
+ Both ```spawn``` methods return process exit code, if process was killed by signal, for example
74
+ KILL or INT, return negative signal number (for KILL was -9)
75
+
76
+ ## Contributing
77
+
78
+ 1. Fork it
79
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
80
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
81
+ 4. Push to the branch (`git push origin my-new-feature`)
82
+ 5. Create new Pull Request
83
+
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'evrone/common/spawn/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "evrone-common-spawn"
8
+ spec.version = Evrone::Common::Spawn::VERSION
9
+ spec.authors = ["Dmitry Galinsky"]
10
+ spec.email = ["dima.exe@gmail.com"]
11
+ spec.description = %q{ Spawn system, ssh processes, capturing output in realtime,
12
+ allow to set temeouts and read timeouts }
13
+ spec.summary = %q{ This gem helps to spawn system, ssh processes, capturing output in realtime,
14
+ allow to set temeouts and read timeouts }
15
+ spec.homepage = "https://github.com/evrone/evrone-common-spawn"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_runtime_dependency "net-ssh", "~> 2.6"
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "pry"
28
+ end
@@ -0,0 +1,34 @@
1
+ require 'timeout'
2
+
3
+ module Evrone
4
+ module Common
5
+ module Spawn
6
+
7
+ class TimeoutError < ::Timeout::Error
8
+
9
+ def initialize(cmd, seconds)
10
+ @cmd = cmd
11
+ @seconds = seconds
12
+ end
13
+
14
+ def to_s
15
+ "Execution of '#{@cmd}' expired"
16
+ end
17
+
18
+ end
19
+
20
+ class ReadTimeoutError < ::Timeout::Error
21
+
22
+ def initialize(cmd, seconds)
23
+ @cmd = cmd
24
+ @seconds = seconds
25
+ end
26
+
27
+ def to_s
28
+ "No output has been received of '#{@cmd}' in the last #{@seconds} seconds"
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,69 @@
1
+ require 'timeout'
2
+
3
+ module Evrone
4
+ module Common
5
+ module Spawn
6
+ module Process
7
+
8
+ extend self
9
+
10
+ def spawn(*args, &block)
11
+ env = args.first.is_a?(Hash) ? args.shift : {}
12
+ options = args.last.is_a?(Hash) ? args.pop : {}
13
+ cmd = args.join(" ")
14
+
15
+ select_timeout = options.delete(:pool_interval) || Spawn.pool_interval
16
+ timeout = Spawn::Timeout.new options.delete(:timeout)
17
+ read_timeout = Spawn::ReadTimeout.new options.delete(:read_timeout)
18
+
19
+ r,w = IO.pipe
20
+ r.sync = true
21
+
22
+ pid = ::Process.spawn(env, cmd, options.merge(out: w, err: w))
23
+ w.close
24
+
25
+ read_loop r, timeout, read_timeout, select_timeout, &block
26
+
27
+ ::Process.kill 'KILL', pid
28
+ _, status = ::Process.wait2(pid) # protect from zombies
29
+
30
+ compute_exit_code cmd, status, timeout, read_timeout
31
+ end
32
+
33
+ private
34
+
35
+ def compute_exit_code(command, status, timeout, read_timeout)
36
+ case
37
+ when read_timeout.happened?
38
+ raise Spawn::ReadTimeoutError.new command, read_timeout.value
39
+ when timeout.happened?
40
+ raise Spawn::TimeoutError.new command, timeout.value
41
+ else
42
+ termsig = status.termsig
43
+ exit_code = status.exitstatus
44
+ exit_code || (termsig && termsig * -1) || -1
45
+ end
46
+ end
47
+
48
+ def read_loop(reader, timeout, read_timeout, interval, &block)
49
+ read_timeout.reset
50
+
51
+ loop do
52
+ break if timeout.happened?
53
+
54
+ rs, _, _ = IO.select([reader], nil, nil, interval)
55
+
56
+ if rs
57
+ break if rs[0].eof?
58
+ yield rs[0].readpartial(8192)
59
+ read_timeout.reset
60
+ else
61
+ break if read_timeout.happened?
62
+ end
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,29 @@
1
+ module Evrone
2
+ module Common
3
+ module Spawn
4
+ class ReadTimeout
5
+
6
+ def initialize(val)
7
+ @value = val.to_f > 0 ? val.to_f : nil
8
+ @happened = false
9
+ end
10
+
11
+ def reset
12
+ @tm = Time.new if @value
13
+ end
14
+
15
+ def happened?
16
+ return true if @happened
17
+ return false unless @tm
18
+
19
+ @happened = Time.now > (@tm + @value)
20
+ end
21
+
22
+ def value
23
+ @value
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,103 @@
1
+ require 'net/ssh'
2
+ require 'timeout'
3
+
4
+ module Evrone
5
+ module Common
6
+ module Spawn
7
+ class SSH
8
+
9
+ class << self
10
+ def open(host, user, options = {}, &block)
11
+ ::Net::SSH.start(host, user, {
12
+ forward_agent: true,
13
+ paranoid: false
14
+ }.merge(options)) do |ssh|
15
+ yield new(ssh)
16
+ end
17
+ end
18
+ end
19
+
20
+ attr_reader :host, :user, :options
21
+
22
+ def initialize(ssh)
23
+ @ssh = ssh
24
+ end
25
+
26
+ def spawn(*args, &block)
27
+ env = args.first.is_a?(Hash) ? args.shift : {}
28
+ options = args.last.is_a?(Hash) ? args.pop : {}
29
+ command = args.join(" ")
30
+
31
+ exit_code = nil
32
+ timeout = Spawn::Timeout.new options.delete(:timeout)
33
+ read_timeout = Spawn::ReadTimeout.new options.delete(:read_timeout)
34
+
35
+ channel = spawn_channel env, command, read_timeout, &block
36
+
37
+ channel.on_request("exit-status") do |_,data|
38
+ exit_code = data.read_long
39
+ end
40
+
41
+ pool channel, timeout, read_timeout
42
+
43
+ compute_exit_code command, exit_code, timeout, read_timeout
44
+ end
45
+
46
+ private
47
+
48
+ def pool(channel, timeout, read_timeout)
49
+ @ssh.loop Spawn.pool_interval do
50
+ if read_timeout.happened? || timeout.happened?
51
+ false
52
+ else
53
+ channel.active?
54
+ end
55
+ end
56
+ end
57
+
58
+ def compute_exit_code(command, exit_code, timeout, read_timeout)
59
+ case
60
+ when read_timeout.happened?
61
+ raise Spawn::ReadTimeoutError.new command, read_timeout.value
62
+ when timeout.happened?
63
+ raise Spawn::TimeoutError.new command, timeout.value
64
+ else
65
+ exit_code || -1 # nil exit_code means that the process is killed
66
+ end
67
+ end
68
+
69
+ def spawn_channel(env, command, read_timeout, &block)
70
+
71
+ @ssh.open_channel do |channel|
72
+ read_timeout.reset
73
+
74
+ env.each do |k, v|
75
+ channel.env k, v do |_, success|
76
+ yield "FAILED: couldn't execute command (ssh.channel.env)\n" if block_given?
77
+ end
78
+ end
79
+
80
+ channel.exec command do |_, success|
81
+
82
+ unless success
83
+ yield "FAILED: couldn't execute command (ssh.channel.exec)\n" if block_given?
84
+ end
85
+
86
+ channel.on_data do |_, data|
87
+ yield data if block_given?
88
+ read_timeout.reset
89
+ end
90
+
91
+ channel.on_extended_data do |_, _, data|
92
+ yield data if block_given?
93
+ read_timeout.reset
94
+ end
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,26 @@
1
+ module Evrone
2
+ module Common
3
+ module Spawn
4
+ class Timeout
5
+ def initialize(value)
6
+ @value = (value.to_f > 0) ? value.to_f : nil
7
+ if @value
8
+ @time_end = Time.now + @value
9
+ end
10
+ @happened = false
11
+ end
12
+
13
+ def happened?
14
+ return false unless value
15
+ return true if @happened
16
+
17
+ @happened = Time.now > @time_end
18
+ end
19
+
20
+ def value
21
+ @value
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ module Evrone
2
+ module Common
3
+ module Spawn
4
+ VERSION = "0.0.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path("../spawn/version", __FILE__)
2
+
3
+ module Evrone
4
+ module Common
5
+ module Spawn
6
+
7
+ autoload :Process, File.expand_path("../spawn/process", __FILE__)
8
+ autoload :SSH, File.expand_path("../spawn/ssh", __FILE__)
9
+ autoload :Timeout, File.expand_path("../spawn/timeout", __FILE__)
10
+ autoload :ReadTimeout, File.expand_path("../spawn/read_timeout", __FILE__)
11
+ autoload :TimeoutError, File.expand_path("../spawn/error", __FILE__)
12
+ autoload :ReadTimeoutError, File.expand_path("../spawn/error", __FILE__)
13
+
14
+ class << self
15
+ @@pool_interval = 0.1
16
+
17
+ def pool_interval
18
+ @@pool_interval
19
+ end
20
+
21
+ def pool_interval=(val)
22
+ @@pool_interval = val
23
+ end
24
+ end
25
+
26
+ def open_ssh(*args, &block)
27
+ Common::Spawn::SSH.open(*args, &block)
28
+ end
29
+
30
+ def spawn(*args, &block)
31
+ Common::Spawn::Process.spawn(*args, &block)
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+ require 'timeout'
3
+
4
+ describe Evrone::Common::Spawn::Process do
5
+ let(:collected) { "" }
6
+ let(:user) { ENV['USER'] }
7
+
8
+ subject { collected }
9
+
10
+ it "run command successfuly" do
11
+ code = run "echo $USER"
12
+ expect(subject).to eq "#{user}\n"
13
+ expect(code).to eq 0
14
+ end
15
+
16
+ it "run command with error" do
17
+ code = run( "false")
18
+ expect(subject).to eq ""
19
+ expect(code).to eq 1
20
+ end
21
+
22
+ it "run command with env successfuly" do
23
+ code = run( {'FOO' => "BAR" }, "echo $FOO")
24
+ expect(subject).to eq "BAR\n"
25
+ expect(code).to eq 0
26
+ end
27
+
28
+ context "timeout" do
29
+ it 'run command with timeout' do
30
+ expect {
31
+ run("echo $USER && sleep 0.5", timeout: 0.2)
32
+ }.to raise_error(Evrone::Common::Spawn::TimeoutError)
33
+ expect(subject).to eq "#{user}\n"
34
+ end
35
+
36
+ it 'run command with timeout successfuly' do
37
+ code = run( {'FOO' => "BAR" }, "echo $FOO && sleep 0.1", timeout: 0.5)
38
+ expect(subject).to eq "BAR\n"
39
+ expect(code).to eq 0
40
+ end
41
+ end
42
+
43
+ context "read_timeout" do
44
+ it 'run command with read timeout' do
45
+ expect{
46
+ run('sleep 0.5', read_timeout: 0.2)
47
+ }.to raise_error(Evrone::Common::Spawn::ReadTimeoutError)
48
+ expect(collected).to eq ""
49
+ end
50
+
51
+ it 'run command with read timeout in loop' do
52
+ expect{
53
+ run('sleep 0.1 ; echo $USER ; sleep 0.5', read_timeout: 0.3)
54
+ }.to raise_error(Evrone::Common::Spawn::ReadTimeoutError)
55
+ expect(collected).to eq "#{user}\n"
56
+ end
57
+
58
+ it 'run command with read timeout successfuly' do
59
+ code = run('echo $USER; sleep 0.1', read_timeout: 0.5)
60
+ expect(collected).to eq "#{user}\n"
61
+ expect(code).to eq 0
62
+ end
63
+
64
+ it 'run command with read timeout in loop successfuly' do
65
+ code = run('sleep 0.3 ; echo $USER; sleep 0.3 ; echo $USER', read_timeout: 0.5)
66
+ expect(collected).to eq "#{user}\n#{user}\n"
67
+ expect(code).to eq 0
68
+ end
69
+ end
70
+
71
+ it 'run and kill process' do
72
+ code = run( "echo $USER; kill -KILL $$")
73
+ expect(subject).to eq "#{user}\n"
74
+ expect(code).to eq(-9)
75
+ end
76
+
77
+ it 'run and interupt process' do
78
+ code = run( "echo $USER; kill -INT $$")
79
+ expect(subject).to eq "#{user}\n"
80
+ expect(code).to eq(-2)
81
+ end
82
+
83
+ def run(*args, &block)
84
+ timeout do
85
+ described_class.spawn(*args) do |out|
86
+ collected << out
87
+ end
88
+ end
89
+ end
90
+
91
+ def timeout
92
+ Timeout.timeout(10) do
93
+ yield
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::Common::Spawn::ReadTimeout do
4
+ subject { described_class.new 0.2 }
5
+
6
+ context "just created" do
7
+ its(:value) { should eq 0.2 }
8
+ its(:happened?) { should be_false }
9
+ end
10
+
11
+ it "should be work" do
12
+ subject.reset
13
+ sleep 0.1
14
+ expect(subject.happened?).to be_false
15
+
16
+ subject.reset
17
+ sleep 0.3
18
+ expect(subject.happened?).to be_true
19
+ end
20
+
21
+ it "do nothing unless value" do
22
+ expect(subject.happened?).to be_false
23
+ end
24
+
25
+ it "do nothing unless timeout" do
26
+ subject.reset
27
+ sleep 0.1
28
+ expect(subject.happened?).to be_false
29
+ end
30
+ end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+ require 'timeout'
3
+
4
+ describe Evrone::Common::Spawn::SSH, ssh: true do
5
+
6
+ let(:user) { ENV['SSH_USER'] }
7
+ let(:host) { ENV['SSH_HOST'] }
8
+ let(:pass) { ENV['SSH_PASS'] }
9
+ let(:collected) { '' }
10
+
11
+ it "run command successfuly" do
12
+ code = run_ssh 'echo $USER'
13
+ expect(collected).to eq "#{user}\n"
14
+ expect(code).to eq 0
15
+ end
16
+
17
+ it "run command with error" do
18
+ code = run_ssh 'false'
19
+ expect(collected).to eq ""
20
+ expect(code).to eq 1
21
+ end
22
+
23
+ it "run command with env successfuly" do
24
+ code = run_ssh({'FOO' => "BAR"}, 'echo $FOO')
25
+ expect(collected).to match(re "FAILED: couldn't execute command (ssh.channel.env)")
26
+ expect(code).to eq 0
27
+ end
28
+
29
+ context "timeout" do
30
+ it 'run command with timeout' do
31
+ expect{
32
+ run_ssh('echo $USER; sleep 0.5', timeout: 0.2)
33
+ }.to raise_error(Evrone::Common::Spawn::TimeoutError)
34
+ end
35
+
36
+ it 'run command with timeout successfuly' do
37
+ code = run_ssh('echo $USER; sleep 0.2', timeout: 0.5)
38
+ expect(collected).to eq "#{user}\n"
39
+ expect(code).to eq 0
40
+ end
41
+ end
42
+
43
+ context "read_timeout" do
44
+ it 'run command with read timeout' do
45
+ expect{
46
+ run_ssh('sleep 0.5', read_timeout: 0.2)
47
+ }.to raise_error(Evrone::Common::Spawn::ReadTimeoutError)
48
+ expect(collected).to eq ""
49
+ end
50
+
51
+ it 'run command with read timeout in loop' do
52
+ expect{
53
+ run_ssh('sleep 0.1 ; echo $USER ; sleep 0.5', read_timeout: 0.3)
54
+ }.to raise_error(Evrone::Common::Spawn::ReadTimeoutError)
55
+ expect(collected).to eq "#{user}\n"
56
+ end
57
+
58
+ it 'run command with read timeout successfuly' do
59
+ code = run_ssh('echo $USER; sleep 0.1', read_timeout: 0.5)
60
+ expect(collected).to eq "#{user}\n"
61
+ expect(code).to eq 0
62
+ end
63
+
64
+ it 'run command with read timeout in loop successfuly' do
65
+ code = run_ssh('sleep 0.3 ; echo $USER; sleep 0.3 ; echo $USER', read_timeout: 0.5)
66
+ expect(collected).to eq "#{user}\n#{user}\n"
67
+ expect(code).to eq 0
68
+ end
69
+ end
70
+
71
+ it 'run and kill process' do
72
+ code = run_ssh("echo $USER; kill -9 $$")
73
+ expect(collected).to eq "#{user}\n"
74
+ expect(code).to eq(-1)
75
+ end
76
+
77
+ it 'run and interupt process' do
78
+ code = run_ssh("echo $USER; kill -9 $$")
79
+ expect(collected).to eq "#{user}\n"
80
+ expect(code).to eq(-1)
81
+ end
82
+
83
+ def open_ssh(&block)
84
+ described_class.open(host, user, password: pass, verbose: 2, &block)
85
+ end
86
+
87
+ def re(s)
88
+ Regexp.escape s
89
+ end
90
+
91
+ def run_ssh(*args)
92
+ timeout do
93
+ open_ssh do |ssh|
94
+ ssh.spawn(*args) do |s|
95
+ collected << s
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ def timeout
102
+ Timeout.timeout(10) do
103
+ yield
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::Common::Spawn do
4
+
5
+ subject { Object.new }
6
+
7
+ before { subject.extend described_class }
8
+
9
+ context "spawn" do
10
+ it "should be" do
11
+ expect(subject.spawn 'true').to eq 0
12
+ end
13
+ end
14
+
15
+ context "open_ssh" do
16
+ let(:ssh) { nil }
17
+ it "should be" do
18
+ subject.open_ssh(ENV['SSH_HOST'], ENV['SSH_USER'], password: ENV['SSH_PASS']) do |ssh|
19
+ expect(ssh.spawn 'true').to eq 0
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,6 @@
1
+ require 'rspec/autorun'
2
+ require File.expand_path('../../lib/evrone-common-spawn', __FILE__)
3
+
4
+ RSpec.configure do |c|
5
+ end
6
+
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: evrone-common-spawn
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dmitry Galinsky
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net-ssh
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: " Spawn system, ssh processes, capturing output in realtime,\nallow to
84
+ set temeouts and read timeouts "
85
+ email:
86
+ - dima.exe@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - .rspec
93
+ - .travis.yml
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - evrone-common-spawn.gemspec
99
+ - lib/evrone/common/spawn.rb
100
+ - lib/evrone/common/spawn/error.rb
101
+ - lib/evrone/common/spawn/process.rb
102
+ - lib/evrone/common/spawn/read_timeout.rb
103
+ - lib/evrone/common/spawn/ssh.rb
104
+ - lib/evrone/common/spawn/timeout.rb
105
+ - lib/evrone/common/spawn/version.rb
106
+ - spec/lib/spawn/process_spec.rb
107
+ - spec/lib/spawn/read_timeout_spec.rb
108
+ - spec/lib/spawn/ssh_spec.rb
109
+ - spec/lib/spawn_spec.rb
110
+ - spec/spec_helper.rb
111
+ homepage: https://github.com/evrone/evrone-common-spawn
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.0.2
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: This gem helps to spawn system, ssh processes, capturing output in realtime,
135
+ allow to set temeouts and read timeouts
136
+ test_files:
137
+ - spec/lib/spawn/process_spec.rb
138
+ - spec/lib/spawn/read_timeout_spec.rb
139
+ - spec/lib/spawn/ssh_spec.rb
140
+ - spec/lib/spawn_spec.rb
141
+ - spec/spec_helper.rb