chrono_trigger 0.2.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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