net-ssh-cli 1.3.1 → 1.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: edf3e84c80ca5ee2c6b67efee26c5f5b4f4b51a6c3425c4b7093e1d20eee4816
4
- data.tar.gz: 59b804e5249298c0f6de5debb26a89eacc3221e0a7d1bf3fe47aa08c5c2e89fa
3
+ metadata.gz: e3557b2b202abb2f722b950d3f16d0e1c36a57716289f138d4c7f04edb453546
4
+ data.tar.gz: 8e58d5fa7d2e89021ffcb10751fff17526542d1d16314f79769f7e5f67451ea0
5
5
  SHA512:
6
- metadata.gz: 0d1046b9eab50cf26d5a1acab9d9301fa90225204df55168c64dcb9d985310aacdee023fe2c4ce2628cf016847e891feed6f94da3c0423c6555f41f3727262da
7
- data.tar.gz: 2c70b909d56f711d972b8381f4eef838e785b1b78d63d11786fded541b00d0b03b487fa66418b791965d4c13c0a02c28f65751cab5fa917a459c5ccdffa00ae6
6
+ metadata.gz: 447b6ac1b58038620c3886241352e48bf5b89cbe0512a9506e08ab359378f62d3629f0007516bbcf4c360e204ea259d865d65e6396ee66d5d10c8c05275ede08
7
+ data.tar.gz: a898d86bf7d7fdde7977bd6161e1801606da032b96e3fb04ba6c55a6e104d1d2db0e8f68b12763afb63fee036c19e3c087af203563323543d4328a5fb61c487d
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6
1
+ 3.0
data/README.md CHANGED
@@ -60,6 +60,12 @@ end
60
60
  # => "echo 'bananas'\nbananas"
61
61
  cli.cmd "echo 'bananas'", rm_command: true, rm_prompt: true
62
62
  # => "bananas"
63
+ cli.cmd "echo 'bananas'", rm_command: true, rm_prompt: true, minimum_duration: 9
64
+ # => "bananas"
65
+ cli.cmd "echo 'bananas'", rm_command: true, rm_prompt: true, prompt: /\nuser@host:/m
66
+ # => "bananas"
67
+ cli.cmd "echo 'bananas'", rm_command: true, rm_prompt: true, timeout: 60
68
+ # => "bananas"
63
69
  ```
64
70
 
65
71
  Remove the command and the prompt for #cmd & #dialog by default
@@ -69,9 +75,23 @@ Remove the command and the prompt for #cmd & #dialog by default
69
75
  # => "bananas"
70
76
  ```
71
77
 
78
+ You can define a timeout for a `#cmd` in order to avoid hanging commands. The timeout gets passed into the underlying function #read_till.
79
+ This is usefull in case your prompt won't match because of an unexpected behaviour or undefined behaviour. For example some form of unexpected dialog.
80
+ The underlying implementation is using a soft timeout because `Timeout.timeout` is dangerous. In order to deal anyway with hanging low level issues, `Timeout.timeout` is used too, but with a higher value than the soft timeout.
81
+
82
+ ```ruby
83
+ cli = ssh.cli(default_prompt: /(\nuser@host):/m, read_till_timeout: 11)
84
+ cli.cmd "echo 'bananas'" # timeout is set to 11
85
+ # => "bananas"
86
+ cli.cmd "echo 'bananas'", timeout: 22 # timeout is set to 22
87
+ # => "bananas"
88
+ cli.cmd "sleep 33", timeout: 22 # timeout is set to 22
89
+ # Net::SSH::CLI::Error::CMD
90
+ ```
91
+
72
92
  ### #cmds
73
93
 
74
- It's the same as #cmd but for multiple commands.
94
+ It's the same as `#cmd` but for multiple commands.
75
95
 
76
96
  ```ruby
77
97
  cli.cmds ["echo 'bananas'", "echo 'apples'"], rm_command: true, rm_prompt: true
@@ -79,12 +99,22 @@ It's the same as #cmd but for multiple commands.
79
99
  ```
80
100
 
81
101
  ### #dialog
102
+
103
+ Use this method to specify a differnt 'prompt' for once. This is perfect for interactive commands.
104
+
82
105
  ```ruby
83
106
  cli.dialog "echo 'are you sure?' && read -p 'yes|no>'", /\nyes|no>/
84
107
  # => "echo 'are you sure?' && read -p 'yes|no>'\nyes|no>"
85
108
  cli.cmd "yes"
86
109
  ```
