#!/usr/bin/python
# kate: space-indent on; indent-width 4; replace-tabs on; indent-mode python; remove-trailing-space all;

# a helper script for Kubuntu devs to upload a release of frameworks/plasma/applications to the plasma archive
# will use git packaging and compare it against the relevant kubuntu-ppa/staging-foo PPA to check for sanity
# then put the files into upload/ ready for dput
# Copyright (others and) Jonathan Riddell 2015, may be copied under the GNU GPL version 2 or later

import shutil
import argparse
from distro_info import UbuntuDistroInfo
import glob
from launchpadlib.launchpad import Launchpad
import os
import re
import subprocess
import sys
import tempfile
import json

from lib.utils import *

parser = argparse.ArgumentParser(description="Upload new KDE software release to Ubuntu archive")
parser.add_argument("-v", "--version", required=True, help="Upstream version")
parser.add_argument("-p", "--packages", help="Override the list packages to upload (comma separated)")
parser.add_argument("-t", "--tmpdir", help="Temporary dir where the packages are prepared")
parser.add_argument("-r", "--releasetype", help="Type [applications,frameworks,plasma]", default="applications")
parser.add_argument("-a", "--ppa", help="PPA to get packages from (kubuntu-ppa/staging-RELEASETYPE)")
parser.add_argument("--sru", action="store_true", help="Do a Stable Release Upload")
parser.add_argument("--paused", action="store_true", help="Obsolete, has no effect")
parser.add_argument("--nopush", action="store_true", help="Obsolete, has no effect")

args = parser.parse_args()
releaseType = args.releasetype

# git base url for pkg-kde on moszumanska:
debian_git = "git+ssh://git.debian.org/git/pkg-kde/"

version = args.version
if not args.sru:
    release = UbuntuDistroInfo().devel()
else:
    release = UbuntuDistroInfo().stable()

lp = Launchpad.login_anonymously("kubuntu-archive-upload", "production")
ubuntu = lp.distributions["ubuntu"]
lpseries = ubuntu.getSeries(name_or_version=release)

if args.ppa:
    ppaString = args.ppa
    team, ppaName = ppaString.rsplit('/')
    print "Checking packages from %s" % ppaString
    ppa = lp.people[team].getPPAByName(name=ppaName)
else:
    ppaString = "kubuntu-ppa/staging-%s" % args.releasetype
    if args.releasetype == "applications":
        ppaString = "kubuntu-ppa/staging-%s" % "kdeapplications"
        print "Checking packages from ppaString"
        ppa = lp.people["kubuntu-ppa"].getPPAByName(name="staging-%s" % "kdeapplications")
    else:
        ppaString = "kubuntu-ppa/staging-%s" % args.releasetype
        print "Checking packages from ppaString"
        ppa = lp.people["kubuntu-ppa"].getPPAByName(name="staging-%s" % args.releasetype)

if args.packages:
    packages = args.packages.split(",")
else:
    f = open("package-name-lists/%s-%s" % (releaseType, release), "r")
    packages = f.readlines()
    f.close()

    packages = map(lambda line: line.strip("\r\n\t "), packages)
    packages = filter(lambda line: line and not line.startswith("#"), packages)

if args.tmpdir:
    basedir = args.tmpdir
else:
    basedir = tempfile.mkdtemp()
uploaddir = basedir + "/upload"

try:
  os.mkdir(uploaddir)
except OSError:
  print uploaddir + " dir exists"
  pass

skipped = []

topline = re.compile(r'^(\w%(name_chars)s*) \(([^\(\) \t]+)\)'
                     '((\s+%(name_chars)s+)+)\;'
                     % {'name_chars': '[-+0-9a-z.]'},
                     re.IGNORECASE)

def parseChangelogVersions(path):
    f = open(path, "r")
    lines = f.readlines()
    f.close()

    versions = []
    for line in lines:
        match = topline.search(line.strip("\r\n"))
        if match:
            versions.append(match.group(2))
    return versions

pythonDir = os.path.dirname(os.path.realpath(__file__))
with open(pythonDir + '/packaging-exceptions.json') as data_file:
    packagingExceptions = json.load(data_file)

