backup 3.5.1 → 3.6.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.
- checksums.yaml +4 -4
- data/lib/backup/cli.rb +29 -6
- data/lib/backup/errors.rb +46 -81
- data/lib/backup/model.rb +184 -143
- data/lib/backup/notifier/base.rb +60 -29
- data/lib/backup/notifier/campfire.rb +23 -105
- data/lib/backup/notifier/hipchat.rb +19 -17
- data/lib/backup/notifier/mail.rb +64 -59
- data/lib/backup/notifier/prowl.rb +27 -19
- data/lib/backup/notifier/pushover.rb +26 -36
- data/lib/backup/notifier/twitter.rb +13 -15
- data/lib/backup/pipeline.rb +1 -3
- data/lib/backup/storage/s3.rb +0 -3
- data/lib/backup/utilities.rb +9 -8
- data/lib/backup/version.rb +1 -1
- data/templates/notifier/mail/failure.erb +2 -0
- data/templates/notifier/mail/success.erb +4 -0
- data/templates/notifier/mail/warning.erb +2 -0
- metadata +16 -30
data/lib/backup/notifier/base.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
module Backup
|
4
4
|
module Notifier
|
5
5
|
class Base
|
6
|
+
include Backup::Utilities::Helpers
|
6
7
|
include Backup::Configuration::Helpers
|
7
8
|
|
8
9
|
##
|
@@ -24,7 +25,17 @@ module Backup
|
|
24
25
|
alias :notify_on_failure? :on_failure
|
25
26
|
|
26
27
|
##
|
27
|
-
#
|
28
|
+
# Number of times to retry failed attempts to send notification.
|
29
|
+
# Default: 10
|
30
|
+
attr_accessor :max_retries
|
31
|
+
|
32
|
+
##
|
33
|
+
# Time in seconds to pause before each retry.
|
34
|
+
# Default: 30
|
35
|
+
attr_accessor :retry_waitsec
|
36
|
+
|
37
|
+
attr_reader :model
|
38
|
+
|
28
39
|
def initialize(model)
|
29
40
|
@model = model
|
30
41
|
load_defaults!
|
@@ -32,48 +43,68 @@ module Backup
|
|
32
43
|
@on_success = true if on_success.nil?
|
33
44
|
@on_warning = true if on_warning.nil?
|
34
45
|
@on_failure = true if on_failure.nil?
|
46
|
+
@max_retries ||= 10
|
47
|
+
@retry_waitsec ||= 30
|
35
48
|
end
|
36
49
|
|
37
|
-
|
38
|
-
#
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
action = false
|
50
|
-
if failure
|
51
|
-
action = :failure if notify_on_failure?
|
52
|
-
else
|
53
|
-
if notify_on_success? || (notify_on_warning? && Logger.has_warnings?)
|
54
|
-
action = Logger.has_warnings? ? :warning : :success
|
55
|
-
end
|
56
|
-
end
|
50
|
+
# This method is called from an ensure block in Model#perform! and must
|
51
|
+
# not raise any exceptions. However, each Notifier's #notify! method
|
52
|
+
# should raise an exception if the request fails so it may be retried.
|
53
|
+
def perform!
|
54
|
+
status = case model.exit_status
|
55
|
+
when 0
|
56
|
+
:success if notify_on_success?
|
57
|
+
when 1
|
58
|
+
:warning if notify_on_success? || notify_on_warning?
|
59
|
+
else
|
60
|
+
:failure if notify_on_failure?
|
61
|
+
end
|
57
62
|
|
58
|
-
if
|
59
|
-
|
60
|
-
notify!(
|
63
|
+
if status
|
64
|
+
Logger.info "Sending notification using #{ notifier_name }..."
|
65
|
+
with_retries { notify!(status) }
|
61
66
|
end
|
67
|
+
|
68
|
+
rescue Exception => err
|
69
|
+
Logger.error Errors::NotifierError.wrap(err, "#{ notifier_name } Failed!")
|
62
70
|
end
|
63
71
|
|
64
72
|
private
|
65
73
|
|
74
|
+
def with_retries
|
75
|
+
retries = 0
|
76
|
+
begin
|
77
|
+
yield
|
78
|
+
rescue StandardError, Timeout::Error => err
|
79
|
+
retries += 1
|
80
|
+
raise if retries > max_retries
|
81
|
+
|
82
|
+
Logger.info Errors::NotifierError.
|
83
|
+
wrap(err, "Retry ##{ retries } of #{ max_retries }.")
|
84
|
+
sleep(retry_waitsec)
|
85
|
+
retry
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
66
89
|
##
|
67
90
|
# Return the notifier name, with Backup namespace removed
|
68
91
|
def notifier_name
|
69
92
|
self.class.to_s.sub('Backup::', '')
|
70
93
|
end
|
71
94
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
95
|
+
# For ruby-1.8.7. Both sorted so specs will match.
|
96
|
+
def encode_www_form(enum)
|
97
|
+
if RUBY_VERSION < '1.9'
|
98
|
+
require 'cgi'
|
99
|
+
str = ''
|
100
|
+
enum.to_a.map {|k,v| [k.to_s, v] }.sort.each do |k,v|
|
101
|
+
str << '&' unless str.empty?
|
102
|
+
str << CGI.escape(k) << '=' << CGI.escape(v)
|
103
|
+
end
|
104
|
+
str
|
105
|
+
else
|
106
|
+
URI.encode_www_form(enum.sort)
|
107
|
+
end
|
77
108
|
end
|
78
109
|
|
79
110
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require '
|
2
|
+
require 'excon'
|
3
|
+
require 'json'
|
3
4
|
|
4
5
|
module Backup
|
5
6
|
module Notifier
|
@@ -18,8 +19,7 @@ module Backup
|
|
18
19
|
attr_accessor :room_id
|
19
20
|
|
20
21
|
def initialize(model, &block)
|
21
|
-
super
|
22
|
-
|
22
|
+
super
|
23
23
|
instance_eval(&block) if block_given?
|
24
24
|
end
|
25
25
|
|
@@ -27,124 +27,42 @@ module Backup
|
|
27
27
|
|
28
28
|
##
|
29
29
|
# Notify the user of the backup operation results.
|
30
|
+
#
|
30
31
|
# `status` indicates one of the following:
|
31
32
|
#
|
32
33
|
# `:success`
|
33
34
|
# : The backup completed successfully.
|
34
|
-
# : Notification will be sent if `on_success`
|
35
|
+
# : Notification will be sent if `on_success` is `true`.
|
35
36
|
#
|
36
37
|
# `:warning`
|
37
|
-
# : The backup completed successfully, but warnings were logged
|
38
|
-
# : Notification will be sent
|
39
|
-
# : backup log, if `on_warning` was set to `true`
|
38
|
+
# : The backup completed successfully, but warnings were logged.
|
39
|
+
# : Notification will be sent if `on_warning` or `on_success` is `true`.
|
40
40
|
#
|
41
41
|
# `:failure`
|
42
42
|
# : The backup operation failed.
|
43
|
-
# : Notification will be sent
|
44
|
-
# : the failure, the Exception's backtrace, a copy of the current
|
45
|
-
# : backup log and other information if `on_failure` was set to `true`
|
43
|
+
# : Notification will be sent if `on_warning` or `on_success` is `true`.
|
46
44
|
#
|
47
45
|
def notify!(status)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
message = "
|
46
|
+
tag = case status
|
47
|
+
when :success then '[Backup::Success]'
|
48
|
+
when :warning then '[Backup::Warning]'
|
49
|
+
when :failure then '[Backup::Failure]'
|
50
|
+
end
|
51
|
+
message = "#{ tag } #{ model.label } (#{ model.trigger })"
|
54
52
|
send_message(message)
|
55
53
|
end
|
56
54
|
|
57
|
-
##
|
58
|
-
# Creates a new Campfire::Interface object and passes in the
|
59
|
-
# campfire clients "room_id", "subdomain" and "api_token". Using this object
|
60
|
-
# the provided "message" will be sent to the desired Campfire chat room
|
61
55
|
def send_message(message)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
# The Campfire::Interface acts as the Interface for the Campfire class.
|
68
|
-
# It uses the HTTParty library and the Campfire::Room class to communicate
|
69
|
-
# with the Campfire rooms. HTTParty provides the Campfire::Interface with the methods
|
70
|
-
# necessary to communicate (inside the HTTParty module) such as the class methods:
|
71
|
-
# * post
|
72
|
-
# * base_uri
|
73
|
-
# * basic_auth
|
74
|
-
class Interface
|
75
|
-
include HTTParty
|
76
|
-
|
77
|
-
##
|
78
|
-
# We communicate using the JSON data format
|
79
|
-
headers 'Content-Type' => 'application/json'
|
80
|
-
|
81
|
-
##
|
82
|
-
# Instantiates a new Campfire::Room object with
|
83
|
-
# the provided arguments and returns this object
|
84
|
-
def self.room(room_id, subdomain, api_token)
|
85
|
-
Room.new(room_id, subdomain, api_token)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
##
|
90
|
-
# The Campfire::Room acts as a model for an actual room on the Campfire service.
|
91
|
-
# And it uses the Campfire::Interface's (HTTParty) class methods to communicate based
|
92
|
-
# on the provided parameters (room_id, subdomain and api_token)
|
93
|
-
class Room
|
94
|
-
|
95
|
-
##
|
96
|
-
# Campfire api authentication api_token
|
97
|
-
attr_accessor :api_token
|
98
|
-
|
99
|
-
##
|
100
|
-
# Campfire account's subdomain
|
101
|
-
attr_accessor :subdomain
|
102
|
-
|
103
|
-
##
|
104
|
-
# Campfire account's room id
|
105
|
-
attr_accessor :room_id
|
106
|
-
|
107
|
-
##
|
108
|
-
# Instantiates a new Campfire::Room object and sets all the
|
109
|
-
# necessary arguments (@room_id, @subdomain, @api_token)
|
110
|
-
def initialize(room_id, subdomain, api_token)
|
111
|
-
@room_id = room_id
|
112
|
-
@subdomain = subdomain
|
113
|
-
@api_token = api_token
|
114
|
-
end
|
115
|
-
|
116
|
-
##
|
117
|
-
# Wrapper method for the #send_message (private) method
|
118
|
-
def message(message)
|
119
|
-
send_message(message)
|
120
|
-
end
|
121
|
-
|
122
|
-
private
|
123
|
-
|
124
|
-
##
|
125
|
-
# Takes a "message" as argument, the "type" defaults to "Textmessage".
|
126
|
-
# This method builds up a POST request with the necessary params (serialized to JSON format)
|
127
|
-
# and sends it to the Campfire service in order to submit the message
|
128
|
-
def send_message(message, type = 'Textmessage')
|
129
|
-
post 'speak', :body => MultiJson.encode(
|
130
|
-
{ :message => { :body => message, :type => type } }
|
56
|
+
uri = "https://#{ subdomain }.campfirenow.com/room/#{ room_id }/speak.json"
|
57
|
+
options = {
|
58
|
+
:headers => { 'Content-Type' => 'application/json' },
|
59
|
+
:body => JSON.dump(
|
60
|
+
{ :message => { :body => message, :type => 'Textmessage' } }
|
131
61
|
)
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
# the POST request that was built in the #send_message (private) method
|
137
|
-
def post(action, options = {})
|
138
|
-
Interface.base_uri("https://#{subdomain}.campfirenow.com")
|
139
|
-
Interface.basic_auth(api_token, 'x')
|
140
|
-
Interface.post(room_url_for(action), options)
|
141
|
-
end
|
142
|
-
|
143
|
-
##
|
144
|
-
# Returns the url for the specified room (in JSON format)
|
145
|
-
def room_url_for(action)
|
146
|
-
"/room/#{room_id}/#{action}.json"
|
147
|
-
end
|
62
|
+
}
|
63
|
+
options.merge!(:user => api_token, :password => 'x') # Basic Auth
|
64
|
+
options.merge!(:expects => 201) # raise error if unsuccessful
|
65
|
+
Excon.post(uri, options)
|
148
66
|
end
|
149
67
|
|
150
68
|
end
|
@@ -37,55 +37,57 @@ module Backup
|
|
37
37
|
attr_accessor :failure_color
|
38
38
|
|
39
39
|
def initialize(model, &block)
|
40
|
-
super
|
40
|
+
super
|
41
|
+
instance_eval(&block) if block_given?
|
41
42
|
|
42
43
|
@notify_users ||= false
|
43
44
|
@rooms_notified ||= []
|
44
45
|
@success_color ||= 'yellow'
|
45
46
|
@warning_color ||= 'yellow'
|
46
47
|
@failure_color ||= 'yellow'
|
47
|
-
|
48
|
-
instance_eval(&block) if block_given?
|
49
48
|
end
|
50
49
|
|
51
50
|
private
|
52
51
|
|
53
52
|
##
|
54
53
|
# Notify the user of the backup operation results.
|
54
|
+
#
|
55
55
|
# `status` indicates one of the following:
|
56
56
|
#
|
57
57
|
# `:success`
|
58
58
|
# : The backup completed successfully.
|
59
|
-
# : Notification will be sent if `on_success`
|
59
|
+
# : Notification will be sent if `on_success` is `true`.
|
60
60
|
#
|
61
61
|
# `:warning`
|
62
|
-
# : The backup completed successfully, but warnings were logged
|
63
|
-
# : Notification will be sent
|
64
|
-
# : backup log, if `on_warning` was set to `true`
|
62
|
+
# : The backup completed successfully, but warnings were logged.
|
63
|
+
# : Notification will be sent if `on_warning` or `on_success` is `true`.
|
65
64
|
#
|
66
65
|
# `:failure`
|
67
66
|
# : The backup operation failed.
|
68
|
-
# : Notification will be sent
|
69
|
-
# : the failure, the Exception's backtrace, a copy of the current
|
70
|
-
# : backup log and other information if `on_failure` was set to `true`
|
67
|
+
# : Notification will be sent if `on_warning` or `on_success` is `true`.
|
71
68
|
#
|
72
69
|
def notify!(status)
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
message = "
|
70
|
+
tag, color = case status
|
71
|
+
when :success then ['[Backup::Success]', success_color]
|
72
|
+
when :warning then ['[Backup::Warning]', warning_color]
|
73
|
+
when :failure then ['[Backup::Failure]', failure_color]
|
74
|
+
end
|
75
|
+
message = "#{ tag } #{ model.label } (#{ model.trigger })"
|
79
76
|
send_message(message, color)
|
80
77
|
end
|
81
78
|
|
79
|
+
# Hipchat::Client will raise an error if unsuccessful.
|
82
80
|
def send_message(msg, color)
|
83
81
|
client = HipChat::Client.new(token)
|
84
|
-
|
82
|
+
rooms_to_notify.each do |room|
|
85
83
|
client[room].send(from, msg, :color => color, :notify => notify_users)
|
86
84
|
end
|
87
85
|
end
|
88
86
|
|
87
|
+
def rooms_to_notify
|
88
|
+
Array(rooms_notified).map {|r| r.split(',').map(&:strip) }.flatten
|
89
|
+
end
|
90
|
+
|
89
91
|
end
|
90
92
|
end
|
91
93
|
end
|
data/lib/backup/notifier/mail.rb
CHANGED
@@ -17,11 +17,11 @@ module Backup
|
|
17
17
|
#
|
18
18
|
# [:sendmail - ::Mail::Sendmail]
|
19
19
|
# Settings used by this method:
|
20
|
-
# {#
|
20
|
+
# {#sendmail_args}
|
21
21
|
#
|
22
22
|
# [:exim - ::Mail::Exim]
|
23
23
|
# Settings used by this method:
|
24
|
-
# {#
|
24
|
+
# {#exim_args}
|
25
25
|
#
|
26
26
|
# [:file - ::Mail::FileDelivery]
|
27
27
|
# Settings used by this method:
|
@@ -76,13 +76,6 @@ module Backup
|
|
76
76
|
# Use a +SSL/TLS+ connection.
|
77
77
|
attr_accessor :encryption
|
78
78
|
|
79
|
-
attr_deprecate :enable_starttls_auto, :version => '3.2.0',
|
80
|
-
:message => "Use #encryption instead.\n" +
|
81
|
-
'e.g. mail.encryption = :starttls',
|
82
|
-
:action => lambda {|klass, val|
|
83
|
-
klass.encryption = val ? :starttls : :none
|
84
|
-
}
|
85
|
-
|
86
79
|
##
|
87
80
|
# OpenSSL Verify Mode
|
88
81
|
#
|
@@ -92,52 +85,44 @@ module Backup
|
|
92
85
|
# Use +:none+ for a self-signed and/or wildcard certificate
|
93
86
|
attr_accessor :openssl_verify_mode
|
94
87
|
|
95
|
-
##
|
96
|
-
# Path to `sendmail` (if needed)
|
97
|
-
#
|
98
|
-
# When using the `:sendmail` `delivery_method` option,
|
99
|
-
# this may be used to specify the absolute path to `sendmail`
|
100
|
-
#
|
101
|
-
# Example: '/usr/sbin/sendmail'
|
102
|
-
attr_accessor :sendmail
|
103
|
-
|
104
88
|
##
|
105
89
|
# Optional arguments to pass to `sendmail`
|
106
90
|
#
|
107
|
-
# Note that this will override the defaults set by the Mail gem
|
108
|
-
# So, if set here, be sure to set all the arguments
|
91
|
+
# Note that this will override the defaults set by the Mail gem
|
92
|
+
# (currently: '-i'). So, if set here, be sure to set all the arguments
|
93
|
+
# you require.
|
109
94
|
#
|
110
|
-
# Example: '-i -
|
95
|
+
# Example: '-i -X/tmp/traffic.log'
|
111
96
|
attr_accessor :sendmail_args
|
112
97
|
|
113
|
-
##
|
114
|
-
# Path to `exim` (if needed)
|
115
|
-
#
|
116
|
-
# When using the `:exim` `delivery_method` option,
|
117
|
-
# this may be used to specify the absolute path to `exim`
|
118
|
-
#
|
119
|
-
# Example: '/usr/sbin/exim'
|
120
|
-
attr_accessor :exim
|
121
|
-
|
122
98
|
##
|
123
99
|
# Optional arguments to pass to `exim`
|
124
100
|
#
|
125
|
-
# Note that this will override the defaults set by the Mail gem
|
126
|
-
# So, if set here, be sure to set all the arguments
|
101
|
+
# Note that this will override the defaults set by the Mail gem
|
102
|
+
# (currently: '-i -t') So, if set here, be sure to set all the arguments
|
103
|
+
# you require.
|
127
104
|
#
|
128
105
|
# Example: '-i -t -X/tmp/traffic.log'
|
129
106
|
attr_accessor :exim_args
|
130
107
|
|
131
108
|
##
|
132
|
-
# Folder where mail will be kept when using the `:file` `delivery_method
|
109
|
+
# Folder where mail will be kept when using the `:file` `delivery_method`.
|
133
110
|
#
|
134
111
|
# Default location is '$HOME/Backup/emails'
|
135
112
|
attr_accessor :mail_folder
|
136
113
|
|
137
|
-
|
138
|
-
|
114
|
+
##
|
115
|
+
# Array of statuses for which the log file should be attached.
|
116
|
+
#
|
117
|
+
# Available statuses are: `:success`, `:warning` and `:failure`.
|
118
|
+
# Default: [:warning, :failure]
|
119
|
+
attr_accessor :send_log_on
|
139
120
|
|
121
|
+
def initialize(model, &block)
|
122
|
+
super
|
140
123
|
instance_eval(&block) if block_given?
|
124
|
+
|
125
|
+
@send_log_on ||= [:warning, :failure]
|
141
126
|
end
|
142
127
|
|
143
128
|
private
|
@@ -147,42 +132,43 @@ module Backup
|
|
147
132
|
#
|
148
133
|
# `status` indicates one of the following:
|
149
134
|
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
135
|
+
# `:success`
|
136
|
+
# : The backup completed successfully.
|
137
|
+
# : Notification will be sent if `on_success` is `true`.
|
153
138
|
#
|
154
|
-
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
139
|
+
# `:warning`
|
140
|
+
# : The backup completed successfully, but warnings were logged.
|
141
|
+
# : Notification will be sent, including a copy of the current
|
142
|
+
# : backup log, if `on_warning` or `on_success` is `true`.
|
158
143
|
#
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
# backup log and other information if `on_failure` was set to `true`
|
144
|
+
# `:failure`
|
145
|
+
# : The backup operation failed.
|
146
|
+
# : Notification will be sent, including a copy of the current
|
147
|
+
# : backup log, if `on_failure` is `true`.
|
164
148
|
#
|
165
149
|
def notify!(status)
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
150
|
+
tag = case status
|
151
|
+
when :success then '[Backup::Success]'
|
152
|
+
when :warning then '[Backup::Warning]'
|
153
|
+
when :failure then '[Backup::Failure]'
|
154
|
+
end
|
172
155
|
|
173
156
|
email = new_email
|
174
|
-
email.subject = "
|
175
|
-
|
157
|
+
email.subject = "#{ tag } #{ model.label } (#{ model.trigger })"
|
158
|
+
|
159
|
+
send_log = send_log_on.include?(status)
|
160
|
+
template = Backup::Template.new({ :model => model, :send_log => send_log })
|
161
|
+
email.body = template.result('notifier/mail/%s.erb' % status.to_s)
|
176
162
|
|
177
163
|
if send_log
|
178
164
|
email.convert_to_multipart
|
179
|
-
email.attachments["#{
|
165
|
+
email.attachments["#{ model.time }.#{ model.trigger }.log"] = {
|
180
166
|
:mime_type => 'text/plain;',
|
181
167
|
:content => Logger.messages.map(&:formatted_lines).flatten.join("\n")
|
182
168
|
}
|
183
169
|
end
|
184
170
|
|
185
|
-
email.deliver!
|
171
|
+
email.deliver! # raise error if unsuccessful
|
186
172
|
end
|
187
173
|
|
188
174
|
##
|
@@ -208,12 +194,12 @@ module Backup
|
|
208
194
|
}
|
209
195
|
when 'sendmail'
|
210
196
|
opts = {}
|
211
|
-
opts.merge!(:location =>
|
197
|
+
opts.merge!(:location => utility(:sendmail))
|
212
198
|
opts.merge!(:arguments => @sendmail_args) if @sendmail_args
|
213
199
|
opts
|
214
200
|
when 'exim'
|
215
201
|
opts = {}
|
216
|
-
opts.merge!(:location =>
|
202
|
+
opts.merge!(:location => utility(:exim))
|
217
203
|
opts.merge!(:arguments => @exim_args) if @exim_args
|
218
204
|
opts
|
219
205
|
when 'file'
|
@@ -232,6 +218,25 @@ module Backup
|
|
232
218
|
email
|
233
219
|
end
|
234
220
|
|
221
|
+
attr_deprecate :enable_starttls_auto, :version => '3.2.0',
|
222
|
+
:message => "Use #encryption instead.\n" +
|
223
|
+
'e.g. mail.encryption = :starttls',
|
224
|
+
:action => lambda {|klass, val|
|
225
|
+
klass.encryption = val ? :starttls : :none
|
226
|
+
}
|
227
|
+
|
228
|
+
attr_deprecate :sendmail, :version => '3.6.0',
|
229
|
+
:message => 'Use Backup::Utilities.configure instead.',
|
230
|
+
:action => lambda {|klass, val|
|
231
|
+
Utilities.configure { sendmail val }
|
232
|
+
}
|
233
|
+
|
234
|
+
attr_deprecate :exim, :version => '3.6.0',
|
235
|
+
:message => 'Use Backup::Utilities.configure instead.',
|
236
|
+
:action => lambda {|klass, val|
|
237
|
+
Utilities.configure { exim val }
|
238
|
+
}
|
239
|
+
|
235
240
|
end
|
236
241
|
end
|
237
242
|
end
|