gofer 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ # Revision History
2
+
3
+ ### v0.1.0 20/04/2011
4
+
5
+ * Replace string return from run with a 'response' object
6
+ * Removed 'within' functionality - will be replaced by 'open' later
7
+
8
+ ### v0.0.1 03/04/2011
9
+
10
+ * Initial release
data/README.md CHANGED
@@ -5,73 +5,67 @@
5
5
  **Gofer** has been written to support the needs of system automation scripts. As such, **gofer** will:
6
6
 
7
7
  * automatically raise an error if a command returns a non-zero exit status
8
- * print and capture STDOUT automatically
9
- * print STDERR but don't capture it
10
- * override the above: return non-zero exit status instead of raising an error, capture STDERR, suppress output
8
+ * print and capture STDOUT and STDERR automatically
9
+ * allow you to access captured STDOUT and STDERR individually or as a combined string
10
+ * override the above: return non-zero exit status instead of raising an error, suppress output
11
11
 
12
12
  ## Examples
13
13
 
14
- # in a block
15
- Gofer::Host.new('ubuntu', 'my.host.com', :identity_file => 'key.pem').within do
16
- # Basic usage
17
- run "sudo stop mysqld"
14
+ ### Instantiation
18
15
 
19
- # Copying files
20
- upload 'file' 'remote_file'
21
- download 'remote_dir', 'dir'
16
+ h = Gofer::Host.new('ubuntu', 'my.host.com', :identity_file => 'key.pem')
22
17
 
23
- # Filesystem inspection
24
- if exists?('remote_directory')
25
- run "rm -rf 'remote_directory'"
26
- end
18
+ ### Run a command
27
19
 
28
- # read/ls
29
- puts read('a_remote_file')
30
- puts ls('a_remote_dir').join(", ")
20
+ h.run "sudo stop mysqld"
31
21
 
32
- # error handling - default to critical failure if a command fails
33
- run "false" # this will fail
34
- run "false", :capture_exit_status => true # this won't ...
35
- puts last_exit_status # and will make the exit status available
22
+ ### Copy some files
36
23
 
37
- # stderr/stdout
38
- hello = run "echo hello" # will print 'hello'
39
- puts hello # will print "hello\n"
24
+ h.upload 'file', 'remote_file'
25
+ h.download 'remote_dir', 'dir'
40
26
 
41
- goodbye = run "echo goodbye 1>&2"
42
- # goodbye will be empty, as we don't capture stderr by default
43
-
44
- goodbye = run "echo goodbye 1>&2", :capture_stderr => true # unless you ask for it
45
-
46
- # output suppression
47
- run "echo noisy", :quiet => true # don't output from our command
48
- run "echo noisier 1>&2", :quiet_stderr => true # don't even output stderr!
27
+ ### Interact with the filesystem
49
28
 
29
+ if h.exists?('remote_directory')
30
+ h.run "rm -rf 'remote_directory'"
50
31
  end
51
32
 
52
- # using the instance directly
53
- h = Gofer::Host.new('ubuntu', 'my.host.com')
54
- h.run('sudo mysqld stop')
55
- h.upload('file', 'remote_file')
56
- # etc..
33
+ puts h.read('a_remote_file')
34
+ puts h.ls('a_remote_dir').join(", ")
35
+
36
+ ### Respond to command errors
37
+
38
+ h.run "false" # this will fail
39
+ response = h.run "false", :capture_exit_status => true # this won't ...
40
+ puts response.exit_status # and will make the exit status available
41
+
42
+ ### Capture output
43
+
44
+ response = h.run "echo hello; echo goodbye 1>&2\n"
45
+ puts response # will print "hello\n"
46
+ puts response.stdout # will also print "hello\n"
47
+ puts response.stderr # will print "goodbye\n"
48
+ puts response.output # will print "hello\ngoodbye\n"
49
+
50
+ ### Suppress output
51
+
52
+ h.run "echo noisy", :quiet => true # don't output from our command
53
+ h.run "echo noisier 1>&2", :quiet_stderr => true # don't even output stderr!
57
54
 
58
55
  ## Planned Features
