backup 3.0.19 → 3.0.20

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 (188) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +9 -8
  3. data/Gemfile.lock +19 -1
  4. data/Guardfile +13 -9
  5. data/README.md +93 -31
  6. data/backup.gemspec +3 -3
  7. data/bin/backup +6 -283
  8. data/lib/backup.rb +101 -72
  9. data/lib/backup/archive.rb +21 -9
  10. data/lib/backup/binder.rb +22 -0
  11. data/lib/backup/cleaner.rb +36 -0
  12. data/lib/backup/cli/helpers.rb +103 -0
  13. data/lib/backup/cli/utility.rb +308 -0
  14. data/lib/backup/compressor/base.rb +2 -2
  15. data/lib/backup/compressor/pbzip2.rb +76 -0
  16. data/lib/backup/configuration/compressor/pbzip2.rb +28 -0
  17. data/lib/backup/configuration/database/riak.rb +25 -0
  18. data/lib/backup/configuration/encryptor/open_ssl.rb +6 -0
  19. data/lib/backup/configuration/helpers.rb +5 -18
  20. data/lib/backup/configuration/notifier/base.rb +13 -0
  21. data/lib/backup/configuration/notifier/hipchat.rb +41 -0
  22. data/lib/backup/configuration/notifier/mail.rb +38 -0
  23. data/lib/backup/configuration/notifier/prowl.rb +23 -0
  24. data/lib/backup/configuration/storage/cloudfiles.rb +4 -0
  25. data/lib/backup/configuration/storage/dropbox.rb +8 -4
  26. data/lib/backup/database/base.rb +10 -2
  27. data/lib/backup/database/mongodb.rb +16 -19
  28. data/lib/backup/database/mysql.rb +2 -2
  29. data/lib/backup/database/postgresql.rb +2 -2
  30. data/lib/backup/database/redis.rb +15 -7
  31. data/lib/backup/database/riak.rb +45 -0
  32. data/lib/backup/dependency.rb +21 -7
  33. data/lib/backup/encryptor/base.rb +1 -1
  34. data/lib/backup/encryptor/open_ssl.rb +20 -5
  35. data/lib/backup/errors.rb +124 -0
  36. data/lib/backup/finder.rb +11 -3
  37. data/lib/backup/logger.rb +121 -82
  38. data/lib/backup/model.rb +103 -44
  39. data/lib/backup/notifier/base.rb +50 -0
  40. data/lib/backup/notifier/campfire.rb +32 -52
  41. data/lib/backup/notifier/hipchat.rb +99 -0
  42. data/lib/backup/notifier/mail.rb +100 -61
  43. data/lib/backup/notifier/presently.rb +31 -40
  44. data/lib/backup/notifier/prowl.rb +73 -0
  45. data/lib/backup/notifier/twitter.rb +29 -39
  46. data/lib/backup/packager.rb +25 -0
  47. data/lib/backup/splitter.rb +62 -0
  48. data/lib/backup/storage/base.rb +178 -18
  49. data/lib/backup/storage/cloudfiles.rb +34 -28
  50. data/lib/backup/storage/dropbox.rb +64 -67
  51. data/lib/backup/storage/ftp.rb +48 -40
  52. data/lib/backup/storage/local.rb +33 -28
  53. data/lib/backup/storage/ninefold.rb +40 -26
  54. data/lib/backup/storage/object.rb +8 -6
  55. data/lib/backup/storage/rsync.rb +61 -51
  56. data/lib/backup/storage/s3.rb +29 -27
  57. data/lib/backup/storage/scp.rb +56 -36
  58. data/lib/backup/storage/sftp.rb +49 -33
  59. data/lib/backup/syncer/base.rb +1 -1
  60. data/lib/backup/syncer/rsync.rb +1 -1
  61. data/lib/backup/template.rb +46 -0
  62. data/lib/backup/version.rb +1 -1
  63. data/spec/archive_spec.rb +34 -9
  64. data/spec/backup_spec.rb +1 -1
  65. data/spec/cli/helpers_spec.rb +35 -0
  66. data/spec/cli/utility_spec.rb +38 -0
  67. data/spec/compressor/bzip2_spec.rb +1 -1
  68. data/spec/compressor/gzip_spec.rb +1 -1
  69. data/spec/compressor/lzma_spec.rb +1 -1
  70. data/spec/compressor/pbzip2_spec.rb +63 -0
  71. data/spec/configuration/base_spec.rb +1 -1
  72. data/spec/configuration/compressor/bzip2_spec.rb +1 -1
  73. data/spec/configuration/compressor/gzip_spec.rb +1 -1
  74. data/spec/configuration/compressor/lzma_spec.rb +1 -1
  75. data/spec/configuration/database/base_spec.rb +1 -1
  76. data/spec/configuration/database/mongodb_spec.rb +1 -1
  77. data/spec/configuration/database/mysql_spec.rb +1 -1
  78. data/spec/configuration/database/postgresql_spec.rb +1 -1
  79. data/spec/configuration/database/redis_spec.rb +1 -1
  80. data/spec/configuration/database/riak_spec.rb +31 -0
  81. data/spec/configuration/encryptor/gpg_spec.rb +1 -1
  82. data/spec/configuration/encryptor/open_ssl_spec.rb +4 -1
  83. data/spec/configuration/notifier/campfire_spec.rb +1 -1
  84. data/spec/configuration/notifier/hipchat_spec.rb +43 -0
  85. data/spec/configuration/notifier/mail_spec.rb +34 -22
  86. data/spec/configuration/notifier/presently_spec.rb +1 -1
  87. data/spec/configuration/notifier/prowl_spec.rb +28 -0
  88. data/spec/configuration/notifier/twitter_spec.rb +1 -1
  89. data/spec/configuration/storage/cloudfiles_spec.rb +19 -16
  90. data/spec/configuration/storage/dropbox_spec.rb +1 -1
  91. data/spec/configuration/storage/ftp_spec.rb +1 -1
  92. data/spec/configuration/storage/local_spec.rb +1 -1
  93. data/spec/configuration/storage/ninefold_spec.rb +1 -1
  94. data/spec/configuration/storage/rsync_spec.rb +1 -1
  95. data/spec/configuration/storage/s3_spec.rb +1 -1
  96. data/spec/configuration/storage/scp_spec.rb +1 -1
  97. data/spec/configuration/storage/sftp_spec.rb +1 -1
  98. data/spec/configuration/syncer/rsync_spec.rb +1 -1
  99. data/spec/configuration/syncer/s3_spec.rb +1 -1
  100. data/spec/database/base_spec.rb +10 -1
  101. data/spec/database/mongodb_spec.rb +34 -7
  102. data/spec/database/mysql_spec.rb +8 -7
  103. data/spec/database/postgresql_spec.rb +8 -7
  104. data/spec/database/redis_spec.rb +39 -9
  105. data/spec/database/riak_spec.rb +50 -0
  106. data/spec/encryptor/gpg_spec.rb +1 -1
  107. data/spec/encryptor/open_ssl_spec.rb +77 -20
  108. data/spec/errors_spec.rb +306 -0
  109. data/spec/finder_spec.rb +91 -0
  110. data/spec/logger_spec.rb +254 -33
  111. data/spec/model_spec.rb +120 -15
  112. data/spec/notifier/campfire_spec.rb +127 -52
  113. data/spec/notifier/hipchat_spec.rb +193 -0
  114. data/spec/notifier/mail_spec.rb +290 -74
  115. data/spec/notifier/presently_spec.rb +290 -73
  116. data/spec/notifier/prowl_spec.rb +149 -0
  117. data/spec/notifier/twitter_spec.rb +106 -41
  118. data/spec/spec_helper.rb +8 -2
  119. data/spec/splitter_spec.rb +71 -0
  120. data/spec/storage/base_spec.rb +280 -19
  121. data/spec/storage/cloudfiles_spec.rb +38 -22
  122. data/spec/storage/dropbox_spec.rb +17 -13
  123. data/spec/storage/ftp_spec.rb +145 -55
  124. data/spec/storage/local_spec.rb +6 -6
  125. data/spec/storage/ninefold_spec.rb +70 -29
  126. data/spec/storage/object_spec.rb +44 -44
  127. data/spec/storage/rsync_spec.rb +186 -63
  128. data/spec/storage/s3_spec.rb +23 -24
  129. data/spec/storage/scp_spec.rb +116 -41
  130. data/spec/storage/sftp_spec.rb +124 -46
  131. data/spec/syncer/rsync_spec.rb +3 -3
  132. data/spec/syncer/s3_spec.rb +1 -1
  133. data/spec/version_spec.rb +1 -1
  134. data/templates/cli/utility/archive +13 -0
  135. data/{lib/templates → templates/cli/utility}/compressor/bzip2 +1 -1
  136. data/{lib/templates → templates/cli/utility}/compressor/gzip +1 -1
  137. data/{lib/templates → templates/cli/utility}/compressor/lzma +0 -0
  138. data/templates/cli/utility/compressor/pbzip2 +7 -0
  139. data/templates/cli/utility/config +31 -0
  140. data/{lib/templates → templates/cli/utility}/database/mongodb +1 -1
  141. data/{lib/templates → templates/cli/utility}/database/mysql +1 -1
  142. data/{lib/templates → templates/cli/utility}/database/postgresql +1 -1
  143. data/{lib/templates → templates/cli/utility}/database/redis +1 -1
  144. data/templates/cli/utility/database/riak +8 -0
  145. data/{lib/templates → templates/cli/utility}/encryptor/gpg +1 -1
  146. data/templates/cli/utility/encryptor/openssl +9 -0
  147. data/templates/cli/utility/model.erb +23 -0
  148. data/{lib/templates → templates/cli/utility}/notifier/campfire +2 -1
  149. data/templates/cli/utility/notifier/hipchat +15 -0
  150. data/{lib/templates → templates/cli/utility}/notifier/mail +6 -1
  151. data/{lib/templates → templates/cli/utility}/notifier/presently +1 -0
  152. data/templates/cli/utility/notifier/prowl +11 -0
  153. data/{lib/templates → templates/cli/utility}/notifier/twitter +2 -1
  154. data/templates/cli/utility/splitter +7 -0
  155. data/templates/cli/utility/storage/cloudfiles +12 -0
  156. data/{lib/templates → templates/cli/utility}/storage/dropbox +1 -1
  157. data/{lib/templates → templates/cli/utility}/storage/ftp +0 -0
  158. data/templates/cli/utility/storage/local +7 -0
  159. data/{lib/templates → templates/cli/utility}/storage/ninefold +1 -1
  160. data/templates/cli/utility/storage/rsync +11 -0
  161. data/{lib/templates → templates/cli/utility}/storage/s3 +0 -2
  162. data/templates/cli/utility/storage/scp +11 -0
  163. data/templates/cli/utility/storage/sftp +11 -0
  164. data/{lib/templates → templates/cli/utility}/syncer/rsync +1 -1
  165. data/{lib/templates → templates/cli/utility}/syncer/s3 +1 -1
  166. data/templates/general/links +11 -0
  167. data/templates/general/version.erb +2 -0
  168. data/templates/notifier/mail/failure.erb +9 -0
  169. data/templates/notifier/mail/success.erb +7 -0
  170. data/templates/notifier/mail/warning.erb +9 -0
  171. data/templates/storage/dropbox/authorization_url.erb +6 -0
  172. data/templates/storage/dropbox/authorized.erb +4 -0
  173. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  174. metadata +81 -45
  175. data/lib/backup/cli.rb +0 -110
  176. data/lib/backup/exception/command_failed.rb +0 -8
  177. data/lib/backup/exception/command_not_found.rb +0 -8
  178. data/lib/backup/notifier/binder.rb +0 -32
  179. data/lib/backup/notifier/templates/notify_failure.erb +0 -33
  180. data/lib/backup/notifier/templates/notify_success.erb +0 -16
  181. data/lib/templates/archive +0 -7
  182. data/lib/templates/encryptor/openssl +0 -8
  183. data/lib/templates/readme +0 -15
  184. data/lib/templates/storage/cloudfiles +0 -11
  185. data/lib/templates/storage/local +0 -7
  186. data/lib/templates/storage/rsync +0 -11
  187. data/lib/templates/storage/scp +0 -11
  188. data/lib/templates/storage/sftp +0 -11
