whenever 0.9.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9ec69e7c581dc0a3b78c99dc92d7ba20603fe314
4
- data.tar.gz: 02fc72439569835cce71da0fc186ed48568ed1e2
2
+ SHA256:
3
+ metadata.gz: dc5ff14e6e9d357583f5e20d31fafbcf2dfe3aea8ac756cf9103f51504674e9a
4
+ data.tar.gz: 446e8398b741a1a9a7ee262b3542efb107d1453259083fef03ea50726227d7dd
5
5
  SHA512:
6
- metadata.gz: 732ee6e0a5d38ed8f323e814e2e6243306a5c2e84b44d5ce8f05d2c0ef7bf7520341044892906c7ea6899a24a87e840285a001dc54e35a196414da06de42a607
7
- data.tar.gz: 9bbf8365c6fd030b7ba465d06660f1bd84cb8593b957f4482676fa50c6daf684b2de91c98bb84907e2e62f2e493f22b76c1ccbb7dbd469072ebf937e5e12cf85
6
+ metadata.gz: 41f396515f594a4726bd9048783653b0b203e0beb4ea65f6b95faf508061d0fd064bec0a31bbcf6dad6a23f68ec4f3364ae6e8f160eb0539ec6073a6c4960242
7
+ data.tar.gz: 4fbe2b52fc350ee272d7d03638369b8a6443c1ed6e122be511b9ccf07881c1e559d63587153259343febc89db40aa45bc4ca45cf83af885fd618fd5668ddd1d2
data/.travis.yml CHANGED
@@ -1,18 +1,21 @@
1
1
  language: ruby
2
- script: bundle exec rake
3
2
 
4
3
  before_install:
5
4
  - gem install bundler
6
-
5
+ - unset _JAVA_OPTIONS
7
6
  rvm:
8
- - 1.9.3
9
- - 2.0.0
10
- - 2.1.0
11
- - 2.2.0
12
- - 2.3.0
13
- - jruby
7
+ - 2.4.6
8
+ - 2.5.5
9
+ - 2.6.3
10
+ - jruby-9.2.6.0
14
11
 
15
12
  gemfile:
16
- - Gemfile
17
13
  - gemfiles/activesupport4.1.gemfile
18
14
  - gemfiles/activesupport4.2.gemfile
