#!/usr/bin/ruby

require 'rubygems'
require 'cgi'
require 'uri'
require 'net/http'
require 'json'

class Servlet
  CONFIGFILE_PATH = "/tmp"
  DEPLOY_PATH = "/tmp"
  CHECKOUT = 'svn checkout --non-interactive'
  UPDATE = 'svn update --non-interactive'
  OPTIONAL_DEPLOY = 'deploy.sh'

  #--------------------------------------------------
  # Process CGI request
  def cgi_process_request
    @cgi = CGI.new('html4')

    # Assembla may test if we are alive
    if @cgi['project'].empty?
      cgi_response('OK', 'Deploy agent is alive')
    else
      deploy()
    end

  end


  #--------------------------------------------------
  # Respond to CGI request
  def cgi_response(code, text = '')
    @cgi.out("status"     => code,
             "type"       => "text/html") {text}
  end


  #-----------------------------------------------
  # Load a bash shell script file containing config variables
  #!/bin/bash
  #export PROJECT_NAME=svnspace
  #export SPACE_TOOL_ID=cwIozk53r5r3QnPaaWP00om
  #export SECRET_KEY=e934f76c7f23d49a1239ef38f91041b94b4aa3df
  #export POST_URL=http://www.assembla.com/tool_events
  #export SCM_URL=http://svn.assembla.com/svn/svnspace/trunk
  #export SCM=svn
  #export SCM_LOGIN=deploybot1330294941
  #export SCM_PASSWORD=dMPyQ25cirxyznPaaWP00om
         
  def read_config(configfile)
    @project_name  = ''
    @space_tool_id = ''
    @secret_key    = ''
    @post_url      = ''
    @scm_url       = ''
    @scm           = ''
    @scm_login     = ''
    @scm_password  = ''

    begin
      File.open(configfile, 'r') do |f|
        line = f.gets
        while line do
          env = line.split(/[ =]/)

          if env.size > 2
            case env[1]
            when 'PROJECT_NAME'  then @project_name  = env[2].strip
            when 'SPACE_TOOL_ID' then @space_tool_id = env[2].strip
            when 'SECRET_KEY'    then @secret_key    = env[2].strip
            when 'POST_URL'      then @post_url      = env[2].strip
            when 'SCM_URL'       then @scm_url       = env[2].strip
            when 'SCM'           then @scm           = env[2].strip
            when 'SCM_LOGIN'     then @scm_login     = env[2].strip
            when 'SCM_PASSWORD'  then @scm_password  = env[2].strip
            end
          end

          line = f.gets
        end
      end
    rescue => e
      @message = e.message
      return false
    end

    if @project_name.empty?
      @message = "Missing PROJECT_NAME in #{configfile}"
      return false
    elsif @space_tool_id.empty?
      @message = "Missing SPACE_TOOL_ID in #{configfile}"
      return false
    elsif @secret_key.empty?
      @message = "Missing SECRET_KEY in #{configfile}"
      return false
    elsif @post_url.empty?
      @message = "Missing POST_URL in #{configfile}"
      return false
    elsif @scm_url.empty?
      @message = "Missing SCM_URL in #{configfile}"
      return false
    end

    return true
  end


  #-----------------------------------------------
  # Post a response to the Build tool "Build results"
  def post_build_results(status, start_time, log, comment, link)

    # Create a parameter list for the POST
    opts = { :status     => status,
             :start_time => start_time,
             :end_time   => Time.now }
    opts.merge!(:log => log) if !log.nil? && !log.empty?
    opts.merge!(:comment => comment) if !comment.nil? && !comment.empty?
    opts.merge!(:link => link) if !link.nil? && !link.empty?

    data = { :space_tool_id => @space_tool_id, 
             :secret_key    => @secret_key, 
             :opts          => opts.to_json }

    # Build the POST
    uri = URI.parse(@post_url)
    req = Net::HTTP::Post.new(uri.path)
    req.set_form_data(data)

    # Send the POST
    r, rd = Net::HTTP.new(uri.host, uri.port).request(req)
    return (r.code == "201") # Net::HTTPCreated
  end


  #-----------------------------------------------
  # Deploy the application
  def deploy
    start_time = Time.now

    # Read the configuration file
    configfile = "#{CONFIGFILE_PATH}/#{@cgi['project']}_conf.sh"
    rc = read_config(configfile)
    if !rc
      cgi_response('NOT_FOUND', "#{configfile}: #{@message}")
      return
    end

    deploydir = "#{DEPLOY_PATH}/#{@project_name}"

    # Construct a deployment command
    login_creds = ""
    if ! @scm_login.empty? && ! @scm_password.empty?
      login_creds = "--username \"#{@scm_login}\" --password \"#{@scm_password}\""
    end

    if File.directory?(deploydir)
      deploycmd = "#{UPDATE} #{login_creds} #{deploydir}"
    else
      deploycmd = "#{CHECKOUT} #{login_creds} #{@scm_url} #{deploydir}"
    end

    # Deploy the app
    comment = ''
    code = 'OK'
    buildlog = `#{deploycmd} 2>&1`
    rc = $?
    if rc != 0
      code = 'NOT_FOUND'
      comment = "Unable to deploy from URL #{@scm_url} with username #{@scm_login}"
    end

    # Run optional deploy script
    if File.executable?(OPTIONAL_DEPLOY)
      buildlog = buildlog + `#{OPTIONAL_DEPLOY} 2>&1`
      rc = $?
    end

    # Notify Build tool
    link = nil   # Use the default link to build results
    post_build_results(rc, start_time, buildlog, comment, link)
    cgi_response(code, comment)

  end

end

Servlet.new.cgi_process_request