@@ -38,7 +38,6 @@ module Backup
38
38
  @additional_options ||= Array.new
39
39
 
40
40
  instance_eval(&block)
41
- prepare!
42
41
  end
43
42
 
44
43
  ##
@@ -95,7 +94,8 @@ module Backup
95
94
  # Performs the mysqldump command and outputs the
96
95
  # data to the specified path based on the 'trigger'
97
96
  def perform!
98
- log!
97
+ super
98
+
99
99
  run("#{mysqldump} > '#{File.join(dump_path, name)}.sql'")
100
100
  end
101
101
 
@@ -40,7 +40,6 @@ module Backup
40
40
  @additional_options ||= Array.new
41
41
 
42
42
  instance_eval(&block)
43
- prepare!
44
43
  ENV['PGPASSWORD'] = password
45
44
  end
46
45
 
@@ -110,7 +109,8 @@ module Backup
110
109
  # data to the specified path based on the 'trigger'
111
110
  # and resets the 'PGPASSWORD' environment variable to nil
112
111
  def perform!
113
- log!
112
+ super
113
+
114
114
  run("#{pgdump} > '#{File.join(dump_path, name)}.sql'")
115
115
  ENV['PGPASSWORD'] = nil
116
116
  end
@@ -34,7 +34,6 @@ module Backup
34
34
  @additional_options ||= Array.new
