net-scp 3.0.0 → 4.1.3

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.
@@ -49,7 +49,8 @@ module Net; class SCP
49
49
  directive = "D%04o %d %s\n" % [mode, 0, File.basename(channel[:current])]
50
50
  channel.send_data(directive)
51
51
  channel[:cwd] = channel[:current]
52
- channel[:stack] << Dir.entries(channel[:current]).reject { |i| i == "." || i == ".." }
52
+ entries = Dir.entries(channel[:current]).reject { |i| i == "." || i == ".." }
53
+ channel[:stack] << entries.reject { |i| skip_broken_symlink(channel, File.join(channel[:current], i)) }
53
54
  await_response(channel, :next_item)
54
55
  end
55
56
  end
@@ -91,6 +92,7 @@ module Net; class SCP
91
92
  # upload and moves to #upload_current_state.
92
93
  def next_item_state(channel)
93
94
  if channel[:stack].empty?
95
+ channel[:state] = :finish
94
96
  finish_state(channel)
95
97
  else
96
98
  next_item = channel[:stack].last.shift
@@ -118,6 +120,32 @@ module Net; class SCP
118
120
  end
119
121
 
120
122
  channel[:size] = channel[:stat] ? channel[:stat].size : channel[:current].size
123
+ if channel[:current].respond_to?(:read) && channel[:current].respond_to?(:pos)
124
+ channel[:size] = [channel[:size] - channel[:current].pos, 0].max
125
+ end
126
+ end
127
+
128
+ # Returns true if +path+ is a symlink whose target doesn't exist, after
129
+ # logging a warning and recording it for #raise_if_entries_skipped.
130
+ def skip_broken_symlink(channel, path)
131
+ return false unless File.symlink?(path) && !File.exist?(path)
132
+
133
+ lwarn { "#{path}: broken symlink, skipping" }
134
+ (channel[:skipped] ||= []) << path
135
+ true
136
+ end
137
+
138
+ # Once the remote has closed the channel, raises a Net::SCP::Error listing
139
+ # the entries skipped by #skip_broken_symlink, if any.
140
+ def raise_if_entries_skipped(channel)
141
+ return unless channel.closing? && channel[:skipped]
142
+
143
+ # Cleared so it raises once, as on_process keeps calling this until the close is flushed.
144
+ skipped, channel[:skipped] = channel[:skipped], nil
145
+ # A failed remote scp is reported by start_command's exit-status check instead.
146
+ return unless channel[:exit].to_i.zero?
147
+
148
+ raise Net::SCP::Error, "upload incomplete, skipped broken symlinks: #{skipped.map(&:inspect).join(', ')}"
121
149
  end
122
150
 
123
151
  # If the :preserve option is set, send a 'T' directive and wait for the
@@ -1,5 +1,5 @@
1
1
  module Net
2
- module SCP
2
+ class SCP
3
3
  # A class for describing the current version of a library. The version
4
4
  # consists of three parts: the +major+ number, the +minor+ number, and the
5
5
  # +tiny+ (or +patch+) number.
@@ -46,13 +46,13 @@ module Net
46
46
  end
47
47
 
48
48
  # The major component of this version of the Net::SSH library
49
- MAJOR = 3
49
+ MAJOR = 4
50
50
 
51
51
  # The minor component of this version of the Net::SSH library
52
- MINOR = 0
52
+ MINOR = 1
53
53
 
54
54
  # The tiny component of this version of the Net::SSH library
55
- TINY = 0
55
+ TINY = 3
56
56
 
57
57
  # The prerelease component of this version of the Net::SSH library
58
58
  # nil allowed
data/lib/net/scp.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'pathname'
1
2
  require 'stringio'
2
3
  require 'shellwords'
3
4
 
@@ -64,7 +65,7 @@ module Net
64
65
  # puts "#{name}: #{sent}/#{total}"
65
66
  # end
66
67
  #
67
- # Whenever a new chunk of data is recieved for or sent to a file, the callback
68
+ # Whenever a new chunk of data is received for or sent to a file, the callback
68
69
  # will be invoked, indicating the name of the file (local for downloads,
69
70
  # remote for uploads), the number of bytes that have been sent or received
70
71
  # so far for the file, and the size of the file.
@@ -258,13 +259,24 @@ module Net
258
259
  #
259
260
  # * :recursive - the +local+ parameter refers to a local directory, which
260
261
  # should be uploaded to a new directory named +remote+ on the remote
261
- # server.
262
+ # server. Broken symlinks in it are skipped with a warning, and once
263
+ # everything else is uploaded a Net::SCP::Error listing them is raised.
262
264
  # * :preserve - the atime and mtime of the file should be preserved.
263
265
  # * :verbose - the process should result in verbose output on the server
264
266
  # end (useful for debugging).
