simple_backup 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +2 -1
  4. data/backup_example.rb +23 -13
  5. data/lib/simple_backup/backend/abstract.rb +35 -0
  6. data/lib/simple_backup/backend/local.rb +45 -0
  7. data/lib/simple_backup/backends.rb +60 -0
  8. data/lib/simple_backup/dsl.rb +26 -93
  9. data/lib/simple_backup/engine.rb +41 -3
  10. data/lib/simple_backup/source/abstract.rb +130 -0
  11. data/lib/simple_backup/source/dir.rb +39 -0
  12. data/lib/simple_backup/source/dir_strategy/bare.rb +17 -0
  13. data/lib/simple_backup/source/dir_strategy/capistrano.rb +41 -0
  14. data/lib/simple_backup/source/file.rb +20 -0
  15. data/lib/simple_backup/source/mysql.rb +28 -0
  16. data/lib/simple_backup/sources.rb +74 -0
  17. data/lib/simple_backup/utils/disk_usage.rb +53 -0
  18. data/lib/simple_backup/utils/logger.rb +92 -0
  19. data/lib/simple_backup/utils/mailer.rb +126 -0
  20. data/lib/simple_backup/utils/mysql.rb +65 -0
  21. data/lib/simple_backup/utils.rb +4 -53
  22. data/lib/simple_backup/version.rb +2 -2
  23. data/lib/simple_backup.rb +40 -5
  24. metadata +17 -19
  25. data/lib/simple_backup/engine/abstract.rb +0 -42
  26. data/lib/simple_backup/engine/app_strategy/abstract.rb +0 -13
  27. data/lib/simple_backup/engine/app_strategy/bare.rb +0 -29
  28. data/lib/simple_backup/engine/app_strategy/capistrano.rb +0 -44
  29. data/lib/simple_backup/engine/app_strategy/factory.rb +0 -20
  30. data/lib/simple_backup/engine/apps.rb +0 -63
  31. data/lib/simple_backup/engine/mysql.rb +0 -104
  32. data/lib/simple_backup/exception/app_already_defined.rb +0 -6
  33. data/lib/simple_backup/exception/apps_dir_does_not_exists.rb +0 -6
  34. data/lib/simple_backup/exception/base.rb +0 -6
  35. data/lib/simple_backup/exception/cant_create_dir.rb +0 -6
  36. data/lib/simple_backup/exception/type_does_not_exists.rb +0 -6
  37. data/lib/simple_backup/exception.rb +0 -5
  38. data/lib/simple_backup/logger.rb +0 -84
  39. data/lib/simple_backup/mailer.rb +0 -138
  40. data/lib/simple_backup/storage.rb +0 -96
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cd3e8ec26688c63d6e75643e4b962556b330c9ef
4
- data.tar.gz: d721a3e4ee4cea8064440289e527f9633c553a17
3
+ metadata.gz: db18d1aeca0f0b1e397e8599de6ed70474fd49e1
4
+ data.tar.gz: 9e70279a4648074f77da59a0f070a869ce8c555d
5
5
  SHA512:
6
- metadata.gz: ba862bc3835154a09912e16c85eab02c7b8defc932dfb755f5d5d6fcaf4f473e1ee87109194520f0a57bbac34188458000ad37aeab9b4d7549845840f8cda6cc
7
- data.tar.gz: f4eb040ff8315e5b35690ceb309237e8341090185376837e677afa50c92e7b457bbeda0b5f7b87a84142946974c4384f745b32241e5fff18aa1593b7d77aa13e
6
+ metadata.gz: d94e122a1bfab65a376e29087564568917c939149cec9d52c37d5905dd683687b033b1132fb28bcf6cf373da9f0fc3cb6492fd8cc30fe1c09bb2d38ef3412421
7
+ data.tar.gz: 00bb1b44ad48000765a9aa84817cc451772886beb03dc41e07a7503cbcf3d2e4d1293844de049caa6987d5d11a0221f57534453cafa9904ff4356d38eae1c54b
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  /pkg/
2
+ /Dockerfile
2
3
  /Gemfile.lock