87
110
 
111
+ ```ruby
112
+ cli.dialog "passwd", /Current Password:/i
113
+ cli.dialog "Old Password", /New Password:/i
114
+ cli.dialog "New Password", /Repeat Password:/i
115
+ cli.cmd "New Password"
116
+ ```
117
+
88
118
  ### #impact
89
119
 
90
120
  The very same as `#cmd` but it respects a flag whether to run commands with 'impact'.
@@ -148,10 +178,12 @@ Nearly everything can be configured.
148
178
  ### Callbacks
149
179
 
150
180
  The following callbacks are available
151
- - #before_open_channel
152
- - #after_open_channel
153
- - #before_on_data
154
- - #before_on_data
181
+ - before_open_channel
182
+ - after_open_channel
183
+ - before_on_stdout
184
+ - after_on_stdout
185
+ - before_on_stdin
186
+ - after_on_stdin
155
187
 
156
188
  ```ruby
157
189
  cli.before_open_channel do
@@ -166,6 +198,41 @@ cli.after_open_channel do
166
198
  end
167
199
  ```
168
200
 
201
+ Using the callbacks you can define a debugger which shows the `stdout` buffer content each time new data is received.
202
+
203
+ ```ruby
204
+ cli.after_on_stdout do
205
+ warn stdout
206
+ end
207
+ ```
208
+
209
+ ```ruby
210
+ cli.after_on_stdout do
211
+ puts "the following new data arrived on stdout #{new_data.inspect} from #{hostname}"
212
+ end
213
+ ```
214
+
215
+ or convert new lines between different OS
216
+ ```ruby
217
+ cli.after_on_stdout do
218
+ stdout.gsub!("\r\n", "\n")
219
+ end
220
+ ```
221
+
222
+ or hide passwords
223
+ ```ruby
224
+ cli.after_on_stdout do
225
+ stdout.gsub!(/password:\S+/, "<HIDDEN>")
226
+ end
227
+ ```
228
+
229
+ or change the stdin before sending it
230
+ ```ruby
231
+ cli.before_on_stdin do
232
+ content.gsub("\n\n", "\n")
233
+ end
234
+ ```
235
+
169
236
  ### #hostname #host #to_s
170
237
 
171
238
  ```ruby
@@ -189,6 +256,38 @@ This works usually, but is not guaranteed to work well.
189
256
  # => "[my prompt]"
190
257
  ```
191
258
 
259
+ ### An outdated view of all available Options
260
+
261
+ Please check the file `lib/net/ssh/cli.rb` `OPTIONS` in order to get an up-to-date view of all available options, flags and arguments.
262
+
263
+ ```ruby
264
+ OPTIONS = ActiveSupport::HashWithIndifferentAccess.new(
265
+ default_prompt: /\n?^(\S+@.*)\z/, # the default prompt to search for
266
+ cmd_rm_prompt: false, # whether the prompt should be removed in the output of #cmd
267
+ cmd_rm_command: false, # whether the given command should be removed in the output of #cmd
268
+ cmd_rm_command_tail: "\n", # which format does the end of line return after a command has been submitted. Could be something like "ls\n" "ls\r\n" or "ls \n" (extra spaces)
269
+ run_impact: false, # whether to run #impact commands. This might align with testing|development|production. example #impact("reboot")
270
+ read_till_timeout: nil, # timeout for #read_till to find the match
271
+ read_till_hard_timeout: nil, # hard timeout for #read_till to find the match using Timeout.timeout(hard_timeout) {}. Might creates unpredicted sideffects
272
+ read_till_hard_timeout_factor: 1.2, # hard timeout factor in case read_till_hard_timeout is true
273
+ named_prompts: ActiveSupport::HashWithIndifferentAccess.new, # you can used named prompts for #with_prompt {}
274
+ before_cmd_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call before #cmd
275
+ after_cmd_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call after #cmd
276
+ before_on_stdout_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call before data arrives from the underlying connection
277
+ after_on_stdout_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call after data arrives from the underlying connection
278
+ before_on_stdin_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call before data is sent to the underlying channel
279
+ after_on_stdin_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call after data is sent to the underlying channel
280
+ before_open_channel_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call before opening a channel
281
+ after_open_channel_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call after opening a channel, for example you could call #detect_prompt or #read_till
282
+ open_channel_timeout: nil, # timeout to open the channel
283
+ net_ssh_options: ActiveSupport::HashWithIndifferentAccess.new, # a wrapper for options to pass to Net::SSH.start in case net_ssh is undefined
284
+ process_time: 0.00001, # how long #process is processing net_ssh#process or sleeping (waiting for something)
285
+ background_processing: false, # default false, whether the process method maps to the underlying net_ssh#process or the net_ssh#process happens in a separate loop
286
+ on_stdout_processing: 100, # whether to optimize the on_stdout performance by calling #process #optimize_on_stdout-times in case more data arrives
287
+ sleep_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call instead of Kernel.sleep(), perfect for async hooks
288
+ )
289
+ ```
290
+
192
291
  ## Development
