lib/backup/packager.rb
# frozen_string_literal: true
module Backup
module Packager
class Error < Backup::Error; end
class << self
include Utilities::Helpers
##
# Build the final package for the backup model.
def package!(model)
@package = model.package
@encryptor = model.encryptor
@splitter = model.splitter
@pipeline = Pipeline.new
Logger.info "Packaging the backup files..."
procedure.call
if @pipeline.success?
Logger.info "Packaging Complete!"
else
raise Error, "Failed to Create Backup Package\n" +
@pipeline.error_messages
end
end
private
##
# Builds a chain of nested Procs which adds each command to a Pipeline
# needed to package the final command to package the backup.
# This is done so that the Encryptor and Splitter have the ability
# to perform actions before and after the final command is executed.
# No Encryptors currently utilize this, however the Splitter does.
def procedure
stack = []
##
# Initial `tar` command to package the temporary backup folder.
# The command's output will then be either piped to the Encryptor
# or the Splitter (if no Encryptor), or through `cat` into the final
# output file if neither are configured.
@pipeline.add(
"#{utility(:tar)} -cf - " \
"-C '#{Config.tmp_path}' '#{@package.trigger}'",
tar_success_codes
)
##
# If an Encryptor was configured, it will be called first
# to add the encryption utility command to be piped through,
# and amend the final package extension.
# It's output will then be either piped into a Splitter,
# or through `cat` into the final output file.
if @encryptor
stack << lambda do
@encryptor.encrypt_with do |command, ext|
@pipeline << command
@package.extension << ext
stack.shift.call
end
end
end
##
# If a Splitter was configured, the `split` utility command will be
# added to the Pipeline to split the final output into multiple files.
# Once the Proc executing the Pipeline has completed and returns back
# to the Splitter, it will check the final output files to determine
# if the backup was indeed split.
# If so, it will set the package's chunk_suffixes. If not, it will
# remove the '-aa' suffix from the only file created by `split`.
#
# If no Splitter was configured, the final file output will be
# piped through `cat` into the final output file.
stack <<
if @splitter
lambda do
@splitter.split_with do |command|
@pipeline << command
stack.shift.call
end
end
else
lambda do
outfile = File.join(Config.tmp_path, @package.basename)
@pipeline << "#{utility(:cat)} > #{outfile}"
stack.shift.call
end
end
##
# Last Proc to be called runs the Pipeline the procedure built.
# Once complete, the call stack will unwind back through the
# preceeding Procs in the stack (if any)
stack << -> { @pipeline.run }
stack.shift
end
def tar_success_codes
gnu_tar? ? [0, 1] : [0]
end
end
end
end