rye 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +26 -0
- data/LICENSE.txt +19 -0
- data/README.rdoc +176 -0
- data/Rakefile +83 -0
- data/bin/try +148 -0
- data/lib/esc.rb +301 -0
- data/lib/rye.rb +155 -0
- data/lib/rye/box.rb +312 -0
- data/lib/rye/cmd.rb +47 -0
- data/lib/rye/rap.rb +83 -0
- data/lib/rye/set.rb +145 -0
- data/lib/sys.rb +274 -0
- data/rye.gemspec +56 -0
- data/test/10_rye_test.rb +63 -0
- metadata +90 -0
data/lib/esc.rb
ADDED
@@ -0,0 +1,301 @@
|
|
1
|
+
# escape.rb - escape/unescape library for several formats
|
2
|
+
#
|
3
|
+
# Copyright (C) 2006,2007 Tanaka Akira <akr@fsij.org>
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
# 3. The name of the author may not be used to endorse or promote products
|
14
|
+
# derived from this software without specific prior written permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
17
|
+
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
18
|
+
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
19
|
+
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
20
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
21
|
+
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
22
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
23
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
24
|
+
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
25
|
+
# OF SUCH DAMAGE.
|
26
|
+
|
27
|
+
# Escape module provides several escape functions.
|
28
|
+
# * URI
|
29
|
+
# * HTML
|
30
|
+
# * shell command
|
31
|
+
module Escape # :nodoc:all
|
32
|
+
module_function
|
33
|
+
|
34
|
+
class StringWrapper # :nodoc:all
|
35
|
+
class << self
|
36
|
+
alias new_no_dup new
|
37
|
+
def new(str)
|
38
|
+
new_no_dup(str.dup)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(str)
|
43
|
+
@str = str
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
47
|
+
@str.dup
|
48
|
+
end
|
49
|
+
|
50
|
+
def inspect
|
51
|
+
"\#<#{self.class}: #{@str}>"
|
52
|
+
end
|
53
|
+
|
54
|
+
def ==(other)
|
55
|
+
other.class == self.class && @str == other.instance_variable_get(:@str)
|
56
|
+
end
|
57
|
+
alias eql? ==
|
58
|
+
|
59
|
+
def hash
|
60
|
+
@str.hash
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class ShellEscaped < StringWrapper #:nodoc:all
|
65
|
+
end
|
66
|
+
|
67
|
+
# Escape.shell_command composes
|
68
|
+
# a sequence of words to
|
69
|
+
# a single shell command line.
|
70
|
+
# All shell meta characters are quoted and
|
71
|
+
# the words are concatenated with interleaving space.
|
72
|
+
# It returns an instance of ShellEscaped.
|
73
|
+
#
|
74
|
+
# Escape.shell_command(["ls", "/"]) #=> #<Escape::ShellEscaped: ls />
|
75
|
+
# Escape.shell_command(["echo", "*"]) #=> #<Escape::ShellEscaped: echo '*'>
|
76
|
+
#
|
77
|
+
# Note that system(*command) and
|
78
|
+
# system(Escape.shell_command(command)) is roughly same.
|
79
|
+
# There are two exception as follows.
|
80
|
+
# * The first is that the later may invokes /bin/sh.
|
81
|
+
# * The second is an interpretation of an array with only one element:
|
82
|
+
# the element is parsed by the shell with the former but
|
83
|
+
# it is recognized as single word with the later.
|
84
|
+
# For example, system(*["echo foo"]) invokes echo command with an argument "foo".
|
85
|
+
# But system(Escape.shell_command(["echo foo"])) invokes "echo foo" command without arguments (and it probably fails).
|
86
|
+
def shell_command(*command)
|
87
|
+
command = [command].flatten.compact # Delano
|
88
|
+
s = command.map {|word| shell_single_word(word) }.join(' ')
|
89
|
+
ShellEscaped.new_no_dup(s)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Escape.shell_single_word quotes shell meta characters.
|
93
|
+
# It returns an instance of ShellEscaped.
|
94
|
+
#
|
95
|
+
# The result string is always single shell word, even if
|
96
|
+
# the argument is "".
|
97
|
+
# Escape.shell_single_word("") returns #<Escape::ShellEscaped: ''>.
|
98
|
+
#
|
99
|
+
# Escape.shell_single_word("") #=> #<Escape::ShellEscaped: ''>
|
100
|
+
# Escape.shell_single_word("foo") #=> #<Escape::ShellEscaped: foo>
|
101
|
+
# Escape.shell_single_word("*") #=> #<Escape::ShellEscaped: '*'>
|
102
|
+
def shell_single_word(str)
|
103
|
+
return unless str
|
104
|
+
str &&= str.to_s # Delano fix
|
105
|
+
if str.empty?
|
106
|
+
ShellEscaped.new_no_dup("''")
|
107
|
+
elsif %r{\A[0-9A-Za-z+,./:=@_-]+\z} =~ str
|
108
|
+
ShellEscaped.new(str)
|
109
|
+
else
|
110
|
+
result = ''
|
111
|
+
str.scan(/('+)|[^']+/) {
|
112
|
+
if $1
|
113
|
+
result << %q{\'} * $1.length
|
114
|
+
else
|
115
|
+
result << "'#{$&}'"
|
116
|
+
end
|
117
|
+
}
|
118
|
+
ShellEscaped.new_no_dup(result)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class PercentEncoded < StringWrapper #:nodoc:all
|
123
|
+
end
|
124
|
+
|
125
|
+
# Escape.uri_segment escapes URI segment using percent-encoding.
|
126
|
+
# It returns an instance of PercentEncoded.
|
127
|
+
#
|
128
|
+
# Escape.uri_segment("a/b") #=> #<Escape::PercentEncoded: a%2Fb>
|
129
|
+
#
|
130
|
+
# The segment is "/"-splitted element after authority before query in URI, as follows.
|
131
|
+
#
|
132
|
+
# scheme://authority/segment1/segment2/.../segmentN?query#fragment
|
133
|
+
#
|
134
|
+
# See RFC 3986 for details of URI.
|
135
|
+
def uri_segment(str)
|
136
|
+
# pchar - pct-encoded = unreserved / sub-delims / ":" / "@"
|
137
|
+
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
138
|
+
# sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
139
|
+
s = str.gsub(%r{[^A-Za-z0-9\-._~!$&'()*+,;=:@]}n) {
|
140
|
+
'%' + $&.unpack("H2")[0].upcase
|
141
|
+
}
|
142
|
+
PercentEncoded.new_no_dup(s)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Escape.uri_path escapes URI path using percent-encoding.
|
146
|
+
# The given path should be a sequence of (non-escaped) segments separated by "/".
|
147
|
+
# The segments cannot contains "/".
|
148
|
+
# It returns an instance of PercentEncoded.
|
149
|
+
#
|
150
|
+
# Escape.uri_path("a/b/c") #=> #<Escape::PercentEncoded: a/b/c>
|
151
|
+
# Escape.uri_path("a?b/c?d/e?f") #=> #<Escape::PercentEncoded: a%3Fb/c%3Fd/e%3Ff>
|
152
|
+
#
|
153
|
+
# The path is the part after authority before query in URI, as follows.
|
154
|
+
#
|
155
|
+
# scheme://authority/path#fragment
|
156
|
+
#
|
157
|
+
# See RFC 3986 for details of URI.
|
158
|
+
#
|
159
|
+
# Note that this function is not appropriate to convert OS path to URI.
|
160
|
+
def uri_path(str)
|
161
|
+
s = str.gsub(%r{[^/]+}n) { uri_segment($&) }
|
162
|
+
PercentEncoded.new_no_dup(s)
|
163
|
+
end
|
164
|
+
|
165
|
+
def html_form_fast(pairs, sep='&')
|
166
|
+
s = pairs.map {|k, v|
|
167
|
+
# query-chars - pct-encoded - x-www-form-urlencoded-delimiters =
|
168
|
+
# unreserved / "!" / "$" / "'" / "(" / ")" / "*" / "," / ":" / "@" / "/" / "?"
|
169
|
+
# query-char - pct-encoded = unreserved / sub-delims / ":" / "@" / "/" / "?"
|
170
|
+
# query-char = pchar / "/" / "?" = unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?"
|
171
|
+
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
172
|
+
# sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
173
|
+
# x-www-form-urlencoded-delimiters = "&" / "+" / ";" / "="
|
174
|
+
k = k.gsub(%r{[^0-9A-Za-z\-\._~:/?@!\$'()*,]}n) {
|
175
|
+
'%' + $&.unpack("H2")[0].upcase
|
176
|
+
}
|
177
|
+
v = v.gsub(%r{[^0-9A-Za-z\-\._~:/?@!\$'()*,]}n) {
|
178
|
+
'%' + $&.unpack("H2")[0].upcase
|
179
|
+
}
|
180
|
+
"#{k}=#{v}"
|
181
|
+
}.join(sep)
|
182
|
+
PercentEncoded.new_no_dup(s)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Escape.html_form composes HTML form key-value pairs as a x-www-form-urlencoded encoded string.
|
186
|
+
# It returns an instance of PercentEncoded.
|
187
|
+
#
|
188
|
+
# Escape.html_form takes an array of pair of strings or
|
189
|
+
# an hash from string to string.
|
190
|
+
#
|
191
|
+
# Escape.html_form([["a","b"], ["c","d"]]) #=> #<Escape::PercentEncoded: a=b&c=d>
|
192
|
+
# Escape.html_form({"a"=>"b", "c"=>"d"}) #=> #<Escape::PercentEncoded: a=b&c=d>
|
193
|
+
#
|
194
|
+
# In the array form, it is possible to use same key more than once.
|
195
|
+
# (It is required for a HTML form which contains
|
196
|
+
# checkboxes and select element with multiple attribute.)
|
197
|
+
#
|
198
|
+
# Escape.html_form([["k","1"], ["k","2"]]) #=> #<Escape::PercentEncoded: k=1&k=2>
|
199
|
+
#
|
200
|
+
# If the strings contains characters which must be escaped in x-www-form-urlencoded,
|
201
|
+
# they are escaped using %-encoding.
|
202
|
+
#
|
203
|
+
# Escape.html_form([["k=","&;="]]) #=> #<Escape::PercentEncoded: k%3D=%26%3B%3D>
|
204
|
+
#
|
205
|
+
# The separator can be specified by the optional second argument.
|
206
|
+
#
|
207
|
+
# Escape.html_form([["a","b"], ["c","d"]], ";") #=> #<Escape::PercentEncoded: a=b;c=d>
|
208
|
+
#
|
209
|
+
# See HTML 4.01 for details.
|
210
|
+
def html_form(pairs, sep='&')
|
211
|
+
r = ''
|
212
|
+
first = true
|
213
|
+
pairs.each {|k, v|
|
214
|
+
# query-chars - pct-encoded - x-www-form-urlencoded-delimiters =
|
215
|
+
# unreserved / "!" / "$" / "'" / "(" / ")" / "*" / "," / ":" / "@" / "/" / "?"
|
216
|
+
# query-char - pct-encoded = unreserved / sub-delims / ":" / "@" / "/" / "?"
|
217
|
+
# query-char = pchar / "/" / "?" = unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?"
|
218
|
+
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
219
|
+
# sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
220
|
+
# x-www-form-urlencoded-delimiters = "&" / "+" / ";" / "="
|
221
|
+
r << sep if !first
|
222
|
+
first = false
|
223
|
+
k.each_byte {|byte|
|
224
|
+
ch = byte.chr
|
225
|
+
if %r{[^0-9A-Za-z\-\._~:/?@!\$'()*,]}n =~ ch
|
226
|
+
r << "%" << ch.unpack("H2")[0].upcase
|
227
|
+
else
|
228
|
+
r << ch
|
229
|
+
end
|
230
|
+
}
|
231
|
+
r << '='
|
232
|
+
v.each_byte {|byte|
|
233
|
+
ch = byte.chr
|
234
|
+
if %r{[^0-9A-Za-z\-\._~:/?@!\$'()*,]}n =~ ch
|
235
|
+
r << "%" << ch.unpack("H2")[0].upcase
|
236
|
+
else
|
237
|
+
r << ch
|
238
|
+
end
|
239
|
+
}
|
240
|
+
}
|
241
|
+
PercentEncoded.new_no_dup(r)
|
242
|
+
end
|
243
|
+
|
244
|
+
class HTMLEscaped < StringWrapper #:nodoc:all
|
245
|
+
end
|
246
|
+
|
247
|
+
HTML_TEXT_ESCAPE_HASH = {
|
248
|
+
'&' => '&',
|
249
|
+
'<' => '<',
|
250
|
+
'>' => '>',
|
251
|
+
}
|
252
|
+
|
253
|
+
|
254
|
+
# Escape.html_text escapes a string appropriate for HTML text using character references.
|
255
|
+
# It returns an instance of HTMLEscaped.
|
256
|
+
#
|
257
|
+
# It escapes 3 characters:
|
258
|
+
# * '&' to '&'
|
259
|
+
# * '<' to '<'
|
260
|
+
# * '>' to '>'
|
261
|
+
#
|
262
|
+
# Escape.html_text("abc") #=> #<Escape::HTMLEscaped: abc>
|
263
|
+
# Escape.html_text("a & b < c > d") #=> #<Escape::HTMLEscaped: a & b < c > d>
|
264
|
+
#
|
265
|
+
# This function is not appropriate for escaping HTML element attribute
|
266
|
+
# because quotes are not escaped.
|
267
|
+
def html_text(str) #:nodoc:all
|
268
|
+
s = str.gsub(/[&<>]/) {|ch| HTML_TEXT_ESCAPE_HASH[ch] }
|
269
|
+
HTMLEscaped.new_no_dup(s)
|
270
|
+
end
|
271
|
+
|
272
|
+
HTML_ATTR_ESCAPE_HASH = { #:nodoc:all
|
273
|
+
'&' => '&',
|
274
|
+
'<' => '<',
|
275
|
+
'>' => '>',
|
276
|
+
'"' => '"',
|
277
|
+
}
|
278
|
+
|
279
|
+
|
280
|
+
class HTMLAttrValue < StringWrapper #:nodoc:all
|
281
|
+
end
|
282
|
+
|
283
|
+
# Escape.html_attr_value encodes a string as a double-quoted HTML attribute using character references.
|
284
|
+
# It returns an instance of HTMLAttrValue.
|
285
|
+
#
|
286
|
+
# Escape.html_attr_value("abc") #=> #<Escape::HTMLAttrValue: "abc">
|
287
|
+
# Escape.html_attr_value("a&b") #=> #<Escape::HTMLAttrValue: "a&b">
|
288
|
+
# Escape.html_attr_value("ab&<>\"c") #=> #<Escape::HTMLAttrValue: "ab&<>"c">
|
289
|
+
# Escape.html_attr_value("a'c") #=> #<Escape::HTMLAttrValue: "a'c">
|
290
|
+
#
|
291
|
+
# It escapes 4 characters:
|
292
|
+
# * '&' to '&'
|
293
|
+
# * '<' to '<'
|
294
|
+
# * '>' to '>'
|
295
|
+
# * '"' to '"'
|
296
|
+
#
|
297
|
+
def html_attr_value(str) #:nodoc:all
|
298
|
+
s = '"' + str.gsub(/[&<>"]/) {|ch| HTML_ATTR_ESCAPE_HASH[ch] } + '"'
|
299
|
+
HTMLAttrValue.new_no_dup(s)
|
300
|
+
end
|
301
|
+
end
|
data/lib/rye.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
|
2
|
+
require 'rubygems' unless defined? Gem
|
3
|
+
|
4
|
+
require 'net/ssh'
|
5
|
+
require 'thread'
|
6
|
+
require 'highline'
|
7
|
+
require 'esc'
|
8
|
+
require 'sys'
|
9
|
+
|
10
|
+
# = Rye
|
11
|
+
#
|
12
|
+
# Run system commands via SSH locally and remotely in a Ruby way.
|
13
|
+
#
|
14
|
+
# Rye is similar to Rush[http://rush.heroku.com] but everything
|
15
|
+
# happens over SSH (no HTTP daemon) and the default settings are
|
16
|
+
# less powerful (for safety). For example, file globs are disabled
|
17
|
+
# so unless otherwise specified, you can't do this:
|
18
|
+
# <tt>rbox.rm('/etc/**/*')</tt>.
|
19
|
+
#
|
20
|
+
# * See +bin/try+ for a bunch of working examples.
|
21
|
+
# * See Rye::Box#initialize for info about disabling safe-mode.
|
22
|
+
#
|
23
|
+
module Rye
|
24
|
+
extend self
|
25
|
+
|
26
|
+
unless defined?(SYSINFO)
|
27
|
+
VERSION = 0.3.freeze
|
28
|
+
SYSINFO = SystemInfo.new.freeze
|
29
|
+
end
|
30
|
+
|
31
|
+
@@agent_env = Hash.new # holds ssh-agent env vars
|
32
|
+
@@mutex = Mutex.new # for synchronizing threads
|
33
|
+
|
34
|
+
# Accessor for an instance of SystemInfo
|
35
|
+
def Rye.sysinfo; SYSINFO; end
|
36
|
+
|
37
|
+
# Accessor for an instance of SystemInfo
|
38
|
+
def sysinfo; SYSINFO; end
|
39
|
+
|
40
|
+
class CommandNotFound < RuntimeError; end
|
41
|
+
class NoBoxes < RuntimeError; end
|
42
|
+
class NoHost < RuntimeError; end
|
43
|
+
class NotConnected < RuntimeError; end
|
44
|
+
|
45
|
+
# Reload Rye dynamically. Useful with irb.
|
46
|
+
# NOTE: does not reload rye.rb.
|
47
|
+
def reload
|
48
|
+
pat = File.join(File.dirname(__FILE__), 'rye')
|
49
|
+
%w{rap cmd box set}.each {|lib| load File.join(pat, "#{lib}.rb") }
|
50
|
+
end
|
51
|
+
|
52
|
+
def mutex
|
53
|
+
@@mutex
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# Add one or more private keys to the SSH Agent.
|
58
|
+
# * +keys+ one or more file paths to private keys used for passwordless logins.
|
59
|
+
def add_keys(*keys)
|
60
|
+
keys = [keys].flatten.compact || []
|
61
|
+
return if keys.empty?
|
62
|
+
Rye::Box.shell("ssh-add", keys) if keys
|
63
|
+
Rye::Box.shell("ssh-add") # Add the user's default keys
|
64
|
+
keys
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns an Array of info about the currently available
|
68
|
+
# SSH keys, as provided by the SSH Agent. See
|
69
|
+
# Rye.start_sshagent_environment
|
70
|
+
#
|
71
|
+
# Returns: [[bits, finger-print, file-path], ...]
|
72
|
+
#
|
73
|
+
def keys
|
74
|
+
# 2048 76:cb:d7:82:90:92:ad:75:3d:68:6c:a9:21:ca:7b:7f /Users/rye/.ssh/id_rsa (RSA)
|
75
|
+
# 2048 7b:a6:ba:55:b1:10:1d:91:9f:73:3a:aa:0c:d4:88:0e /Users/rye/.ssh/id_dsa (DSA)
|
76
|
+
keystr = Rye::Box.shell("ssh-add", '-l')
|
77
|
+
return nil unless keystr
|
78
|
+
keystr.split($/).collect do |key|
|
79
|
+
key.split(/\s+/)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Start the SSH Agent locally. This is important
|
86
|
+
# primarily because Rye relies on it for SSH key
|
87
|
+
# management. If the agent doesn't start then
|
88
|
+
# passwordless logins won't work.
|
89
|
+
#
|
90
|
+
# This method starts an instances of ssh-agent
|
91
|
+
# and sets the appropriate environment so all
|
92
|
+
# local commands run by Rye will have access be aware
|
93
|
+
# of this instance of the agent too.
|
94
|
+
#
|
95
|
+
# The equivalent commands on the shell are:
|
96
|
+
#
|
97
|
+
# $ ssh-agent -s
|
98
|
+
# SSH_AUTH_SOCK=/tmp/ssh-tGvaOXIXSr/agent.12951; export SSH_AUTH_SOCK;
|
99
|
+
# SSH_AGENT_PID=12952; export SSH_AGENT_PID;
|
100
|
+
# $ SSH_AUTH_SOCK=/tmp/ssh-tGvaOXIXSr/agent.12951; export SSH_AUTH_SOCK;
|
101
|
+
# $ SSH_AGENT_PID=12952; export SSH_AGENT_PID;
|
102
|
+
#
|
103
|
+
# NOTE: The OpenSSL library (The C one, not the Ruby one)
|
104
|
+
# must be installed for this to work.
|
105
|
+
#
|
106
|
+
def start_sshagent_environment
|
107
|
+
return if @@agent_env["SSH_AGENT_PID"]
|
108
|
+
|
109
|
+
lines = Rye::Box.shell("ssh-agent", '-s') || ''
|
110
|
+
lines.split($/).each do |line|
|
111
|
+
next unless line.index("echo").nil?
|
112
|
+
line = line.slice(0..(line.index(';')-1))
|
113
|
+
key, value = line.chomp.split( /=/ )
|
114
|
+
@@agent_env[key] = value
|
115
|
+
end
|
116
|
+
ENV["SSH_AUTH_SOCK"] = @@agent_env["SSH_AUTH_SOCK"]
|
117
|
+
ENV["SSH_AGENT_PID"] = @@agent_env["SSH_AGENT_PID"]
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
|
121
|
+
# Kill the local instance of the SSH Agent we started.
|
122
|
+
#
|
123
|
+
# Calls this command via the local shell:
|
124
|
+
#
|
125
|
+
# $ ssh-agent -k
|
126
|
+
#
|
127
|
+
# which uses the SSH_AUTH_SOCK and SSH_AGENT_PID environment variables
|
128
|
+
# to determine which ssh-agent to kill.
|
129
|
+
#
|
130
|
+
def end_sshagent_environment
|
131
|
+
pid = @@agent_env["SSH_AGENT_PID"]
|
132
|
+
Rye::Box.shell("ssh-agent", '-k') || ''
|
133
|
+
#Rye::Box.shell("kill", ['-9', pid]) if pid
|
134
|
+
@@agent_env.clear
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
|
138
|
+
Rye.reload
|
139
|
+
|
140
|
+
begin
|
141
|
+
@@mutex.synchronize { # One thread only
|
142
|
+
start_sshagent_environment # Run this now
|
143
|
+
at_exit { end_sshagent_environment } # Run this before Ruby exits
|
144
|
+
}
|
145
|
+
rescue => ex
|
146
|
+
STDERR.puts "Error initializing the SSH Agent (is OpenSSL installed?):"
|
147
|
+
STDERR.puts ex.message
|
148
|
+
exit 1
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
|
155
|
+
|