Chee 0.1.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.
- data/.gitignore +8 -0
- data/Chee.gemspec +35 -0
- data/Gemfile +6 -0
- data/README.md +81 -0
- data/Rakefile +3 -0
- data/lib/Chee.rb +165 -0
- data/lib/Chee/version.rb +3 -0
- data/spec/files/errors_with_exit_0.rb +6 -0
- data/spec/files/exit_with_2.rb +2 -0
- data/spec/helper.rb +15 -0
- data/spec/main.rb +16 -0
- data/spec/tests/Chee.rb +84 -0
- data/spec/tests/bin.rb +13 -0
- metadata +189 -0
data/.gitignore
ADDED
data/Chee.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
$:.push File.expand_path("../lib", __FILE__)
|
4
|
+
require "Chee/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "Chee"
|
8
|
+
s.version = Chee::VERSION
|
9
|
+
s.authors = ["da99"]
|
10
|
+
s.email = ["i-hate-spam-45671204@mailinator.com"]
|
11
|
+
s.homepage = "https://github.com/da99/Chee"
|
12
|
+
s.summary = %q{Interact with a SSH session using tty and STDIN.}
|
13
|
+
s.description = %q{
|
14
|
+
Send commands through SSH, but using a tty/pty and STDIN.
|
15
|
+
That's right: Interactive SSH sessions. **Note:** Programs that
|
16
|
+
redraw the screen (e.g. vim) don't work that well. Apt-get and
|
17
|
+
other programs that request input in a simple manner should work well enough.
|
18
|
+
}
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
|
25
|
+
s.add_development_dependency 'bacon'
|
26
|
+
s.add_development_dependency 'rake'
|
27
|
+
s.add_development_dependency 'Bacon_Colored'
|
28
|
+
s.add_development_dependency 'pry'
|
29
|
+
s.add_development_dependency 'mocha-on-bacon'
|
30
|
+
|
31
|
+
# Specify any dependencies here; for example:
|
32
|
+
s.add_runtime_dependency 'Get_Set'
|
33
|
+
s.add_runtime_dependency 'net-ssh'
|
34
|
+
s.add_runtime_dependency 'net-scp'
|
35
|
+
end
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
Chee
|
3
|
+
================
|
4
|
+
|
5
|
+
Send commands through SSH, but using a tty/pty and STDIN.
|
6
|
+
That's right: Interactive SSH sessions.
|
7
|
+
|
8
|
+
Limitations
|
9
|
+
-----------
|
10
|
+
|
11
|
+
* Programs that redraw the screen (e.g. vim) don't work that well.
|
12
|
+
Apt-get and
|
13
|
+
other programs that request input in a simple manner should work well enough.
|
14
|
+
|
15
|
+
* PTY (psuedo-terminal) is used. Which means it runs in a sub-shell.
|
16
|
+
Which leads to *no* STDERR access. All output is done on STDOUT.
|
17
|
+
|
18
|
+
Installation
|
19
|
+
------------
|
20
|
+
|
21
|
+
gem install Chee
|
22
|
+
|
23
|
+
Usage
|
24
|
+
------
|
25
|
+
|
26
|
+
require "Chee"
|
27
|
+
|
28
|
+
Chee.server "my_server" # If you configured server using ~/.ssh/config
|
29
|
+
Chee.server Hash[
|
30
|
+
:ip => 'localhost',
|
31
|
+
:user => 'me',
|
32
|
+
|
33
|
+
# options other than :ip/:user are sent to Net::SSH
|
34
|
+
:password => "try to use private/public keys",
|
35
|
+
:timeout => 3
|
36
|
+
]
|
37
|
+
Chee.ssh %^ sudo add-apt-repository ppa:nginx/stable ^
|
38
|
+
<!-- sudo apt-get install nginx -->
|
39
|
+
<!-- ^ -->
|
40
|
+
|
41
|
+
Or you could include the DSL into your own object:
|
42
|
+
|
43
|
+
Class My_SSH
|
44
|
+
|
45
|
+
include Chee::DSL
|
46
|
+
|
47
|
+
def ssh cmd
|
48
|
+
super cmd.strip
|
49
|
+
end
|
50
|
+
|
51
|
+
end # === Class My_SSH
|
52
|
+
|
53
|
+
Run Tests
|
54
|
+
---------
|
55
|
+
|
56
|
+
To run the tests:
|
57
|
+
|
58
|
+
git clone git@github.com:da99/Chee.git
|
59
|
+
cd Chee
|
60
|
+
bundle update
|
61
|
+
bundle exec bacon spec/main.rb
|
62
|
+
|
63
|
+
Don't forget to setup ssh server, firewall, and passwordless SSH using
|
64
|
+
private keys. The following is useful for Ubuntu users:
|
65
|
+
|
66
|
+
sudo apt-get install ufw openssh-server
|
67
|
+
sudo ufw allow from 127.0.0.1 to any port 22
|
68
|
+
sudo ufw deny ssh
|
69
|
+
sudo ufw default deny
|
70
|
+
sudo ufw enable
|
71
|
+
|
72
|
+
* [UFW: Firewall](https://help.ubuntu.com/community/UFW)
|
73
|
+
* Common UFW rules: [http://blog.bodhizazen.net/linux/firewall-ubuntu-desktops/](http://blog.bodhizazen.net/linux/firewall-ubuntu-desktops/)
|
74
|
+
* [~/.ssh/config and private keys](http://www.cyberciti.biz/faq/force-ssh-client-to-use-given-private-key-identity-file/)
|
75
|
+
|
76
|
+
"I hate writing."
|
77
|
+
-----------------------------
|
78
|
+
|
79
|
+
If you know of existing software that makes the above redundant,
|
80
|
+
please tell me. The last thing I want to do is maintain code.
|
81
|
+
|
data/Rakefile
ADDED
data/lib/Chee.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'Chee/version'
|
2
|
+
require 'Get_Set'
|
3
|
+
require 'net/ssh'
|
4
|
+
require 'net/scp'
|
5
|
+
require 'readline'
|
6
|
+
|
7
|
+
class Chee
|
8
|
+
|
9
|
+
Result = Class.new {
|
10
|
+
include Get_Set::DSL
|
11
|
+
attr_get_set :exit_status, :out, :err
|
12
|
+
}
|
13
|
+
|
14
|
+
Exit_Error = Class.new(RuntimeError) {
|
15
|
+
include Get_Set::DSL
|
16
|
+
attr_get_set :exit_status, :out, :err
|
17
|
+
}
|
18
|
+
|
19
|
+
module DSL
|
20
|
+
|
21
|
+
def server *args
|
22
|
+
return @server if args.empty?
|
23
|
+
@server = args
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Thread technique came from:
|
28
|
+
# http://stackoverflow.com/questions/6942279/ruby-net-ssh-channel-dies
|
29
|
+
#
|
30
|
+
def ssh command
|
31
|
+
stdout = ""
|
32
|
+
stderr = ""
|
33
|
+
t = nil # used to store a Thread
|
34
|
+
|
35
|
+
ip, user, new_opts = *server
|
36
|
+
opts = {:timeout=>3}.merge(new_opts || {})
|
37
|
+
|
38
|
+
begin
|
39
|
+
|
40
|
+
get_input = true
|
41
|
+
@channel = nil
|
42
|
+
cmd = ''
|
43
|
+
prev_cmd = ''
|
44
|
+
prev_data = ''
|
45
|
+
result = Result.new
|
46
|
+
|
47
|
+
t = Thread.new {
|
48
|
+
|
49
|
+
while get_input do
|
50
|
+
|
51
|
+
cmd = begin
|
52
|
+
Readline.readline("", true).strip
|
53
|
+
rescue Interrupt => e # Send CTRL-C:
|
54
|
+
get_input = false
|
55
|
+
"^C"
|
56
|
+
end
|
57
|
+
|
58
|
+
if @channel
|
59
|
+
@channel.process
|
60
|
+
else
|
61
|
+
print "Connection closed. Could not send: #{cmd}\n"
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
}
|
67
|
+
|
68
|
+
Net::SSH.start(ip, user, opts) { |ssh|
|
69
|
+
|
70
|
+
@channel = ssh.open_channel do |ch1|
|
71
|
+
|
72
|
+
ch1.on_extended_data do |ch, type, d|
|
73
|
+
stderr << d
|
74
|
+
end
|
75
|
+
|
76
|
+
ch1.on_request 'exit-status' do |ch, d|
|
77
|
+
result.exit_status d.read_long
|
78
|
+
end
|
79
|
+
|
80
|
+
ch1.on_open_failed { |ch, code, desc|
|
81
|
+
stderr << "Failure to open channel: #{code.inspect}: #{desc}"
|
82
|
+
}
|
83
|
+
|
84
|
+
ch1.on_process do |ch|
|
85
|
+
if cmd.strip == '^C'
|
86
|
+
#ch.close
|
87
|
+
ch.send_data( Net::SSH::Buffer.from(:byte, 3, :raw, "\n").to_s )
|
88
|
+
stderr << "User requested interrupt."
|
89
|
+
else
|
90
|
+
if cmd.strip.empty?
|
91
|
+
# ignore it
|
92
|
+
else
|
93
|
+
ch.send_data( "#{cmd}\n" )
|
94
|
+
prev_cmd = cmd
|
95
|
+
cmd = ''
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
ch1.on_data do |ch, d|
|
101
|
+
|
102
|
+
stdout << d # .sub(%r!\r?\n\Z!,'')
|
103
|
+
|
104
|
+
unless prev_cmd.to_s.strip == d.strip
|
105
|
+
print d
|
106
|
+
STDOUT.flush
|
107
|
+
end
|
108
|
+
|
109
|
+
prev_data = d
|
110
|
+
end
|
111
|
+
|
112
|
+
ch1.request_pty do |ch, success|
|
113
|
+
if success
|
114
|
+
# do nothing
|
115
|
+
else
|
116
|
+
ch.close
|
117
|
+
(stderr << "Unknown error requesting pty.")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
ch1.exec(command)
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
ssh.loop 0.1
|
126
|
+
} # === Net::SSH.start
|
127
|
+
|
128
|
+
rescue Timeout::Error => e
|
129
|
+
raise e.class, server.inspect
|
130
|
+
|
131
|
+
rescue Net::SSH::AuthenticationFailed => e
|
132
|
+
raise e.class, "Using: #{server.inspect}"
|
133
|
+
|
134
|
+
#rescue Net::SSH::HostKeyMismatch => e
|
135
|
+
# if e.message[%r!fingerprint .+ does not match for!]
|
136
|
+
# print "Try this", "ssh-keygen -f \"~/.ssh/known_hosts\" -R #{server[:ip]}\n"
|
137
|
+
# raise Retry_Command, "Removed the RSA key."
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# raise e
|
141
|
+
ensure
|
142
|
+
get_input = false
|
143
|
+
t.exit if t
|
144
|
+
end
|
145
|
+
|
146
|
+
result.err stderr
|
147
|
+
result.out stdout
|
148
|
+
|
149
|
+
if !result.err.empty? || result.exit_status != 0
|
150
|
+
e = Exit_Error.new("Exit: #{result.exit_status}, STDERR: #{result.err}")
|
151
|
+
e.exit_status result.exit_status
|
152
|
+
e.out result.out
|
153
|
+
e.err result.err
|
154
|
+
raise e
|
155
|
+
end
|
156
|
+
|
157
|
+
result.out.strip!
|
158
|
+
result
|
159
|
+
end
|
160
|
+
|
161
|
+
end # === module DSL
|
162
|
+
|
163
|
+
extend DSL
|
164
|
+
|
165
|
+
end # === class Chee
|
data/lib/Chee/version.rb
ADDED
data/spec/helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.print e.message, "\n"
|
7
|
+
$stderr.print "Run `bundle install` to install missing gems\n"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'bacon'
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
|
15
|
+
Bacon.summary_on_exit
|
data/spec/main.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
require File.expand_path('spec/helper')
|
3
|
+
require 'Chee'
|
4
|
+
require 'Bacon_Colored'
|
5
|
+
require 'pry'
|
6
|
+
require 'mocha-on-bacon'
|
7
|
+
|
8
|
+
|
9
|
+
# ======== Include the tests.
|
10
|
+
if ARGV.size > 1 && ARGV[1, ARGV.size - 1].detect { |a| File.exists?(a) }
|
11
|
+
# Do nothing. Bacon grabs the file.
|
12
|
+
else
|
13
|
+
Dir.glob('spec/tests/*.rb').each { |file|
|
14
|
+
require File.expand_path(file.sub('.rb', '')) if File.file?(file)
|
15
|
+
}
|
16
|
+
end
|
data/spec/tests/Chee.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
|
2
|
+
describe ":ssh_exec" do
|
3
|
+
|
4
|
+
before do
|
5
|
+
@localhost = 'localhost'
|
6
|
+
|
7
|
+
@wrong_ip = Hash[
|
8
|
+
:ip=> 'localhosts',
|
9
|
+
:user=>`whoami`.strip
|
10
|
+
]
|
11
|
+
|
12
|
+
Chee.server @localhost
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'accepts a String for the server info.' do
|
16
|
+
Chee.server "localhost"
|
17
|
+
Chee.ssh("echo 'a'").out.should == "a"
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'accepts a Hash for the server info.' do
|
21
|
+
Chee.server 'localhost', `whoami`.strip, :password=>nil
|
22
|
+
Chee.ssh("echo 'b'").out.should == 'b'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'uses a PTY' do
|
26
|
+
Chee.ssh("tty").out.should.match %r!/dev/pts/\d+!
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns a SSH::Results' do
|
30
|
+
Chee.ssh("hostname").should.be.is_a Chee::Result
|
31
|
+
end
|
32
|
+
|
33
|
+
it "strips returned data" do
|
34
|
+
target = `uptime`.strip.gsub(%r!\d+!, '[0-9]{1,2}')
|
35
|
+
Chee.ssh("uptime").out.should.match %r!#{target}!
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'raises Net::SSH::AuthenticationFailed if login/password are incorrect' do
|
39
|
+
lambda {
|
40
|
+
Chee.server "github.com"
|
41
|
+
Chee.ssh "hostname"
|
42
|
+
}.should.raise(Net::SSH::AuthenticationFailed)
|
43
|
+
.message.should.match %r!Using: ..github.com..!
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'raises Chee::Exit_Error if return status is not zero' do
|
48
|
+
e = lambda {
|
49
|
+
Chee.ssh "HOSTNAMES"
|
50
|
+
}.should.raise(Chee::Exit_Error)
|
51
|
+
|
52
|
+
e.exit_status.should == 127
|
53
|
+
end
|
54
|
+
|
55
|
+
end # === describe :ssh_exec
|
56
|
+
|
57
|
+
__END__
|
58
|
+
describe ":ssh_exits" do
|
59
|
+
|
60
|
+
it 'captures exits based on key => int, val => Regexp' do
|
61
|
+
lambda {
|
62
|
+
ignore_exits("cat something.txt", 1=>%r!something\.txt\: No such file or directory!)
|
63
|
+
}.should.not.raise
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'captures exits based on key => int, val => String' do
|
67
|
+
lambda {
|
68
|
+
ignore_exits("cat something.txt", 1=>'something.txt: No such file or directory')
|
69
|
+
}.should.not.raise
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'returns SSH::Results for a non-zero exit status' do
|
73
|
+
ignore_exits("cat something.txt", 1=>'something.txt: No such file or directory')
|
74
|
+
.should.be.is_a Unified_IO::Remote::SSH::Results
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns SSH::Results for a zero exit status' do
|
78
|
+
ignore_exits("uptime", 1=>'something.txt: No such file or directory')
|
79
|
+
.should.be.is_a Unified_IO::Remote::SSH::Results
|
80
|
+
end
|
81
|
+
|
82
|
+
end # === describe :ssh_exits
|
83
|
+
|
84
|
+
|
data/spec/tests/bin.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
bins = Dir.glob("bin/*")
|
3
|
+
|
4
|
+
unless bins.empty?
|
5
|
+
describe "permissions of bin/" do
|
6
|
+
bins.each { |file|
|
7
|
+
it "should chmod 755 for: #{file}" do
|
8
|
+
`stat -c %a #{file}`.strip
|
9
|
+
.should.be == "755"
|
10
|
+
end
|
11
|
+
}
|
12
|
+
end # === permissions of bin/
|
13
|
+
end # === unless bins.empty?
|
metadata
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Chee
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- da99
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bacon
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: Bacon_Colored
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: pry
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: mocha-on-bacon
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: Get_Set
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: net-ssh
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: net-scp
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
description: ! "\n Send commands through SSH, but using a tty/pty and STDIN.\n
|
143
|
+
\ That's right: Interactive SSH sessions. **Note:** Programs that\n redraw
|
144
|
+
the screen (e.g. vim) don't work that well. Apt-get and \n other programs that
|
145
|
+
request input in a simple manner should work well enough.\n "
|
146
|
+
email:
|
147
|
+
- i-hate-spam-45671204@mailinator.com
|
148
|
+
executables: []
|
149
|
+
extensions: []
|
150
|
+
extra_rdoc_files: []
|
151
|
+
files:
|
152
|
+
- .gitignore
|
153
|
+
- Chee.gemspec
|
154
|
+
- Gemfile
|
155
|
+
- README.md
|
156
|
+
- Rakefile
|
157
|
+
- lib/Chee.rb
|
158
|
+
- lib/Chee/version.rb
|
159
|
+
- spec/files/errors_with_exit_0.rb
|
160
|
+
- spec/files/exit_with_2.rb
|
161
|
+
- spec/helper.rb
|
162
|
+
- spec/main.rb
|
163
|
+
- spec/tests/Chee.rb
|
164
|
+
- spec/tests/bin.rb
|
165
|
+
homepage: https://github.com/da99/Chee
|
166
|
+
licenses: []
|
167
|
+
post_install_message:
|
168
|
+
rdoc_options: []
|
169
|
+
require_paths:
|
170
|
+
- lib
|
171
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
172
|
+
none: false
|
173
|
+
requirements:
|
174
|
+
- - ! '>='
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
|
+
none: false
|
179
|
+
requirements:
|
180
|
+
- - ! '>='
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
requirements: []
|
184
|
+
rubyforge_project:
|
185
|
+
rubygems_version: 1.8.19
|
186
|
+
signing_key:
|
187
|
+
specification_version: 3
|
188
|
+
summary: Interact with a SSH session using tty and STDIN.
|
189
|
+
test_files: []
|