trick_bag 0.62.1 → 0.63.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 63e8ed88386c75d0f6522fca732a04df5579ab5e
4
- data.tar.gz: cc023bc71f5647e01088546869b755dc896b7b26
3
+ metadata.gz: 0768490eaa9eb879f69f015c1d8f49c0085ba0b3
4
+ data.tar.gz: 8cb3fb12ffb33ef3830fcd2241b42b282085f2fd
5
5
  SHA512:
6
- metadata.gz: 4ea59ca32862f9b6ad6cc99f4ec1dff179b3afe15d3cd989ccb6b9c7605ac9632a3b6d78df1e406bb15359ac6614d50181d8cc8a9b08faf4b6347c904e2ea24c
7
- data.tar.gz: cc121cced456988a0a5915b3a217a52e151252b06573b3a08237201766c04a1f211ab68d60b3d8f9b2b24c155f26ddf65000a7670c2f4733ebebefd89d755278
6
+ metadata.gz: 5f01c0def2bc580f7f638cc1c62e19a960226ed8d3b336eddf4bf2e00c7454ea182076aa0d5d9eafd1ff4abf5271e7a35b9be2c8514983e7b72c0af0cba78bac
7
+ data.tar.gz: abdc6c693166648ecb65b6f1245ea9e9dc3cb0c8de73f67c65ac1ad39942855627272eeae70b0de253c4a29daffe358dcf95dc723e4963bf105a9d5b633e3369
data/RELEASE_NOTES.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## v0.63.0
2
+
3
+ * Add SshOutputReader.
4
+
1
5
  ## v0.62.1
2
6
 
3
7
  * Reinstated thread.kill in Timing.try_with_timeout.
