cwninja-whenever 0.1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +26 -0
- data/README.rdoc +127 -0
- data/Rakefile +26 -0
- data/bin/whenever +42 -0
- data/bin/wheneverize +69 -0
- data/lib/base.rb +15 -0
- data/lib/command_line.rb +68 -0
- data/lib/job_list.rb +90 -0
- data/lib/job_types/default.rb +27 -0
- data/lib/job_types/rake_task.rb +12 -0
- data/lib/job_types/runner.rb +12 -0
- data/lib/outputs/cron.rb +104 -0
- data/lib/version.rb +10 -0
- data/lib/whenever.rb +19 -0
- data/test/command_line_test.rb +63 -0
- data/test/cron_test.rb +187 -0
- data/test/output_command_test.rb +70 -0
- data/test/output_env_test.rb +23 -0
- data/test/output_rake_test.rb +74 -0
- data/test/output_runner_test.rb +125 -0
- data/test/test_helper.rb +33 -0
- data/whenever.gemspec +39 -0
- metadata +118 -0
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
== 0.1.5 / February 19th, 2009
|
2
|
+
|
3
|
+
* Fixed load path so Whenever's files don't conflict with anything in Rails. Thanks Ryan Koopmans. [Javan Makhmali]
|
4
|
+
|
5
|
+
|
6
|
+
== 0.1.4 / February 17th, 2009
|
7
|
+
|
8
|
+
* Added --load-file and --user opts to whenever binary. [Javan Makhmali]
|
9
|
+
|
10
|
+
|
11
|
+
== 0.1.3 / February 16th, 2009
|
12
|
+
|
13
|
+
* Added 'rake' helper for defining scheduled rake tasks. [Javan Makhmali]
|
14
|
+
|
15
|
+
* Renamed :cron_environment and :cron_path to :enviroment and :path for better (word) compatibility with rake tasks. [Javan Makhmali]
|
16
|
+
|
17
|
+
* Improved test load paths so tests can be run individually. [Javan Makhmali]
|
18
|
+
|
19
|
+
* Got rid of already initialized constant warning. [Javan Makhmali]
|
20
|
+
|
21
|
+
* Requiring specific gem versions: Chronic >=0.2.3 and activesupport >= 1.3.0 [Javan Makhmali]
|
22
|
+
|
23
|
+
|
24
|
+
== 0.1.0 / February 15th, 2009
|
25
|
+
|
26
|
+
* Initial release [Javan Makhmali]
|
data/README.rdoc
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
== Introduction
|
2
|
+
|
3
|
+
Whenever is a ruby gem that provides a ruby syntax for defining cron jobs. It outputs valid cron syntax and can even write your crontab file for you. It is designed to work well with Rails applications and can be deployed with Capistrano. Whenever works fine independently as well.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
Regular (non-Rails) install:
|
8
|
+
|
9
|
+
$ gem sources -a http://gems.github.com (you only need to run this once)
|
10
|
+
$ sudo gem install javan-whenever
|
11
|
+
|
12
|
+
In a Rails (2.1 or greater) application:
|
13
|
+
|
14
|
+
in your "config/environment.rb" file:
|
15
|
+
|
16
|
+
Rails::Initializer.run do |config|
|
17
|
+
config.gem 'javan-whenever', :lib => false, :version => '>= 0.1.5' :source => 'http://gems.github.com'
|
18
|
+
end
|
19
|
+
|
20
|
+
To install this gem (and all other missing gem dependencies), run rake gems:install (use sudo if necessary).
|
21
|
+
|
22
|
+
In older versions of Rails:
|
23
|
+
|
24
|
+
$ gem sources -a http://gems.github.com (you only need to run this once)
|
25
|
+
$ gem install javan-whenever
|
26
|
+
|
27
|
+
in your "config/environment.rb" file:
|
28
|
+
|
29
|
+
Rails::Initializer.run do |config|
|
30
|
+
...
|
31
|
+
end
|
32
|
+
|
33
|
+
require 'whenever'
|
34
|
+
|
35
|
+
NOTE: Requiring the whenever gem inside your Rails application is technically optional. However, if you plan to use something like Capistrano to automatically deploy and write your crontab file, you'll need to have the gem installed on your servers, and requiring it in your app is one to ensure this.
|
36
|
+
|
37
|
+
== Getting started
|
38
|
+
|
39
|
+
$ cd /my/rails/app
|
40
|
+
$ wheneverize .
|
41
|
+
|
42
|
+
This will create an initial "config/schedule.rb" file you.
|
43
|
+
|
44
|
+
== Example schedule.rb file
|
45
|
+
|
46
|
+
every 3.hours do
|
47
|
+
runner "MyModel.some_process"
|
48
|
+
rake "my:rake:task"
|
49
|
+
command "/usr/bin/my_great_command"
|
50
|
+
end
|
51
|
+
|
52
|
+
every 1.day, :at => '4:30 am' do
|
53
|
+
runner "DB.Backup"
|
54
|
+
end
|
55
|
+
|
56
|
+
every :hour do # Many shortcuts available: :hour, :day, :month, :year, :reboot
|
57
|
+
runner "SomeModel.ladeeda"
|
58
|
+
end
|
59
|
+
|
60
|
+
every :sunday do # Use any day of the week or :weekend, :weekday
|
61
|
+
runner "Task.do_something_great"
|
62
|
+
end
|
63
|
+
|
64
|
+
More examples on the wiki: http://wiki.github.com/javan/whenever/instructions-and-examples
|
65
|
+
|
66
|
+
== Cron output
|
67
|
+
|
68
|
+
$ cd /my/rails/app
|
69
|
+
$ whenever
|
70
|
+
|
71
|
+
And you'll see your schedule.rb converted to cron sytax
|
72
|
+
|
73
|
+
== Capistrano integration
|
74
|
+
|
75
|
+
in your "config/deploy.rb" file do something like:
|
76
|
+
|
77
|
+
after "deploy:symlink", "deploy:write_crontab"
|
78
|
+
|
79
|
+
namespace :deploy do
|
80
|
+
desc "write the crontab file"
|
81
|
+
task :write_crontab, :roles => :app do
|
82
|
+
run "cd #{release_path} && whenever --write-crontab"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
By mixing and matching the "--load-file" and "--user" options with your various :roles in Capistrano it is entirely possible to deploy different crontab schedules under different users to all your various servers. Get creative!
|
87
|
+
|
88
|
+
USING THE "--write-crontab" OPTION WILL COMPLETELY OVERWRITE ANY EXISTING CRONTAB ENTRIES!
|
89
|
+
|
90
|
+
You can use --update-crontab to simply update whenever generated tasks.
|
91
|
+
|
92
|
+
== Credit
|
93
|
+
|
94
|
+
Whenever was created for use at Inkling (http://inklingmarkets.com) where I work.
|
95
|
+
|
96
|
+
While building Whenever, I learned a lot by digging through the source code of Capistrano - http://github.com/jamis/capistrano
|
97
|
+
|
98
|
+
== Feedback
|
99
|
+
|
100
|
+
Lighthouse: http://javan.lighthouseapp.com/projects/25781-whenever/overview
|
101
|
+
|
102
|
+
Email me: javan [at] javan (dot) us
|
103
|
+
|
104
|
+
== License
|
105
|
+
|
106
|
+
Copyright (c) 2009 Javan Makhmali
|
107
|
+
|
108
|
+
Permission is hereby granted, free of charge, to any person
|
109
|
+
obtaining a copy of this software and associated documentation
|
110
|
+
files (the "Software"), to deal in the Software without
|
111
|
+
restriction, including without limitation the rights to use,
|
112
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
113
|
+
copies of the Software, and to permit persons to whom the
|
114
|
+
Software is furnished to do so, subject to the following
|
115
|
+
conditions:
|
116
|
+
|
117
|
+
The above copyright notice and this permission notice shall be
|
118
|
+
included in all copies or substantial portions of the Software.
|
119
|
+
|
120
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
121
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
122
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
123
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
124
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
125
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
126
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
127
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'echoe'
|
7
|
+
|
8
|
+
require File.expand_path(File.dirname(__FILE__) + "/lib/version")
|
9
|
+
|
10
|
+
Echoe.new('whenever', Whenever::VERSION::STRING) do |p|
|
11
|
+
p.description = "Provides clean ruby syntax for defining messy cron jobs and running them Whenever."
|
12
|
+
p.url = "http://github.com/javan/whenever"
|
13
|
+
p.author = "Javan Makhmali"
|
14
|
+
p.email = "javan@javan.us"
|
15
|
+
p.dependencies = ["chronic >=0.2.3", "activesupport >=1.3.0"]
|
16
|
+
end
|
17
|
+
rescue LoadError
|
18
|
+
puts "Could not load echoe"
|
19
|
+
end
|
20
|
+
|
21
|
+
Rake::TestTask.new do |t|
|
22
|
+
t.test_files = FileList['test/*_test.rb']
|
23
|
+
t.verbose = true
|
24
|
+
end
|
25
|
+
|
26
|
+
task :default => [:test]
|
data/bin/whenever
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'optparse'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'tempfile'
|
7
|
+
require 'whenever'
|
8
|
+
|
9
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/version")
|
10
|
+
|
11
|
+
options = Hash.new
|
12
|
+
|
13
|
+
OptionParser.new do |opts|
|
14
|
+
opts.banner = "Usage: whenever [options]"
|
15
|
+
opts.on('-v', '--version') { puts "Whenever v#{Whenever::VERSION::STRING}"; exit }
|
16
|
+
opts.on('-w', '--write-crontab') { options[:write] = true }
|
17
|
+
opts.on('-p', '--update-crontab') { options[:update] = true }
|
18
|
+
opts.on('-f', '--load-file [schedule file]', 'default: config/schedule.rb') do |file|
|
19
|
+
options[:file] = file if file
|
20
|
+
end
|
21
|
+
opts.on('-u', '--user [user]', 'default: current user') do |user|
|
22
|
+
options[:user] = user if user
|
23
|
+
end
|
24
|
+
end.parse!
|
25
|
+
|
26
|
+
options[:file] ||= 'config/schedule.rb'
|
27
|
+
|
28
|
+
unless File.exists?(options[:file])
|
29
|
+
warn("[fail] can't find file: #{options[:file]}")
|
30
|
+
exit(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
command_line = CommandLine.new(options)
|
34
|
+
|
35
|
+
if options[:write]
|
36
|
+
command_line.write!
|
37
|
+
elsif options[:update]
|
38
|
+
command_line.update!
|
39
|
+
else
|
40
|
+
puts Whenever.cron(:file => options[:file])
|
41
|
+
exit
|
42
|
+
end
|
data/bin/wheneverize
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# This file is based heavily on Capistrano's `capify` command
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: #{File.basename($0)} [path]"
|
10
|
+
|
11
|
+
begin
|
12
|
+
opts.parse!(ARGV)
|
13
|
+
rescue OptionParser::ParseError => e
|
14
|
+
warn e.message
|
15
|
+
puts opts
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
if ARGV.empty?
|
21
|
+
abort "Please specify the directory to wheneverize, e.g. `#{File.basename($0)} .'"
|
22
|
+
elsif !File.exists?(ARGV.first)
|
23
|
+
abort "`#{ARGV.first}' does not exist."
|
24
|
+
elsif !File.directory?(ARGV.first)
|
25
|
+
abort "`#{ARGV.first}' is not a directory."
|
26
|
+
elsif ARGV.length > 1
|
27
|
+
abort "Too many arguments; please specify only the directory to wheneverize."
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
content = <<-FILE
|
32
|
+
# Use this file to easily define all of your cron jobs.
|
33
|
+
#
|
34
|
+
# It's helpful, but not entirely necessary to understand cron before proceeding.
|
35
|
+
# http://en.wikipedia.org/wiki/Cron
|
36
|
+
|
37
|
+
# Example:
|
38
|
+
#
|
39
|
+
# set :cron_log, "/path/to/my/cron_log.log"
|
40
|
+
#
|
41
|
+
# every 2.hours do
|
42
|
+
# command "/usr/bin/some_great_command"
|
43
|
+
# runner "MyModel.some_method"
|
44
|
+
# rake "some:great:rake:task"
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# every 4.days do
|
48
|
+
# runner "AnotherModel.prune_old_records"
|
49
|
+
# end
|
50
|
+
|
51
|
+
# Learn more: http://github.com/javan/whenever
|
52
|
+
FILE
|
53
|
+
|
54
|
+
file = 'config/schedule.rb'
|
55
|
+
base = ARGV.shift
|
56
|
+
|
57
|
+
file = File.join(base, file)
|
58
|
+
if File.exists?(file)
|
59
|
+
warn "[skip] `#{file}' already exists"
|
60
|
+
elsif File.exists?(file.downcase)
|
61
|
+
warn "[skip] `#{file.downcase}' exists, which could conflict with `#{file}'"
|
62
|
+
elsif !File.exists?(File.dirname(file))
|
63
|
+
warn "[skip] directory `#{File.dirname(file)}' does not exist"
|
64
|
+
else
|
65
|
+
puts "[add] writing `#{file}'"
|
66
|
+
File.open(file, "w") { |f| f.write(content) }
|
67
|
+
end
|
68
|
+
|
69
|
+
puts "[done] wheneverized!"
|
data/lib/base.rb
ADDED
data/lib/command_line.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
class CommandLine
|
3
|
+
START_MARKER = "### BEGIN whenever generated crontab ###"
|
4
|
+
END_MARKER = "### END whenever generated crontab ###"
|
5
|
+
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def write!
|
13
|
+
cron_output = Whenever.cron(:file => options[:file])
|
14
|
+
write_crontab(cron_output)
|
15
|
+
end
|
16
|
+
|
17
|
+
def update!
|
18
|
+
before, after = strip_whenever_crontab(read_crontab)
|
19
|
+
whenever_cron = Whenever.cron(:file => options[:file])
|
20
|
+
write_crontab((before + [START_MARKER, whenever_cron, END_MARKER] + after).compact.join("\n"))
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def strip_whenever_crontab(existing_crontab)
|
25
|
+
return [], [] if existing_crontab.nil? or existing_crontab == ""
|
26
|
+
lines = existing_crontab.split("\n")
|
27
|
+
if start = lines.index(START_MARKER)
|
28
|
+
if finish = lines.index(END_MARKER)
|
29
|
+
return lines[0...start], lines[(finish + 1)..-1]
|
30
|
+
else
|
31
|
+
warn "[fail] could not find END marker in existing crontab"
|
32
|
+
exit(1)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
return lines, []
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def read_crontab
|
40
|
+
command = ['crontab']
|
41
|
+
command << "-u #{options[:user]}" if options[:user]
|
42
|
+
command << "-l"
|
43
|
+
|
44
|
+
IO.popen(command.join(' ')) do |io|
|
45
|
+
return io.read
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def write_crontab(data)
|
50
|
+
tmp_cron_file = Tempfile.new('whenever_tmp_cron').path
|
51
|
+
File.open(tmp_cron_file, File::WRONLY | File::APPEND) do |file|
|
52
|
+
file.puts data
|
53
|
+
end
|
54
|
+
|
55
|
+
command = ['crontab']
|
56
|
+
command << "-u #{options[:user]}" if options[:user]
|
57
|
+
command << tmp_cron_file
|
58
|
+
|
59
|
+
if system(command.join(' '))
|
60
|
+
puts "[write] crontab file updated"
|
61
|
+
exit
|
62
|
+
else
|
63
|
+
warn "[fail] couldn't write crontab"
|
64
|
+
exit(1)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
data/lib/job_list.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
module Whenever
|
2
|
+
class JobList
|
3
|
+
|
4
|
+
def initialize(options)
|
5
|
+
@jobs = Hash.new
|
6
|
+
@env = Hash.new
|
7
|
+
|
8
|
+
config = case options
|
9
|
+
when String then options
|
10
|
+
when Hash
|
11
|
+
if options[:string]
|
12
|
+
options[:string]
|
13
|
+
elsif options[:file]
|
14
|
+
File.read(options[:file])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
eval(config)
|
19
|
+
end
|
20
|
+
|
21
|
+
def set(variable, value)
|
22
|
+
instance_variable_set("@#{variable}".to_sym, value)
|
23
|
+
self.class.send(:attr_reader, variable.to_sym)
|
24
|
+
end
|
25
|
+
|
26
|
+
def env(variable, value)
|
27
|
+
@env[variable.to_s] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
def every(frequency, options = {})
|
31
|
+
@current_time_scope = frequency
|
32
|
+
@options = options
|
33
|
+
yield
|
34
|
+
end
|
35
|
+
|
36
|
+
def command(task, options = {})
|
37
|
+
options[:cron_log] ||= @cron_log unless options[:cron_log] === false
|
38
|
+
options[:class] ||= Whenever::Job::Default
|
39
|
+
@jobs[@current_time_scope] ||= []
|
40
|
+
@jobs[@current_time_scope] << options[:class].new(@options.merge(:task => task).merge(options))
|
41
|
+
end
|
42
|
+
|
43
|
+
def runner(task, options = {})
|
44
|
+
options.reverse_merge!(:environment => @environment, :path => @path)
|
45
|
+
options[:class] = Whenever::Job::Runner
|
46
|
+
command(task, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def rake(task, options = {})
|
50
|
+
options.reverse_merge!(:environment => @environment, :path => @path)
|
51
|
+
options[:class] = Whenever::Job::RakeTask
|
52
|
+
command(task, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def generate_cron_output
|
56
|
+
[environment_variables, cron_jobs].compact.join
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def environment_variables
|
62
|
+
return if @env.empty?
|
63
|
+
|
64
|
+
output = []
|
65
|
+
@env.each do |key, val|
|
66
|
+
output << "#{key}=#{val}\n"
|
67
|
+
end
|
68
|
+
output << "\n"
|
69
|
+
|
70
|
+
output.join
|
71
|
+
end
|
72
|
+
|
73
|
+
def cron_jobs
|
74
|
+
return if @jobs.empty?
|
75
|
+
|
76
|
+
output = []
|
77
|
+
@jobs.each do |time, jobs|
|
78
|
+
jobs.each do |job|
|
79
|
+
cron = Whenever::Output::Cron.output(time, job)
|
80
|
+
cron << " >> #{job.cron_log} 2>&1" if job.cron_log
|
81
|
+
cron << "\n\n"
|
82
|
+
output << cron
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
output.join
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Whenever
|
2
|
+
module Job
|
3
|
+
class Default
|
4
|
+
|
5
|
+
attr_accessor :task, :at, :cron_log
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@task = options[:task]
|
9
|
+
@at = options[:at]
|
10
|
+
@cron_log = options[:cron_log]
|
11
|
+
@environment = options[:environment] || :production
|
12
|
+
@path = options[:path] || Whenever.path
|
13
|
+
end
|
14
|
+
|
15
|
+
def output
|
16
|
+
task
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def path_required
|
22
|
+
raise ArgumentError, "No path available; set :path, '/your/path' in your schedule file" if @path.blank?
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/outputs/cron.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
module Whenever
|
2
|
+
module Output
|
3
|
+
|
4
|
+
class Cron
|
5
|
+
|
6
|
+
attr_accessor :time, :task
|
7
|
+
|
8
|
+
def initialize(time = nil, task = nil, at = nil)
|
9
|
+
@time = time
|
10
|
+
@task = task
|
11
|
+
@at = at.is_a?(String) ? (Chronic.parse(at) || 0) : (at || 0)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.output(time, job)
|
15
|
+
out = new(time, job.output, job.at)
|
16
|
+
"#{out.time_in_cron_syntax} #{out.task}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def time_in_cron_syntax
|
20
|
+
case @time
|
21
|
+
when Symbol then parse_symbol
|
22
|
+
when String then parse_as_string
|
23
|
+
else parse_time
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def parse_symbol
|
30
|
+
case @time
|
31
|
+
when :reboot then '@reboot'
|
32
|
+
when :year, :yearly then '@annually'
|
33
|
+
when :day, :daily then '@daily'
|
34
|
+
when :midnight then '@midnight'
|
35
|
+
when :month, :monthly then '@monthly'
|
36
|
+
when :week, :weekly then '@weekly'
|
37
|
+
when :hour, :hourly then '@hourly'
|
38
|
+
else parse_as_string
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_time
|
43
|
+
timing = Array.new(5, '*')
|
44
|
+
case @time
|
45
|
+
when 0.seconds...1.minute
|
46
|
+
raise ArgumentError, "Time must be in minutes or higher"
|
47
|
+
when 1.minute...1.hour
|
48
|
+
minute_frequency = @time / 60
|
49
|
+
timing[0] = comma_separated_timing(minute_frequency, 59)
|
50
|
+
when 1.hour...1.day
|
51
|
+
hour_frequency = (@time / 60 / 60).round
|
52
|
+
timing[0] = @at.is_a?(Time) ? @at.min : @at
|
53
|
+
timing[1] = comma_separated_timing(hour_frequency, 23)
|
54
|
+
when 1.day...1.month
|
55
|
+
day_frequency = (@time / 24 / 60 / 60).round
|
56
|
+
timing[0] = @at.is_a?(Time) ? @at.min : 0
|
57
|
+
timing[1] = @at.is_a?(Time) ? @at.hour : @at
|
58
|
+
timing[2] = comma_separated_timing(day_frequency, 31, 1)
|
59
|
+
when 1.month..12.months
|
60
|
+
month_frequency = (@time / 30 / 24 / 60 / 60).round
|
61
|
+
timing[0] = @at.is_a?(Time) ? @at.min : 0
|
62
|
+
timing[1] = @at.is_a?(Time) ? @at.hour : 0
|
63
|
+
timing[2] = @at.is_a?(Time) ? @at.day : (@at.zero? ? 1 : @at)
|
64
|
+
timing[3] = comma_separated_timing(month_frequency, 12, 1)
|
65
|
+
else
|
66
|
+
return parse_as_string
|
67
|
+
end
|
68
|
+
timing.join(' ')
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse_as_string
|
72
|
+
return unless @time
|
73
|
+
string = @time.to_s
|
74
|
+
|
75
|
+
return "0 0 * * mon-fri" if string.downcase.index('weekday')
|
76
|
+
return "0 0 * * sat,sun" if string.downcase.index('weekend')
|
77
|
+
|
78
|
+
%w(sun mon tue wed thu fri sat).each do |day|
|
79
|
+
return "0 0 * * #{day}" if string.downcase.index(day)
|
80
|
+
end
|
81
|
+
|
82
|
+
raise ArgumentError, "Couldn't parse: #{@time}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def comma_separated_timing(frequency, max, start = 0)
|
86
|
+
return start if frequency.blank? || frequency.zero?
|
87
|
+
return '*' if frequency == 1
|
88
|
+
return frequency if frequency > (max * 0.5).ceil
|
89
|
+
|
90
|
+
original_start = start
|
91
|
+
|
92
|
+
start += frequency unless (max + 1).modulo(frequency).zero? || start > 0
|
93
|
+
output = (start..max).step(frequency).to_a
|
94
|
+
|
95
|
+
max_occurances = (max.to_f / (frequency.to_f)).round
|
96
|
+
max_occurances += 1 if original_start.zero?
|
97
|
+
|
98
|
+
output[0, max_occurances].join(',')
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
data/lib/version.rb
ADDED
data/lib/whenever.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
unless defined?(Whenever)
|
2
|
+
$:.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
# Hoping to load Rails' Rakefile
|
5
|
+
begin
|
6
|
+
load 'Rakefile'
|
7
|
+
rescue LoadError => e
|
8
|
+
nil
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Dependencies
|
13
|
+
require 'activesupport'
|
14
|
+
require 'chronic'
|
15
|
+
|
16
|
+
# Whenever files
|
17
|
+
%w{ base version job_list job_types/default job_types/rake_task job_types/runner outputs/cron command_line}.each do |file|
|
18
|
+
require File.expand_path(File.dirname(__FILE__) + "/#{file}")
|
19
|
+
end
|