Permalink
Browse files

add root path option to Archive (closes #300)

  • Loading branch information...
1 parent 74d9fc1 commit 90ead409523f538ca053d54e74611bf2241cba54 Brian D. Burns committed Mar 20, 2013
Showing with 567 additions and 389 deletions.
  1. +106 −79 lib/backup/archive.rb
  2. +143 −303 spec/archive_spec.rb
  3. +15 −7 templates/cli/archive
  4. +303 −0 vagrant/spec/acceptance/archive_spec.rb
View
@@ -3,121 +3,148 @@
module Backup
class Archive
include Backup::Utilities::Helpers
+ attr_reader :name, :options
##
- # Stores the name of the archive
- attr_reader :name
-
- ##
- # Stores an array of different paths/files to store
- attr_reader :paths
-
- ##
- # Stores an array of different paths/files to exclude
- attr_reader :excludes
-
- ##
- # String of additional arguments for the `tar` command
- attr_reader :tar_args
-
- ##
- # Takes the name of the archive and the configuration block
+ # Adds a new Archive to a Backup Model.
+ #
+ # Backup::Model.new(:my_backup, 'My Backup') do
+ # archive :my_archive do |archive|
+ # archive.add 'path/to/archive'
+ # archive.add '/another/path/to/archive'
+ # archive.exclude 'path/to/exclude'
+ # archive.exclude '/another/path/to/exclude'
+ # end
+ # end
+ #
+ # All paths added using `add` or `exclude` will be expanded to their
+ # full paths from the root of the filesystem. Files will be added to
+ # the tar archive using these full paths, and their leading `/` will
+ # be preserved (using tar's `-P` option).
+ #
+ # /path/to/pwd/path/to/archive/...
+ # /another/path/to/archive/...
+ #
+ # When a `root` path is given, paths to add/exclude are taken as
+ # relative to the `root` path, unless given as absolute paths.
+ #
+ # Backup::Model.new(:my_backup, 'My Backup') do
+ # archive :my_archive do |archive|
+ # archive.root '~/my_data'
+ # archive.add 'path/to/archive'
+ # archive.add '/another/path/to/archive'
+ # archive.exclude 'path/to/exclude'
+ # archive.exclude '/another/path/to/exclude'
+ # end
+ # end
+ #
+ # This directs `tar` to change directories to the `root` path to create
+ # the archive. Unless paths were given as absolute, the paths within the
+ # archive will be relative to the `root` path.
+ #
+ # path/to/archive/...
+ # /another/path/to/archive/...
+ #
+ # For absolute paths added to this archive, the leading `/` will be
+ # preserved. Take note that when archives are extracted, leading `/` are
+ # stripped by default, so care must be taken when extracting archives with
+ # mixed relative/absolute paths.
def initialize(model, name, &block)
- @model = model
- @name = name.to_s
- @paths = Array.new
- @excludes = Array.new
- @tar_args = ''
-
- instance_eval(&block) if block_given?
- end
-
- ##
- # Adds new paths to the @paths instance variable array
- def add(path)
- @paths << File.expand_path(path)
- end
-
- ##
- # Adds new paths to the @excludes instance variable array
- def exclude(path)
- @excludes << File.expand_path(path)
+ @model = model
+ @name = name.to_s
+ @options = {
+ :root => false,
+ :paths => [],
+ :excludes => [],
+ :tar_options => ''
+ }
+ DSL.new(@options).instance_eval(&block)
end
- ##
- # Adds the given String of +options+ to the `tar` command.
- # e.g. '-h --xattrs'
- def tar_options(options)
- @tar_args = options
- end
-
- ##
- # Archives all the provided paths in to a single .tar file
- # and places that .tar file in the folder which later will be packaged
- # If the model is configured with a Compressor, the tar command output
- # will be piped through the Compressor command and the file extension
- # will be adjusted to indicate the type of compression used.
def perform!
- Logger.info "#{ self.class } has started archiving:\n" +
- paths.map {|path| " #{path}" }.join("\n")
+ Logger.info "Creating Archive '#{ name }'..."
- archive_path = File.join(Config.tmp_path, @model.trigger, 'archives')
- FileUtils.mkdir_p(archive_path)
+ path = File.join(Config.tmp_path, @model.trigger, 'archives')
+ FileUtils.mkdir_p(path)
- archive_ext = 'tar'
pipeline = Pipeline.new
-
pipeline.add(
- "#{ utility(:tar) } #{ tar_arguments } -cPf - " +
+ "#{ utility(:tar) } #{ tar_options } -cPf -#{ tar_root } " +
"#{ paths_to_exclude } #{ paths_to_package }",
tar_success_codes
)
- if @model.compressor
- @model.compressor.compress_with do |command, ext|
- pipeline << command
- archive_ext << ext
- end
- end
+ extension = 'tar'
+ @model.compressor.compress_with do |command, ext|
+ pipeline << command
+ extension << ext
+ end if @model.compressor
pipeline << "#{ utility(:cat) } > " +
- "'#{ File.join(archive_path, "#{name}.#{archive_ext}") }'"
+ "'#{ File.join(path, "#{ name }.#{ extension }") }'"
pipeline.run
+
if pipeline.success?
- Logger.info "#{ self.class } Complete!"
+ Logger.info "Archive '#{ name }' Complete!"
else
raise Errors::Archive::PipelineError,
- "Failed to Create Backup Archive\n" +
+ "Failed to Create Archive '#{ name }'\n" +
pipeline.error_messages
end
end
private
- ##
- # Returns a "tar-ready" string of all the specified paths combined
+ def tar_root
+ options[:root] ? " -C '#{ File.expand_path(options[:root]) }'" : ''
+ end
+
def paths_to_package
- paths.map {|path| "'#{path}'" }.join(' ')
+ options[:paths].map {|path|
+ "'#{ prepare_path(path) }'"
+ }.join(' ')
end
- ##
- # Returns a "tar-ready" string of all the specified excludes combined
def paths_to_exclude
- if excludes.any?
- excludes.map {|path| "--exclude='#{path}'" }.join(' ')
- end
+ options[:excludes].map {|path|
+ "--exclude='#{ prepare_path(path) }'"
+ }.join(' ')
end
- ##
- # Returns arguments for GNU or BSD tar.
- def tar_arguments
- gnu_tar? ? "--ignore-failed-read #{ tar_args }".strip : tar_args
+ def prepare_path(path)
+ options[:root] ? path : File.expand_path(path)
+ end
+
+ def tar_options
+ args = options[:tar_options]
+ gnu_tar? ? "--ignore-failed-read #{ args }".strip : args
end
- ##
- # Returns successful GNU or BSD tar exit codes.
def tar_success_codes
gnu_tar? ? [0, 1] : [0]
end
+
+ class DSL
+ def initialize(options)
+ @options = options
+ end
+
+ def root(path)
+ @options[:root] = path
+ end
+
+ def add(path)
+ @options[:paths] << path
+ end
+
+ def exclude(path)
+ @options[:excludes] << path
+ end
+
+ def tar_options(opts)
+ @options[:tar_options] = opts
+ end
+ end
+
end
end
Oops, something went wrong.

0 comments on commit 90ead40

Please sign in to comment.