From 3b3b5f8fba95394c25dc4f4f57dcba02f0237c30 Mon Sep 17 00:00:00 2001 From: Caleb Crane Date: Tue, 26 Mar 2013 11:33:03 +0000 Subject: [PATCH] adds executable tests for README examples; removes CWI hanging pry --- .gitignore | 1 - Gemfile | 1 - Gemfile.lock | 8 ------- README.md | 24 ++++++++++--------- readme/1.rb | 55 ++++++++++++++++++++++++++++++++++++++++++++ readme/2.rb | 21 +++++++++++++++++ readme/3.rb | 46 ++++++++++++++++++++++++++++++++++++ readme/4.rb | 46 ++++++++++++++++++++++++++++++++++++ readme/arg-parser.rb | 17 ++++++++++++++ 9 files changed, 198 insertions(+), 21 deletions(-) create mode 100755 readme/1.rb create mode 100755 readme/2.rb create mode 100755 readme/3.rb create mode 100755 readme/4.rb create mode 100644 readme/arg-parser.rb diff --git a/.gitignore b/.gitignore index 4c77bbe..db3296f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -readme.*.rb tags *.gem diff --git a/Gemfile b/Gemfile index e759529..c9c6ae3 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,6 @@ source "http://rubygems.org" gem "em-ssh", :path => File.expand_path("../", __FILE__) -gem "pry" gemspec group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 54fd103..f235c2b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,16 +9,10 @@ GEM remote: http://rubygems.org/ specs: bluecloth (2.1.0) - coderay (1.0.8) diff-lcs (1.1.3) eventmachine (1.0.1) highline (1.6.13) - method_source (0.8.1) net-ssh (2.6.2) - pry (0.9.10) - coderay (~> 1.0.5) - method_source (~> 0.8) - slop (~> 3.3.1) rspec (2.6.0) rspec-core (~> 2.6.0) rspec-expectations (~> 2.6.0) @@ -28,7 +22,6 @@ GEM diff-lcs (~> 1.1.2) rspec-mocks (2.6.0) ruby-termios (0.9.6) - slop (3.3.3) yard (0.7.3) PLATFORMS @@ -38,7 +31,6 @@ DEPENDENCIES bluecloth em-ssh! highline - pry rspec (> 2.2.0) rspec-core (< 2.7.0) ruby-termios diff --git a/README.md b/README.md index 0a32f11..a16f803 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,12 @@ Em-ssh is not associated with the Jamis Buck's [net-ssh](http://net-ssh.github.c ##Synopsis ```ruby +require "em-ssh" EM.run do EM::Ssh.start(host, user, :password => password) do |connection| connection.errback do |err| $stderr.puts "#{err} (#{err.class})" + EM.stop end connection.callback do |ssh| # capture all stderr and stdout output from a remote process @@ -76,7 +78,7 @@ EM.run do EM.stop end shell.errback do |err| - puts "error: #{err} (#{err.class})" + $stderr.puts "error: #{err} (#{err.class})" EM.stop end end @@ -93,7 +95,7 @@ commands = ["uname -a", "uptime", "ifconfig"] EM.run do EM::Ssh::Shell.new(host, user, "") do |shell| shell.errback do |err| - puts "error: #{err} (#{err.class})" + $stderr.puts "error: #{err} (#{err.class})" EM.stop end @@ -107,19 +109,19 @@ EM.run do end mys.callback do - puts("waiting for: #{waitstr.inspect}") + $stderr.puts("waiting for: #{waitstr.inspect}") # When given a block, Shell#expect does not 'block' mys.expect(waitstr) do - puts "sending #{command.inspect} and waiting for #{waitstr.inspect}" + $stderr.puts "sending #{command.inspect} and waiting for #{waitstr.inspect}" mys.expect(waitstr, command) do |result| - puts "#{mys} result: '#{result}'" + $stderr.puts "#{mys} result: '#{result}'" mys.close end end end mys.errback do |err| - puts "subshell error: #{err} (#{err.class})" + $stderr.puts "subshell error: #{err} (#{err.class})" mys.close end @@ -138,8 +140,8 @@ require 'em-ssh/shell' EM.run do EM::Ssh::Shell.new(host, user, "") do |shell| shell.errback do |err| - puts "error: #{err} (#{err.class})" - puts err.backtrace + $stderr.puts "error: #{err} (#{err.class})" + $stderr.puts err.backtrace EM.stop end @@ -155,16 +157,16 @@ EM.run do EM.stop if commands.empty? end mys.errback do |err| - puts "subshell error: #{err} (#{err.class})" + $stderr.puts "subshell error: #{err} (#{err.class})" mys.close end mys.expect(waitstr) result = mys.expect(waitstr, command) - puts "#{mys} result: '#{result.inspect}'" + $stderr.puts "#{mys} result: '#{result.inspect}'" result end - puts "split result: #{sresult.inspect} +++" + $stderr.puts "split result: #{sresult.inspect} +++" }.resume end diff --git a/readme/1.rb b/readme/1.rb new file mode 100755 index 0000000..c0635f8 --- /dev/null +++ b/readme/1.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby +require File.expand_path("../arg-parser", __FILE__) + +host, user = require_host_user + +require "em-ssh" +EM.run do + EM::Ssh.start(host, user) do |connection| + connection.errback do |err| + $stderr.puts "#{err} (#{err.class})" + EM.stop + end + connection.callback do |ssh| + # capture all stderr and stdout output from a remote process + ssh.exec!('uname -a').tap {|r| puts "\nuname: #{r}"} + + # capture only stdout matching a particular pattern + stdout = "" + ssh.exec!("ls -l /home") do |channel, stream, data| + stdout << data if stream == :stdout + end + puts "\n#{stdout}" + + # run multiple processes in parallel to completion + ssh.exec('ping -c 1 www.google.com') + ssh.exec('ping -c 1 www.yahoo.com') + ssh.exec('ping -c 1 www.rakuten.co.jp') + + #open a new channel and configure a minimal set of callbacks, then wait for the channel to finishes (closees). + channel = ssh.open_channel do |ch| + ch.exec "/usr/local/bin/ruby /path/to/file.rb" do |ch, success| + raise "could not execute command" unless success + + # "on_data" is called when the process writes something to stdout + ch.on_data do |c, data| + $stdout.print data + end + + # "on_extended_data" is called when the process writes something to stderr + ch.on_extended_data do |c, type, data| + $stderr.print data + end + + ch.on_close { puts "done!" } + end + end + + channel.wait + + ssh.close + EM.stop + end + end +end + diff --git a/readme/2.rb b/readme/2.rb new file mode 100755 index 0000000..275a48a --- /dev/null +++ b/readme/2.rb @@ -0,0 +1,21 @@ +#!/usr/bin/env ruby +require File.expand_path("../arg-parser", __FILE__) + +host, user = require_host_user + +require 'em-ssh/shell' +EM.run do + EM::Ssh::Shell.new(host, user, "") do |shell| + shell.callback do + shell.expect(Regexp.escape('~]$ ')) + $stderr.puts shell.expect(Regexp.escape('~]$ '),'uname -a') + $stderr.puts shell.expect(Regexp.escape('~]$ '), '/sbin/ifconfig -a') + EM.stop + end + shell.errback do |err| + $stderr.puts "error: #{err} (#{err.class})" + EM.stop + end + end +end + diff --git a/readme/3.rb b/readme/3.rb new file mode 100755 index 0000000..bcfdcdc --- /dev/null +++ b/readme/3.rb @@ -0,0 +1,46 @@ +#!/usr/bin/env ruby +require File.expand_path("../arg-parser", __FILE__) + +host, user = require_host_user + +require 'em-ssh/shell' + +waitstr = Regexp.escape('~]$ ') +commands = ["uname -a", "uptime", "ifconfig"] +EM.run do + EM::Ssh::Shell.new(host, user, "") do |shell| + shell.errback do |err| + $stderr.puts "error: #{err} (#{err.class})" + EM.stop + end + + shell.callback do + commands.clone.each do |command| + mys = shell.split # provides a second session over the same connection + + mys.on(:closed) do + commands.delete(command) + EM.stop if commands.empty? + end + + mys.callback do + $stderr.puts("waiting for: #{waitstr.inspect}") + # When given a block, Shell#expect does not 'block' + mys.expect(waitstr) do + $stderr.puts "sending #{command.inspect} and waiting for #{waitstr.inspect}" + mys.expect(waitstr, command) do |result| + $stderr.puts "#{mys} result: '#{result}'" + mys.close + end + end + end + + mys.errback do |err| + $stderr.puts "subshell error: #{err} (#{err.class})" + mys.close + end + + end + end + end +end diff --git a/readme/4.rb b/readme/4.rb new file mode 100755 index 0000000..ac7c7ec --- /dev/null +++ b/readme/4.rb @@ -0,0 +1,46 @@ +#!/usr/bin/env ruby +require "em-ssh" +require File.expand_path("../arg-parser", __FILE__) + +host, user = require_host_user + +waitstr = Regexp.escape('~]$ ') +commands = ["uname -a", "uptime", "ifconfig"] + +require 'em-ssh/shell' +EM.run do + EM::Ssh::Shell.new(host, user, "") do |shell| + shell.errback do |err| + $stderr.puts "error: #{err} (#{err.class})" + $stderr.puts err.backtrace + EM.stop + end + + shell.callback do + commands.clone.each do |command| + Fiber.new { + # When given a block Shell#split will close the Shell after + # the block returns. If a block is given it must be called + # within a Fiber. + sresult = shell.split do |mys| + mys.on(:closed) do + commands.delete(command) + EM.stop if commands.empty? + end + mys.errback do |err| + $stderr.puts "subshell error: #{err} (#{err.class})" + mys.close + end + + mys.expect(waitstr) + result = mys.expect(waitstr, command) + $stderr.puts "#{mys} result: '#{result.inspect}'" + result + end + $stderr.puts "split result: #{sresult.inspect} +++" + }.resume + + end + end + end +end diff --git a/readme/arg-parser.rb b/readme/arg-parser.rb new file mode 100644 index 0000000..a105424 --- /dev/null +++ b/readme/arg-parser.rb @@ -0,0 +1,17 @@ +require "optparse" + +def require_host_user + summary =<<-SUMM + A simple utility corresponding to a usage example in the + [em-ssh](https://github.com/simulacre/em-ssh/) README. It requries a + single argument user@host. You use must have an authorized ssh public + key on the target host. After logging in a few non-destructive commands + will be executed. + SUMM + + host = nil + user = nil + user,host = ARGV[0].split("@") if ARGV[0] + abort "Usage: #{File.basename($0)} user@host\n\n#{summary}" if ARGV.include?("-h") || host.nil? || user.nil? + [host, user] +end