@@ -0,0 +1,157 @@
1
+ require 'net/ssh'
2
+
3
+ # Runs an ssh command, collecting the stdout and stderr produced by it.
4
+ # Optionally a predicate can be specified that, when called with the
5
+ # instance of this class, returns true to close
6
+ # the channel or false to continue.
7
+ #
8
+ # There are instance methods to return the most recent and all accumulated text
9
+ # for both stdout and stderr, so the predicate can easily inspect the text.
10
+ #
11
+ # While the predicate will most likely be a lambda, it can be any
12
+ # object that responds to call().
13
+ class SshOutputReader
14
+
15
+ attr_reader :host, :command, :user, :password, :exit_predicate
16
+ attr_accessor :latest_stdout, :all_stdout, :latest_stderr, :all_stderr, :latest_output_type, :channel
17
+
18
+ def initialize(host, command, user = ENV['USER'], password = nil)
19
+ @host = host
20
+ @user = user
21
+ @password = password
22
+ @command = command
23
+ @exit_predicate = ->(instance_of_this_class) { false }
24
+ clear_buffers
25
+ end
26
+
27
+
28
+ def clear_buffers
29
+ @latest_stdout = ''
30
+ @all_stdout = ''
31
+ @latest_stderr = ''
32
+ @all_stderr = ''
33
+ end
34
+
35
+
36
+ # Sets a predicate that, when called with this reader instance, returns true
37
+ # to close the channel and return, or false to permit the
38
+ # channel to continue operating.
39
+ #
40
+ # Using this self value, any instance methods can be called; the most useful
41
+ # will probably be latest_stdout, all_stdout, latest_stderr, and all_stderr.
42
+ # There is also a latest_output_type that returns :stdout or :stderr to
43
+ # indicate which type of output just occurred.
44
+ #
45
+ # For example, to exit when the string "exit" is sent to stdout:
46
+ # reader.set_exit_predicate(->(reader) { /exit/ === reader.latest_stdout })
47
+ #
48
+ # Returns self to facilitate chaining, e.g.:
49
+ # stdout, stderr = SshOutputReader.new(...).set_exit_predicate(...).run
50
+ def set_exit_predicate(exit_predicate)
51
+ @exit_predicate = exit_predicate
52
+ self
53
+ end
54
+
55
+
56
+ # Runs the specified command.
57
+ # If an exit predicate has been specified via set_exit_predicate,
58
+ # then it will be called whenever anything is output to stdout or stderr,
59
+ # and the channel will be closed if the predicate returns true.
60
+ #
61
+ # @return self, to support chaining
62
+ def run
63
+ clear_buffers
64
+ Net::SSH.start(host, user, password: password) do |ssh|
65
+
66
+ # Open a new channel and configure a minimal set of callbacks, then run
67
+ # the event loop until the channel finishes (closes).
68
+ self.channel = ssh.open_channel do |ch|
69
+ ch.exec(command) do |ch, success|
70
+ raise "could not execute command" unless success
71
+
72
+ # "on_data" is called when the process writes something to stdout
73
+ ch.on_data do |c, data|
74
+ self.latest_output_type = :stdout
75
+ self.latest_stdout = data
76
+ self.all_stdout << data
77
+ $stdout.print data
78
+ ch.close if exit_predicate.(self)
79
+ end
80
+
81
+ # "on_extended_data" is called when the process writes something to stderr
82
+ ch.on_extended_data do |c, type, data|
83
+ self.latest_output_type = :stderr
84
+ self.latest_stderr = data
85
+ self.all_stderr << data
86
+ $stderr.print data
87
+ ch.close if exit_predicate.(self)
88
+ end
89
+
90
+ ch.on_close { self.channel = nil; return self }
91
+ end
92
+ end
93
+
94
+ channel.wait
95
+ self.channel = nil
96
+ self
97
+ end
98
+ end
99
+
100
+
101
+ # The channel will automatically be closed if the predicate returns false
102
+ # or if the command completes. This method is provided for cases where
103
+ # the predicate wants to raise an error; close should be called before raising the error.
104
+ def close
105
+ channel.close if channel
106
+ end
107
+
108
+
109
+ def to_s
110
+ "host = #{host}, command = #{command}, user = #{user}" # password intentionally omitted
111
+ end
112
+ end
113
+
114
+
115
+
116
+ if $0 == __FILE__
117
+
118
+ Thread.abort_on_exception = true
119
+ # require 'pry'
120
+ has_a_2 = ->(reader) do
121
+ reader.latest_output_type == :stdout \
122
+ && \
123
+ /2/ === reader.latest_stdout
124
+ end
125
+
126
+ has_3_lines = ->(reader) { reader.all_stdout.split("\n").size >= 3 }
127
+
128
+ def run_reader(r)
129
+ puts "Starting reader: #{r}"
130
+ r.run
131
+ puts; puts "Stdout:\n" + (r.all_stdout.empty? ? '[Empty]' : r.all_stdout)
132
+ puts; puts "Stderr:\n" + (r.all_stderr.empty? ? '[Empty]' : r.all_stderr)
133
+ puts "Done\n#{'-' * 79}\n"
134
+ end
135
+
136
+ command = \
137
+ 'echo 1
138
+ sleep 1
139
+ echo error output >& 2
140
+ echo 2
141
+ sleep 1
142
+ echo 3
143
+ sleep 1
144
+ echo 4'
145
+
146
+ # reader = SshOutputReader.new('localhost', command)
147
+ # reader.run
148
+ # puts "All reader stdout:\n" + reader.all_stdout
149
+
150
+ run_reader(SshOutputReader.new('localhost', command)\
151
+ .set_exit_predicate(has_a_2))
152
+
153
+ # run_reader(SshOutputReader.new('localhost', command)\
154
+ # .set_exit_predicate(has_3_lines))
155
+
156
+ # run_reader(SshOutputReader.new('localhost', command))
157
+ end
@@ -1,3 +1,3 @@
1
1
  module TrickBag
2
- VERSION = '0.62.1'
2
+ VERSION = '0.63.0'
3
3
  end
data/trick_bag.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "os", '~> 0'
22
22
  spec.add_dependency "diffy", '~> 3.0'
23
+ spec.add_dependency 'net-ssh'
23
24
 
24
25
  spec.add_development_dependency "bundler", "~> 1.3"
25
26
  spec.add_development_dependency "rake", '~> 10.1'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trick_bag
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.62.1
4
+ version: 0.63.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith Bennett
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-09 00:00:00.000000000 Z
11
+ date: 2015-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: os
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: net-ssh
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -138,6 +152,7 @@ files:
138
152
  - lib/trick_bag/io/temp_files.rb
139
153
  - lib/trick_bag/io/text_mode_status_updater.rb
140
154
  - lib/trick_bag/meta/classes.rb
155
+ - lib/trick_bag/networking/ssh_output_reader.rb
141
156
  - lib/trick_bag/numeric/bit_mapping.rb
142
157
  - lib/trick_bag/numeric/bitmap.rb
143
158
  - lib/trick_bag/numeric/kmgt_numeric_string.rb