265
267
  # * :chunk_size - the size of each "chunk" that should be sent. Defaults
266
268
  # to 2048. Changing this value may improve throughput at the expense
267
269
  # of decreasing interactivity.
270
+ # * :quote - how +remote+ is quoted in the scp command run by the remote
271
+ # shell. :posix (the default) escapes it for a POSIX shell, leaving a
272
+ # leading "~" or "~/" unescaped so it expands to the remote home
273
+ # directory ("~user/" is not expanded). :windows is for Win32-OpenSSH,
274
+ # whose shell may be cmd.exe or PowerShell: backslashes become "/", the
275
+ # path is wrapped in double quotes, and paths containing a double or curly
276
+ # quote, $, `, %, !, CR, LF or NUL raise ArgumentError. :none sends the
277
+ # path unchanged, for servers that don't run a shell (some routers and
278
+ # appliances); never use it with untrusted input. A callable is given
279
+ # +remote+ and returns the string to send.
268
280
  #
269
281
  # This method will return immediately, returning the Net::SSH::Connection::Channel
270
282
  # object that will support the upload. To wait for the upload to finish,
@@ -274,6 +286,10 @@ module Net
274
286
  # channel = scp.upload("/local/path", "/remote/path")
275
287
  # channel.wait
276
288
  def upload(local, remote, options={}, &progress)
289
+ chunk_size = options[:chunk_size] || Upload::DEFAULT_CHUNK_SIZE
290
+ unless chunk_size.is_a?(Integer) && chunk_size > 0
291
+ raise ArgumentError, ":chunk_size must be a positive Integer"
292
+ end
277
293
  start_command(:upload, local, remote, options, &progress)
278
294
  end
279
295
 
@@ -293,6 +309,7 @@ module Net
293
309
  # * :preserve - the atime and mtime of the file should be preserved.
294
310
  # * :verbose - the process should result in verbose output on the server
295
311
  # end (useful for debugging).
312
+ # * :quote - how +remote+ is quoted for the remote shell (see #upload).
296
313
  #
297
314
  # This method will return immediately, returning the Net::SSH::Connection::Channel
298
315
  # object that will support the download. To wait for the download to finish,
@@ -329,7 +346,7 @@ module Net
329
346
  # (:verbose, :recursive, :preserve). Returns the command-line as a
330
347
  # string, ready to execute.
331
348
  def scp_command(mode, options)
332
- command = "scp "
349
+ command = +"scp "
333
350
  command << (mode == :upload ? "-t" : "-f")
334
351
  command << " -v" if options[:verbose]
335
352
  command << " -r" if options[:recursive]
@@ -342,15 +359,15 @@ module Net
342
359
  # sets up a state machine to use to process the upload or download.
343
360
  # (See Net::SCP::Upload and Net::SCP::Download).
344
361
  def start_command(mode, local, remote, options={}, &callback)