193
292
 
194
293
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/lib/net/ssh/cli.rb CHANGED
@@ -17,6 +17,7 @@ module Net
17
17
  class OpenChannelTimeout < Error; end
18
18
  class ReadTillTimeout < Error; end
19
19
  class PromptDetection < Error; end
20
+ class CMD < Error; end
20
21
  end
21
22
 
22
23
  # Example
@@ -39,20 +40,30 @@ module Net
39
40
  attr_accessor :channel, :stdout, :net_ssh, :logger, :new_data, :process_count
40
41
 
41
42
  OPTIONS = ActiveSupport::HashWithIndifferentAccess.new(
42
- default_prompt: /\n?^(\S+@.*)\z/, # the default prompt to search for
43
+ default_prompt: /\n?^(\S+@.*)\z/, # the default prompt to search for. It is recommended to use \z to ensure you don't match the prompt too early.
43
44
  cmd_rm_prompt: false, # whether the prompt should be removed in the output of #cmd
44
45
  cmd_rm_command: false, # whether the given command should be removed in the output of #cmd
46
+ cmd_rm_command_tail: "\n", # which format does the end of line return after a command has been submitted. Could be something like "ls\n" "ls\r\n" or "ls \n" (extra spaces)
47
+ cmd_minimum_duration: 0, # how long do you want to wait/sleep after sending the command. After this waiting time, the output will be processed and the prompt will be searched.
45
48
  run_impact: false, # whether to run #impact commands. This might align with testing|development|production. example #impact("reboot")
46
49
  read_till_timeout: nil, # timeout for #read_till to find the match
50
+ read_till_hard_timeout: nil, # hard timeout for #read_till to find the match using Timeout.timeout(hard_timeout) {}. Might creates unpredicted sideffects
51
+ read_till_hard_timeout_factor: 1.2, # hard timeout factor in case read_till_hard_timeout is true
47
52
  named_prompts: ActiveSupport::HashWithIndifferentAccess.new, # you can used named prompts for #with_prompt {}
53
+ before_cmd_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call before #cmd
54
+ after_cmd_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call after #cmd
48
55
  before_on_stdout_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call before data arrives from the underlying connection
49
56
  after_on_stdout_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call after data arrives from the underlying connection
57
+ before_on_stdin_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call before data is sent to the underlying channel
58
+ after_on_stdin_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call after data is sent to the underlying channel
50
59
  before_open_channel_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call before opening a channel
51
60
  after_open_channel_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call after opening a channel, for example you could call #detect_prompt or #read_till
52
61
  open_channel_timeout: nil, # timeout to open the channel
53
62
  net_ssh_options: ActiveSupport::HashWithIndifferentAccess.new, # a wrapper for options to pass to Net::SSH.start in case net_ssh is undefined
54
63
  process_time: 0.00001, # how long #process is processing net_ssh#process or sleeping (waiting for something)
55
64
  background_processing: false, # default false, whether the process method maps to the underlying net_ssh#process or the net_ssh#process happens in a separate loop
65
+ on_stdout_processing: 100, # whether to optimize the on_stdout performance by calling #process #optimize_on_stdout-times in case more data arrives
66
+ sleep_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call instead of Kernel.sleep(), perfect for async hooks
56
67
  )
57
68
 
58
69
  def options
@@ -107,19 +118,19 @@ module Net
107
118
  before_on_stdout_procs.each { |_name, a_proc| instance_eval(&a_proc) }
108
119
  stdout << new_data
109
120
  after_on_stdout_procs.each { |_name, a_proc| instance_eval(&a_proc) }
110
- self.process_count += 1
111
- process unless process_count > 100 # if we receive data, we probably receive more - improves performance - but on a lot of data, this leads to a stack level too deep
112
- self.process_count -= 1
121
+ optimise_stdout_processing
113
122
  stdout
