gofer 0.3.0 → 0.3.1

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MWQwYzJjNDA5ZGZiOGQ3MDRkYWFhYmRhNGQ4MmZlNmM5OGU5MmY0OQ==
4
+ ZWNlZjlhNDIyYjAyMDAxMWMwNTRiMmFlN2ZjMjk4NGYzYmU4NDRlMQ==
5
5
  data.tar.gz: !binary |-
6
- MTcwYTIwZDJjZWZlOGZhYWI5OTZjOWQ4NzUzM2NmYTBhNTU0YjhiMA==
6
+ YzA2ZmJkNGUzY2U5NmQwN2I4YTRmODIwMmY5OTJiOTk1ZmZjNjdmZQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NmM0OTY3MjQ4ZDZjYjkxZDNlY2M0OTdlMzMyNmFkODA4N2Q5OTkzMzUyNGQ2
10
- OWNiYjNkOTNjN2NlMDg2MDNiYTUwODEyMjUyYTFlNDg3OGNiNDE1YjI4NTNh
11
- ZTJkMDlmMzcyMmMzZDI0NGEyZGQ3ZTc2Yzg3NzA4MTFkYjIyOGM=
9
+ ZTBmYWFhOGEwODAzMzZhNGVhNWJmOTMyNDQ0N2FjMDc5ZjkwZjI3OWU2YmQx
10
+ ZjZkYTZlZmQ3MWYyMGE0MWFlM2FkODFjNTI1ZjE0MGMzYjY3MTEwMzc5ZGFk
11
+ OGQyYTZkZmE0OWQ3NjgzN2ExYmIxMTBkZjliZDE2YzM2ZWNmMTQ=
12
12
  data.tar.gz: !binary |-
13
- ZDE5ODhmYmM5NzEwZjg4MjA5YzRmYTE5ZTcxMzgzN2NmYjRkYjExMTBmMWQ1
14
- NzgwYjc4OTBhYjM2YTBhZjk3ODRhYzExMzFiMzU0NDYwYTUwNGEwYzcwNDcy
15
- NGNmODY4NDY4MzY0YWIxNGI2YTNhMzFiZTFiYzE5N2Y1OTBhNDI=
13
+ MzU4MGRhMmM1ZWNlNWE4MWFiNzZkMmViZjk1MTNiYjJmMDI1ZmZjODM4NGM3
14
+ NGM3YjNhOTUzYmEyYjEwYjRiZGYyN2E2ZWRmM2E0YWEyMzdiOTQ1NTYyMWUz
15
+ M2Q4M2U4M2Q0YmVlYmZhYTVmMDJkMzA1MGUyYTMyNzM3YzE5NjM=
@@ -1,4 +1,18 @@
1
1
  # Revision History
2
+
3
+ ### v0.3.1
4
+
5
+ * Prefix stderr/stdout per host with `:output_prefix`
6
+
7
+ ### v0.3.0
8
+
9
+ * Add cluster support via `Gofer::Cluster` (@rich0h)
10
+
11
+ ### v0.2.6 30/08/2012
12
+
13
+ * Preserve options on file upload/download
14
+ * Include host & server response in `Gofer::HostError` exceptions
15
+
2
16
  ### v0.2.5 02/06/2011
3
17
 
4
18
  * `#exists?` -> `#exist?` to be consistent with `File.exist?`
@@ -6,7 +20,7 @@
6
20
  ### v0.2.4 24/05/2011
7
21
 
8
22
  * Add `:quiet` as an option on `Gofer::Host` instantiation
9
-
23
+
10
24
  ### v0.2.3 21/05/2011
11
25
 
12
26
  * Add `write` command to `Gofer::Host`
@@ -14,7 +28,7 @@
14
28
  ### v0.2.2 10/05/20011
15
29
 
16
30
  * Add `run_multiple` method to `Gofer::Host`
17
-
31
+
18
32
  ### v0.2.1 08/05/2011
19
33
 
20
34
  * Add `quiet=` to Host instance to allow setting quiet to be the default.
@@ -22,7 +36,7 @@
22
36
  ### v0.2.0 03/05/2011
23
37
 
24
38
  * Flip ordering of username/hostname on instantiation to match that of `Net::SSH`