data/README.md CHANGED
@@ -9,7 +9,8 @@ development and its API should be treat as unstable.
9
9
  ## TODO
10
10
 
11
11
  - [ ] Refactorization
12
- - [ ] Few backend for backup store (file, s3, ftp)
12
+ - [ ] Few backends for backup store (file, s3, ftp)
13
+ - [ ] Filters mechanism (e.g. PGP encryption)
13
14
  - [ ] Tests
14
15
  - [ ] Docummentation and examples
15
16
 
data/backup_example.rb CHANGED
@@ -1,31 +1,41 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
3
6
  require 'simple_backup'
4
7
 
5
8
  SimpleBackup.run do
6
- # log_level :debug
7
- backup_dir '/backup'
9
+ log_level :debug
10
+
8
11
  high_usage_treshold 0.9
9
12
  check_disk_path '/'
10
13
  check_disk_path '/backup'
11
14
  check_disk_path '/home/app'
12
15
 
13
- apps do
14
- keep_last 9
16
+ default_keep_last 9
17
+
18
+ sources do
19
+ dir 'app-1', '/home/app/app-1', type: :capistrano, backends: 'backup'
20
+ dir 'app-2', '/home/app/app-2', backends: :none
21
+ dir 'none', '/none'
22
+
23
+ file 'hosts', '/etc/hosts'
15
24
 
16
- app '/home/app/app-1', type: :capistrano
17
- app '/home/app/app-2', type: :bare
25
+ mysql 'test1', 'test1'
26
+ mysql 'test2', 'test2'
27
+ mysql 'test3', 'test3', exclude_tables: ['t_test1']
18
28
  end
19
29
 
20
- mysql do
21
- keep_last 9
30
+ backends do
31
+ local 'backup', path: '/srv/backup'
32
+ end
22
33
 
34
+ mysql do
23
35
  host 'localhost'
24
36
  port 3306
25
- user 'backup'
26
- pass 'backup'
27
- db 'test1'
28
- db 'test2', exclude_tables: ['t_test1']
37
+ user 'root'
38
+ pass 'root'
29
39
  end
30
40
 
31
41
  mailer do
@@ -33,7 +43,7 @@ SimpleBackup.run do
33
43
 
34
44
  from 'backup@localhost'
35
45
  to 'root@localhost'
36
- cc 'root@localhost'
46
+ cc 'rb@localhost'
37
47
  bcc 'root@localhost'
38
48
  end
39
49
  end
