Skip to content

Commit

Permalink
Merge pull request #237 from robd/simplify-backend-hierarchy
Browse files Browse the repository at this point in the history
Simplify backend hierarchy
  • Loading branch information
leehambley committed Apr 26, 2015
2 parents b9886c7 + 58db2d1 commit 81aa347
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 281 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ appear at the top.

* Add your entries below here, remember to credit yourself however you want
to be credited!
* Simplified backend hierarchy. @robd
* Moved duplicate implementations of `make`, `rake`, `test`, `capture`, `background` on to `Abstract` backend.
* Backend implementations now only need to implement `execute_command`, `upload!` and `download!`
* Removed `Printer` from backend hierarchy for `Local` and `Netssh` backends (they now just extend `Abstract`)
* Removed unused `Net::SSH:LogLevelShim`

## 1.7.1

Expand Down
44 changes: 33 additions & 11 deletions lib/sshkit/backends/abstract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Abstract
attr_reader :host

def run
# Nothing to do
instance_exec(@host, &@block)
end

def initialize(host, &block)
Expand Down Expand Up @@ -47,23 +47,32 @@ def trace(messages)
end

def make(commands=[])
raise MethodUnavailableError
execute :make, commands
end

def rake(commands=[])
raise MethodUnavailableError
execute :rake, commands
end

def test(command, args=[])
raise MethodUnavailableError
def test(*args)
options = args.extract_options!.merge(raise_on_non_zero_exit: false, verbosity: Logger::DEBUG)
create_command_and_execute(args, options).success?
end

def execute(command, args=[])
raise MethodUnavailableError
def capture(*args)
options = { verbosity: Logger::DEBUG }.merge(args.extract_options!)
create_command_and_execute(args, options).full_stdout
end

def capture(command, args=[])
raise MethodUnavailableError
def background(*args)
warn "[Deprecated] The background method is deprecated. Blame badly behaved pseudo-daemons!"
options = args.extract_options!.merge(run_in_background: true)
create_command_and_execute(args, options).success?
end

def execute(*args)
options = args.extract_options!
create_command_and_execute(args, options).success?
end

def within(directory, &block)
Expand Down Expand Up @@ -118,10 +127,23 @@ def configure
end
end

# Backends which extend the Abstract backend should implement the following methods:
def upload!(local, remote, options = {}) raise MethodUnavailableError end
def download!(remote, local=nil, options = {}) raise MethodUnavailableError end
def execute_command(cmd) raise MethodUnavailableError end
private :execute_command # Can inline after Ruby 2.1

private

def command(*args)
options = args.extract_options!
def output
SSHKit.config.output
end

def create_command_and_execute(args, options)
command(args, options).tap { |cmd| execute_command(cmd) }
end

def command(args, options)
SSHKit::Command.new(*[*args, options.merge({in: @pwd.nil? ? nil : File.join(@pwd), env: @env, host: @host, user: @user, group: @group})])
end

Expand Down
69 changes: 23 additions & 46 deletions lib/sshkit/backends/local.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,13 @@ module SSHKit

module Backend

class Local < Printer
class Local < Abstract

def initialize(_ = nil, &block)
@host = Host.new(:local) # just for logging
@block = block
end

def run
instance_exec(@host, &@block)
end

def test(*args)
options = args.extract_options!.merge(
raise_on_non_zero_exit: false,
verbosity: Logger::DEBUG
)
_execute(*[*args, options]).success?
end

def execute(*args)
_execute(*args).success?
end

def capture(*args)
options = { verbosity: Logger::DEBUG }.merge(args.extract_options!)
_execute(*[*args, options]).full_stdout
end

def upload!(local, remote, options = {})
if local.is_a?(String)
FileUtils.cp(local, remote)
Expand All @@ -54,40 +33,38 @@ def download!(remote, local=nil, options = {})

private

def _execute(*args)
command(*args).tap do |cmd|
output << cmd
def execute_command(cmd)
output << cmd

cmd.started = Time.now
cmd.started = Time.now

Open3.popen3(cmd.to_command) do |stdin, stdout, stderr, wait_thr|
stdout_thread = Thread.new do
while line = stdout.gets do
cmd.stdout = line
cmd.full_stdout += line
Open3.popen3(cmd.to_command) do |stdin, stdout, stderr, wait_thr|
stdout_thread = Thread.new do
while line = stdout.gets do
cmd.stdout = line
cmd.full_stdout += line

output << cmd
end
output << cmd
end
end

stderr_thread = Thread.new do
while line = stderr.gets do
cmd.stderr = line
cmd.full_stderr += line
stderr_thread = Thread.new do
while line = stderr.gets do
cmd.stderr = line
cmd.full_stderr += line

output << cmd
end
output << cmd
end
end

stdout_thread.join
stderr_thread.join
stdout_thread.join
stderr_thread.join

cmd.exit_status = wait_thr.value.to_i
cmd.stdout = ''
cmd.stderr = ''
cmd.exit_status = wait_thr.value.to_i
cmd.stdout = ''
cmd.stderr = ''

