lib/remi/extractor/sftp_file.rb in remi-0.2.19 vs lib/remi/extractor/sftp_file.rb in remi-0.2.20
- old
+ new
@@ -1,58 +1,109 @@
module Remi
module Extractor
class LocalFile
- def initialize(path)
+ def initialize(path:, folder: nil)
@path = path
+ @folder = folder
end
def extract
- @path
+ if @folder
+ Dir.entries(@folder).map do |entry|
+ next unless entry.match(@path)
+ File.join(@folder,entry)
+ end.compact
+ else
+ @path
+ end
end
end
class SftpFile
class FileNotFoundError < StandardError; end
- def initialize(credentials:, remote_file:, remote_folder: '', local_folder: Settings.work_dir, port: '22', most_recent_only: false, logger: Remi::Settings.logger)
+ SortDesc = Struct.new(:value) do
+ def <=> (target)
+ -(self.value <=> target.value)
+ end
+ end
+
+ def initialize(credentials:, remote_file:, remote_folder: '', local_folder: Settings.work_dir, port: nil, most_recent_only: false, group_by: nil, most_recent_by: :createtime, logger: Remi::Settings.logger)
@credentials = credentials
@remote_file = remote_file
@remote_folder = remote_folder
@local_folder = local_folder
- @port = port
+ @port = port || (credentials && credentials[:port]) || '22'
@most_recent_only = most_recent_only
+ @group_by = group_by
+ @most_recent_by = most_recent_by
@logger = logger
end
attr_reader :logger
def extract
- to_download = @most_recent_only ? Array(most_recent_entry(matching_entries)) : matching_entries
raise FileNotFoundError, "File not found: #{@remote_file}" if to_download.size == 0
download(to_download)
end
+ def to_download
+ if @group_by
+ most_recent_in_group
+ elsif @most_recent_only
+ Array(most_recent_entry(matching_entries))
+ else
+ matching_entries
+ end
+ end
+
def all_entries(remote_folder = @remote_folder)
@all_entries ||= connection { |sftp| sftp.dir.entries(File.join("/", remote_folder)) }
end
def matching_entries(match_name = @remote_file)
all_entries.select { |e| match_name.match e.name }
end
def most_recent_entry(entries = matching_entries)
- entries.sort_by { |e| e.attributes.createtime }.reverse!.first
+ entries.sort_by { |e| sort_files_by(e) }.reverse!.first
end
- def download(to_download = matching_entries, local_folder: @local_folder, ntry: 3)
+ def sort_files_by(entry)
+ if @most_recent_by == :filename
+ entry.name
+ else
+ entry.attributes.send(@most_recent_by)
+ end
+ end
+
+ def most_recent_in_group(match_group = @group_by)
+ entries_with_group = matching_entries.map do |entry|
+ match = entry.name.match(match_group)
+ next unless match
+
+ group = match.to_a[1..-1]
+ { group: group, entry: entry }
+ end.compact
+ entries_with_group.sort_by! { |e| [e[:group], SortDesc.new(sort_files_by(e[:entry]))] }
+
+ last_group = nil
+ entries_with_group.map do |entry|
+ next unless entry[:group] != last_group
+ last_group = entry[:group]
+ entry[:entry]
+ end.compact
+ end
+
+ def download(entries_to_download, remote_folder: @remote_folder, local_folder: @local_folder, ntry: 3)
connection do |sftp|
- to_download.map do |entry|
+ entries_to_download.map do |entry|
local_file = File.join(local_folder, entry.name)
@logger.info "Downloading #{entry.name} to #{local_file}"
- retry_download(ntry) { sftp.download!(entry.name, local_file) }
+ retry_download(ntry) { sftp.download!(File.join(remote_folder, entry.name), local_file) }
local_file
end
end
end
@@ -69,9 +120,10 @@
def retry_download(ntry=2, &block)
1.upto(ntry).each do |itry|
begin
block.call
+ break
rescue RuntimeError => err
raise err unless itry < ntry
@logger.error "Download failed with error: #{err.message}"
@logger.error "Retry attempt #{itry}/#{ntry-1}"
sleep(1)