whenever 0.4.1 → 0.5.2

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/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  .DS_Store
2
2
  pkg
3
- doc
3
+ doc
4
+ .*.sw[a-z]
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,34 @@
1
+ == 0.5.2 / September 15th, 2010
2
+
3
+ * Quotes automatically escaped in jobs. [Jay Adkisson]
4
+
5
+ * Added --cut option to the command line to allow pruning of the crontab. [Peer Allan]
6
+
7
+ * Switched to aaronh-chronic which is ruby 1.9.2 compatible. [Aaron Hurley, Javan Makhmali]
8
+
9
+ * Lots of internal reorganizing; tests broken into unit and functional. [Javan Makhmali]
10
+
11
+
12
+ == 0.5.0 / June 28th, 2010
13
+
14
+ * New job_type API for writing custom jobs. Internals use this to define command, runner, and rake. [Javan Makhmali - inspired by idlefingers (Damien)]
15
+
16
+ * Jobs < 1.hour can specify an :at. [gorenje]
17
+
18
+ * --clear option to remove crontab entries for a specific [identifier]. [mraidel (Michael Raidel)]
19
+
20
+
21
+ == 0.4.2 / April 26th, 2010
22
+
23
+ * runners now cd into the app's directory and then execute. [Michael Guterl]
24
+
25
+ * Fix STDERR output redirection to file to append instead of overwrite. [weplay]
26
+
27
+ * Move require of tempfile lib to file that actually uses it. [Finn Smith]
28
+
29
+ * bugfix: comparison Time with 0 failed. #32 [Dan Hixon]
30
+
31
+
1
32
  == 0.4.1 / November 30th, 2009
2
33
 
3
34
  * exit(0) instead of just exit to make JRuby happy. [Elan Meng]
data/README.rdoc CHANGED
@@ -7,18 +7,8 @@ Ryan Bates created a great Railscast about Whenever: http://railscasts.com/episo
7
7
  Discussion: http://groups.google.com/group/whenever-gem
8
8
 
9
9
  == Installation
10
-
11
- If you haven't already, get set up with http://gemcutter.org
12
-
13
- $ sudo gem install whenever
14
-
15
- In a Rails (2.1 or greater) application:
16
10
 
17
- in your "config/environment.rb" file:
18
-
19
- Rails::Initializer.run do |config|
20
- config.gem 'whenever', :lib => false, :source => 'http://gemcutter.org/'
21
- end
11
+ $ sudo gem install whenever
22
12
 
23
13
  == Getting started
24
14
 
@@ -49,6 +39,28 @@ This will create an initial "config/schedule.rb" file you.
49
39
 
50
40
  More examples on the wiki: http://wiki.github.com/javan/whenever/instructions-and-examples
51
41
 
42
+ == Define your own job types
43
+
44
+ Whenever ships with three pre-defined job types: command, runner, and rake. You can define your own with <code>job_type</code>.
45
+
46
+ For example:
47
+
48
+ job_type :awesome, '/usr/local/bin/awesome :task :fun_level'
49
+
50
+ every 2.hours do
51
+ awesome "party", :fun_level => "extreme"
52
+ end
53
+
54
+ Would run <code>/usr/local/bin/awesome party extreme</code> every two hours. <code>:task</code> is always replaced with the first argument, and any additional <code>:whatevers</code> are replaced with the options passed in or by variables that have been defined with <code>set</code>.
55
+
56
+ The default job types that ship with Whenever are defined like so:
57
+
58
+ job_type :command, ":task"
59
+ job_type :runner, "cd :path && script/runner -e :environment ':task'"
60
+ job_type :rake, "cd :path && RAILS_ENV=:environment /usr/bin/env rake :task"
61
+
62
+ If a <code>:path</code> is not set it will default to the directory in which <code>whenever</code> was executed. <code>:environment</code> will default to 'production'.
63
+
52
64
  == Cron output
53
65
 
54
66
  $ cd /my/rails/app
@@ -91,7 +103,7 @@ If you've found a genuine bug or issue, please use the Issues section on github:
91
103
 