114
123
  end
115
124
 
116
- def write(content = String.new)
125
+ def stdin(content = String.new)
117
126
  logger.debug { "#write #{content.inspect}" }
127
+ before_on_stdin_procs.each { |_name, a_proc| instance_eval(&a_proc) }
118
128
  channel.send_data content
119
129
  process
130
+ after_on_stdin_procs.each { |_name, a_proc| instance_eval(&a_proc) }
120
131
  content
121
132
  end
122
- alias stdin write
133
+ alias write stdin
123
134
 
124
135
  def write_n(content = String.new)
125
136
  write content + "\n"
@@ -128,7 +139,7 @@ module Net
128
139
  def read
129
140
  process
130
141
  var = stdout!
131
- logger.debug("#read: \n#{var}")
142
+ logger.debug { "#read: \n#{var}" }
132
143
  var
133
144
  end
134
145
 
@@ -139,6 +150,16 @@ module Net
139
150
  with_prompts[-1] || default_prompt
140
151
  end
141
152
 
153
+ # run something with a different named prompt
154
+ #
155
+ # named_prompts["root"] = /(?<prompt>\nroot)\z/
156
+ #
157
+ # with_named_prompt("root") do
158
+ # cmd("sudo -i")
159
+ # cmd("cat /etc/passwd")
160
+ # end
161
+ # cmd("exit")
162
+ #
142
163
  def with_named_prompt(name)
143
164
  raise Error::UndefinedMatch, "unknown named_prompt #{name}" unless named_prompts[name]
144
165
 
@@ -147,20 +168,25 @@ module Net
147
168
  end
148
169
  end
149
170
 
171
+ # tries to detect the prompt
172
+ # sends a "\n", waits for a X seconds, and uses the last line as prompt
173
+ # this won't work reliable if the prompt changes during the session
150
174
  def detect_prompt(seconds: 3)
151
175
  write_n
152
- future = Time.now + seconds
153
- while future > Time.now
154
- process
155
- sleep 0.1
156
- end
176
+ process(seconds)
157
177
  self.default_prompt = read[/\n?^.*\z/]
158
178
  raise Error::PromptDetection, "couldn't detect a prompt" unless default_prompt.present?
159
179
 
160
180
  default_prompt
161
181
  end
162
182
 
163
- # prove a block where the default prompt changes
183
+ # run something with a different prompt
184
+ #
185
+ # with_prompt(/(?<prompt>\nroot)\z/) do
186
+ # cmd("sudo -i")
187
+ # cmd("cat /etc/passwd")
188
+ # end
189
+ # cmd("exit")
164
190
  def with_prompt(prompt)
165
191
  logger.debug { "#with_prompt: #{current_prompt.inspect} => #{prompt.inspect}" }
166
192
  with_prompts << prompt
@@ -171,26 +197,48 @@ module Net
171
197
  logger.debug { "#with_prompt: => #{current_prompt.inspect}" }
172
198
  end
173
199
 
174
- def read_till(prompt: current_prompt, timeout: read_till_timeout, **_opts)
200
+ # continues to process the ssh connection till #stdout matches the given prompt.
201
+ # might raise a timeout error if a soft/hard timeout is given
202
+ # be carefull when using the hard_timeout, this is using the dangerous Timeout.timeout
203
+ # this gets really slow on large outputs, since the prompt will be searched in the whole output. Use \z in the regex if possible
204
+ #
205
+ # Optional named arguments:
206
+ # - prompt: expected to be a regex
207
+ # - timeout: nil or a number
208
+ # - hard_timeout: nil, true, or a number
209
+ # - hard_timeout_factor: nil, true, or a number
210
+ # - when hard_timeout == true, this will set the hard_timeout as (read_till_hard_timeout_factor * read_till_timeout), defaults to 1.2 = +20%
211
+ def read_till(prompt: current_prompt, timeout: read_till_timeout, hard_timeout: read_till_hard_timeout, hard_timeout_factor: read_till_hard_timeout_factor, **_opts)
175
212
  raise Error::UndefinedMatch, 'no prompt given or default_prompt defined' unless prompt
213
+ hard_timeout = (read_till_hard_timeout_factor * timeout) if timeout and hard_timeout == true
214
+ hard_timeout = nil if hard_timeout == true
176
215
 
