net-ssh-cli 1.5.0 → 1.9.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: 3c603e7ea0fcbda5d3e982acf28cd42b1f8eaa5aa7d553f8b4e6e0e783ccf3ec
4
- data.tar.gz: 0c70002f557ad71cee9a12f32998c808fe6d984d24c82a1a11c9f7f0a04655e4
3
+ metadata.gz: fe1c60d30e59f8fc15074b0a59f9a0c868f47472df17d1ad156c301b3582bc22
4
+ data.tar.gz: bd9f7a6dd71fb3429440f2fd6713d7f04322aba58705bd63d474156a7932cf00
5
5
  SHA512:
6
- metadata.gz: 4f806eb1c4a035b586ce2b2e3783db4a8ba77d4143e7b916686fe95d54a0f5f748139245265b7cca18a52cdf7cbdb28de3f54c71bcbbb8cad15e03eeeb7599b6
7
- data.tar.gz: ff6953edf2520f5732ee7b896a30e6fa184506093addb7e39b0c8cb69eb5735f928291047f989a1ba100f2d5a317cda5608cea1c97624eaac6b284c83e34b923
6
+ metadata.gz: c81d16a0fd072fea7563c55aaae2bbd0f17622ff27294ec080c14084cf11a106a6bbadb7aeb6516aab8cbb5e35ee8a8be501b33f45f0ed8afff5e0fbb36a08dd
7
+ data.tar.gz: 8f27e6a09b431191571d90d360486a4141c3b314bf291b948fe401737049e6deebfdd25d8aeaeb830cdeb8727074ae628880c03ea3987f988775a349958c31f8
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
@@ -162,6 +182,8 @@ The following callbacks are available
162
182
  - after_open_channel
163
183
  - before_on_stdout
164
184
  - after_on_stdout
185
+ - before_on_stdin
186
+ - after_on_stdin
165
187
 
166
188
  ```ruby
167
189
  cli.before_open_channel do
@@ -184,12 +206,33 @@ cli.after_on_stdout do
184
206
  end
185
207
  ```
186
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
187
216
  ```ruby
188
217
  cli.after_on_stdout do
189
218
  stdout.gsub!("\r\n", "\n")
190
219
  end
191
220
  ```
192
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
+
193
236
  ### #hostname #host #to_s
194
237
 
195
238
  ```ruby
@@ -213,6 +256,38 @@ This works usually, but is not guaranteed to work well.
213
256
  # => "[my prompt]"
214
257
  ```
215
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
+
216
291
  ## Development
217
292
 
218
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.
@@ -3,7 +3,7 @@
3
3
  module Net
4
4
  module SSH
5
5
  module CLI
6
- VERSION = '1.5.0'
6
+ VERSION = '1.9.0'
7
7
  end
8
8
  end
9
9
  end
data/lib/net/ssh/cli.rb CHANGED
@@ -40,20 +40,36 @@ module Net
40
40
  attr_accessor :channel, :stdout, :net_ssh, :logger, :new_data, :process_count
41
41
 
42
42
  OPTIONS = ActiveSupport::HashWithIndifferentAccess.new(
43
- 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.
44
44
  cmd_rm_prompt: false, # whether the prompt should be removed in the output of #cmd
45
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.
46
48
  run_impact: false, # whether to run #impact commands. This might align with testing|development|production. example #impact("reboot")
47
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
48
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
49
55
  before_on_stdout_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call before data arrives from the underlying connection
50
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
51
59
  before_open_channel_procs: ActiveSupport::HashWithIndifferentAccess.new, # procs to call before opening a channel
52
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
53
61
  open_channel_timeout: nil, # timeout to open the channel
54
62
  net_ssh_options: ActiveSupport::HashWithIndifferentAccess.new, # a wrapper for options to pass to Net::SSH.start in case net_ssh is undefined
55
63
  process_time: 0.00001, # how long #process is processing net_ssh#process or sleeping (waiting for something)
56
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
67
+ terminal_chars_width: 320, # Sets and sends the terminal dimensions during the opening of the channel. It does not send a channel_request on change.
68
+ terminal_chars_height: 120, # See also https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/connection/channel.rb#L220 section 'def request_pty'
69
+ terminal_pixels_width: 1920, # See also https://www.ietf.org/rfc/rfc4254.txt section pty-req and section window-change
70
+ terminal_pixels_height: 1080, #
71
+ terminal_term: nil, # Sets the terminal term, usually xterm
72
+ terminal_modes: nil, #
57
73
  )