92
104
  == License
93
105
 
94
- Copyright (c) 2009 Javan Makhmali
106
+ Copyright (c) 2009+ Javan Makhmali
95
107
 
96
108
  Permission is hereby granted, free of charge, to any person
97
109
  obtaining a copy of this software and associated documentation
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
3
 
4
- require 'lib/whenever/version.rb'
4
+ require File.expand_path(File.dirname(__FILE__) + "/lib/whenever/version")
5
5
 
6
6
  begin
7
7
  require 'jeweler'
@@ -13,7 +13,10 @@ begin
13
13
  gemspec.email = "javan@javan.us"
14
14
  gemspec.homepage = "http://github.com/javan/whenever"
15
15
  gemspec.authors = ["Javan Makhmali"]
16
- gemspec.add_dependency("chronic", '>= 0.2.3')
16
+ gemspec.add_dependency 'aaronh-chronic', '>= 0.3.9'
17
+ gemspec.add_dependency 'activesupport', '>= 2.3.4'
18
+ gemspec.add_development_dependency 'shoulda', '>= 2.1.1'
19
+ gemspec.add_development_dependency 'mocha', '>= 0.9.5'
17
20
  end
18
21
  Jeweler::GemcutterTasks.new
19
22
  rescue LoadError
@@ -22,10 +25,10 @@ end
22
25
 
23
26
  require 'rake/testtask'
24
27
  Rake::TestTask.new(:test) do |test|
25
- test.libs << 'lib' << 'test'
26
- test.pattern = 'test/*.rb'
27
- test.verbose = true
28
- end
28
+ test.libs << 'lib' << 'test'
29
+ test.pattern = 'test/{functional,unit}/**/*_test.rb'
30
+ test.verbose = true
31
+ end
29
32
 
30
33
  task :test => :check_dependencies
31
34
 
data/bin/whenever CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'optparse'
5
- require 'fileutils'
6
- require 'tempfile'
7
5
  require 'whenever'
8
6
 
9
7
  options = Hash.new
@@ -12,10 +10,17 @@ OptionParser.new do |opts|
12
10
  opts.banner = "Usage: whenever [options]"
13
11
  opts.on('-v', '--version') { puts "Whenever v#{Whenever::VERSION}"; exit(0) }
14
12
  opts.on('-w', '--write-crontab') { options[:write] = true }
13
+ opts.on('-c', '--cut [lines]', 'Cut lines from the top of the cronfile') do |lines|
14
+ options[:cut] = lines.to_i if lines
15
+ end
15
16
  opts.on('-i', '--update-crontab [identifier]', 'Default: full path to schedule.rb file') do |identifier|
16
17
  options[:update] = true
17
18
  options[:identifier] = identifier if identifier
18
19
  end
20
+ opts.on('-c', '--clear-crontab [identifier]') do |identifier|
21
+ options[:clear] = true
22
+ options[:identifier] = identifier if identifier
23
+ end
19
24
  opts.on('-f', '--load-file [schedule file]', 'Default: config/schedule.rb') do |file|
20
25
  options[:file] = file if file
21
26
  end
@@ -27,4 +32,4 @@ OptionParser.new do |opts|
27
32
  end
28
33
  end.parse!
29
34
 
30
- Whenever::CommandLine.execute(options)
35
+ Whenever::CommandLine.execute(options)
data/lib/whenever/base.rb CHANGED
@@ -5,11 +5,7 @@ module Whenever
5
5
  end
6
6
 
7
7
  def self.path
8
- if defined?(RAILS_ROOT)
9
- RAILS_ROOT
10
- elsif defined?(::RAILS_ROOT)
11
- ::RAILS_ROOT
12
- end
8
+ Dir.pwd
13
9
  end
14
10
 
15
11
  end
@@ -1,3 +1,6 @@
1
+ require 'fileutils'
2
+ require 'tempfile'
3
+
1
4
  module Whenever
2
5
  class CommandLine
3
6
 
@@ -9,6 +12,7 @@ module Whenever
9
12
  @options = options
