javan-whenever 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.1.6 / March 5th, 2009
2
+
3
+ * Added ability to update the crontab file non-destuctively instead of only overwriting it. [Javan Makhmali -- Inspired by code submitted individually from: Tien Dung (tiendung), Tom Lea (cwninja), Kyle Maxwell (fizx), and Andrew Timberlake (andrewtimberlake) on github]
4
+
1
5
  == 0.1.5 / February 19th, 2009
2
6
 
3
7
  * Fixed load path so Whenever's files don't conflict with anything in Rails. Thanks Ryan Koopmans. [Javan Makhmali]
data/README.rdoc CHANGED
@@ -1,12 +1,12 @@
1
1
  == Introduction
2
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.
3
+ Whenever is a Ruby gem that provides a clear 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
4
 
5
5
  == Installation
6
6
 
7
7
  Regular (non-Rails) install:
8
8
 
9
- $ gem sources -a http://gems.github.com (you only need to run this once)
9
+ $ gem sources -a http://gems.github.com #you only need to run this once
10
10
  $ sudo gem install javan-whenever
11
11
 
12
12
  In a Rails (2.1 or greater) application:
@@ -14,14 +14,14 @@ In a Rails (2.1 or greater) application:
14
14
  in your "config/environment.rb" file:
15
15
 
16
16
  Rails::Initializer.run do |config|
17
- config.gem 'javan-whenever', :lib => false, :version => '>= 0.1.5' :source => 'http://gems.github.com'
17
+ config.gem 'javan-whenever', :lib => false, :version => '>= 0.1.6' :source => 'http://gems.github.com'
18
18
  end
19
19
 
20
20
  To install this gem (and all other missing gem dependencies), run rake gems:install (use sudo if necessary).
21
21
 
22
22
  In older versions of Rails:
23
23
 
24
- $ gem sources -a http://gems.github.com (you only need to run this once)
24
+ $ gem sources -a http://gems.github.com #you only need to run this once
25
25
  $ gem install javan-whenever
26
26
 
27
27
  in your "config/environment.rb" file:
@@ -32,7 +32,7 @@ in your "config/environment.rb" file:
32
32
 
33
33
  require 'whenever'
34
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.
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 way to ensure this.
36
36
 
37
37
  == Getting started
38
38
 
@@ -42,7 +42,7 @@ NOTE: Requiring the whenever gem inside your Rails application is technically op
42
42
  This will create an initial "config/schedule.rb" file you.
43
43
 
44
44
  == Example schedule.rb file
45
-
45
+
46
46
  every 3.hours do
47
47
  runner "MyModel.some_process"
48
48
  rake "my:rake:task"
@@ -50,7 +50,7 @@ This will create an initial "config/schedule.rb" file you.
50
50
  end
51
51
 
52
52
  every 1.day, :at => '4:30 am' do
53
- runner "DB.Backup"
53
+ runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
54
54
  end
55
55
 
56
56
  every :hour do # Many shortcuts available: :hour, :day, :month, :year, :reboot
@@ -72,24 +72,26 @@ And you'll see your schedule.rb converted to cron sytax
72
72
 
73
73
  == Capistrano integration
74
74
 
75
- in your "config/deploy.rb" file do something like:
75
+ In your "config/deploy.rb" file do something like:
76
76
 
77
- after "deploy:symlink", "deploy:write_crontab"
77
+ after "deploy:symlink", "deploy:update_crontab"
78
78
 
79
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"
80
+ desc "Update the crontab file"
81
+ task :update_crontab, :roles => :db do
82
+ run "cd #{release_path} && whenever --update-crontab"
83
83
  end
84
84
  end
85
-
85
+
86
+ This will update your crontab file, leaving any existing entries unharmed. When using the "--update-crontab" option, Whenever will only update the entries in your crontab file related to the current schedule.rb file. This means you can use Whenever to deploy any number of apps to the same server and have them share a single crontab file peacefully.
87
+
88
+ If you wish to simply overwrite your crontab file each time you deploy, use the "--write-crontab" option. This is ideal if you are only working with one app and every crontab entry is contained in a single schedule.rb file.
89
+
86
90
  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
