here_or_there 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/here_or_there/local.rb +14 -0
- data/lib/here_or_there/remote.rb +71 -0
- data/lib/here_or_there/response.rb +29 -0
- data/lib/here_or_there/version.rb +3 -0
- data/lib/here_or_there.rb +21 -0
- data/spec/here_or_there/local_spec.rb +41 -0
- data/spec/here_or_there/remote_spec.rb +116 -0
- data/spec/here_or_there/response_spec.rb +57 -0
- data/spec/here_or_there_spec.rb +29 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/support/capture.rb +59 -0
- data/spec/support/stubbed_session.rb +17 -0
- metadata +78 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 028df86fad5122406b9777794a31fd0b3618ad5d
|
4
|
+
data.tar.gz: 8b492ae31ae4df58236da68b478e99ece562e4a3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fcaeba290157c9d4b63fc0058849b4b9a2d9939aa5f04e51fbc1be8d97db6c8d55f145e5ddd842838f7bd17e19280ee0b46ae1a7a6b9b6bae653c4d498e5d6ad
|
7
|
+
data.tar.gz: 02b3273e0e0e7bab4eedee8af30d2b917c75a5b185d2662993d13bebba5e42c3afb65a6bf93087693a946cd4f2dc17e8ad4f8e37805e18839750914d94f5d5ac
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module HereOrThere
|
2
|
+
module Remote
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def session options={}
|
6
|
+
sessions.fetch(options) { add_session(options) }
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def sessions
|
12
|
+
@_sessions ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_session options
|
16
|
+
sessions[options] = SSH.new( options )
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class SSH
|
22
|
+
attr_reader :hostname, :user, :options
|
23
|
+
attr_reader :session
|
24
|
+
|
25
|
+
def initialize options
|
26
|
+
@options = options.dup
|
27
|
+
@hostname = @options.delete(:hostname)
|
28
|
+
@user = @options.delete(:user)
|
29
|
+
end
|
30
|
+
|
31
|
+
def run command
|
32
|
+
stdout, stderr, status = [ '', '', false ]
|
33
|
+
|
34
|
+
open_session
|
35
|
+
|
36
|
+
session.exec! command do |channel, response_type, response_data|
|
37
|
+
|
38
|
+
if response_type == :stdout
|
39
|
+
stdout = response_data
|
40
|
+
status = true
|
41
|
+
else
|
42
|
+
stderr = response_data
|
43
|
+
end
|
44
|
+
|
45
|
+
return Response.new( stdout, stderr, status )
|
46
|
+
end
|
47
|
+
|
48
|
+
# catch that odd state where no data is returned
|
49
|
+
# but the execution is successful
|
50
|
+
return Response.new( '', '', true )
|
51
|
+
|
52
|
+
rescue Net::SSH::AuthenticationFailed
|
53
|
+
close_session
|
54
|
+
return Response.new( '', 'Authentication failed when connecting to remote', false )
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def open_session
|
60
|
+
unless session && !session.closed?
|
61
|
+
@session = Net::SSH.start hostname, user, options
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def close_session
|
66
|
+
session.close unless !session || session.closed?
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module HereOrThere
|
2
|
+
class Response
|
3
|
+
attr_reader :stdout, :stderr, :status
|
4
|
+
|
5
|
+
def initialize stdout, stderr, status
|
6
|
+
@stdout = stdout
|
7
|
+
@stderr = stderr
|
8
|
+
@status = status
|
9
|
+
end
|
10
|
+
|
11
|
+
def [] key
|
12
|
+
case key
|
13
|
+
when 0 then stdout
|
14
|
+
when 1 then stderr
|
15
|
+
when 2 then status
|
16
|
+
else
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def success?
|
22
|
+
if status.respond_to? :success?
|
23
|
+
status.success?
|
24
|
+
else
|
25
|
+
status
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# util
|
2
|
+
require 'open3'
|
3
|
+
require 'net/ssh'
|
4
|
+
|
5
|
+
# gem
|
6
|
+
require 'here_or_there/version'
|
7
|
+
require 'here_or_there/response'
|
8
|
+
require 'here_or_there/local'
|
9
|
+
require 'here_or_there/remote'
|
10
|
+
|
11
|
+
module HereOrThere
|
12
|
+
|
13
|
+
def run_local command
|
14
|
+
Local.new.run command
|
15
|
+
end
|
16
|
+
|
17
|
+
def run_remote command, options={}
|
18
|
+
Remote.session( options ).run( command )
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HereOrThere::Local do
|
4
|
+
context "when not given a block" do
|
5
|
+
|
6
|
+
it "returns a Response instance" do
|
7
|
+
ret = HereOrThere::Local.new.run( 'spec/fixtures/hello_stdout')
|
8
|
+
expect( ret.is_a? HereOrThere::Response ).to be_true
|
9
|
+
end
|
10
|
+
it "returns stdout as return.stdout" do
|
11
|
+
ret = HereOrThere::Local.new.run( 'spec/fixtures/hello_stdout' )
|
12
|
+
expect( ret.stdout ).to eq "Hello Stdout\n"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns stderr as return.stderr" do
|
16
|
+
ret = HereOrThere::Local.new.run( 'spec/fixtures/hello_stderr' )
|
17
|
+
expect( ret.stderr ).to eq "Hello Stderr\n"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns a successful status for a successful command" do
|
21
|
+
ret_succ = HereOrThere::Local.new.run( 'spec/fixtures/hello_stdout' )
|
22
|
+
expect( ret_succ.success? ).to be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns an unsuccessful status for an unsuccessful command" do
|
26
|
+
ret_err = HereOrThere::Local.new.run( 'spec/fixtures/hello_stderr' )
|
27
|
+
expect( ret_err.success? ).to be_false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when given a block" do
|
32
|
+
it "yields Response" do
|
33
|
+
ret = ""
|
34
|
+
HereOrThere::Local.new.run( 'spec/fixtures/hello_stdout' ) do |response|
|
35
|
+
ret = response
|
36
|
+
end
|
37
|
+
|
38
|
+
expect( ret.class ).to eq HereOrThere::Response
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HereOrThere::Remote do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
Net::SSH.stub( start: StubbedSession.new )
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "::session" do
|
10
|
+
|
11
|
+
before :each do
|
12
|
+
if HereOrThere::Remote.send(:instance_variable_defined?, :@_sessions)
|
13
|
+
HereOrThere::Remote.send(:remove_instance_variable, :@_sessions)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "creates an SSH object" do
|
18
|
+
expect(
|
19
|
+
HereOrThere::Remote.session( hostname: 'foo', user: 'bar' ).is_a?(HereOrThere::Remote::SSH)
|
20
|
+
).to be_true
|
21
|
+
end
|
22
|
+
|
23
|
+
it "doesn't recreate an instance" do
|
24
|
+
first_instance = HereOrThere::Remote.session( hostname: 'foo', user: 'bar' )
|
25
|
+
expect( HereOrThere::Remote.session( hostname: 'foo', user: 'bar' ) ).to eq first_instance
|
26
|
+
end
|
27
|
+
|
28
|
+
it "creates a new instance for uniq options" do
|
29
|
+
first_instance = HereOrThere::Remote.session( hostname: 'foo', user: 'bar' )
|
30
|
+
expect( HereOrThere::Remote.session( hostname: 'wu', user: 'tang' ) ).not_to eq first_instance
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
describe HereOrThere::Remote::SSH do
|
36
|
+
|
37
|
+
before :each do
|
38
|
+
@ssh = HereOrThere::Remote::SSH.new( hostname: 'foo', user: 'bar' )
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#run" do
|
42
|
+
it "returns a response object" do
|
43
|
+
expect( @ssh.run("foo").is_a? HereOrThere::Response ).to be_true
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when response is stdout" do
|
47
|
+
|
48
|
+
before :each do
|
49
|
+
StubbedSession.any_instance.stub(:exec!).and_yield("foo", :stdout, "hello stdout")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "assigns response_data to Response.stdout" do
|
53
|
+
expect( @ssh.run("foo").stdout ).to eq "hello stdout"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "responds with a successful response object" do
|
57
|
+
expect( @ssh.run("foo") ).to be_success
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when response is stderr" do
|
63
|
+
|
64
|
+
before :each do
|
65
|
+
StubbedSession.any_instance.stub(:exec!).and_yield("foo", :stderr, "hello stderr")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "assigns response_data to Response.stderr" do
|
69
|
+
expect( @ssh.run("foo").stderr ).to eq "hello stderr"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "responds with an unsuccessful response object" do
|
73
|
+
expect( @ssh.run("foo") ).not_to be_success
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when the block isn't called" do
|
79
|
+
# this happens when there is an empty response
|
80
|
+
# and no error from the remote
|
81
|
+
|
82
|
+
before :each do
|
83
|
+
StubbedSession.any_instance.stub(:exec!).and_return(nil)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns an empty successful response" do
|
87
|
+
resp = @ssh.run('foo')
|
88
|
+
|
89
|
+
expect( resp ).to be_success
|
90
|
+
expect( resp.stdout ).to eq ''
|
91
|
+
expect( resp.stderr ).to eq ''
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "when raises Net::SSH::AuthenticationFailed" do
|
96
|
+
|
97
|
+
before :each do
|
98
|
+
StubbedSession.any_instance.stub(:exec!).and_raise(Net::SSH::AuthenticationFailed)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "returns an unsucessful response with err as stderr" do
|
102
|
+
resp = @ssh.run("foo")
|
103
|
+
expect( resp ).not_to be_success
|
104
|
+
expect( resp.stderr ).to eq "Authentication failed when connecting to remote"
|
105
|
+
end
|
106
|
+
|
107
|
+
it "closes the session" do
|
108
|
+
this_session = @ssh.session
|
109
|
+
@ssh.run("foo")
|
110
|
+
expect( @ssh.session ).not_to eq this_session
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HereOrThere::Response do
|
4
|
+
let(:response) { HereOrThere::Response.new( 'stdout', 'stderr', 'status' ) }
|
5
|
+
|
6
|
+
describe "#stdout" do
|
7
|
+
it "returns the stdout value" do
|
8
|
+
expect( response.stdout ).to eq 'stdout'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#stderr" do
|
13
|
+
it "returns the stderr value" do
|
14
|
+
expect( response.stderr ).to eq 'stderr'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#status" do
|
19
|
+
it "returns the status value" do
|
20
|
+
expect( response.status ).to eq 'status'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#[]" do
|
25
|
+
it "returns stdout for [0]" do
|
26
|
+
expect( response[0] ).to eq 'stdout'
|
27
|
+
end
|
28
|
+
it "returns stderr for [1]" do
|
29
|
+
expect( response[1] ).to eq 'stderr'
|
30
|
+
end
|
31
|
+
it "returns status for [2]" do
|
32
|
+
expect( response[2] ).to eq 'status'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#success?" do
|
37
|
+
context "when status responds to success? (an open3 response)" do
|
38
|
+
it "is truthy when process is success" do
|
39
|
+
ret_succ = HereOrThere::Local.new.run( 'spec/fixtures/hello_stdout' )
|
40
|
+
expect( ret_succ ).to be_success
|
41
|
+
end
|
42
|
+
it "is falsy when status returns err" do
|
43
|
+
ret_err = HereOrThere::Local.new.run( 'spec/fixtures/hello_stderr' )
|
44
|
+
expect( ret_err ).not_to be_success
|
45
|
+
end
|
46
|
+
end
|
47
|
+
context "when status is a boolean (a ssh response)" do
|
48
|
+
it "is truthy when status is true" do
|
49
|
+
expect( HereOrThere::Response.new( 'stdout', 'stderr', true ) ).to be_success
|
50
|
+
end
|
51
|
+
it "is falsy when status is false" do
|
52
|
+
expect( HereOrThere::Response.new( 'stdout', 'stderr', false ) ).not_to be_success
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HereOrThere do
|
4
|
+
include HereOrThere
|
5
|
+
|
6
|
+
describe "#run_local" do
|
7
|
+
it "passes the command to a Local instance" do
|
8
|
+
HereOrThere::Local.any_instance.should_receive(:run).with("foo")
|
9
|
+
|
10
|
+
run_local('foo')
|
11
|
+
end
|
12
|
+
it "returns a response object" do
|
13
|
+
expect( run_local('spec/fixtures/hello_stdout').is_a? HereOrThere::Response ).to be_true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#run_remote" do
|
18
|
+
it "passes the command to a SSH instance" do
|
19
|
+
HereOrThere::Remote::SSH.any_instance.should_receive(:run).with('ls')
|
20
|
+
|
21
|
+
run_remote( 'ls', hostname: 'foo', user: 'bar' )
|
22
|
+
end
|
23
|
+
it "returns a response object" do
|
24
|
+
HereOrThere::Remote::SSH.any_instance.stub( session: StubbedSession.new )
|
25
|
+
expect( run_remote( 'ls', hostname: 'foo', user: 'bar').is_a? HereOrThere::Response ).to be_true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# utils
|
2
|
+
# nice to have for debugging -- uncomment in gemfile to use
|
3
|
+
# require 'pry'
|
4
|
+
# require 'byebug'
|
5
|
+
|
6
|
+
# rspec support
|
7
|
+
require 'support/capture'
|
8
|
+
require 'support/stubbed_session'
|
9
|
+
|
10
|
+
# library
|
11
|
+
require 'here_or_there'
|
12
|
+
|
13
|
+
describe "support" do
|
14
|
+
|
15
|
+
describe Capture do
|
16
|
+
describe "#stdout" do
|
17
|
+
it "returns a string representation fo what is sent to stdout inside the given block" do
|
18
|
+
out = Capture.stdout { $stdout.puts "hello"; $stdout.puts "world" }
|
19
|
+
expect( out ).to eq "hello\nworld\n"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#stderr" do
|
24
|
+
it "returns a string representation fo what is sent to stderr inside the given block" do
|
25
|
+
out = Capture.stderr { $stderr.puts "hello"; $stderr.puts "world" }
|
26
|
+
expect( out ).to eq "hello\nworld\n"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
describe "fixtures" do
|
35
|
+
|
36
|
+
describe "hello_stdout" do
|
37
|
+
it "puts hello stdout to stdout" do
|
38
|
+
stdout, stderr, status = Open3.capture3('spec/fixtures/hello_stdout')
|
39
|
+
expect( stdout ).to eq "Hello Stdout\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns success code" do
|
43
|
+
stdout, stderr, status = Open3.capture3('spec/fixtures/hello_stdout')
|
44
|
+
expect( status.success? ).to be_true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "hello_stderr" do
|
49
|
+
it "puts hello stderr to stderr" do
|
50
|
+
stdout, stderr, status = Open3.capture3('spec/fixtures/hello_stderr')
|
51
|
+
expect( stderr ).to eq "Hello Stderr\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "returns error code" do
|
55
|
+
stdout, stderr, status = Open3.capture3('spec/fixtures/hello_stderr')
|
56
|
+
expect( status.success? ).to be_false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Capture
|
2
|
+
|
3
|
+
class << self
|
4
|
+
def stdout &block
|
5
|
+
StdOut.new.capture(&block).read
|
6
|
+
end
|
7
|
+
|
8
|
+
def stderr &block
|
9
|
+
StdErr.new.capture(&block).read
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class StdOut
|
14
|
+
attr_reader :orig_stdout
|
15
|
+
attr_reader :new_stdout
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@orig_stdout = $stdout
|
19
|
+
@new_stdout = StringIO.open('','w+')
|
20
|
+
end
|
21
|
+
|
22
|
+
def capture &block
|
23
|
+
$stdout = new_stdout
|
24
|
+
yield
|
25
|
+
$stdout = orig_stdout
|
26
|
+
|
27
|
+
return self
|
28
|
+
end
|
29
|
+
|
30
|
+
def read
|
31
|
+
new_stdout.rewind
|
32
|
+
new_stdout.read
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class StdErr
|
37
|
+
attr_reader :orig_stderr
|
38
|
+
attr_reader :new_stderr
|
39
|
+
|
40
|
+
def initialize
|
41
|
+
@orig_stderr = $stderr
|
42
|
+
@new_stderr = StringIO.open('','w+')
|
43
|
+
end
|
44
|
+
|
45
|
+
def capture &block
|
46
|
+
$stderr = new_stderr
|
47
|
+
yield
|
48
|
+
$stderr = orig_stderr
|
49
|
+
|
50
|
+
return self
|
51
|
+
end
|
52
|
+
|
53
|
+
def read
|
54
|
+
new_stderr.rewind
|
55
|
+
new_stderr.read
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: here_or_there
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Steven Sloan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-18 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
|
+
description: A unified interface for running local or remote commands. Provides a
|
28
|
+
dependable & identical response from both types of command.
|
29
|
+
email:
|
30
|
+
- stevenosloan@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- lib/here_or_there/local.rb
|
36
|
+
- lib/here_or_there/remote.rb
|
37
|
+
- lib/here_or_there/response.rb
|
38
|
+
- lib/here_or_there/version.rb
|
39
|
+
- lib/here_or_there.rb
|
40
|
+
- spec/here_or_there/local_spec.rb
|
41
|
+
- spec/here_or_there/remote_spec.rb
|
42
|
+
- spec/here_or_there/response_spec.rb
|
43
|
+
- spec/here_or_there_spec.rb
|
44
|
+
- spec/spec_helper.rb
|
45
|
+
- spec/support/capture.rb
|
46
|
+
- spec/support/stubbed_session.rb
|
47
|
+
homepage: http://github.com/stevenosloan/here_or_there
|
48
|
+
licenses:
|
49
|
+
- MIT
|
50
|
+
metadata: {}
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 2.0.5
|
68
|
+
signing_key:
|
69
|
+
specification_version: 4
|
70
|
+
summary: Unified interface for running local and remote commands
|
71
|
+
test_files:
|
72
|
+
- spec/here_or_there/local_spec.rb
|
73
|
+
- spec/here_or_there/remote_spec.rb
|
74
|
+
- spec/here_or_there/response_spec.rb
|
75
|
+
- spec/here_or_there_spec.rb
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
- spec/support/capture.rb
|
78
|
+
- spec/support/stubbed_session.rb
|