output << cmd
end
output << cmd
end
end

Expand Down
143 changes: 49 additions & 94 deletions lib/sshkit/backends/netssh.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,9 @@ def default_files

module SSHKit

class Logger

class Net::SSH::LogLevelShim
attr_reader :output
def initialize(output)
@output = output
end
def debug(args)
output << LogMessage.new(Logger::TRACE, args)
end
def error(args)
output << LogMessage.new(Logger::ERROR, args)
end
def lwarn(args)
output << LogMessage.new(Logger::WARN, args)
end
end

end

module Backend

class Netssh < Printer
class Netssh < Abstract

class Configuration
attr_accessor :connection_timeout, :pty
Expand All @@ -48,33 +28,10 @@ def ssh_options
end
end

include SSHKit::CommandHelper

def run
instance_exec(host, &@block)
end

def test(*args)
options = args.extract_options!.merge(
raise_on_non_zero_exit: false,
verbosity: Logger::DEBUG
)
_execute(*[*args, options]).success?
end

def execute(*args)
_execute(*args).success?
end

def background(*args)
warn "[Deprecated] The background method is deprecated. Blame badly behaved pseudo-daemons!"
options = args.extract_options!.merge(run_in_background: true)
_execute(*[*args, options]).success?
end

def capture(*args)
options = { verbosity: Logger::DEBUG }.merge(args.extract_options!)
_execute(*[*args, options]).full_stdout.strip
# The behaviour to strip the full stdout was removed from the local backend in commit 7d15a9a,
# but was left in for the net ssh backend.
super(*args).strip
end

def upload!(local, remote, options = {})
Expand Down Expand Up @@ -129,56 +86,54 @@ def transfer_summarizer(action)
end
end

def _execute(*args)
command(*args).tap do |cmd|
output << cmd
cmd.started = true
exit_status = nil
with_ssh do |ssh|
ssh.open_channel do |chan|
chan.request_pty if Netssh.config.pty
chan.exec cmd.to_command do |ch, success|
chan.on_data do |ch, data|
cmd.stdout = data
cmd.full_stdout += data
output << cmd
end
chan.on_extended_data do |ch, type, data|
cmd.stderr = data
cmd.full_stderr += data
output << cmd
end
chan.on_request("exit-status") do |ch, data|
exit_status = data.read_long
end
#chan.on_request("exit-signal") do |ch, data|
# # TODO: This gets called if the program is killed by a signal
# # might also be a worthwhile thing to report
# exit_signal = data.read_string.to_i
# warn ">>> " + exit_signal.inspect
# output << cmd
#end
chan.on_open_failed do |ch|
# TODO: What do do here?
# I think we should raise something
end
chan.on_process do |ch|
# TODO: I don't know if this is useful
end
chan.on_eof do |ch|
# TODO: chan sends EOF before the exit status has been
# writtend
end
def execute_command(cmd)
output << cmd
cmd.started = true
exit_status = nil
with_ssh do |ssh|
ssh.open_channel do |chan|
chan.request_pty if Netssh.config.pty
chan.exec cmd.to_command do |ch, success|
chan.on_data do |ch, data|
cmd.stdout = data
cmd.full_stdout += data
output << cmd
end
chan.on_extended_data do |ch, type, data|
cmd.stderr = data
cmd.full_stderr += data
output << cmd
end
chan.on_request("exit-status") do |ch, data|
exit_status = data.read_long
end
#chan.on_request("exit-signal") do |ch, data|
# # TODO: This gets called if the program is killed by a signal
# # might also be a worthwhile thing to report
# exit_signal = data.read_string.to_i
# warn ">>> " + exit_signal.inspect
# output << cmd
#end
chan.on_open_failed do |ch|
# TODO: What do do here?
# I think we should raise something
end
chan.on_process do |ch|
# TODO: I don't know if this is useful
end
chan.on_eof do |ch|
# TODO: chan sends EOF before the exit status has been
# writtend
end
chan.wait
end
ssh.loop
end
# Set exit_status and log the result upon completion
if exit_status
cmd.exit_status = exit_status
output << cmd
chan.wait
end
ssh.loop
end
# Set exit_status and log the result upon completion
if exit_status
cmd.exit_status = exit_status
output << cmd
end
end

Expand Down
25 changes: 2 additions & 23 deletions lib/sshkit/backends/printer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,12 @@ module Backend

class Printer < Abstract

include SSHKit::CommandHelper

def run
instance_exec(host, &@block)
end

def execute(*args)
command(*args).tap do |cmd|
output << cmd
end
def execute_command(cmd)
output << cmd
end
alias :upload! :execute
alias :download! :execute
alias :test :execute

def capture(*args)
String.new.tap { execute(*args) }
end
alias :capture! :capture


private

def output
SSHKit.config.output
end

end
end
end
Loading

0 comments on commit 81aa347

Please sign in to comment.