gofer 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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