backup 3.0.27 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. data/LICENSE.md +1 -1
  2. data/README.md +139 -386
  3. data/bin/backup +1 -7
  4. data/lib/backup.rb +3 -9
  5. data/lib/backup/archive.rb +26 -20
  6. data/lib/backup/cleaner.rb +2 -2
  7. data/lib/backup/cli.rb +366 -0
  8. data/lib/backup/compressor/base.rb +2 -2
  9. data/lib/backup/compressor/gzip.rb +35 -1
  10. data/lib/backup/config.rb +1 -2
  11. data/lib/backup/database/base.rb +2 -2
  12. data/lib/backup/database/mongodb.rb +3 -3
  13. data/lib/backup/database/mysql.rb +3 -2
  14. data/lib/backup/database/postgresql.rb +3 -2
  15. data/lib/backup/database/riak.rb +18 -5
  16. data/lib/backup/dependency.rb +144 -93
  17. data/lib/backup/encryptor/base.rb +2 -2
  18. data/lib/backup/logger.rb +108 -110
  19. data/lib/backup/logger/console.rb +51 -0
  20. data/lib/backup/logger/logfile.rb +113 -0
  21. data/lib/backup/logger/syslog.rb +116 -0
  22. data/lib/backup/model.rb +67 -65
  23. data/lib/backup/notifier/base.rb +1 -1
  24. data/lib/backup/notifier/hipchat.rb +1 -1
  25. data/lib/backup/notifier/mail.rb +1 -1
  26. data/lib/backup/notifier/pushover.rb +6 -3
  27. data/lib/backup/packager.rb +4 -4
  28. data/lib/backup/pipeline.rb +17 -3
  29. data/lib/backup/splitter.rb +2 -2
  30. data/lib/backup/storage/base.rb +2 -2
  31. data/lib/backup/storage/cloudfiles.rb +2 -2
  32. data/lib/backup/storage/dropbox.rb +4 -4
  33. data/lib/backup/storage/ftp.rb +2 -2
  34. data/lib/backup/storage/local.rb +2 -2
  35. data/lib/backup/storage/ninefold.rb +2 -2
  36. data/lib/backup/storage/rsync.rb +3 -3
  37. data/lib/backup/storage/s3.rb +2 -2
  38. data/lib/backup/storage/scp.rb +2 -6
  39. data/lib/backup/storage/sftp.rb +2 -5
  40. data/lib/backup/syncer/base.rb +1 -1
  41. data/lib/backup/syncer/cloud/base.rb +15 -8
  42. data/lib/backup/syncer/rsync/local.rb +1 -1
  43. data/lib/backup/syncer/rsync/pull.rb +1 -1
  44. data/lib/backup/syncer/rsync/push.rb +1 -1
  45. data/lib/backup/utilities.rb +211 -0
  46. data/lib/backup/version.rb +1 -1
  47. data/templates/cli/{utility/archive → archive} +4 -8
  48. data/templates/cli/{utility/compressor → compressor}/bzip2 +0 -0
  49. data/templates/cli/{utility/compressor → compressor}/custom +0 -0
  50. data/templates/cli/{utility/compressor → compressor}/gzip +0 -0
  51. data/templates/cli/{utility/compressor → compressor}/lzma +0 -0
  52. data/templates/cli/{utility/compressor → compressor}/pbzip2 +0 -0
  53. data/templates/cli/config +68 -0
  54. data/templates/cli/{utility/database → database}/mongodb +1 -1
  55. data/templates/cli/{utility/database → database}/mysql +1 -1
  56. data/templates/cli/{utility/database → database}/postgresql +1 -1
  57. data/templates/cli/{utility/database → database}/redis +0 -0
  58. data/templates/cli/database/riak +20 -0
  59. data/templates/cli/{utility/encryptor → encryptor}/gpg +0 -0
  60. data/templates/cli/{utility/encryptor → encryptor}/openssl +0 -0
  61. data/templates/cli/{utility/model.erb → model.erb} +4 -4
  62. data/templates/cli/{utility/notifier → notifier}/campfire +0 -0
  63. data/templates/cli/{utility/notifier → notifier}/hipchat +0 -0
  64. data/templates/cli/{utility/notifier → notifier}/mail +0 -0
  65. data/templates/cli/{utility/notifier → notifier}/prowl +0 -0
  66. data/templates/cli/{utility/notifier → notifier}/pushover +0 -0
  67. data/templates/cli/{utility/notifier → notifier}/twitter +0 -0
  68. data/templates/cli/{utility/splitter → splitter} +0 -0
  69. data/templates/cli/{utility/storage → storage}/cloud_files +0 -0
  70. data/templates/cli/{utility/storage → storage}/dropbox +0 -0
  71. data/templates/cli/{utility/storage → storage}/ftp +0 -0
  72. data/templates/cli/{utility/storage → storage}/local +0 -0
  73. data/templates/cli/{utility/storage → storage}/ninefold +0 -0
  74. data/templates/cli/{utility/storage → storage}/rsync +0 -0
  75. data/templates/cli/{utility/storage → storage}/s3 +0 -0
  76. data/templates/cli/{utility/storage → storage}/scp +0 -0
  77. data/templates/cli/{utility/storage → storage}/sftp +0 -0
  78. data/templates/cli/{utility/syncer → syncer}/cloud_files +0 -0
  79. data/templates/cli/{utility/syncer → syncer}/rsync_local +0 -0
  80. data/templates/cli/{utility/syncer → syncer}/rsync_pull +0 -0
  81. data/templates/cli/{utility/syncer → syncer}/rsync_push +0 -0
  82. data/templates/cli/{utility/syncer → syncer}/s3 +0 -0
  83. metadata +55 -131
  84. data/.gitignore +0 -8
  85. data/.travis.yml +0 -10
  86. data/Gemfile +0 -28
  87. data/Guardfile +0 -23
  88. data/backup.gemspec +0 -32
  89. data/lib/backup/cli/helpers.rb +0 -93
  90. data/lib/backup/cli/utility.rb +0 -255
  91. data/spec-live/.gitignore +0 -6
  92. data/spec-live/README +0 -7
  93. data/spec-live/backups/config.rb +0 -83
  94. data/spec-live/backups/config.yml.template +0 -46
  95. data/spec-live/backups/models.rb +0 -184
  96. data/spec-live/compressor/custom_spec.rb +0 -30
  97. data/spec-live/compressor/gzip_spec.rb +0 -30
  98. data/spec-live/encryptor/gpg_keys.rb +0 -239
  99. data/spec-live/encryptor/gpg_spec.rb +0 -287
  100. data/spec-live/notifier/mail_spec.rb +0 -121
  101. data/spec-live/spec_helper.rb +0 -151
  102. data/spec-live/storage/dropbox_spec.rb +0 -151
  103. data/spec-live/storage/local_spec.rb +0 -83
  104. data/spec-live/storage/scp_spec.rb +0 -193
  105. data/spec-live/syncer/cloud/s3_spec.rb +0 -124
  106. data/spec/archive_spec.rb +0 -335
  107. data/spec/cleaner_spec.rb +0 -312
  108. data/spec/cli/helpers_spec.rb +0 -301
  109. data/spec/cli/utility_spec.rb +0 -411
  110. data/spec/compressor/base_spec.rb +0 -52
  111. data/spec/compressor/bzip2_spec.rb +0 -217
  112. data/spec/compressor/custom_spec.rb +0 -106
  113. data/spec/compressor/gzip_spec.rb +0 -217
  114. data/spec/compressor/lzma_spec.rb +0 -123
  115. data/spec/compressor/pbzip2_spec.rb +0 -165
  116. data/spec/config_spec.rb +0 -321
  117. data/spec/configuration/helpers_spec.rb +0 -247
  118. data/spec/configuration/store_spec.rb +0 -39
  119. data/spec/configuration_spec.rb +0 -62
  120. data/spec/database/base_spec.rb +0 -63
  121. data/spec/database/mongodb_spec.rb +0 -510
  122. data/spec/database/mysql_spec.rb +0 -411
  123. data/spec/database/postgresql_spec.rb +0 -353
  124. data/spec/database/redis_spec.rb +0 -334
  125. data/spec/database/riak_spec.rb +0 -176
  126. data/spec/dependency_spec.rb +0 -51
  127. data/spec/encryptor/base_spec.rb +0 -40
  128. data/spec/encryptor/gpg_spec.rb +0 -909
  129. data/spec/encryptor/open_ssl_spec.rb +0 -148
  130. data/spec/errors_spec.rb +0 -306
  131. data/spec/logger_spec.rb +0 -367
  132. data/spec/model_spec.rb +0 -666
  133. data/spec/notifier/base_spec.rb +0 -104
  134. data/spec/notifier/campfire_spec.rb +0 -217
  135. data/spec/notifier/hipchat_spec.rb +0 -211
  136. data/spec/notifier/mail_spec.rb +0 -316
  137. data/spec/notifier/prowl_spec.rb +0 -138
  138. data/spec/notifier/pushover_spec.rb +0 -123
  139. data/spec/notifier/twitter_spec.rb +0 -153
  140. data/spec/package_spec.rb +0 -61
  141. data/spec/packager_spec.rb +0 -213
  142. data/spec/pipeline_spec.rb +0 -259
  143. data/spec/spec_helper.rb +0 -60
  144. data/spec/splitter_spec.rb +0 -120
  145. data/spec/storage/base_spec.rb +0 -166
  146. data/spec/storage/cloudfiles_spec.rb +0 -254
  147. data/spec/storage/cycler_spec.rb +0 -247
  148. data/spec/storage/dropbox_spec.rb +0 -480
  149. data/spec/storage/ftp_spec.rb +0 -271
  150. data/spec/storage/local_spec.rb +0 -259
  151. data/spec/storage/ninefold_spec.rb +0 -343
  152. data/spec/storage/rsync_spec.rb +0 -362
  153. data/spec/storage/s3_spec.rb +0 -245
  154. data/spec/storage/scp_spec.rb +0 -233
  155. data/spec/storage/sftp_spec.rb +0 -244
  156. data/spec/syncer/base_spec.rb +0 -109
  157. data/spec/syncer/cloud/base_spec.rb +0 -515
  158. data/spec/syncer/cloud/cloud_files_spec.rb +0 -181
  159. data/spec/syncer/cloud/s3_spec.rb +0 -174
  160. data/spec/syncer/rsync/base_spec.rb +0 -98
  161. data/spec/syncer/rsync/local_spec.rb +0 -149
  162. data/spec/syncer/rsync/pull_spec.rb +0 -98
  163. data/spec/syncer/rsync/push_spec.rb +0 -333
  164. data/spec/version_spec.rb +0 -21
  165. data/templates/cli/utility/config +0 -32
  166. data/templates/cli/utility/database/riak +0 -11