58
74
 
59
75
  def options
@@ -89,7 +105,9 @@ module Net
89
105
 
90
106
  OPTIONS.keys.select {|key| key.to_s.include? "procs"}.each do |name|
91
107
  define_method name.sub("_procs","") do |&blk|
92
- self.send(name)[SecureRandom.uuid] = Proc.new {blk.call}
108
+ id = SecureRandom.uuid
109
+ self.send(name)[id] = Proc.new {blk.call}
110
+ id
93
111
  end
94
112
  end
95
113
 
@@ -108,19 +126,19 @@ module Net
108
126
  before_on_stdout_procs.each { |_name, a_proc| instance_eval(&a_proc) }
109
127
  stdout << new_data
110
128
  after_on_stdout_procs.each { |_name, a_proc| instance_eval(&a_proc) }
111
- self.process_count += 1
112
- 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
113
- self.process_count -= 1
129
+ optimise_stdout_processing
114
130
  stdout
115
131
  end
116
132
 
117
- def write(content = String.new)
133
+ def stdin(content = String.new)
118
134
  logger.debug { "#write #{content.inspect}" }
135
+ before_on_stdin_procs.each { |_name, a_proc| instance_eval(&a_proc) }
119
136
  channel.send_data content
120
137
  process
138
+ after_on_stdin_procs.each { |_name, a_proc| instance_eval(&a_proc) }
121
139
  content
122
140
  end
123
- alias stdin write
141
+ alias write stdin
124
142
 
125
143
  def write_n(content = String.new)
126
144
  write content + "\n"
@@ -129,7 +147,7 @@ module Net
129
147
  def read
130
148
  process
131
149
  var = stdout!
132
- logger.debug("#read: \n#{var}")
150
+ logger.debug { "#read: \n#{var}" }
133
151
  var
134
152
  end
135
153
 
@@ -140,6 +158,16 @@ module Net
140
158
  with_prompts[-1] || default_prompt
141
159
  end
142
160
 
161
+ # run something with a different named prompt
162
+ #
163
+ # named_prompts["root"] = /(?<prompt>\nroot)\z/
164
+ #
165
+ # with_named_prompt("root") do
166
+ # cmd("sudo -i")
167
+ # cmd("cat /etc/passwd")
168
+ # end
169
+ # cmd("exit")
170
+ #
143
171
  def with_named_prompt(name)
144
172
  raise Error::UndefinedMatch, "unknown named_prompt #{name}" unless named_prompts[name]
145
173
 
@@ -148,20 +176,25 @@ module Net
148
176
  end
149
177
  end
150
178
 
179
+ # tries to detect the prompt
180
+ # sends a "\n", waits for a X seconds, and uses the last line as prompt
181
+ # this won't work reliable if the prompt changes during the session
151
182
  def detect_prompt(seconds: 3)
152
183
  write_n
153
- future = Time.now + seconds
154
- while future > Time.now
155
- process
156
- sleep 0.1
157
- end
184
+ process(seconds)
158
185
  self.default_prompt = read[/\n?^.*\z/]
159
186
  raise Error::PromptDetection, "couldn't detect a prompt" unless default_prompt.present?
160
187
 
161
188
  default_prompt
162
189
  end
163
190
 
164
- # prove a block where the default prompt changes
191
+ # run something with a different prompt
192
+ #
193
+ # with_prompt(/(?<prompt>\nroot)\z/) do
194
+ # cmd("sudo -i")
195
+ # cmd("cat /etc/passwd")
196
+ # end
197
+ # cmd("exit")
165
198
  def with_prompt(prompt)
166
199
  logger.debug { "#with_prompt: #{current_prompt.inspect} => #{prompt.inspect}" }
167
200
  with_prompts << prompt
@@ -172,26 +205,48 @@ module Net
172
205
  logger.debug { "#with_prompt: => #{current_prompt.inspect}" }
173
206
  end
174
207
 