10
13
 
11
14
  @options[:file] ||= 'config/schedule.rb'
15
+ @options[:cut] ||= 0
12
16
  @options[:identifier] ||= default_identifier
13
17
 
14
18
  unless File.exists?(@options[:file])
@@ -16,14 +20,21 @@ module Whenever
16
20
  exit(1)
17
21
  end
18
22
 
19
- if @options[:update] && @options[:write]
20
- warn("[fail] Can't update AND write. choose one.")
23
+ if [@options[:update], @options[:write], @options[:clear]].compact.length > 1
24
+ warn("[fail] Can only update, write or clear. Choose one.")
25
+ exit(1)
26
+ end
27
+
28
+ unless @options[:cut].to_s =~ /[0-9]*/
29
+ warn("[fail] Can't cut negative lines from the crontab #{options[:cut]}")
21
30
  exit(1)
22
31
  end
32
+ @options[:cut] = @options[:cut].to_i
33
+
23
34
  end
24
35
 
25
36
  def run
26
- if @options[:update]
37
+ if @options[:update] || @options[:clear]
27
38
  write_crontab(updated_crontab)
28
39
  elsif @options[:write]
29
40
  write_crontab(whenever_cron)
@@ -40,7 +51,7 @@ module Whenever
40
51
  end
41
52
 
42
53
  def whenever_cron
43
- @whenever_cron ||= [comment_open, Whenever.cron(@options), comment_close].join("\n") + "\n"
54
+ @whenever_cron ||= [comment_open, (Whenever.cron(@options) unless @options[:clear]), comment_close].compact.join("\n") + "\n"
44
55
  end
45
56
 
46
57
  def read_crontab
@@ -50,7 +61,7 @@ module Whenever
50
61
  command << "-u #{@options[:user]}" if @options[:user]
51
62
 