data/bin/backup CHANGED
@@ -1,11 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: utf-8
3
3
 
4
- # Load the Backup core library
5
4
  require File.expand_path("../../lib/backup", __FILE__)
6
-
7
- # Load the Backup command line interface utility
8
- require File.expand_path("../../lib/backup/cli/utility", __FILE__)
9
-
10
- # Initialize the Backup command line utility
11
- Backup::CLI::Utility.start
5
+ Backup::CLI.start
data/lib/backup.rb CHANGED
@@ -4,6 +4,7 @@
4
4
  require 'rubygems'
5
5
  require 'fileutils'
6
6
  require 'tempfile'
7
+ require 'syslog'
7
8
  require 'yaml'
8
9
  require 'etc'
9
10
 
@@ -17,7 +18,6 @@ module Backup
17
18
  ##
18
19
  # Backup's internal paths
19
20
  LIBRARY_PATH = File.join(File.dirname(__FILE__), 'backup')
20
- CLI_PATH = File.join(LIBRARY_PATH, 'cli')
21
21
  STORAGE_PATH = File.join(LIBRARY_PATH, 'storage')
22
22
  DATABASE_PATH = File.join(LIBRARY_PATH, 'database')
23
23
  COMPRESSOR_PATH = File.join(LIBRARY_PATH, 'compressor')