@@ -0,0 +1,35 @@
1
+ module SimpleBackup
2
+ module Backend
3
+ class Abstract
4
+ @@logger = Utils::Logger.instance
5
+
6
+ def configure(*args)
7
+ raise NotImplementedError
8
+ end
9
+
10
+ def name=(value)
11
+ @name = value.gsub(/[^a-zA-Z0-9\-\_\. ]*/, '').gsub(/\s+/, '_').downcase
12
+ end
13
+
14
+ def name
15
+ @name
16
+ end
17
+
18
+ def type
19
+ self.class.name.split('::').last.gsub(/[^a-zA-Z0-9\-\_\. ]*/, '').gsub(/\s+/, '_').downcase
20
+ end
21
+
22
+ def desc
23
+ '%5s :: %s' % [type, @name]
24
+ end
25
+
26
+ def store(source)
27
+ raise NotImplementedError
28
+ end
29
+
30
+ def cleanup(source)
31
+ raise NotImplementedError
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,45 @@
1
+ module SimpleBackup
2
+ module Backend
3
+ class Local < Abstract
4
+ def configure(options = {})
5
+ raise "Must provide :path option" unless options[:path]
6
+
7
+ @path = options[:path]
8
+
9
+ raise "#{@path} does not exists" unless ::File.exist?(@path)
10
+ raise "#{@path} is not a directory" unless ::File.directory?(@path)
11
+ raise "#{@path} is not writable" unless ::File.writable?(@path)
12
+ end
13
+
14
+ def store(source)
15
+ storage_path = get_storage_path(source)
16
+ FileUtils.cp source.backup_file, storage_path
17
+ end
18
+
19
+ def cleanup(source)
20
+ storage_path = get_storage_path(source)
21
+
22
+ files = ::Dir.glob(::File.join(storage_path, '*.tar.gz')).sort
23
+
24
+ to_persist = files
25
+ to_persist = files.slice(source.keep_last * -1, source.keep_last) if files.length > source.keep_last
26
+ to_remove = files - to_persist
27
+
28
+ @@logger.scope_start
29
+ to_remove.each do |file|
30
+ FileUtils.rm(file)
31
+ @@logger.debug "Old backup '#{file}' for source '#{source.desc.strip}' cleaned up from '#{desc.strip}'"
32
+ end
33
+ @@logger.scope_end
34
+ end
35
+
36
+ private
37
+ def get_storage_path(source)
38
+ path = ::File.join(@path, source.type, source.name)
39
+ FileUtils.mkpath path unless ::File.exist?(path)
40
+
41
+ path
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,60 @@
1
+ require 'singleton'
2
+ require 'simple_backup/backend/abstract'
3
+
4
+ module SimpleBackup
5
+ class Backends
6
+ include Singleton
7
+
8
+ @@logger = Utils::Logger.instance
9
+ @@sources = Sources.instance
10
+
11
+ def initialize
12
+ @backends = {}
13
+ end
14
+
15
+ def each(&block)
16
+ @backends.each(&block)
17
+ end
18
+
19
+ def save_and_cleanup
20
+ each do |name, backend|
21
+ @@sources.each do |name, source|
22
+ next unless source.backup_file and source.supports(backend)
23
+
24
+ backend.store(source)
25
+ @@logger.info "Source '#{source.desc.strip}' stored in backend '#{backend.desc.strip}'"
26
+
27
+ backend.cleanup(source)
28
+ @@logger.info "Source '#{source.desc.strip}' cleaned up in backend '#{backend.desc.strip}'"
29
+ end
30
+ end
31
+ end
32
+
33
+ def method_missing(method, *args)
34
+ backend = create_backend(method)
35
+
36
+ return nil if backend.nil?
37
+
38
+ name = args.shift
39
+ options = args.shift
40
+ options ||= {}
41
+
42
+ raise "Name '#{name}' for backend already used" if @backends.has_key?(name.to_sym)
43
+
44
+ backend.name = name
45
+ backend.configure(options)
46
+
47
+ @@logger.info "Created backend for: #{backend.desc}"
48
+ @backends[name.to_sym] = backend
49
+ end
50
+
51
+ private
52
+ def create_backend(name)
53
+ file = "simple_backup/backend/#{name}"
54
+
55
+ require file
56
+ backend_name = Object.const_get("SimpleBackup::Backend::#{name.capitalize}")
57
+ backend_name.new
58
+ end
59
+ end
60
+ end
@@ -1,120 +1,53 @@
1
1
  module SimpleBackup
2
- TIMESTAMP = Time.new.strftime('%Y%m%d%H%M%S')
3
- @@status = :failed
4
-
5
- def self.status
6
- @@status
7
- end
8
-
9
- def self.run(&block)
10
- Logger::info "Backup #{TIMESTAMP} started"
11
-
12
- dsl = DSL.new
13
-
14
- Logger::scope_start :info, "Configuration"
15
- dsl.instance_eval(&block)
16
- dsl.prepare
17
- Logger::scope_end
18
-
19
- dsl.run
20
- dsl.cleanup
21
- @@status = :succeed
22
-
23
- Logger::info "Backup #{TIMESTAMP} finished"
24
- rescue StandardError => e
25
- self.handle_exception(e)
26
- ensure
27
- dsl.notify
28
- Logger::info "Notifications for backup #{TIMESTAMP} finished"
29
- end
30
-
31
- def self.handle_exception(e)
32
- Logger::error "#{e.class} => #{e.message}"
33
- Logger::error "Backup #{TIMESTAMP} failed"
34
- STDERR.puts "Error @ #{Time.new.strftime('%Y-%m-%dT%H:%M:%S')}"
35
- STDERR.puts "#{e.inspect}"
36
- STDERR.puts e.backtrace
37
- end
38
-
39
2
  class DSL