59
56
 
60
- write("a string buffer", 'a_remote_file')
57
+ h.write("a string buffer", 'a_remote_file')
61
58
  # constant connection (no reconnect for each action)
62
- h = Gofer::Host.new(..., :keep_open => true)
63
- h.run( ... )
64
- h.close
65
-
59
+ Gofer::Host.new(...).open do |h|
60
+ h.run( ... )
61
+ end
62
+
66
63
  # overriding defaults
67
- set :quiet => true
68
- set :capture_exit_status => false
69
-
70
- # Separate the command from the arguments, system() style
71
- run "echo" "Some" "arguments" "with" "'quotes'" "in" "them"
64
+ h.set :quiet => true
65
+ h.set :capture_exit_status => false
72
66
 
73
67
  # Local system usage, too:
74
- run "hostname" # > my.macbook.com
68
+ Gofer::Localhost.new.run "hostname" # > my.macbook.com
75
69
 
76
70
  ## Testing
77
71
 
@@ -82,6 +76,7 @@
82
76
 
83
77
  * ls, exists?, directory? should use sftp if available rather than shell commands
84
78
  * wrap STDOUT with host prefix for easy identification of system output
79
+ * RDoc
85
80
 
86
81
  ## License
87
82
 
@@ -1,4 +1,5 @@
1
1
  require 'gofer/ssh_wrapper'
2
+ require 'gofer/response'
2
3
  require 'gofer/host'
3
4
  require 'gofer/version'
4
5
 
@@ -7,7 +7,7 @@ module Gofer
7
7
 
8
8
  class Host
9
9
 
10
- attr_reader :last_exit_status, :hostname
10
+ attr_reader :hostname
11
11
 
12
12
  def initialize username, _hostname, identity_file=nil
13
13
  @hostname = _hostname
@@ -15,18 +15,15 @@ module Gofer
15
15
  end
16
16
 
17
17
  def run command, opts={}
18
- @ssh.run command, opts
19
- if opts[:capture_exit_status]
20
- @last_exit_status = @ssh.last_exit_status
21
- elsif @ssh.last_exit_status != 0
18
+ response = @ssh.run command, opts
19
+ if !opts[:capture_exit_status] && response.exit_status != 0
22
20
  raise HostError.new(self, "Command #{command} failed with exit status #{@ssh.last_exit_status}")
23
21
  end
24
- @ssh.last_output
22
+ response
25
23
  end
26
24
 
27
25
  def exists? path
28
- @ssh.run "sh -c '[ -e #{path} ]'"
29
- @ssh.last_exit_status == 0
26
+ @ssh.run("sh -c '[ -e #{path} ]'").exit_status == 0
30
27
  end
31
28
 
32
29
  def read path
@@ -34,16 +31,15 @@ module Gofer
34
31
  end
35
32
 
36
33
  def directory? path
37
- @ssh.run "sh -c '[ -d #{path} ]'"
38
- @ssh.last_exit_status == 0
34
+ @ssh.run("sh -c '[ -d #{path} ]'").exit_status == 0
39
35
  end
40
36
 
41
37
  def ls path
42
- @ssh.run "ls -1 #{path}", :quiet => true
43
- if @ssh.last_exit_status == 0
44
- @ssh.last_output.strip.split("\n")
38
+ response = @ssh.run "ls -1 #{path}", :quiet => true
39
+ if response.exit_status == 0
40
+ response.stdout.strip.split("\n")
45
41
  else
46
- raise HostError.new(self, "Could not list #{path}, exit status #{@ssh.last_exit_status}")
42
+ raise HostError.new(self, "Could not list #{path}, exit status #{response.exit_status}")
47
43
  end
48
44
  end
49
45
 
@@ -54,9 +50,5 @@ module Gofer
54
50
  def download from, to
55
51
  @ssh.download from, to, :recursive => directory?(from)
56
52
  end
57
-
58
- def within &block
59
- instance_eval &block
60
- end
61
53
  end
62
54
  end
