require 'rake/gempackagetask'
require 'rake/contrib/rubyforgepublisher'

namespace :release do
  PKG_NAME = "oupsnow"
  PKG_VERSION = "0.1.0"
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
  RUBY_FORGE_PROJECT = 'oupsnow'
  RUBY_FORGE_USER = 'shingara'
  AUTHOR = "Cyril Mougel"
  EMAIL = "cyril.mougel@gmail.com"
  HOMEPAGE = "http://oupsnow.rubyforge.org/"
  SUMMARY = "A bugtracker in Merb/Datamapper"
  EXCLUDE = [ /\.$/, /config\/database.yml$/, /config\/database.yml-/, 
    /database\.sqlite/,
    /\.log$/, /^pkg/, /\.git/, /^vendor\/rails/, 
    /^public\/(files|xml|articles|pages|index.html)/, 
    /^public\/(stylesheets|javascripts|images)\/theme/, /\~$/, 
    /\/\._/, /\/#/, /^Capfile/, /config\/deploy.rb/, 
    /tasks\/converter/, /log\//, /^doc\//, /^lib\/tasks\/release.rake/ ]
  RELEASE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"

  task :manifest do
    files = Dir.glob('**/*', File::FNM_DOTMATCH).reject do |f| 
      EXCLUDE.any? {|regex| f =~ regex }
    end
    files = files.sort.join "\n"
    File.open 'Manifest.txt', 'w' do |fp| fp.puts files end
  end


  spec = Gem::Specification.new do |s|
    s.name = PKG_NAME
    s.version = PKG_VERSION
    s.summary = SUMMARY
    s.has_rdoc = false

    s.files = File.read('Manifest.txt').split("\n") 
    s.require_path = '.'
    s.author = AUTHOR
    s.email = EMAIL
    s.homepage = HOMEPAGE  
    s.rubyforge_project = RUBY_FORGE_PROJECT
    s.platform = Gem::Platform::RUBY 

  end

  Rake::GemPackageTask.new(spec) do |p|
    p.gem_spec = spec
    p.need_tar = true
    p.need_zip = true
  end

  desc "Publish the release files to RubyForge."
  task :tag_git do
    system("git tag release_#{PKG_VERSION.gsub(/\./,'_')}")
    system("git push origin --tags")
  end

  desc 'Upload website files to rubyforge'
  task :upload_website do
    host = "#{RUBY_FORGE_USER}@rubyforge.org"
    remote_dir = "/var/www/gforge-projects/#{RUBY_FORGE_PROJECT}/"
    local_dir = 'website'
    sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
  end

  desc "Publish the release files to RubyForge."
  task :rubyforge_upload => [:package] do
    files = ["tgz", "zip"].map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }

    if RUBY_FORGE_PROJECT then
      require 'net/http'
      require 'open-uri'

      project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
      project_data = open(project_uri) { |data| data.read }
      group_id = project_data[/[?&]group_id=(\d+)/, 1]
      raise "Couldn't get group id" unless group_id

      # This echos password to shell which is a bit sucky
      if ENV["RUBY_FORGE_PASSWORD"]
        password = ENV["RUBY_FORGE_PASSWORD"]
      else
        print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
        password = STDIN.gets.chomp
      end

      login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
        data = [
          "login=1",
          "form_loginname=#{RUBY_FORGE_USER}",
          "form_pw=#{password}"
        ].join("&")
        http.post("/account/login.php", data)
      end

      cookie = login_response["set-cookie"]
      raise "Login failed" unless cookie
      headers = { "Cookie" => cookie }

      release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
      release_data = open(release_uri, headers) { |data| data.read }
      package_id = release_data[/[?&]package_id=(\d+)/, 1]
      raise "Couldn't get package id" unless package_id

      first_file = true
      release_id = ""

      files.each do |filename|
        basename  = File.basename(filename)
        file_ext  = File.extname(filename)
        file_data = File.open(filename, "rb") { |file| file.read }

        puts "Releasing #{basename}..."

        release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
          release_date = Time.now.strftime("%Y-%m-%d %H:%M")
          type_map = {
            ".zip"    => "3000",
            ".tgz"    => "3110",
            ".gz"     => "3110",
          }; type_map.default = "9999"
          type = type_map[file_ext]
          boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"

          query_hash = if first_file then
                         {
                           "group_id" => group_id,
                           "package_id" => package_id,
                           "release_name" => RELEASE_NAME,
                           "release_date" => release_date,
                           "type_id" => type,
                           "processor_id" => "8000", # Any
                           "release_notes" => "",
                           "release_changes" => "",
                           "preformatted" => "1",
                           "submit" => "1"
                         }
                       else
                         {
                           "group_id" => group_id,
                           "release_id" => release_id,
                           "package_id" => package_id,
                           "step2" => "1",
                           "type_id" => type,
                           "processor_id" => "8000", # Any
                           "submit" => "Add This File"
                         }
                       end

          query = "?" + query_hash.map do |(name, value)|
            [name, URI.encode(value)].join("=")
          end.join("&")

          data = [
            "--" + boundary,
            "Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
            "Content-Type: application/octet-stream",
            "Content-Transfer-Encoding: binary",
            "", file_data, ""
          ].join("\x0D\x0A")

          release_headers = headers.merge(
            "Content-Type" => "multipart/form-data; boundary=#{boundary}"
          )

          target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
          http.post(target + query, data, release_headers)
        end

        if first_file then
          release_id = release_response.body[/release_id=(\d+)/, 1]
          raise("Couldn't get release id") unless release_id
        end

        first_file = false
      end
    end
  end
end
