#!/usr/local/bin/ruby
ENV['PATH'] = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin'
begin
    require 'rubygems'
    require 'builder'
    require_gem 'rscm', '=0.3.14'

    REPOS_URL = 'http://code.whytheluckystiff.net/'
    REPOS_DIR = '/usr/local/www/data'
    TRAC_CHANGES = 'http://code.whytheluckystiff.net/%s/changeset/%d'
    TRAC_FILE = 'http://code.whytheluckystiff.net/%s/browser/trunk/%s?rev=%d'

    # rss easy method
    def rss(io, repo_name, revs)
        feed = Builder::XmlMarkup.new( :target => io, :indent => 2 )
        feed.instruct! :xml, :version => "1.0", :encoding => "UTF-8"
        feed.rss( 'xmlns:admin' => 'http://webns.net/mvcb/',
                  'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
                  'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
                  'version' => '2.0' ) do |rss|
            rss.channel do |c|
                # channel stuffs
                c.dc :language, "en-us" 
                c.dc :creator, "Ruby #{ VERSION }"
                c.dc :date, Time.now.utc.strftime( "%Y-%m-%dT%H:%M:%S+00:00" )
                c.admin :generatorAgent, "rdf:resource" => "http://builder.rubyforge.org/"
                c.title "Why's Subversion Repos: #{repo_name}"
                c.link REPOS_URL
                c.description "Feed listing recent changesets to #{repo_name} repositories"

                revs.each do |repos, rev, changes|
                c.item do |item|

                    link = TRAC_CHANGES % [repos, rev.identifier]
                    item.title "[#{repos}:#{rev.identifier}] #{rev.files.map {|f| f.path}.join(', ')}"
                    item.link link
                    item.guid link
                    item.dc :creator, rev.developer
                    item.dc :date, rev.time.utc.strftime( "%Y-%m-%dT%H:%M:%S+00:00" )
                    item.description %{
                    <style type="text/css">
                        #changes, #changes td, #changes th { 
                            color: #333;
                            font-family: verdana, arial, sans-serif;
                            font-size: 11px;
                        }
                        h3 { font-size: 14px; }
                        h4 { font-size: 12px; }
                    </style>
                    <div id="changes">
                        <h3><nobr>#{ rev.developer }&nbsp;&nbsp;&nbsp;&nbsp;#{ rev.time }</nobr></h3>
                        <h4>Modified Files</h4>
                        <ul>#{ rev.files.map {|f| %{
                            <li><a href='#{TRAC_FILE % [repos, f.path, rev.identifier]}'>#{ f.path }</a>: #{ f.status }</li>
                        } } }</ul>
                        <h4>Log</h4>
                        <p>#{ rev.message.gsub( /\r?\n/, '<br />' ) }</p>
                        <h4>Changes</h4>
                        <table border="0" cellspacing="2" cellpadding="2">
                        <tr><th>Status</th><th>Adds</th><th>Dels</th><th>Path</th></tr>
                        #{ changes.map { |i, status, adds, dels, path| %{
                            <tr><td>#{status}</td><td>+#{adds}</td><td>-#{dels}</td>
                                <td><a href='#{link}#file#{i}'>#{path}</a></td></tr>
                        } } }
                        </table>
                    </div>
                    }
                end
                end
            end
        end 
    end

    all_revs = []
    Dir['/home/svn/repos/*'].each do |repos|
        next unless File.directory? repos
        repos = File.basename(repos)

        scm = RSCM::Subversion.new("file:///home/svn/repos/#{repos}/trunk")
        revs = scm.revisions(Time.now - (30*24*60*60)).map do |rev|
            i = -1
            changes = 
                rev.files.sort_by { |f| f.path }.map do |f| 
                    dels, adds = 0, 0
                    if f.status == "MODIFIED"
                        f.diff(scm) do |diff|
                            diff = diff.read
                            dels = diff.scan(/^\-(?!\-\-)/).length
                            adds = diff.scan(/^\+(?!\+\+)/).length
                        end 
                    end
                    i += 1
                    [i, f.status, adds, dels, f.path]
                end
            [repos, rev, changes]
        end
        File.open(File.join(REPOS_DIR, "#{repos}.xml"), 'w') do |f|
            rss(f, repos, revs)
        end
        all_revs += revs
    end

    all_revs = all_revs.sort_by { |repos, rev| Time.now - rev.time }.slice(0, 20)

    File.open( '/usr/local/www/data/index.xml', 'w' ) do |f|
        rss(f, 'all', all_revs)
    end
rescue => e
    File.open( '/tmp/hook-error.log', 'w' ) do |f|
        f << %{
           #{ e.class }
           #{ e.message }
           #{ e.backtrace }
        }
    end
end
