backup-remote 0.0.2

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 (135) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +112 -0
  3. data/bin/backup-remote +5 -0
  4. data/lib/backup.rb +155 -0
  5. data/lib/backup/archive.rb +170 -0
  6. data/lib/backup/binder.rb +22 -0
  7. data/lib/backup/cleaner.rb +116 -0
  8. data/lib/backup/cli.rb +374 -0
  9. data/lib/backup/cloud_io/base.rb +41 -0
  10. data/lib/backup/cloud_io/cloud_files.rb +298 -0
  11. data/lib/backup/cloud_io/s3.rb +260 -0
  12. data/lib/backup/compressor/base.rb +35 -0
  13. data/lib/backup/compressor/bzip2.rb +39 -0
  14. data/lib/backup/compressor/custom.rb +53 -0
  15. data/lib/backup/compressor/gzip.rb +74 -0
  16. data/lib/backup/config.rb +121 -0
  17. data/lib/backup/config/dsl.rb +106 -0
  18. data/lib/backup/config/helpers.rb +143 -0
  19. data/lib/backup/database/base.rb +85 -0
  20. data/lib/backup/database/mongodb.rb +187 -0
  21. data/lib/backup/database/mysql.rb +192 -0
  22. data/lib/backup/database/openldap.rb +95 -0
  23. data/lib/backup/database/postgresql.rb +133 -0
  24. data/lib/backup/database/redis.rb +179 -0
  25. data/lib/backup/database/remote_mysql.rb +248 -0
  26. data/lib/backup/database/riak.rb +82 -0
  27. data/lib/backup/database/sqlite.rb +57 -0
  28. data/lib/backup/encryptor/base.rb +29 -0
  29. data/lib/backup/encryptor/gpg.rb +747 -0
  30. data/lib/backup/encryptor/open_ssl.rb +77 -0
  31. data/lib/backup/errors.rb +58 -0
  32. data/lib/backup/logger.rb +199 -0
  33. data/lib/backup/logger/console.rb +51 -0
  34. data/lib/backup/logger/fog_adapter.rb +29 -0
  35. data/lib/backup/logger/logfile.rb +133 -0
  36. data/lib/backup/logger/syslog.rb +116 -0
  37. data/lib/backup/model.rb +479 -0
  38. data/lib/backup/notifier/base.rb +128 -0
  39. data/lib/backup/notifier/campfire.rb +63 -0
  40. data/lib/backup/notifier/command.rb +102 -0
  41. data/lib/backup/notifier/datadog.rb +107 -0
  42. data/lib/backup/notifier/flowdock.rb +103 -0
  43. data/lib/backup/notifier/hipchat.rb +118 -0
  44. data/lib/backup/notifier/http_post.rb +117 -0
  45. data/lib/backup/notifier/mail.rb +249 -0
  46. data/lib/backup/notifier/nagios.rb +69 -0
  47. data/lib/backup/notifier/pagerduty.rb +81 -0
  48. data/lib/backup/notifier/prowl.rb +68 -0
  49. data/lib/backup/notifier/pushover.rb +74 -0
  50. data/lib/backup/notifier/ses.rb +105 -0
  51. data/lib/backup/notifier/slack.rb +148 -0
  52. data/lib/backup/notifier/twitter.rb +58 -0
  53. data/lib/backup/notifier/zabbix.rb +63 -0
  54. data/lib/backup/package.rb +55 -0
  55. data/lib/backup/packager.rb +107 -0
  56. data/lib/backup/pipeline.rb +128 -0
  57. data/lib/backup/remote/command.rb +82 -0
  58. data/lib/backup/splitter.rb +76 -0
  59. data/lib/backup/storage/base.rb +69 -0
  60. data/lib/backup/storage/cloud_files.rb +158 -0
  61. data/lib/backup/storage/cycler.rb +75 -0
  62. data/lib/backup/storage/dropbox.rb +212 -0
  63. data/lib/backup/storage/ftp.rb +112 -0
  64. data/lib/backup/storage/local.rb +64 -0
  65. data/lib/backup/storage/qiniu.rb +65 -0
  66. data/lib/backup/storage/rsync.rb +248 -0
  67. data/lib/backup/storage/s3.rb +156 -0
  68. data/lib/backup/storage/scp.rb +67 -0
  69. data/lib/backup/storage/sftp.rb +82 -0
  70. data/lib/backup/syncer/base.rb +70 -0
  71. data/lib/backup/syncer/cloud/base.rb +179 -0
  72. data/lib/backup/syncer/cloud/cloud_files.rb +83 -0
  73. data/lib/backup/syncer/cloud/local_file.rb +100 -0
  74. data/lib/backup/syncer/cloud/s3.rb +110 -0
  75. data/lib/backup/syncer/rsync/base.rb +54 -0
  76. data/lib/backup/syncer/rsync/local.rb +31 -0
  77. data/lib/backup/syncer/rsync/pull.rb +51 -0
  78. data/lib/backup/syncer/rsync/push.rb +205 -0
  79. data/lib/backup/template.rb +46 -0
  80. data/lib/backup/utilities.rb +224 -0
  81. data/lib/backup/version.rb +5 -0
  82. data/templates/cli/archive +28 -0
  83. data/templates/cli/compressor/bzip2 +4 -0
  84. data/templates/cli/compressor/custom +7 -0
  85. data/templates/cli/compressor/gzip +4 -0
  86. data/templates/cli/config +123 -0
  87. data/templates/cli/databases/mongodb +15 -0
  88. data/templates/cli/databases/mysql +18 -0
  89. data/templates/cli/databases/openldap +24 -0
  90. data/templates/cli/databases/postgresql +16 -0
  91. data/templates/cli/databases/redis +16 -0
  92. data/templates/cli/databases/riak +17 -0
  93. data/templates/cli/databases/sqlite +11 -0
  94. data/templates/cli/encryptor/gpg +27 -0
  95. data/templates/cli/encryptor/openssl +9 -0
  96. data/templates/cli/model +26 -0
  97. data/templates/cli/notifier/zabbix +15 -0
  98. data/templates/cli/notifiers/campfire +12 -0
  99. data/templates/cli/notifiers/command +32 -0
  100. data/templates/cli/notifiers/datadog +57 -0
  101. data/templates/cli/notifiers/flowdock +16 -0
  102. data/templates/cli/notifiers/hipchat +16 -0
  103. data/templates/cli/notifiers/http_post +32 -0
  104. data/templates/cli/notifiers/mail +24 -0
  105. data/templates/cli/notifiers/nagios +13 -0
  106. data/templates/cli/notifiers/pagerduty +12 -0
  107. data/templates/cli/notifiers/prowl +11 -0
  108. data/templates/cli/notifiers/pushover +11 -0
  109. data/templates/cli/notifiers/ses +15 -0
  110. data/templates/cli/notifiers/slack +22 -0
  111. data/templates/cli/notifiers/twitter +13 -0
  112. data/templates/cli/splitter +7 -0
  113. data/templates/cli/storages/cloud_files +11 -0
  114. data/templates/cli/storages/dropbox +20 -0
  115. data/templates/cli/storages/ftp +13 -0
  116. data/templates/cli/storages/local +8 -0
  117. data/templates/cli/storages/qiniu +12 -0
  118. data/templates/cli/storages/rsync +17 -0
  119. data/templates/cli/storages/s3 +16 -0
  120. data/templates/cli/storages/scp +15 -0
  121. data/templates/cli/storages/sftp +15 -0
  122. data/templates/cli/syncers/cloud_files +22 -0
  123. data/templates/cli/syncers/rsync_local +20 -0
  124. data/templates/cli/syncers/rsync_pull +28 -0
  125. data/templates/cli/syncers/rsync_push +28 -0
  126. data/templates/cli/syncers/s3 +27 -0
  127. data/templates/general/links +3 -0
  128. data/templates/general/version.erb +2 -0
  129. data/templates/notifier/mail/failure.erb +16 -0
  130. data/templates/notifier/mail/success.erb +16 -0
  131. data/templates/notifier/mail/warning.erb +16 -0
  132. data/templates/storage/dropbox/authorization_url.erb +6 -0
  133. data/templates/storage/dropbox/authorized.erb +4 -0
  134. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  135. metadata +1122 -0
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ class Binder
5
+
6
+ ##
7
+ # Creates a new Backup::Notifier::Binder instance. Loops through the provided
8
+ # Hash to set instance variables
9
+ def initialize(key_and_values)
10
+ key_and_values.each do |key, value|
11
+ instance_variable_set("@#{ key }", value)
12
+ end
13
+ end
14
+
15
+ ##
16
+ # Returns the binding (needs a wrapper method because #binding is a private method)
17
+ def get_binding
18
+ binding
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ module Cleaner
5
+ class Error < Backup::Error; end
6
+
7
+ class << self
8
+
9
+ ##
10
+ # Logs warnings if any temporary files still exist
11
+ # from the last time this model/trigger was run,
12
+ # then removes the files.
13
+ def prepare(model)
14
+ messages = []
15
+
16
+ packaging_folder = File.join(Config.tmp_path, model.trigger)
17
+ if File.exist?(packaging_folder)
18
+ messages << <<-EOS
19
+ The temporary packaging folder still exists!
20
+ '#{ packaging_folder }'
21
+ It will now be removed.
22
+ EOS
23
+ FileUtils.rm_rf(packaging_folder)
24
+ end
25
+
26
+ package_files = package_files_for(model.trigger)
27
+ unless package_files.empty?
28
+ # the chances of the packaging folder AND
29
+ # the package files existing are practically nil
30
+ messages << ('-' * 74) unless messages.empty?
31
+
32
+ messages << <<-EOS
33
+ The temporary backup folder '#{ Config.tmp_path }'
34
+ appears to contain the package files from the previous backup!
35
+ #{ package_files.join("\n") }
36
+ These files will now be removed.
37
+ EOS
38
+ package_files.each {|file| FileUtils.rm_f(file) }
39
+ end
40
+
41
+ unless messages.empty?
42
+ Logger.warn Error.new(<<-EOS)
43
+ Cleanup Warning
44
+ #{ messages.join("\n") }
45
+ Please check the log for messages and/or your notifications
46
+ concerning this backup: '#{ model.label } (#{ model.trigger })'
47
+ The temporary files which had to be removed should not have existed.
48
+ EOS
49
+ end
50
+ end
51
+
52
+ ##
53
+ # Remove the temporary folder used during packaging
54
+ def remove_packaging(model)
55
+ Logger.info "Cleaning up the temporary files..."
56
+ FileUtils.rm_rf(File.join(Config.tmp_path, model.trigger))
57
+ end
58
+
59
+ ##
60
+ # Remove the final package files from tmp_path
61
+ # Note: 'force' is used, since a Local Storage may *move* these files.
62
+ def remove_package(package)
63
+ Logger.info "Cleaning up the package files..."
64
+ package.filenames.each do |file|
65
+ FileUtils.rm_f(File.join(Config.tmp_path, file))
66
+ end
67
+ end
68
+
69
+ ##
70
+ # Logs warnings if any temporary files still exist
71
+ # when errors occur during the backup
72
+ def warnings(model)
73
+ messages = []
74
+
75
+ packaging_folder = File.join(Config.tmp_path, model.trigger)
76
+ if File.exist?(packaging_folder)
77
+ messages << <<-EOS
78
+ The temporary packaging folder still exists!
79
+ '#{ packaging_folder }'
80
+ This folder may contain completed Archives and/or Database backups.
81
+ EOS
82
+ end
83
+
84
+ package_files = package_files_for(model.trigger)
85
+ unless package_files.empty?
86
+ # the chances of the packaging folder AND
87
+ # the package files existing are practically nil
88
+ messages << ('-' * 74) unless messages.empty?
89
+
90
+ messages << <<-EOS
91
+ The temporary backup folder '#{ Config.tmp_path }'
92
+ appears to contain the backup files which were to be stored:
93
+ #{ package_files.join("\n") }
94
+ EOS
95
+ end
96
+
97
+ unless messages.empty?
98
+ Logger.warn Error.new(<<-EOS)
99
+ Cleanup Warning
100
+ #{ messages.join("\n") }
101
+ Make sure you check these files before the next scheduled backup for
102
+ '#{ model.label } (#{ model.trigger })'
103
+ These files will be removed at that time!
104
+ EOS
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ def package_files_for(trigger)
111
+ Dir[File.join(Config.tmp_path,"#{ trigger }.tar{,[.-]*}")]
112
+ end
113
+
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,374 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Build the Backup Command Line Interface using Thor
5
+ module Backup
6
+ class CLI < Thor
7
+ class Error < Backup::Error; end
8
+ class FatalError < Backup::FatalError; end
9
+
10
+ ##
11
+ # [Perform]
12
+ #
13
+ # The only required option is the --trigger [-t].
14
+ # If --config-file, --data-path, --tmp-path or --log-path
15
+ # aren't specified they will fallback to defaults.
16
+ # If --root-path is given, it will be used as the base path for our defaults,
17
+ # as well as the base path for any option specified as a relative path.
18
+ # Any option given as an absolute path will be used "as-is".
19
+ #
20
+ # This command will exit with one of the following status codes:
21
+ #
22
+ # 0: All triggers were successful and no warnings were issued.
23
+ # 1: All triggers were successful, but some had warnings.
24
+ # 2: All triggers were processed, but some failed.
25
+ # 3: A fatal error caused Backup to exit.
26
+ # Some triggers may not have been processed.
27
+ #
28
+ # If the --check option is given, `backup check` will be run
29
+ # and no triggers will be performed.
30
+ desc 'perform', "Performs the backup for the specified trigger(s)."
31
+
32
+ long_desc <<-EOS.gsub(/^ +/, '')
33
+ Performs the backup for the specified trigger(s).
34
+
35
+ You may perform multiple backups by providing multiple triggers,
36
+ separated by commas. Each will run in the order specified.
37
+
38
+ $ backup perform --triggers backup1,backup2,backup3,backup4
39
+
40
+ --root-path may be an absolute path or relative to the current directory.
41
+
42
+ To use the current directory, use: `--root-path .`
43
+
44
+ Relative paths given for --config-file, --data-path, --tmp-path,
45
+ and --log-path will be relative to --root-path.
46
+
47
+ Console log output may be forced using --no-quiet.
48
+
49
+ Logging to file or syslog may be disabled using --no-logfile or --no-syslog
50
+ respectively. This will override logging options set in `config.rb`.
51
+ EOS
52
+
53
+ method_option :trigger,
54
+ :aliases => ['-t', '--triggers'],
55
+ :required => true,
56
+ :type => :string,
57
+ :desc => "Triggers to perform. e.g. 'trigger_a,trigger_b'"
58
+
59
+ method_option :config_file,
60
+ :aliases => '-c',
61
+ :type => :string,
62
+ :default => '',
63
+ :desc => 'Path to your config.rb file.'
64
+
65
+ method_option :root_path,
66
+ :aliases => '-r',
67
+ :type => :string,
68
+ :default => '',
69
+ :desc => 'Root path to base all relative path on.'
70
+
71
+ method_option :data_path,
72
+ :aliases => '-d',
73
+ :type => :string,
74
+ :default => '',
75
+ :desc => 'Path to store storage cycling data.'
76
+
77
+ method_option :log_path,
78
+ :aliases => '-l',
79
+ :type => :string,
80
+ :default => '',
81
+ :desc => "Path to store Backup's log file."
82
+
83
+ method_option :tmp_path,
84
+ :type => :string,
85
+ :default => '',
86
+ :desc => 'Path to store temporary data during the backup.'
87
+
88
+ # Note that :quiet, :syslog and :logfile are specified as :string types,
89
+ # so the --no-<option> usage will set the value to nil instead of false.
90
+ method_option :quiet,
91
+ :aliases => '-q',
92
+ :type => :string,
93
+ :default => false,
94
+ :banner => '',
95
+ :desc => 'Disable console log output.'
96
+
97
+ method_option :syslog,
98
+ :type => :string,
99
+ :default => false,
100
+ :banner => '',
101
+ :desc => 'Enable logging to syslog.'
102
+
103
+ method_option :logfile,
104
+ :type => :string,
105
+ :default => true,
106
+ :banner => '',
107
+ :desc => "Enable Backup's log file."
108
+
109
+ method_option :check,
110
+ :type => :boolean,
111
+ :default => false,
112
+ :desc => 'Check configuration for errors or warnings.'
113
+
114
+ def perform
115
+ check if options[:check] # this will exit()
116
+
117
+ models = nil
118
+ begin
119
+ # Set logger options
120
+ opts = options
121
+ Logger.configure do
122
+ console.quiet = opts[:quiet]
123
+ logfile.enabled = opts[:logfile]
124
+ logfile.log_path = opts[:log_path]
125
+ syslog.enabled = opts[:syslog]
126
+ end
127
+
128
+ # Load the user's +config.rb+ file and all their Models
129
+ Config.load(options)
130
+
131
+ # Identify all Models to be run for the given +triggers+.
132
+ triggers = options[:trigger].split(',').map(&:strip)
133
+ models = triggers.map {|trigger|
134
+ Model.find_by_trigger(trigger)
135
+ }.flatten.uniq
136
+
137
+ raise Error, "No Models found for trigger(s) " +
138
+ "'#{ triggers.join(',') }'." if models.empty?
139
+
140
+ # Finalize Logger and begin real-time logging.
141
+ Logger.start!
142
+
143
+ rescue Exception => err
144
+ Logger.error Error.wrap(err)
145
+ unless Helpers.is_backup_error? err
146
+ Logger.error err.backtrace.join("\n")
147
+ end
148
+ # Logger configuration will be ignored
149
+ # and messages will be output to the console only.
150
+ Logger.abort!
151
+ exit(3)
152
+ end
153
+
154
+ until models.empty?
155
+ model = models.shift
156
+ model.perform!
157
+
158
+ case model.exit_status
159
+ when 1
160
+ warnings = true
161
+ when 2
162
+ errors = true
163
+ unless models.empty?
164
+ Logger.info Error.new(<<-EOS)
165
+ Backup will now continue...
166
+ The following triggers will now be processed:
167
+ (#{ models.map {|m| m.trigger }.join(', ') })
168
+ EOS
169
+ end
170
+ when 3
171
+ fatal = true
172
+ unless models.empty?
173
+ Logger.error FatalError.new(<<-EOS)
174
+ Backup will now exit.
175
+ The following triggers will not be processed:
176
+ (#{ models.map {|m| m.trigger }.join(', ') })
177
+ EOS
178
+ end
179
+ end
180
+
181
+ model.notifiers.each(&:perform!)
182
+ exit(3) if fatal
183
+ Logger.clear!
184
+ end
185
+
186
+ exit(errors ? 2 : 1) if errors || warnings
187
+ end
188
+
189
+ ##
190
+ # [Check]
191
+ #
192
+ # Loads the user's `config.rb` (and all Model files) and reports any Errors
193
+ # or Warnings. This is primarily for checking for syntax errors, missing
194
+ # dependencies and deprecation warnings.
195
+ #
196
+ # This may also be invoked using the `--check` option to `backup perform`.
197
+ #
198
+ # This command only requires `Config.config_file` to be correct.
199
+ # All other Config paths are irrelevant.
200
+ #
201
+ # All output will be sent to the console only.
202
+ # Logger options will be ignored.
203
+ #
204
+ # If successful, this method with exit(0).
205
+ # If there are Errors or Warnings, it will exit(1).
206
+ desc 'check', 'Check for configuration errors or warnings'
207
+
208
+ long_desc <<-EOS.gsub(/^ +/, '')
209
+ Loads your 'config.rb' file and all models and reports any
210
+ errors or warnings with your configuration, including missing
211
+ dependencies and the use of any deprecated settings.
212
+ EOS
213
+
214
+ method_option :config_file,
215
+ :aliases => '-c',
216
+ :type => :string,
217
+ :default => '',
218
+ :desc => "Path to your config.rb file."
219
+
220
+ def check
221
+ begin
222
+ Config.load(options)
223
+ rescue Exception => err
224
+ Logger.error Error.wrap(err)
225
+ unless Helpers.is_backup_error? err
226
+ Logger.error err.backtrace.join("\n")
227
+ end
228
+ end
229
+
230
+ if Logger.has_warnings? || Logger.has_errors?
231
+ Logger.error 'Configuration Check Failed.'
232
+ exit_code = 1
233
+ else
234
+ Logger.info 'Configuration Check Succeeded.'
235
+ exit_code = 0
236
+ end
237
+
238
+ Logger.abort!
239
+ exit(exit_code)
240
+ end
241
+
242
+ ##
243
+ # [Generate:Model]
244
+ # Generates a model configuration file based on the arguments passed in.
245
+ # For example:
246
+ # $ backup generate:model --trigger my_backup --databases='mongodb'
247
+ # will generate a pre-populated model with a base MongoDB setup
248
+ desc 'generate:model', "Generates a Backup model file."
249
+
250
+ long_desc <<-EOS.gsub(/^ +/, '')
251
+ Generates a Backup model file.
252
+
253
+ If your configuration file is not in the default location at
254
+ #{ Config.config_file }
255
+ you must specify it's location using '--config-file'.
256
+ If no configuration file exists at this location, one will be created.
257
+
258
+ The model file will be created as '<config_path>/models/<trigger>.rb'
259
+ Your model file will be created in a 'models/' sub-directory
260
+ where your config file is located. The default location would be:
261
+ #{ Config.root_path }/models/<trigger>.rb
262
+ EOS
263
+
264
+ method_option :trigger,
265
+ :aliases => '-t',
266
+ :required => true,
267
+ :type => :string,
268
+ :desc => 'Trigger name for the Backup model'
269
+
270
+ method_option :config_file,
271
+ :type => :string,
272
+ :desc => 'Path to your Backup configuration file'
273
+
274
+ # options with their available values
275
+ %w{ databases storages syncers encryptor compressor notifiers }.each do |name|
276
+ path = File.join(Backup::TEMPLATE_PATH, 'cli', name)
277
+ opts = Dir[path + '/*'].sort.map {|p| File.basename(p) }.join(', ')
278
+ method_option name, :type => :string, :desc => "(#{ opts })"
279
+ end
280
+
281
+ method_option :archives,
282
+ :type => :boolean,
283
+ :desc => 'Model will include tar archives.'
284
+
285
+ method_option :splitter,
286
+ :type => :boolean,
287
+ :default => false,
288
+ :desc => 'Add Splitter to the model'
289
+
290
+ define_method 'generate:model' do
291
+ opts = options.merge(:trigger => options[:trigger].gsub(/\W/, '_'))
292
+ config_file = opts[:config_file] ?
293
+ File.expand_path(opts.delete(:config_file)) : Config.config_file
294
+ models_path = File.join(File.dirname(config_file), 'models')
295
+ model_file = File.join(models_path, "#{ opts[:trigger] }.rb")
296
+
297
+ unless File.exist?(config_file)
298
+ invoke 'generate:config', [], :config_file => config_file
299
+ end
300
+
301
+ FileUtils.mkdir_p(models_path)
302
+ if Helpers.overwrite?(model_file)
303
+ File.open(model_file, 'w') do |file|
304
+ file.write(Backup::Template.new({:options => opts}).result('cli/model'))
305
+ end
306
+ puts "Generated model file: '#{ model_file }'."
307
+ end
308
+ end
309
+
310
+ ##
311
+ # [Generate:Config]
312
+ # Generates the main configuration file
313
+ desc 'generate:config', 'Generates the main Backup configuration file'
314
+
315
+ long_desc <<-EOS.gsub(/^ +/, '')
316
+ Path to the Backup configuration file to generate.
317
+
318
+ Defaults to:
319
+
320
+ #{ Config.config_file }
321
+ EOS
322
+
323
+ method_option :config_file,
324
+ :type => :string,
325
+ :desc => 'Path to the Backup configuration file to generate.'
326
+
327
+ define_method 'generate:config' do
328
+ config_file = options[:config_file] ?
329
+ File.expand_path(options[:config_file]) : Config.config_file
330
+
331
+ FileUtils.mkdir_p(File.dirname(config_file))
332
+ if Helpers.overwrite?(config_file)
333
+ File.open(config_file, 'w') do |file|
334
+ file.write(Backup::Template.new.result('cli/config'))
335
+ end
336
+ puts "Generated configuration file: '#{ config_file }'."
337
+ end
338
+ end
339
+
340
+ ##
341
+ # [Version]
342
+ # Returns the current version of the Backup gem
343
+ map '-v' => :version
344
+ desc 'version', 'Display installed Backup version'
345
+ def version
346
+ puts "Backup #{ Backup::VERSION }"
347
+ end
348
+
349
+ # This is to avoid Thor's warnings when stubbing methods on the Thor class.
350
+ module Helpers
351
+ class << self
352
+
353
+ def overwrite?(path)
354
+ return true unless File.exist?(path)
355
+
356
+ $stderr.print "A file already exists at '#{ path }'.\n" +
357
+ "Do you want to overwrite? [y/n] "
358
+ /^[Yy]/ =~ $stdin.gets
359
+ end
360
+
361
+ def exec!(cmd)
362
+ puts "Launching: #{ cmd }"
363
+ exec(cmd)
364
+ end
365
+
366
+ def is_backup_error?(error)
367
+ error.class.ancestors.include? Backup::Error
368
+ end
369
+
370
+ end
371
+ end
372
+
373
+ end
374
+ end