#! /usr/bin/python3

from __future__ import print_function

from contextlib import closing
import re
import sys
try:
    from urllib.request import urlopen
except ImportError:
    from urllib2 import urlopen

from debian import deb822
import launchpadlib.errors
from launchpadlib.launchpad import Launchpad

changes_re = re.compile(r'lp:\s+\#\d+(?:,\s*\#\d+)*', re.I)
bug_re = re.compile(r'\#(\d+)')

if sys.version >= '3':
    # Force encoding to UTF-8 even in non-UTF-8 locales.
    import io
    sys.stdout = io.TextIOWrapper(
        sys.stdout.detach(), encoding="UTF-8", line_buffering=True)
else:
    # Avoid having to do .encode('UTF-8') everywhere. This is a pain; I wish
    # Python supported something like "sys.stdout.encoding = 'UTF-8'".
    def fix_stdout():
        import codecs
        sys.stdout = codecs.EncodedFile(sys.stdout, 'UTF-8')
        def null_decode(input, errors='strict'):
            return input, len(input)
        sys.stdout.decode = null_decode

    fix_stdout()

lp = Launchpad.login_anonymously('pointrelease-updates', 'production', version='1.0')

def is_security_bug(bug):
    try:
        return len(lp.bugs[bug].cves_collection) != 0
    except (KeyError, launchpadlib.errors.HTTPError):
        return False

# Monkey-patch Deb822.gpg_stripped_paragraph to work around broken UTF-8 in
# some .changes files.
deb822.Deb822.orig_gpg_stripped_paragraph = deb822.Deb822.gpg_stripped_paragraph
def gpg_stripped_paragraph(cls, sequence):
    for line in cls.orig_gpg_stripped_paragraph(sequence):
        yield line.decode('utf-8', 'ignore')
deb822.Deb822.gpg_stripped_paragraph = classmethod(gpg_stripped_paragraph)

ubuntu = lp.distributions['ubuntu']

if len(sys.argv) == 1:
  print("Usage: %s <series> [YYYY-MM-DD]" % sys.argv[0])
  sys.exit(1)

series = ubuntu.getSeries(name_or_version=sys.argv[1])

created_since = None
if len(sys.argv) > 2:
  created_since = sys.argv[2]

# filter our list before we reverse it, for great justice.
pubs = [pub for pub in
        ubuntu.main_archive.getPublishedSources(distro_series=series,
                                                pocket='Updates',
                                                created_since_date=created_since,
                                                order_by_date=True)
        if (pub.component_name in ('main', 'restricted')
            # always filter out language packs, which never have bugs
            # to report anyway
            and not pub.source_package_name.startswith('language-pack-'))]
# chronological order, oldest first
pubs.reverse()
for pub in pubs:
    changes_file_url = pub.changesFileUrl()
    #print('', pub.component_name, pub.source_package_name, pub.source_package_version, pub.date_published, changes_file_url)
    with closing(urlopen(changes_file_url)) as changes_handle:
        changes = deb822.Changes(changes_handle.read())
    accum = ''
    for line in changes['changes'].splitlines():
        if not line.startswith('  '):
            continue
        line = line.strip()
        if line and line[0] in '*-+[':
            nextline = line.lstrip('*-+[ ')
            if nextline.lower().startswith('lp:'):
                accum += ' ' + nextline
            else:
                for match in changes_re.findall(accum):
                    bugnums = [bug for bug in bug_re.findall(match) if not is_security_bug(bug)]
                    if bugnums:
                        print('|| %s || %s || %s ||' % (pub.source_package_name, ' '.join(['Bug:%s' % bug for bug in bugnums]), accum))
                accum = nextline
        else:
            accum += ' ' + line
    for match in changes_re.findall(accum):
        bugnums = [bug for bug in bug_re.findall(match) if not is_security_bug(bug)]
        if bugnums:
            print('|| %s || %s || %s ||' % (pub.source_package_name, ' '.join(['Bug:%s' % bug for bug in bugnums]), accum))
