gofer 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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