35
35
 
36
36
  instance_eval(&block)
37
- prepare!
38
37
  end
39
38
 
40
39
  ##
@@ -73,7 +72,7 @@ module Backup
73
72
  # the Redis server to persist the current state to the dump file
74
73
  # before copying the dump to get the most recent updates in to the backup
75
74
  def perform!
76
- log!
75
+ super
77
76
 
78
77
  invoke_save! if invoke_save
79
78
  copy!
@@ -83,10 +82,17 @@ module Backup
83
82
  # Tells Redis to persist the current state of the
84
83
  # in-memory database to the persisted dump file
85
84
  def invoke_save!
86
- response = run("#{ utility('redis-cli') } #{ credential_options } #{ connectivity_options } #{ additional_options } SAVE")
85
+ response = run("#{ utility('redis-cli') } #{ credential_options } " +
86
+ "#{ connectivity_options } #{ additional_options } SAVE")
87
87
  unless response =~ /OK/
88
- Logger.error "Could not invoke the Redis SAVE command. The #{ database } file might not contain the most recent data."
89
- Logger.error "Please check if the server is running, the credentials (if any) are correct, and the host/port/socket are correct."
88
+ raise Errors::Database::Redis::CommandError, <<-EOS
89
+ Could not invoke the Redis SAVE command.
90
+ The #{ database } file might not contain the most recent data.
91
+ Please check if the server is running, the credentials (if any) are correct,
92
+ and the host/port/socket are correct.
93
+
94
+ Redis CLI response: #{ response }
95
+ EOS
90
96
  end