345
- session.open_channel do |channel|
346
-
347
- if options[:shell]
348
- escaped_file = shellescape(remote).gsub(/'/) { |m| "'\\''" }
349
- command = "#{options[:shell]} -c '#{scp_command(mode, options)} #{escaped_file}'"
350
- else
351
- command = "#{scp_command(mode, options)} #{shellescape remote}"
352
- end
362
+ local = local.to_path if local.is_a?(Pathname)
363
+ # Kept in channel[:remote] too, so a download's basename check sees "C:/a/b.txt" as b.txt.
364
+ remote = remote.to_s.tr("\\", "/") if options[:quote] == :windows
365
+ command = "#{scp_command(mode, options)} #{quote_remote(remote, options[:quote] || :posix)}"
366
+ if options[:shell]
367
+ command = "#{options[:shell]} -c '#{command.gsub("'") { "'\\''" }}'"
368
+ end
353
369
 
370
+ session.open_channel do |channel|
354
371
  channel.exec(command) do |ch, success|
355
372
  if success
356
373
  channel[:local ] = local
@@ -360,9 +377,28 @@ module Net
360
377
  channel[:buffer ] = Net::SSH::Buffer.new
361
378
  channel[:state ] = "#{mode}_start"
362
379
  channel[:stack ] = []
363
- channel[:error_string] = ''
380
+ channel[:error_string] = +''
364
381
 
365
- channel.on_close { |ch2| send("#{channel[:state]}_state", channel); raise Net::SCP::Error, "SCP did not finish successfully (#{channel[:exit]}): #{channel[:error_string]}" if channel[:exit] != 0 }
382
+ channel.on_close do
383
+ begin
384
+ # The close can be dispatched before on_process has consumed data that arrived with it.
385
+ send("#{channel[:state]}_state", channel)
386
+ # If we got an exit-status and it is not 0, something went wrong
387
+ if !channel[:exit].nil? && channel[:exit] != 0
388
+ raise Net::SCP::Error, 'SCP did not finish successfully ' \
389
+ "(#{channel[:exit]}): #{channel[:error_string]}"
390
+ end
391
+ # A zero or missing exit-status does not prove the transfer completed.
392
+ if channel[:state] != :finish
393
+ message = +'SCP did not finish successfully (channel closed before end of transmission)'
394
+ message << ": #{channel[:error_string]}" unless channel[:error_string].empty?
395
+ raise Net::SCP::Error, message
396
+ end
397
+ ensure
398
+ io = channel[:io]
399
+ io.close if io && io != channel[:local] && !io.closed?
400
+ end
401
+ end
366
402
  channel.on_data { |ch2, data| channel[:buffer].append(data) }
367
403
  channel.on_extended_data { |ch2, type, data| debug { data.chomp } }
368
404
  channel.on_request("exit-status") { |ch2, data| channel[:exit] = data.read_long }
@@ -405,6 +441,7 @@ module Net
405
441
  # of the pipe, and allows the pipe to drain until the server closes it.
406
442
  def finish_state(channel)
407
443
  channel.eof!
444
+ raise_if_entries_skipped(channel)
408
445
  end
409
446
 
410
447
  # Invoked to report progress back to the client. If a callback was not
@@ -413,6 +450,29 @@ module Net
413
450
  channel[:callback].call(channel, name, sent, total) if channel[:callback]
414
451
  end
415
452
 
453
+ # Inside double quotes cmd.exe still expands % and !, PowerShell expands $ and `, and PowerShell also ends a string at U+2018..U+201E.
454
+ WINDOWS_UNSAFE = /["$`%!\r\n\0\u2018-\u201E]/
455
+
456
+ def quote_remote(remote, quote)
457
+ case quote
458
+ when :posix
459
+ remote = remote.to_s
460
+ return remote if remote == "~" || remote == "~/"
461
+ return "~/#{shellescape(remote[2..-1])}" if remote.start_with?("~/")
462
+ shellescape(remote)
463
+ when :windows
464
+ if remote.dup.force_encoding(Encoding::UTF_8) =~ WINDOWS_UNSAFE
465
+ raise ArgumentError, "remote path #{remote.inspect} contains a character that can't be quoted safely for a Windows shell"
466
+ end
467
+ "\"#{remote}\""
468
+ when :none
469
+ remote.to_s
470
+ else
471
+ raise ArgumentError, ":quote must be :posix, :windows, :none or a callable, got #{quote.inspect}" unless quote.respond_to?(:call)
472
+ quote.call(remote).to_s
473
+ end
474
+ end
475
+
416
476
  # Imported from ruby 1.9.2 shellwords.rb
417
477
  def shellescape(path)
418
478
  # Convert path to a string if it isn't already one.
data/lib/uri/open-scp.rb CHANGED
@@ -8,9 +8,21 @@ module URI
8
8
 
9
9
  class SCP
10
10
  def buffer_open(buf, proxy, open_options)
11
- options = open_options.merge(:port => port, :password => password)
11
+ options = open_options.dup
12
+ options[:ssh] = { :port => port }
13
+ options[:ssh][:password] = URI::DEFAULT_PARSER.unescape(password) if password
14
+ options[:ssh].merge!(open_options[:ssh] || {})
12
15
  progress = options.delete(:progress_proc)
13
- buf << Net::SCP.download!(host, user, path, nil, options, &progress)
16
+ content_length = options.delete(:content_length_proc)
17
+ output = Object.new
18
+ output.define_singleton_method(:write) { |data| buf << data }
19
+ Net::SCP.download!(hostname, user && URI::DEFAULT_PARSER.unescape(user), URI::DEFAULT_PARSER.unescape(path), output, options) do |_channel, _name, received, total|
20
+ if content_length
21
+ content_length.call(total)
22
+ content_length = nil
23
+ end
24
+ progress.call(received) if progress
25
+ end
14
26
  buf.io.rewind
15
27
  end
16
28
 
data/lib/uri/scp.rb CHANGED
@@ -8,11 +8,9 @@ module URI
8
8
  :scheme,
9
9
  :userinfo,
10
10
  :host, :port, :path,
11
- :query
11
+ :query
12
12
  ].freeze
13
13
 
14
- attr_reader :options
15
-
16
14
  def self.new2(user, password, host, port, path, query)
17
15
  new('scp', [user, password], host, port, nil, path, nil, query)
18
16
  end
@@ -20,16 +18,29 @@ module URI
20
18
  def initialize(*args)
21
19
  super(*args)
22
20
 
21
+ options
22
+ end
23
+
24
+ def options
25
+ return @options if defined?(@options_query) && @options_query == query
26
+
27
+ @options_query = query && query.dup
23
28
  @options = Hash.new
24
29
  (query || "").split(/&/).each do |pair|
30
+ next if pair.empty?
25
31
  name, value = pair.split(/=/, 2)
26
32
  opt_name = name.to_sym
27
- values = value.split(/,/).map { |v| v.to_i.to_s == v ? v.to_i : v }
33
+ values = value.to_s.split(/,/).map { |v| v.to_i.to_s == v ? v.to_i : v }
28
34
  values = values.first if values.length == 1
29
- options[opt_name] = values
35
+ @options[opt_name] = values
30
36
  end
37
+ @options
31
38
  end
32
39
  end
33
40
 
34
- @@schemes['SCP'] = SCP
35
- end
41
+ if respond_to? :register_scheme
42
+ register_scheme "SCP", SCP
43
+ else
44
+ @@schemes["SCP"] = SCP
45
+ end
46
+ end
@@ -1,20 +1,21 @@
1
1
  -----BEGIN CERTIFICATE-----
2
- MIIDQDCCAiigAwIBAgIBATANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBpuZXRz
3
- c2gvREM9c29sdXRpb3VzL0RDPWNvbTAeFw0yMDAyMDMxMTEwMjJaFw0yMTAyMDIx
4
- MTEwMjJaMCUxIzAhBgNVBAMMGm5ldHNzaC9EQz1zb2x1dGlvdXMvREM9Y29tMIIB
5
- IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxieE22fR/qmdPKUHyYTyUx2g
6
- wskLwrCkxay+Tvc97ZZUOwf85LDDDPqhQaTWLvRwnIOMgQE2nBPzwalVclK6a+pW
7
- x/18KDeZY15vm3Qn5p42b0wi9hUxOqPm3J2hdCLCcgtENgdX21nVzejn39WVqFJO
8
- lntgSDNW5+kCS8QaRsmIbzj17GKKkrsw39kiQw7FhWfJFeTjddzoZiWwc59KA/Bx
9
- fBbmDnsMLAtAtauMOxORrbx3EOY7sHku/kSrMg3FXFay7jc6BkbbUij+MjJ/k82l
10
- 4o8o0YO4BAnya90xgEmgOG0LCCxRhuXQFnMDuDjK2XnUe0h4/6NCn94C+z9GsQID
11
- AQABo3sweTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUBfKiwO2e
12
- M4NEiRrVG793qEPLYyMwHwYDVR0RBBgwFoEUbmV0c3NoQHNvbHV0aW91cy5jb20w
13
- HwYDVR0SBBgwFoEUbmV0c3NoQHNvbHV0aW91cy5jb20wDQYJKoZIhvcNAQELBQAD
14
- ggEBAEX1hTqm214do6XA9kKqZ9Y5vAEoylc486EO+2tqB0IPd2fDfoR3cHaF+wce
15
- nirOmEJ+H9Q4Ehx+/bycte/zhADTXXdIVzrcee47yZ3FXPkWIuItB+UdIWDyle6a
16
- d6WBpOQfuEU4f10hGew2qTMjmnr9s1XDO2kBcfwaIW3jTTQbqmH70wy+t+5i+sQb
17
- 3EsE1xwDi47Td8kbeJ/RsvVIpXdq6aXILzlRMV86Qd1N4gRm3M52TehJa9RJseTw
18
- pG2//qKBn/ef0vtnP/2TUc+8Y79K7nCh/TIS0nuFZPH9anXsyVZxp7IByWrsLUtI
19
- Nkqln1AUK+VU/Y+SS6RfI4irHlQ=
2
+ MIIDeDCCAmCgAwIBAgIBATANBgkqhkiG9w0BAQsFADBBMQ8wDQYDVQQDDAZuZXRz
3
+ c2gxGTAXBgoJkiaJk/IsZAEZFglzb2x1dGlvdXMxEzARBgoJkiaJk/IsZAEZFgNj
4
+ b20wHhcNMjYwNTE2MTYyMDUzWhcNMjcwNTE2MTYyMDUzWjBBMQ8wDQYDVQQDDAZu
5
+ ZXRzc2gxGTAXBgoJkiaJk/IsZAEZFglzb2x1dGlvdXMxEzARBgoJkiaJk/IsZAEZ
6
+ FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGJ4TbZ9H+qZ08
7
+ pQfJhPJTHaDCyQvCsKTFrL5O9z3tllQ7B/zksMMM+qFBpNYu9HCcg4yBATacE/PB
8
+ qVVyUrpr6lbH/XwoN5ljXm+bdCfmnjZvTCL2FTE6o+bcnaF0IsJyC0Q2B1fbWdXN
9
+ 6Off1ZWoUk6We2BIM1bn6QJLxBpGyYhvOPXsYoqSuzDf2SJDDsWFZ8kV5ON13Ohm
10
+ JbBzn0oD8HF8FuYOewwsC0C1q4w7E5GtvHcQ5juweS7+RKsyDcVcVrLuNzoGRttS
11
+ KP4yMn+TzaXijyjRg7gECfJr3TGASaA4bQsILFGG5dAWcwO4OMrZedR7SHj/o0Kf
12
+ 3gL7P0axAgMBAAGjezB5MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
13
+ BBQF8qLA7Z4zg0SJGtUbv3eoQ8tjIzAfBgNVHREEGDAWgRRuZXRzc2hAc29sdXRp
14
+ b3VzLmNvbTAfBgNVHRIEGDAWgRRuZXRzc2hAc29sdXRpb3VzLmNvbTANBgkqhkiG
15
+ 9w0BAQsFAAOCAQEAVx/yCCX0ZPQ8TFeZe1T+OBEn3Co/AfjAmCdhstf1TF+Jziyx
16
+ dFJ8m8mF4596gru87Mi8mvu+WbPsLlFMOf5LDUkAsgnlvJ+zqNL7jPjGmsh0KOHJ
17
+ 0dzPYnTeGcfyrp1AXNN3Z2jWlEInrnqvo376vOmejjTtmDVVlhPjITHQqLSXzRaQ
18
+ e3M8fbJ+nupobti6jpXCYvH86KtpaxF66mwaynfdjzxQAVycV/ilKtL+sHH8zxlg
19
+ vNiMFH5yLu/tlav4xh+HlYscWVdFQIvd7f/Uxa+Vip1Pi16wmhnrE15z/vDX921v
20
+ hukBRIoCEAuUgNVBh+L/C8aETzbf/77WU3Si/w==
20
21
  -----END CERTIFICATE-----
data/net-scp.gemspec CHANGED
@@ -17,13 +17,14 @@ Gem::Specification.new do |spec|
17
17
  spec.homepage = "https://github.com/net-ssh/net-scp"
18
18
  spec.license = "MIT"
19
19
  spec.required_rubygems_version = Gem::Requirement.new(">= 0") if spec.respond_to? :required_rubygems_version=
20
+ spec.required_ruby_version = ">= 2.3"
20
21
  spec.metadata = {
21
22
  "changelog_uri" => "https://github.com/net-ssh/net-scp/blob/master/CHANGES.txt"
22
23
  }
23
24
 
24
25
  spec.extra_rdoc_files = [
25
26
  "LICENSE.txt",
26
- "README.rdoc"
27
+ "README.md"
27
28
  ]
28
29
 
29
30
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
@@ -33,16 +34,16 @@ Gem::Specification.new do |spec|
33
34
  spec.specification_version = 3
34
35
 
35
36
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
36
- spec.add_runtime_dependency(%q<net-ssh>, [">= 2.6.5", "< 7.0.0"])
37
+ spec.add_runtime_dependency(%q<net-ssh>, [">= 2.6.5", "< 9.0.0"])
37
38
  spec.add_development_dependency(%q<test-unit>, [">= 0"])
38
39
  spec.add_development_dependency(%q<mocha>, [">= 0"])
39
40
  else
40
- spec.add_dependency(%q<net-ssh>, [">= 2.6.5", "< 7.0.0"])
41
+ spec.add_dependency(%q<net-ssh>, [">= 2.6.5", "< 9.0.0"])
41
42
  spec.add_dependency(%q<test-unit>, [">= 0"])
42
43
  spec.add_dependency(%q<mocha>, [">= 0"])
43
44
  end
44
45
  else
45
- spec.add_dependency(%q<net-ssh>, [">= 2.6.5", "< 7.0.0"])
46
+ spec.add_dependency(%q<net-ssh>, [">= 2.6.5", "< 9.0.0"])
46
47
  spec.add_dependency(%q<test-unit>, [">= 0"])
47
48
  spec.add_dependency(%q<mocha>, [">= 0"])
48
49
  end
data/setup.rb CHANGED
@@ -120,7 +120,7 @@ class ConfigTable
120
120
  ((major == 1) and
121
121
  ((minor >= 5) or
122
122
  ((minor == 4) and (teeny >= 4)))))