175
- def read_till(prompt: current_prompt, timeout: read_till_timeout, **_opts)
208
+ # continues to process the ssh connection till #stdout matches the given prompt.
209
+ # might raise a timeout error if a soft/hard timeout is given
210
+ # be carefull when using the hard_timeout, this is using the dangerous Timeout.timeout
211
+ # this gets really slow on large outputs, since the prompt will be searched in the whole output. Use \z in the regex if possible
212
+ #
213
+ # Optional named arguments:
214
+ # - prompt: expected to be a regex
215
+ # - timeout: nil or a number
216
+ # - hard_timeout: nil, true, or a number
217
+ # - hard_timeout_factor: nil, true, or a number
218
+ # - when hard_timeout == true, this will set the hard_timeout as (read_till_hard_timeout_factor * read_till_timeout), defaults to 1.2 = +20%
219
+ 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)
176
220
  raise Error::UndefinedMatch, 'no prompt given or default_prompt defined' unless prompt
221
+ hard_timeout = (read_till_hard_timeout_factor * timeout) if timeout and hard_timeout == true
222
+ hard_timeout = nil if hard_timeout == true
177
223
 
178
- hard_timeout = timeout
179
- hard_timeout += 0.5 if timeout
180
- ::Timeout.timeout(hard_timeout, Error::ReadTillTimeout, "#{current_prompt.inspect} didn't match on #{stdout.inspect} within #{timeout}s") do
181
- with_prompt(prompt) do
224
+ with_prompt(prompt) do
225
+ ::Timeout.timeout(hard_timeout, Error::ReadTillTimeout, "#{current_prompt.inspect} didn't match on #{stdout.inspect} within #{hard_timeout}s") do
182
226
  soft_timeout = Time.now + timeout if timeout
183
- until stdout[current_prompt] do
227
+ until prompt_in_stdout? do
184
228
  if timeout and soft_timeout < Time.now
185
229
  raise Error::ReadTillTimeout, "#{current_prompt.inspect} didn't match on #{stdout.inspect} within #{timeout}s"
186
230
  end
187
231
  process
188
- sleep 0.1
232
+ sleep 0.01 # don't race for CPU
189
233
  end
190
234
  end
191
235
  end
192
236
  read
193
237
  end
194
238
 
239
+ def prompt_in_stdout?
240
+ case current_prompt
241
+ when Regexp
242
+ !!stdout[current_prompt]
243
+ when String
244
+ stdout.include?(current_prompt)
245
+ else
246
+ raise Net::SSH::CLI::Error, "prompt/current_prompt is not a String/Regex #{current_prompt.inspect}"
247
+ end
248
+ end
249
+
195
250
  def read_for(seconds:)
196
251
  process(seconds)
197
252
  read
@@ -202,18 +257,26 @@ module Net
202
257
  cmd(command, **opts)
203
258
  end
204
259
 
205
- # 'read' first on purpuse as a feature. once you cmd you ignore what happend before. otherwise use read|write directly.
206
- # this should avoid many horrible state issues where the prompt is not the last prompt
207
- def cmd(command, pre_read: true, rm_prompt: cmd_rm_prompt, rm_command: cmd_rm_command, prompt: current_prompt, **opts)
260
+ # send a command and get the output as return value
261
+ # 1. sends the given command to the ssh connection channel
262
+ # 2. continues to process the ssh connection until the prompt is found in the stdout
263
+ # 3. prepares the output using your callbacks
264
+ # 4. returns the output of your command
265
+ # Hint: 'read' first on purpose as a feature. once you cmd you ignore what happend before. otherwise use read|write directly.
266
+ # this should avoid many horrible state issues where the prompt is not the last prompt
267
+ 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)
208
268
  opts = opts.clone.merge(pre_read: pre_read, rm_prompt: rm_prompt, rm_command: rm_command, prompt: prompt)
209
269
  if pre_read
210
270
  pre_read_data = read
211
271
  logger.debug { "#cmd ignoring pre-command output: #{pre_read_data.inspect}" } if pre_read_data.present?
212
272
  end
273
+ before_cmd_procs.each { |_name, a_proc| instance_eval(&a_proc) }
213
274
  write_n command
275
+ sleep(minimum_duration)
214
276
  output = read_till(**opts)
215
277
  rm_prompt!(output, **opts)
216
278
  rm_command!(output, command, **opts)
279
+ after_cmd_procs.each { |_name, a_proc| instance_eval(&a_proc) }
217
280
  output
218
281
  rescue Error::ReadTillTimeout => error
219
282
  raise Error::CMD, "#{error.message} after cmd #{command.inspect} was sent"
@@ -221,20 +284,36 @@ module Net
221
284
  alias command cmd
222
285
  alias exec cmd
223
286
 