91
97
  end
92
98
 
@@ -94,8 +100,10 @@ module Backup
94
100
  # Performs the copy command to copy over the Redis dump file to the Backup archive
95
101
  def copy!
96
102
  unless File.exist?(File.join(path, database))
97
- Logger.error "Redis database dump not found in '#{ File.join(path, database) }'"
98
- exit
103
+ raise Errors::Database::Redis::NotFoundError, <<-EOS
104
+ Redis database dump not found
105
+ File path was #{ File.join(path, database) }
106
+ EOS
99
107
  end
100
108
 
101
109
  # Temporarily remove a custom `utility_path` setting so that the system
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ module Database
5
+ class Riak < Base
6
+
7
+ ##
8
+ # Name is the name of the backup
9
+ attr_accessor :name
10
+
11
+ ##
12
+ # Node is the node from which to perform the backup.
13
+ attr_accessor :node
14
+
15
+ ##
16
+ # Cookie is the Erlang cookie/shared secret used to connect to the node.
17
+ attr_accessor :cookie
18
+
19
+ ##
20
+ # Creates a new instance of the Riak adapter object
21
+ def initialize(&block)
22
+ load_defaults!
23
+
24
+ instance_eval(&block)
25
+ end
26
+
27
+ ##
28
+ # Builds the full riak-admin string based on all attributes
29
+ def riakadmin
30
+ "riak-admin backup #{node} #{cookie}"
31
+ end
32
+
33
+ ##
34
+ # Performs the riak-admin command and outputs the
35
+ # data to the specified path based on the 'trigger'
36
+ def perform!
37
+ super
38
+ # have to make riak the owner since the riak-admin tool runs as the riak user in a default setup.
39
+ run("chown -R riak.riak #{dump_path}")
40
+ run("#{riakadmin} #{File.join(dump_path, name)} node")
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -48,7 +48,7 @@ module Backup
48
48
 
49
49
  'mail' => {
50
50
  :require => 'mail',
51
- :version => '~> 2.3.0',
51
+ :version => '>= 2.2.15',
52
52
  :for => 'Sending Emails (Mail Notifier)'
53
53
  },
54
54
 
@@ -69,6 +69,18 @@ module Backup
69
69
  :version => '~> 1.5.1',
