#!/usr/bin/python
#
# rebuildd-job - Manage jobs for rebuildd
#
# (c) 2007 - Julien Danjou <acid@debian.org>
#
#   This software is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; version 2 dated June, 1991.
#
#   This software is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this software; if not, write to the Free Software
#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
#

from rebuildd.Rebuildd import Rebuildd
from rebuildd.RebuilddConfig import RebuilddConfig
from rebuildd.Package import Package
from rebuildd.JobStatus import JobStatus
from rebuildd.Job import Job
import sys, os.path

def usage():
    print "%s -- Manage job for rebuildd" % os.path.basename(sys.argv[0])
    print "Usage: %s [command] <opts>\n" % os.path.basename(sys.argv[0])
    print "Commands:"
    print "   add                     - add jobs, reading from stdin"
    print "   add-deps                - add build-depends, reading from stdin"
    print "   add-quinn-diff <dist>   - add package reading quinn-diff input from stdin"
    print "   requeue <jobid>         - requeue job for rebuild"
    print "   delete <jobid>          - delete job"
    print "   list-deps               - list the whole depends table"
    print "   list <criteria>=<value> - list jobs matching criteria"
    print "   stats                   - view a nice graph of build status"
    sys.exit(1)

def add_deps():
    empty = True
    for line in sys.stdin.readlines():
        empty = False
        args = line.strip().split(' ')
        Rebuildd().add_deps(job_id=args[0], dependency_ids=args[1:])

    if empty:
        print "E: usage: %s\n   read <job_id> <dependency_job_id> [dependency_job_id] [...] from stdin" % sys.argv[0]
        sys.exit(1)

def dep_list_to_string(job_list):
    output_string = ""
    for job in job_list:
	output_string = output_string + " " + str(job.id)
    return output_string

def display_dep():
    jobs = Job.selectBy()
    print "  id  |    dependencies     "
    print "------+----------------------"
    for job in jobs:
        print "%04.4s | %021.21s" % (job.id, dep_list_to_string(job.deps))

def add():
    empty = True
    for line in sys.stdin.readlines():
        empty = False
        args = line.strip().split(' ')
        if len(args) == 4:
            Rebuildd().add_job(args[0], args[1], args[2], args[3])
        if len(args) == 5:
            Rebuildd().add_job(args[0], args[1], args[2], args[3], mailto=None, arch=args[4])
        if len(args) == 6:
            Rebuildd().add_job(args[0], args[1], args[2], args[3], mailto=args[5], arch=args[4])
    if empty:
        print "E: usage: %s\n   read <package> <version> <priority> <dist> [arch] [mailto] from stdin" % sys.argv[0]
        sys.exit(1)

def add_quinn_diff(dist):
    for line in sys.stdin.readlines():
        name = line.split('/')[1].split('_')[0]
        version = line.split('/')[1].split('_')[1].split('.dsc')[0]
        priority = line.split('/')[1].split('_')[1].split('.dsc')[1].split(':')[0][2:]
        Rebuildd().add_job(name, version, priority, dist)

def requeue_job(jobid):
    if not Rebuildd().requeue_job(jobid):
        print "E: rebuild not accepted"
        sys.exit(1)

def list():
    if len(sys.argv) == 3:
        try:
            (critname, critvalue) = sys.argv[2].split('=')
        except ValueError:
            print "E: usage: %s list criteria=value" % os.path.basename(sys.argv[0])
            return False
    else:
        print_jobs(Job.selectBy())
        return True

    if critname == "package":
        critvaluepkg = critvalue.split('_')
        pkgname = critvaluepkg[0]
        pkgver = None
        if len(critvaluepkg) > 1:
            pkgver = critvaluepkg[1]
        if pkgver:
            pkgs = Package.selectBy(name=pkgname, version=pkgver)
        else:
            pkgs = Package.selectBy(name=pkgname)
        for pkg in pkgs:
            print_jobs(Job.selectBy(package=pkg))

    if critname == "arch":
        print_jobs(Job.selectBy(arch=critvalue))

    if critname == "dist":
        print_jobs(Job.selectBy(dist=critvalue))

    if critname == "host":
        print_jobs(Job.selectBy(host=critvalue))

    if critname == "status":
        try:
            print_jobs(Job.selectBy(status=getattr(JobStatus, critvalue)))
        except AttributeError:
            print "E: unknown status"
            sys.exit(1)

    if critname == "id":
        print_jobs(Job.selectBy(id=critvalue))

def stats():
    nbjobs = Job.selectBy().count()
    wait = Job.selectBy(status=JobStatus.WAIT).count()
    wait += Job.selectBy(status=JobStatus.WAIT_LOCKED).count()
    building = Job.selectBy(status=JobStatus.BUILDING).count()
    ok = Job.selectBy(status=JobStatus.BUILD_OK).count()
    failed = Job.selectBy(status=JobStatus.SOURCE_FAILED).count()
    failed += Job.selectBy(status=JobStatus.BUILD_FAILED).count()
    failed += Job.selectBy(status=JobStatus.POST_BUILD_FAILED).count()

    if nbjobs > 0:
        wait *= 10.0 / nbjobs
        building *= 10.0 / nbjobs
        failed *= 10.0 / nbjobs
        ok *= 10.0 / nbjobs
    else:
        wait = 0.0
        building = 0.0
        failed = 0.0
        ok = 0.0

    lines = 10
    while lines > 0:
        print "[;1m%3.0d %% |" % (lines * 10),
        if int(round(wait)) >= lines:
            print " [34;1m##0 ",
        else:
            print "    ",
        if int(round(building)) >= lines:
            print " [35;1m##0 ",
        else:
            print "    ",
        if int(round(failed)) >= lines:
            print " [31;1m##0 ",
        else:
            print "    ",
        if int(round(ok)) >= lines:
            print " [32;1m##0 ",
        else:
            print "    ",
        print "[0m"
        lines -= 1
    print "[;1m      +----------------------"
    print "         WA   BU   FA   OK[0m"

def delete(jobid):
    job = Job.get(jobid)
    if job.status == JobStatus.WAIT:
        if job.destroySelf():
            print "I: job %s deleted" % jobid
        else:
            print "E: unable to delete job"
    else:
        print "E: can't delete job, build status is %s and should be WAIT" % JobStatus.whatis(job.status)

def print_headers():
    print "  id  |     package name     |    version     |    status    |  host  | dist  |  arch  "
    print "------+----------------------+----------------+--------------+--------+-------+--------"

def print_jobs(jobs):
    try:
        print_headers()
        for job in jobs:
            print "%05.5s | %020.20s | %014.14s | %012.12s | %06.6s | %05.5s | %06.6s" % \
                    (job.id, job.package.name, job.package.version,
                     JobStatus.whatis(job.status),
                     job.host, job.dist, job.arch)
    except IOError:
        pass

if len(sys.argv) > 1:
    # Init system
    Rebuildd()
    if sys.argv[1] == "add":
        add()
    if sys.argv[1] == "add-deps":
        add_deps()
    if sys.argv[1] == "list-deps":
        display_dep()
    if sys.argv[1] == "add-quinn-diff" and len(sys.argv) > 2:
        add_quinn_diff(sys.argv[2])
    if sys.argv[1] == "list":
        list()
    if sys.argv[1] == "stats":
        stats()
    if sys.argv[1] == "delete" and len(sys.argv) > 2:
        delete(int(sys.argv[2]))
    if sys.argv[1] == "requeue" and len(sys.argv) == 3:
        requeue_job(int(sys.argv[2]))
else:
    usage()
