lib/remote/session.rb in remote-session-0.0.2 vs lib/remote/session.rb in remote-session-0.0.3

- old
+ new

@@ -1,8 +1,10 @@ +require 'remote/session/send_file' require 'remote/session/version' require 'net/sftp' require 'net/ssh' +require 'base64' module Remote class Session SUDO_PROMPT = 'sudo_prompt' @@ -39,45 +41,33 @@ raise "Session is closed" if @session.nil? puts "@#{ @host }: #{ command }" puts @session.exec!( command ) end - def sudo( command ) + def sudo( commands ) raise "Session is closed" if @session.nil? + commands = [ *commands ] - puts "@#{ @host }: sudo #{ command }" @session.open_channel do |ch| ch.request_pty do |ch, success| raise "Could not obtain pty" if ! success - channel_exec ch, command + channel_exec ch, commands end end @session.loop end def close @session.close @session = nil end - def sudo_put( remote_path, &block ) - temp_path = "/tmp/remote-session.#{ Time.now.to_f }" - run "mkdir #{ temp_path }" - run "chmod 0700 #{ temp_path }" - - temp_file = File.join( temp_path, File.basename( remote_path ) ) - put temp_file, &block - - sudo "cp -f #{ temp_file } #{ remote_path }" - run "rm -rf #{ temp_path }" - end - def put( remote_path, &block ) sftp = Net::SFTP::Session.new( @session ).connect! sftp.file.open( remote_path, 'w' ) do |f| - f.puts block.call + f.write block.call end sftp.close_channel end private @@ -92,31 +82,72 @@ def connect @session = Net::SSH.start( @host, @username, ssh_options ) end - def channel_exec( ch, command ) - ch.exec "sudo -p '#{ SUDO_PROMPT }' #{ command }" do |ch, success| - raise "Could not execute sudo command: #{ command }" if ! success + def channel_exec( ch, commands ) + ch[ :commands ] = commands - ch.on_data do | ch, data | - if data =~ Regexp.new( SUDO_PROMPT ) - ch.send_data "#{ @sudo_password }\n" - else - prompt_matched = false - @prompts.each_pair do | prompt, send | - if data =~ Regexp.new( prompt ) - ch.send_data "#{ send }\n" - prompt_matched = true - end - end - puts data if ! prompt_matched - end - end + ch.exec "sudo -k -p '#{ SUDO_PROMPT }' su -" do |ch, success| + raise "Could not execute sudo su command" if ! success + ch.on_data( &method( :on_data ) ) + ch.on_extended_data do |ch, type, data| - raise "Error #{ data } while performing command: #{ command }" + $stderr.puts data end + end + end + + def on_data( ch, data ) + if data =~ Regexp.new( SUDO_PROMPT ) + ch.send_data "#{ @sudo_password }\n" + return + end + + @prompts.each_pair do | prompt, send | + if data =~ Regexp.new( prompt ) + ch.send_data "#{ send }\n" + return + end + end + + $stdout.write( data ) + + if ch[ :commands ].size == 0 + ch.send_data "exit\n" + return + end + + command = ch[ :commands ].shift + if command.is_a?( Remote::Session::SendFile ) + send_file_chunk( ch, command ) + else + ch.send_data "#{command}\n" + end + end + + def send_file_chunk( ch, send_file ) + if send_file.open? + operator = '>>' + else + send_file.open + operator = '>' + end + + chunk = + if ! send_file.eof? + Base64.encode64( send_file.read ) + else + # Handle empty files + '' + end + ch.send_data "echo -n '#{ chunk }' | base64 -d #{ operator } #{ send_file.remote_path }\n" + + if send_file.eof? + send_file.close + else + ch[ :commands ].unshift send_file end end end end