70
70
  :for => 'Parsing JSON for HTTParty'
71
71
  },
72
+
73
+ 'prowler' => {
74
+ :require => 'prowler',
75
+ :version => '>= 1.3.1',
76
+ :for => 'Sending iOS push notifications (Prowl Notifier)'
77
+ },
78
+
79
+ 'hipchat' => {
80
+ :require => 'hipchat',
81
+ :version => '~> 0.4.1',
82
+ :for => 'Sending notifications to Hipchat'
83
+ }
72
84
  }
73
85
  end
74
86
 
@@ -81,12 +93,14 @@ module Backup
81
93
  gem(name, all[name][:version])
82
94
  require(all[name][:require])
83
95
  rescue LoadError
84
- Backup::Logger.error("Dependency missing.")
85
- puts "\nDependency required for:"
86
- puts "\n\s\s#{all[name][:for]}"
87
- puts "\nTo install the gem, issue the following command:"
88
- puts "\n\s\sgem install #{name} -v '#{all[name][:version]}'"
89
- puts "\nPlease try again after installing the missing dependency."
96
+ Logger.error Errors::Dependency::LoadError.new(<<-EOS)
97
+ Dependency missing
98
+ Dependency required for:
99
+ #{all[name][:for]}
100
+ To install the gem, issue the following command:
101
+ > gem install #{name} -v '#{all[name][:version]}'
102
+ Please try again after installing the missing dependency.
103
+ EOS
90
104
  exit
91
105
  end
92
106
  end
@@ -3,7 +3,7 @@
3
3
  module Backup
4
4
  module Encryptor
5
5
  class Base
6
- include Backup::CLI
6
+ include Backup::CLI::Helpers
7
7
  include Backup::Configuration::Helpers
8
8
 
9
9
  ##
@@ -9,6 +9,10 @@ module Backup
9
9
  # password will be required to decrypt the backup later on.
10
10
  attr_accessor :password
11
11
 
12
+ ##
13
+ # The password file to use to encrypt the backup.
14
+ attr_accessor :password_file
15
+
12
16
  ##
13
17
  # Determines whether the 'base64' should be used or not
14
18
  attr_writer :base64
@@ -23,8 +27,9 @@ module Backup
23
27
  def initialize(&block)
24
28
  load_defaults!
25
29
 
26
- @base64 ||= false
27
- @salt ||= false
30
+ @base64 ||= false
31
+ @salt ||= false
32
+ @password_file ||= nil
28
33
 
29
34
  instance_eval(&block) if block_given?
30
35
  end
@@ -33,7 +38,7 @@ module Backup
33
38
  # Performs the encryption of the backup file
34
39
  def perform!
35
40
  log!
36
- run("#{ utility(:openssl) } #{ options } -in '#{ Backup::Model.file }' -out '#{ Backup::Model.file }.enc' -k '#{ password }'")
41
+ run("#{ utility(:openssl) } #{ options } -in '#{ Backup::Model.file }' -out '#{ Backup::Model.file }.enc'")
37
42
  rm(Backup::Model.file)
38
43
  Backup::Model.extension += '.enc'
39
44
  end
@@ -44,11 +49,11 @@ module Backup
44
49
  # Backup::Encryptor::OpenSSL uses the 256bit AES encryption cipher.
45
50
  # 256bit AES is what the US Government uses to encrypt information at the "Top Secret" level.
46
51
  def options
47
- (['aes-256-cbc'] + base64 + salt).join("\s")
52
+ (['aes-256-cbc'] + base64 + salt + pass).join("\s")
48
53
  end
49
54
 
50
55
  ##
51
- # Returns '-a' if @base64 is set to 'true'.
56
+ # Returns '-base64' if @base64 is set to 'true'.
52
57
  # This option will make the encrypted output base64 encoded,
53
58
  # this makes the encrypted file readable using text editors
54
59
  def base64
@@ -62,6 +67,16 @@ module Backup
62
67
  return ['-salt'] if @salt; []
63
68
  end
64
69
 
70
+ ##
71
+ # Returns '-pass file:<password file>' when @password_file has been set.
72
+ def pass
73
+ if @password_file
74
+ ["-pass file:#{@password_file}"]
75
+ else
76
+ ["-k '#{@password}'"]
77
+ end
78
+ end
79
+
65
80
  end
66
81
  end
67
82
  end
