Skip to content

Commit

Permalink
Barebone version of a Sinatra app to show cronjobs on a timeline.
Browse files Browse the repository at this point in the history
  • Loading branch information
Shashank Date committed Jan 4, 2011
1 parent 73fd59c commit e2c4920
Show file tree
Hide file tree
Showing 91 changed files with 7,044 additions and 0 deletions.
1 change: 1 addition & 0 deletions .rvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rvm use ree-1.8.7-head@timeline
44 changes: 44 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
== Description

A barebone Sinatra app to show the cron jobs on a timeline.

Powered by SIMILE Timeline Widget: http://www.simile-widgets.org/wiki/Timeline.

Tested on Ubuntu 10.10, FireFox 3.6.13, using ree-1.8.7-head with gemset:

json_pure (1.4.6)
rack (1.2.1)
shotgun (0.8)
sinatra (1.1.2)
tilt (1.2.1)

== Version

0.0.1 (Jan 3rd, 2011)

== Installation

Install the required gems and then git clone git://github.com/shanko/misc.git

== Usage

$ shotgun cron_timeline.rb

== ToDo

* Improve the rendering of the timeline
* RSpec examples
* Documentation

== Author

Shashank Date <mailto:stdate@gmail.com>

== License

MIT license: http://www.opensource.org/licenses/mit-license.php





12 changes: 12 additions & 0 deletions cron_timeline.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require 'rubygems'
require 'sinatra'
require 'json'
require 'models/parse_cron'

get "/cron" do
cron_jobs = ['*/15 * * 1 * whoami','*/30 * * 1 * uname' ]
hr_window = 2
erb :cron, :locals => { :json => to_timeline_hash(cron_jobs,hr_window).to_json }
end


148 changes: 148 additions & 0 deletions models/parse_cron.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
require "pp"

def parse_time_element(te,from,to)
ret = []

if te =~ /^\d+$/
ret << te.to_i
elsif te =~ /^[*]$/
ret = (from..to).to_a
elsif te =~ /,/
te.split(',').each do |e|
if e =~ /^\d+$/
ret << e.to_i
elsif e =~ /-/
ret += parse_time_element(e,from,to)
else
raise "Cannot parse: #{te}"
end
end
elsif te =~ /^(\d+)-(\d+)\/?(\d+)?$/
if $3.to_i < 2
ret = ($1.to_i..$2.to_i).to_a
else
step = $3.to_i
start = $1.to_i
stop = $2.to_i
while start < stop do
ret << start
start += step
end
end
elsif te =~ /^[*]\/(\d+)$/
freq = $1.to_i
to_limit = (to - from + 1)
if freq > 0 && freq < to_limit
to_limit.times do |i|
m = i * freq
break if m >= to_limit
ret << m
end
else
raise "Cannot parse: #{te}"
end
else
raise "Cannot parse: #{te}"
end
ret
end

def canonize(min, hr, day, month, wday, cmd)
cmd_str = cmd.join(" ")
minutes = parse_time_element(min, 0, 59)
hours = parse_time_element(hr, 0, 23)
days = parse_time_element(day, 1, 31)
months = parse_time_element(month, 1, 12)
week_days = parse_time_element(wday, 0, 6)
return [minutes, hours, days, months, week_days, cmd_str]
end

def will_execute_at?(cron_entry,at_time=Time.now)
val = true
at = [at_time.min, at_time.hour, at_time.day, at_time.month, at_time.wday]

cron_entry.each_with_index do |element,i|
next if element.class == String
found = false
element.each{|t| found = (at[i] == t); break if found}
unless found
val = found
break
end
end

val
end

def will_execute_when?(cron_entry,from_time,to_time)
times = []
return times if from_time > to_time
min = 0
next_minute = from_time + min * 60
while (next_minute <= to_time)
times << next_minute if will_execute_at?(cron_entry,next_minute)
min += 1
next_minute = from_time + min * 60
end
times
end

def cron_hash(cron_jobs,hour_window=1)
reverse_cron_hash = {}
cron_jobs.each do |line|
next if (line.strip.size == 0) || (line =~ /^\s*#/)
min, hr, day, month, week_day, *cmd = line.strip.split

begin
cron_entry = canonize(min, hr, day, month, week_day, cmd)
# pp cron_entry

from, to = Time.now, Time.now + (hour_window * 60 * 60)
arr = will_execute_when?(cron_entry,from,to)

arr.each do |time_element|
if reverse_cron_hash[time_element.to_s]
reverse_cron_hash[time_element.to_s] << cron_entry[-1] unless reverse_cron_hash[time_element.to_s].include?(cron_entry[-1])
else
reverse_cron_hash[time_element.to_s] = [cron_entry[-1]]
end
end

rescue
puts "---------------------\n" + line + ' ' + $!.to_s
end
end
reverse_cron_hash
end

def to_timeline_hash(cron_jobs,hour_window)
chash = cron_hash(cron_jobs,hour_window)
events_arr = []
chash.each do |key,val|
val.each do |cmd|
events_arr << {"start" => key, "instant" => true, "title" => cmd, "description" => ""}
end
end

event_data = {
'dateTimeFormat' => 'Gregorian',
'events' => events_arr
}

# pp event_data

event_data
end

if __FILE__ == $0
# min hr day month week-day command
cron_jobs = ['*/15 * * 1 * whoami','*/30 * * 1 * uname' ]
# cron_jobs = `crontab -l`
# cron_jobs = File.readlines("cronfile.txt")

puts
pp to_timeline_hash(cron_jobs,2)
end



7 changes: 7 additions & 0 deletions public/timeline_ajax/content/history.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<html>
<head>
<title>Dummy Page for Keeping Track of History</title>
</head>
<body>
</body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/bubble-bottom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/bubble-left.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/bubble-right.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/bubble-top-left.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/bubble-top-right.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/bubble-top.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/close-button.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/copy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/message-left.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/message-right.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/message-top-left.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/timeline_ajax/images/message-top-right.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions public/timeline_ajax/scripts/signal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*==================================================
* This file is used to detect that all outstanding
* javascript files have been loaded. You can put
* a function reference into SimileAjax_onLoad
* to have it executed once all javascript files
* have loaded.
*==================================================
*/
(function() {
var substring = SimileAjax.urlPrefix + "scripts/signal.js";
var heads = document.documentElement.getElementsByTagName("head");
for (var h = 0; h < heads.length; h++) {
var node = heads[h].firstChild;
while (node != null) {
if (node.nodeType == 1 && node.tagName.toLowerCase() == "script") {
var url = node.src;
var i = url.indexOf(substring);
if (i >= 0) {
heads[h].removeChild(node); // remove it so we won't hit it again

var count = parseInt(url.substr(url.indexOf(substring) + substring.length + 1));
SimileAjax.loadingScriptsCount -= count;
if (SimileAjax.loadingScriptsCount == 0) {
var f = null;
if (typeof SimileAjax_onLoad == "string") {
f = eval(SimileAjax_onLoad);
SimileAjax_onLoad = null;
} else if (typeof SimileAjax_onLoad == "function") {
f = SimileAjax_onLoad;
SimileAjax_onLoad = null;
}

if (f != null) {
f();
}
}
return;
}
}
node = node.nextSibling;
}
}
})();
Loading

0 comments on commit e2c4920

Please sign in to comment.