15
+ - gemfiles/activesupport5.0.gemfile
16
+ - gemfiles/activesupport5.1.gemfile
17
+ - gemfiles/activesupport5.2.gemfile
18
+
19
+ env:
20
+ global:
21
+ - JRUBY_OPTS=--debug
data/Appraisals ADDED
@@ -0,0 +1,19 @@
1
+ appraise 'activesupport4.1' do
2
+ gem "activesupport", "~> 4.1.0"
3
+ end
4
+
5
+ appraise 'activesupport4.2' do
6
+ gem "activesupport", "~> 4.2.0"
7
+ end
8
+
9
+ appraise 'activesupport5.0' do
10
+ gem "activesupport", "~> 5.0.0"
11
+ end
12
+
13
+ appraise 'activesupport5.1' do
14
+ gem "activesupport", "~> 5.1.0"
15
+ end
16
+
17
+ appraise 'activesupport5.2' do
18
+ gem "activesupport", "~> 5.2.0beta2"
19
+ end
data/CHANGELOG.md CHANGED
@@ -1,4 +1,36 @@
1
- ### develop
1
+ ### unreleased
2
+
3
+ ### 1.0.0 / Jun 13, 2019
4
+
5
+ * First stable release per SemVer.
6
+
7
+ * Removes support for versions of Ruby which are no longer supported by the Ruby project.
8
+
9
+ ### 0.11.0 / April 23, 2019
10
+
11
+ * Add support for mapping Range objects to cron range syntax [Tim Craft](https://github.com/javan/whenever/pull/725)
12
+
13
+ * Bugfix: Avoid modifying Capistrano `default_env` when setting the whenever environment. [ta1kt0me](https://github.com/javan/whenever/pull/728)
14
+
15
+ * Enable to execute whenever's task independently without setting :release_path or :whenever_path [ta1kt0me](https://github.com/javan/whenever/pull/729)
16
+
17
+ * Make error message clearer when parsing cron syntax fails due to a trailing space [ignisf](https://github.com/javan/whenever/pull/744)
18
+
19
+ ### 0.10.0 / November 19, 2017
20
+
21
+ * Modify wheneverize to allow for the creating of 'config' directory when not present
22
+
23
+ * Add --crontab-command to whenever binary for overriding the crontab command. [Martin Grandrath]
24
+
25
+ * Allow setting the path within which Capistrano will execute whenever. [Samuel Johnson](https://github.com/javan/whenever/pull/619)
26
+
27
+ * Allow the use of string literals for month and day-of-week in raw cron syntax.. [Potamianos Gregory](https://github.com/javan/whenever/pull/711)
28
+
29
+ * Include Capistrano default environment variables when executing Whenever. [Karl Li](https://github.com/javan/whenever/pull/719)
30
+
31
+ * Allow configuring an alternative schedule file in Capistrano. [Shinichi Okamoto](https://github.com/javan/whenever/pull/666)
32
+
33
+ * Add customizing email recipient option with the MAILTO environment variable. [Chikahiro Tokoro](https://github.com/javan/whenever/pull/678)
2
34
 
3
35
  ### 0.9.7 / June 14, 2016
4
36
 
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in whenever.gemspec
4
4
  gemspec
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2016 Javan Makhmali
1
+ Copyright (c) 2017 Javan Makhmali
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
data/README.md CHANGED
@@ -9,7 +9,7 @@ $ gem install whenever
9
9
  Or with Bundler in your Gemfile.
10
10
 
11
11
  ```ruby
12
- gem 'whenever', :require => false
12
+ gem 'whenever', require: false
13
13
  ```
14
14
 
15
15
  ### Getting started
@@ -19,7 +19,7 @@ $ cd /apps/my-great-project
19
19
  $ wheneverize .
20
20
  ```
21
21
 
22
- This will create an initial `config/schedule.rb` file for you.
22
+ This will create an initial `config/schedule.rb` file for you (as long as the config folder is already present in your project).
23
23
 
24
24
  ### The `whenever` command
25
25
 
@@ -34,28 +34,39 @@ This will simply show you your `schedule.rb` file converted to cron syntax. It d
34
34
  $ whenever --update-crontab
35
35
  ```
36
36
 
37
+ Other commonly used options include:
38
+ ```sh
39
+ $ whenever --user app # set a user as which to install the crontab
40
+ $ whenever --load-file config/my_schedule.rb # set the schedule file
41
+ $ whenever --crontab-command 'sudo crontab' # override the crontab command
42
+ ```
43
+
37
44
  You can list installed cron jobs using `crontab -l`.
38
45
 
39
- Run `whenever --help` for a complete list of options for selecting the schedule to use, setting variables in the schedule, selecting a user as which to install the crontab, etc.
46
+ Run `whenever --help` for a complete list of options for selecting the schedule to use, setting variables in the schedule, etc.
40
47
 
41
48
  ### Example schedule.rb file
42
49
 
43
50
  ```ruby
44
- every 3.hours do
51
+ every 3.hours do # 1.minute 1.day 1.week 1.month 1.year is also supported
45
52
  runner "MyModel.some_process"
46
53
  rake "my:rake:task"
47
54
  command "/usr/bin/my_great_command"
48
55
  end
49
56
 
50
- every 1.day, :at => '4:30 am' do
57
+ every 1.day, at: '4:30 am' do
51
58
  runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
52
59
  end
53
60
 
61
+ every 1.day, at: ['4:30 am', '6:00 pm'] do
62
+ runner "Mymodel.task_to_run_in_two_times_every_day"
63
+ end
64
+
54
65
  every :hour do # Many shortcuts available: :hour, :day, :month, :year, :reboot
55
66
  runner "SomeModel.ladeeda"
56
67
  end
57
68
 
58
- every :sunday, :at => '12pm' do # Use any day of the week or :weekend, :weekday
69
+ every :sunday, at: '12pm' do # Use any day of the week or :weekend, :weekday
59
70
  runner "Task.do_something_great"
60
71
  end
61
72
 
@@ -65,7 +76,7 @@ end
65
76
 
66
77
  # run this task only on servers with the :app role in Capistrano
67
78
  # see Capistrano roles section below
68
- every :day, :at => '12:20am', :roles => [:app] do
79
+ every :day, at: '12:20am', roles: [:app] do
69
80
  rake "app_server:task"
70
81
  end
71
82
  ```
@@ -80,7 +91,7 @@ For example:
80
91
  job_type :awesome, '/usr/local/bin/awesome :task :fun_level'
81
92
 
82
93
  every 2.hours do
83
- awesome "party", :fun_level => "extreme"
94
+ awesome "party", fun_level: "extreme"
84
95
  end
85
96
  ```
86
97
 
@@ -113,6 +124,57 @@ Or set the job_template to nil to have your jobs execute normally.
113
124
  set :job_template, nil
114
125
  ```
115
126
 
127
+ ### Parsing dates and times
128
+
129
+ Whenever uses the [Chronic](https://github.com/mojombo/chronic) gem to parse the specified dates and times.
130
+
131
+ You can set your custom Chronic configuration if the defaults don't fit you.
132
+
133
+ For example, to assume a 24 hour clock instead of the default 12 hour clock:
134
+
135
+ ```ruby
136
+ set :chronic_options, hours24: true
137
+
138
+ # By default this would run the job every day at 3am
139
+ every 1.day, at: '3:00' do
140
+ runner "MyModel.nightly_archive_job"
141
+ end
142
+ ```
143
+
144
+ You can see a list of all available options here: <https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb>
145
+
146
+ ### Customize email recipient with the `MAILTO` environment variable
147
+
148
+ Output from the jobs is sent to the email address configured in the `MAILTO` environment variable.
149
+
150
+ There are many ways to further configure the recipient.
151
+
152
+ Example: A global configuration, overriding the environment's value:
153
+
154
+ ```ruby
155
+ env 'MAILTO', 'output_of_cron@example.com'
156
+
157
+ every 3.hours do
158
+ command "/usr/bin/my_great_command"
159
+ end
160
+ ```
161
+
162
+ Example: A `MAILTO` configured for all the jobs in an interval block:
163
+
164
+ ```ruby
165
+ every 3.hours, mailto: 'my_super_command@example.com' do
166
+ command "/usr/bin/my_super_command"
167
+ end
168
+ ```
169
+
170
+ Example: A `MAILTO` configured for a single job:
171
+
172
+ ```ruby
173
+ every 3.hours do
174
+ command "/usr/bin/my_super_command", mailto: 'my_super_command_output@example.com'
175
+ end
176
+ ```
177
+
116
178
  ### Capistrano integration
117
179
 
118
180
  Use the built-in Capistrano recipe for easy crontab updates with deploys. For Capistrano V3, see the next section.
@@ -140,7 +202,7 @@ require "whenever/capistrano"
140
202
 
141
203
  The capistrano variable `:stage` should be the one holding your environment name. This will make the correct `:environment` available in your `schedule.rb`.
142
204
 
143
- If both your environments are on the same server you'll want to namespace them or they'll overwrite each other when you deploy:
205
+ If both your environments are on the same server you'll want to namespace them, or they'll overwrite each other when you deploy:
144
206
 
145
207
  ```ruby
146
208
  set :whenever_environment, defer { stage }
@@ -148,6 +210,13 @@ set :whenever_identifier, defer { "#{application}_#{stage}" }
148
210
  require "whenever/capistrano"
149
211
  ```
150
212
 
213
+ If you use a schedule at an alternative path, you may configure it like so:
214
+
215
+ ```ruby
216
+ set :whenever_load_file, defer { "#{release_path}/somewhere/else/schedule.rb" }
217
+ require "whenever/capistrano"
218
+ ```
219
+
151
220
  ### Capistrano V3 Integration
152
221
 
153
222
  In your "Capfile" file:
@@ -172,10 +241,10 @@ different servers in your capistrano deployment, then you can safely stop readin
172
241
  now and everything should just work the same way it always has.
173
242
 
174
243
  When you define a job in your schedule.rb file, by default it will be deployed to
175
- all servers in the whenever_roles list (which defaults to [:db]).
244
+ all servers in the whenever_roles list (which defaults to `[:db]`).
176
245
 
177
246
  However, if you want to restrict certain jobs to only run on subset of servers,
178
- you can add a :roles => [...] argument to their definitions. **Make sure to add
247
+ you can add a `roles: [...]` argument to their definitions. **Make sure to add
179
248
  that role to the whenever_roles list in your deploy.rb.**
180
249
 
181
250
  When you run `cap deploy`, jobs with a :roles list specified will only be added to
@@ -184,28 +253,28 @@ the crontabs on servers with one or more of the roles in that list.
184
253
  Jobs with no :roles argument will be deployed to all servers in the whenever_roles
185
254
  list. This is to maintain backward compatibility with previous releases of whenever.
186
255
 
187
- So, for example, with the default whenever_roles of [:db], a job like this would be
188
- deployed to all servers with the :db role:
256
+ So, for example, with the default whenever_roles of `[:db]`, a job like this would be
257
+ deployed to all servers with the `:db` role:
189
258
 
190
259
  ```ruby
191
- every :day, :at => '12:20am' do
260
+ every :day, at: '12:20am' do
192
261
  rake 'foo:bar'
193
262
  end
194
263
  ```
195
264
 
196
- If we set whenever_roles to [:db, :app] in deploy.rb, and have the following
265
+ If we set whenever_roles to `[:db, :app]` in deploy.rb, and have the following
197
266
  jobs in schedule.rb:
198
267
 
199
268
  ```ruby
200
- every :day, :at => '1:37pm', :roles => [:app] do
269
+ every :day, at: '1:37pm', roles: [:app] do
201
270
  rake 'app:task' # will only be added to crontabs of :app servers
202
271
  end
203
272
 
204
- every :hour, :roles => [:db] do
273
+ every :hour, roles: [:db] do
205
274
  rake 'db:task' # will only be added to crontabs of :db servers
206
275
  end
207
276
 
208
- every :day, :at => '12:02am' do
277
+ every :day, at: '12:02am' do
209
278
  command "run_this_everywhere" # will be deployed to :db and :app servers
210
279
  end
211
280
  ```
@@ -253,8 +322,8 @@ It's a little bit dated now, but remains a good introduction.
253
322
 
254
323
  ----
255
324
 
256
- [![Build Status](https://secure.travis-ci.org/javan/whenever.png)](http://travis-ci.org/javan/whenever)
325
+ [![Build Status](https://secure.travis-ci.org/javan/whenever.svg)](http://travis-ci.org/javan/whenever)
257
326
 
258
327
  ----
259
328
 
260
- Copyright &copy; 2016 Javan Makhmali
329
+ Copyright &copy; 2017 Javan Makhmali
data/bin/whenever CHANGED
@@ -35,6 +35,9 @@ OptionParser.new do |opts|
35
35
  opts.on('-r', '--roles [role1,role2]', 'Comma-separated list of server roles to generate cron jobs for') do |roles|
36
36
  options[:roles] = roles.split(',').map(&:to_sym) if roles
37
37
  end
38
+ opts.on('-x', '--crontab-command [command]', 'Default: crontab') do |crontab_command|
39
+ options[:crontab_command] = crontab_command if crontab_command
40
+ end
38
41
  opts.on('-v', '--version') { puts "Whenever v#{Whenever::VERSION}"; exit(0) }
39
42
  end.parse!
40
43
 
data/bin/wheneverize CHANGED
@@ -58,9 +58,12 @@ if File.exist?(file)
58
58
  warn "[skip] `#{file}' already exists"
59
59
  elsif File.exist?(file.downcase)
60
60
  warn "[skip] `#{file.downcase}' exists, which could conflict with `#{file}'"
61
- elsif !File.exist?(File.dirname(file))
62
- warn "[skip] directory `#{File.dirname(file)}' does not exist"
63
61
  else
62
+ dir = File.dirname(file)
63
+ if !File.exist?(dir)
64
+ warn "[add] creating `#{dir}'"
65
+ FileUtils.mkdir_p(dir)
66
+ end
64
67
  puts "[add] writing `#{file}'"
65
68
  File.open(file, "w") { |f| f.write(content) }
66
69
  end
@@ -1,4 +1,6 @@
1
- source "https://rubygems.org"
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
2
4
 
3
5
  gem "activesupport", "~> 4.1.0"
4
6
 
@@ -1,4 +1,6 @@
1
- source "https://rubygems.org"
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
2
4
 
3
5
  gem "activesupport", "~> 4.2.0"
4
6
 
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "activesupport", "~> 5.0.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "activesupport", "~> 5.1.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "activesupport", "~> 5.2.0beta2"
6
+
7
+ gemspec path: "../"
@@ -11,6 +11,7 @@ Capistrano::Configuration.instance(:must_exist).load do
11
11
  _cset(:whenever_variables) { "environment=#{fetch :whenever_environment}" }
12
12
  _cset(:whenever_update_flags) { "--update-crontab #{fetch :whenever_identifier} --set #{fetch :whenever_variables}" }
13
13
  _cset(:whenever_clear_flags) { "--clear-crontab #{fetch :whenever_identifier}" }
14
+ _cset(:whenever_path) { fetch :latest_release }
14
15
 
15
16
  namespace :whenever do
16
17
  desc "Update application's crontab entries using Whenever"
@@ -18,7 +19,7 @@ Capistrano::Configuration.instance(:must_exist).load do
18
19
  args = {
19
20
  :command => fetch(:whenever_command),
20
21
  :flags => fetch(:whenever_update_flags),
21
- :path => fetch(:latest_release)
22
+ :path => fetch(:whenever_path)
22
23
  }
23
24
 
24
25
  if whenever_servers.any?
@@ -38,7 +39,7 @@ Capistrano::Configuration.instance(:must_exist).load do
38
39
  args = {
39
40
  :command => fetch(:whenever_command),
40
41
  :flags => fetch(:whenever_clear_flags),
41
- :path => fetch(:latest_release)
42
+ :path => fetch(:whenever_path)
42
43
  }
43
44
 
44
45
  whenever_run_commands(args)
@@ -4,7 +4,7 @@ namespace :whenever do
4
4
 
5
5
  on roles fetch(:whenever_roles) do |host|
6
6
  args_for_host = block_given? ? args + Array(yield(host)) : args
7
- within release_path do
7
+ within fetch(:whenever_path) do
8
8
  with fetch(:whenever_command_environment_variables) do
9
9
  execute(*args_for_host)
10
10
  end
@@ -12,17 +12,28 @@ namespace :whenever do
12
12
  end
13
13
  end
14
14
 
15
+ def load_file
16
+ file = fetch(:whenever_load_file)
17
+ if file
18
+ "-f #{file}"
19
+ else
20
+ ''
21
+ end
22
+ end
23
+
15
24
  desc "Update application's crontab entries using Whenever"
16
25
  task :update_crontab do
17
26
  setup_whenever_task do |host|
18
27
  roles = host.roles_array.join(",")
19
- [fetch(:whenever_update_flags), "--roles=#{roles}"]
28
+ [fetch(:whenever_update_flags), "--roles=#{roles}", load_file]
20
29
  end
21
30
  end
22
31
 
23
32
  desc "Clear application's crontab entries using Whenever"
24
33
  task :clear_crontab do
25
- setup_whenever_task(fetch(:whenever_clear_flags))
34
+ setup_whenever_task do |host|
35
+ [fetch(:whenever_clear_flags), load_file]
36
+ end
26
37
  end
27
38
 
28
39
  after "deploy:updated", "whenever:update_crontab"
@@ -33,11 +44,13 @@ namespace :load do
33
44
  task :defaults do
34
45
  set :whenever_roles, ->{ :db }
35
46
  set :whenever_command, ->{ [:bundle, :exec, :whenever] }
36
- set :whenever_command_environment_variables, ->{ { rails_env: fetch(:whenever_environment) } }
47
+ set :whenever_command_environment_variables, ->{ fetch(:default_env).merge(rails_env: fetch(:whenever_environment)) }
37
48
  set :whenever_identifier, ->{ fetch :application }
38
49
  set :whenever_environment, ->{ fetch :rails_env, fetch(:stage, "production") }
39
50
  set :whenever_variables, ->{ "environment=#{fetch :whenever_environment}" }
51
+ set :whenever_load_file, ->{ nil }
40
52
  set :whenever_update_flags, ->{ "--update-crontab #{fetch :whenever_identifier} --set #{fetch :whenever_variables}" }
41
53
  set :whenever_clear_flags, ->{ "--clear-crontab #{fetch :whenever_identifier}" }
54
+ set :whenever_path, ->{ release_path }
42
55
  end
43
56
  end
@@ -9,9 +9,10 @@ module Whenever
9
9
  def initialize(options={})
10
10
  @options = options
11
11
 
12
- @options[:file] ||= 'config/schedule.rb'
13
- @options[:cut] ||= 0
14
- @options[:identifier] ||= default_identifier
12
+ @options[:crontab_command] ||= 'crontab'
13
+ @options[:file] ||= 'config/schedule.rb'
14
+ @options[:cut] ||= 0
15
+ @options[:identifier] ||= default_identifier
15
16
 
16
17
  if !File.exist?(@options[:file]) && @options[:clear].nil?
17
18
  warn("[fail] Can't find file: #{@options[:file]}")
@@ -28,6 +29,8 @@ module Whenever
28
29
  exit(1)
29
30
  end
30
31
  @options[:cut] = @options[:cut].to_i
32
+
33
+ @timestamp = Time.now.to_s
31
34
  end
32
35
 
33
36
  def run
@@ -55,9 +58,10 @@ module Whenever
55
58
  end
56
59
 
57
60
  def read_crontab
58
- return @current_crontab if @current_crontab
61
+ return @current_crontab if instance_variable_defined?(:@current_crontab)
59
62
 
60
- command = ['crontab -l']
63
+ command = [@options[:crontab_command]]
64
+ command << '-l'
61
65
  command << "-u #{@options[:user]}" if @options[:user]
62
66
 
63
67
  command_results = %x[#{command.join(' ')} 2> /dev/null]
@@ -65,7 +69,7 @@ module Whenever
65
69
  end
66
70
 
67
71
  def write_crontab(contents)
68
- command = ['crontab']
72
+ command = [@options[:crontab_command]]
69
73
  command << "-u #{@options[:user]}" if @options[:user]
70
74
  # Solaris/SmartOS cron does not support the - option to read from stdin.
71
75
  command << "-" unless OS.solaris?
@@ -90,19 +94,19 @@ module Whenever
90
94
 
91
95
  def updated_crontab
92
96
  # Check for unopened or unclosed identifier blocks
93
- if read_crontab =~ Regexp.new("^#{comment_open}\s*$") && (read_crontab =~ Regexp.new("^#{comment_close}\s*$")).nil?
94
- warn "[fail] Unclosed indentifier; Your crontab file contains '#{comment_open}', but no '#{comment_close}'"
97
+ if read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$") && (read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")).nil?
98
+ warn "[fail] Unclosed indentifier; Your crontab file contains '#{comment_open(false)}', but no '#{comment_close(false)}'"
95
99
  exit(1)
96
- elsif (read_crontab =~ Regexp.new("^#{comment_open}\s*$")).nil? && read_crontab =~ Regexp.new("^#{comment_close}\s*$")
97
- warn "[fail] Unopened indentifier; Your crontab file contains '#{comment_close}', but no '#{comment_open}'"
100
+ elsif (read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$")).nil? && read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")
101
+ warn "[fail] Unopened indentifier; Your crontab file contains '#{comment_close(false)}', but no '#{comment_open(false)}'"
98
102
  exit(1)
99
103
  end
100
104
 
101
- # If an existing identier block is found, replace it with the new cron entries
102
- if read_crontab =~ Regexp.new("^#{comment_open}\s*$") && read_crontab =~ Regexp.new("^#{comment_close}\s*$")
105
+ # If an existing identifier block is found, replace it with the new cron entries
106
+ if read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$") && read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")
103
107
  # If the existing crontab file contains backslashes they get lost going through gsub.
104
108
  # .gsub('\\', '\\\\\\') preserves them. Go figure.
105
- read_crontab.gsub(Regexp.new("^#{comment_open}\s*$.+^#{comment_close}\s*$", Regexp::MULTILINE), whenever_cron.chomp.gsub('\\', '\\\\\\'))
109
+ read_crontab.gsub(Regexp.new("^#{comment_open_regex}\s*$.+^#{comment_close_regex}\s*$", Regexp::MULTILINE), whenever_cron.chomp.gsub('\\', '\\\\\\'))
106
110
  else # Otherwise, append the new cron entries after any existing ones
107
111
  [read_crontab, whenever_cron].join("\n\n")
108
112
  end.gsub(/\n{3,}/, "\n\n") # More than two newlines becomes just two.
@@ -120,16 +124,32 @@ module Whenever
120
124
  stripped_contents.gsub!(/\s+$/, $/)
121
125
  end
122
126
 
123
- def comment_base
124
- "Whenever generated tasks for: #{@options[:identifier]}"
127
+ def comment_base(include_timestamp = true)
128
+ if include_timestamp
129
+ "Whenever generated tasks for: #{@options[:identifier]} at: #{@timestamp}"
130
+ else
131
+ "Whenever generated tasks for: #{@options[:identifier]}"
132
+ end
133
+ end
134
+
135
+ def comment_open(include_timestamp = true)
136
+ "# Begin #{comment_base(include_timestamp)}"
137
+ end
138
+
139
+ def comment_close(include_timestamp = true)
140
+ "# End #{comment_base(include_timestamp)}"
141
+ end
142
+
143
+ def comment_open_regex
144
+ "#{comment_open(false)}(#{timestamp_regex}|)"
125
145
  end
126
146
 
127
- def comment_open
128
- "# Begin #{comment_base}"
147
+ def comment_close_regex
148
+ "#{comment_close(false)}(#{timestamp_regex}|)"
129
149
  end
130
150
 
131
- def comment_close
132
- "# End #{comment_base}"
151
+ def timestamp_regex
152
+ " at: \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} ([+-]\\d{4}|UTC)"
133
153
  end
134
154
  end
135
155
  end