52
63
  command_results = %x[#{command.join(' ')} 2> /dev/null]
53
- @current_crontab = $?.exitstatus.zero? ? command_results : ''
64
+ @current_crontab = $?.exitstatus.zero? ? prepare(command_results) : ''
54
65
  end
55
66
 
56
67
  def write_crontab(contents)
@@ -92,6 +103,11 @@ module Whenever
92
103
  end
93
104
  end
94
105
 
106
+ #
107
+ def prepare(contents)
108
+ contents.split("\n")[@options[:cut]..-1].join("\n")
109
+ end
110
+
95
111
  def comment_base
96
112
  "Whenever generated tasks for: #{@options[:identifier]}"
97
113
  end
@@ -105,4 +121,4 @@ module Whenever
105
121
  end
106
122
 
107
123
  end
108
- end
124
+ end
@@ -1,6 +1,5 @@
1
1
  module Whenever
2
2
  module Output
3
-
4
3
  class Cron
5
4
 
6
5
  attr_accessor :time, :task
@@ -43,7 +42,7 @@ module Whenever
43
42
  end
44
43
 
45
44
  def output_redirection
46
- OutputRedirection.new(@output_redirection).to_s unless @output_redirection == :not_set
45
+ Whenever::Output::Cron::OutputRedirection.new(@output_redirection).to_s unless @output_redirection == :not_set
47
46
  end
48
47
 
49
48
  protected
@@ -60,7 +59,7 @@ module Whenever
60
59
  end
61
60
 
62
61
  if shortcut
63
- if @at > 0
62
+ if @at.is_a?(Time) || (@at.is_a?(Numeric) && @at > 0)
64
63
  raise ArgumentError, "You cannot specify an ':at' when using the shortcuts for times."
65
64
  else
66
65
  return shortcut
@@ -77,7 +76,7 @@ module Whenever
77
76
  raise ArgumentError, "Time must be in minutes or higher"
78
77
  when 1.minute...1.hour
79
78
  minute_frequency = @time / 60
80
- timing[0] = comma_separated_timing(minute_frequency, 59)
79
+ timing[0] = comma_separated_timing(minute_frequency, 59, @at || 0)
81
80
  when 1.hour...1.day
82
81
  hour_frequency = (@time / 60 / 60).round
83
82
  timing[0] = @at.is_a?(Time) ? @at.min : @at
@@ -134,6 +133,5 @@ module Whenever
134
133
  end
135
134
 
136
135
  end
137
-
138
136
  end
139
137
  end
@@ -0,0 +1,41 @@
1
+ module Whenever
2
+ class Job
3
+
4
+ attr_reader :at, :output_redirection
5
+
6
+ def initialize(options = {})
7
+ @options = options
8
+
9
+ @at = options[:at]
10
+ @output_redirection = options.has_key?(:output) ? options[:output] : :not_set
11
+ @options[:environment] ||= :production
12
+ @options[:path] ||= Whenever.path
13
+ end
14
+
15
+ def output
16
+ @options[:template].dup.gsub(/:\w+/) do |key|
17
+ before_and_after = [$`[-1..-1], $'[0..0]]
18
+ option = @options[key.sub(':', '').to_sym]
19
+
20
+ if before_and_after.all? { |c| c == "'" }
21
+ escape_single_quotes(option)
22
+ elsif before_and_after.all? { |c| c == '"' }
23
+ escape_double_quotes(option)
24
+ else
25
+ option
26
+ end
27
+ end
28
+ end
29
+
30
+ protected
31
+
32
+ def escape_single_quotes(str)
33
+ str.gsub(/'/) { "'\\''" }
34
+ end
35
+
36
+ def escape_double_quotes(str)
37
+ str.gsub(/"/) { '\"' }
38
+ end
39
+
40
+ end
41
+ end
@@ -2,8 +2,7 @@ module Whenever
2
2
  class JobList
3
3
 
4
4
  def initialize(options)
5
- @jobs = Hash.new
6
- @env = Hash.new
5
+ @jobs, @env, @set_variables = {}, {}, {}
7
6
 
8
7
  case options
9
8
  when String
@@ -16,7 +15,12 @@ module Whenever
16
15
  end
17
16
  pre_set(options[:set])
18
17
  end
19
-
18
+
19
+ # Load all job type files.
20
+ Dir["#{File.expand_path(File.dirname(__FILE__))}/job_types/*.rb"].each do |file|
21
+ eval(File.read(file))
22
+ end
23
+
20
24
  eval(config)
21
25
  end
22
26
 
@@ -25,6 +29,7 @@ module Whenever
25
29
 
26
30
  instance_variable_set("@#{variable}".to_sym, value)
27
31
  self.class.send(:attr_reader, variable.to_sym)
32
+ @set_variables[variable] = value
28
33
  end
29
34
 
30
35
  def env(variable, value)
@@ -37,26 +42,21 @@ module Whenever
37
42
  yield
38
43
  end
39
44
 
40
- def command(task, options = {})
41
- # :cron_log was an old option for output redirection, it remains for backwards compatibility
42
- options[:output] = (options[:cron_log] || @cron_log) if defined?(@cron_log) || options.has_key?(:cron_log)
43
- # :output is the newer, more flexible option.
44
- options[:output] = @output if defined?(@output) && !options.has_key?(:output)
45
- options[:class] ||= Whenever::Job::Default
46
- @jobs[@current_time_scope] ||= []
47
- @jobs[@current_time_scope] << options[:class].new(@options.merge(:task => task).merge(options))
48
- end
49
-
50
- def runner(task, options = {})
51
- options.reverse_merge!(:environment => @environment, :path => @path)
52
- options[:class] = Whenever::Job::Runner
53
- command(task, options)
54
- end
55
-
56
- def rake(task, options = {})
57
- options.reverse_merge!(:environment => @environment, :path => @path)
58
- options[:class] = Whenever::Job::RakeTask
59
- command(task, options)
45
+ def job_type(name, template)
46
+ class_eval do
47
+ define_method(name) do |task, *args|
48
+ options = { :task => task, :template => template }
49
+ options.merge!(args[0]) if args[0].is_a? Hash
50
+
51
+ # :cron_log was an old option for output redirection, it remains for backwards compatibility
52
+ options[:output] = (options[:cron_log] || @cron_log) if defined?(@cron_log) || options.has_key?(:cron_log)
53
+ # :output is the newer, more flexible option.
54
+ options[:output] = @output if defined?(@output) && !options.has_key?(:output)
55
+
56
+ @jobs[@current_time_scope] ||= []
57
+ @jobs[@current_time_scope] << Whenever::Job.new(@options.merge(@set_variables).merge(options))
58
+ end
59
+ end
60
60
  end
61
61
 
62
62
  def generate_cron_output
@@ -79,7 +79,7 @@ module Whenever
79
79
  pairs.each do |pair|
80
80
  next unless pair.index('=')
81
81
  variable, value = *pair.split('=')
82
- set(variable.strip, value.strip) unless variable.blank? || value.blank?
82
+ set(variable.strip.to_sym, value.strip) unless variable.blank? || value.blank?
83
83
  end
84
84
  end
85
85
 
@@ -1,27 +1,3 @@
1
- module Whenever
2
- module Job
3
- class Default
4
-
5
- attr_accessor :task, :at, :output, :output_redirection
6
-
7
- def initialize(options = {})
8
- @task = options[:task]
9
- @at = options[:at]
10
- @output_redirection = options.has_key?(:output) ? options[:output] : :not_set
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
1
+ job_type :command, ":task"
2
+ job_type :runner, "cd :path && script/runner -e :environment ':task'"
3
+ job_type :rake, "cd :path && RAILS_ENV=:environment /usr/bin/env rake :task"
@@ -32,11 +32,17 @@ module Whenever
32
32
  def redirect_from_hash
33
33
  case
34
34
  when stdout == '/dev/null' && stderr == '/dev/null'
35
- ">> /dev/null 2>&1"
35
+ "> /dev/null 2>&1"
36
+ when stdout && stderr == '/dev/null'
37
+ ">> #{stdout} 2> /dev/null"
36
38
  when stdout && stderr
37
- ">> #{stdout} 2> #{stderr}"
39
+ ">> #{stdout} 2>> #{stderr}"
40
+ when stderr == '/dev/null'
41
+ "2> /dev/null"
38
42
  when stderr
39
- "2> #{stderr}"
43
+ "2>> #{stderr}"
44
+ when stdout == '/dev/null'
45
+ "> /dev/null"
40
46
  when stdout
41
47
  ">> #{stdout}"
42
48
  else
@@ -1,3 +1,3 @@
1
1
  module Whenever
2
- VERSION = '0.4.1'
2
+ VERSION = '0.5.2'
3
3
  end unless defined?(Whenever::VERSION)
data/lib/whenever.rb CHANGED
@@ -1,31 +1,10 @@
1
1
  require 'chronic'
2
+ require 'active_support/all'
2
3
 
3
- # Hoping to load Rails' Rakefile
4
- begin
5
- load 'Rakefile'
6
- rescue LoadError
7
- nil
8
- end
9
-
10
- # If Rails' rakefile was loaded than so was active_support, but
11
- # if this is being used in a non-rails enviroment we need to require it.
12
- # It was previously defined as a dependency of this gem, but that became
13
- # problematic. See: http://github.com/javan/whenever/issues#issue/1
14
- begin
15
- require 'active_support'
16
- rescue LoadError
17
- warn 'To user Whenever you need the active_support gem:'
18
- warn '$ sudo gem install active_support'
19
- exit(1)
20
- end
21
-
22
- # Whenever files
23
4
  require 'whenever/base'
24
5
  require 'whenever/job_list'
25
- require 'whenever/job_types/default'
26
- require 'whenever/job_types/rake_task'
27
- require 'whenever/job_types/runner'
28
- require 'whenever/outputs/cron'
29
- require 'whenever/outputs/cron/output_redirection'
6
+ require 'whenever/job'
7
+ require 'whenever/cron'
8
+ require 'whenever/output_redirection'
30
9
  require 'whenever/command_line'
31
10
  require 'whenever/version'