25
-
39
+
26
40
  ### v0.1.2 03/05/2011
27
41
 
28
42
  * Pass through `Gofer::Host` instantiation options straight through to `Net::SSH`.
@@ -35,7 +49,7 @@
35
49
 
36
50
  * Replace string return from run with a 'response' object
37
51
  * Removed 'within' functionality - will be replaced by 'open' later
38
-
52
+
39
53
  ### v0.0.1 03/04/2011
40
54
 
41
55
  * Initial release
data/README.md CHANGED
@@ -61,6 +61,13 @@ puts response.stderr # will print "goodbye\n"
61
61
  puts response.output # will print "hello\ngoodbye\n"
62
62
  ```
63
63
 
64
+ ### Prefix output
65
+
66
+ ``` ruby
67
+ h.output_prefix = 'apollo' # or set :output_prefix on instantiation
68
+ h.run "echo hello; echo goodbye" # prints apollo: hello\napollo: goodbye
69
+ ```
70
+
64
71
  ### Suppress output
65
72
 
66
73
  ``` ruby
@@ -80,8 +87,8 @@ puts response.stdout # will print "hello\ngoodbye\n"
80
87
 
81
88
  ``` ruby
82
89
  cluster = Gopher::Cluster.new
83
- cluster << Gofer::Host.new('my.host.com', 'ubuntu', :keys => ['key.pem'])
84
- cluster << Gofer::Host.new('other.host.com', 'ubuntu', :keys => ['key.pem'])
90
+ cluster << Gofer::Host.new('my.host.com', 'ubuntu', :keys => ['key.pem'], :output_prefix => " my")
91
+ cluster << Gofer::Host.new('other.host.com', 'ubuntu', :keys => ['key.pem'], :output_prefix => "other")
85
92
 
86
93
  cluster.run do |c|
87
94
  c.run("hostname") # This will run on both hosts at once
@@ -92,34 +99,24 @@ cluster.run(:max_concurrency => 1) do |c|
92
99
  end
93
100
  ```
94
101
 
95
- ## Planned Features
96
-
97
- ``` ruby
98
- # constant connection (no reconnect for each action)
99
- Gofer::Host.new(...).open do |h|
100
- h.run( ... )
101
- end
102
-
103
- # overriding defaults
104
- h.set :quiet => true
105
- h.set :capture_exit_status => false
106
-
107
- # Local system usage, too:
108
- Gofer::Localhost.new.run "hostname" # > my.macbook.com
109
- ```
110
-
111
102
  ## Testing
112
103
 
113
104
  * Ensure that your user can ssh as itself to localhost using the key in `~/.ssh/id_rsa`.
114
105
  * Run `rspec spec` or `bundle install && rake spec`
115
106
 
107
+ ## Contributing
108
+
109
+ Contributions should be via pull request. Please add tests and a note in the
110
+ `README.md` for new functionality. Please use 1.8.7-compatiable syntax.
111
+
116
112
  ## TODO
117
113
 
118
114
  * ls, exists?, directory? should use sftp if available rather than shell commands
119
- * wrap STDOUT with host prefix for easy identification of system output
120
115
  * Deal with timeouts/disconnects on persistent connections
121
- * CHANGELOG.md
122
116
  * Release 1.0 & use Semver
117
+ * Ensure RDodc is complete & up to date, link to rdoc.info from README
118
+ * Add unit tests, bring in Travis.ci
119
+ * Local system usage (eg `Gofer::Localhost.new.run "hostname"`)
123
120
 
124
121
  ## License
125
122
 
@@ -13,13 +13,14 @@ module Gofer
13
13
  class Host
14
14
 
15
15
  attr_reader :hostname
16
- attr_accessor :quiet
16
+ attr_accessor :quiet, :output_prefix
17
17
 
18
18
  # Create a new Host connection
19
19
  #
20
20
  # Options:
21
21
  #
22
22
  # +quiet+:: Don't print stdout output from +run+ commands
23
+ # +output_prefix+:: Prefix each line of stdout to differentiate multiple host output
23
24
  # All other+opts+ is passed through directly to Net::SSH.start
24
25
  # See http://net-ssh.github.com/ssh/v2/api/index.html for valid arguments.
