rbcrontab 0.1 → 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -1
- data/examples/full_example.rb +72 -0
- data/lib/{extensions.rb → crontab_helper.rb} +12 -4
- data/lib/rbcrontab.rb +178 -24
- metadata +4 -3
data/Rakefile
CHANGED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby -rrubygems
|
2
|
+
require 'rbcrontab'
|
3
|
+
|
4
|
+
# setup your basic file paths
|
5
|
+
ROOT = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
# global setup -- we want to source our profile before any cron command
|
8
|
+
source_bash = 'source $HOME/.bash_profile'
|
9
|
+
|
10
|
+
# simple rake helper method
|
11
|
+
def rake(app, command, silent = true)
|
12
|
+
"rake -f#{ROOT}/#{app}/Rakefile #{'-s' if silent} #{command}"
|
13
|
+
end
|
14
|
+
|
15
|
+
# simple script helper method
|
16
|
+
def script(name)
|
17
|
+
"#{ROOT}/scripts/name"
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Crontab Start
|
22
|
+
#
|
23
|
+
|
24
|
+
crontab = Crontab.new do |cron|
|
25
|
+
|
26
|
+
# mail it to me
|
27
|
+
cron.mail_to 'you@example.com'
|
28
|
+
# add my custom paths
|
29
|
+
cron.path %w{/usr/local/bin /usr/bin $HOME/bin}, false
|
30
|
+
# setup my home variable
|
31
|
+
cron.home ENV['HOME']
|
32
|
+
# make sure every schedule sources the bash profile and sets
|
33
|
+
# the RAILS_ENV to production
|
34
|
+
cron.global_setup source_bash, 'RAILS_ENV=production'
|
35
|
+
|
36
|
+
# handle some requests through rake on some app
|
37
|
+
cron.desc 'handle requests at 5 min intervals on weekdays'
|
38
|
+
cron.schedule :every => 5.minutes, :on => Days::WEEKDAYS do
|
39
|
+
rake 'app', 'requests:process'
|
40
|
+
end
|
41
|
+
|
42
|
+
# do some nightly database backups through a bash script we have
|
43
|
+
# in our scripts folder
|
44
|
+
cron.desc 'backup app database files at midnight on weekdays'
|
45
|
+
cron.schedule :at => Time::MIDNIGHT, :on => Days::WEEKDAYS do
|
46
|
+
script 'backup_database_script'
|
47
|
+
end
|
48
|
+
|
49
|
+
# clean up some old user searches if they are old
|
50
|
+
cron.desc 'clean old user searches in some app if > 1 week old on monday'
|
51
|
+
# set the DAYS_OLD environment variable so the rake task can use it
|
52
|
+
cron.schedule :at => Time::MIDNIGHT, :on => Days::MONDAY, :setup => 'DAYS_OLD=7' do
|
53
|
+
rake 'app', 'searches:clean'
|
54
|
+
end
|
55
|
+
|
56
|
+
# just a stupid 'hello world' task to show how to ignore global setups
|
57
|
+
cron.desc 'at 8:30am echo "I GOT A CASE OF THE MUNDAYS!" on mondays'
|
58
|
+
cron.schedule :at => '08:30', :on => Days::MONDAY, :ignore_global_setup => true do
|
59
|
+
"echo 'I GOT A CASE OF THE MUNDAYS!'"
|
60
|
+
end
|
61
|
+
|
62
|
+
# pointless, but just to show how to override the global setup and make your own for this one
|
63
|
+
# schedule
|
64
|
+
cron.desc 'using our OWN setup, not the global one'
|
65
|
+
cron.schedule :every => 1.hour, :on => Days::WEEKENDS, :ignore_global_setup => true, :setup => ['A=1', 'B=2'] do
|
66
|
+
"echo $A && echo $B"
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
# eval the CLI script so you can run it from the command line
|
72
|
+
Crontab::CLI.start! binding
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# create the cron equiv of Fixnum.minutes
|
2
2
|
# Example:
|
3
|
-
# 10.minutes #=> '10
|
4
|
-
# 5.hours #=> '
|
3
|
+
# 10.minutes #=> '*/10 *'
|
4
|
+
# 5.hours #=> '0 */5'
|
5
5
|
class Fixnum
|
6
6
|
def minutes
|
7
|
-
'
|
7
|
+
'*/%s *' % self
|
8
8
|
end
|
9
9
|
alias_method :minute, :minutes
|
10
10
|
def hours
|
11
|
-
'
|
11
|
+
'0 */%s' % self
|
12
12
|
end
|
13
13
|
alias_method :hour, :hours
|
14
14
|
end
|
@@ -37,4 +37,12 @@ class Days
|
|
37
37
|
EVERYDAY = '*'
|
38
38
|
WEEKDAYS = '1-5'
|
39
39
|
WEEKENDS = '0,6'
|
40
|
+
SUNDAY = 0
|
41
|
+
MONDAY = 1
|
42
|
+
TUESDAY = 2
|
43
|
+
WEDNESDAY = 3
|
44
|
+
THURSDAY = 4
|
45
|
+
FRIDAY = 5
|
46
|
+
SATURDAY = 6
|
47
|
+
SUNDAY_ALT= 7
|
40
48
|
end
|
data/lib/rbcrontab.rb
CHANGED
@@ -33,7 +33,7 @@
|
|
33
33
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
34
34
|
# OTHER DEALINGS IN THE SOFTWARE.
|
35
35
|
require 'optparse'
|
36
|
-
require '
|
36
|
+
require 'crontab_helper'
|
37
37
|
# Example:
|
38
38
|
# crontab = Crontab.new do |cron|
|
39
39
|
# cron.desc 'this is my schedule description'
|
@@ -43,18 +43,23 @@ require 'extensions'
|
|
43
43
|
#
|
44
44
|
# see the examples directory for a more verbose example
|
45
45
|
class Crontab
|
46
|
+
|
46
47
|
# can either use as a block or regular object
|
47
48
|
# Crontab.new { |cron| ... }
|
48
49
|
# crontab = Crontab.new
|
49
|
-
def initialize
|
50
|
+
def initialize(options = {})
|
50
51
|
@schedules = []
|
52
|
+
@global_setup = nil
|
53
|
+
@header = options[:header] || false
|
51
54
|
yield self if block_given?
|
52
55
|
end
|
56
|
+
|
53
57
|
# set the MAILTO user for the _entire_ crontab
|
54
58
|
# to set it per-schedule view the schedule :mail_to arg
|
55
59
|
def mail_to(who)
|
56
60
|
@mail_to = who
|
57
61
|
end
|
62
|
+
|
58
63
|
# set the path for the _entire_ crontab
|
59
64
|
# include_path will keep the original $PATH in there
|
60
65
|
def path(paths, include_path = true)
|
@@ -63,28 +68,75 @@ class Crontab
|
|
63
68
|
@paths << paths
|
64
69
|
@paths = @paths.flatten.join(':')
|
65
70
|
end
|
71
|
+
|
72
|
+
# defines your setup for every schedule
|
73
|
+
def global_setup(*commands)
|
74
|
+
@global_setup = commands
|
75
|
+
end
|
76
|
+
|
66
77
|
# set your home path, probably not necessary, but why not
|
67
78
|
def home(home_path)
|
68
79
|
@home = home_path
|
69
80
|
end
|
81
|
+
|
70
82
|
# creates a schedule object from the args passes
|
71
83
|
# your command will go in the block
|
72
84
|
#
|
73
85
|
# crontab.schedule(:args => ...) { "command to run" }
|
74
|
-
def schedule(
|
75
|
-
|
86
|
+
def schedule(settings, &block)
|
87
|
+
settings.merge! :description => @last_description if @last_description
|
88
|
+
setup = []
|
89
|
+
setup << @global_setup if @global_setup and not settings[:ignore_global_setup]
|
90
|
+
setup << settings[:setup] if settings[:setup]
|
91
|
+
settings[:setup] = setup.flatten.uniq.join(' && ') unless setup.empty?
|
76
92
|
@last_description = nil
|
77
|
-
@schedules << Schedule.new(
|
93
|
+
@schedules << Schedule.new(settings, &block)
|
78
94
|
end
|
95
|
+
|
79
96
|
# runs the to_cron method on all schedules and dumps
|
80
97
|
# the crontab to be copied/pasted
|
81
|
-
|
82
|
-
|
98
|
+
# if display_cron_header is true, it will output the
|
99
|
+
# text block in cron_description_block
|
100
|
+
#
|
101
|
+
# FIXME: ugly as fuck
|
102
|
+
def to_crontab(display_cron_header = false)
|
103
|
+
crontab = ''
|
104
|
+
crontab << header
|
105
|
+
crontab << cron_description_block if display_cron_header
|
106
|
+
@schedules.each { |s| crontab << s.to_cron + "\n\n" }
|
107
|
+
crontab
|
108
|
+
end
|
109
|
+
|
110
|
+
# goofy cron description text to visually see whats going on if you aren't
|
111
|
+
# familiar with crontabs
|
112
|
+
# FIXME: ugly as fuck
|
113
|
+
def cron_description_block
|
114
|
+
%{
|
115
|
+
# +---------------- minute (0 - 59)
|
116
|
+
# | +------------- hour (0 - 23)
|
117
|
+
# | | +---------- day of month (1 - 31)
|
118
|
+
# | | | +------- month (1 - 12)
|
119
|
+
# | | | | +---- day of week (0 - 7) (Sunday=0 or 7)
|
120
|
+
# | | | | |
|
121
|
+
# * * * * * command to be executed
|
122
|
+
|
123
|
+
}
|
83
124
|
end
|
125
|
+
|
84
126
|
# sets the description for the schedule immediately following
|
85
127
|
def desc(description)
|
86
128
|
@last_description = description
|
87
129
|
end
|
130
|
+
|
131
|
+
# creates a human readable list of all crob schedules
|
132
|
+
def to_s(verbose = true)
|
133
|
+
@schedules.inject('') do |o,s|
|
134
|
+
o << s.to_s + "\n"
|
135
|
+
o << "`#{s.command}`\n" if verbose
|
136
|
+
o << "\n"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
88
140
|
# lists the descriptions of all cron schedules for easy reviewing
|
89
141
|
def describe
|
90
142
|
output = "Crontabs\n" + ('-' * 40) + "\n"
|
@@ -94,6 +146,7 @@ class Crontab
|
|
94
146
|
end
|
95
147
|
output
|
96
148
|
end
|
149
|
+
|
97
150
|
def header #:nodoc:
|
98
151
|
headers = []
|
99
152
|
headers << "HOME=%s" % @home if @home
|
@@ -102,12 +155,14 @@ class Crontab
|
|
102
155
|
headers << "\n" unless headers.empty?
|
103
156
|
headers.join("\n")
|
104
157
|
end
|
158
|
+
|
105
159
|
# Example:
|
106
160
|
# crontab.schedule(:at => Time::MIDNIGHT, :on => Day::WEEKDAYS) { 'backup_database' }
|
107
161
|
# crontab.schedule(:every => 10.minutes, :on => Day::WEEKENDS) { 'check something' }
|
108
162
|
# crontab.schedule(:at => '18:00', :on_the => '5', :of => Month::MAY) { 'party!' }
|
163
|
+
# crontab.schedule(:every => 5.minutes, :on =>Days::WEEKDAYS, :setup => 'source $HOME/.bashrc') { 'command' }
|
164
|
+
# crontab.schedule(:every => 1.hour, :on =>Days::MONDAY, :setup => ['HI=1', 'WORLD=2']) { 'command' }
|
109
165
|
class Schedule
|
110
|
-
attr_reader :description
|
111
166
|
# args consist of
|
112
167
|
# * :every => 1.minute, 10.minutes, 1.hour, 5.hours -- minutes or hours
|
113
168
|
# * :at => '00:00' -- 24 hour time for when to run
|
@@ -115,37 +170,130 @@ class Crontab
|
|
115
170
|
# * :on_the => '1,2,3' -- days of the _month_
|
116
171
|
# * :in => Month::JANUARY -- month [0..12]
|
117
172
|
# * :of => Month::JANUARY -- month [0..12] -- alias for readability
|
118
|
-
|
119
|
-
|
173
|
+
# * :setup => 'command' (or ['command', 'command', ...]) -- anything to do _before_ running your comand (source bashrc or whatnot for example)
|
174
|
+
# * :ignore_global_setup => true|false -- if you would like to ignore the global setup command
|
175
|
+
def initialize(settings, &block)
|
176
|
+
settings.each { |k,v| instance_variable_set "@#{k}", v }
|
120
177
|
@do = yield
|
121
178
|
end
|
179
|
+
|
180
|
+
# the command the schedule should run
|
181
|
+
def command
|
182
|
+
all_commands = []
|
183
|
+
all_commands << @setup if @setup
|
184
|
+
all_commands << @do
|
185
|
+
all_commands.join ' && '
|
186
|
+
end
|
187
|
+
|
122
188
|
# builds the cron schedule line
|
123
189
|
def to_cron
|
124
190
|
cron_lines = []
|
125
|
-
cron_lines <<
|
191
|
+
cron_lines << "# #{@description}" if @description
|
126
192
|
cron_lines << ('MAILTO=%s' % [@mail_to]) if @mail_to
|
127
193
|
cron_lines << ("%s %s %s %s %s" % [time, days_of_month, months, weekdays, command])
|
128
194
|
cron_lines.join("\n")
|
129
195
|
end
|
196
|
+
|
197
|
+
# outputs a human readable format of the cron schedule
|
198
|
+
def to_s
|
199
|
+
output = ''
|
200
|
+
output << human_time if human_time
|
201
|
+
output << ' on ' + human_day_of_month if human_day_of_month
|
202
|
+
output << ' in ' + human_month if human_month
|
203
|
+
output << ' on ' + human_weekdays if human_weekdays
|
204
|
+
output << " \"#{@description}\"" if @description
|
205
|
+
output
|
206
|
+
end
|
207
|
+
|
130
208
|
private
|
131
|
-
|
132
|
-
|
209
|
+
|
210
|
+
# converts a cron weekday list into human readable form
|
211
|
+
def human_weekdays
|
212
|
+
case weekdays
|
213
|
+
when '*': nil
|
214
|
+
when Days::WEEKDAYS: 'Weekdays'
|
215
|
+
when Days::WEEKENDS: 'Weekends'
|
216
|
+
when Days::MONDAY: 'Monday'
|
217
|
+
when Days::TUESDAY: 'Tuesday'
|
218
|
+
when Days::WEDNESDAY: 'Wednesday'
|
219
|
+
when Days::THURSDAY: 'Thursday'
|
220
|
+
when Days::FRIDAY: 'Friday'
|
221
|
+
when Days::SATURDAY: 'Saturday'
|
222
|
+
when Days::SUNDAY, Days::SUNDAY_ALT: 'Sunday'
|
223
|
+
else
|
224
|
+
weekdays
|
225
|
+
end
|
133
226
|
end
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
227
|
+
|
228
|
+
# converts a cron day of month list into human readable form
|
229
|
+
def human_day_of_month
|
230
|
+
case days_of_month
|
231
|
+
when '*': nil
|
232
|
+
else
|
233
|
+
"the %s" % days_of_month
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# converts a cron month into a human readable month
|
238
|
+
def human_month
|
239
|
+
case months
|
240
|
+
when '*': nil
|
241
|
+
when Month::JANUARY: 'January'
|
242
|
+
when Month::FEBRUARY: 'February'
|
243
|
+
when Month::MARCH: 'March'
|
244
|
+
when Month::APRIL: 'April'
|
245
|
+
when Month::MAY: 'May'
|
246
|
+
when Month::JUNE: 'June'
|
247
|
+
when Month::JULY: 'July'
|
248
|
+
when Month::AUGUST: 'August'
|
249
|
+
when Month::SEPTEMBER: 'September'
|
250
|
+
when Month::OCTOBER: 'October'
|
251
|
+
when Month::NOVEMBER: 'November'
|
252
|
+
else
|
253
|
+
months
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# converts a cron minute/hour list into human readable format
|
258
|
+
def human_time
|
259
|
+
minutes, hours = time.split(' ')
|
260
|
+
|
261
|
+
minute_description = \
|
262
|
+
case minutes
|
263
|
+
when '*': 'Every minute'
|
264
|
+
when '0': nil
|
265
|
+
when /\*\/(\d*)/: "every #{$1} minutes"
|
266
|
+
end
|
267
|
+
|
268
|
+
hour_description = \
|
269
|
+
case hours
|
270
|
+
when '*': nil
|
271
|
+
when /\*\/(\d*)/: $1.to_i == 1 ? 'every hour' : "every #{$1} hours"
|
272
|
+
end
|
273
|
+
|
274
|
+
unless minute_description or hour_description
|
275
|
+
output = "at %02d:%02d" % [hours.to_i, minutes.to_i]
|
276
|
+
else
|
277
|
+
output = ''
|
278
|
+
output << minute_description if minute_description
|
279
|
+
output << ' in ' if hour_description and minute_description
|
280
|
+
output << hour_description if hour_description
|
281
|
+
end
|
282
|
+
output.capitalize
|
139
283
|
end
|
284
|
+
|
140
285
|
def time #:nodoc:
|
141
286
|
@at ? (@at || '*:*').split(':').reverse.join(' ') : (@every || '* *')
|
142
287
|
end
|
288
|
+
|
143
289
|
def days_of_month #:nodoc:
|
144
290
|
@on_the || '*'
|
145
291
|
end
|
292
|
+
|
146
293
|
def months #:nodoc:
|
147
294
|
@in || @of || '*'
|
148
295
|
end
|
296
|
+
|
149
297
|
def weekdays #:nodoc:
|
150
298
|
@on || '*'
|
151
299
|
end
|
@@ -153,14 +301,17 @@ class Crontab
|
|
153
301
|
# Simple CLI class which includes basic command line options
|
154
302
|
# to the cron script
|
155
303
|
# Options:
|
156
|
-
# -h --help
|
157
|
-
# -
|
304
|
+
# -h --help print the usage
|
305
|
+
# --cron-description shows the cron description block
|
306
|
+
# -d --describe describes the crontab
|
158
307
|
class CLI
|
159
308
|
# evaluates the necessary script to handle CLI option parsing
|
160
309
|
# it wants the current binding so inside your script you'd do
|
161
310
|
# Example:
|
162
311
|
# Crontab::CLI.start!(binding)
|
163
|
-
|
312
|
+
# if your crontab is _not_ named 'crontab' you must pass the object in using
|
313
|
+
# Crontab::CLI.start! binding, whatever_your_crontab_object_is_called
|
314
|
+
def self.start!(binding, crontab_object = 'crontab')
|
164
315
|
eval %{if $0 == __FILE__
|
165
316
|
options = {}
|
166
317
|
OptionParser.new do |opts|
|
@@ -168,6 +319,9 @@ class Crontab
|
|
168
319
|
opts.on('-d', '--describe', 'Describe current cron schedules') do |d|
|
169
320
|
options[:describe] = d
|
170
321
|
end
|
322
|
+
opts.on('--cron-description', 'Show the cron description block in the crontab') do |c|
|
323
|
+
options[:cron_description] = c
|
324
|
+
end
|
171
325
|
opts.on_tail("-h", "--help", "Show this message") do
|
172
326
|
puts opts
|
173
327
|
exit
|
@@ -175,12 +329,12 @@ class Crontab
|
|
175
329
|
end.parse!
|
176
330
|
|
177
331
|
if options[:describe]
|
178
|
-
puts
|
332
|
+
puts #{crontab_object}.to_s
|
179
333
|
else
|
180
|
-
puts
|
334
|
+
puts #{crontab_object}.to_crontab(options[:cron_description])
|
181
335
|
end
|
182
336
|
end
|
183
|
-
},
|
337
|
+
}, binding
|
184
338
|
end
|
185
339
|
end
|
186
340
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbcrontab
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0
|
4
|
+
version: "1.0"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Hurring
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-09-22 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -23,7 +23,8 @@ extra_rdoc_files:
|
|
23
23
|
- README
|
24
24
|
files:
|
25
25
|
- examples/cli_crontab.rb
|
26
|
-
-
|
26
|
+
- examples/full_example.rb
|
27
|
+
- lib/crontab_helper.rb
|
27
28
|
- lib/rbcrontab.rb
|
28
29
|
- README
|
29
30
|
- Rakefile
|