backup 3.0.27 → 3.1.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 (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