25
26
  def initialize _hostname, username, opts={}
@@ -31,6 +32,7 @@ module Gofer
31
32
  end
32
33
 
33
34
  @quiet = opts.delete(:quiet)
35
+ @output_prefix = opts.delete(:output_prefix)
34
36
 
35
37
  # support legacy identity_file argument
36
38
  if opts[:identity_file]
@@ -55,6 +57,7 @@ module Gofer
55
57
  # +capture_exit_status+:: Don't raise an error on a non-zero exit status
56
58
  def run command, opts={}
57
59
  opts[:quiet] = quiet unless opts.include?(:quiet)
60
+ opts[:output_prefix] = @output_prefix
58
61
  response = @ssh.run command, opts
59
62
  if !opts[:capture_exit_status] && response.exit_status != 0
60
63
  raise HostError.new(self, response, "Command #{command} failed with exit status #{@ssh.last_exit_status}")
@@ -8,6 +8,7 @@ module Gofer
8
8
 
9
9
  def initialize *args
10
10
  @net_ssh_args = args
11
+ @at_start_of_line = true
11
12
  end
12
13
 
13
14
  def run command, opts={}
@@ -49,14 +50,14 @@ module Gofer
49
50
  channel.on_data do |ch, data| # stdout
50
51
  stdout += data
51
52
  output += data
52
- $stdout.print data unless opts[:quiet]
53
+ $stdout.print wrap_output(data, opts[:output_prefix]) unless opts[:quiet]
53
54
  end
54
55
 
55
56
  channel.on_extended_data do |ch, type, data|
56
57
  next unless type == 1 # only handle stderr
57
58
  stderr += data
58
59
  output += data
59
- $stderr.print data unless opts[:quiet_stderr]
60
+ $stderr.print wrap_output(data, opts[:output_prefix]) unless opts[:quiet_stderr]
60
61
  end
61
62
 
62
63
  channel.on_request("exit-status") do |ch, data|
@@ -70,5 +71,16 @@ module Gofer
70
71
  ssh.loop
71
72
  Gofer::Response.new(stdout, stderr, output, exit_code)
72
73
  end
74
+
75
+ def wrap_output output, prefix
76
+ return output unless prefix
77
+
78
+ output = "#{prefix}: " + output if @at_start_of_line
79
+
80
+ @at_start_of_line = output.end_with?("\n")
81
+
82
+ output.gsub(/\n(.)/, "\n#{prefix}: \\1")
83
+ end
84
+
73
85
  end
74
86
  end
@@ -1,3 +1,3 @@
1
1
  module Gofer # :nodoc:
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -29,6 +29,14 @@ describe Gofer do
29
29
  end
30
30
  end
31
31
 
32
+ def with_captured_output
33
+ @stdout = ''
34
+ @stderr = ''
35
+ @combined = ''
36
+ $stdout.stub!( :write ) { |*args| @stdout.<<( *args ); @combined.<<( *args )}
37
+ $stderr.stub!( :write ) { |*args| @stderr.<<( *args ); @combined.<<( *args )}
38
+ end
39
+
32
40
  before :all do
33
41
  @host = Gofer::Host.new(HOSTNAME, USERNAME, :keys => [IDENTITY_FILE], :quiet => true)
34
42
  @tmpdir = raw_ssh("mktemp -d /tmp/gofertest.XXXXX").chomp
@@ -86,6 +94,35 @@ describe Gofer do
86
94
  it_should_behave_like "an output capturer"
87
95
  end
88
96
 
97
+
98
+ it "should print stdout responses if quiet is false" do
99
+ $stdout.should_receive(:write).with "stdout\n"
100
+ @host.run "echo stdout", :quiet => false
101
+ end
102
+
103
+ it "should print stderr responses if quiet_stderr is false" do
104
+ $stderr.should_receive(:write).with "stderr\n"
105
+ @host.run "echo stderr 1>&2", :quiet_stderr => false
106
+ end
107
+
108
+ context "with a host output prefix" do
109
+ before do
110
+ @host.output_prefix = "derp"
111
+ with_captured_output
112
+ end
113
+ it "should prefix each line of the stdout and stderr responses with the output prefix" do
114
+ @host.run "echo stdout; echo stdout2; echo stderr 1>&2; echo stderr2 1>&2", :quiet => false, :quiet_stderr => false
115
+ @stdout.should eq "derp: stdout\nderp: stdout2\n"
116
+ @stderr.should eq "derp: stderr\nderp: stderr2\n"
117
+ end
118
+
119
+ it "should not prefix if the output is not actually on a new line" do
120
+ @host.run "echo -n foo; echo bar; echo baz; ", :quiet => false
121
+ @combined.should eq "derp: foobar\nderp: baz\n"
122
+ end
123
+
124
+ end
125
+
89
126
  it "should error if a command returns a non-zero response" do