for package in packages:
    print "package: " + package
    if package in packagingExceptions:
        version = packagingExceptions[package]
        print "using version %s" % version
    else:
        version = args.version

    archive = ubuntu.getArchive(name='primary')
    archive_package = archive.getPublishedSources(source_name=package)
    try:
        archive_version = archive_package[0].source_package_version
        if version in archive_version:
            print "=== Skipping %s because version %s is already in the archive" % (package, version)
            skipped.append(package)
            continue
    except IndexError:
        print "=== %s not in the archive, new package?" % (package)

    packageDir = basedir + "/" + package
    try:
      os.mkdir(packageDir)
    except OSError:
      print packageDir + " exists, removing"
      shutil.rmtree(packageDir)
      os.mkdir(packageDir)
    os.chdir(packageDir)

    if not args.sru:
        subprocess.check_call(["pull-ppa-source", "-d", ppaString, package, release])
        ppaDsc = glob.glob("%s_*.dsc" % (package,))[0]

        gitName = upstreamName(package)
        print "gitName" + gitName
        print "package" + package
        if package == "kde4libs":
            print "MMM gitName = kde4libs"
            gitName = "kde4libs" # as an exception this one has git repo named after package
        subprocess.check_call(["git", "clone", debian_git + args.releasetype + "/" + gitName, "git"])
        os.chdir("git")
        subprocess.check_call(["git", "checkout", "kubuntu_"+release+"_archive"])
    else:
        #TODO check over SRU stuff
        try:
            subprocess.check_call(["pull-ppa-source", "kubuntu-ppa/ppa", package, release])
            ninjasDsc = glob.glob("%s_*.dsc" % (package,))[0]
        except subprocess.CalledProcessError, e:
            if e.returncode == 2:
                print >> sys.stderr, "=== Skipping " + package + ", package not found."
                skipped.append(package)
                continue
            else:
                raise e
        try:
            os.chdir(glob.glob("%s-%s*" % (package, version))[0])
        except:
            print "=== Skipping " + package + " because it doesn't match our version"
            skipped.append(package)
            continue

    versions = parseChangelogVersions("debian/changelog")
    if version not in versions[0]:
        print >> sys.stderr, "=== Skipping " + package + ", changelog invalid."
        skipped.append(package)
        continue
    packageVersion = versions[0]

    changelogRelease = release
    subprocess.check_call(["dch", "-r", "-m", "-D", changelogRelease, ""])

    f = open("debian/changelog", "r")
    changelogLines = f.readlines()
    f.close()

    if "ppa" in changelogLines[0]:
        print >> sys.stderr, "=== Stripping [~ubuntuX]~ppa from version."
        changelogLines[0] = re.sub(r'(~ubuntu[\d\.]+)?~ppa\d+', "", changelogLines[0])
        packageVersion = re.sub(r'(~ubuntu[\d\.]+)?~ppa\d+', "", packageVersion)
        f = open("debian/changelog", "w")
        f.write("".join(changelogLines))
        f.close()
    elif args.sru:
        print >> sys.stderr, "No ~ppa in " + package + "changelog, aborting"
        sys.exit(1)

    if not args.sru:
        subprocess.check_call(["git", "commit", "-a", "-m", "NOCI\nRelease to " + release + "."])
        try:
            subprocess.check_call(["gbp", "buildpackage", "--git-ignore-branch", "--git-tag-only", "--git-sign-tags", "--git-debian-tag=ubuntu/%(version)s", "--git-debian-tag-msg='%(pkg)s Ubuntu release %(version)s'"])
            # don't tag until we know what tags are actually accepted by
            # pkg-kde
            print "FIXME tagging"
            pass
        except:
          print "already tagged"
        try:
            subprocess.check_call(["gbp", "buildpackage", "--git-ignore-branch", "--git-no-create-orig", "--git-ignore-new", "-S"])
        except subprocess.CalledProcessError:
            print "=== gbp failed"
    else:
        subprocess.check_call(["debuild", "-S", "-nc"])

    dscFileVersion = packageVersion
    match = re.search(r'^(\d+:)', dscFileVersion)
    if match:
        dscFileVersion = dscFileVersion[len(match.group(1)):]
    archiveDsc = "%s_%s.dsc" % (package, dscFileVersion)

    os.chdir("..")

    if not args.sru:
        p = subprocess.Popen(["debdiff", ppaDsc, archiveDsc], stdout=subprocess.PIPE)
        diff, _ = p.communicate()
        if p.returncode != 0 and p.returncode != 1:
            print >> sys.stderr, "=== debdiff error, aborting."
            sys.exit(1)
        p = subprocess.Popen(["diffstat", "-l", "-p1"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        diffstat, _ = p.communicate(diff)
        diffstatLines = diffstat.strip("\r\n\t ").splitlines()
        ## FIXME: Potential issue for a IndexOutOfRange error
        try:
         if len(diffstatLines) > 1 or diffstatLines[0] != "debian/changelog":
            p = subprocess.Popen(["less"], stdin=subprocess.PIPE)
            p.communicate("-PPA version; +git version\nPackage: %s\n\n=== diffstat ===\n\n%s\n\n=== diff ===\n\n%s" % (package, diffstat, diff))
            sys.stdout.write("==Package %s from the PPA differs from bzr, continue [Y/n]? " % (package))
            choice = raw_input().lower()
            if choice not in ("yes", "y", ""):
                sys.stdout.write("== %s skipped\n" % (package))
                skipped.append(package)
                continue
        except IndexError, e:
          print "IndexOutOfRange"

    subprocess.check_call(["dcmd", "cp", "%s_%s_source.changes" % (package, dscFileVersion), uploaddir])

print "Skipped packages: " + ', '.join(skipped)
print "Rememeber to push the git changes!"
