backup 3.0.19 → 3.0.20
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +9 -8
- data/Gemfile.lock +19 -1
- data/Guardfile +13 -9
- data/README.md +93 -31
- data/backup.gemspec +3 -3
- data/bin/backup +6 -283
- data/lib/backup.rb +101 -72
- data/lib/backup/archive.rb +21 -9
- data/lib/backup/binder.rb +22 -0
- data/lib/backup/cleaner.rb +36 -0
- data/lib/backup/cli/helpers.rb +103 -0
- data/lib/backup/cli/utility.rb +308 -0
- data/lib/backup/compressor/base.rb +2 -2
- data/lib/backup/compressor/pbzip2.rb +76 -0
- data/lib/backup/configuration/compressor/pbzip2.rb +28 -0
- data/lib/backup/configuration/database/riak.rb +25 -0
- data/lib/backup/configuration/encryptor/open_ssl.rb +6 -0
- data/lib/backup/configuration/helpers.rb +5 -18
- data/lib/backup/configuration/notifier/base.rb +13 -0
- data/lib/backup/configuration/notifier/hipchat.rb +41 -0
- data/lib/backup/configuration/notifier/mail.rb +38 -0
- data/lib/backup/configuration/notifier/prowl.rb +23 -0
- data/lib/backup/configuration/storage/cloudfiles.rb +4 -0
- data/lib/backup/configuration/storage/dropbox.rb +8 -4
- data/lib/backup/database/base.rb +10 -2
- data/lib/backup/database/mongodb.rb +16 -19
- data/lib/backup/database/mysql.rb +2 -2
- data/lib/backup/database/postgresql.rb +2 -2
- data/lib/backup/database/redis.rb +15 -7
- data/lib/backup/database/riak.rb +45 -0
- data/lib/backup/dependency.rb +21 -7
- data/lib/backup/encryptor/base.rb +1 -1
- data/lib/backup/encryptor/open_ssl.rb +20 -5
- data/lib/backup/errors.rb +124 -0
- data/lib/backup/finder.rb +11 -3
- data/lib/backup/logger.rb +121 -82
- data/lib/backup/model.rb +103 -44
- data/lib/backup/notifier/base.rb +50 -0
- data/lib/backup/notifier/campfire.rb +32 -52
- data/lib/backup/notifier/hipchat.rb +99 -0
- data/lib/backup/notifier/mail.rb +100 -61
- data/lib/backup/notifier/presently.rb +31 -40
- data/lib/backup/notifier/prowl.rb +73 -0
- data/lib/backup/notifier/twitter.rb +29 -39
- data/lib/backup/packager.rb +25 -0
- data/lib/backup/splitter.rb +62 -0
- data/lib/backup/storage/base.rb +178 -18
- data/lib/backup/storage/cloudfiles.rb +34 -28
- data/lib/backup/storage/dropbox.rb +64 -67
- data/lib/backup/storage/ftp.rb +48 -40
- data/lib/backup/storage/local.rb +33 -28
- data/lib/backup/storage/ninefold.rb +40 -26
- data/lib/backup/storage/object.rb +8 -6
- data/lib/backup/storage/rsync.rb +61 -51
- data/lib/backup/storage/s3.rb +29 -27
- data/lib/backup/storage/scp.rb +56 -36
- data/lib/backup/storage/sftp.rb +49 -33
- data/lib/backup/syncer/base.rb +1 -1
- data/lib/backup/syncer/rsync.rb +1 -1
- data/lib/backup/template.rb +46 -0
- data/lib/backup/version.rb +1 -1
- data/spec/archive_spec.rb +34 -9
- data/spec/backup_spec.rb +1 -1
- data/spec/cli/helpers_spec.rb +35 -0
- data/spec/cli/utility_spec.rb +38 -0
- data/spec/compressor/bzip2_spec.rb +1 -1
- data/spec/compressor/gzip_spec.rb +1 -1
- data/spec/compressor/lzma_spec.rb +1 -1
- data/spec/compressor/pbzip2_spec.rb +63 -0
- data/spec/configuration/base_spec.rb +1 -1
- data/spec/configuration/compressor/bzip2_spec.rb +1 -1
- data/spec/configuration/compressor/gzip_spec.rb +1 -1
- data/spec/configuration/compressor/lzma_spec.rb +1 -1
- data/spec/configuration/database/base_spec.rb +1 -1
- data/spec/configuration/database/mongodb_spec.rb +1 -1
- data/spec/configuration/database/mysql_spec.rb +1 -1
- data/spec/configuration/database/postgresql_spec.rb +1 -1
- data/spec/configuration/database/redis_spec.rb +1 -1
- data/spec/configuration/database/riak_spec.rb +31 -0
- data/spec/configuration/encryptor/gpg_spec.rb +1 -1
- data/spec/configuration/encryptor/open_ssl_spec.rb +4 -1
- data/spec/configuration/notifier/campfire_spec.rb +1 -1
- data/spec/configuration/notifier/hipchat_spec.rb +43 -0
- data/spec/configuration/notifier/mail_spec.rb +34 -22
- data/spec/configuration/notifier/presently_spec.rb +1 -1
- data/spec/configuration/notifier/prowl_spec.rb +28 -0
- data/spec/configuration/notifier/twitter_spec.rb +1 -1
- data/spec/configuration/storage/cloudfiles_spec.rb +19 -16
- data/spec/configuration/storage/dropbox_spec.rb +1 -1
- data/spec/configuration/storage/ftp_spec.rb +1 -1
- data/spec/configuration/storage/local_spec.rb +1 -1
- data/spec/configuration/storage/ninefold_spec.rb +1 -1
- data/spec/configuration/storage/rsync_spec.rb +1 -1
- data/spec/configuration/storage/s3_spec.rb +1 -1
- data/spec/configuration/storage/scp_spec.rb +1 -1
- data/spec/configuration/storage/sftp_spec.rb +1 -1
- data/spec/configuration/syncer/rsync_spec.rb +1 -1
- data/spec/configuration/syncer/s3_spec.rb +1 -1
- data/spec/database/base_spec.rb +10 -1
- data/spec/database/mongodb_spec.rb +34 -7
- data/spec/database/mysql_spec.rb +8 -7
- data/spec/database/postgresql_spec.rb +8 -7
- data/spec/database/redis_spec.rb +39 -9
- data/spec/database/riak_spec.rb +50 -0
- data/spec/encryptor/gpg_spec.rb +1 -1
- data/spec/encryptor/open_ssl_spec.rb +77 -20
- data/spec/errors_spec.rb +306 -0
- data/spec/finder_spec.rb +91 -0
- data/spec/logger_spec.rb +254 -33
- data/spec/model_spec.rb +120 -15
- data/spec/notifier/campfire_spec.rb +127 -52
- data/spec/notifier/hipchat_spec.rb +193 -0
- data/spec/notifier/mail_spec.rb +290 -74
- data/spec/notifier/presently_spec.rb +290 -73
- data/spec/notifier/prowl_spec.rb +149 -0
- data/spec/notifier/twitter_spec.rb +106 -41
- data/spec/spec_helper.rb +8 -2
- data/spec/splitter_spec.rb +71 -0
- data/spec/storage/base_spec.rb +280 -19
- data/spec/storage/cloudfiles_spec.rb +38 -22
- data/spec/storage/dropbox_spec.rb +17 -13
- data/spec/storage/ftp_spec.rb +145 -55
- data/spec/storage/local_spec.rb +6 -6
- data/spec/storage/ninefold_spec.rb +70 -29
- data/spec/storage/object_spec.rb +44 -44
- data/spec/storage/rsync_spec.rb +186 -63
- data/spec/storage/s3_spec.rb +23 -24
- data/spec/storage/scp_spec.rb +116 -41
- data/spec/storage/sftp_spec.rb +124 -46
- data/spec/syncer/rsync_spec.rb +3 -3
- data/spec/syncer/s3_spec.rb +1 -1
- data/spec/version_spec.rb +1 -1
- data/templates/cli/utility/archive +13 -0
- data/{lib/templates → templates/cli/utility}/compressor/bzip2 +1 -1
- data/{lib/templates → templates/cli/utility}/compressor/gzip +1 -1
- data/{lib/templates → templates/cli/utility}/compressor/lzma +0 -0
- data/templates/cli/utility/compressor/pbzip2 +7 -0
- data/templates/cli/utility/config +31 -0
- data/{lib/templates → templates/cli/utility}/database/mongodb +1 -1
- data/{lib/templates → templates/cli/utility}/database/mysql +1 -1
- data/{lib/templates → templates/cli/utility}/database/postgresql +1 -1
- data/{lib/templates → templates/cli/utility}/database/redis +1 -1
- data/templates/cli/utility/database/riak +8 -0
- data/{lib/templates → templates/cli/utility}/encryptor/gpg +1 -1
- data/templates/cli/utility/encryptor/openssl +9 -0
- data/templates/cli/utility/model.erb +23 -0
- data/{lib/templates → templates/cli/utility}/notifier/campfire +2 -1
- data/templates/cli/utility/notifier/hipchat +15 -0
- data/{lib/templates → templates/cli/utility}/notifier/mail +6 -1
- data/{lib/templates → templates/cli/utility}/notifier/presently +1 -0
- data/templates/cli/utility/notifier/prowl +11 -0
- data/{lib/templates → templates/cli/utility}/notifier/twitter +2 -1
- data/templates/cli/utility/splitter +7 -0
- data/templates/cli/utility/storage/cloudfiles +12 -0
- data/{lib/templates → templates/cli/utility}/storage/dropbox +1 -1
- data/{lib/templates → templates/cli/utility}/storage/ftp +0 -0
- data/templates/cli/utility/storage/local +7 -0
- data/{lib/templates → templates/cli/utility}/storage/ninefold +1 -1
- data/templates/cli/utility/storage/rsync +11 -0
- data/{lib/templates → templates/cli/utility}/storage/s3 +0 -2
- data/templates/cli/utility/storage/scp +11 -0
- data/templates/cli/utility/storage/sftp +11 -0
- data/{lib/templates → templates/cli/utility}/syncer/rsync +1 -1
- data/{lib/templates → templates/cli/utility}/syncer/s3 +1 -1
- data/templates/general/links +11 -0
- data/templates/general/version.erb +2 -0
- data/templates/notifier/mail/failure.erb +9 -0
- data/templates/notifier/mail/success.erb +7 -0
- data/templates/notifier/mail/warning.erb +9 -0
- data/templates/storage/dropbox/authorization_url.erb +6 -0
- data/templates/storage/dropbox/authorized.erb +4 -0
- data/templates/storage/dropbox/cache_file_written.erb +10 -0
- metadata +81 -45
- data/lib/backup/cli.rb +0 -110
- data/lib/backup/exception/command_failed.rb +0 -8
- data/lib/backup/exception/command_not_found.rb +0 -8
- data/lib/backup/notifier/binder.rb +0 -32
- data/lib/backup/notifier/templates/notify_failure.erb +0 -33
- data/lib/backup/notifier/templates/notify_success.erb +0 -16
- data/lib/templates/archive +0 -7
- data/lib/templates/encryptor/openssl +0 -8
- data/lib/templates/readme +0 -15
- data/lib/templates/storage/cloudfiles +0 -11
- data/lib/templates/storage/local +0 -7
- data/lib/templates/storage/rsync +0 -11
- data/lib/templates/storage/scp +0 -11
- 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
|
-
|
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
|
-
|
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
|
-
|
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 }
|
85
|
+
response = run("#{ utility('redis-cli') } #{ credential_options } " +
|
86
|
+
"#{ connectivity_options } #{ additional_options } SAVE")
|
87
87
|
unless response =~ /OK/
|
88
|
-
|
89
|
-
|
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
|
-
|
98
|
-
|
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
|
data/lib/backup/dependency.rb
CHANGED
@@ -48,7 +48,7 @@ module Backup
|
|
48
48
|
|
49
49
|
'mail' => {
|
50
50
|
:require => 'mail',
|
51
|
-
:version => '
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
@@ -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
|
27
|
-
@salt
|
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'
|
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 '-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
4
|
+
module Logger
|
5
|
+
class << self
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
59
|
-
|
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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|