scutil 0.2.2 → 0.2.3
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/CHANGELOG +7 -1
- data/lib/scutil.rb +15 -180
- data/lib/scutil/connection_cache.rb +46 -0
- data/lib/scutil/error.rb +31 -0
- data/lib/scutil/exec.rb +37 -0
- data/lib/scutil/system_connection.rb +63 -0
- data/scutil.gemspec +29 -0
- data/test/test_scutil.rb +50 -0
- metadata +11 -3
data/CHANGELOG
CHANGED
data/lib/scutil.rb
CHANGED
@@ -24,53 +24,13 @@ THE SOFTWARE.
|
|
24
24
|
=end
|
25
25
|
|
26
26
|
require 'net/ssh'
|
27
|
+
require 'scutil/exec'
|
28
|
+
require 'scutil/error'
|
29
|
+
require 'scutil/connection_cache'
|
30
|
+
require 'scutil/system_connection'
|
27
31
|
|
28
32
|
module Scutil
|
29
|
-
|
30
|
-
# reuse later.
|
31
|
-
class ConnectionCache
|
32
|
-
attr_reader :cache
|
33
|
-
include Enumerable
|
34
|
-
|
35
|
-
def initialize
|
36
|
-
@cache = []
|
37
|
-
end
|
38
|
-
|
39
|
-
# Need each to mixin Enumerable
|
40
|
-
def each
|
41
|
-
@cache.each do |c|
|
42
|
-
yield c
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def fetch(hostname)
|
47
|
-
each do |c|
|
48
|
-
return c if c.hostname == hostname
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def exists?(hostname)
|
53
|
-
each do |c|
|
54
|
-
return true if c.hostname == hostname
|
55
|
-
end
|
56
|
-
false
|
57
|
-
end
|
58
|
-
|
59
|
-
# Remove all instances of _hostname_.
|
60
|
-
def remove(hostname)
|
61
|
-
@cache.delete_if { |c| c.hostname == hostname }
|
62
|
-
end
|
63
|
-
|
64
|
-
def <<(conn)
|
65
|
-
@cache << conn
|
66
|
-
end
|
67
|
-
|
68
|
-
def to_s
|
69
|
-
@cache.join("\n")
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
SCUTIL_VERSION = '0.2.2'
|
33
|
+
SCUTIL_VERSION = '0.2.3'
|
74
34
|
# By default, buffer 10M of data before writing.
|
75
35
|
DEFAULT_OUTPUT_BUFFER_SIZE = 0xA00000
|
76
36
|
# Checks for a command starting with _sudo_ by default.
|
@@ -85,105 +45,6 @@ module Scutil
|
|
85
45
|
# Set to 10M by default, this can be adjusted to tell scutil when
|
86
46
|
# to write command output to _output_.
|
87
47
|
attr_accessor :output_buffer_size
|
88
|
-
end
|
89
|
-
|
90
|
-
# Wrapper for each connection to a system. Capabile of holding a
|
91
|
-
# standard connect (@connection) and and PTY connection
|
92
|
-
# (@pty_connection) for each system.
|
93
|
-
class SystemConnection
|
94
|
-
attr_reader :hostname,:pty_connection,:connection
|
95
|
-
def initialize(hostname, options={})
|
96
|
-
@hostname = hostname
|
97
|
-
@connection = nil
|
98
|
-
@pty_connection = nil
|
99
|
-
@options = options
|
100
|
-
end
|
101
|
-
|
102
|
-
# Return a connection for system. Checks to see if an established
|
103
|
-
# connection exists. If not it creates a new one. Requests a PTY
|
104
|
-
# if needed.
|
105
|
-
def get_connection(hostname, username, pty_needed=false, options={})
|
106
|
-
conn = nil
|
107
|
-
# Local map has precedence.
|
108
|
-
@options.merge!(options)
|
109
|
-
|
110
|
-
scrub_options @options
|
111
|
-
|
112
|
-
if (pty_needed)
|
113
|
-
if !@pty_connection.nil?
|
114
|
-
# Existing PTY connection
|
115
|
-
$stderr.print "[#{hostname}] Using existing connection (pty)\n" if @options[:scutil_verbose]
|
116
|
-
return @pty_connection
|
117
|
-
end
|
118
|
-
|
119
|
-
# New PTY connection
|
120
|
-
$stderr.print "[#{hostname}] Opening new channel (pty) to system...\n" if @options[:scutil_verbose]
|
121
|
-
conn = Net::SSH.start(hostname, username, @options)
|
122
|
-
@pty_connection = conn
|
123
|
-
else
|
124
|
-
if !@connection.nil?
|
125
|
-
# Existing non-PTY connection
|
126
|
-
$stderr.print "[#{hostname}] Using existing connection (non-pty)\n" if @options[:scutil_verbose]
|
127
|
-
return @connection
|
128
|
-
end
|
129
|
-
|
130
|
-
# New non-PTY connection
|
131
|
-
$stderr.print "[#{hostname}] Opening channel (non-pty) to system...\n" if @options[:scutil_verbose]
|
132
|
-
conn = Net::SSH.start(hostname, username, @options)
|
133
|
-
@connection = conn
|
134
|
-
end
|
135
|
-
|
136
|
-
return conn
|
137
|
-
end
|
138
|
-
|
139
|
-
# Remove scutil specific options. The rest go to Net::SSH.
|
140
|
-
def scrub_options(options)
|
141
|
-
options.delete(:scutil_verbose) if (options.has_key?(:scutil_verbose))
|
142
|
-
options.delete(:scutil_force_pty) if (options.has_key?(:scutil_force_pty))
|
143
|
-
options.delete(:scutil_pty_regex) if (options.has_key?(:scutil_pty_regex))
|
144
|
-
end
|
145
|
-
|
146
|
-
def to_s
|
147
|
-
"#{self.class}: #{@name}, @connection = #{@connection}, @pty_connection = #{@pty_connection}"
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
# Instantiate this class if you wish to use scutil as an object.
|
152
|
-
# For example:
|
153
|
-
#
|
154
|
-
# exec = Scutil::Exec.new('severname', 'mas')
|
155
|
-
#
|
156
|
-
# exec.exec_command('echo "foo"')
|
157
|
-
#
|
158
|
-
# exec.exec_command('echo "bar"; sudo whoami', "",
|
159
|
-
# { :scutil_force_pty => true,
|
160
|
-
# :scutil_verbose => true
|
161
|
-
# })
|
162
|
-
#
|
163
|
-
class Exec
|
164
|
-
include Scutil
|
165
|
-
attr_reader :hostname,:username
|
166
|
-
|
167
|
-
def initialize(hostname, username, options={})
|
168
|
-
@hostname = hostname
|
169
|
-
@username = username
|
170
|
-
@options = options
|
171
|
-
end
|
172
|
-
|
173
|
-
# See Scutil.exec_command. Takes _cmd_ and optionally _output_,
|
174
|
-
# and _options_. Other arguments specified at class
|
175
|
-
# initialization.
|
176
|
-
#
|
177
|
-
# The _options_ specified here will take precedence over those
|
178
|
-
# specified in the constructor.
|
179
|
-
def exec_command(cmd, output=nil, options={})
|
180
|
-
# Local map has precedence.
|
181
|
-
@options.merge!(options)
|
182
|
-
Scutil.exec_command(@hostname, @username, cmd, output, @options)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
class << self
|
187
48
|
|
188
49
|
# Should we request a PTY? Uses custom regex if defined in
|
189
50
|
# +:scutil_pty_regex+.
|
@@ -205,16 +66,16 @@ module Scutil
|
|
205
66
|
return options[:scutil_force_pty] ? true : false
|
206
67
|
end
|
207
68
|
end
|
208
|
-
|
69
|
+
|
209
70
|
# Drops all instances of +hostname+ from connection_cache.
|
210
71
|
def clear!(hostname)
|
211
72
|
if (Scutil.connection_cache.exists?(hostname))
|
212
|
-
Scutil.connection_cache.
|
73
|
+
Scutil.connection_cache.remove(hostname)
|
213
74
|
else
|
214
75
|
raise Scutil::Error.new("Error: :scutil_pty_regex must be a kind of Regexp", hostname)
|
215
76
|
end
|
216
77
|
end
|
217
|
-
|
78
|
+
|
218
79
|
# Scutil.exec_command is used to execute a command, specified in
|
219
80
|
# _cmd_, on a remote system. The return value and any ouput of
|
220
81
|
# the command are captured.
|
@@ -265,12 +126,13 @@ module Scutil
|
|
265
126
|
begin
|
266
127
|
if (Scutil.connection_cache.exists?(hostname))
|
267
128
|
sys_conn = Scutil.connection_cache.fetch(hostname)
|
129
|
+
$stderr.print "[#{hostname}] Using existing connection\n" if options[:scutil_verbose]
|
268
130
|
conn = sys_conn.get_connection(hostname, username, pty_needed, options)
|
269
131
|
else
|
270
132
|
sys_conn = SystemConnection.new(hostname)
|
271
|
-
$stderr.print "[#{hostname}] Adding new connection to cache\n" if options[:scutil_verbose]
|
272
133
|
# Call get_connection first. Don't add to cache unless established.
|
273
134
|
conn = sys_conn.get_connection(hostname, username, pty_needed, options)
|
135
|
+
$stderr.print "[#{hostname}] Adding new connection to cache\n" if options[:scutil_verbose]
|
274
136
|
Scutil.connection_cache << sys_conn
|
275
137
|
end
|
276
138
|
rescue Net::SSH::AuthenticationFailed => err
|
@@ -330,7 +192,11 @@ module Scutil
|
|
330
192
|
channel.on_request("exit-status") do |ch, data|
|
331
193
|
exit_status = data.read_long
|
332
194
|
end
|
333
|
-
|
195
|
+
|
196
|
+
# channel.on_open_failed do |ch, code, desc|
|
197
|
+
#
|
198
|
+
# end
|
199
|
+
|
334
200
|
channel.exec(cmd)
|
335
201
|
# channel.wait
|
336
202
|
end
|
@@ -352,34 +218,3 @@ module Scutil
|
|
352
218
|
|
353
219
|
# end
|
354
220
|
end
|
355
|
-
|
356
|
-
# Exception class for scutil. The system, error message, and return
|
357
|
-
# value of the remote command are stored here on error.
|
358
|
-
#
|
359
|
-
# begin
|
360
|
-
# Scutil.exec_command('ls -al /root')
|
361
|
-
# rescue Scutil::Error => err
|
362
|
-
# puts "Message: " + err.message
|
363
|
-
# puts "Hostname: " + err.hostname
|
364
|
-
# puts "Exit status: #{err.command_exit_status}"
|
365
|
-
# end
|
366
|
-
#
|
367
|
-
# Will produce:
|
368
|
-
#
|
369
|
-
# Message: Error: ls: /root: Permission denied
|
370
|
-
# Hostname: server.name.com
|
371
|
-
# Exit status: 2
|
372
|
-
#
|
373
|
-
class Scutil::Error < StandardError
|
374
|
-
attr_reader :hostname,:message,:command_exit_status
|
375
|
-
|
376
|
-
def initialize(message=nil, hostname=nil, command_exit_status=-1)
|
377
|
-
@message = message
|
378
|
-
@hostname = hostname
|
379
|
-
@command_exit_status = command_exit_status
|
380
|
-
end
|
381
|
-
|
382
|
-
def to_s
|
383
|
-
"Message: #{@message}\nHostname: #{@hostname}\nExit status: #{command_exit_status}\n"
|
384
|
-
end
|
385
|
-
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
module Scutil
|
3
|
+
# Utiliy class to hold all the connections created, possibly for
|
4
|
+
# reuse later.
|
5
|
+
class ConnectionCache
|
6
|
+
attr_reader :cache
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@cache = []
|
11
|
+
end
|
12
|
+
|
13
|
+
# Need each to mixin Enumerable
|
14
|
+
def each
|
15
|
+
@cache.each do |c|
|
16
|
+
yield c
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def fetch(hostname)
|
21
|
+
each do |c|
|
22
|
+
return c if c.hostname == hostname
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def exists?(hostname)
|
27
|
+
each do |c|
|
28
|
+
return true if c.hostname == hostname
|
29
|
+
end
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
# Remove all instances of _hostname_.
|
34
|
+
def remove(hostname)
|
35
|
+
@cache.delete_if { |c| c.hostname == hostname }
|
36
|
+
end
|
37
|
+
|
38
|
+
def <<(conn)
|
39
|
+
@cache << conn
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s
|
43
|
+
@cache.join("\n")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/scutil/error.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
# Exception class for scutil. The system, error message, and return
|
3
|
+
# value of the remote command are stored here on error.
|
4
|
+
#
|
5
|
+
# begin
|
6
|
+
# Scutil.exec_command('ls -al /root')
|
7
|
+
# rescue Scutil::Error => err
|
8
|
+
# puts "Message: " + err.message
|
9
|
+
# puts "Hostname: " + err.hostname
|
10
|
+
# puts "Exit status: #{err.command_exit_status}"
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# Will produce:
|
14
|
+
#
|
15
|
+
# Message: Error: ls: /root: Permission denied
|
16
|
+
# Hostname: server.name.com
|
17
|
+
# Exit status: 2
|
18
|
+
#
|
19
|
+
class Scutil::Error < StandardError
|
20
|
+
attr_reader :hostname,:message,:command_exit_status
|
21
|
+
|
22
|
+
def initialize(message=nil, hostname=nil, command_exit_status=-1)
|
23
|
+
@message = message
|
24
|
+
@hostname = hostname
|
25
|
+
@command_exit_status = command_exit_status
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"Message: #{@message}\nHostname: #{@hostname}\nExit status: #{command_exit_status}\n"
|
30
|
+
end
|
31
|
+
end
|
data/lib/scutil/exec.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
module Scutil
|
3
|
+
# Instantiate this class if you wish to use scutil as an object.
|
4
|
+
# For example:
|
5
|
+
#
|
6
|
+
# exec = Scutil::Exec.new('severname', 'mas')
|
7
|
+
#
|
8
|
+
# exec.exec_command('echo "foo"')
|
9
|
+
#
|
10
|
+
# exec.exec_command('echo "bar"; sudo whoami', "",
|
11
|
+
# { :scutil_force_pty => true,
|
12
|
+
# :scutil_verbose => true
|
13
|
+
# })
|
14
|
+
#
|
15
|
+
class Exec
|
16
|
+
include Scutil
|
17
|
+
attr_reader :hostname,:username
|
18
|
+
|
19
|
+
def initialize(hostname, username, options={})
|
20
|
+
@hostname = hostname
|
21
|
+
@username = username
|
22
|
+
@options = options
|
23
|
+
end
|
24
|
+
|
25
|
+
# See Scutil.exec_command. Takes _cmd_ and optionally _output_,
|
26
|
+
# and _options_. Other arguments specified at class
|
27
|
+
# initialization.
|
28
|
+
#
|
29
|
+
# The _options_ specified here will take precedence over those
|
30
|
+
# specified in the constructor.
|
31
|
+
def exec_command(cmd, output=nil, options={})
|
32
|
+
# Local map has precedence.
|
33
|
+
@options.merge!(options)
|
34
|
+
Scutil.exec_command(@hostname, @username, cmd, output, @options)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
|
2
|
+
module Scutil
|
3
|
+
# Wrapper for each connection to a system. Capabile of holding a
|
4
|
+
# standard connect (@connection) and and PTY connection
|
5
|
+
# (@pty_connection) for each system.
|
6
|
+
class SystemConnection
|
7
|
+
attr_reader :hostname,:pty_connection,:connection
|
8
|
+
def initialize(hostname, options={})
|
9
|
+
@hostname = hostname
|
10
|
+
@connection = nil
|
11
|
+
@pty_connection = nil
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return a connection for system. Checks to see if an established
|
16
|
+
# connection exists. If not it creates a new one. Requests a PTY
|
17
|
+
# if needed.
|
18
|
+
def get_connection(hostname, username, pty_needed=false, options={})
|
19
|
+
conn = nil
|
20
|
+
# Local map has precedence.
|
21
|
+
@options.merge!(options)
|
22
|
+
|
23
|
+
scrub_options @options
|
24
|
+
|
25
|
+
if (pty_needed)
|
26
|
+
if !@pty_connection.nil?
|
27
|
+
# Existing PTY connection
|
28
|
+
$stderr.print "[#{hostname}] Using existing connection (pty)\n" if @options[:scutil_verbose]
|
29
|
+
return @pty_connection
|
30
|
+
end
|
31
|
+
|
32
|
+
# New PTY connection
|
33
|
+
$stderr.print "[#{hostname}] Opening new channel (pty) to system...\n" if @options[:scutil_verbose]
|
34
|
+
conn = Net::SSH.start(hostname, username, @options)
|
35
|
+
@pty_connection = conn
|
36
|
+
else
|
37
|
+
if !@connection.nil?
|
38
|
+
# Existing non-PTY connection
|
39
|
+
$stderr.print "[#{hostname}] Using existing connection (non-pty)\n" if @options[:scutil_verbose]
|
40
|
+
return @connection
|
41
|
+
end
|
42
|
+
|
43
|
+
# New non-PTY connection
|
44
|
+
$stderr.print "[#{hostname}] Opening channel (non-pty) to system...\n" if @options[:scutil_verbose]
|
45
|
+
conn = Net::SSH.start(hostname, username, @options)
|
46
|
+
@connection = conn
|
47
|
+
end
|
48
|
+
|
49
|
+
return conn
|
50
|
+
end
|
51
|
+
|
52
|
+
# Remove scutil specific options. The rest go to Net::SSH.
|
53
|
+
def scrub_options(options)
|
54
|
+
options.delete(:scutil_verbose) if (options.has_key?(:scutil_verbose))
|
55
|
+
options.delete(:scutil_force_pty) if (options.has_key?(:scutil_force_pty))
|
56
|
+
options.delete(:scutil_pty_regex) if (options.has_key?(:scutil_pty_regex))
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
"#{self.class}: #{@name}, @connection = #{@connection}, @pty_connection = #{@pty_connection}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/scutil.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'scutil'
|
3
|
+
s.version = '0.2.3'
|
4
|
+
s.date = '2011-09-27'
|
5
|
+
s.summary = 'SSH Command UTILity'
|
6
|
+
s.description = <<-EOF
|
7
|
+
Scutil is a library for conveniently executing commands
|
8
|
+
remotely via SSH.
|
9
|
+
EOF
|
10
|
+
s.author = 'Marc Soda'
|
11
|
+
s.email = 'marcantoniosr@gmail.com'
|
12
|
+
s.license = 'MIT'
|
13
|
+
s.homepage = 'http://marcantonio.github.com/scutil'
|
14
|
+
s.rdoc_options << '--title' << 'SSH Command UTILity' << '--main' << 'README'
|
15
|
+
s.extra_rdoc_files = ['README', 'THANKS', 'CHANGELOG']
|
16
|
+
s.add_runtime_dependency 'net-ssh', '>= 2.1.0'
|
17
|
+
s.files = %w(
|
18
|
+
lib/scutil.rb
|
19
|
+
lib/scutil/connection_cache.rb
|
20
|
+
lib/scutil/error.rb
|
21
|
+
lib/scutil/exec.rb
|
22
|
+
lib/scutil/system_connection.rb
|
23
|
+
scutil.gemspec
|
24
|
+
README
|
25
|
+
CHANGELOG
|
26
|
+
THANKS
|
27
|
+
test/test_scutil.rb
|
28
|
+
)
|
29
|
+
end
|
data/test/test_scutil.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/ruby -I../lib -w
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'scutil'
|
5
|
+
require 'stringio'
|
6
|
+
|
7
|
+
class TestScutil < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@hostname = ARGV[0]
|
10
|
+
@port = ARGV[1]
|
11
|
+
@user = 'mas'
|
12
|
+
@exec = Scutil::Exec.new(@hostname, @user,
|
13
|
+
{ :port => @port,
|
14
|
+
# :keys => '~mas/.ssh/id_rsa',
|
15
|
+
})
|
16
|
+
@output = nil
|
17
|
+
@t_output = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def divert_stdout
|
21
|
+
@t_output = $stdout
|
22
|
+
$stdout = StringIO.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def revert_stdout
|
26
|
+
@output = $stdout
|
27
|
+
$stdout = @t_output
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_initialize_exec_object
|
31
|
+
assert_not_nil @exec
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_is_correct_instance
|
35
|
+
assert_instance_of Scutil::Exec, @exec
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_run_command
|
39
|
+
divert_stdout
|
40
|
+
retval = @exec.exec_command('echo "alpha"')
|
41
|
+
revert_stdout
|
42
|
+
assert_equal "alpha", @output.string.chomp
|
43
|
+
assert_equal 0, retval
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if ARGV[1].nil?
|
48
|
+
puts "Usage: #{$0} host1 [host2 host3] port"
|
49
|
+
exit(1)
|
50
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: scutil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.2.
|
5
|
+
version: 0.2.3
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Marc Soda
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-09-
|
13
|
+
date: 2011-09-27 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: net-ssh
|
@@ -35,9 +35,15 @@ extra_rdoc_files:
|
|
35
35
|
- CHANGELOG
|
36
36
|
files:
|
37
37
|
- lib/scutil.rb
|
38
|
+
- lib/scutil/connection_cache.rb
|
39
|
+
- lib/scutil/error.rb
|
40
|
+
- lib/scutil/exec.rb
|
41
|
+
- lib/scutil/system_connection.rb
|
42
|
+
- scutil.gemspec
|
38
43
|
- README
|
39
|
-
- THANKS
|
40
44
|
- CHANGELOG
|
45
|
+
- THANKS
|
46
|
+
- test/test_scutil.rb
|
41
47
|
homepage: http://marcantonio.github.com/scutil
|
42
48
|
licenses:
|
43
49
|
- MIT
|
@@ -45,6 +51,8 @@ post_install_message:
|
|
45
51
|
rdoc_options:
|
46
52
|
- --title
|
47
53
|
- SSH Command UTILity
|
54
|
+
- --main
|
55
|
+
- README
|
48
56
|
require_paths:
|
49
57
|
- lib
|
50
58
|
required_ruby_version: !ruby/object:Gem::Requirement
|