backup-agoddard 3.0.27

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of backup-agoddard might be problematic. Click here for more details.

Files changed (190) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +10 -0
  3. data/Gemfile +28 -0
  4. data/Guardfile +23 -0
  5. data/LICENSE.md +24 -0
  6. data/README.md +478 -0
  7. data/backup.gemspec +32 -0
  8. data/bin/backup +11 -0
  9. data/lib/backup.rb +133 -0
  10. data/lib/backup/archive.rb +117 -0
  11. data/lib/backup/binder.rb +22 -0
  12. data/lib/backup/cleaner.rb +121 -0
  13. data/lib/backup/cli/helpers.rb +93 -0
  14. data/lib/backup/cli/utility.rb +255 -0
  15. data/lib/backup/compressor/base.rb +35 -0
  16. data/lib/backup/compressor/bzip2.rb +50 -0
  17. data/lib/backup/compressor/custom.rb +53 -0
  18. data/lib/backup/compressor/gzip.rb +50 -0
  19. data/lib/backup/compressor/lzma.rb +52 -0
  20. data/lib/backup/compressor/pbzip2.rb +59 -0
  21. data/lib/backup/config.rb +174 -0
  22. data/lib/backup/configuration.rb +33 -0
  23. data/lib/backup/configuration/helpers.rb +130 -0
  24. data/lib/backup/configuration/store.rb +24 -0
  25. data/lib/backup/database/base.rb +53 -0
  26. data/lib/backup/database/mongodb.rb +230 -0
  27. data/lib/backup/database/mysql.rb +160 -0
  28. data/lib/backup/database/postgresql.rb +144 -0
  29. data/lib/backup/database/redis.rb +136 -0
  30. data/lib/backup/database/riak.rb +67 -0
  31. data/lib/backup/dependency.rb +108 -0
  32. data/lib/backup/encryptor/base.rb +29 -0
  33. data/lib/backup/encryptor/gpg.rb +760 -0
  34. data/lib/backup/encryptor/open_ssl.rb +72 -0
  35. data/lib/backup/errors.rb +124 -0
  36. data/lib/backup/hooks.rb +68 -0
  37. data/lib/backup/logger.rb +152 -0
  38. data/lib/backup/model.rb +409 -0
  39. data/lib/backup/notifier/base.rb +81 -0
  40. data/lib/backup/notifier/campfire.rb +155 -0
  41. data/lib/backup/notifier/hipchat.rb +93 -0
  42. data/lib/backup/notifier/mail.rb +206 -0
  43. data/lib/backup/notifier/prowl.rb +65 -0
  44. data/lib/backup/notifier/pushover.rb +88 -0
  45. data/lib/backup/notifier/twitter.rb +70 -0
  46. data/lib/backup/package.rb +47 -0
  47. data/lib/backup/packager.rb +100 -0
  48. data/lib/backup/pipeline.rb +110 -0
  49. data/lib/backup/splitter.rb +75 -0
  50. data/lib/backup/storage/base.rb +99 -0
  51. data/lib/backup/storage/cloudfiles.rb +87 -0
  52. data/lib/backup/storage/cycler.rb +117 -0
  53. data/lib/backup/storage/dropbox.rb +178 -0
  54. data/lib/backup/storage/ftp.rb +119 -0
  55. data/lib/backup/storage/local.rb +82 -0
  56. data/lib/backup/storage/ninefold.rb +116 -0
  57. data/lib/backup/storage/rsync.rb +149 -0
  58. data/lib/backup/storage/s3.rb +94 -0
  59. data/lib/backup/storage/scp.rb +99 -0
  60. data/lib/backup/storage/sftp.rb +108 -0
  61. data/lib/backup/syncer/base.rb +46 -0
  62. data/lib/backup/syncer/cloud/base.rb +247 -0
  63. data/lib/backup/syncer/cloud/cloud_files.rb +78 -0
  64. data/lib/backup/syncer/cloud/s3.rb +68 -0
  65. data/lib/backup/syncer/rsync/base.rb +49 -0
  66. data/lib/backup/syncer/rsync/local.rb +55 -0
  67. data/lib/backup/syncer/rsync/pull.rb +36 -0
  68. data/lib/backup/syncer/rsync/push.rb +116 -0
  69. data/lib/backup/template.rb +46 -0
  70. data/lib/backup/version.rb +43 -0
  71. data/spec-live/.gitignore +6 -0
  72. data/spec-live/README +7 -0
  73. data/spec-live/backups/config.rb +83 -0
  74. data/spec-live/backups/config.yml.template +46 -0
  75. data/spec-live/backups/models.rb +184 -0
  76. data/spec-live/compressor/custom_spec.rb +30 -0
  77. data/spec-live/compressor/gzip_spec.rb +30 -0
  78. data/spec-live/encryptor/gpg_keys.rb +239 -0
  79. data/spec-live/encryptor/gpg_spec.rb +287 -0
  80. data/spec-live/notifier/mail_spec.rb +121 -0
  81. data/spec-live/spec_helper.rb +151 -0
  82. data/spec-live/storage/dropbox_spec.rb +151 -0
  83. data/spec-live/storage/local_spec.rb +83 -0
  84. data/spec-live/storage/scp_spec.rb +193 -0
  85. data/spec-live/syncer/cloud/s3_spec.rb +124 -0
  86. data/spec/archive_spec.rb +335 -0
  87. data/spec/cleaner_spec.rb +312 -0
  88. data/spec/cli/helpers_spec.rb +301 -0
  89. data/spec/cli/utility_spec.rb +411 -0
  90. data/spec/compressor/base_spec.rb +52 -0
  91. data/spec/compressor/bzip2_spec.rb +217 -0
  92. data/spec/compressor/custom_spec.rb +106 -0
  93. data/spec/compressor/gzip_spec.rb +217 -0
  94. data/spec/compressor/lzma_spec.rb +123 -0
  95. data/spec/compressor/pbzip2_spec.rb +165 -0
  96. data/spec/config_spec.rb +321 -0
  97. data/spec/configuration/helpers_spec.rb +247 -0
  98. data/spec/configuration/store_spec.rb +39 -0
  99. data/spec/configuration_spec.rb +62 -0
  100. data/spec/database/base_spec.rb +63 -0
  101. data/spec/database/mongodb_spec.rb +510 -0
  102. data/spec/database/mysql_spec.rb +411 -0
  103. data/spec/database/postgresql_spec.rb +353 -0
  104. data/spec/database/redis_spec.rb +334 -0
  105. data/spec/database/riak_spec.rb +176 -0
  106. data/spec/dependency_spec.rb +51 -0
  107. data/spec/encryptor/base_spec.rb +40 -0
  108. data/spec/encryptor/gpg_spec.rb +909 -0
  109. data/spec/encryptor/open_ssl_spec.rb +148 -0
  110. data/spec/errors_spec.rb +306 -0
  111. data/spec/hooks_spec.rb +35 -0
  112. data/spec/logger_spec.rb +367 -0
  113. data/spec/model_spec.rb +694 -0
  114. data/spec/notifier/base_spec.rb +104 -0
  115. data/spec/notifier/campfire_spec.rb +217 -0
  116. data/spec/notifier/hipchat_spec.rb +211 -0
  117. data/spec/notifier/mail_spec.rb +316 -0
  118. data/spec/notifier/prowl_spec.rb +138 -0
  119. data/spec/notifier/pushover_spec.rb +123 -0
  120. data/spec/notifier/twitter_spec.rb +153 -0
  121. data/spec/package_spec.rb +61 -0
  122. data/spec/packager_spec.rb +213 -0
  123. data/spec/pipeline_spec.rb +259 -0
  124. data/spec/spec_helper.rb +60 -0
  125. data/spec/splitter_spec.rb +120 -0
  126. data/spec/storage/base_spec.rb +166 -0
  127. data/spec/storage/cloudfiles_spec.rb +254 -0
  128. data/spec/storage/cycler_spec.rb +247 -0
  129. data/spec/storage/dropbox_spec.rb +480 -0
  130. data/spec/storage/ftp_spec.rb +271 -0
  131. data/spec/storage/local_spec.rb +259 -0
  132. data/spec/storage/ninefold_spec.rb +343 -0
  133. data/spec/storage/rsync_spec.rb +362 -0
  134. data/spec/storage/s3_spec.rb +245 -0
  135. data/spec/storage/scp_spec.rb +233 -0
  136. data/spec/storage/sftp_spec.rb +244 -0
  137. data/spec/syncer/base_spec.rb +109 -0
  138. data/spec/syncer/cloud/base_spec.rb +515 -0
  139. data/spec/syncer/cloud/cloud_files_spec.rb +181 -0
  140. data/spec/syncer/cloud/s3_spec.rb +174 -0
  141. data/spec/syncer/rsync/base_spec.rb +98 -0
  142. data/spec/syncer/rsync/local_spec.rb +149 -0
  143. data/spec/syncer/rsync/pull_spec.rb +98 -0
  144. data/spec/syncer/rsync/push_spec.rb +333 -0
  145. data/spec/version_spec.rb +21 -0
  146. data/templates/cli/utility/archive +25 -0
  147. data/templates/cli/utility/compressor/bzip2 +4 -0
  148. data/templates/cli/utility/compressor/custom +11 -0
  149. data/templates/cli/utility/compressor/gzip +4 -0
  150. data/templates/cli/utility/compressor/lzma +10 -0
  151. data/templates/cli/utility/compressor/pbzip2 +10 -0
  152. data/templates/cli/utility/config +32 -0
  153. data/templates/cli/utility/database/mongodb +18 -0
  154. data/templates/cli/utility/database/mysql +21 -0
  155. data/templates/cli/utility/database/postgresql +17 -0
  156. data/templates/cli/utility/database/redis +16 -0
  157. data/templates/cli/utility/database/riak +11 -0
  158. data/templates/cli/utility/encryptor/gpg +27 -0
  159. data/templates/cli/utility/encryptor/openssl +9 -0
  160. data/templates/cli/utility/model.erb +23 -0
  161. data/templates/cli/utility/notifier/campfire +12 -0
  162. data/templates/cli/utility/notifier/hipchat +15 -0
  163. data/templates/cli/utility/notifier/mail +22 -0
  164. data/templates/cli/utility/notifier/prowl +11 -0
  165. data/templates/cli/utility/notifier/pushover +11 -0
  166. data/templates/cli/utility/notifier/twitter +13 -0
  167. data/templates/cli/utility/splitter +7 -0
  168. data/templates/cli/utility/storage/cloud_files +22 -0
  169. data/templates/cli/utility/storage/dropbox +20 -0
  170. data/templates/cli/utility/storage/ftp +12 -0
  171. data/templates/cli/utility/storage/local +7 -0
  172. data/templates/cli/utility/storage/ninefold +9 -0
  173. data/templates/cli/utility/storage/rsync +11 -0
  174. data/templates/cli/utility/storage/s3 +19 -0
  175. data/templates/cli/utility/storage/scp +11 -0
  176. data/templates/cli/utility/storage/sftp +11 -0
  177. data/templates/cli/utility/syncer/cloud_files +46 -0
  178. data/templates/cli/utility/syncer/rsync_local +12 -0
  179. data/templates/cli/utility/syncer/rsync_pull +17 -0
  180. data/templates/cli/utility/syncer/rsync_push +17 -0
  181. data/templates/cli/utility/syncer/s3 +43 -0
  182. data/templates/general/links +11 -0
  183. data/templates/general/version.erb +2 -0
  184. data/templates/notifier/mail/failure.erb +9 -0
  185. data/templates/notifier/mail/success.erb +7 -0
  186. data/templates/notifier/mail/warning.erb +9 -0
  187. data/templates/storage/dropbox/authorization_url.erb +6 -0
  188. data/templates/storage/dropbox/authorized.erb +4 -0
  189. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  190. metadata +277 -0
