module EY module Backup class BackupSet include EY::Backup::Logging extend EY::Backup::Logging MULTIPART_EXTENSION = /\.part\d+/ def self.from(database, basename, file) new(database, basename, file, nil) end def initialize(database, basename, filename, keys) @database = database @basename = basename @filename = filename @keys = keys end attr_reader :basename def database_name @database.name end def cleanup say "Cleanup for #{database_name}" @database.backups[0...(-@database.keep)].each do |backup| say "Deleting: #{backup.basename}" backup.delete! end end def self.list(databases) all_backups = [] databases.each do |db| backups = db.backups all_backups << backups puts "Listing database backups for #{db.name}" puts "#{backups.size} backup(s) found" backups.each_with_index do |backup_set, i| puts "#{i}:#{backup_set.database_name} #{backup_set.normalized_name}" end puts # just some extra whitespace end all_backups.flatten end def self.download(database, index) fatal "You didn't specify a database name: e.g. 1:rails_production" if database.nil? || index < 0 backup = database.backups[index] fatal "No backup found for database #{database}: requested index: #{index}" unless backup backup.download! backup end def parts @keys.size end def normalized_name normalize(@basename) end def load! @database.engine.load(@database.name, @filename) end def upload! @database.start_upload(@remote_filenames) end def download! @remote_filenames = [] @keys.each do |key| remote_filename = File.join(@database.base_path, normalize(key)) puts "Filename: #{remote_filename}" info "Downloading #{key} to #{@database.base_path}" File.open(remote_filename, 'wb') do |f| @database.bucket_minder.stream(key) do |chunk, remaining_size, total_size| f.write(chunk) end end @remote_filenames << remote_filename end end def delete! @keys.each do |key| @database.bucket_minder.remove_object(key) end end def remove_split_files! (@remote_filenames - [@filename]).each do |filename| FileUtils.rm(filename) end end def remove_joined_file! FileUtils.rm(@filename) end def rm! remove_split_files! remove_joined_file! end def split!(split_size) @remote_filenames = Splitter.dump(@filename, split_size) end def join! @filename = Splitter.load(@remote_filenames) end def normalize(o) o.gsub(/^.*?\//, '') end def timestamp @basename[/(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})/, 1] end def <=>(o) self.timestamp <=> o.timestamp end end end end