did_craken 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +170 -0
- data/lib/craken.rb +112 -0
- data/lib/enumeration.rb +89 -0
- data/lib/raketab.rb +104 -0
- data/spec/craken_spec.rb +138 -0
- data/spec/enumeration_spec.rb +136 -0
- data/spec/raketab_spec.rb +171 -0
- metadata +76 -0
data/README.rdoc
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
= Craken
|
2
|
+
|
3
|
+
Craken is a rails plugin for managing and installing rake-centric crontab files
|
4
|
+
over Capistrano.
|
5
|
+
|
6
|
+
What is a crontab? A command list that cron will run at specified intervals.
|
7
|
+
What is cron? A daemon to execute scheduled commands.
|
8
|
+
|
9
|
+
If you don't know these things already you should probably do a little research
|
10
|
+
before using this tool :) Begin here: http://en.wikipedia.org/wiki/Cron
|
11
|
+
|
12
|
+
Craken uses files called +raketab+s that are similar in every respect to crontab
|
13
|
+
files except the commands are rake tasks instead of arbitrary unix commands. The file
|
14
|
+
goes in the craken directory inside config (i.e. #{RAILS_ROOT}/config/craken/raketab).
|
15
|
+
|
16
|
+
Why not just let it run arbitrary commands instead of limiting it to rake tasks?
|
17
|
+
The main issue this plugin attempts to alleviate is having to manage the
|
18
|
+
rails environment configuration for multiple deployments. Craken will set up the
|
19
|
+
crontab to change into the application's current directory and set rake to run in
|
20
|
+
the correct environment.
|
21
|
+
|
22
|
+
Raketab files can also handle ERB escaped text bound to the rake environment.
|
23
|
+
|
24
|
+
A Capistrano file is also included to make it easy to install cron jobs on multiple
|
25
|
+
hosts. A new :cron capistrano role is necessary to define which machines to install to.
|
26
|
+
|
27
|
+
== Configuration
|
28
|
+
|
29
|
+
Command line configuration options to the rake task (defaults are in parens):
|
30
|
+
[+deploy_path+] Where the application is deployed (RAILS_ROOT)
|
31
|
+
[+crontab_exe+] Where to find the crontab excutable (/usr/bin/crontab)
|
32
|
+
[+rake_exe+] The rake executable (/usr/bin/rake)
|
33
|
+
[+raketab_rails_env+] Rails environment mode to set the cron jobs to run in (RAILS_ENV)
|
34
|
+
[+app_name+] Name of the application (tries to figure it out from the deploy path)
|
35
|
+
[+raketab_file+] Where the raketab file is:
|
36
|
+
|
37
|
+
#{RAILS_ROOT}/config/craken/#{HOSTNAME}_raketab or
|
38
|
+
#{RAILS_ROOT}/config/craken/raketab if the first is not found
|
39
|
+
|
40
|
+
The +raketab_file+ can be a crontab file (no extension), a .yaml/.yml file or
|
41
|
+
an .rb file (see Other Formats below).
|
42
|
+
|
43
|
+
== Example
|
44
|
+
|
45
|
+
An example line from an example raketab file:
|
46
|
+
|
47
|
+
59 * * * * thing:to_do > /tmp/thing_to_do.log 2>&1
|
48
|
+
|
49
|
+
This will run the rake task thing:to_do every 59th minute after every hour.
|
50
|
+
The little redirect thing is added for effect; otherwise output will be mailed
|
51
|
+
to the user who the crontab is installed on.
|
52
|
+
|
53
|
+
When craken:install is run on the production box, the crontab will look like this:
|
54
|
+
|
55
|
+
### foo raketab
|
56
|
+
59 * * * * cd /home/thatguy/u/apps/foo/current && /usr/bin/rake --silent RAILS_ENV=production thing:to_do > /tmp/thing_to_do.log 2>&1
|
57
|
+
### foo raketab end
|
58
|
+
|
59
|
+
The "magic" part of craken is the bit that crontab added:
|
60
|
+
|
61
|
+
cd /home/thatguy/u/apps/foo/current && /usr/bin/rake --silent RAILS_ENV=production
|
62
|
+
|
63
|
+
=== Special crontab string support
|
64
|
+
|
65
|
+
An example line to add a rake task to be executed after reboot:
|
66
|
+
|
67
|
+
@reboot thinking_sphinx:start > /tmp/ts_startup.log 2>&1
|
68
|
+
|
69
|
+
All special strings and their effects:
|
70
|
+
[<tt>@reboot</tt>] execute after reboot
|
71
|
+
[<tt>@yearly</tt>] every year
|
72
|
+
[<tt>@annually</tt>] every year hipster version
|
73
|
+
[<tt>@monthly</tt>] every month, or better known as: <i>No roll in the hay for you this time honey!</i>
|
74
|
+
[<tt>@weekly</tt>] just like every month but weekly
|
75
|
+
[<tt>@daily</tt>] like brushing your teeth
|
76
|
+
[<tt>@midnight</tt>] when the ghosts come out
|
77
|
+
[<tt>@hourly</tt>] whenever the long hand of your watch is at 12
|
78
|
+
|
79
|
+
Read more about crontab special strings here: http://unixhelp.ed.ac.uk/CGI/man-cgi?crontab+5
|
80
|
+
== Other Formats
|
81
|
+
|
82
|
+
You can also specify other types of files to describe +raketabs+. You can have multiple formats and they
|
83
|
+
will be aggregated together.
|
84
|
+
|
85
|
+
=== YAML
|
86
|
+
|
87
|
+
You can specify it in YAML. For instance in a +config/craken/raketab.yml+:
|
88
|
+
|
89
|
+
my_command:
|
90
|
+
hour: 5
|
91
|
+
minute: 30
|
92
|
+
day: 1
|
93
|
+
month: September
|
94
|
+
command: thing:to_do > /tmp/thing_to_do.log 2>&1
|
95
|
+
|
96
|
+
Here we've specified my_command to run at 5:30 AM on September 1st. Aside from the command to run,
|
97
|
+
the timings have the following defaults: 0 minute, 0 hour, every day, every month, every weekday. So
|
98
|
+
you could specify in your raketab.yml:
|
99
|
+
|
100
|
+
my_other_command:
|
101
|
+
command: other:thing:to_do > /tmp/thing_to_do.log 2>&1
|
102
|
+
|
103
|
+
This will run at midnight of every day. You can also specify weekday:
|
104
|
+
|
105
|
+
my_third_command:
|
106
|
+
weekday: thursday
|
107
|
+
command: third:thing:to_do > /tmp/thing_to_do.log 2>&1
|
108
|
+
|
109
|
+
You can also specify the month number or weekday number as you would in a crontab. Lastly, you can specify ranges or full match strings and they will be passed on to the crontab directly:
|
110
|
+
|
111
|
+
and_finally:
|
112
|
+
hour: *
|
113
|
+
weekday: 1-5
|
114
|
+
command: last:thing:to_do > /tmp/thing_to_do.log 2>&1
|
115
|
+
|
116
|
+
Here, the command will run every hour from Monday to Friday. Month and Weekday names are not supported when doing ranges in this fashion.
|
117
|
+
|
118
|
+
=== Raketab DSL
|
119
|
+
|
120
|
+
The other format is written in pure ruby using the +Raketab+ object. In your +config/craken/raketab.rb+ file:
|
121
|
+
|
122
|
+
Raketab.new do |cron|
|
123
|
+
cron.schedule 'thing:to_do > /tmp/thing_to_do.log 2>&1', :every => :thursday
|
124
|
+
end
|
125
|
+
|
126
|
+
The defaults are like those for the YAML file, so in this case, thing to do will run at midnight on thursdays.
|
127
|
+
|
128
|
+
Raketab.new do |cron|
|
129
|
+
cron.schedule 'thing:to_do > /tmp/thing_to_do.log 2>&1', :on => :september, :the => '1st', :at => '5:30'
|
130
|
+
end
|
131
|
+
|
132
|
+
Here it will run only on the first of september at 5:30 AM. Month and weekday names are also supported, and
|
133
|
+
also the named units (hour, minute, month, day, weekday):
|
134
|
+
|
135
|
+
Raketab.new do |cron|
|
136
|
+
cron.schedule 'thing:to_do > /tmp/thing_to_do.log 2>&1', :on => september, :every => thursday
|
137
|
+
end
|
138
|
+
|
139
|
+
Here it will run every Thursday in September. Ranges (inclusive and exclusive), comma separated lists, in strings or using numbers or weekday and month names are also supported and their three letter abbreviations:
|
140
|
+
|
141
|
+
Raketab.new do |cron|
|
142
|
+
cron.schedule 'thing:to_do > /tmp/thing_to_do.log 2>&1', :every => mon..fri
|
143
|
+
cron.schedule 'first:five:days > /tmp/thing_to_do.log 2>&1', :days => [1,2,3,4,5]
|
144
|
+
cron.schedule 'first:day:q1 > /tmp/thing_to_do.log 2>&1', :the => '1st', :in => [jan,feb,mar]
|
145
|
+
cron.schedule 'first:day:q4 > /tmp/thing_to_do.log 2>&1', :the => '1st', :months => 'October,November,December'
|
146
|
+
end
|
147
|
+
|
148
|
+
You can find all the variants in the spec for Raketab and pick and choose which is most natural for you.
|
149
|
+
|
150
|
+
= Running the Capistrano Script
|
151
|
+
|
152
|
+
cap craken:install
|
153
|
+
|
154
|
+
Deploying to someplace other than production? Rails environment is important so rake
|
155
|
+
is set in the right mode when the cron job runs:
|
156
|
+
|
157
|
+
cap -c rails_env=qa craken:install
|
158
|
+
|
159
|
+
Different raketab files can be used to limit a subset of rake tasks to a particular
|
160
|
+
machine listed as a :cron role. These files are prefixed with the name of the machine
|
161
|
+
they need to be deployed to:
|
162
|
+
|
163
|
+
foo_raketab # goes on the "foo" machine
|
164
|
+
bar_raketab # goes on the "bar" machine
|
165
|
+
raketab # goes on all machines except "foo" and "bar"
|
166
|
+
|
167
|
+
Doug McInnes <doug.mcinnes@latimes.com>
|
168
|
+
John Dewey <john.dewey@latimes.com>
|
169
|
+
Reid MacDonald <reid.macdonald@latimes.com>
|
170
|
+
Copyright (c) 2008 Los Angeles Times, released under the MIT license
|
data/lib/craken.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require "#{File.dirname(__FILE__)}/raketab"
|
3
|
+
|
4
|
+
module Craken
|
5
|
+
def self.determine_raketab_files
|
6
|
+
if File.directory?("#{DEPLOY_PATH}/config/craken/") # Use hostname specific raketab first.
|
7
|
+
raketabs = Dir["#{DEPLOY_PATH}/config/craken/*raketab*"].partition {|f| f =~ %r[/raketab.*$] }
|
8
|
+
raketabs.last.empty? ? raketabs.first : raketabs.last.grep(/#{HOSTNAME}_raketab/)
|
9
|
+
else
|
10
|
+
Dir["#{DEPLOY_PATH}/config/raketab*"]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
HOSTNAME = Socket.gethostname.split('.').first.downcase.strip
|
15
|
+
DEPLOY_PATH = ENV['deploy_path'] || RAILS_ROOT
|
16
|
+
RAKETAB_FILES = ENV['raketab_files'].split(":") rescue determine_raketab_files
|
17
|
+
CRONTAB_EXE = ENV['crontab_exe'] || "/usr/bin/crontab"
|
18
|
+
RAKE_EXE = ENV['rake_exe'] || ((rake = `which rake`.strip and rake.empty?) ? "/usr/bin/rake" : rake)
|
19
|
+
RAKETAB_RAILS_ENV = ENV['raketab_rails_env'] || RAILS_ENV
|
20
|
+
# assumes root of app is name of app, also takes into account
|
21
|
+
# capistrano deployments
|
22
|
+
APP_NAME = ENV['app_name'] || (DEPLOY_PATH =~ /\/([^\/]*)\/releases\/\d*$/ ? $1 : File.basename(DEPLOY_PATH))
|
23
|
+
|
24
|
+
# see here: http://unixhelp.ed.ac.uk/CGI/man-cgi?crontab+5
|
25
|
+
SPECIAL_STRINGS = %w[@reboot @yearly @annually @monthly @weekly @daily @midnight @hourly]
|
26
|
+
|
27
|
+
CRONTAB_MARKER_START = "### #{APP_NAME} #{RAKETAB_RAILS_ENV} raketab start"
|
28
|
+
CRONTAB_MARKER_END = "### #{APP_NAME} #{RAKETAB_RAILS_ENV} raketab end"
|
29
|
+
# strip out the existing raketab cron tasks for this project
|
30
|
+
def load_and_strip
|
31
|
+
crontab = ''
|
32
|
+
old = false
|
33
|
+
`#{CRONTAB_EXE} -l`.each_line do |line|
|
34
|
+
line.strip!
|
35
|
+
if old || line == CRONTAB_MARKER_START
|
36
|
+
old = line != CRONTAB_MARKER_END
|
37
|
+
else
|
38
|
+
crontab << line
|
39
|
+
crontab << "\n"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
crontab
|
43
|
+
end
|
44
|
+
|
45
|
+
def append_tasks(crontab, raketab)
|
46
|
+
crontab << "#{CRONTAB_MARKER_START}\n"
|
47
|
+
raketab.each_line do |line|
|
48
|
+
line.strip!
|
49
|
+
unless line =~ /^#/ || line.empty? # ignore comments and blank lines
|
50
|
+
sp = line.split
|
51
|
+
if SPECIAL_STRINGS.include?(sp.first)
|
52
|
+
crontab << sp.shift
|
53
|
+
tasks = sp
|
54
|
+
else
|
55
|
+
crontab << sp[0,5].join(' ')
|
56
|
+
tasks = sp[5,sp.size]
|
57
|
+
end
|
58
|
+
crontab << " cd #{DEPLOY_PATH} && #{RAKE_EXE} --silent RAILS_ENV=#{RAKETAB_RAILS_ENV}"
|
59
|
+
tasks.each do |task|
|
60
|
+
crontab << " #{task}"
|
61
|
+
end
|
62
|
+
crontab << "\n"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
crontab << "#{CRONTAB_MARKER_END}\n"
|
66
|
+
crontab
|
67
|
+
end
|
68
|
+
|
69
|
+
# install new crontab
|
70
|
+
def install(crontab)
|
71
|
+
filename = ".crontab#{rand(9999)}"
|
72
|
+
File.open(filename, 'w') { |f| f.write crontab }
|
73
|
+
`#{CRONTAB_EXE} #{filename}`
|
74
|
+
FileUtils.rm filename
|
75
|
+
end
|
76
|
+
|
77
|
+
def raketab(files=RAKETAB_FILES)
|
78
|
+
files.map do |file|
|
79
|
+
next unless File.exist?(file)
|
80
|
+
builder = file =~ /.(\w+)$/ ? "build_raketab_from_#{$1}" : "build_raketab"
|
81
|
+
send(builder.to_sym, file)
|
82
|
+
end.join("\n")
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
def build_raketab_from_rb(file)
|
87
|
+
eval(File.new(file).read).tabs
|
88
|
+
end
|
89
|
+
|
90
|
+
def build_raketab_from_yml(file)
|
91
|
+
yml = YAML::load(ERB.new(File.read(file)).result(binding))
|
92
|
+
yml.map do |name,tab|
|
93
|
+
format = []
|
94
|
+
format << (tab['min'] || tab['minute'] || '0')
|
95
|
+
format << (tab['hour'] || '0')
|
96
|
+
format << (tab['day'] || '*')
|
97
|
+
format << (tab['month'] =~ /^\d+$/ ? tab['month'] : Date._parse(tab['month'].to_s)[:mon] || '*')
|
98
|
+
format << ((day = tab['weekday'] || tab['wday'] and day =~ /^\d+$/ ? day : Date._parse(day.to_s)[:wday]) || '*')
|
99
|
+
format << tab['command']
|
100
|
+
format.join(' ')
|
101
|
+
end.join("\n")
|
102
|
+
end
|
103
|
+
alias_method :build_raketab_from_yaml, :build_raketab_from_yml
|
104
|
+
|
105
|
+
def build_raketab(file)
|
106
|
+
ERB.new(File.read(file)).result(binding)
|
107
|
+
end
|
108
|
+
|
109
|
+
def method_missing(method, *args)
|
110
|
+
method.to_s =~ /^build_raketab/ ? build_raketab(*args) : super
|
111
|
+
end
|
112
|
+
end
|
data/lib/enumeration.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
class Enumeration
|
2
|
+
include Comparable
|
3
|
+
|
4
|
+
def initialize(id)
|
5
|
+
@unit_id = id % self.class.size
|
6
|
+
end
|
7
|
+
private_class_method :new
|
8
|
+
|
9
|
+
def self.for(var)
|
10
|
+
units[var.to_s =~ /^\d+$/ ? var.to_i - offset : abbrs.index(var[0,3].downcase.capitalize)]
|
11
|
+
end
|
12
|
+
|
13
|
+
def succ
|
14
|
+
self.class.units[(@unit_id + 1) % self.class.size]
|
15
|
+
end
|
16
|
+
|
17
|
+
def between?(a,b)
|
18
|
+
true # always in rings, change for non rings
|
19
|
+
end
|
20
|
+
|
21
|
+
def <=>(o)
|
22
|
+
@unit_id <=> o.instance_variable_get("@unit_id")
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
self.class.names[@unit_id]
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_i
|
30
|
+
@unit_id + self.class.offset
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_abbr
|
34
|
+
to_s[0,3]
|
35
|
+
end
|
36
|
+
|
37
|
+
def coerce(o)
|
38
|
+
[self.class.for(o % self.class.size), self]
|
39
|
+
end
|
40
|
+
|
41
|
+
def +(o)
|
42
|
+
self.class.for((to_i + o.to_i) % self.class.size)
|
43
|
+
end
|
44
|
+
|
45
|
+
def -(o)
|
46
|
+
self.class.for((to_i - o.to_i) % self.class.size)
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect
|
50
|
+
"#<#{self.class.name.split("::").last}:#{to_s}>"
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.generate(names, offset=0)
|
54
|
+
klass = Class.new(self)
|
55
|
+
klass.send(:build_from, names)
|
56
|
+
klass.send(:offset=, offset)
|
57
|
+
klass.instance_eval { undef generate }
|
58
|
+
klass
|
59
|
+
end
|
60
|
+
|
61
|
+
class << self
|
62
|
+
include Enumerable
|
63
|
+
def each
|
64
|
+
units.each { |u| yield u }
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_accessor :offset
|
68
|
+
attr_reader :names, :abbrs, :units, :size
|
69
|
+
def build_from(names)
|
70
|
+
@names = names.dup.freeze
|
71
|
+
@abbrs = names.map { |n| n[0,3] }.freeze
|
72
|
+
|
73
|
+
@size = @names.size
|
74
|
+
@units = (0...@size).map { |n| new(n) }.freeze
|
75
|
+
|
76
|
+
@names.each_with_index do |c,i|
|
77
|
+
const = c.upcase
|
78
|
+
const_get(const) rescue const_set(const, @units[i])
|
79
|
+
const_get(const[0,3]) rescue const_set(const[0,3], @units[i])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
private :build_from
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def Enumeration(*args)
|
87
|
+
Enumeration.generate(*args)
|
88
|
+
end
|
89
|
+
alias enum Enumeration
|
data/lib/raketab.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/enumeration"
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
class Raketab
|
5
|
+
Month = enum %w[January February March April May June July August September October November December], 1
|
6
|
+
Weekday = enum %w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday]
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def methodize_enum(enum)
|
10
|
+
enum.each do |e|
|
11
|
+
p = Proc.new { e }
|
12
|
+
define_method(e.to_s.downcase, p)
|
13
|
+
define_method(e.to_abbr.downcase, p)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
private :methodize_enum
|
17
|
+
|
18
|
+
def schedule(&block)
|
19
|
+
tab = Raketab.new
|
20
|
+
tab.instance_eval(&block)
|
21
|
+
tab
|
22
|
+
end
|
23
|
+
end
|
24
|
+
methodize_enum(Month)
|
25
|
+
methodize_enum(Weekday)
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@tabs = []
|
29
|
+
end
|
30
|
+
|
31
|
+
def run(command, options={})
|
32
|
+
month, wday, mday, hour, min = options[:month] || options[:months] || options[:mon],
|
33
|
+
options[:weekday] || options[:weekdays] || options[:wday],
|
34
|
+
options[:day] || options[:days] || options[:mday],
|
35
|
+
options[:hour] || options[:hours],
|
36
|
+
options[:minute] || options[:minutes] || options[:min]
|
37
|
+
|
38
|
+
# make sure we have ints instead of enums, yo
|
39
|
+
month, wday = [[month, Month], [wday, Weekday]].map do |element,type|
|
40
|
+
if element.kind_of?(Array) # just arrays for now
|
41
|
+
element.each_with_index { |e,i| element[i] = enum_to_i(e,type) }
|
42
|
+
else
|
43
|
+
enum_to_i(element,type)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
[:each, :every, :on, :in, :at, :the].each do |type|
|
48
|
+
if options[type]
|
49
|
+
if(options[type] =~ /:/)
|
50
|
+
from = options[type]
|
51
|
+
else
|
52
|
+
from, ignore, exclusive, to = options[type].to_s.match(/(\w+)(\.\.(\.?)(\w+))?/)[1..4].map { |m| m.gsub(/s$/i, '') if m }
|
53
|
+
end
|
54
|
+
|
55
|
+
parse = Date._parse(from)
|
56
|
+
range = to ? Date._parse(to) : {}
|
57
|
+
|
58
|
+
month ||= get_value(parse, range, exclusive == '.', :mon)
|
59
|
+
wday ||= get_value(parse, range, exclusive == '.', :wday)
|
60
|
+
mday ||= get_value(parse, range, exclusive == '.', :mday)
|
61
|
+
hour ||= get_value(parse, range, exclusive == '.', :hour)
|
62
|
+
min ||= get_value(parse, range, exclusive == '.', :min)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# deal with any arrays and ranges
|
67
|
+
min, hour, mday, wday, month = [min, hour, mday, wday, month].map do |type|
|
68
|
+
type.respond_to?(:map) ? type.map.join(',') : type
|
69
|
+
end
|
70
|
+
|
71
|
+
# special cases with hours
|
72
|
+
hour ||= options[:at].to_i if options[:at] # :at => "5 o'clock" / "5" / 5
|
73
|
+
|
74
|
+
# fill missing items
|
75
|
+
hour, min = [hour, min].map { |t| t || '0' }
|
76
|
+
month, wday, mday = [month, wday, mday].map { |t| t || '*' }
|
77
|
+
|
78
|
+
# put it together
|
79
|
+
@tabs << "#{min} #{hour} #{mday} #{month} #{wday} #{command}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def tabs
|
83
|
+
@tabs.join("\n")
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
def get_value(from, to, exclusive, on)
|
88
|
+
value = (from[on] and to[on]) ? Range.new(from[on], to[on], exclusive) : from[on]
|
89
|
+
if value.is_a?(Range) and value.first > value.last
|
90
|
+
reverse = (value.last.to_i+(exclusive ? 0 : 1)..(value.first.to_i-1))
|
91
|
+
range = case on
|
92
|
+
when :mon then 1..12
|
93
|
+
when :wday then 0..6
|
94
|
+
when :mday then 1..31
|
95
|
+
end
|
96
|
+
value = range.map - reverse.map
|
97
|
+
end
|
98
|
+
value
|
99
|
+
end
|
100
|
+
|
101
|
+
def enum_to_i(element, type)
|
102
|
+
element.kind_of?(type) ? element.to_i : element
|
103
|
+
end
|
104
|
+
end
|
data/spec/craken_spec.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
RAILS_ROOT = "foo/bar/baz"
|
2
|
+
RAILS_ENV = "test"
|
3
|
+
ENV['app_name'] = "craken_test"
|
4
|
+
ENV['raketab_rails_env'] = "test"
|
5
|
+
ENV['rake_exe'] = '/usr/bin/bundle exec rake'
|
6
|
+
|
7
|
+
require File.dirname(__FILE__) + "/../lib/craken"
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
describe Craken do
|
11
|
+
|
12
|
+
include Craken
|
13
|
+
|
14
|
+
describe "load_and_strip" do
|
15
|
+
|
16
|
+
it "should load the user's installed crontab" do
|
17
|
+
# figured out how to do this from here:
|
18
|
+
# http://jakescruggs.blogspot.com/2007/11/mocking-backticks-and-other-kernel.html
|
19
|
+
self.should_receive(:`).with(/crontab -l/).and_return('')
|
20
|
+
load_and_strip
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should strip out preinstalled raketab commands associated with the project" do
|
24
|
+
|
25
|
+
crontab = <<EOS
|
26
|
+
### craken_test test raketab start
|
27
|
+
this is a test
|
28
|
+
one more line
|
29
|
+
### craken_test test raketab end
|
30
|
+
EOS
|
31
|
+
|
32
|
+
self.should_receive(:`).with(/crontab -l/).and_return(crontab)
|
33
|
+
load_and_strip.should be_empty
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not strip out preinstalled raketab commands not associated with the project" do
|
37
|
+
|
38
|
+
crontab = <<EOS
|
39
|
+
1 2 3 4 5 blah blah
|
40
|
+
### craken_test test raketab start
|
41
|
+
this is a test
|
42
|
+
one more line
|
43
|
+
### craken_test test raketab end
|
44
|
+
6 7 8 9 10 foo bar
|
45
|
+
EOS
|
46
|
+
|
47
|
+
self.should_receive(:`).with(/crontab -l/).and_return(crontab)
|
48
|
+
load_and_strip.should == "1 2 3 4 5 blah blah\n6 7 8 9 10 foo bar\n"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "append_tasks" do
|
53
|
+
before(:each) do
|
54
|
+
@crontab = "1 2 3 4 5 blah blah\n6 7 8 9 10 foo bar\n"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should add comments to the beginning and end of the rake tasks it adds to crontab" do
|
58
|
+
raketab = "0 1 0 0 0 foo:bar"
|
59
|
+
cron = append_tasks(@crontab, raketab)
|
60
|
+
cron.should match(/### craken_test test raketab start\n0 1 0 0 0 /)
|
61
|
+
cron.should match(/### craken_test test raketab end\n$/)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should ignore comments in the raketab string" do
|
65
|
+
raketab = <<EOS
|
66
|
+
# comment to ignore
|
67
|
+
0 1 0 0 0 foo:bar
|
68
|
+
# another comment to ignore
|
69
|
+
EOS
|
70
|
+
cron = append_tasks(@crontab, raketab)
|
71
|
+
cron.should_not match(/# comment to ignore/)
|
72
|
+
cron.should_not match(/# another comment to ignore/)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should not munge the eight crontab special strings" do
|
76
|
+
raketab = <<EOS
|
77
|
+
@reboot brush:teeth
|
78
|
+
@yearly dont_forget_girlfriends:birthday
|
79
|
+
@annually just_damn_remember:it
|
80
|
+
@monthly do_some:sport
|
81
|
+
@weekly get:stash
|
82
|
+
@daily take:shower
|
83
|
+
@midnight stop_working_on_os:projects
|
84
|
+
@hourly drink:water
|
85
|
+
EOS
|
86
|
+
cron = append_tasks(@crontab, raketab)
|
87
|
+
cron.should match(/@reboot (.*)/)
|
88
|
+
cron.should match(/@yearly (.*)/)
|
89
|
+
cron.should match(/@annually (.*)/)
|
90
|
+
cron.should match(/@monthly (.*)/)
|
91
|
+
cron.should match(/@weekly (.*)/)
|
92
|
+
cron.should match(/@daily (.*)/)
|
93
|
+
cron.should match(/@midnight (.*)/)
|
94
|
+
cron.should match(/@hourly (.*)/)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should not munge the crontab time configuration" do
|
98
|
+
raketab = <<EOS
|
99
|
+
0 1 0 0 0 foo:bar
|
100
|
+
1,2,3,4,5,6 0 7,8 4 5 baz:blarg
|
101
|
+
EOS
|
102
|
+
cron = append_tasks(@crontab, raketab)
|
103
|
+
cron.should match(/0 1 0 0 0 [^\d]/)
|
104
|
+
cron.should match(/1,2,3,4,5,6 0 7,8 4 5 [^\d]/)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should add a cd command, rake command and environment variables" do
|
108
|
+
raketab = "0 1 0 0 0 foo:bar"
|
109
|
+
cron = append_tasks(@crontab, raketab)
|
110
|
+
cron.should match(/0 1 0 0 0 cd #{Craken::DEPLOY_PATH} && #{Craken::RAKE_EXE} --silent RAILS_ENV=#{Craken::RAKETAB_RAILS_ENV} foo:bar/)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should use the rake command given via ENV['rake_exe']" do
|
114
|
+
raketab = "0 1 0 0 0 foo:bar"
|
115
|
+
cron = append_tasks(@crontab, raketab)
|
116
|
+
cron.should include('/usr/bin/bundle exec rake')
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should ignore additional data at the end of the configuration" do
|
120
|
+
raketab = "0 1 0 0 0 foo:bar >> /tmp/foobar.log 2>&1"
|
121
|
+
cron = append_tasks(@crontab, raketab)
|
122
|
+
cron.should match(/0 1 0 0 0 cd #{Craken::DEPLOY_PATH} && #{Craken::RAKE_EXE} --silent RAILS_ENV=#{Craken::RAKETAB_RAILS_ENV} foo:bar >> \/tmp\/foobar.log 2>&1/)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "install" do
|
127
|
+
it "should install crontab by creating a temporary file, running crontab, then deleting the temp file" do
|
128
|
+
crontab = "crontab"
|
129
|
+
file_handle = mock("file handle")
|
130
|
+
file_handle.should_receive(:write).with(crontab)
|
131
|
+
File.should_receive(:open).with(/.crontab[0-9]*/, 'w').and_yield(file_handle)
|
132
|
+
self.should_receive(:`).with(/crontab .crontab[0-9]*$/)
|
133
|
+
FileUtils.should_receive(:rm).with(/.crontab[0-9]*/)
|
134
|
+
install(crontab)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
describe Enumeration do
|
2
|
+
Weekday = enum %w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday]
|
3
|
+
|
4
|
+
describe 'creation' do
|
5
|
+
it "should create an enumeration by Enumeration.generate, Enumeration(), or enum" do
|
6
|
+
ABC1 = Enumeration.generate(%w[a b c])
|
7
|
+
ABC1.units.should == [ABC1::A, ABC1::B, ABC1::C]
|
8
|
+
|
9
|
+
ABC2 = Enumeration(%w[a b c])
|
10
|
+
ABC2.units.should == [ABC1::A, ABC1::B, ABC1::C]
|
11
|
+
|
12
|
+
ABC3 = enum %w[a b c]
|
13
|
+
ABC3.units.should == [ABC1::A, ABC1::B, ABC1::C]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should not generate an enumeration itself" do
|
17
|
+
ABC4 = enum %w[a b c]
|
18
|
+
ABC4.methods.grep(/generate/).should be_empty
|
19
|
+
lambda{ ABC4.generate(%w[a b c]) }.should raise_error(NoMethodError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should allow an offset from zero to be specified" do
|
23
|
+
ABC = enum %w[a b c], 1
|
24
|
+
ABC.offset.should == 1
|
25
|
+
ABC.size.should == 3
|
26
|
+
ABC.units.map { |l| l.to_i }.should == [1,2,3]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'properties' do
|
31
|
+
it "should generate the right size of elements" do
|
32
|
+
Weekday.units.size.should == 7
|
33
|
+
Weekday.size.should == Weekday.units.size
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should generate an enumeration based on an collection of names" do
|
37
|
+
# full names
|
38
|
+
Weekday.names.should == %w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday]
|
39
|
+
Weekday.units.should ==
|
40
|
+
[Weekday::SUNDAY, Weekday::MONDAY, Weekday::TUESDAY, Weekday::WEDNESDAY, Weekday::THURSDAY, Weekday::FRIDAY, Weekday::SATURDAY]
|
41
|
+
|
42
|
+
# abbreviationss
|
43
|
+
Weekday.abbrs.should == %w[Sun Mon Tue Wed Thu Fri Sat]
|
44
|
+
Weekday.units.should ==
|
45
|
+
[Weekday::SUN, Weekday::MON, Weekday::TUE, Weekday::WED, Weekday::THU, Weekday::FRI, Weekday::SAT]
|
46
|
+
Weekday.units.map { |w| w.to_i }.should == (0..6).map
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should get units based on integer value" do
|
50
|
+
(0..6).each do |value|
|
51
|
+
Weekday.for(value).should == Weekday.units[value]
|
52
|
+
end
|
53
|
+
|
54
|
+
# and respect offsets
|
55
|
+
(1..3).each do |value|
|
56
|
+
ABC.for(value).should == ABC.units[value - ABC.offset]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should be enumerable on the units" do
|
61
|
+
Weekday.methods.grep(/^each$/).should == %w[each]
|
62
|
+
Weekday.is_a?(Enumerable)
|
63
|
+
Weekday.map {|x| x.to_i }.should == Weekday.units.map {|x| x.to_i }
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not be able to create new units" do
|
67
|
+
lambda { Weekday.new(7) }.should raise_error(NoMethodError)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'units' do
|
72
|
+
it "should be comparable" do
|
73
|
+
Weekday::SUN.methods.grep(/^succ$/).should == %w[succ]
|
74
|
+
Weekday::SUN.is_a?(Comparable)
|
75
|
+
Weekday::SUN.should < Weekday::MON
|
76
|
+
Weekday::SUN.should <= Weekday::MON
|
77
|
+
Weekday::MON.should > Weekday::SUN
|
78
|
+
Weekday::MON.should >= Weekday::SUN
|
79
|
+
Weekday::SUN.should == Weekday::SUN
|
80
|
+
Weekday::WED.between?(Weekday::MON, Weekday::FRI).should be_true
|
81
|
+
Weekday::FRI.between?(Weekday::THU, Weekday::SUN).should be_true # if a ring
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
# this should be configurable!? is true for now!
|
86
|
+
it "should be a ring of values (cross boundries)" do
|
87
|
+
Weekday::SAT.succ.should == Weekday::SUN
|
88
|
+
Weekday::SUN.succ.should == Weekday::MON
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should work in a range" do
|
92
|
+
(Weekday::MON..Weekday::FRI).map.should == Weekday.units[1..5]
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should have to_s be it's name" do
|
96
|
+
%w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday].each do |name|
|
97
|
+
Weekday.for(name).to_s.should == name
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should have to_abbr to get it's three letter abbreviation" do
|
102
|
+
%w[Sun Mon Tue Wed Thu Fri Sat].each do |abbr|
|
103
|
+
Weekday.for(abbr).to_abbr.should == abbr
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should show the enumerable name and unit name in inspect" do
|
108
|
+
%w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday].each do |name|
|
109
|
+
Weekday.for(name).inspect.should == "#<Weekday:#{name}>"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should use integer values in arithmatic (+/-) and return another unit" do
|
114
|
+
Weekday.each_with_index do |w,i|
|
115
|
+
(Weekday::SUN + i).should == w
|
116
|
+
end
|
117
|
+
Weekday.map.reverse.each_with_index do |w,i|
|
118
|
+
(Weekday::SUN - i - 1).should == w
|
119
|
+
end
|
120
|
+
# ring / identity
|
121
|
+
(Weekday::SUN + 7).should == Weekday::SUN
|
122
|
+
(Weekday::SUN - 7).should == Weekday::SUN
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should use integer values in arithmatic (+/-) and return another unit with coersion to weekday on integer" do
|
126
|
+
Weekday.each_with_index do |w,i|
|
127
|
+
(1 + w).should == Weekday.map[(i+1) % Weekday.size]
|
128
|
+
end
|
129
|
+
Weekday.each_with_index do |w,i|
|
130
|
+
(i - w).should == Weekday::SUN
|
131
|
+
end
|
132
|
+
(0 + Weekday::MON).should == Weekday::MON
|
133
|
+
(2 - Weekday::MON).should == Weekday::MON
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
describe Raketab do
|
2
|
+
it "should have defaults (0 for hour, minutes and * for days and months)" do
|
3
|
+
Raketab.schedule { run 'test' }.tabs.should == '0 0 * * * test'
|
4
|
+
end
|
5
|
+
|
6
|
+
it "should set all the fields by name" do
|
7
|
+
Raketab.schedule { run 'test', :min => 1 }.tabs.should == "1 0 * * * test"
|
8
|
+
Raketab.schedule { run 'test', :minute => 1 }.tabs.should == "1 0 * * * test"
|
9
|
+
Raketab.schedule { run 'test', :hour => 1 }.tabs.should == "0 1 * * * test"
|
10
|
+
Raketab.schedule { run 'test', :day => 1 }.tabs.should == "0 0 1 * * test"
|
11
|
+
Raketab.schedule { run 'test', :mday => 1 }.tabs.should == "0 0 1 * * test"
|
12
|
+
Raketab.schedule { run 'test', :month => 1 }.tabs.should == "0 0 * 1 * test"
|
13
|
+
Raketab.schedule { run 'test', :mon => 1 }.tabs.should == "0 0 * 1 * test"
|
14
|
+
Raketab.schedule { run 'test', :wday => 1 }.tabs.should == "0 0 * * 1 test"
|
15
|
+
Raketab.schedule { run 'test', :weekday => 1 }.tabs.should == "0 0 * * 1 test"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should set month and weekday fields by method name" do
|
19
|
+
Raketab.schedule { run 'test', :month => january }.tabs.should == "0 0 * 1 * test"
|
20
|
+
Raketab.schedule { run 'test', :mon => jan }.tabs.should == "0 0 * 1 * test"
|
21
|
+
Raketab.schedule { run 'test', :wday => monday }.tabs.should == "0 0 * * 1 test"
|
22
|
+
Raketab.schedule { run 'test', :weekday => mon }.tabs.should == "0 0 * * 1 test"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should set the fields by comma string" do
|
26
|
+
Raketab.schedule { run 'test', :minutes => '1,2,3' }.tabs.should == "1,2,3 0 * * * test"
|
27
|
+
Raketab.schedule { run 'test', :hours => '1,2,3' }.tabs.should == "0 1,2,3 * * * test"
|
28
|
+
Raketab.schedule { run 'test', :days => '1,2,3' }.tabs.should == "0 0 1,2,3 * * test"
|
29
|
+
Raketab.schedule { run 'test', :months => '1,2,3' }.tabs.should == "0 0 * 1,2,3 * test"
|
30
|
+
Raketab.schedule { run 'test', :weekdays => '1,2,3' }.tabs.should == "0 0 * * 1,2,3 test"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should set the fields by array populated by method names" do
|
34
|
+
Raketab.schedule { run 'test', :months => [jan,feb,mar] }.tabs.should == "0 0 * 1,2,3 * test"
|
35
|
+
Raketab.schedule { run 'test', :weekdays => [mon,tue,wed] }.tabs.should == "0 0 * * 1,2,3 test"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should set the fields by array" do
|
39
|
+
Raketab.schedule { run 'test', :minutes => [1,2,3] }.tabs.should == "1,2,3 0 * * * test"
|
40
|
+
Raketab.schedule { run 'test', :hours => [1,2,3] }.tabs.should == "0 1,2,3 * * * test"
|
41
|
+
Raketab.schedule { run 'test', :days => [1,2,3] }.tabs.should == "0 0 1,2,3 * * test"
|
42
|
+
Raketab.schedule { run 'test', :months => [1,2,3] }.tabs.should == "0 0 * 1,2,3 * test"
|
43
|
+
Raketab.schedule { run 'test', :weekdays => [1,2,3] }.tabs.should == "0 0 * * 1,2,3 test"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should set the fields by inclusive ranges" do
|
47
|
+
Raketab.schedule { run 'test', :minutes => 1..3 }.tabs.should == "1,2,3 0 * * * test"
|
48
|
+
Raketab.schedule { run 'test', :hours => 1..3 }.tabs.should == "0 1,2,3 * * * test"
|
49
|
+
Raketab.schedule { run 'test', :days => 1..3 }.tabs.should == "0 0 1,2,3 * * test"
|
50
|
+
Raketab.schedule { run 'test', :months => 1..3 }.tabs.should == "0 0 * 1,2,3 * test"
|
51
|
+
Raketab.schedule { run 'test', :weekdays => 1..3 }.tabs.should == "0 0 * * 1,2,3 test"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should set the fields by exclusive ranges" do
|
55
|
+
Raketab.schedule { run 'test', :minutes => 1...4 }.tabs.should == "1,2,3 0 * * * test"
|
56
|
+
Raketab.schedule { run 'test', :hours => 1...4 }.tabs.should == "0 1,2,3 * * * test"
|
57
|
+
Raketab.schedule { run 'test', :days => 1...4 }.tabs.should == "0 0 1,2,3 * * test"
|
58
|
+
Raketab.schedule { run 'test', :months => 1...4 }.tabs.should == "0 0 * 1,2,3 * test"
|
59
|
+
Raketab.schedule { run 'test', :weekdays => 1...4 }.tabs.should == "0 0 * * 1,2,3 test"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should set weekday with symbol or string of the day name or abbreviation" do
|
63
|
+
Raketab.schedule { run 'test', :on => :thursday }.tabs.should == '0 0 * * 4 test'
|
64
|
+
Raketab.schedule { run 'test', :on => 'Thursday' }.tabs.should == '0 0 * * 4 test'
|
65
|
+
Raketab.schedule { run 'test', :on => :thu }.tabs.should == '0 0 * * 4 test'
|
66
|
+
Raketab.schedule { run 'test', :on => 'Thurs' }.tabs.should == '0 0 * * 4 test'
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
it "should set month with symbol or string of the month name or abbreviation" do
|
71
|
+
Raketab.schedule { run 'test', :on => :september }.tabs.should == '0 0 * 9 * test'
|
72
|
+
Raketab.schedule { run 'test', :on => 'September' }.tabs.should == '0 0 * 9 * test'
|
73
|
+
Raketab.schedule { run 'test', :on => :sep }.tabs.should == '0 0 * 9 * test'
|
74
|
+
Raketab.schedule { run 'test', :on => 'Sep' }.tabs.should == '0 0 * 9 * test'
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should set month with any syntactic sugar" do
|
78
|
+
Raketab.schedule { run 'test', :every => :september }.tabs.should == '0 0 * 9 * test'
|
79
|
+
Raketab.schedule { run 'test', :each => :september }.tabs.should == '0 0 * 9 * test'
|
80
|
+
Raketab.schedule { run 'test', :on => :september }.tabs.should == '0 0 * 9 * test'
|
81
|
+
Raketab.schedule { run 'test', :in => :september }.tabs.should == '0 0 * 9 * test'
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should set day with any syntactic sugar" do
|
85
|
+
Raketab.schedule { run 'test', :every => '1st' }.tabs.should == '0 0 1 * * test'
|
86
|
+
Raketab.schedule { run 'test', :each => '2nd' }.tabs.should == '0 0 2 * * test'
|
87
|
+
Raketab.schedule { run 'test', :the => '3rd' }.tabs.should == '0 0 3 * * test'
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should set the time of day, with AM/PM or military time" do
|
91
|
+
Raketab.schedule { run 'no meridiem', :at => '12:30' }.tabs.should == '30 12 * * * no meridiem'
|
92
|
+
Raketab.schedule { run 'am meridiem', :at => '12:30AM' }.tabs.should == '30 0 * * * am meridiem'
|
93
|
+
Raketab.schedule { run 'pm meridiem', :at => '12:30PM' }.tabs.should == '30 12 * * * pm meridiem'
|
94
|
+
Raketab.schedule { run 'military', :at => '23:30' }.tabs.should == '30 23 * * * military'
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should set all the fields if they are all provided" do
|
98
|
+
Raketab.schedule do |t|
|
99
|
+
t.run 'test', :every => :sep, :the => '1st', :on => :thursdays, :at => "12:30"
|
100
|
+
end.tabs.should == "30 12 1 9 4 test"
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should set the range of months" do
|
104
|
+
Raketab.schedule { run 'inclusive full', :in => 'September..November' }.tabs.should == '0 0 * 9,10,11 * inclusive full'
|
105
|
+
Raketab.schedule { run 'exclusive full', :in => 'September...December' }.tabs.should == '0 0 * 9,10,11 * exclusive full'
|
106
|
+
Raketab.schedule { run 'inclusive abbr', :in => 'Sep..Nov' }.tabs.should == '0 0 * 9,10,11 * inclusive abbr'
|
107
|
+
Raketab.schedule { run 'exclusive abbr', :in => 'Sep...Dec' }.tabs.should == '0 0 * 9,10,11 * exclusive abbr'
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should set the range of months across year boundry" do
|
111
|
+
Raketab.schedule { run 'inclusive full reverse', :in => 'November..January' }.tabs.should == '0 0 * 1,11,12 * inclusive full reverse'
|
112
|
+
Raketab.schedule { run 'exclusive full reverse', :in => 'November...February' }.tabs.should == '0 0 * 1,11,12 * exclusive full reverse'
|
113
|
+
Raketab.schedule { run 'inclusive abbr reverse', :in => 'Nov..Jan' }.tabs.should == '0 0 * 1,11,12 * inclusive abbr reverse'
|
114
|
+
Raketab.schedule { run 'exclusive abbr reverse', :in => 'Nov...Feb' }.tabs.should == '0 0 * 1,11,12 * exclusive abbr reverse'
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should set the range of days" do
|
118
|
+
Raketab.schedule { run 'inclusive full', :on => 'Monday..Thursday' }.tabs.should == '0 0 * * 1,2,3,4 inclusive full'
|
119
|
+
Raketab.schedule { run 'exclusive full', :on => 'Monday...Friday' }.tabs.should == '0 0 * * 1,2,3,4 exclusive full'
|
120
|
+
Raketab.schedule { run 'inclusive abbr', :on => 'Mon..Thur' }.tabs.should == '0 0 * * 1,2,3,4 inclusive abbr'
|
121
|
+
Raketab.schedule { run 'exclusive abbr', :on => 'Mon...Fri' }.tabs.should == '0 0 * * 1,2,3,4 exclusive abbr'
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should set the range of days across week boundry" do
|
125
|
+
Raketab.schedule { run 'inclusive full', :on => 'Thursday..Monday' }.tabs.should == '0 0 * * 0,1,4,5,6 inclusive full'
|
126
|
+
Raketab.schedule { run 'exclusive full', :on => 'Thursday...Monday' }.tabs.should == '0 0 * * 0,4,5,6 exclusive full'
|
127
|
+
Raketab.schedule { run 'inclusive abbr', :on => 'Thu..Mon' }.tabs.should == '0 0 * * 0,1,4,5,6 inclusive abbr'
|
128
|
+
Raketab.schedule { run 'exclusive abbr', :on => 'Thu...Mon' }.tabs.should == '0 0 * * 0,4,5,6 exclusive abbr'
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should set the range of months using month name methods" do
|
132
|
+
Raketab.schedule { run 'inclusive full', :in => september..november }.tabs.should == '0 0 * 9,10,11 * inclusive full'
|
133
|
+
Raketab.schedule { run 'exclusive full', :in => september...december }.tabs.should == '0 0 * 9,10,11 * exclusive full'
|
134
|
+
Raketab.schedule { run 'inclusive abbr', :in => sep..nov }.tabs.should == '0 0 * 9,10,11 * inclusive abbr'
|
135
|
+
Raketab.schedule { run 'exclusive abbr', :in => sep...dec }.tabs.should == '0 0 * 9,10,11 * exclusive abbr'
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should set the range of months across year boundry using month name methods" do
|
139
|
+
Raketab.schedule { run 'inclusive full reverse', :in => november..january }.tabs.should == '0 0 * 1,11,12 * inclusive full reverse'
|
140
|
+
Raketab.schedule { run 'exclusive full reverse', :in => november...february }.tabs.should == '0 0 * 1,11,12 * exclusive full reverse'
|
141
|
+
Raketab.schedule { run 'inclusive abbr reverse', :in => nov..jan }.tabs.should == '0 0 * 1,11,12 * inclusive abbr reverse'
|
142
|
+
Raketab.schedule { run 'exclusive abbr reverse', :in => nov...feb }.tabs.should == '0 0 * 1,11,12 * exclusive abbr reverse'
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should set the range of days using weekday name methods" do
|
146
|
+
Raketab.schedule { run 'inclusive full', :on => monday..thursday }.tabs.should == '0 0 * * 1,2,3,4 inclusive full'
|
147
|
+
Raketab.schedule { run 'exclusive full', :on => monday...friday }.tabs.should == '0 0 * * 1,2,3,4 exclusive full'
|
148
|
+
Raketab.schedule { run 'inclusive abbr', :on => mon..thu }.tabs.should == '0 0 * * 1,2,3,4 inclusive abbr'
|
149
|
+
Raketab.schedule { run 'exclusive abbr', :on => mon...fri }.tabs.should == '0 0 * * 1,2,3,4 exclusive abbr'
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should set the range of days across week boundry using weekday name methods" do
|
153
|
+
Raketab.schedule { run 'inclusive full', :on => thursday..monday }.tabs.should == '0 0 * * 0,1,4,5,6 inclusive full'
|
154
|
+
Raketab.schedule { run 'exclusive full', :on => thursday...monday }.tabs.should == '0 0 * * 0,4,5,6 exclusive full'
|
155
|
+
Raketab.schedule { run 'inclusive abbr', :on => thu..mon }.tabs.should == '0 0 * * 0,1,4,5,6 inclusive abbr'
|
156
|
+
Raketab.schedule { run 'exclusive abbr', :on => thu...mon }.tabs.should == '0 0 * * 0,4,5,6 exclusive abbr'
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should set the time with just a number on at" do
|
160
|
+
Raketab.schedule { run 'test', :at => "5 o'clock" }.tabs.should == '0 5 * * * test'
|
161
|
+
Raketab.schedule { run 'test', :at => "5" }.tabs.should == '0 5 * * * test'
|
162
|
+
Raketab.schedule { run 'test', :at => 5 }.tabs.should == '0 5 * * * test'
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should handle multiple cron jobs" do
|
166
|
+
Raketab.schedule do
|
167
|
+
run '1st', :at => "5 o'clock"
|
168
|
+
run '2nd', :on => :thursday
|
169
|
+
end.tabs.should == "0 5 * * * 1st\n0 0 * * 4 2nd"
|
170
|
+
end
|
171
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: did_craken
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Doug McInnes
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-02-14 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Craken is a rails plugin for managing and installing rake-centric crontab files over Capistrano.
|
23
|
+
email:
|
24
|
+
- didier@nocoffee.fr
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files:
|
30
|
+
- README.rdoc
|
31
|
+
files:
|
32
|
+
- lib/craken.rb
|
33
|
+
- lib/enumeration.rb
|
34
|
+
- lib/raketab.rb
|
35
|
+
- README.rdoc
|
36
|
+
- spec/craken_spec.rb
|
37
|
+
- spec/enumeration_spec.rb
|
38
|
+
- spec/raketab_spec.rb
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: https://github.com/latimes/craken
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options:
|
45
|
+
- --charset=UTF-8
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
hash: 3
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 3
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.4.2
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: A Rails plugin for managing and installing rake-centric crontab files.
|
73
|
+
test_files:
|
74
|
+
- spec/craken_spec.rb
|
75
|
+
- spec/enumeration_spec.rb
|
76
|
+
- spec/raketab_spec.rb
|