#!/usr/pkg/bin/ruby193

$VERBOSE = true

$:.unshift(File::join(File::dirname(File::dirname(__FILE__)), "lib"))

require 'getoptlong'
require 'rubyforge'

PROGRAM     = File::basename $0

USAGE = <<-EOL
SYNOPSIS

  #{ PROGRAM } [options]* mode [mode_args]*

DESCRIPTION

  simplistic script which automates a limited set of rubyforge operations

MODES

  setup()
    initializes your .rubyforge directory.  you need to run this first before
    doing anything else.

    example :
      #{ PROGRAM } setup

  config([project])
    Helps you populate your auto-config.yml file by scraping rubyforge and
    getting your groups, projects, and releases.

    example :
      #{ PROGRAM } config
      #{ PROGRAM } config myproject

  names()
    Prints out the names of your configured groups and projects.

    example :
      #{ PROGRAM } names

  create_package(group_id, package_name)
    creates the named package under the specified group.

    example :
      #{ PROGRAM } create_package 1024 traits
      #{ PROGRAM } create_package codeforpeople.com traits

  add_release(group_id, package_id, release_name, userfile)
    release a file as release_name under the specified group_id and
    package_id.

    example :
      #{ PROGRAM } add_release codeforpeople.com traits 0.8.0 traits-0.8.0.gem
      #{ PROGRAM } add_release codeforpeople.com traits 0.8.0 traits-0.8.0.tgz
      #{ PROGRAM } add_release 1024 1242 0.8.0 traits-0.8.0.gem
      #{ PROGRAM } add_release 1024 1242 0.8.0 traits-0.8.0.gem

  add_file(group_id, package_id, release_id, userfile)
    add a file to an existing release under the specified group_id,
    package_id, and release_id

    example :
      #{ PROGRAM } add_file codeforpeople.com traits 0.8.0 traits-0.8.0.gem
      #{ PROGRAM } add_file codeforpeople.com traits 0.8.0 traits-0.8.0.tgz
      #{ PROGRAM } add_file 1024 1242 0.8.0 traits-0.8.0.gem

  delete_package(group_id, package_name)
    deletes a package and all its files.

    example :
      #{ PROGRAM } delete_package codeforpeople.com traits
      #{ PROGRAM } delete_package 1024 traits

  post_news(group_id, summary, details)
    posts a news item to the specified group

    example :
      #{ PROGRAM } post_news codeforpeople.com "new release" "this release is great!"
      #{ PROGRAM } post_news 1024 traits "new release" "this release is great!"
NOTES

  - In order to use group_id, package_id, or release_id by name,
    rather than number, you must edit the rubyforge[group_ids] and
    rubyforge[package_ids] translation tables in your config.yml. See
    the config command for more information and help.

TODO

  - add error checking.  this may require mods to the REST API as 
    well to ensure that it returns useful error codes.

OPTIONS

  global :
    --help            , -h
      this message
    --config          , -c
      specify a config file (default #{ RubyForge::CONFIG_F })
    --username        , -u
      specify username, taken from config otherwise
    --password        , -p
      specify password, taken from config otherwise

  add_release :
    --is_private      , -P
      if true, release is not public
    --release_date    , -r
      specify time of release (default 'now')
    --type_id         , -t
      specify filetype code (default determined by ext)
    --processor_id    , -o
      specify processor (default 'Any')
    --release_notes   , -n
      specify release notes as string or file
    --release_changes , -a
      specify release changes as string or file
    --preformatted    , -f
      specify whether release_notes/changes are preformatted

EOL

mode = ARGV.shift

opts = GetoptLong::new(
         [ "--help"            , "-h" , GetoptLong::NO_ARGUMENT ],
         [ "--force"           , "-F" , GetoptLong::NO_ARGUMENT ],
         [ "--username"        , "-u" , GetoptLong::REQUIRED_ARGUMENT ],
         [ "--password"        , "-p" , GetoptLong::REQUIRED_ARGUMENT ],
         [ "--is_private"      , "-P" , GetoptLong::REQUIRED_ARGUMENT ],
         [ "--release_date"    , "-r" , GetoptLong::REQUIRED_ARGUMENT ],
         [ "--type_id"         , "-t" , GetoptLong::REQUIRED_ARGUMENT ],
         [ "--processor_id"    , "-o" , GetoptLong::REQUIRED_ARGUMENT ],
         [ "--release_notes"   , "-n" , GetoptLong::REQUIRED_ARGUMENT ],
         [ "--release_changes" , "-a" , GetoptLong::REQUIRED_ARGUMENT ],
         [ "--preformatted"    , "-f" , GetoptLong::NO_ARGUMENT ]
       ).enum_for.inject({}) { |h, (k, v)| h.update k.delete('-') => v }

rubyforge = RubyForge.new
rubyforge.configure opts

mode = "help" if opts["help"]

case mode
when %r/help/
  USAGE.display
when %r/login/
  puts "No need to call login since each API request is authenticated separately"
when %r/logout/
  puts "No need to call logout since each API request is authenticated separately"
when %r/setup/
  rubyforge.setup
when %r/config/
  project = ARGV.shift
  if project then
    rubyforge.scrape_project(project)
  else
    rubyforge.scrape_config
  end
when %r/names/
  rf = rubyforge.autoconfig
  puts "groups  : #{rf["group_ids"].keys.sort.join(", ")}"
  puts "packages: #{rf["package_ids"].keys.sort.join(", ")}"
when %r/create_package/
  page, msg = "/frs/admin/index.php", "post_content"

  group_id, package_name = ARGV

  abort "no <group_id>"     unless group_id
  abort "no <package_name>" unless package_name

  group_id = Integer(group_id) rescue group_id

  rubyforge.create_package group_id, package_name
when %r/post_news/
  group_id, summary, details = ARGV

  abort "no <group_id>"     unless group_id

  group_id = Integer(group_id) rescue group_id

  rubyforge.post_news group_id, summary, details
when %r/delete_package/
  group_id, package_id = ARGV

  abort "no <group_id>"   unless group_id
  abort "no <package_id>" unless package_id

  group_id   = Integer(group_id)   rescue group_id
  package_id = Integer(package_id) rescue package_id

  rubyforge.delete_package group_id, package_id
when %r/add_release/
  group_id, package_id, release_name, userfile = ARGV

  abort "no <group_id>"     unless group_id
  abort "no <package_id>"   unless package_id
  abort "no <release_name>" unless release_name
  abort "no <userfile>"     unless userfile

  group_id   = Integer(group_id)   rescue group_id
  package_id = Integer(package_id) rescue package_id

  rubyforge.add_release group_id, package_id, release_name, userfile
when %r/add_file/
  group_id, package_id, release_id, userfile = ARGV

  abort "no <group_id>"   unless group_id
  abort "no <package_id>" unless package_id
  abort "no <release_id>" unless release_id
  abort "no <userfile>"   unless userfile

  group_id   = Integer(group_id)   rescue group_id
  package_id = Integer(package_id) rescue package_id
  release_id = Integer(release_id) rescue release_id

  rubyforge.add_file group_id, package_id, release_id, userfile
else
  abort USAGE
end