@@ -26,13 +26,6 @@ module Backup
26
26
  SYNCER_PATH = File.join(LIBRARY_PATH, 'syncer')
27
27
  TEMPLATE_PATH = File.expand_path('../../templates', __FILE__)
28
28
 
29
- ##
30
- # Autoload Backup CLI files
31
- module CLI
32
- autoload :Helpers, File.join(CLI_PATH, 'helpers')
33
- autoload :Utility, File.join(CLI_PATH, 'utility')
34
- end
35
-
36
29
  ##
37
30
  # Autoload Backup storage files
38
31
  module Storage
@@ -100,7 +93,6 @@ module Backup
100
93
  # Autoload notification files
101
94
  module Notifier
102
95
  autoload :Base, File.join(NOTIFIER_PATH, 'base')
103
- autoload :Binder, File.join(NOTIFIER_PATH, 'binder')
104
96
  autoload :Mail, File.join(NOTIFIER_PATH, 'mail')
105
97
  autoload :Twitter, File.join(NOTIFIER_PATH, 'twitter')
106
98
  autoload :Campfire, File.join(NOTIFIER_PATH, 'campfire')
@@ -112,10 +104,12 @@ module Backup
112
104
  ##
113
105
  # Require Backup base files
114
106
  %w{
107
+ utilities
115
108
  archive
116
109
  binder
117
110
  cleaner
118
111
  config
112
+ cli
119
113
  configuration
120
114
  dependency
121
115
  errors
@@ -2,23 +2,23 @@
2
2
 
3
3
  module Backup
4
4
  class Archive
5
- include Backup::CLI::Helpers
5
+ include Backup::Utilities::Helpers
6
6
 
7
7
  ##
8
8
  # Stores the name of the archive
9
- attr_accessor :name
9
+ attr_reader :name
10
10
 
11
11
  ##
12
12
  # Stores an array of different paths/files to store
13
- attr_accessor :paths
13
+ attr_reader :paths
14
14
 
15
15
  ##
16
16
  # Stores an array of different paths/files to exclude
17
- attr_accessor :excludes
17
+ attr_reader :excludes
18
18
 
19
19
  ##
20
20
  # String of additional arguments for the `tar` command
21
- attr_accessor :tar_args
21
+ attr_reader :tar_args
22
22
 
23
23
  ##
24
24
  # Takes the name of the archive and the configuration block
@@ -35,16 +35,7 @@ module Backup
35
35
  ##
36
36
  # Adds new paths to the @paths instance variable array
37
37
  def add(path)
38
- path = File.expand_path(path)
39
- if File.exist?(path)
40
- @paths << path
41
- else
42
- Logger.warn Errors::Archive::NotFoundError.new(<<-EOS)
43
- The following path was not found:
44
- #{ path }
45
- This path will be omitted from the '#{ name }' Archive.
46
- EOS
47
- end
38
+ @paths << File.expand_path(path)
48
39
  end
49
40
 
50
41
  ##
@@ -67,7 +58,7 @@ module Backup
67
58
  # will be piped through the Compressor command and the file extension
68
59
  # will be adjusted to indicate the type of compression used.
69
60
  def perform!
70
- Logger.message "#{ self.class } has started archiving:\n" +
61
+ Logger.info "#{ self.class } has started archiving:\n" +
71
62
  paths.map {|path| " #{path}" }.join("\n")
72
63
 
73
64
  archive_path = File.join(Config.tmp_path, @model.trigger, 'archives')
@@ -76,8 +67,11 @@ module Backup
76
67
  archive_ext = 'tar'
77
68
  pipeline = Pipeline.new
78
69
 
79
- pipeline << "#{ utility(:tar) } #{ tar_args } -cPf - " +
80
- "#{ paths_to_exclude } #{ paths_to_package }"
70
+ pipeline.add(
71
+ "#{ utility(:tar) } #{ tar_arguments } -cPf - " +
72
+ "#{ paths_to_exclude } #{ paths_to_package }",
73
+ tar_success_codes
74
+ )
81
75
 
82
76
  if @model.compressor
83
77
  @model.compressor.compress_with do |command, ext|
@@ -86,10 +80,11 @@ module Backup
86
80
  end
87
81
  end
88
82
 
89
- pipeline << "cat > '#{ File.join(archive_path, "#{name}.#{archive_ext}") }'"
83
+ pipeline << "#{ utility(:cat) } > " +
84
+ "'#{ File.join(archive_path, "#{name}.#{archive_ext}") }'"
90
85
  pipeline.run
91
86
  if pipeline.success?
92
- Logger.message "#{ self.class } Complete!"
87
+ Logger.info "#{ self.class } Complete!"
93
88
  else
94
89
  raise Errors::Archive::PipelineError,
95
90
  "Failed to Create Backup Archive\n" +
@@ -113,5 +108,16 @@ module Backup
113
108
  end
114
109
  end
115
110
 
111
+ ##
112
+ # Returns arguments for GNU or BSD tar.
113
+ def tar_arguments
114
+ gnu_tar? ? "--ignore-failed-read #{ tar_args }".strip : tar_args
115
+ end
116
+
117
+ ##
118
+ # Returns successful GNU or BSD tar exit codes.
119
+ def tar_success_codes
120
+ gnu_tar? ? [0, 1] : [0]
121
+ end
116
122
  end
117
123
  end
@@ -50,7 +50,7 @@ module Backup
50
50
  ##
51
51
  # Remove the temporary folder used during packaging
52
52
  def remove_packaging(model)
53
- Logger.message "Cleaning up the temporary files..."
53
+ Logger.info "Cleaning up the temporary files..."
54
54
  FileUtils.rm_rf(File.join(Config.tmp_path, model.trigger))
55
55
  end
56
56
 
@@ -58,7 +58,7 @@ module Backup
58
58
  # Remove the final package files from tmp_path
59
59
  # Note: 'force' is used, since a Local Storage may *move* these files.
60
60
  def remove_package(package)
61
- Logger.message "Cleaning up the package files..."
61
+ Logger.info "Cleaning up the package files..."
62
62
  package.filenames.each do |file|
63
63
  FileUtils.rm_f(File.join(Config.tmp_path, file))
64
64
  end
data/lib/backup/cli.rb ADDED
@@ -0,0 +1,366 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Build the Backup Command Line Interface using Thor
5
+ module Backup
6
+ class CLI < Thor
7
+ include Thor::Actions
8
+
9
+ ##
10
+ # [Perform]
11
+ # Performs the backup process. The only required option is the --trigger [-t].
12
+ # If the other options (--config-file, --data-path, --cache-path, --tmp-path) aren't specified
13
+ # they will fallback to the (good) defaults
14
+ #
15
+ # If --root-path is given, it will be used as the base path for our defaults,
16
+ # as well as the base path for any option specified as a relative path.
17
+ # Any option given as an absolute path will be used "as-is".
18
+ desc 'perform', "Performs the backup for the specified trigger(s)."
19
+ long_desc "Performs the backup for the specified trigger(s).\n\n" +
20
+ "You may perform multiple backups by providing multiple triggers, separated by commas.\n\n" +
21
+ "Example:\n\s\s$ backup perform --triggers backup1,backup2,backup3,backup4\n\n" +
22
+ "This will invoke 4 backups, and they will run in the order specified (not asynchronous).\n\n" +
23
+ "\n\n" +
24
+ "--root-path may be an absolute path or relative to the current working directory.\n\n" +
25
+ "To use the current directory, you can use: `--root-path .` (i.e. a period for the argument)"
26
+
27
+ method_option :trigger, :type => :string, :required => true, :aliases => ['-t', '--triggers'],
28
+ :desc => "Triggers to perform. e.g. 'trigger_a,trigger_b'"
29
+ method_option :config_file, :type => :string, :default => '', :aliases => '-c',
30
+ :desc => "Path to your config.rb file. " +
31
+ "Absolute, or relative to --root-path."
32
+ method_option :root_path, :type => :string, :default => '', :aliases => '-r',
33
+ :desc => "Root path to base all relative path on. " +
34
+ "Absolute or relative to current directory (#{Dir.pwd})."
35
+ method_option :data_path, :type => :string, :default => '', :aliases => '-d',
36
+ :desc => "Path to store persisted data (storage 'keep' data). " +
37
+ "Absolute, or relative to --root-path."
38
+ method_option :log_path, :type => :string, :default => '', :aliases => '-l',
39
+ :desc => "Path to store Backup's log file. " +
40
+ "Absolute, or relative to --root-path."
41
+ method_option :cache_path, :type => :string, :default => '',
42
+ :desc => "Path to store Dropbox's cached authorization. " +
43
+ "Absolute, or relative to --root-path."
44
+ method_option :tmp_path, :type => :string, :default => '',
45
+ :desc => "Path to store temporary data during the backup process. " +
46
+ "Absolute, or relative to --root-path."
47
+ # Note that :quiet, :syslog and :logfile are specified as :string types,
48
+ # so the --no-<option> usage will set the value to nil instead of false.
49
+ method_option :quiet, :type => :string, :default => false, :aliases => '-q', :banner => '',
50
+ :desc => "Disable console log output. " +
51
+ "May be force enabled using --no-quiet."
52
+ method_option :syslog, :type => :string, :default => false, :banner => '',
53
+ :desc => "Enable logging to syslog. " +
54
+ "May be forced disabled using --no-syslog."
55
+ method_option :logfile, :type => :string, :default => true, :banner => '',
56
+ :desc => "Enable Backup's log file. " +
57
+ "May be forced disabled using --no-logfile."
58
+ method_option :check, :type => :boolean, :default => false,
59
+ :desc => "Check `config.rb` and all Model configuration for errors or warnings."
60
+
61
+ def perform
62
+ ##
63
+ # Prepare to perform requested backup jobs.
64
+ models = nil
65
+ begin
66
+ ##
67
+ # Set logger options
68
+ opts = options
69
+ Logger.configure do
70
+ console.quiet = opts[:quiet]
71
+ logfile.enabled = opts[:logfile]
72
+ logfile.log_path = opts[:log_path]
73
+ syslog.enabled = opts[:syslog]
74
+ end
75
+
76
+ ##
77
+ # Update Config variables
78
+ # (config_file, root_path, data_path, cache_path, tmp_path)
79
+ Config.update(options)
80
+
81
+ ##
82
+ # Ensure the :cache_path and :tmp_path are created
83
+ # if they do not yet exist
84
+ [Config.cache_path, Config.tmp_path].each do |path|
85
+ FileUtils.mkdir_p(path)
86
+ end
87
+
88
+ ##
89
+ # Load the user's +config.rb+ file (and all their Models).
90
+ # May update Logger options.
91
+ Config.load_config!
92
+
93
+ ##
94
+ # Identify all Models to be run for the given +triggers+.
95
+ triggers = options[:trigger].split(',').map(&:strip)
96
+ models = triggers.map {|trigger|
97
+ Model.find_by_trigger(trigger)
98
+ }.flatten.uniq
99
+
100
+ if models.empty?
101
+ raise Errors::CLIError,
102
+ "No Models found for trigger(s) '#{triggers.join(',')}'."
103
+ end
104
+
105
+ if options[:check] && Logger.has_warnings?
106
+ raise Errors::CLIError, 'Configuration Check has warnings.'
107
+ end
108
+
109
+ ##
110
+ # Finalize Logger configuration and begin real-time logging.
111
+ Logger.start!
112
+
113
+ rescue => err
114
+ Logger.error Errors::CLIError.wrap(err)
115
+ Logger.error 'Configuration Check Failed.' if options[:check]
116
+ # Logger configuration will be ignored
117
+ # and messages will be output to the console only.
118
+ Logger.abort!
119
+ exit(1)
120
+ end
121
+
122
+ if options[:check]
123
+ Logger.info 'Configuration Check Succeeded.'
124
+ else
125
+ ##
126
+ # Perform the backup job for each Model found for the given triggers,
127
+ # clearing the Logger after each job.
128
+ #
129
+ # Model#perform! handles all exceptions from this point,
130
+ # as each model may fail and return here to allow others to run.
131
+ models.each do |model|
132
+ model.perform!
133
+ Logger.clear!
134
+ end
135
+ end
136
+ end
137
+
138
+ ##
139
+ # [Generate:Model]
140
+ # Generates a model configuration file based on the arguments passed in.
141
+ # For example:
142
+ # $ backup generate:model --trigger my_backup --databases='mongodb'
143
+ # will generate a pre-populated model with a base MongoDB setup
144
+ desc 'generate:model', "Generates a Backup model file."
145
+ long_desc "Generates a Backup model file.\n\n" +
146
+ "\s\sNote: '--config-path' is the path to the directory where 'config.rb' is located.\n\n" +
147
+ "\s\sThe model file will be created as '<config_path>/models/<trigger>.rb'\n\n" +
148
+ "\s\sDefault: #{Config.root_path}\n\n"
149
+
150
+ method_option :trigger, :type => :string, :required => true, :aliases => '-t'
151
+ method_option :config_path, :type => :string,
152
+ :desc => 'Path to your Backup configuration directory'
153
+
154
+ # options with their available values
155
+ %w{ databases storages syncers
156
+ encryptors compressors notifiers }.map(&:to_sym).each do |name|
157
+ path = File.join(Backup::TEMPLATE_PATH, 'cli', name.to_s[0..-2])
158
+ method_option name, :type => :string, :desc =>
159
+ "(#{Dir[path + '/*'].sort.map {|p| File.basename(p) }.join(', ')})"
160
+ end
161
+
162
+ method_option :archives, :type => :boolean
163
+ method_option :splitter, :type => :boolean, :default => true,
164
+ :desc => "use `--no-splitter` to disable"
165
+
166
+ define_method "generate:model" do
167
+ opts = options.merge(
168
+ :trigger => options[:trigger].gsub(/\W/, '_'),
169
+ :config_path => options[:config_path] ?
170
+ File.expand_path(options[:config_path]) : nil
171
+ )
172
+ config_path = opts[:config_path] || Config.root_path
173
+ models_path = File.join(config_path, "models")
174
+ config = File.join(config_path, "config.rb")
175
+ model = File.join(models_path, "#{opts[:trigger]}.rb")
176
+
177
+ FileUtils.mkdir_p(models_path)
178
+ if overwrite?(model)
179
+ File.open(model, 'w') do |file|
180
+ file.write(
181
+ Backup::Template.new({:options => opts}).result("cli/model.erb")
182
+ )
183
+ end
184
+ puts "Generated model file: '#{ model }'."
185
+ end
186
+
187
+ if not File.exist?(config)
188
+ File.open(config, "w") do |file|
189
+ file.write(Backup::Template.new.result("cli/config"))
190
+ end
191
+ puts "Generated configuration file: '#{ config }'."
192
+ end
193
+ end
194
+
195
+ ##
196
+ # [Generate:Config]
197
+ # Generates the main configuration file
198
+ desc 'generate:config', 'Generates the main Backup bootstrap/configuration file'
199
+ method_option :config_path, :type => :string,
200
+ :desc => "Path to your Backup configuration directory. Default: #{Config.root_path}"
201
+
202
+ define_method 'generate:config' do
203
+ config_path = options[:config_path] ?
204
+ File.expand_path(options[:config_path]) : Config.root_path
205
+ config = File.join(config_path, "config.rb")
206
+
207
+ FileUtils.mkdir_p(config_path)
208
+ if overwrite?(config)
209
+ File.open(config, "w") do |file|
210
+ file.write(Backup::Template.new.result("cli/config"))
211
+ end
212
+ puts "Generated configuration file: '#{ config }'."
213
+ end
214
+ end
215
+
216
+ ##
217
+ # [Decrypt]
218
+ # Shorthand for decrypting encrypted files
219
+ desc 'decrypt', 'Decrypts encrypted files'
220
+ method_option :encryptor, :type => :string, :required => true
221
+ method_option :in, :type => :string, :required => true
222
+ method_option :out, :type => :string, :required => true
223
+ method_option :base64, :type => :boolean, :default => false
224
+ method_option :password_file, :type => :string, :default => ''
225
+ method_option :salt, :type => :boolean, :default => false
226
+
227
+ def decrypt
228
+ case options[:encryptor].downcase
229
+ when 'openssl'
230
+ base64 = options[:base64] ? '-base64' : ''
231
+ password = options[:password_file].empty? ? '' : "-pass file:#{options[:password_file]}"
232
+ salt = options[:salt] ? '-salt' : ''
233
+ %x[openssl aes-256-cbc -d #{base64} #{password} #{salt} -in '#{options[:in]}' -out '#{options[:out]}']
234
+ when 'gpg'
235
+ %x[gpg -o '#{options[:out]}' -d '#{options[:in]}']
236
+ else
237
+ puts "Unknown encryptor: #{options[:encryptor]}"
238
+ puts "Use either 'openssl' or 'gpg'."
239
+ end
240
+ end
241
+
242
+ ##
243
+ # [Dependencies]
244
+ # Returns a list of Backup's dependencies
245
+ desc 'dependencies', 'Display, Check or Install Dependencies for Backup.'
246
+ long_desc 'Display the list of dependencies for Backup, check the installation status, or install them through Backup.'
247
+ method_option :install, :type => :string
248
+ method_option :list, :type => :boolean
249
+ method_option :installed, :type => :string
250
+
251
+ def dependencies
252
+ unless options.any?
253
+ puts
254
+ puts "To display a list of available dependencies, run:\n\n"
255
+ puts " backup dependencies --list"
256
+ puts
257
+ puts "To install one of these dependencies (with the correct version), run:\n\n"
258
+ puts " backup dependencies --install <name>"
259
+ puts
260
+ puts "To check if a dependency is already installed, run:\n\n"
261
+ puts " backup dependencies --installed <name>"
262
+ exit
263
+ end
264
+
265
+ if options[:list]
266
+ deps = Dependency.all
267
+ width = 15 + deps.map {|dep| dep.used_for }.map(&:length).max
268
+ deps.each do |dep|
269
+ puts
270
+ puts "Gem Name: #{ dep.name }"
271
+ puts "Version: #{ dep.requirements.join(', ') }"
272
+ puts "Used for: #{ dep.used_for }"
273
+ puts '-' * width
274
+ end
275
+ exit
276
+ end
277
+
278
+ name = options[:install] || options[:installed]
279
+ unless dep = Dependency.find(name)
280
+ abort "'#{ name }' is not a Backup dependency."
281
+ end
282
+
283
+ if options[:install]
284
+ if Helpers.bundler_loaded?
285
+ abort <<-EOS.gsub(/^ +/, '')
286
+ === Bundler Detected ===
287
+ This command should not be run within a Bundler managed environment.
288
+ While it is possible to install Backup and it's dependencies using
289
+ Bundler, the gem version requirements must still be met as shown by:
290
+ > backup dependencies --list
291
+ EOS
292
+ end
293
+
294
+ dep.dependencies.each do |_dep|
295
+ unless _dep.installed?
296
+ abort <<-EOS.gsub(/^ +/, '')
297
+ The '#{ dep.name }' gem requires '#{ _dep.name }'
298
+ Please install this first using the following command:
299
+ > backup dependencies --install #{ _dep.name }
300
+ EOS
301
+ end
302
+ end
303
+
304
+ dep.install!
305
+ end
306
+
307
+ if options[:installed]
308
+ name, err_msg = nil, nil
309
+
310
+ dep.dependencies.each do |_dep|
311
+ unless _dep.installed?
312
+ name = _dep.name
313
+ err_msg = "'#{ dep.name }' requires the '#{ name }' gem."
314
+ break
315
+ end
316
+ end
317
+
318
+ unless err_msg || dep.installed?
319
+ name = dep.name
320
+ err_msg = "'#{ name }' is not installed."
321
+ end
322
+
323
+ if err_msg
324
+ abort <<-EOS.gsub(/^ +/, '')
325
+ #{ err_msg }
326
+ To install the gem, issue the following command:
327
+ > backup dependencies --install #{ name }
328
+ Please try again after installing the missing dependency.
329
+ EOS
330
+ else
331
+ puts "'#{ dep.name }' is installed."
332
+ end
333
+ end
334
+ end
335
+
336
+ ##
337
+ # [Version]
338
+ # Returns the current version of the Backup gem
339
+ map '-v' => :version
340
+ desc 'version', 'Display installed Backup version'
341
+ def version
342
+ puts "Backup #{Backup::Version.current}"
343
+ end
344
+
345
+ private
346
+
347
+ ##
348
+ # Helper method for asking the user if he/she wants to overwrite the file
349
+ def overwrite?(path)
350
+ if File.exist?(path)
351
+ return yes? "A file already exists at '#{ path }'. Do you want to overwrite? [y/n]"
352
+ end
353
+ true
354
+ end
355
+
356
+ # This is to avoid Thor's warnings when stubbing methods on the Thor class.
357
+ module Helpers
358
+ class << self
359
+ def bundler_loaded?
360
+ defined?(Bundler)
361
+ end
362
+ end
363
+ end
364
+
365
+ end
366
+ end