40
- def initialize
41
- @storage = Storage.new
42
- end
43
-
44
- def prepare
45
- if @apps_block
46
- @apps = Engine::Apps.new
47
- @apps.storage = @storage
48
- @apps.instance_eval(&@apps_block)
49
- end
50
-
51
- if @mysql_block
52
- @mysql = Engine::MySQL.new
53
- @mysql.storage = @storage
54
- @mysql.instance_eval(&@mysql_block)
55
- end
56
- end
57
-
58
- def run
59
- usage = Utils::Disk::usage
60
- Logger::error "Disk high usage treshold exceeded #{usage[:high_usage]}" if usage[:high_usage_exceeded]
3
+ @@logger = Utils::Logger.instance
61
4
 
62
- Logger::scope_start :info, "Backup job"
63
- @apps.backup if @apps
64
- @mysql.backup if @mysql
65
- Logger::scope_end
5
+ def initialize(engine)
6
+ @engine = engine
66
7
  end
67
8
 
68
- def cleanup
69
- Logger::scope_start :info, "Cleanup job"
70
- @apps.cleanup if @apps
71
- @mysql.cleanup if @mysql
72
- Logger::scope_end
73
- end
74
-
75
- def notify
76
- @mailer.send if @mailer
77
- rescue StandardError => e
78
- SimpleBackup.handle_exception(e)
9
+ def log_level(level)
10
+ @@logger.level = level
79
11
  end
80
12
 
81
- def sources
82
- sources = {}
83
- sources[:apps] = @apps.sources if @apps
84
- sources[:mysql] = @mysql.sources if @mysql
13
+ def high_usage_treshold(value)
14
+ @@logger.info "Setting high_usage_treshold to #{value}"
85
15
 
86
- sources
16
+ Utils::Disk.high_usage_treshold = value
87
17
  end
88
18
 
89
- def log_level(level)
90
- Logger::level = level
91
- end
19
+ def check_disk_path(path)
20
+ @@logger.info "Adding disk path '#{path}' to usage check"
92
21
 
93
- def backup_dir(dir)
94
- @storage.dir = dir
22
+ Utils::Disk.add_path(path)
95
23
  end
96
24
 
97
- def high_usage_treshold(value)
98
- Logger::info "Setting high_usage_treshold to #{value}"
99
- Utils::Disk.high_usage_treshold = value
25
+ def default_keep_last(value)
26
+ Sources.instance.default_keep_last = value
100
27
  end
101
28
 
102
- def check_disk_path(path)
103
- Logger::info "Adding disk path '#{path}' to usage check"
104
- Utils::Disk.add_path(path)
29
+ def sources(&block)
30
+ sources = Sources.instance
31
+ sources.instance_eval(&block)
105
32
  end
106
33
 
107
- def apps(&block)
108
- @apps_block = block
34
+ def backends(&block)
35
+ backends = Backends.instance
36
+ backends.instance_eval(&block)
109
37
  end
110
38
 
111
39
  def mysql(&block)
112
- @mysql_block = block
40
+ @@logger.info "Configuring MySQL Util"
41
+
42
+ Utils::MySQL.instance.instance_eval(&block)
113
43
  end
114
44
 
115
45
  def mailer(&block)
116
- @mailer = Mailer.new(self, @storage)
46
+ @@logger.info "Configuring Mailer Util"
47
+
48
+ @mailer = Utils::Mailer.new
117
49
  @mailer.instance_eval(&block)
50
+ @engine.mailer = @mailer
118
51
  end
119
52
  end
120
53
  end