287
+ # Execute multiple cmds, see #cmd
224
288
  def cmds(*commands, **opts)
225
289
  commands.flatten.map { |command| [command, cmd(command, **opts)] }
226
290
  end
227
291
  alias commands cmds
228
292
 
229
293
  def rm_command!(output, command, **opts)
230
- output[command + "\n"] = '' if rm_command?(**opts) && output[command + "\n"]
294
+ output[command + cmd_rm_command_tail] = '' if rm_command?(**opts) && output[command + cmd_rm_command_tail]
231
295
  end
232
296
 
233
- def rm_prompt!(output, **opts)
297
+ # removes the prompt from the given output
298
+ # prompt should contain a named match 'prompt' /(?<prompt>.*something.*)\z/
299
+ # for backwards compatibility it also tries to replace the first match of the prompt /(something)\z/
300
+ # it removes the whole match if no matches are given /something\z/
301
+ def rm_prompt!(output, prompt: current_prompt, **opts)
234
302
  if rm_prompt?(**opts)
235
- prompt = opts[:prompt] || current_prompt
236
303
  if output[prompt]
237
- prompt.is_a?(Regexp) ? output[prompt, 1] = '' : output[prompt] = ''
304
+ case prompt
305
+ when String then output[prompt] = ''
306
+ when Regexp
307
+ if prompt.names.include?("prompt")
308
+ output[prompt, "prompt"] = ''
309
+ else
310
+ begin
311
+ output[prompt, 1] = ''
312
+ rescue IndexError
313
+ output[prompt] = ''
314
+ end
315
+ end
316
+ end
238
317
  end
239
318
  end
240
319
  end
@@ -261,6 +340,19 @@ module Net
261
340
  alias hostname host
262
341
  alias to_s host
263
342
 
343
+ # if #sleep_procs are set, they will be called instead of Kernel.sleep
344
+ # great for async
345
+ # .sleep_procs["async"] = proc do |duration| async_reactor.sleep(duration) end
346
+ #
347
+ # cli.sleep(1)
348
+ def sleep(duration)
349
+ if sleep_procs.any?
350
+ sleep_procs.each { |_name, a_proc| instance_exec(duration, &a_proc) }
351
+ else
352
+ Kernel.sleep(duration)
353
+ end
354
+ end
355
+
264
356
  ## NET::SSH
265
357
  #
266
358
 
@@ -291,7 +383,7 @@ module Net
291
383
  net_ssh.open_channel do |new_channel|
292
384
  logger.debug 'channel is open'
293
385
  self.channel = new_channel
294
- new_channel.request_pty do |_ch, success|
386
+ new_channel.request_pty(terminal_options) do |_ch, success|
295
387
  raise Error::Pty, "#{host || ip} Failed to open ssh pty" unless success
296
388
  end
297
389
  new_channel.send_channel_request('shell') do |_ch, success|
@@ -333,6 +425,28 @@ module Net
333
425
  def rm_command?(**opts)
334
426
  opts[:rm_cmd].nil? ? cmd_rm_command : opts[:rm_cmd]
335
427
  end
428
+
429
+ # when new data is beeing received, likely more data will arrive - this improves the performance by a large factor
430
+ # but on a lot of data, this leads to a stack level too deep
431
+ # therefore it is limited to max #on_stdout_processing
432
+ # the bigger on_stdout_processing, the closer we get to a stack level too deep
433
+ def optimise_stdout_processing
434
+ self.process_count += 1
435
+ process unless process_count > on_stdout_processing
436
+ ensure
437
+ self.process_count -= 1
438
+ end
439
+
440
+ def terminal_options
441
+ {
442
+ term: terminal_term,
443
+ chars_wide: terminal_chars_width,
444
+ chars_high: terminal_chars_height,
445
+ pixels_wide: terminal_pixels_width,
446
+ pixels_high: terminal_pixels_height,
447
+ modes: terminal_modes
448
+ }.reject {|k,v| v.nil?}
449
+ end
336
450
  end
337
451
  end
338
452
  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.5.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fabian Stillhart
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-13 00:00:00.000000000 Z
11
+ date: 2021-09-07 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
@@ -140,7 +140,7 @@ 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.3
143
+ rubygems_version: 3.2.24
144
144
  signing_key:
145
145
  specification_version: 4
146
146
  summary: 'Net::SSH::CLI: A library to handle CLI Sessions'