data/backup.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('lib/backup/version')
4
+
5
+ Gem::Specification.new do |gem|
6
+
7
+ ##
8
+ # General configuration / information
9
+ gem.name = 'backup-agoddard'
10
+ gem.version = Backup::Version.current
11
+ gem.platform = Gem::Platform::RUBY
12
+ gem.authors = 'Michael van Rooijen; Anthony Goddard; Dane O\'Connor'
13
+ gem.email = 'meskyanichi@gmail.com; agoddard@eol.org'
14
+ gem.homepage = 'http://github.com/agoddard/backup'
15
+ gem.summary = 'Backup is a RubyGem, written for UNIX-like operating systems, that allows you to easily perform backup operations on both your remote and local environments. It provides you with an elegant DSL in Ruby for modeling your backups. Backup has built-in support for various databases, storage protocols/services, syncers, compressors, encryptors and notifiers which you can mix and match. It was built with modularity, extensibility and simplicity in mind.'
16
+
17
+ ##
18
+ # Files and folder that need to be compiled in to the Ruby Gem
19
+ gem.files = %x[git ls-files].split("\n")
20
+ gem.test_files = %x[git ls-files -- {spec}/*].split("\n")
21
+ gem.require_path = 'lib'
22
+
23
+ ##
24
+ # The Backup CLI executable
25
+ gem.executables = ['backup']
26
+
27
+ ##
28
+ # Gem dependencies
29
+ gem.add_dependency 'thor', ['>= 0.15.4', '< 2']
30
+ gem.add_dependency 'open4', ['~> 1.3.0']
31
+
32
+ end
data/bin/backup ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ # Load the Backup core library
5
+ 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
data/lib/backup.rb ADDED
@@ -0,0 +1,133 @@
1
+ # encoding: utf-8
2
+
3
+ # Load Ruby Core Libraries
4
+ require 'rubygems'
5
+ require 'fileutils'
6
+ require 'tempfile'
7
+ require 'yaml'
8
+ require 'etc'
9
+
10
+ require 'open4'
11
+ require 'thor'
12
+
13
+ ##
14
+ # The Backup Ruby Gem
15
+ module Backup
16
+
17
+ ##
18
+ # Backup's internal paths
19
+ LIBRARY_PATH = File.join(File.dirname(__FILE__), 'backup')
20
+ CLI_PATH = File.join(LIBRARY_PATH, 'cli')
21
+ STORAGE_PATH = File.join(LIBRARY_PATH, 'storage')
22
+ DATABASE_PATH = File.join(LIBRARY_PATH, 'database')
23
+ COMPRESSOR_PATH = File.join(LIBRARY_PATH, 'compressor')
24
+ ENCRYPTOR_PATH = File.join(LIBRARY_PATH, 'encryptor')
25
+ NOTIFIER_PATH = File.join(LIBRARY_PATH, 'notifier')
26
+ SYNCER_PATH = File.join(LIBRARY_PATH, 'syncer')
27
+ TEMPLATE_PATH = File.expand_path('../../templates', __FILE__)
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
+ ##
37
+ # Autoload Backup storage files
38
+ module Storage
39
+ autoload :Base, File.join(STORAGE_PATH, 'base')
40
+ autoload :Cycler, File.join(STORAGE_PATH, 'cycler')
41
+ autoload :S3, File.join(STORAGE_PATH, 's3')
42
+ autoload :CloudFiles, File.join(STORAGE_PATH, 'cloudfiles')
43
+ autoload :Ninefold, File.join(STORAGE_PATH, 'ninefold')
44
+ autoload :Dropbox, File.join(STORAGE_PATH, 'dropbox')
45
+ autoload :FTP, File.join(STORAGE_PATH, 'ftp')
46
+ autoload :SFTP, File.join(STORAGE_PATH, 'sftp')
47
+ autoload :SCP, File.join(STORAGE_PATH, 'scp')
48
+ autoload :RSync, File.join(STORAGE_PATH, 'rsync')
49
+ autoload :Local, File.join(STORAGE_PATH, 'local')
50
+ end
51
+
52
+ ##
53
+ # Autoload Backup syncer files
54
+ module Syncer
55
+ autoload :Base, File.join(SYNCER_PATH, 'base')
56
+ module Cloud
57
+ autoload :Base, File.join(SYNCER_PATH, 'cloud', 'base')
58
+ autoload :CloudFiles, File.join(SYNCER_PATH, 'cloud', 'cloud_files')
59
+ autoload :S3, File.join(SYNCER_PATH, 'cloud', 's3')
60
+ end
61
+ module RSync
62
+ autoload :Base, File.join(SYNCER_PATH, 'rsync', 'base')
63
+ autoload :Local, File.join(SYNCER_PATH, 'rsync', 'local')
64
+ autoload :Push, File.join(SYNCER_PATH, 'rsync', 'push')
65
+ autoload :Pull, File.join(SYNCER_PATH, 'rsync', 'pull')
66
+ end
67
+ end
68
+
69
+ ##
70
+ # Autoload Backup database files
71
+ module Database
72
+ autoload :Base, File.join(DATABASE_PATH, 'base')
73
+ autoload :MySQL, File.join(DATABASE_PATH, 'mysql')
74
+ autoload :PostgreSQL, File.join(DATABASE_PATH, 'postgresql')
75
+ autoload :MongoDB, File.join(DATABASE_PATH, 'mongodb')
76
+ autoload :Redis, File.join(DATABASE_PATH, 'redis')
77
+ autoload :Riak, File.join(DATABASE_PATH, 'riak')
78
+ end
79
+
80
+ ##
81
+ # Autoload compressor files
82
+ module Compressor
83
+ autoload :Base, File.join(COMPRESSOR_PATH, 'base')
84
+ autoload :Gzip, File.join(COMPRESSOR_PATH, 'gzip')
85
+ autoload :Bzip2, File.join(COMPRESSOR_PATH, 'bzip2')
86
+ autoload :Custom, File.join(COMPRESSOR_PATH, 'custom')
87
+ autoload :Pbzip2, File.join(COMPRESSOR_PATH, 'pbzip2')
88
+ autoload :Lzma, File.join(COMPRESSOR_PATH, 'lzma')
89
+ end
90
+
91
+ ##
92
+ # Autoload encryptor files
93
+ module Encryptor
94
+ autoload :Base, File.join(ENCRYPTOR_PATH, 'base')
95
+ autoload :OpenSSL, File.join(ENCRYPTOR_PATH, 'open_ssl')
96
+ autoload :GPG, File.join(ENCRYPTOR_PATH, 'gpg')
97
+ end
98
+
99
+ ##
100
+ # Autoload notification files
101
+ module Notifier
102
+ autoload :Base, File.join(NOTIFIER_PATH, 'base')
103
+ autoload :Binder, File.join(NOTIFIER_PATH, 'binder')
104
+ autoload :Mail, File.join(NOTIFIER_PATH, 'mail')
105
+ autoload :Twitter, File.join(NOTIFIER_PATH, 'twitter')
106
+ autoload :Campfire, File.join(NOTIFIER_PATH, 'campfire')
107
+ autoload :Prowl, File.join(NOTIFIER_PATH, 'prowl')
108
+ autoload :Hipchat, File.join(NOTIFIER_PATH, 'hipchat')
109
+ autoload :Pushover, File.join(NOTIFIER_PATH, 'pushover')
110
+ end
111
+
112
+ ##
113
+ # Require Backup base files
114
+ %w{
115
+ archive
116
+ binder
117
+ cleaner
118
+ config
119
+ configuration
120
+ dependency
121
+ errors
122
+ hooks
123
+ logger
124
+ model
125
+ package
126
+ packager
127
+ pipeline
128
+ splitter
129
+ template
130
+ version
131
+ }.each {|lib| require File.join(LIBRARY_PATH, lib) }
132
+
133
+ end
@@ -0,0 +1,117 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ class Archive
5
+ include Backup::CLI::Helpers
6
+
7
+ ##
8
+ # Stores the name of the archive
9
+ attr_accessor :name
10
+
11
+ ##
12
+ # Stores an array of different paths/files to store
13
+ attr_accessor :paths
14
+
15
+ ##
16
+ # Stores an array of different paths/files to exclude
17
+ attr_accessor :excludes
18
+
19
+ ##
20
+ # String of additional arguments for the `tar` command
21
+ attr_accessor :tar_args
22
+
23
+ ##
24
+ # Takes the name of the archive and the configuration block
25
+ def initialize(model, name, &block)
26
+ @model = model
27
+ @name = name.to_s
28
+ @paths = Array.new
29
+ @excludes = Array.new
30
+ @tar_args = ''
31
+
32
+ instance_eval(&block) if block_given?
33
+ end
34
+
35
+ ##
36
+ # Adds new paths to the @paths instance variable array
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
48
+ end
49
+
50
+ ##
51
+ # Adds new paths to the @excludes instance variable array
52
+ def exclude(path)
53
+ @excludes << File.expand_path(path)
54
+ end
55
+
56
+ ##
57
+ # Adds the given String of +options+ to the `tar` command.
58
+ # e.g. '-h --xattrs'
59
+ def tar_options(options)
60
+ @tar_args = options
61
+ end
62
+
63
+ ##
64
+ # Archives all the provided paths in to a single .tar file
65
+ # and places that .tar file in the folder which later will be packaged
66
+ # If the model is configured with a Compressor, the tar command output
67
+ # will be piped through the Compressor command and the file extension
68
+ # will be adjusted to indicate the type of compression used.
69
+ def perform!
70
+ Logger.message "#{ self.class } has started archiving:\n" +
71
+ paths.map {|path| " #{path}" }.join("\n")
72
+
73
+ archive_path = File.join(Config.tmp_path, @model.trigger, 'archives')
74
+ FileUtils.mkdir_p(archive_path)
75
+
76
+ archive_ext = 'tar'
77
+ pipeline = Pipeline.new
78
+
79
+ pipeline << "#{ utility(:tar) } #{ tar_args } -cPf - " +
80
+ "#{ paths_to_exclude } #{ paths_to_package }"
81
+
82
+ if @model.compressor
83
+ @model.compressor.compress_with do |command, ext|
84
+ pipeline << command
85
+ archive_ext << ext
86
+ end
87
+ end
88
+
89
+ pipeline << "cat > '#{ File.join(archive_path, "#{name}.#{archive_ext}") }'"
90
+ pipeline.run
91
+ if pipeline.success?
92
+ Logger.message "#{ self.class } Complete!"
93
+ else
94
+ raise Errors::Archive::PipelineError,
95
+ "Failed to Create Backup Archive\n" +
96
+ pipeline.error_messages
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ ##
103
+ # Returns a "tar-ready" string of all the specified paths combined
104
+ def paths_to_package
105
+ paths.map {|path| "'#{path}'" }.join(' ')
106
+ end
107
+
108
+ ##
109
+ # Returns a "tar-ready" string of all the specified excludes combined
110
+ def paths_to_exclude
111
+ if excludes.any?
112
+ excludes.map {|path| "--exclude='#{path}'" }.join(' ')
113
+ end
114
+ end
115
+
116
+ end
117
+ end
@@ -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,121 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ module Cleaner
5
+ class << self
6
+
7
+ ##
8
+ # Logs warnings if any temporary files still exist
9
+ # from the last time this model/trigger was run,
10
+ # then removes the files.
11
+ def prepare(model)
12
+ @model = model
13
+
14
+ messages = []
15
+ if packaging_folder_dirty?
16
+ messages << <<-EOS
17
+ The temporary backup folder still contains files!
18
+ '#{ File.join(Config.tmp_path, @model.trigger) }'
19
+ These files will now be removed.
20
+ EOS
21
+ FileUtils.rm_rf(File.join(Config.tmp_path, @model.trigger))
22
+ end
23
+
24
+ package_files = tmp_path_package_files
25
+ unless package_files.empty?
26
+ # the chances that tmp_path would be dirty
27
+ # AND package files exist are practically nil
28
+ messages << ('-' * 74) unless messages.empty?
29
+
30
+ messages << <<-EOS
31
+ The temporary backup folder '#{ Config.tmp_path }'
32
+ appears to contain the package files from the previous backup!
33
+ #{ package_files.join("\n") }
34
+ These files will now be removed.
35
+ EOS
36
+ package_files.each {|file| FileUtils.rm_f(file) }
37
+ end
38
+
39
+ unless messages.empty?
40
+ Logger.warn Errors::CleanerError.new(<<-EOS)
41
+ Cleanup Warning
42
+ #{ messages.join("\n") }
43
+ Please check the log for messages and/or your notifications
44
+ concerning this backup: '#{ @model.label } (#{ @model.trigger })'
45
+ The temporary files which had to be removed should not have existed.
46
+ EOS
47
+ end
48
+ end
49
+
50
+ ##
51
+ # Remove the temporary folder used during packaging
52
+ def remove_packaging(model)
53
+ Logger.message "Cleaning up the temporary files..."
54
+ FileUtils.rm_rf(File.join(Config.tmp_path, model.trigger))
55
+ end
56
+
57
+ ##
58
+ # Remove the final package files from tmp_path
59
+ # Note: 'force' is used, since a Local Storage may *move* these files.
60
+ def remove_package(package)
61
+ Logger.message "Cleaning up the package files..."
62
+ package.filenames.each do |file|
63
+ FileUtils.rm_f(File.join(Config.tmp_path, file))
64
+ end
65
+ end
66
+
67
+ ##
68
+ # Logs warnings if any temporary files still exist
69
+ # when errors occur during the backup
70
+ def warnings(model)
71
+ @model = model
72
+
73
+ messages = []
74
+ if packaging_folder_dirty?
75
+ messages << <<-EOS
76
+ The temporary backup folder still contains files!
77
+ '#{ File.join(Config.tmp_path, @model.trigger) }'
78
+ This folder may contain completed Archives and/or Database backups.
79
+ EOS
80
+ end
81
+
82
+ package_files = tmp_path_package_files
83
+ unless package_files.empty?
84
+ # the chances that tmp_path would be dirty
85
+ # AND package files exist are practically nil
86
+ messages << ('-' * 74) unless messages.empty?
87
+
88
+ messages << <<-EOS
89
+ The temporary backup folder '#{ Config.tmp_path }'
90
+ appears to contain the backup files which were to be stored:
91
+ #{ package_files.join("\n") }
92
+ EOS
93
+ end
94
+
95
+ unless messages.empty?
96
+ Logger.warn Errors::CleanerError.new(<<-EOS)
97
+ Cleanup Warning
98
+ #{ messages.join("\n") }
99
+ Make sure you check these files before the next scheduled backup for
100
+ '#{ @model.label } (#{ @model.trigger })'
101
+ These files will be removed at that time!
102
+ EOS
103
+ end
104
+ end
105
+
106
+ private
107
+
108
+ def packaging_folder_dirty?
109
+ !Dir[File.join(Config.tmp_path, @model.trigger, '*')].empty?
110
+ end
111
+
112
+ def tmp_path_package_files
113
+ Dir[File.join(
114
+ Config.tmp_path,
115
+ "????.??.??.??.??.??.#{ @model.trigger }.tar{,[.-]*}"
116
+ )]
117
+ end
118
+
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,93 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ module CLI
5
+ module Helpers
6
+ UTILITY = {}
7
+
8
+ private
9
+
10
+ ##
11
+ # Runs a system command
12
+ #
13
+ # All messages generated by the command will be logged.
14
+ # Messages on STDERR will be logged as warnings.
15
+ #
16
+ # If the command fails to execute, or returns a non-zero exit status
17
+ # an Error will be raised.
18
+ #
19
+ # Returns STDOUT
20
+ def run(command)
21
+ name = command_name(command)
22
+ Logger.message "Running system utility '#{ name }'..."
23
+
24
+ begin
25
+ out, err = '', ''
26
+ ps = Open4.popen4(command) do |pid, stdin, stdout, stderr|
27
+ stdin.close
28
+ out, err = stdout.read.strip, stderr.read.strip
29
+ end
30
+ rescue Exception => e
31
+ raise Errors::CLI::SystemCallError.wrap(e, <<-EOS)
32
+ Failed to execute system command on #{ RUBY_PLATFORM }
33
+ Command was: #{ command }
34
+ EOS
35
+ end
36
+
37
+ if ps.success?
38
+ unless out.empty?
39
+ Logger.message(
40
+ out.lines.map {|line| "#{ name }:STDOUT: #{ line }" }.join
41
+ )
42
+ end
43
+
44
+ unless err.empty?
45
+ Logger.warn(
46
+ err.lines.map {|line| "#{ name }:STDERR: #{ line }" }.join
47
+ )
48
+ end
49
+
50
+ return out
51
+ else
52
+ raise Errors::CLI::SystemCallError, <<-EOS
53
+ '#{ name }' Failed on #{ RUBY_PLATFORM }
54
+ The following information should help to determine the problem:
55
+ Command was: #{ command }
56
+ Exit Status: #{ ps.exitstatus }
57
+ STDOUT Messages: #{ out.empty? ? 'None' : "\n#{ out }" }
58
+ STDERR Messages: #{ err.empty? ? 'None' : "\n#{ err }" }
59
+ EOS
60
+ end
61
+ end
62
+
63
+
64
+ ##
65
+ # Returns the full path to the specified utility.
66
+ # Raises an error if utility can not be found in the system's $PATH
67
+ def utility(name)
68
+ name = name.to_s.strip
69
+ raise Errors::CLI::UtilityNotFoundError,
70
+ 'Utility Name Empty' if name.empty?
71
+
72
+ path = UTILITY[name] || %x[which #{ name } 2>/dev/null].chomp
73
+ if path.empty?
74
+ raise Errors::CLI::UtilityNotFoundError, <<-EOS
75
+ Could not locate '#{ name }'.
76
+ Make sure the specified utility is installed
77
+ and available in your system's $PATH.
78
+ EOS
79
+ end
80
+ UTILITY[name] = path
81
+ end
82
+
83
+ ##
84
+ # Returns the name of the command name from the given command line
85
+ def command_name(command)
86
+ i = command =~ /\s/
87
+ command = command.slice(0, i) if i
88
+ command.split('/')[-1]
89
+ end
90
+
91
+ end
92
+ end
93
+ end