90
127
  lambda {@host.run "false"}.should raise_error(/failed with exit status/)
91
128
  begin
@@ -204,42 +241,35 @@ describe Gofer do
204
241
  end
205
242
 
206
243
  describe :cluster do
207
- it "should run commands in parallel" do
208
- cluster = Gofer::Cluster.new
244
+ before do
245
+ @cluster = Gofer::Cluster.new
209
246
  # Cheat and use the same host repeatedly
210
- host1 = Gofer::Host.new(HOSTNAME, USERNAME, :keys => [IDENTITY_FILE], :quiet => true)
211
- host2 = Gofer::Host.new(HOSTNAME, USERNAME, :keys => [IDENTITY_FILE], :quiet => true)
212
- cluster << host1
213
- cluster << host2
247
+ @host1 = Gofer::Host.new(HOSTNAME, USERNAME, :keys => [IDENTITY_FILE], :quiet => true)
248
+ @host2 = Gofer::Host.new(HOSTNAME, USERNAME, :keys => [IDENTITY_FILE], :quiet => true)
249
+ @cluster << @host1
250
+ @cluster << @host2
251
+ end
214
252
 
215
- results = cluster.run do |c|
216
- c.run "date '+%s%N'; sleep 1; date '+%s%N'"
253
+ it "should run commands in parallel" do
254
+ results = @cluster.run do |c|
255
+ c.run "ruby -e 'puts Time.now.to_f; sleep 0.1; puts Time.now.to_f'"
217
256
  end
218
257
 
219
- res1 = results[host1].stdout.lines.to_a
220
- res2 = results[host2].stdout.lines.to_a
258
+ res1 = results[@host1].stdout.lines.to_a
259
+ res2 = results[@host2].stdout.lines.to_a
221
260
 
222
261
  expect(res1[1].to_f).to be > res2[0].to_f
223
-
224
262
  end
225
263
 
226
264
  it "should respect max_concurrency" do
227
- cluster = Gofer::Cluster.new
228
- # Cheat and use the same host repeatedly
229
- host1 = Gofer::Host.new(HOSTNAME, USERNAME, :keys => [IDENTITY_FILE], :quiet => true)
230
- host2 = Gofer::Host.new(HOSTNAME, USERNAME, :keys => [IDENTITY_FILE], :quiet => true)
231
- cluster << host1
232
- cluster << host2
233
-
234
- results = cluster.run(:max_concurrency => 1) do |c|
235
- c.run "date '+%s%N'; sleep 1; date '+%s%N'"
265
+ results = @cluster.run(:max_concurrency => 1) do |c|
266
+ c.run "ruby -e 'puts Time.now.to_f; sleep 0.1; puts Time.now.to_f'"
236
267
  end
237
268
 
238
- res1 = results[host1].stdout.lines.to_a
239
- res2 = results[host2].stdout.lines.to_a
269
+ res1 = results[@host1].stdout.lines.to_a
270
+ res2 = results[@host2].stdout.lines.to_a
240
271
 
241
272
  expect(res2[0].to_f).to be >= res1[1].to_f
242
-
243
273
  end
244
274
  end
245
275
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gofer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Pearson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-23 00:00:00.000000000 Z
11
+ date: 2013-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-ssh
@@ -52,8 +52,8 @@ extensions: []
52
52
  extra_rdoc_files: []
53
53
  files:
54
54
  - .gitignore
55
+ - CHANGELOG.md
55
56
  - Gemfile
56
- - HISTORY.md
57
57
  - README.md
58
58
  - Rakefile
59
59
  - gofer.gemspec