chrono_trigger 0.2.1 → 1.0.0

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/.project DELETED
@@ -1,11 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <projectDescription>
3
- <name>chrono_trigger</name>
4
- <comment></comment>
5
- <projects>
6
- </projects>
7
- <buildSpec>
8
- </buildSpec>
9
- <natures>
10
- </natures>
11
- </projectDescription>
data/History.txt DELETED
@@ -1,21 +0,0 @@
1
- == 0.2.1 2013-01-15
2
- * 1 patch
3
- * Upgraded support for Ruby 1.8.6
4
-
5
- == 0.2.0 2013-01-10
6
- * 1 enhancement
7
- * Upgraded to support Ruby 1.9.x
8
-
9
- == 0.0.4 2009-04-09
10
- * 1 enhancement
11
- * Added chrono_trigger binary and supporting files
12
-
13
- == 0.0.2 2009-04-02
14
-
15
- * 1 minor enhancement:
16
- * Updated to add tasks file
17
-
18
- == 0.0.1 2009-04-02
19
-
20
- * 1 major enhancement:
21
- * Initial release
data/Manifest.txt DELETED
@@ -1,25 +0,0 @@
1
- History.txt
2
- Manifest.txt
3
- PostInstall.txt
4
- README.rdoc
5
- Rakefile
6
- bin/chrono_trigger
7
- lib/chrono_trigger.rb
8
- lib/chrono_trigger/cron_entry.rb
9
- lib/chrono_trigger/process.rb
10
- lib/chrono_trigger/runner.rb
11
- lib/chrono_trigger/shell.rb
12
- lib/chrono_trigger/tasks.rb
13
- lib/chrono_trigger/trigger.rb
14
- lib/chrono_trigger/version.rb
15
- lib/triggers/test_triggers.rb
16
- script/console
17
- script/destroy
18
- script/generate
19
- tasks/chrono_trigger.rake
20
- test/test_chrono_trigger.rb
21
- test/test_cron_entry.rb
22
- test/test_helper.rb
23
- test/test_shell.rb
24
- test/test_trigger.rb
25
- test/triggers.rb
data/PostInstall.txt DELETED
@@ -1 +0,0 @@
1
-
data/README.rdoc DELETED
@@ -1,61 +0,0 @@
1
- = chrono_trigger
2
-
3
- This is a branch of http://github.com/gregfitz23/chrono_trigger/tree/master as it hasn't been updated in sometime.
4
- New code can be found at https://github.com/darful/chrono_trigger. Now with Ruby 1.9.x support.
5
-
6
-
7
- == DESCRIPTION:
8
-
9
- A cron framework for defining cron tasks using a readable DSL.
10
-
11
- == FEATURES/PROBLEMS:
12
-
13
- == SYNOPSIS:
14
-
15
- Create trigger files directory.
16
- Triggers should follow the pattern:
17
-
18
- trigger "name" do
19
- runs { code to execute }
20
- on :monday
21
- every :minutes=>10
22
- at :hour=>9, :minute=>[30,50]
23
- end
24
- Run `chrono_trigger -t{full path to trigger file}`.
25
- Other available options are:
26
- * -a - Specify an application context for the triggers to run against.
27
- * -e - Specify the environment the triggers should run against
28
-
29
- == REQUIREMENTS:
30
-
31
- * ActiveSupport >= 2.3.4
32
- * Ruby >= 1.8.6
33
-
34
- == INSTALL:
35
-
36
- * gem install chrono_trigger
37
-
38
- == LICENSE:
39
-
40
- (The MIT License)
41
-
42
- Copyright (c) 2009 FIXME full name
43
-
44
- Permission is hereby granted, free of charge, to any person obtaining
45
- a copy of this software and associated documentation files (the
46
- 'Software'), to deal in the Software without restriction, including
47
- without limitation the rights to use, copy, modify, merge, publish,
48
- distribute, sublicense, and/or sell copies of the Software, and to
49
- permit persons to whom the Software is furnished to do so, subject to
50
- the following conditions:
51
-
52
- The above copyright notice and this permission notice shall be
53
- included in all copies or substantial portions of the Software.
54
-
55
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
56
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
57
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
58
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
59
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
60
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
61
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/VERSION.yml DELETED
@@ -1,4 +0,0 @@
1
- ---
2
- :major: 0
3
- :minor: 2
4
- :patch: 1
data/bin/chrono_trigger DELETED
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
-
4
- require 'chrono_trigger/runner'
5
-
6
- ChronoTrigger::Runner.run
7
-
@@ -1,72 +0,0 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
-
5
- # -*- encoding: utf-8 -*-
6
-
7
- Gem::Specification.new do |s|
8
-
9
- s.name = "chrono_trigger"
10
- s.authors = ["Jon Ciccone"]
11
- s.date = "2013-01-10"
12
- s.summary = "Rails cron jobs."
13
- s.description = "This gem allows you to write, deploy, and maintain cron jobs withing the rails framework."
14
- s.email = "darful@gmail.com"
15
- s.homepage = "https://github.com/darful/chrono_trigger"
16
- s.version = '0.2.1'
17
-
18
- s.files = [
19
- ".project",
20
- "History.txt",
21
- "Manifest.txt",
22
- "PostInstall.txt",
23
- "README.rdoc",
24
- "Rakefile",
25
- "VERSION.yml",
26
- "bin/chrono_trigger",
27
- "chrono_trigger.gemspec",
28
- "lib/chrono_trigger.rb",
29
- "lib/chrono_trigger/cron_entry.rb",
30
- "lib/chrono_trigger/process.rb",
31
- "lib/chrono_trigger/runner.rb",
32
- "lib/chrono_trigger/shell.rb",
33
- "lib/chrono_trigger/tasks.rb",
34
- "lib/chrono_trigger/trigger.rb",
35
- "lib/chrono_trigger/version.rb",
36
- "lib/tasks/chrono_trigger.rake",
37
- "lib/triggers/test_triggers.rb",
38
- "script/console",
39
- "script/destroy",
40
- "script/generate",
41
- "test/test_chrono_trigger.rb",
42
- "test/test_cron_entry.rb",
43
- "test/test_helper.rb",
44
- "test/test_shell.rb",
45
- "test/test_trigger.rb",
46
- "test/triggers.rb"
47
- ]
48
- s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
49
- s.test_files = s.files.grep(%r{^(test)/})
50
- s.require_paths = ["lib"]
51
- s.extra_rdoc_files = ["README.rdoc"]
52
-
53
- s.add_dependency "activesupport", ">= 2.3.4"
54
- #s.add_dependency "activerecord", ">= 2.3.4"
55
-
56
- s.add_development_dependency "shoulda", ">= 2.10"
57
- s.add_development_dependency "mocha", ">= 0.9.5"
58
-
59
- s.add_development_dependency "rubyforge"
60
- s.add_development_dependency "git"
61
- s.add_development_dependency "technicalpickles-jeweler"
62
-
63
- if s.respond_to? :specification_version then
64
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
65
- s.specification_version = 3
66
-
67
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
68
- else
69
- end
70
- else
71
- end
72
- end
@@ -1,71 +0,0 @@
1
- module ChronoTrigger
2
-
3
- class CronEntry
4
-
5
- def initialize(options={})
6
- set_days(options[:days])
7
- set_hours(options[:hours])
8
- set_minutes(options[:minutes])
9
- end
10
-
11
- DAYS_CONVERSION = {
12
- :sunday => 0,
13
- :monday => 1,
14
- :tuesday => 2,
15
- :wednesday => 3,
16
- :thursday => 4,
17
- :friday => 5,
18
- :saturday => 6
19
- }
20
-
21
- CALENDAR_DAYS = *(1..31)
22
-
23
- def set_hours(*args)
24
- args.compact!
25
- args.flatten!
26
- raise ChronoTrigger::ConfigurationException.new("Hours must be less than 24") if args.any? {|hour| hour >= 24}
27
- @hours = args
28
- end
29
-
30
- def set_days(*args)
31
- args.compact!
32
- args.flatten!
33
- args.each {|day| raise ChronoTrigger::ConfigurationException.new("Day #{day} setting is invalid") if !DAYS_CONVERSION.keys.include?(day)}
34
- @days = args.map { |day| DAYS_CONVERSION[day] }
35
- end
36
-
37
- def set_minutes(*args)
38
- args.compact!
39
- args.flatten!
40
- raise ChronoTrigger::ConfigurationException.new("Minutes must be less than 60") if args.any? {|minute| minute >= 60}
41
- @minutes = args
42
- end
43
-
44
- def set_calendar_days(*args)
45
- args.compact!
46
- args.flatten!
47
- args.each {|calendar_day| raise ChronoTrigger::ConfigurationException.new("Calendar Day #{calendar_day} setting is invalid") if !CALENDAR_DAYS.include?(calendar_day)}
48
- @calendar_days = args
49
- end
50
-
51
- def matches?(datetime)
52
- if @minutes.blank? && !@days.blank?
53
- raise ChronoTrigger::ConfigurationException.new("Days were specified for a CronEntry with no minutes specified")
54
- end
55
-
56
- if (@minutes.blank? || @hours.blank?) && !@calendar_days.blank?
57
- raise ChronoTrigger::ConfigurationException.new("Calendar Days were specified for a CronEntry with no minutes and/or no hours specified")
58
- end
59
-
60
- if !@days.blank? && !@calendar_days.blank?
61
- raise ChronoTrigger::ConfigurationException.new("Calendar Days and Days were specified. This is unsupported.")
62
- end
63
-
64
- return false if !@minutes.blank? && !@minutes.include?(datetime.min)
65
- return false if !@hours.blank? && !@hours.include?(datetime.hour)
66
- return false if (!@days.blank? && !@days.include?(datetime.wday)) || (!@calendar_days.blank? && !@calendar_days.include?(datetime.day))
67
- return true
68
- end
69
-
70
- end
71
- end
@@ -1,37 +0,0 @@
1
- module ChronoTrigger
2
-
3
- class Process
4
-
5
- def run(options={})
6
- @thread = Thread.new do
7
- setup(options)
8
-
9
- shell = ChronoTrigger::Shell.new
10
- options[:trigger_files] ? shell.load_triggers(options[:trigger_files].split(":")) : shell.load_triggers
11
- loop do
12
- shell.execute_triggers
13
- sleep 1.minute.to_i
14
- end
15
- end
16
-
17
- @thread.join
18
- end
19
-
20
- def stop
21
- @thread.exit
22
- end
23
-
24
- private
25
- def setup(options={})
26
- if application_context = options[:application_context]
27
- ENV['RAILS_ENV'] = options[:env] || "development"
28
-
29
- application_path = File.join(application_context, 'config', 'environment')
30
- STDOUT.puts "Loading application environment at #{File.join(application_context, 'config', 'environment')} for '#{ENV['RAILS_ENV']}' environment."
31
- require(application_path)
32
- end
33
-
34
- require "chrono_trigger"
35
- end
36
- end
37
- end
@@ -1,293 +0,0 @@
1
- require File.join(File.dirname(__FILE__), 'process')
2
- require "logger"
3
- require 'optparse'
4
- require 'yaml'
5
- require 'fileutils'
6
-
7
- module ChronoTrigger
8
- class Runner
9
-
10
- attr_accessor :options
11
- private :options, :options=
12
-
13
- def self.run
14
- new
15
- end
16
-
17
- def self.shutdown
18
- @@instance.shutdown
19
- end
20
-
21
- def initialize
22
- @@instance = self
23
- parse_options
24
-
25
- @process = ProcessHelper.new(options[:logger], options[:pid_file], options[:user], options[:group])
26
-
27
- if options[:stop]
28
- @process.kill
29
- exit(1)
30
- end
31
-
32
- pid = @process.running?
33
- if pid
34
- if options[:force]
35
- STDOUT.puts "Shutting down existing ChronoTrigger."
36
- @process.kill
37
- @process = ProcessHelper.new(options[:logger], options[:pid_file], options[:user], options[:group])
38
- else
39
- STDERR.puts "There is already a ChronoTrigger process running (pid #{pid}), exiting."
40
- exit(1)
41
- end
42
- elsif pid.nil?
43
- STDERR.puts "Cleaning up stale pidfile at #{options[:pid_file]}."
44
- end
45
-
46
- start
47
- end
48
-
49
- def parse_options
50
- self.options = {
51
- :log_level => Logger::INFO,
52
- :daemonize => false,
53
- :pid_file => File.join('', 'var', 'run', 'chrono_trigger.pid'),
54
- :env => "development"
55
- }
56
-
57
- OptionParser.new do |opts|
58
- opts.summary_width = 25
59
-
60
- opts.banner = "ChronoTrigger - Execute cron jobs within the context of a Rails application\n\n",
61
- "usage: chrono_trigger [options...]\n",
62
- " chrono_trigger --help\n",
63
- " chrono_trigger --version\n"
64
-
65
- opts.separator ""
66
- opts.separator ""; opts.separator "ChronoTrigger Options:"
67
-
68
- opts.on("-tTRIGGER_FILES", "--triggers TRIGGER_FILES", "Path to file(s) specifying triggers to be executed. Multiple files should be separated by a :. When also specifying -a, this path will be relative to the application path") do |trigger_files|
69
- options[:trigger_files] = trigger_files
70
- end
71
-
72
- opts.on("-f", "--force", "Force restart of ChronoTrigger process (can be used in conjunction with -P).") do
73
- options[:force] = true
74
- end
75
-
76
- opts.on("-s", "--stop", "Stop a currently running ChronoTrigger process (can be used in conjunction with -P).") do
77
- options[:stop] = true
78
- end
79
-
80
- opts.separator ""
81
- opts.separator ""; opts.separator "Rails options:"
82
-
83
- opts.on("-aAPPLICATION", "--application RAILS", "Path to Rails application context to execture triggers in.") do |application_context|
84
- options[:application_context] = application_context
85
- end
86
-
87
- opts.on("-eENVIRONMENT", "--environment ENVIRONMENT", "Rails environment to execute triggers in.") do |environment|
88
- options[:env] = environment
89
- end
90
-
91
- opts.separator ""
92
- opts.separator ""; opts.separator "Process:"
93
-
94
- opts.on("-PFILE", "--pid FILENAME", "save PID in FILENAME when using -d option.", "(default: #{options[:pid_file]})") do |pid_file|
95
- options[:pid_file] = File.expand_path(pid_file)
96
- end
97
-
98
- opts.on("-u", "--user USER", "User to run as") do |user|
99
- options[:user] = user.to_i == 0 ? Etc.getpwnam(user).uid : user.to_i
100
- end
101
-
102
- opts.on("-gGROUP", "--group GROUP", "Group to run as") do |group|
103
- options[:group] = group.to_i == 0 ? Etc.getgrnam(group).gid : group.to_i
104
- end
105
-
106
- opts.separator ""; opts.separator "Logging:"
107
-
108
- opts.on("-L", "--log [FILE]", "Path to print debugging information.") do |log_path|
109
- options[:logger] = File.expand_path(log_path)
110
- end
111
-
112
- opts.on("-v", "Increase logging verbosity (may be used multiple times).") do
113
- options[:log_level] -= 1
114
- end
115
-
116
- opts.on("-d", "Run as a daemon.") do
117
- options[:daemonize] = true
118
- end
119
- end.parse!
120
- end
121
-
122
- def start
123
- drop_privileges
124
-
125
- @process.daemonize if options[:daemonize]
126
-
127
- if application_context = options[:application_context]
128
- Dir.chdir(application_context)
129
- end
130
-
131
- setup_signal_traps
132
- @process.write_pid_file
133
-
134
- STDOUT.puts "Starting ChronoTrigger."
135
- @chrono_trigger_process = ChronoTrigger::Process.new
136
- @chrono_trigger_process.run(options)
137
-
138
- @process.remove_pid_file
139
- end
140
-
141
- def drop_privileges
142
- ::Process.egid = options[:group] if options[:group]
143
- ::Process.euid = options[:user] if options[:user]
144
- end
145
-
146
- def shutdown
147
- begin
148
- STDOUT.puts "Shutting down."
149
- @chrono_trigger_process.stop
150
- exit(1)
151
- rescue Object => e
152
- STDERR.puts "There was an error shutting down: #{e}"
153
- exit(70)
154
- end
155
- end
156
-
157
- def setup_signal_traps
158
- Signal.trap("INT") { shutdown }
159
- Signal.trap("TERM") { shutdown }
160
- end
161
- end
162
-
163
- class ProcessHelper
164
-
165
- def initialize(log_file = nil, pid_file = nil, user = nil, group = nil)
166
- @log_file = log_file
167
- @pid_file = pid_file
168
- @user = user
169
- @group = group
170
- end
171
-
172
- def safefork
173
- begin
174
- if pid = fork
175
- return pid
176
- end
177
- rescue Errno::EWOULDBLOCK
178
- sleep 5
179
- retry
180
- end
181
- end
182
-
183
- def daemonize
184
- sess_id = detach_from_terminal
185
- exit if pid = safefork
186
-
187
- Dir.chdir("/")
188
- File.umask 0000
189
-
190
- close_io_handles
191
- redirect_io
192
-
193
- return sess_id
194
- end
195
-
196
- def detach_from_terminal
197
- srand
198
- safefork and exit
199
-
200
- unless sess_id = ::Process.setsid
201
- raise "Couldn't detach from controlling terminal."
202
- end
203
-
204
- trap 'SIGHUP', 'IGNORE'
205
-
206
- sess_id
207
- end
208
-
209
- def close_io_handles
210
- ObjectSpace.each_object(IO) do |io|
211
- unless [STDIN, STDOUT, STDERR].include?(io)
212
- begin
213
- io.close unless io.closed?
214
- rescue Exception
215
- end
216
- end
217
- end
218
- end
219
-
220
- def redirect_io
221
- begin; STDIN.reopen('/dev/null'); rescue Exception; end
222
-
223
- if @log_file
224
- begin
225
- STDOUT.reopen(@log_file, "a")
226
- STDOUT.sync = true
227
- rescue Exception
228
- begin; STDOUT.reopen('/dev/null'); rescue Exception; end
229
- end
230
- else
231
- begin; STDOUT.reopen('/dev/null'); rescue Exception; end
232
- end
233
-
234
- begin; STDERR.reopen(STDOUT); rescue Exception; end
235
- STDERR.sync = true
236
- end
237
-
238
- def rescue_exception
239
- begin
240
- yield
241
- rescue Exception
242
- end
243
- end
244
-
245
- def write_pid_file
246
- return unless @pid_file
247
- FileUtils.mkdir_p(File.dirname(@pid_file))
248
- File.open(@pid_file, "w") { |f| f.write(::Process.pid) }
249
- File.chmod(0644, @pid_file)
250
- end
251
-
252
- def remove_pid_file
253
- return unless @pid_file
254
- File.unlink(@pid_file) if File.exists?(@pid_file)
255
- end
256
-
257
- def running?
258
- return false unless @pid_file
259
-
260
- pid = File.read(@pid_file).chomp.to_i rescue nil
261
- pid = nil if pid == 0
262
- return false unless pid
263
-
264
- begin
265
- ::Process.kill(0, pid)
266
- return pid
267
- rescue Errno::ESRCH
268
- return nil
269
- rescue Errno::EPERM
270
- return pid
271
- end
272
- end
273
-
274
- def kill
275
- return false unless @pid_file
276
-
277
- pid = File.read(@pid_file).chomp.to_i rescue nil
278
- pid = nil if pid == 0
279
- return false unless pid
280
-
281
- begin
282
- ::Process.kill("TERM", pid)
283
- remove_pid_file
284
- return pid
285
- rescue Errno::ESRCH
286
- return nil
287
- rescue Errno::EPERM
288
- return pid
289
- end
290
-
291
- end
292
- end
293
- end