177
- hard_timeout = timeout
178
- hard_timeout += 0.5 if timeout
179
- ::Timeout.timeout(hard_timeout, Error::ReadTillTimeout) do
180
- with_prompt(prompt) do
216
+ with_prompt(prompt) do
217
+ ::Timeout.timeout(hard_timeout, Error::ReadTillTimeout, "#{current_prompt.inspect} didn't match on #{stdout.inspect} within #{hard_timeout}s") do
181
218
  soft_timeout = Time.now + timeout if timeout
182
- until stdout[current_prompt] do
219
+ until prompt_in_stdout? do
183
220
  if timeout and soft_timeout < Time.now
184
- raise Error::ReadTillTimeout, "Timeout after #{timeout}s, #{current_prompt.inspect} never matched #{stdout.inspect}"
221
+ raise Error::ReadTillTimeout, "#{current_prompt.inspect} didn't match on #{stdout.inspect} within #{timeout}s"
185
222
  end
186
223
  process
187
- sleep 0.1
224
+ sleep 0.01 # don't race for CPU
188
225
  end
189
226
  end
190
227
  end
191
228
  read
192
229
  end
193
230
 
231
+ def prompt_in_stdout?
232
+ case current_prompt
233
+ when Regexp
234
+ !!stdout[current_prompt]
235
+ when String
236
+ stdout.include?(current_prompt)
237
+ else
238
+ raise Net::SSH::CLI::Error, "prompt/current_prompt is not a String/Regex #{current_prompt.inspect}"
239
+ end
240
+ end
241
+
194
242
  def read_for(seconds:)
195
243
  process(seconds)
196
244
  read
@@ -198,40 +246,66 @@ module Net
198
246
 
199
247
  def dialog(command, prompt, **opts)
200
248
  opts = opts.clone.merge(prompt: prompt)
201
- cmd(command, opts)
249
+ cmd(command, **opts)
202
250
  end
203
251
 
204
- # 'read' first on purpuse as a feature. once you cmd you ignore what happend before. otherwise use read|write directly.
205
- # this should avoid many horrible state issues where the prompt is not the last prompt
206
- def cmd(command, pre_read: true, rm_prompt: cmd_rm_prompt, rm_command: cmd_rm_command, prompt: current_prompt, **opts)
252
+ # send a command and get the output as return value
253
+ # 1. sends the given command to the ssh connection channel
254
+ # 2. continues to process the ssh connection until the prompt is found in the stdout
255
+ # 3. prepares the output using your callbacks
256
+ # 4. returns the output of your command
257
+ # Hint: 'read' first on purpose as a feature. once you cmd you ignore what happend before. otherwise use read|write directly.
258
+ # this should avoid many horrible state issues where the prompt is not the last prompt
259
+ def cmd(command, pre_read: true, rm_prompt: cmd_rm_prompt, rm_command: cmd_rm_command, prompt: current_prompt, minimum_duration: cmd_minimum_duration, **opts)
207
260
  opts = opts.clone.merge(pre_read: pre_read, rm_prompt: rm_prompt, rm_command: rm_command, prompt: prompt)
208
261
  if pre_read
209
262
  pre_read_data = read
210
263
  logger.debug { "#cmd ignoring pre-command output: #{pre_read_data.inspect}" } if pre_read_data.present?
211
264
  end
265
+ before_cmd_procs.each { |_name, a_proc| instance_eval(&a_proc) }
212
266
  write_n command
213
- output = read_till(opts)
214
- rm_prompt!(output, opts)
215
- rm_command!(output, command, opts)
267
+ sleep(minimum_duration)
268
+ output = read_till(**opts)
269
+ rm_prompt!(output, **opts)
270
+ rm_command!(output, command, **opts)
271
+ after_cmd_procs.each { |_name, a_proc| instance_eval(&a_proc) }
216
272
  output
273
+ rescue Error::ReadTillTimeout => error
274
+ raise Error::CMD, "#{error.message} after cmd #{command.inspect} was sent"
217
275
  end
218
276
  alias command cmd
219
277
  alias exec cmd
220
278
 
279
+ # Execute multiple cmds, see #cmd
221
280
  def cmds(*commands, **opts)
222
281
  commands.flatten.map { |command| [command, cmd(command, **opts)] }
223
282
  end
224
283
  alias commands cmds
225
284
 
226
285
  def rm_command!(output, command, **opts)
