public
Description: A Rails plugin for managing and installing rake-centric crontab files.
Homepage: http://dougmcinnes.com/2008/07/14/craken/
Clone URL: git://github.com/latimes/craken.git
craken / lib / craken.rb
100644 102 lines (91 sloc) 3.471 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
require 'socket'
require "#{File.dirname(__FILE__)}/raketab"
 
module Craken
  def self.determine_raketab_files
    if File.directory?("#{DEPLOY_PATH}/config/craken/") # Use hostname specific raketab first.
      raketabs = Dir["#{DEPLOY_PATH}/config/craken/*raketab*"].partition {|f| f =~ %r[/raketab.*$] }
      raketabs.last.empty? ? raketabs.first : raketabs.last.grep(/#{HOSTNAME}_raketab/)
    else
      Dir["#{DEPLOY_PATH}/config/raketab*"]
    end
  end
 
  HOSTNAME = Socket.gethostname.split('.').first.downcase.strip
  DEPLOY_PATH = ENV['deploy_path'] || RAILS_ROOT
  RAKETAB_FILES = ENV['raketab_files'].split(":") rescue determine_raketab_files
  CRONTAB_EXE = ENV['crontab_exe'] || "/usr/bin/crontab"
  RAKE_EXE = ENV['rake_exe'] || (rake = `which rake`.strip and rake.empty?) ? "/usr/bin/rake" : rake
  RAKETAB_RAILS_ENV = ENV['raketab_rails_env'] || RAILS_ENV
  # assumes root of app is name of app, also takes into account
  # capistrano deployments
  APP_NAME = ENV['app_name'] || (DEPLOY_PATH =~ /\/([^\/]*)\/releases\/\d*$/ ? $1 : File.basename(DEPLOY_PATH))
 
  # strip out the existing raketab cron tasks for this project
  def load_and_strip
    crontab = ''
    old = false
    `#{CRONTAB_EXE} -l`.each_line do |line|
      line.strip!
      if old || line == "### #{APP_NAME} raketab"
        old = line != "### #{APP_NAME} raketab end"
      else
        crontab << line
        crontab << "\n"
      end
    end
    crontab
  end
 
  def append_tasks(crontab, raketab)
    crontab << "### #{APP_NAME} raketab\n"
    raketab.each_line do |line|
      line.strip!
      unless line =~ /^#/ || line.empty? # ignore comments and blank lines
        sp = line.split
        crontab << sp[0,5].join(' ')
        crontab << " cd #{DEPLOY_PATH} && #{RAKE_EXE} --silent RAILS_ENV=#{RAKETAB_RAILS_ENV}"
        sp[5,sp.size].each do |task|
          crontab << " #{task}"
        end
        crontab << "\n"
      end
    end
    crontab << "### #{APP_NAME} raketab end\n"
    crontab
  end
 
  # install new crontab
  def install(crontab)
    filename = ".crontab#{rand(9999)}"
    File.open(filename, 'w') { |f| f.write crontab }
    `#{CRONTAB_EXE} #{filename}`
    FileUtils.rm filename
  end
  
  def raketab(files=RAKETAB_FILES)
    files.map do |file|
      next unless File.exist?(file)
      builder = file =~ /.(\w+)$/ ? "build_raketab_from_#{$1}" : "build_raketab"
      send(builder.to_sym, file)
    end.join("\n")
  end
  
  private
    def build_raketab_from_rb(file)
      eval(File.new(file).read).tabs
    end
  
    def build_raketab_from_yml(file)
      yml = YAML::load(ERB.new(File.read(file)).result(binding))
      yml.map do |name,tab|
        format = []
        format << (tab['min'] || tab['minute'] || '0')
        format << (tab['hour'] || '0')
        format << (tab['day'] || '*')
        format << (tab['month'] =~ /^\d+$/ ? tab['month'] : Date._parse(tab['month'].to_s)[:mon] || '*')
        format << ((day = tab['weekday'] || tab['wday'] and day =~ /^\d+$/ ? day : Date._parse(day.to_s)[:wday]) || '*')
        format << tab['command']
        format.join(' ')
      end.join("\n")
    end
    alias_method :build_raketab_from_yaml, :build_raketab_from_yml
    
    def build_raketab(file)
      ERB.new(File.read(file)).result(binding)
    end
 
    def method_missing(method, *args)
      method.to_s =~ /^build_raketab/ ? build_raketab(*args) : super
    end
end