lib/io_streams/paths/sftp.rb in iostreams-1.1.0 vs lib/io_streams/paths/sftp.rb in iostreams-1.1.1
- old
+ new
@@ -1,6 +1,6 @@
-require 'open3'
+require "open3"
module IOStreams
module Paths
# Read a file from a remote sftp server.
#
@@ -27,12 +27,12 @@
class << self
attr_accessor :sshpass_bin, :sftp_bin, :sshpass_wait_seconds
end
- @sftp_bin = 'sftp'
- @sshpass_bin = 'sshpass'
+ @sftp_bin = "sftp"
+ @sshpass_bin = "sshpass"
@sshpass_wait_seconds = 5
attr_reader :hostname, :username, :ssh_options, :url, :port
# Stream to a remote file over sftp.
@@ -74,11 +74,11 @@
# IOStreams.path("sftp://test.com/path/file_name.csv", username: "jack", ssh_options: {IdentityFile: "~/.ssh/private_key"}).reader do |io|
# puts io.read
# end
def initialize(url, username: nil, password: nil, ssh_options: {})
uri = Utils::URI.new(url)
- raise(ArgumentError, "Invalid URL. Required Format: 'sftp://<host_name>/<file_name>'") unless uri.scheme == 'sftp'
+ raise(ArgumentError, "Invalid URL. Required Format: 'sftp://<host_name>/<file_name>'") unless uri.scheme == "sftp"
@hostname = uri.hostname
@mkdir = false
@username = username || uri.user
@url = url
@@ -131,10 +131,11 @@
flags |= ::File::FNM_DOTMATCH if hidden
Net::SFTP.start(hostname, username, build_ssh_options) do |sftp|
sftp.dir.glob(".", pattern, flags) do |path|
next if !directories && !path.file?
+
new_path = self.class.new("sftp://#{hostname}/#{path.name}", username: username, password: password, **ssh_options)
yield(new_path, path.attributes.attributes)
end
end
nil
@@ -166,17 +167,24 @@
begin
writer.puts password
# Give time for password to be processed and stdin to be passed to sftp process.
sleep self.class.sshpass_wait_seconds
writer.puts "get #{remote_file_name} #{local_file_name}"
- writer.puts 'bye'
+ writer.puts "bye"
writer.close
out = reader.read.chomp
- raise(Errors::CommunicationsFailure, "Download failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}") unless waith_thr.value.success?
+ unless waith_thr.value.success?
+ raise(Errors::CommunicationsFailure, "Download failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}")
+ end
+
out
rescue Errno::EPIPE
- out = reader.read.chomp rescue nil
+ out = begin
+ reader.read.chomp
+ rescue StandardError
+ nil
+ end
raise(Errors::CommunicationsFailure, "Download failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}")
end
end
end
end
@@ -187,33 +195,40 @@
begin
writer.puts(password) if password
# Give time for password to be processed and stdin to be passed to sftp process.
sleep self.class.sshpass_wait_seconds
writer.puts "put #{local_file_name.inspect} #{remote_file_name.inspect}"
- writer.puts 'bye'
+ writer.puts "bye"
writer.close
out = reader.read.chomp
- raise(Errors::CommunicationsFailure, "Upload failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}") unless waith_thr.value.success?
+ unless waith_thr.value.success?
+ raise(Errors::CommunicationsFailure, "Upload failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}")
+ end
+
out
rescue Errno::EPIPE
- out = reader.read.chomp rescue nil
+ out = begin
+ reader.read.chomp
+ rescue StandardError
+ nil
+ end
raise(Errors::CommunicationsFailure, "Upload failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}")
end
end
end
end
def with_sftp_args
- return yield sftp_args(ssh_options) unless ssh_options.key?('IdentityKey')
+ return yield sftp_args(ssh_options) unless ssh_options.key?("IdentityKey")
- Utils.temp_file_name('iostreams-sftp-args', 'key') do |file_name|
+ Utils.temp_file_name("iostreams-sftp-args", "key") do |file_name|
options = ssh_options.dup
- key = options.delete('IdentityKey')
+ key = options.delete("IdentityKey")
# sftp requires that private key is only readable by the current user
- ::File.open(file_name, 'wb', 0600) { |io| io.write(key) }
+ ::File.open(file_name, "wb", 0o600) { |io| io.write(key) }
- options['IdentityFile'] = file_name
+ options["IdentityFile"] = file_name
yield sftp_args(options)
end
end
def sftp_args(ssh_options)
@@ -226,25 +241,25 @@
args << "-oPubkeyAuthentication=no"
else
args << "-oBatchMode=yes"
args << "-oPasswordAuthentication=no"
end
- args << "-oIdentitiesOnly=yes" if ssh_options.key?('IdentityFile')
+ args << "-oIdentitiesOnly=yes" if ssh_options.key?("IdentityFile")
# Default is ask, but this is non-interactive so make the default fail without asking.
- args << "-oStrictHostKeyChecking=yes" unless ssh_options.key?('StrictHostKeyChecking')
- args << "-oLogLevel=#{map_log_level}" unless ssh_options.key?('LogLevel')
+ args << "-oStrictHostKeyChecking=yes" unless ssh_options.key?("StrictHostKeyChecking")
+ args << "-oLogLevel=#{map_log_level}" unless ssh_options.key?("LogLevel")
args << "-oPort=#{port}" unless port == 22
ssh_options.each_pair { |key, value| args << "-o#{key}=#{value}" }
- args << '-b'
- args << '-'
+ args << "-b"
+ args << "-"
args << "#{username}@#{hostname}"
args
end
def build_ssh_options
- options = ssh_options.dup
- options[:logger] ||= self.logger if defined?(SemanticLogger)
- options[:port] ||= port
+ options = ssh_options.dup
+ options[:logger] ||= logger if defined?(SemanticLogger)
+ options[:port] ||= port
options[:max_pkt_size] ||= 65_536
options[:password] ||= @password
options
end