class Net::SSH::Shell
Constants
- VERSION
Attributes
channel[R]
default_process_class[RW]
processes[R]
session[R]
shell[R]
state[R]
Public Class Methods
new(session, shell = :default)
click to toggle source
# File lib/net/ssh/shell.rb, line 14 def initialize(session, shell = :default) @session = session @shell = shell @state = :closed @processes = [] @when_open = [] @on_process_run = nil @default_process_class = Net::SSH::Shell::Process open end
Public Instance Methods
busy?()
click to toggle source
# File lib/net/ssh/shell.rb, line 94 def busy? opening? || processes.any? end
child_finished(child)
click to toggle source
# File lib/net/ssh/shell.rb, line 106 def child_finished(child) channel.on_close(&method(:on_channel_close)) unless channel.nil? processes.delete(child) run_next_process end
close!()
click to toggle source
# File lib/net/ssh/shell.rb, line 102 def close! channel.close if channel end
closed?()
click to toggle source
# File lib/net/ssh/shell.rb, line 57 def closed? state == :closed end
execute(command, *args, &callback)
click to toggle source
# File lib/net/ssh/shell.rb, line 69 def execute(command, *args, &callback) # The class is an optional second argument. klass = default_process_class klass = args.shift if args.first.is_a?(Class) # The properties are expected to be the next argument. props = {} props = args.shift if args.first.is_a?(Hash) process = klass.new(self, command, props, callback) processes << process run_next_process if processes.length == 1 process end
execute!(command, &callback)
click to toggle source
# File lib/net/ssh/shell.rb, line 88 def execute!(command, &callback) process = execute(command, &callback) wait! process end
on_channel_close(_channel)
click to toggle source
# File lib/net/ssh/shell.rb, line 122 def on_channel_close(_channel) @state = :closed @channel = nil end
on_process_run(&callback)
click to toggle source
# File lib/net/ssh/shell.rb, line 65 def on_process_run(&callback) @on_process_run = callback end
open(&callback)
click to toggle source
# File lib/net/ssh/shell.rb, line 25 def open(&callback) if closed? @state = :opening @channel = session.open_channel(&method(:open_succeeded)) @channel.on_open_failed(&method(:open_failed)) @channel.on_request('exit-status', &method(:on_exit_status)) end when_open(&callback) if callback self end
open!()
click to toggle source
# File lib/net/ssh/shell.rb, line 36 def open! unless open? open if closed? session.loop { opening? } end self end
open?()
click to toggle source
# File lib/net/ssh/shell.rb, line 53 def open? state == :open end
opening?()
click to toggle source
# File lib/net/ssh/shell.rb, line 61 def opening? !open? && !closed? end
separator()
click to toggle source
# File lib/net/ssh/shell.rb, line 112 def separator @separator ||= begin s = Digest::SHA1.hexdigest( [session.object_id, object_id, Time.now.to_i, Time.now.usec, rand(0xFFFFFFFF)].join(':') ) s << Digest::SHA1.hexdigest(s) end end
subshell(command, &callback)
click to toggle source
# File lib/net/ssh/shell.rb, line 84 def subshell(command, &callback) execute(command, Net::SSH::Shell::Subshell, &callback) end
wait!()
click to toggle source
# File lib/net/ssh/shell.rb, line 98 def wait! session.loop { busy? } end
when_open() { |self| ... }
click to toggle source
# File lib/net/ssh/shell.rb, line 44 def when_open(&callback) if open? yield self else @when_open << callback end self end
Private Instance Methods
look_for_initialization_done(_channel, data)
click to toggle source
# File lib/net/ssh/shell.rb, line 168 def look_for_initialization_done(_channel, data) return unless data.include?(separator) @state = :open @when_open.each { |callback| callback.call(self) } @when_open.clear end
on_exit_status(_channel, data)
click to toggle source
# File lib/net/ssh/shell.rb, line 147 def on_exit_status(_channel, data) fail 'the shell exited unexpectedly' unless data.read_long == 0 end
open_failed(_channel, code, description)
click to toggle source
# File lib/net/ssh/shell.rb, line 142 def open_failed(_channel, code, description) @state = :closed fail "could not open channel for process manager (#{description}, ##{code})" end
open_succeeded(channel)
click to toggle source
# File lib/net/ssh/shell.rb, line 136 def open_succeeded(channel) @state = :pty channel.on_close(&method(:on_channel_close)) channel.request_pty(modes: { Net::SSH::Connection::Term::ECHO => 0 }, &method(:pty_requested)) end
pty_requested(channel, success)
click to toggle source
# File lib/net/ssh/shell.rb, line 151 def pty_requested(channel, success) @state = :shell fail 'could not request pty for process manager' unless success if shell == :default channel.send_channel_request('shell', &method(:shell_requested)) else channel.exec(shell, &method(:shell_requested)) end end
run_next_process()
click to toggle source
# File lib/net/ssh/shell.rb, line 129 def run_next_process return unless processes.any? process = processes.first @on_process_run.call(self, process) if @on_process_run process.run end
shell_requested(channel, success)
click to toggle source
# File lib/net/ssh/shell.rb, line 161 def shell_requested(channel, success) @state = :initializing fail 'could not request shell for process manager' unless success channel.on_data(&method(:look_for_initialization_done)) channel.send_data "export PS1=; echo #{separator} $?\n" end