123
-
123
+
124
124
  subprefix = lambda {|path|
125
125
  path.sub(/\A#{Regexp.quote(c['prefix'])}/o, '$prefix')
126
126
  }
@@ -172,7 +172,7 @@ class ConfigTable
172
172
  'the directory for ruby scripts' ] ],
173
173
  [ 'so-dir', [ sodir,
174
174
  'path',
175
- 'the directory for ruby extentions' ] ],
175
+ 'the directory for ruby extensions' ] ],
176
176
  [ 'data-dir', [ '$prefix/share',
177
177
  'path',
178
178
  'the directory for shared data' ] ],
@@ -184,10 +184,10 @@ class ConfigTable
184
184
  'the ruby program using for installation' ] ],
185
185
  [ 'make-prog', [ makeprog,
186
186
  'name',
187
- 'the make program to compile ruby extentions' ] ],
187
+ 'the make program to compile ruby extensions' ] ],
188
188
  [ 'without-ext', [ 'no',
189
189
  'yes/no',
190
- 'does not compile/install ruby extentions' ] ]
190
+ 'does not compile/install ruby extensions' ] ]
191
191
  ]
192
192
  multipackage_descripters = [
193
193
  [ 'with', [ '',
@@ -303,7 +303,7 @@ class ConfigTable
303
303
  unless ConfigTable.config_key?(k)
304
304
  @table[k] = v
305
305
  end
306
-
306
+
307
307
  def [](key)
308
308
  return nil unless @table[key]
309
309
  @table[key].gsub(%r<\$([^/]+)>) { self[$1] }
@@ -479,7 +479,7 @@ module FileOperations
479
479
  def ruby(str)
480
480
  command config('ruby-prog') + ' ' + str
481
481
  end
482
-
482
+
483
483
  def make(task = '')
484
484
  command config('make-prog') + ' ' + task
485
485
  end
@@ -572,7 +572,7 @@ module HookScriptAPI
572
572
  def srcdirectory?(path)
573
573
  File.dir?(srcfile(path))
574
574
  end
575
-
575
+
576
576
  def srcfile?(path)
577
577
  File.file? srcfile(path)
578
578
  end
@@ -606,10 +606,10 @@ class ToplevelInstaller
606
606
  TASKS = [
607
607
  [ 'config', 'saves your configurations' ],
608
608
  [ 'show', 'shows current configuration' ],
609
- [ 'setup', 'compiles ruby extentions and others' ],
609
+ [ 'setup', 'compiles ruby extensions and others' ],
610
610
  [ 'install', 'installs files' ],
611
- [ 'clean', "does `make clean' for each extention" ],
612
- [ 'distclean',"does `make distclean' for each extention" ]
611
+ [ 'clean', "does `make clean' for each extension" ],
612
+ [ 'distclean',"does `make distclean' for each extension" ]
613
613
  ]
614
614
 
615
615
  def ToplevelInstaller.invoke
@@ -708,7 +708,7 @@ class ToplevelInstaller
708
708
  when '-v', '--version'
709
709
  puts "#{File.basename($0)} version #{Version}"
710
710
  exit 0
711
-
711
+
712
712
  when '--copyright'
713
713
  puts Copyright
714
714
  exit 0
@@ -911,7 +911,7 @@ class ToplevelInstallerMulti < ToplevelInstaller
911
911
 
912
912
  def print_usage(f)
913
913
  super
914
- f.puts 'Inluded packages:'
914
+ f.puts 'Included packages:'
915
915
  f.puts ' ' + @packages.sort.join(' ')
916
916
  f.puts
917
917
  end
@@ -1146,7 +1146,7 @@ class Installer
1146
1146
 
1147
1147
  def install_dir_ext(rel)
1148
1148
  return unless extdir?(curr_srcdir())
1149
- install_files ruby_extentions('.'),
1149
+ install_files ruby_extensions('.'),
1150
1150
  "#{config('so-dir')}/#{File.dirname(rel)}",
1151
1151
  0555
1152
1152
  end
@@ -1165,9 +1165,9 @@ class Installer
1165
1165
  def ruby_scripts
1166
1166
  collect_filenames_auto().select {|n| /\.rb\z/ =~ n || "module.yml" == n }
1167
1167
  end
1168
-
1168
+
1169
1169
  # picked up many entries from cvs-1.11.1/src/ignore.c
1170
- reject_patterns = %w(
1170
+ reject_patterns = %w(
1171
1171
  core RCSLOG tags TAGS .make.state
1172
1172
  .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
1173
1173
  *~ *.old *.bak *.BAK *.orig *.rej _$* *$
@@ -1212,14 +1212,14 @@ class Installer
1212
1212
  }
1213
1213
  end
1214
1214
 
1215
- def ruby_extentions(dir)
1216
- _ruby_extentions(dir) or
1217
- raise InstallError, "no ruby extention exists: 'ruby #{$0} setup' first"
1215
+ def ruby_extensions(dir)
1216
+ _ruby_extensions(dir) or
1217
+ raise InstallError, "no ruby extension exists: 'ruby #{$0} setup' first"
1218
1218
  end
1219
1219
 
1220
1220
  DLEXT = /\.#{ ::Config::CONFIG['DLEXT'] }\z/
1221
1221
 
1222
- def _ruby_extentions(dir)
1222
+ def _ruby_extensions(dir)
1223
1223
  Dir.open(dir) {|d|
1224
1224
  return d.select {|fname| DLEXT =~ fname }
1225
1225
  }
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,37 +1,38 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-scp
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 4.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamis Buck
8
8
  - Delano Mandelbaum
9
9
  - Miklós Fazekas
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain:
13
13
  - |
14
14
  -----BEGIN CERTIFICATE-----
15
- MIIDQDCCAiigAwIBAgIBATANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBpuZXRz
16
- c2gvREM9c29sdXRpb3VzL0RDPWNvbTAeFw0yMDAyMDMxMTEwMjJaFw0yMTAyMDIx
17
- MTEwMjJaMCUxIzAhBgNVBAMMGm5ldHNzaC9EQz1zb2x1dGlvdXMvREM9Y29tMIIB
18
- IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxieE22fR/qmdPKUHyYTyUx2g
19
- wskLwrCkxay+Tvc97ZZUOwf85LDDDPqhQaTWLvRwnIOMgQE2nBPzwalVclK6a+pW
20
- x/18KDeZY15vm3Qn5p42b0wi9hUxOqPm3J2hdCLCcgtENgdX21nVzejn39WVqFJO
21
- lntgSDNW5+kCS8QaRsmIbzj17GKKkrsw39kiQw7FhWfJFeTjddzoZiWwc59KA/Bx
22
- fBbmDnsMLAtAtauMOxORrbx3EOY7sHku/kSrMg3FXFay7jc6BkbbUij+MjJ/k82l
23
- 4o8o0YO4BAnya90xgEmgOG0LCCxRhuXQFnMDuDjK2XnUe0h4/6NCn94C+z9GsQID
24
- AQABo3sweTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUBfKiwO2e
25
- M4NEiRrVG793qEPLYyMwHwYDVR0RBBgwFoEUbmV0c3NoQHNvbHV0aW91cy5jb20w
26
- HwYDVR0SBBgwFoEUbmV0c3NoQHNvbHV0aW91cy5jb20wDQYJKoZIhvcNAQELBQAD
27
- ggEBAEX1hTqm214do6XA9kKqZ9Y5vAEoylc486EO+2tqB0IPd2fDfoR3cHaF+wce
28
- nirOmEJ+H9Q4Ehx+/bycte/zhADTXXdIVzrcee47yZ3FXPkWIuItB+UdIWDyle6a
29
- d6WBpOQfuEU4f10hGew2qTMjmnr9s1XDO2kBcfwaIW3jTTQbqmH70wy+t+5i+sQb
30
- 3EsE1xwDi47Td8kbeJ/RsvVIpXdq6aXILzlRMV86Qd1N4gRm3M52TehJa9RJseTw
31
- pG2//qKBn/ef0vtnP/2TUc+8Y79K7nCh/TIS0nuFZPH9anXsyVZxp7IByWrsLUtI
32
- Nkqln1AUK+VU/Y+SS6RfI4irHlQ=
15
+ MIIDeDCCAmCgAwIBAgIBATANBgkqhkiG9w0BAQsFADBBMQ8wDQYDVQQDDAZuZXRz
16
+ c2gxGTAXBgoJkiaJk/IsZAEZFglzb2x1dGlvdXMxEzARBgoJkiaJk/IsZAEZFgNj
17
+ b20wHhcNMjYwNTE2MTYyMDUzWhcNMjcwNTE2MTYyMDUzWjBBMQ8wDQYDVQQDDAZu
18
+ ZXRzc2gxGTAXBgoJkiaJk/IsZAEZFglzb2x1dGlvdXMxEzARBgoJkiaJk/IsZAEZ
19
+ FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGJ4TbZ9H+qZ08
20
+ pQfJhPJTHaDCyQvCsKTFrL5O9z3tllQ7B/zksMMM+qFBpNYu9HCcg4yBATacE/PB
21
+ qVVyUrpr6lbH/XwoN5ljXm+bdCfmnjZvTCL2FTE6o+bcnaF0IsJyC0Q2B1fbWdXN
22
+ 6Off1ZWoUk6We2BIM1bn6QJLxBpGyYhvOPXsYoqSuzDf2SJDDsWFZ8kV5ON13Ohm
23
+ JbBzn0oD8HF8FuYOewwsC0C1q4w7E5GtvHcQ5juweS7+RKsyDcVcVrLuNzoGRttS
24
+ KP4yMn+TzaXijyjRg7gECfJr3TGASaA4bQsILFGG5dAWcwO4OMrZedR7SHj/o0Kf
25
+ 3gL7P0axAgMBAAGjezB5MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
26
+ BBQF8qLA7Z4zg0SJGtUbv3eoQ8tjIzAfBgNVHREEGDAWgRRuZXRzc2hAc29sdXRp
27
+ b3VzLmNvbTAfBgNVHRIEGDAWgRRuZXRzc2hAc29sdXRpb3VzLmNvbTANBgkqhkiG
28
+ 9w0BAQsFAAOCAQEAVx/yCCX0ZPQ8TFeZe1T+OBEn3Co/AfjAmCdhstf1TF+Jziyx
29
+ dFJ8m8mF4596gru87Mi8mvu+WbPsLlFMOf5LDUkAsgnlvJ+zqNL7jPjGmsh0KOHJ
30
+ 0dzPYnTeGcfyrp1AXNN3Z2jWlEInrnqvo376vOmejjTtmDVVlhPjITHQqLSXzRaQ
31
+ e3M8fbJ+nupobti6jpXCYvH86KtpaxF66mwaynfdjzxQAVycV/ilKtL+sHH8zxlg
32
+ vNiMFH5yLu/tlav4xh+HlYscWVdFQIvd7f/Uxa+Vip1Pi16wmhnrE15z/vDX921v
33
+ hukBRIoCEAuUgNVBh+L/C8aETzbf/77WU3Si/w==
33
34
  -----END CERTIFICATE-----
34
- date: 2020-04-26 00:00:00.000000000 Z
35
+ date: 2026-10-27 00:00:00.000000000 Z
35
36
  dependencies:
36
37
  - !ruby/object:Gem::Dependency
37
38
  name: net-ssh
@@ -42,7 +43,7 @@ dependencies:
42
43
  version: 2.6.5
43
44
  - - "<"
44
45
  - !ruby/object:Gem::Version
45
- version: 7.0.0
46
+ version: 9.0.0
46
47
  type: :runtime
47
48
  prerelease: false
48
49
  version_requirements: !ruby/object:Gem::Requirement
@@ -52,7 +53,7 @@ dependencies:
52
53
  version: 2.6.5
53
54
  - - "<"
54
55
  - !ruby/object:Gem::Version
55
- version: 7.0.0
56
+ version: 9.0.0
56
57
  - !ruby/object:Gem::Dependency
57
58
  name: test-unit
58
59
  requirement: !ruby/object:Gem::Requirement
@@ -88,16 +89,22 @@ executables: []
88
89
  extensions: []
89
90
  extra_rdoc_files:
90
91
  - LICENSE.txt
91
- - README.rdoc
92
+ - README.md
92
93
  files:
94
+ - ".github/pull_request_template.md"
95
+ - ".github/workflows/changelog.yml"
96
+ - ".github/workflows/ci.yml"
93
97
  - ".gitignore"
94
- - ".travis.yml"
95
98
  - CHANGES.txt
99
+ - CONTRIBUTING.md
96
100
  - Gemfile
97
101
  - LICENSE.txt
98
102
  - Manifest
99
- - README.rdoc
103
+ - README.md
100
104
  - Rakefile
105
+ - SECURITY.md
106
+ - changelog.d/README.md
107
+ - gemfiles/legacy.gemfile
101
108
  - lib/net/scp.rb
102
109
  - lib/net/scp/download.rb
103
110
  - lib/net/scp/errors.rb
@@ -113,7 +120,7 @@ licenses:
113
120
  - MIT
114
121
  metadata:
115
122
  changelog_uri: https://github.com/net-ssh/net-scp/blob/master/CHANGES.txt
116
- post_install_message:
123
+ post_install_message:
117
124
  rdoc_options: []
118
125
  require_paths:
119
126
  - lib
@@ -121,15 +128,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
121
128
  requirements:
122
129
  - - ">="
123
130
  - !ruby/object:Gem::Version
124
- version: '0'
131
+ version: '2.3'
125
132
  required_rubygems_version: !ruby/object:Gem::Requirement
126
133
  requirements:
127
134
  - - ">="
128
135
  - !ruby/object:Gem::Version
129
136
  version: '0'
130
137
  requirements: []
131
- rubygems_version: 3.0.3
132
- signing_key:
138
+ rubygems_version: 3.3.3
139
+ signing_key:
133
140
  specification_version: 3
134
141
  summary: A pure Ruby implementation of the SCP client protocol.
135
142
  test_files: []
metadata.gz.sig CHANGED
Binary file
data/.travis.yml DELETED
@@ -1,16 +0,0 @@
1
- language: ruby
2
- cache: bundler
3
- rvm:
4
- - 2.3.8
5
- - 2.4.5
6
- - 2.5.3
7
- - 2.6.1
8
- - ruby-head
9
-
10
- matrix:
11
- allow_failures:
12
- - rvm: ruby-head
13
-
14
- install: gem install jeweler test-unit mocha net-ssh
15
-
16
- script: rake test