@@ -0,0 +1,13 @@
1
+ module Gofer
2
+ class Response < String
3
+ attr_reader :stdout, :stderr, :output, :exit_status
4
+
5
+ def initialize (_stdout, _stderr, _output, _exit_status)
6
+ super _stdout
7
+ @stdout = _stdout
8
+ @stderr = _stderr
9
+ @output = _output
10
+ @exit_status = _exit_status
11
+ end
12
+ end
13
+ end
@@ -15,9 +15,11 @@ module Gofer
15
15
  end
16
16
 
17
17
  def run command, opts={}
18
+ response = nil
18
19
  Net::SSH.start(*net_ssh_credentials) do |ssh|
19
- ssh_execute(ssh, command, opts)
20
+ response = ssh_execute(ssh, command, opts)
20
21
  end
22
+ response
21
23
  end
22
24
 
23
25
  def read_file path
@@ -55,7 +57,7 @@ module Gofer
55
57
  end
56
58
 
57
59
  def ssh_execute(ssh, command, opts={})
58
- output = ''
60
+ stdout, stderr, output = '', '', ''
59
61
  exit_code = 0
60
62
  ssh.open_channel do |channel|
61
63
  channel.exec(command) do |ch, success|
@@ -64,13 +66,15 @@ module Gofer
64
66
  end
65
67
 
66
68
  channel.on_data do |ch, data| # stdout
69
+ stdout += data
67
70
  output += data
68
71
  $stdout.print data unless opts[:quiet]
69
72
  end
70
73
 
71
74
  channel.on_extended_data do |ch, type, data|
72
75
  next unless type == 1 # only handle stderr
73
- output += data if opts[:capture_stderr]
76
+ stderr += data
77
+ output += data
74
78
  $stderr.print data unless opts[:quiet_stderr]
75
79
  end
76
80
 
@@ -83,9 +87,7 @@ module Gofer
83
87
  end
84
88
 
85
89
  ssh.loop
86
-
87
- @last_exit_status = exit_code
88
- @last_output = output
90
+ Gofer::Response.new(stdout, stderr, output, exit_code)
89
91
  end
90
92
  end
91
93
  end
@@ -1,3 +1,3 @@
1
1
  module Gofer
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -49,19 +49,26 @@ describe Gofer do
49
49
  end
50
50
 
51
51
  describe :run do
52
- it "should run a command and capture its output" do
53
- output = @host.run "echo hello", :quiet => true
54
- output.should == "hello\n"
55
- end
56
-
57
- it "should run a command not capture its stderr by default" do
58
- output = @host.run "echo hello 1>&2", :quiet_stderr => true
59
- output.should == ""
60
- end
61
-
62
- it "should run a command capture its stderr if asked" do
63
- output = @host.run "echo hello 1>&2", :quiet_stderr => true, :capture_stderr => true
64
- output.should == "hello\n"
52
+ describe "with stdout and stderr responses" do
53
+ before :all do
54
+ @response = @host.run "echo stdout; echo stderr 1>&2", :quiet => true, :quiet_stderr => true
55
+ end
56
+
57
+ it "should capture stdout in @response.stdout" do
58
+ @response.stdout.should == "stdout\n"
59
+ end
60
+
61
+ it "should capture stderr in @response.stderr" do
62
+ @response.stderr.should == "stderr\n"
63
+ end
64
+
65
+ it "should combine captured stdout / stderr in @response.output" do
66
+ @response.output.should == "stdout\nstderr\n"
67
+ end
68
+
69
+ it "@response by itself should be the captured stdout" do
70
+ @response.should == "stdout\n"
71
+ end
65
72
  end
66
73
 
67
74
  it "should error if a command returns a non-zero response" do
@@ -69,8 +76,8 @@ describe Gofer do
69
76
  end
70
77
 
71
78
  it "should capture a non-zero exit status if asked" do
72
- @host.run "false", :capture_exit_status => true
73
- @host.last_exit_status.should == 1
79
+ response = @host.run "false", :capture_exit_status => true
80
+ response.exit_status.should == 1
74
81
  end
75
82
  end
76
83
 
@@ -154,12 +161,4 @@ describe Gofer do
154
161
  end
