PageRenderTime 86ms CodeModel.GetById 22ms RepoModel.GetById 10ms app.codeStats 0ms

/external/crontab.rb

http://ruby-hive.googlecode.com/
Ruby | 367 lines | 218 code | 30 blank | 119 comment | 11 complexity | 508f71c57de9df068b6e290554b7dc1c MD5 | raw file
  1. #
  2. # crontab.rb
  3. #
  4. # A modified version of the original Crontab from RAA
  5. # here http://raa.ruby-lang.org/project/crontab/
  6. =begin
  7. = crontab.rb
  8. == SYNOPSIS
  9. -----
  10. require "crontab"
  11. # case 1
  12. tab = Crontab.open("/var/cron/tabs/" + ENV['USER'])
  13. # case 2
  14. tab = Crontab.new
  15. tab.add("5,35 0-23/2 * * *"){system "a_program"}
  16. loop do
  17. tab.run
  18. sleep 60
  19. end
  20. -----
  21. == DESCRIPTION
  22. Crontab class represent crontab(5) file.
  23. == CLASS Crontab
  24. === CONSTANT
  25. : Crontab::CRONTAB_VERSION
  26. A version string.
  27. === CLASS METHOD
  28. : open(filename)
  29. returns a new Crontab object from a crontab(5) file.
  30. : new(str)
  31. returns a new Crontab object for str. str is formatted in crontab(5).
  32. === METHOD
  33. : add(str, job)
  34. : add(str) do .... end
  35. adds a cron record. str format is same as the first five field of
  36. crontab(5). A correspoinding job can be given by string job or a
  37. block.
  38. : grep(time)
  39. returns an array consists of jobs which whould be invoked in time.
  40. : run
  41. : run do |job| .... end
  42. invokes all job should be done now. If a block is given, string jobs
  43. are passed to each block invocation.
  44. == MODULE Crontab::CronRecord
  45. This module is used to provide features to each cron record.
  46. === METHOD
  47. : min
  48. : hour
  49. : mday
  50. : mon
  51. : wday
  52. returns all times matching to each pattern.
  53. : command
  54. returns correspoding job.
  55. : run
  56. : run do |job| .... end
  57. invokes the job immediately. If a block is given, string jobs are
  58. passed to each block invocation.
  59. == AUTHOR
  60. Gotoken
  61. == HISTORY
  62. 2001-01-04: (BUG) camma and slash were misinterpreted <gotoken#notwork.org>
  63. 2000-12-31: replaced Array#filter with collect! <zn#mbf.nifty.com>
  64. 2000-07-06: (bug) Crontab#run throws block <gotoken#notwork.org>
  65. 2000-07-03: (bug) open->File::open <gotoken#notwork.org>
  66. 2000-04-07: Error is subclass of StandardError <matz#netlab.co.jp>
  67. 2000-04-06: Fixed bugs. <c.hintze#gmx.net>
  68. 2000-04-06: Started. <gotoken#notwork.org>
  69. =end
  70. module CronTab
  71. class Crontab
  72. CRONTAB_VERSION = "2001-01-04"
  73. include Enumerable
  74. def Crontab.open(fn)
  75. new(File::open(fn).read)
  76. end
  77. def table
  78. return @table
  79. end
  80. def initialize(type=:min)
  81. @type = type
  82. case @type
  83. when :sec
  84. @table = parse_sec("")
  85. when :min
  86. @table = parse_min("")
  87. end
  88. end
  89. def each(&block)
  90. @table.each(&block)
  91. end
  92. def add(str, job = nil, name="", info="", &action)
  93. job = action if block_given?
  94. case @type
  95. when :sec
  96. @table.push((parse_timedate_sec(str) << job << name << info ).extend(CronRecordSec))
  97. when :min
  98. @table.push((parse_timedate_min(str) << job << name << info ).extend(CronRecordMin))
  99. end
  100. end
  101. attr_reader :table
  102. def run(*args, &block)
  103. grep(Time.now).each{|record|
  104. record.run(*args, &block)
  105. }
  106. end
  107. def grep(time)
  108. case @type
  109. when :sec
  110. return grep_sec(time)
  111. when :min
  112. return grep_min(time)
  113. end
  114. end
  115. def grep_min(time)
  116. @table.find_all{|record|
  117. record.min.include? time.min and record.hour.include? time.hour and record.mday.include? time.mday and record.mon.include? time.mon and record.wday.include? time.wday
  118. }
  119. end
  120. def grep_sec(time)
  121. @table.find_all{|record|
  122. record.sec.include? time.sec and record.min.include? time.min and record.hour.include? time.hour and record.mday.include? time.mday and record.mon.include? time.mon and record.wday.include? time.wday
  123. }
  124. end
  125. def table()
  126. return @table
  127. end
  128. private
  129. def parse_sec(str)
  130. res = []
  131. str.each{|line|
  132. next if /(\A#)|(\A\s*\Z)/ =~ line
  133. res.push(parse_timedate(line).
  134. push(line.scan(/(?:\S+\s+){5}(.*)/).shift[-1]))
  135. }
  136. res.collect{|record|
  137. record.extend CronRecordSec
  138. }
  139. end
  140. private
  141. def parse_min(str)
  142. res = []
  143. str.each{|line|
  144. next if /(\A#)|(\A\s*\Z)/ =~ line
  145. res.push(parse_timedate(line).
  146. push(line.scan(/(?:\S+\s+){4}(.*)/).shift[-1]))
  147. }
  148. res.collect{|record|
  149. record.extend CronRecordMin
  150. }
  151. end
  152. def parse_timedate(str)
  153. case @type
  154. when :sec
  155. return parse_timedate_sec(str)
  156. when :min
  157. return parse_timedate_min(str)
  158. end
  159. end
  160. def parse_timedate_sec(str)
  161. second, minute, hour, day_of_month, month, day_of_week =
  162. str.scan(/^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/).shift
  163. day_of_week = day_of_week.downcase.gsub(/#{WDAY.join("|")}/){
  164. WDAY.index($&)
  165. }
  166. arr = [
  167. parse_field(second, 0, 59),
  168. parse_field(minute, 0, 59),
  169. parse_field(hour, 0, 23),
  170. parse_field(day_of_month, 1, 31),
  171. parse_field(month, 1, 12),
  172. parse_field(day_of_week, 0, 6),
  173. ]
  174. return arr
  175. end
  176. def parse_timedate_min(str)
  177. minute, hour, day_of_month, month, day_of_week =
  178. str.scan(/^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/).shift
  179. day_of_week = day_of_week.downcase.gsub(/#{WDAY.join("|")}/){
  180. WDAY.index($&)
  181. }
  182. arr = [
  183. parse_field(minute, 0, 59),
  184. parse_field(hour, 0, 23),
  185. parse_field(day_of_month, 1, 31),
  186. parse_field(month, 1, 12),
  187. parse_field(day_of_week, 0, 6),
  188. ]
  189. return arr
  190. end
  191. def parse_field(str, first, last)
  192. list = str.split(",")
  193. list.map!{|r|
  194. r, every = r.split("/")
  195. every = every ? every.to_i : 1
  196. f,l = r.split("-")
  197. range = if f == "*"
  198. first..last
  199. elsif l.nil?
  200. f.to_i .. f.to_i
  201. elsif f.to_i < first
  202. raise FormatError.new("out of range (#{f} for #{first})")
  203. elsif last < l.to_i
  204. raise FormatError.new("out of range (#{l} for #{last})")
  205. else
  206. f.to_i .. l.to_i
  207. end
  208. range.to_a.find_all{|i| (i - first) % every == 0}
  209. }
  210. list.flatten!
  211. list
  212. end
  213. module CronRecordMin
  214. def min; self[0]; end
  215. def hour; self[1]; end
  216. def mday; self[2]; end
  217. def mon; self[3]; end
  218. def wday; self[4]; end
  219. def command; self[5]; end
  220. def name; self[6]; end
  221. def info; self[7]; end
  222. def run(*args)
  223. case command
  224. when String
  225. if iterator?
  226. yield(command)
  227. else
  228. puts "-->"
  229. puts "Message from #{$0} (pid=#{$$}) at #{Time.now}"
  230. puts command
  231. puts "EOF"
  232. end
  233. when Proc
  234. command.call(*args)
  235. end
  236. end
  237. end
  238. module CronRecordSec
  239. def sec; self[0]; end
  240. def min; self[1]; end
  241. def hour; self[2]; end
  242. def mday; self[3]; end
  243. def mon; self[4]; end
  244. def wday; self[5]; end
  245. def command; self[6]; end
  246. def name; self[7]; end
  247. def info; self[8]; end
  248. def run(*args)
  249. case command
  250. when String
  251. if iterator?
  252. yield(command)
  253. else
  254. puts "-->"
  255. puts "Message from #{$0} (pid=#{$$}) at #{Time.now}"
  256. puts command
  257. puts "EOF"
  258. end
  259. when Proc
  260. command.call(*args)
  261. end
  262. end
  263. end
  264. WDAY = %w(sun mon tue wed thu fri sat)
  265. class Error < StandardError; end
  266. class FormatError < Error; end
  267. end
  268. if __FILE__ == $0
  269. # tab = Crontab.new(<<"\r\n\r\n")
  270. ## run five minutes after midnight, every day
  271. #5 0 * * * $HOME/bin/daily.job >> $HOME/tmp/out 2>&1
  272. ## run at 2:15pm on the first of every month -- output mailed to paul
  273. #15 14 1 * * $HOME/bin/monthly
  274. ## run at 10 pm on weekdays, annoy Joe
  275. #0 22 * * 1-5 mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
  276. #23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
  277. #5 4 * * sun echo "run at 5 after 4 every sunday"
  278. #\r\n\r\n
  279. #
  280. # [
  281. # Time.local(2000, 4, 5, 0, 5),
  282. # Time.local(2000, 4, 1, 14, 15),
  283. # Time.local(2000, 4, 5, 22, 0),
  284. # Time.local(2000, 4, 5, 22, 23),
  285. # Time.local(2000, 4, 9, 4, 5)
  286. # ].each{|t|
  287. # #print ">>> ", t, "\n"
  288. # #tab.grep(t).each{|r| p r.command}
  289. # }
  290. tab = Crontab.new
  291. #tab.add("23 0-23/2 * * *"){system "ls"}
  292. tab.add("* * * * * *", "...........................second", "mexico", "")
  293. tab.add("0 * * * * *", "...........................minute", "mexico-second", "")
  294. #tab.add("0 * * * *", "...........................hour")
  295. tab.table.each {|record|
  296. puts "name: #{record.name}"
  297. puts "cmd: #{record.command}"
  298. puts "#sec #{record.sec.length}: #{record.sec.join(',')}"
  299. puts "#min #{record.min.length}: #{record.min.join(',')}"
  300. puts "#hour #{record.hour.length}: #{record.hour.join(',')}"
  301. puts "#mday #{record.mday.length}: #{record.mday.join(',')}"
  302. puts "#mon #{record.mon.length}: #{record.mon.join(',')}"
  303. puts "#wday #{record.wday.length}: #{record.wday.join(',')}"
  304. }
  305. while true
  306. tab.run
  307. sleep 1
  308. end
  309. end
  310. end