91
 
90
92
  == Credit
91
93
 
92
- Whenever was created for use at Inkling (http://inklingmarkets.com) where I work.
94
+ Whenever was created for use at Inkling (http://inklingmarkets.com) where I work. Their take on it: http://blog.inklingmarkets.com/2009/02/whenever-easy-way-to-do-cron-jobs-from.html
93
95
 
94
96
  While building Whenever, I learned a lot by digging through the source code of Capistrano - http://github.com/jamis/capistrano
95
97
 
data/bin/whenever CHANGED
@@ -14,40 +14,20 @@ OptionParser.new do |opts|
14
14
  opts.banner = "Usage: whenever [options]"
15
15
  opts.on('-v', '--version') { puts "Whenever v#{Whenever::VERSION::STRING}"; exit }
16
16
  opts.on('-w', '--write-crontab') { options[:write] = true }
17
- opts.on('-f', '--load-file [schedule file]', 'default: config/schedule.rb') do |file|
17
+ opts.on('-i', '--update-crontab [identifier]', 'Default: full path to schedule.rb file') do |identifier|
18
+ options[:update] = true
19
+ options[:identifier] = identifier if identifier
20
+ end
21
+ opts.on('-f', '--load-file [schedule file]', 'Default: config/schedule.rb') do |file|
18
22
  options[:file] = file if file
19
23
  end
20
- opts.on('-u', '--user [user]', 'default: current user') do |user|
24
+ opts.on('-u', '--user [user]', 'Default: current user') do |user|
21
25
  options[:user] = user if user
22
26
  end
23
27
  end.parse!
24
28
 
25
- options[:file] ||= 'config/schedule.rb'
26
-
27
- unless File.exists?(options[:file])
28
- warn("[fail] can't find file: #{options[:file]}")
29
- exit(1)
30
- end
31
-
32
- if options[:write]
33
- cron_output = Whenever.cron(:file => options[:file])
34
- tmp_cron_file = Tempfile.new('whenever_tmp_cron').path
35
- File.open(tmp_cron_file, File::WRONLY | File::APPEND) do |file|
36
- file << cron_output
37
- end
38
-
39
- command = ['crontab']
40
- command << "-u #{options[:user]}" if options[:user]
41
- command << tmp_cron_file
42
-
43
- if system(command.join(' '))
44
- puts "[write] crontab file updated"
45
- exit
46
- else
47
- warn "[fail] couldn't write crontab"
48
- exit(1)
49
- end
50
-
29
+ if options[:update] || options[:write]
30
+ Whenever::CommandLine.execute(options)
51
31
  else
52
32
  puts Whenever.cron(:file => options[:file])
53
33
  exit
@@ -0,0 +1,105 @@
1
+ module Whenever
2
+ class CommandLine
3
+
4
+ def self.execute(options={})
5
+ new(options).run
6
+ end
7
+
8
+ def initialize(options={})
9
+ @options = options
10
+
11
+ @options[:file] ||= 'config/schedule.rb'
12
+ @options[:identifier] ||= default_identifier
13
+
14
+ unless File.exists?(@options[:file])
15
+ warn("[fail] Can't find file: #{@options[:file]}")
16
+ exit(1)
17
+ end
18
+
19
+ if @options[:update] && @options[:write]
20
+ warn("[fail] Can't update AND write. choose one.")
21
+ exit(1)
22
+ end
23
+ end
24
+
25
+ def run
26
+ if @options[:update]
27
+ write_crontab(updated_crontab)
28
+ elsif @options[:write]
29
+ write_crontab(whenever_cron)
30
+ end
31
+ end
32
+
33
+ protected
34
+
35
+ def default_identifier
36
+ File.expand_path(@options[:file])
37
+ end
38
+
39
+ def whenever_cron
40
+ @whenever_cron ||= [comment_open, Whenever.cron(:file => @options[:file]), comment_close].join("\n")
41
+ end
42
+
43
+ def read_crontab
44
+ return @current_crontab if @current_crontab
45
+
46
+ command = ['crontab -l']
47
+ command << "-u #{@options[:user]}" if @options[:user]
48
+
49
+ command_results = %x[#{command.join(' ')} 2> /dev/null]
50
+ @current_crontab = $?.exitstatus.zero? ? command_results : ''
51
+ end
52
+
53
+ def write_crontab(contents)
54
+ tmp_cron_file = Tempfile.new('whenever_tmp_cron').path
55
+ File.open(tmp_cron_file, File::WRONLY | File::APPEND) do |file|
56
+ file << contents
57
+ end
58
+
59
+ command = ['crontab']
60
+ command << "-u #{@options[:user]}" if @options[:user]
61
+ command << tmp_cron_file
62
+
63
+ if system(command.join(' '))
64
+ action = 'written' if @options[:write]
65
+ action = 'updated' if @options[:update]
66
+ puts "[write] crontab file #{action}"
67
+ exit
68
+ else
69
+ warn "[fail] Couldn't write crontab; try running `whenever' with no options to ensure your schedule file is valid."
70
+ exit(1)
71
+ end
72
+ end
73
+
74
+ def updated_crontab
75
+ # Check for unopened or unclosed identifier blocks
76
+ if read_crontab.index(comment_open) && !read_crontab.index(comment_close)
77
+ warn "[fail] Unclosed indentifier; Your crontab file contains '#{comment_open}', but no '#{comment_close}'"
78
+ exit(1)
79
+ elsif !read_crontab.index(comment_open) && read_crontab.index(comment_close)
80
+ warn "[fail] Unopened indentifier; Your crontab file contains '#{comment_close}', but no '#{comment_open}'"
81
+ exit(1)
82
+ end
83
+
84
+ # If an existing identier block is found, replace it with the new cron entries
85
+ if read_crontab.index(comment_open) && read_crontab.index(comment_close)
86
+ read_crontab.gsub(Regexp.new("#{comment_open}.+#{comment_close}", Regexp::MULTILINE), whenever_cron)
87
+ else # Otherwise, append the new cron entries after any existing ones
88
+ [read_crontab, whenever_cron].join("\n\n")
89
+ end
90
+ end
91
+
92
+ def comment_base
93
+ "Whenever generated tasks for: #{@options[:identifier]}"
94
+ end
95
+
96
+ def comment_open
97
+ "# Begin #{comment_base}"
98
+ end
99
+
100
+ def comment_close
101
+ "# End #{comment_base}"
102
+ end
103
+
104
+ end
105
+ end
data/lib/version.rb CHANGED
@@ -2,7 +2,7 @@ module Whenever
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 5
5
+ TINY = 6
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/lib/whenever.rb CHANGED
@@ -14,6 +14,13 @@ require 'activesupport'
14
14
  require 'chronic'
15
15
 
16
16
  # Whenever files
17
- %w{ base version job_list job_types/default job_types/rake_task job_types/runner outputs/cron }.each do |file|
18
- require File.expand_path(File.dirname(__FILE__) + "/#{file}")
19
- end
17
+ %w{
18
+ base
19
+ version
20
+ job_list
21
+ job_types/default
22
+ job_types/rake_task
23
+ job_types/runner
24
+ outputs/cron
25
+ command_line
26
+ }.each { |file| require File.expand_path(File.dirname(__FILE__) + "/#{file}") }
@@ -0,0 +1,104 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/test_helper")
2
+
3
+ class CommandLineTest < Test::Unit::TestCase
4
+
5
+ context "A command line write" do
6
+ setup do
7
+ @command = Whenever::CommandLine.new(:write => true, :identifier => 'My identifier')
8
+ @task = "#{two_hours} /my/command"
9
+ Whenever.expects(:cron).returns(@task)
10
+ end
11
+
12
+ should "output the cron job with identifier blocks" do
13
+ output = <<-expected
14
+ # Begin Whenever generated tasks for: My identifier
15
+ #{@task}
16
+ # End Whenever generated tasks for: My identifier
17
+ expected
18
+
19
+ assert_equal unindent(output).chomp, @command.send(:whenever_cron).chomp
20
+ end
21
+
22
+ should "write the crontab when run" do
23
+ @command.expects(:write_crontab).returns(true)
24
+ assert @command.run
25
+ end
26
+ end
27
+
28
+ context "A command line update" do
29
+ setup do
30
+ @command = Whenever::CommandLine.new(:update => true, :identifier => 'My identifier')
31
+ @task = "#{two_hours} /my/command"
32
+ Whenever.expects(:cron).returns(@task)
33
+ end
34
+
35
+ should "add the cron to the end of the file if there is no existing identifier block" do
36
+ existing = '# Existing crontab'
37
+ @command.expects(:read_crontab).at_least_once.returns(existing)
38
+
39
+ new_cron = <<-expected
40
+ #{existing}
41
+
42
+ # Begin Whenever generated tasks for: My identifier
43
+ #{@task}
44
+ # End Whenever generated tasks for: My identifier
45
+ expected
46
+
47
+ assert_equal unindent(new_cron).chomp, @command.send(:updated_crontab).chomp
48
+
49
+ @command.expects(:write_crontab).with(unindent(new_cron)).returns(true)
50
+ assert @command.run
51
+ end
52
+
53
+ should "replace an existing block if the identifier matches" do
54
+ existing = <<-existing
55
+ # Something
56
+
57
+ # Begin Whenever generated tasks for: My identifier
58
+ My whenever job that was already here
59
+ # End Whenever generated tasks for: My identifier
60
+
61
+ # Begin Whenever generated tasks for: Other identifier
62
+ This shouldn't get replaced
63
+ # End Whenever generated tasks for: Other identifier
64
+ existing
65
+ @command.expects(:read_crontab).at_least_once.returns(unindent(existing))
66
+
67
+ new_cron = <<-new_cron
68
+ # Something
69
+
70
+ # Begin Whenever generated tasks for: My identifier
71
+ #{@task}
72
+ # End Whenever generated tasks for: My identifier
73
+
74
+ # Begin Whenever generated tasks for: Other identifier
75
+ This shouldn't get replaced
76
+ # End Whenever generated tasks for: Other identifier
77
+ new_cron
78
+
79
+ assert_equal unindent(new_cron).chomp, @command.send(:updated_crontab).chomp
80
+
81
+ @command.expects(:write_crontab).with(unindent(new_cron)).returns(true)
82
+ assert @command.run
83
+ end
84
+ end
85
+
86
+ context "A command line update with no identifier" do
87
+ setup do
88
+ Whenever::CommandLine.any_instance.expects(:default_identifier).returns('DEFAULT')
89
+ @command = Whenever::CommandLine.new(:update => true, :file => @file)
90
+ end
91
+
92
+ should "use the default identifier" do
93
+ assert_equal "Whenever generated tasks for: DEFAULT", @command.send(:comment_base)
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def unindent(string)
100
+ indentation = string[/\A\s*/]
101
+ string.strip.gsub(/^#{indentation}/, "")
102
+ end
103
+
104
+ end
data/whenever.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{whenever}
5
- s.version = "0.1.5"
5
+ s.version = "0.1.6"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Javan Makhmali"]
9
- s.date = %q{2009-02-19}
9
+ s.date = %q{2009-03-05}
10
10
  s.description = %q{Provides clean ruby syntax for defining messy cron jobs and running them Whenever.}
11
11
  s.email = %q{javan@javan.us}
12
12
  s.executables = ["whenever", "wheneverize"]
13
- s.extra_rdoc_files = ["bin/whenever", "bin/wheneverize", "CHANGELOG.rdoc", "lib/base.rb", "lib/job_list.rb", "lib/job_types/default.rb", "lib/job_types/rake_task.rb", "lib/job_types/runner.rb", "lib/outputs/cron.rb", "lib/version.rb", "lib/whenever.rb", "README.rdoc"]
14
- s.files = ["bin/whenever", "bin/wheneverize", "CHANGELOG.rdoc", "lib/base.rb", "lib/job_list.rb", "lib/job_types/default.rb", "lib/job_types/rake_task.rb", "lib/job_types/runner.rb", "lib/outputs/cron.rb", "lib/version.rb", "lib/whenever.rb", "Manifest", "Rakefile", "README.rdoc", "test/cron_test.rb", "test/output_command_test.rb", "test/output_env_test.rb", "test/output_rake_test.rb", "test/output_runner_test.rb", "test/test_helper.rb", "whenever.gemspec"]
13
+ s.extra_rdoc_files = ["bin/whenever", "bin/wheneverize", "CHANGELOG.rdoc", "lib/base.rb", "lib/command_line.rb", "lib/job_list.rb", "lib/job_types/default.rb", "lib/job_types/rake_task.rb", "lib/job_types/runner.rb", "lib/outputs/cron.rb", "lib/version.rb", "lib/whenever.rb", "README.rdoc"]
14
+ s.files = ["bin/whenever", "bin/wheneverize", "CHANGELOG.rdoc", "lib/base.rb", "lib/command_line.rb", "lib/job_list.rb", "lib/job_types/default.rb", "lib/job_types/rake_task.rb", "lib/job_types/runner.rb", "lib/outputs/cron.rb", "lib/version.rb", "lib/whenever.rb", "Manifest", "Rakefile", "README.rdoc", "test/command_line_test.rb", "test/cron_test.rb", "test/output_command_test.rb", "test/output_env_test.rb", "test/output_rake_test.rb", "test/output_runner_test.rb", "test/test_helper.rb", "whenever.gemspec"]
15
15
  s.has_rdoc = true
16
16
  s.homepage = %q{http://github.com/javan/whenever}
17
17
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Whenever", "--main", "README.rdoc"]
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.rubyforge_project = %q{whenever}
20
20
  s.rubygems_version = %q{1.3.1}
21
21
  s.summary = %q{Provides clean ruby syntax for defining messy cron jobs and running them Whenever.}
22
- s.test_files = ["test/cron_test.rb", "test/output_command_test.rb", "test/output_env_test.rb", "test/output_rake_test.rb", "test/output_runner_test.rb", "test/test_helper.rb"]
22
+ s.test_files = ["test/command_line_test.rb", "test/cron_test.rb", "test/output_command_test.rb", "test/output_env_test.rb", "test/output_rake_test.rb", "test/output_runner_test.rb", "test/test_helper.rb"]
23
23
 
24
24
  if s.respond_to? :specification_version then
25
25
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: javan-whenever
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Javan Makhmali
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-19 00:00:00 -08:00
12
+ date: 2009-03-05 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -44,6 +44,7 @@ extra_rdoc_files:
44
44
  - bin/wheneverize
45
45
  - CHANGELOG.rdoc
46
46
  - lib/base.rb
47
+ - lib/command_line.rb
47
48
  - lib/job_list.rb
48
49
  - lib/job_types/default.rb
49
50
  - lib/job_types/rake_task.rb
@@ -57,6 +58,7 @@ files:
57
58
  - bin/wheneverize
58
59
  - CHANGELOG.rdoc
59
60
  - lib/base.rb
61
+ - lib/command_line.rb
60
62
  - lib/job_list.rb
61
63
  - lib/job_types/default.rb
62
64
  - lib/job_types/rake_task.rb
@@ -67,6 +69,7 @@ files:
67
69
  - Manifest
68
70
  - Rakefile
69
71
  - README.rdoc
72
+ - test/command_line_test.rb
70
73
  - test/cron_test.rb
71
74
  - test/output_command_test.rb
72
75
  - test/output_env_test.rb
@@ -106,6 +109,7 @@ signing_key:
106
109
  specification_version: 2
107
110
  summary: Provides clean ruby syntax for defining messy cron jobs and running them Whenever.
108
111
  test_files:
112
+ - test/command_line_test.rb
109
113
  - test/cron_test.rb
110
114
  - test/output_command_test.rb
111
115
  - test/output_env_test.rb