net-ssh-cli 1.5.0 → 1.9.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
  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'