#!/usr/bin/env ruby

require 'parsedate'
require 'tempfile' 

# Options handling
require 'optparse'
require 'ostruct'

TEST_AFTER_REVISION = 'c7a7d86bdbc8c4a7351cb7142c90e74a6ef08515'

OPTIONS = OpenStruct.new

options = OptionParser.new do |opts|
  opts.on('-h', '--help', 'Output this help information') do |h|
    OPTIONS.help = h
  end

  opts.on('-r', '--results PATH', 'Path to results') do |r|
    OPTIONS.results = r
  end
end

options.parse!

if OPTIONS.help or not OPTIONS.results then
  puts options.summarize
  exit
end

class Commit
  attr_reader :commit, :working_path, :results_path, :final_path

  def initialize(commit)
    @commit       = commit
    @working_path = Tempfile.new('rbx-working-').path
    @results_path = Tempfile.new('rbx-results-').path
    @final_path   = OPTIONS.results + '/' + @commit + '/'
  end

  def date
    matches = `git log --pretty=fuller #{commit}`.split(/\n/)[4].match(/: +(.+ \d\d\d\d) ([+-]\d\d)(\d\d)/)
    date    = ParseDate.parsedate(matches[1])
    puts matches[2].to_i * 3600 + matches[3].to_i
    Time.gm(*date) + matches[2].to_i * 3600 + matches[3].to_i
  end

  def date_string
    d = date
    "#{d.year}-#{'%02d' % d.month}-#{'%02d' % d.day}-" +
    "#{'%02d' % d.hour}-#{'%02d' % d.min}-#{'%02d' % d.sec}"
  end

  def complete?
    File.directory?(final_path)
  end

  def cleanup
    execute "rm -rf #{working_path}",false
    execute "rm -rf #{results_path}",false
  end

  def benchmark
    begin
      execute "git clone git://github.com/evanphx/rubinius.git #{working_path}"

      Dir.chdir working_path
      execute 'rake build'

      Dir.mkdir results_path
      execute "bin/bm -c -d -f -p #{results_path} -w >/dev/null 2>&1"

      execute "mv #{results_path} #{final_path}"
    rescue
      warn "Failed during benchmark"
    ensure
      cleanup
    end
  end
end

def execute(command,raise_error = true)
  puts command
  unless system command then
    warn $!

    if raise_error
      raise RunTimeError,$!
    end
  end
end

def benchmarkable_commits
  commits = []

  `git log`.grep(/^commit/).each do |line|
    break if line =~ /#{TEST_AFTER_REVISION}$/
    commit = Commit.new(line.match(/\w+$/)[0])
    break if commit.complete?
    commits << commit
  end

  commits.reverse
end

while true do
  benchmarkable_commits.each { |commit| commit.benchmark }
  sleep 60
end