@@ -0,0 +1,124 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ ##
5
+ # - automatically defines module namespaces referenced under Backup::Errors
6
+ # - any constant name referenced that ends with 'Error' will be created
7
+ # as a subclass of Backup::Errors::Error
8
+ # e.g.
9
+ # err = Backup::Errors::Foo::Bar::FooError.new('error message')
10
+ # err.message => "Foo::Bar::FooError: error message"
11
+ #
12
+ module ErrorsHelper
13
+ def const_missing(const)
14
+ if const.to_s.end_with?('Error')
15
+ module_eval("class #{const} < Backup::Errors::Error; end")
16
+ else
17
+ module_eval("module #{const}; extend Backup::ErrorsHelper; end")
18
+ end
19
+ const_get(const)
20
+ end
21
+ end
22
+
23
+ ##
24
+ # provides cascading errors with formatted messages
25
+ # see the specs for details
26
+ #
27
+ # e.g.
28
+ # module Backup
29
+ # begin
30
+ # begin
31
+ # begin
32
+ # raise Errors::ZoneAError, 'an error occurred in Zone A'
33
+ # rescue => err
34
+ # raise Errors::ZoneBError.wrap(err, <<-EOS)
35
+ # an error occurred in Zone B
36
+ #
37
+ # the following error should give a reason
38
+ # EOS
39
+ # end
40
+ # rescue => err
41
+ # raise Errors::ZoneCError.wrap(err)
42
+ # end
43
+ # rescue => err
44
+ # puts Errors::ZoneDError.wrap(err, 'an error occurred in Zone D')
45
+ # end
46
+ # end
47
+ #
48
+ # Outputs:
49
+ # ZoneDError: an error occurred in Zone D
50
+ # Reason: ZoneCError
51
+ # ZoneBError: an error occurred in Zone B
52
+ #
53
+ # the following error should give a reason
54
+ # Reason: ZoneAError
55
+ # an error occurred in Zone A
56
+ #
57
+ module Errors
58
+ extend ErrorsHelper
59
+
60
+ class Error < StandardError
61
+
62
+ def self.wrap(orig_err, msg = nil)
63
+ new(msg, orig_err)
64
+ end
65
+
66
+ def initialize(msg = nil, orig_err = nil)
67
+ super(msg)
68
+ set_backtrace(orig_err.backtrace) if @orig_err = orig_err
69
+ end
70
+
71
+ def to_s
72
+ return @to_s if @to_s
73
+ orig_to_s = super()
74
+
75
+ if orig_to_s == self.class.to_s
76
+ msg = orig_err_msg ?
77
+ "#{orig_err_class}: #{orig_err_msg}" : orig_err_class
78
+ else
79
+ msg = format_msg(orig_to_s)
80
+ msg << "\n Reason: #{orig_err_class}" + (orig_err_msg ?
81
+ "\n #{orig_err_msg}" : ' (no message given)') if @orig_err
82
+ end
83
+
84
+ @to_s = msg ? msg_prefix + msg : class_name
85
+ end
86
+
87
+ private
88
+
89
+ def msg_prefix
90
+ @msg_prefix ||= class_name + ': '
91
+ end
92
+
93
+ def orig_msg
94
+ @orig_msg ||= to_s.sub(msg_prefix, '')
95
+ end
96
+
97
+ def class_name
98
+ @class_name ||= self.class.to_s.sub('Backup::Errors::', '')
99
+ end
100
+
101
+ def orig_err_class
102
+ return unless @orig_err
103
+
104
+ @orig_err_class ||= @orig_err.is_a?(Errors::Error) ?
105
+ @orig_err.send(:class_name) : @orig_err.class.to_s
106
+ end
107
+
108
+ def orig_err_msg
109
+ return unless @orig_err
110
+ return @orig_err_msg unless @orig_err_msg.nil?
111
+
112
+ msg = @orig_err.is_a?(Errors::Error) ?
113
+ @orig_err.send(:orig_msg) : @orig_err.to_s
114
+ @orig_err_msg = (msg == orig_err_class) ?
115
+ false : format_msg(msg)
116
+ end
117
+
118
+ def format_msg(msg)
119
+ msg.gsub(/^ */, ' ').strip
120
+ end
121
+ end
122
+
123
+ end
124
+ end
data/lib/backup/finder.rb CHANGED
@@ -32,7 +32,8 @@ module Backup
32
32
  end
33
33
  end
34
34
 