227
- output[command + "\n"] = '' if rm_command?(opts) && output[command + "\n"]
286
+ output[command + cmd_rm_command_tail] = '' if rm_command?(**opts) && output[command + cmd_rm_command_tail]
228
287
  end
229
288
 
230
- def rm_prompt!(output, **opts)
231
- if rm_prompt?(opts)
232
- prompt = opts[:prompt] || current_prompt
289
+ # removes the prompt from the given output
290
+ # prompt should contain a named match 'prompt' /(?<prompt>.*something.*)\z/
291
+ # for backwards compatibility it also tries to replace the first match of the prompt /(something)\z/
292
+ # it removes the whole match if no matches are given /something\z/
293
+ def rm_prompt!(output, prompt: current_prompt, **opts)
294
+ if rm_prompt?(**opts)
233
295
  if output[prompt]
234
- prompt.is_a?(Regexp) ? output[prompt, 1] = '' : output[prompt] = ''
296
+ case prompt
297
+ when String then output[prompt] = ''
298
+ when Regexp
299
+ if prompt.names.include?("prompt")
300
+ output[prompt, "prompt"] = ''
301
+ else
302
+ begin
303
+ output[prompt, 1] = ''
304
+ rescue IndexError
305
+ output[prompt] = ''
306
+ end
307
+ end
308
+ end
235
309
  end
236
310
  end
237
311
  end
@@ -258,6 +332,19 @@ module Net
258
332
  alias hostname host
259
333
  alias to_s host
260
334
 
335
+ # if #sleep_procs are set, they will be called instead of Kernel.sleep
336
+ # great for async
337
+ # .sleep_procs["async"] = proc do |duration| async_reactor.sleep(duration) end
338
+ #
339
+ # cli.sleep(1)
340
+ def sleep(duration)
341
+ if sleep_procs.any?
342
+ sleep_procs.each { |_name, a_proc| instance_exec(duration, &a_proc) }
343
+ else
344
+ Kernel.sleep(duration)
345
+ end
346
+ end
347
+
261
348
  ## NET::SSH
262
349
  #
263
350
 
@@ -330,6 +417,17 @@ module Net
330
417
  def rm_command?(**opts)
331
418
  opts[:rm_cmd].nil? ? cmd_rm_command : opts[:rm_cmd]
332
419
  end
420
+
421
+ # when new data is beeing received, likely more data will arrive - this improves the performance by a large factor
422
+ # but on a lot of data, this leads to a stack level too deep
423
+ # therefore it is limited to max #on_stdout_processing
424
+ # the bigger on_stdout_processing, the closer we get to a stack level too deep
425
+ def optimise_stdout_processing
426
+ self.process_count += 1
427
+ process unless process_count > on_stdout_processing
428
+ ensure
429
+ self.process_count -= 1
430
+ end
333
431
  end
334
432
  end
335
433
  end
@@ -3,7 +3,7 @@
3
3
  module Net
4
4
  module SSH
5
5
  module CLI
6
- VERSION = '1.3.1'
6
+ VERSION = '1.8.0'
7
7
  end
8
8
  end
9
9
  end
data/net-ssh-cli.gemspec CHANGED
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
39
39
 
40
40
  spec.add_development_dependency 'bundler'
41
41
  spec.add_development_dependency 'bump'
42
- spec.add_development_dependency 'rake', '~> 10.0'
42
+ spec.add_development_dependency 'rake', '~> 13.0'
43
43
  spec.add_development_dependency 'rspec', '~> 3.0'
44
44
  spec.add_dependency 'activesupport', '>= 4.0'
45
45
  spec.add_dependency 'net-ssh', '>= 4.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-ssh-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fabian Stillhart
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-15 00:00:00.000000000 Z
11
+ date: 2021-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '13.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '13.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -125,7 +125,7 @@ homepage: https://github.com/swisscom/net-ssh-cli
125
125
  licenses:
126
126
  - MIT
127
127
  metadata: {}
128
- post_install_message:
128
+ post_install_message:
129
129
  rdoc_options: []
130
130
  require_paths:
131
131
  - lib
@@ -140,8 +140,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
140
  - !ruby/object:Gem::Version
141
141
  version: '0'
142
142
  requirements: []
143
- rubygems_version: 3.0.4
144
- signing_key:
143
+ rubygems_version: 3.2.15
144
+ signing_key:
145
145
  specification_version: 4
146
146
  summary: 'Net::SSH::CLI: A library to handle CLI Sessions'
147
147
  test_files: []