@@ -1,3 +1,41 @@
1
- require 'simple_backup/engine/abstract'
2
- require 'simple_backup/engine/apps'
3
- require 'simple_backup/engine/mysql'
1
+ module SimpleBackup
2
+ module Engine
3
+ class Engine
4
+
5
+ @@backends = Backends.instance
6
+ @@sources = Sources.instance
7
+ @@logger = Utils::Logger.instance
8
+ @@mysql = Utils::MySQL.instance
9
+
10
+ def mailer=(mailer)
11
+ @mailer = mailer
12
+ end
13
+
14
+ def run
15
+ usage = Utils::Disk::usage
16
+
17
+ @@logger.error "Disk high usage treshold exceeded #{usage[:high_usage]}" if usage[:high_usage_exceeded]
18
+ @@logger.scope_start :info, "Backup"
19
+
20
+ @@sources.backup
21
+ @@backends.save_and_cleanup
22
+ @@sources.cleanup
23
+
24
+ @@logger.scope_end
25
+ ensure
26
+ @@mysql.close
27
+ end
28
+
29
+ def notify
30
+ return unless @mailer
31
+ @@logger.scope_start :info, "Sending e-mail notification"
32
+
33
+ @mailer.send
34
+
35
+ @@logger.scope_end :info, "Notifications for backup #{TIMESTAMP} finished"
36
+ rescue StandardError => e
37
+ SimpleBackup.handle_exception(e)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,130 @@
1
+ require 'rubygems/package'
2
+ require 'tmpdir'
3
+ require 'zlib'
4
+
5
+ module SimpleBackup
6
+ module Source
7
+ class Abstract
8
+ @@logger = Utils::Logger.instance
9
+
10
+ def configure(*args)
11
+ raise NotImplementedError
12
+ end
13
+
14
+ def keep_last=(value)
15
+ @keep_last = value
16
+ end
17
+
18
+ def keep_last
19
+ @keep_last
20
+ end
21
+
22
+ def name=(value)
23
+ @name = value.gsub(/[^a-zA-Z0-9\-\_\. ]*/, '').gsub(/\s+/, '_').downcase
24
+ end
25
+
26
+ def name
27
+ @name
28
+ end
29
+
30
+ def type
31
+ self.class.name.split('::').last.gsub(/[^a-zA-Z0-9\-\_\. ]*/, '').gsub(/\s+/, '_').downcase
32
+ end
33
+
34
+ def desc
35
+ '%5s :: %s' % [type, @name]
36
+ end
37
+
38
+ def get
39
+ return @backup_file if @backup_file
40
+
41
+ @@logger.scope_start :info, "Getting archive for: #{desc}"
42
+
43
+ @tmp_dir = ::Dir.mktmpdir('simple_backup-')
44
+ @@logger.debug "Created tmp directory #{@tmp_dir}"
45
+
46
+ data_exists = prepare_data
47
+
48
+ @@logger.warning "No data for: #{desc}" unless data_exists
49
+ archive_data if data_exists
50
+
51
+ FileUtils.rm_rf(@tmp_dir)
52
+ @@logger.debug "Removed tmp directory #{@tmp_dir}"
53
+
54
+ @backup_file
55
+ ensure
56
+ @@logger.scope_end
57
+ end
58
+
59
+ def cleanup
60
+ return nil unless @backup_file
61
+
62
+ FileUtils.rm (@backup_file)
63
+ @@logger.debug "Temporary backup file #{@backup_file} was removed"
64
+ end
65
+
66
+ def backup_file
67
+ @backup_file
68
+ end
69
+
70
+ def backends=(value)
71
+ @backends = []
72
+ @backends = @backends + value if value.kind_of?(Array)
73
+ @backends << value unless value.kind_of?(Array)
74
+ end
75
+
76
+ def supports(backend)
77
+ return TRUE unless @backends
78
+ return FALSE unless @backends.include?(backend.name)
79
+
80
+ TRUE
81
+ end
82
+
83
+ private
84
+ def prepare_data
85
+ raise NotImplementedError
86
+ end
87
+
88
+ def archive_data
89
+ filename = "#{type}-#{name}.#{SimpleBackup::TIMESTAMP}.tar.gz"
90
+ @backup_file = ::File.join(::Dir.tmpdir, filename)
91
+
92
+ ::File.open(backup_file, 'w') do |f|
93
+ f.write targz.string
94
+ end
95
+
96
+ @@logger.debug "Backup saved to temporary file #{backup_file}"
97
+ end
98
+
99
+ def targz
100
+ path = @tmp_dir
101
+
102
+ content = StringIO.new('');
103
+ Gem::Package::TarWriter.new(content) do |tar|
104
+ ::Dir[::File.join(path, '**/*')].each do |file|
105
+ mode = ::File.stat(file).mode
106
+ relative_file = file.sub(/^#{Regexp::escape path}\/?/, '')
107
+
108
+ if ::File.directory?(file)
109
+ tar.mkdir(relative_file, mode)
110
+ else
111
+ tar.add_file relative_file, mode do |tf|
112
+ ::File.open(file, 'rb') do |f|
113
+ tf.write f.read
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ content.rewind
120
+
121
+ gz = StringIO.new('')
122
+ zip = Zlib::GzipWriter.new(gz)
123
+ zip.write content.string
124
+ zip.close
125
+
126
+ gz
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,39 @@
1
+ module SimpleBackup
2
+ module Source
3
+ class Dir < Abstract
4
+ def initialize
5
+ @strategy = :bare
6
+ end
7
+
8
+ def configure(path, options = {})
9
+ @path = path
10
+
11
+ raise "#{path} is a file - use File source instead of Dir" unless !::File.exist?(path) or ::File.directory?(path)
12
+ @strategy = options[:strategy] if options[:strategy]
13
+ end
14
+
15
+ private
16
+ def prepare_data
17
+ return false unless ::File.exist?(@path)
18
+
19
+ path_entries = get_path_entries
20
+ FileUtils.cp_r path_entries, @tmp_dir if path_entries
21
+
22
+ true
23
+ end
24
+
25
+ def get_path_entries
26
+ file = "simple_backup/source/dir_strategy/#{@strategy.to_s}"
27
+
28
+ require file
29
+ strategy_name = Object.const_get("SimpleBackup::Source::DirStrategy::#{@strategy.to_s.capitalize}")
30
+ strategy = strategy_name.new
31
+
32
+ strategy.get_entries(@path)
33
+ rescue Errno::ENOENT
34
+ @@logger.warning "Path '#{@path}' does not exists"
35
+ nil
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ module SimpleBackup
2
+ module Source
3
+ module DirStrategy
4
+ class Bare
5
+ def get_entries(path)
6
+ ::Dir.entries(path).map do |p|
7
+ if p.match(/^\.\.?$/)
8
+ nil
9
+ else
10
+ ::File.join(path, p)
11
+ end
12
+ end.compact
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ module SimpleBackup
2
+ module Source
3
+ module DirStrategy
4
+ class Capistrano
5
+ @@logger = Utils::Logger.instance
6
+
7
+ def get_entries(path)
8
+ shared = shared_path(path)
9
+ current = current_path(path)
10
+ paths = [current, shared].compact
11
+
12
+ if paths.empty?
13
+ @@logger.warning "No capistrano paths for application"
14
+ return nil
15
+ end
16
+
17
+ paths
18
+ end
19
+
20
+ private
21
+ def current_path(path)
22
+ current = ::Dir.new(::File.join(path, 'current') + '/')
23
+ @@logger.debug "Capistrano current path: #{current.path}"
24
+ current.path
25
+ rescue Errno::ENOENT
26
+ @@logger.warning "No capistrano current path for application"
27
+ nil
28
+ end
29
+
30
+ def shared_path(path)
31
+ shared = ::Dir.new(::File.join(path, 'shared'))
32
+ @@logger.debug "Capistrano shared path: #{shared.path}"
33
+ shared.path
34
+ rescue Errno::ENOENT
35
+ @@logger.warning "No capistrano shared path for application"
36
+ nil
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,20 @@
1
+ module SimpleBackup
2
+ module Source
3
+ class File < Abstract
4
+ def configure(path, options = {})
5
+ @path = path
6
+
7
+ raise "#{path} is a directory - use Dir source instead of File" unless !::File.exist?(path) or ::File.file?(path)
8
+ end
9
+
10
+ private
11
+ def prepare_data
12
+ return false unless ::File.exist?(@path)
13
+
14
+ FileUtils.cp @path, @tmp_dir
15
+
16
+ true
17
+ end
18
+ end
19
+ end
20
+ end