35
- puts "Could not find trigger '#{trigger}' in '#{config}'."; exit
35
+ raise Errors::Finder::MissingTriggerError,
36
+ "Could not find trigger '#{trigger}' in '#{config}'."
36
37
  end
37
38
 
38
39
  ##
@@ -68,12 +69,19 @@ module Backup
68
69
  # Tries to find and load the configuration file
69
70
  def load_config!
70
71
  unless File.exist?(config)
71
- puts "Could not find a configuration file in '#{config}'."; exit
72
+ raise Errors::Finder::MissingConfigError,
73
+ "Could not find configuration file: '#{config}'."
72
74
  end
73
75
 
76
+ ##
77
+ # Reset the Backup::Model.all to an empty array since this will be
78
+ # re-filled during the next Backup::Finder.new(arg1, arg2).find
79
+ # or Backup::Finder.new(arg).matching call
80
+ Backup::Model.all = Array.new
81
+
74
82
  ##
75
83
  # Loads the backup configuration file
76
- instance_eval(File.read(config))
84
+ Backup.module_eval(File.read(config), config, 1)
77
85
  end
78
86
  end
79
87
  end
data/lib/backup/logger.rb CHANGED
@@ -1,102 +1,141 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Backup
4
- class Logger
4
+ module Logger
5
+ class << self
5
6
 
6
- ##
7
- # Outputs a messages to the console and writes it to the backup.log
8
- def self.message(string)
9
- puts loggify(:message, string, :green) unless quiet?
10
- to_file loggify(:message, string)
11
- end
7
+ ##
8
+ # Outputs a messages to the console and writes it to the backup.log
9
+ def message(string)
10
+ to_console loggify(string, :message, :green)
11
+ to_file loggify(string, :message)
12
+ end
12
13
 
13
- ##
14
- # Outputs an error to the console and writes it to the backup.log
15
- def self.error(string)
16
- puts loggify(:error, string, :red) unless quiet?
17
- to_file loggify(:error, string)
18
- end
14
+ ##
15
+ # Outputs an error to the console and writes it to the backup.log
16
+ # Called when an Exception has caused the backup process to abort.
17
+ def error(string)
18
+ to_console loggify(string, :error, :red), true
19
+ to_file loggify(string, :error)
20
+ end
19
21
 
20
- ##
21
- # Outputs a notice to the console and writes it to the backup.log
22
- def self.warn(string)
23
- puts loggify(:warning, string, :yellow) unless quiet?
24
- to_file loggify(:warning, string)
25
- end
22
+ ##
23
+ # Outputs a notice to the console and writes it to the backup.log
24
+ # Sets #has_warnings? true so :on_warning notifications will be sent
25
+ def warn(string)
26
+ @has_warnings = true
27
+ to_console loggify(string, :warning, :yellow), true
28
+ to_file loggify(string, :warning)
29
+ end
26
30
 
27
- ##
28
- # Outputs the data as if it were a regular 'puts' command,
29
- # but also logs it to the backup.log
30
- def self.normal(string)
31
- puts string unless quiet?
32
- to_file string
33
- end
31
+ # Outputs the data as if it were a regular 'puts' command,
32
+ # but also logs it to the backup.log
33
+ def normal(string)
34
+ to_console loggify(string)
35
+ to_file loggify(string)
36
+ end
34
37
 
35
- ##
36
- # Silently logs data to the log file
37
- def self.silent(string)
38
- to_file loggify(:silent, string)
39
- end
38
+ ##
39
+ # Silently logs data to the log file
40
+ def silent(string)
41
+ to_file loggify(string, :silent)
42
+ end
40
43
 
41
- ##
42
- # Returns the time in [YYYY/MM/DD HH:MM:SS] format
43
- def self.time
44
- Time.now.strftime("%Y/%m/%d %H:%M:%S")
45
- end
44
+ ##
45
+ # Returns an Array of all messages written to the log file for this session
46
+ def messages
47
+ @messages ||= []
48
+ end
46
49
 
47
- ##
48
- # Builds the string in a log format with the date/time, the type (colorized)
49
- # based on whether it's a message, notice or error, and the message itself.
50
- # ANSI color codes are only used in the console, and are not written to the log
51
- # since it doesn't do anything and just adds more unnecessary bloat to the log file
52
- def self.loggify(type, string, color = false)
53
- return "[#{time}][#{type}] #{string}" unless color
54
- "[#{time}][#{send(color, type)}] #{string}"
55
- end
50
+ ##
51
+ # Returns true if any warnings have been issued
52
+ def has_warnings?
53
+ @has_warnings ||= false
54
+ end
56
55
 