155
162
  end
156
163
  end
157
-
158
- describe :within do
159
- it "should execute commands in the context of the host instance" do
160
- @host.within do
161
- run("echo sup", :quiet => true).should == "sup\n"
162
- end
163
- end
164
- end
165
164
  end
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gofer
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 0
9
- - 1
10
- version: 0.0.1
4
+ prerelease:
5
+ version: 0.1.0
11
6
  platform: ruby
12
7
  authors:
13
8
  - Michael Pearson
@@ -15,7 +10,7 @@ autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2011-04-03 01:00:00 +11:00
13
+ date: 2011-04-20 00:00:00 +10:00
19
14
  default_executable:
20
15
  dependencies:
21
16
  - !ruby/object:Gem::Dependency
@@ -26,11 +21,6 @@ dependencies:
26
21
  requirements:
27
22
  - - ">="
28
23
  - !ruby/object:Gem::Version
29
- hash: 33
30
- segments:
31
- - 2
32
- - 0
33
- - 23
34
24
  version: 2.0.23
35
25
  type: :runtime
36
26
  version_requirements: *id001
@@ -42,19 +32,12 @@ dependencies:
42
32
  requirements:
43
33
  - - ">="
44
34
  - !ruby/object:Gem::Version
45
- hash: 31
46
- segments:
47
- - 1
48
- - 0
49
- - 4
50
35
  version: 1.0.4
51
36
  type: :runtime
52
37
  version_requirements: *id002
53
- description: |
54
-
55
- Gofer provides a flexible and reliable model for performing tasks on remote
56
- server using Net::SSH
57
-
38
+ description: "\n\
39
+ Gofer provides a flexible and reliable model for performing tasks on remote\n\
40
+ server using Net::SSH\n"
58
41
  email:
59
42
  - mipearson@gmail.com
60
43
  executables: []
@@ -66,12 +49,13 @@ extra_rdoc_files: []
66
49
  files:
67
50
  - .gitignore
68
51
  - Gemfile
52
+ - HISTORY.md
69
53
  - README.md
70
54
  - Rakefile
71
55
  - gofer.gemspec
72
56
  - lib/gofer.rb
73
57
  - lib/gofer/host.rb
74
- - lib/gofer/options.rb
58
+ - lib/gofer/response.rb
75
59
  - lib/gofer/ssh_wrapper.rb
76
60
  - lib/gofer/version.rb
77
61
  - spec/gofer/integration_spec.rb
@@ -90,23 +74,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
74
  requirements:
91
75
  - - ">="
92
76
  - !ruby/object:Gem::Version
93
- hash: 3
94
- segments:
95
- - 0
96
77
  version: "0"
97
78
  required_rubygems_version: !ruby/object:Gem::Requirement
98
79
  none: false
99
80
  requirements:
100
81
  - - ">="
101
82
  - !ruby/object:Gem::Version
102
- hash: 3
103
- segments:
104
- - 0
105
83
  version: "0"
106
84
  requirements: []
107
85
 
108
86
  rubyforge_project:
109
- rubygems_version: 1.3.7
87
+ rubygems_version: 1.6.2
110
88
  signing_key:
111
89
  specification_version: 3
112
90
  summary: run commands on remote servers using SSH
@@ -1,37 +0,0 @@
1
- # Unused, keeping for later use.
2
- module Gofer
3
- class Options
4
- VALID_OPTIONS => %w{identity_file}
5
-
6
- def valid_options
7
- VALID_OPTIONS
8
- end
9
-
10
- def initialize
11
- @options = {}
12
- end
13
-
14
- def merge_in opts={}
15
- opts.each |k,v|
16
- set k, v
17
- end
18
- end
19
-
20
- def set k, v
21
- k = option_valid_check(k)
22
- @options[k] = v
23
- end
24
-
25
- def get k
26
- k = option_valid_check(k)
27
- @options[k]
28
- end
29
-
30
- private
31
-
32
- def option_valid_check(k)
33
- k = k.to_s
34
- raise "Invalid option #{k}" unless valid_options.include?(k)
35
- end
36
- end
37
- end