#!/usr/bin/python
# Author: Jamie Strandboge <jamie@canonical.com>
# Copyright (C) 2009 Canonical, Ltd.
# License: GPLv3

import lpl_common
import optparse
import sys

parser = optparse.OptionParser()
parser.add_option("-n", "--not-security", help="Unmark as security bug", action="store_true")
parser.add_option("-P", "--is-private", help="Mark as private", action="store_true")
parser.add_option("-w", "--comment", help="Comment to add to bug", metavar="COMMENT")
parser.add_option("-s", "--status", help="Set status", metavar="STATUS")
parser.add_option("-d", "--duplicate", help="Mark as duplicate", metavar="DUPLICATE")
parser.add_option("-D", "--debian-task", help="create Debian bug task", action="store_true")
parser.add_option("-p", "--package", help="Assign to package", metavar="PACKAGE")
parser.add_option("-t", "--tag", help="Add a tag", metavar="TAG")
parser.add_option("--subscribe", help="Subscribe yourself", action="store_true")

(opt, args) = parser.parse_args()

lp = lpl_common.connect()

def subscribed(bug, person):
    '''This looks for a person in the bug subscription list.
       Sometimes, the API is ugly'''
    for subscriber in bug.subscriptions:
        if str(subscriber.person) == str(person):
            return True
    return False

subject = ''
comment = ''
if opt.comment:
    subject = ''
    comment = opt.comment

valid_status = ['New', 'Incomplete', 'Invalid', "Won't Fix", 'Confirmed', 'Triaged', 'In Progress', 'Fix Committed', 'Fix Released', 'Unknown']
if opt.status:
    if opt.status not in valid_status:
        print >> sys.stderr ("Invalid status '%s'. Aborting") % (opt.status)
        sys.exit(1)

for num in args:
    unsub_self = False
    bug = lp.bugs[num]
    print "%s..." % (num)

    # Set privacy
    if opt.is_private and not bug.private:
        print "\tmarking private..."
        bug.private = True
        if not lpl_common.save(bug):
            print >>sys.stderr, "aborting update of LP: #%s" % (num)
            continue

    # don't act on a bug if it is a duplicate - actually set duplicity later
    if opt.duplicate:
        if bug.duplicate_of:
            print >>sys.stderr, "\taborting as LP: #%s is a duplicate" % (bug.id)
        if bug.duplicates:
            print >>sys.stderr, "\taborting as LP: #%s has duplicates itself" % (bug.id)
            sys.exit(1)

    # reset flags if not security
    if opt.not_security:
        do_save = False
        if not opt.is_private and bug.private:
            print "\tmarking public..."
            bug.private = False
            do_save = True

        if bug.security_related:
            print "\tmarking non-security..."
            bug.security_related = False
            do_save = True

        if do_save and not lpl_common.save(bug):
            print >>sys.stderr, "aborting update of LP: #%s" % (num)
            continue

        # reset subscribers if not private
        if not opt.is_private:
            print "\tsubscribing ubuntu-bugs..."
            bug.subscribe(person=lp.people["ubuntu-bugs"])

        # hack to get around unsubscribing a team that is giving you perms
        # to see a private bug -- you must be subscribed yourself first.
        if bug.private and not subscribed(bug, lp.me):
            print "\ttemporarily subscribing self..."
            bug.subscribe(person=lp.me)
            unsub_self = True

    # Set status and comment before potentially unsubscribing...
    if opt.status:
        print "\tmarking %s..." % (opt.status)
        for task in bug.bug_tasks:
            task.status=opt.status
            lpl_common.save(task)

    # Assign a bug to a package
    if opt.package:
        ubuntu = lp.distributions['ubuntu']
        package = ubuntu.getSourcePackage(name=opt.package)
        if not package:
            print >>sys.stderr, "aborting update of LP: #%s - could not find package %s" % (num, opt.package)
            sys.exit(1)
        if len(bug.bug_tasks) > 1:
            print >>sys.stderr, "aborting update of LP: #%s - it has more than one task" % (num)
            sys.exit(1)
        print "\tassigning to package %s..." % (opt.package)
        task=bug.bug_tasks[0]
        task.target=package
        lpl_common.save(task)

    # optionally add comment
    if comment != '':
        print "\tadding comment..."
        bug.newMessage(content=comment, subject=subject)

    if opt.tag:
        bug = lp.bugs[num] # reload bug in case it changed
        print "\tadding tag %s..." % (opt.tag)
        tag_list = bug.tags
        tag_list.append('%s' % opt.tag)
        bug.tags = tag_list
        lpl_common.save(bug)

    # add a Debian bug task to the bug report (this marks it as needing forwarding)
    if opt.debian_task:
        print "\tcreating a Debian bug task..."
        debian = lp.distributions['debian']
        bug.addTask(target=debian)

    if opt.subscribe:
        print "\tsubscribing you to the bug..."
        bug.subscribe(person=lp.me)

    # mark duplicity at end so master bug gets less(?) e-mail
    if opt.duplicate:
        master = lp.bugs[opt.duplicate]
        print "\tsetting as duplicate of LP: #%s" % (opt.duplicate)
        bug.duplicate_of=master
        lpl_common.save(bug)

    if opt.not_security:
        print "\tunsubscribing ubuntu-security..."
        bug.unsubscribe(person=lp.people["ubuntu-security"])

    if opt.is_private:
        print "\tunsubscribing ubuntu-bugs..."
        bug.unsubscribe(person=lp.people["ubuntu-bugs"])


    # always tag the bug using release info if it is an apport bug
    release_tags = { '8.04':'hardy', '8.10':'gutsy', '9.04':'jaunty', '9.10':'karmic', '10.04':'lucid' }
    if 'apport-bug' in bug.tags or 'apport-package' in bug.tags or 'apport-crash' in bug.tags:
        for line in bug.description.split('\n'):
            if 'DistroRelease: ' in line:
                release = line.split()[-1]
                break
        if release in release_tags:
            release_tag = release_tags[release]
            if release_tag not in bug.tags:
                bug = lp.bugs[num] # reload bug in case it changed
                print "\tadding tag %s..." % (release_tag)
                tag_list = bug.tags
                tag_list.append('%s' % release_tag)
                bug.tags = tag_list
                lpl_common.save(bug)

    # This must be the last thing done!
    if unsub_self:
        print "\tunsubscribing self..."
        try:
            bug.unsubscribe(person=lp.me)
        except:
            # This should die since we're not allowed to see it anymore
            pass