57
- ##
58
- # Writes (appends) a string to the backup.log file
59
- def self.to_file(string)
60
- File.open(File.join(LOG_PATH, 'backup.log'), 'a') do |file|
61
- file.write("#{string}\n")
56
+ def clear!
57
+ messages.clear
58
+ @has_warnings = false
62
59
  end
63
- end
64
60
 
65
- ##
66
- # Invokes the #colorize method with the provided string
67
- # and the color code "32" (for green)
68
- def self.green(string)
69
- colorize(string, 32)
70
- end
61
+ private
71
62
 
72
- ##
73
- # Invokes the #colorize method with the provided string
74
- # and the color code "33" (for yellow)
75
- def self.yellow(string)
76
- colorize(string, 33)
77
- end
63
+ ##
64
+ # Returns the time in [YYYY/MM/DD HH:MM:SS] format
65
+ def time
66
+ Time.now.strftime("%Y/%m/%d %H:%M:%S")
67
+ end
78
68
 
79
- ##
80
- # Invokes the #colorize method the with provided string
81
- # and the color code "31" (for red)
82
- def self.red(string)
83
- colorize(string, 31)
84
- end
69
+ ##
70
+ # Receives a String, or an Object that responds to #to_s (e.g. an
71
+ # Exception), from one of the messaging methods and converts it into an
72
+ # Array of Strings, split on newline separators. Each line is then
73
+ # formatted into a log format based on the given options, and the Array
74
+ # returned to be passed to to_console() and/or to_file().
75
+ def loggify(string, type = false, color = false)
76
+ lines = string.to_s.split("\n")
77
+ if type
78
+ type = send(color, type) if color
79
+ time_now = time
80
+ lines.map {|line| "[#{time_now}][#{type}] #{line}" }
81
+ else
82
+ lines
83
+ end
84
+ end
85
85
 
86
- ##
87
- # Wraps the provided string in colorizing tags to provide
88
- # easier to view output to the client
89
- def self.colorize(string, code)
90
- "\e[#{code}m#{string}\e[0m"
91
- end
86
+ ##
87
+ # Receives an Array of Strings to be written to the console.
88
+ def to_console(lines, stderr = false)
89
+ return if quiet?
90
+ lines.each {|line| stderr ? Kernel.warn(line) : puts(line) }
91
+ end
92
92
 
93
- ##
94
- # Returns 'true' (boolean) if the QUIET constant is defined
95
- # By default it isn't defined, only when initializing Backup using
96
- # the '--quite' (or '-q') option in the CLI (e.g. backup perform -t my_backup --quiet)
97
- def self.quiet?
98
- const_defined?(:QUIET) && QUIET
99
- end
93
+ ##
94
+ # Receives an Array of Strings to be written to the log file.
95
+ def to_file(lines)
96
+ File.open(File.join(LOG_PATH, 'backup.log'), 'a') do |file|
97
+ lines.each {|line| file.puts line }
98
+ end
99
+ messages.push(*lines)
100
+ end
101
+
102
+ ##
103
+ # Invokes the #colorize method with the provided string
104
+ # and the color code "32" (for green)
105
+ def green(string)
106
+ colorize(string, 32)
107
+ end
100
108
 
109
+ ##
110
+ # Invokes the #colorize method with the provided string
111
+ # and the color code "33" (for yellow)
112
+ def yellow(string)
113
+ colorize(string, 33)
114
+ end
115
+
116
+ ##
117
+ # Invokes the #colorize method the with provided string
118
+ # and the color code "31" (for red)
119
+ def red(string)
120
+ colorize(string, 31)
121
+ end
122
+
123
+ ##
124
+ # Wraps the provided string in colorizing tags to provide
125
+ # easier to view output to the client
126
+ def colorize(string, code)
127
+ "\e[#{code}m#{string}\e[0m"
128
+ end
129
+
130
+ ##
131
+ # Returns 'true' (boolean) if the QUIET constant is defined
132
+ # By default it isn't defined, only when initializing Backup using
133
+ # the '--quiet' (or '-q') option in the CLI
134
+ # (e.g. backup perform -t my_backup --quiet)
135
+ def quiet?
136
+ const_defined?(:QUIET) && QUIET
137
+ end
138
+
139
+ end
101
140
  end
102
141
  end