#!/usr/bin/python
# Unembargo a security build from a PPA.
# Instead of showing up as "Pending" in the publication history, using the
# API causes the package to appear in the "Accepted" queue:
# https://edge.launchpad.net/ubuntu/jaunty/+queue?queue_state=2&queue_text=
#
# Copyright (C) 2009, Canonical, Ltd.
# Author: Kees Cook <kees@ubuntu.com>
#
# Copy from PPA to archive -security:
#  ./unembargo $PKG
#
# Copy from archive to a PPA:
#  ./unembargo --ppa ubuntu -d kees --pocket release $PKG

import sys, optparse, time
import lpl_common
import apt_pkg

apt_pkg.InitSystem();

parser = optparse.OptionParser()
parser.add_option("--ppa", help="The PPA to copy from (default: ubuntu-security/ppa)", metavar="GROUP[/PPA]", action='store', default='ubuntu-security/ppa')
parser.add_option("-r","--release", help="Limit unembargo to a specific set of comma-separate releases", metavar="SERIES", action='store', default=None)
parser.add_option("-n","--dry-run", help="Do not actually publish", action='store_true')
parser.add_option("--retries", help="Retry failed sync at most RETRIES times", action='store', metavar="RETRIES", default=1, type="int")
parser.add_option("--lpnet", help="Use lpnet instead of edge for LP API", action='store_true')
parser.add_option("-d", "--destination", help="The archive to copy to (default: Ubuntu Archive)", metavar="GROUP[/PPA]", action='store', default='ubuntu')
parser.add_option("--pocket", help="The destination pocket (default: Security)", metavar="POCKET", action='store', default='Security')
(opt, args) = parser.parse_args()

if len(args) < 1:
    print >>sys.stderr, 'Usage: %s [OPTIONS] PKG [PKG...]' % (sys.argv[0])
    sys.exit(1)

print "Loading Ubuntu Distribution ..."
lp = lpl_common.connect(use_edge=(not opt.lpnet))
ubuntu = lp.distributions['ubuntu']

dest_archive, dest_group, dest_ppa = lpl_common.get_archive(opt.destination, lp, verbose=True, distribution=ubuntu)

origin_archive, origin_group, origin_ppa = lpl_common.get_archive(opt.ppa, lp, verbose=True, distribution=ubuntu)

# Sanity checks due to LP: #334858
if origin_group == 'ubuntu' and dest_group == 'ubuntu':
    print >>sys.stderr, "Primary archive to primary archive copying is not allowed (LP: #334858)"
    sys.exit(1)
if dest_group == 'ubuntu' and opt.pocket != 'Security':
    print >>sys.stderr, "Copying to primary archive is only allow to the -security pocket (LP: #334858)"
    sys.exit(1)

series = dict()
if opt.release:
    serieses = opt.release.split(',')
    for series_name in serieses:
        series.setdefault(series_name, ubuntu.getSeries(name_or_version=series_name))

rc = 0
for pkg_name in args:
    unembargo = []
    seen = dict()

    # Locate the package to copy
    print "Locating %s ..." % (pkg_name)
    sources = origin_archive.getPublishedSources(source_name=pkg_name,
                                                 status='Published',
                                                 exact_match=True)

    # Filter for the series we want
    for source_item in sources:
        series_name = source_item.distro_series.name
        if len(series) > 0 and not series_name in series:
            continue
        if not seen.has_key(series_name):
            seen[series_name] = []
        seen[series_name].append(source_item)

    # Identify most recent package version across all pockets
    for series_name in seen.keys():
        if len(seen[series_name]) > 1:
            seen[series_name] = sorted(seen[series_name], cmp=lambda x, y: apt_pkg.VersionCompare(x.source_package_version, y.source_package_version), reverse=True)
        unembargo.append(seen[series_name][0])

    # Publish
    for source_item in unembargo:
        name = source_item.source_package_name
        version = source_item.source_package_version
        series_name = source_item.distro_series.name
        if opt.dry_run:
            action = "Want to publish"
        else:
            action = "Publishing"
        print "\t%s %s %s to %s-security ..." % (action, name, version, series_name)

        if not opt.dry_run:
            retries = opt.retries
            while retries > 0:
                start = time.time()
                try:
                    dest_archive.syncSource(
                        source_name=name, version=version,
                        from_archive=origin_archive, include_binaries=True,
                        to_series=series_name, to_pocket=opt.pocket)
                    retries = 0
                except lpl_common.HTTPError, err:
                    finish = time.time()
                    if 'same version already uploaded and waiting in ACCEPTED queue' in err.content:
                        print "\t\tAlready in ACCEPTED queue"
                        retries = 0
                        pass
                    else:
                        print >>sys.stderr, "Failed to sync (took %ds): %s\n%s" % (finish - start, str(err), err.response)
                        retries -= 1
                        if retries == 0:
                            rc = 1

sys.exit(rc)
