#!/usr/bin/python

# pylint: disable=line-too-long, missing-docstring, invalid-name, multiple-statements

from __future__ import with_statement

import urllib2
import urlparse
import gzip
import re
import sys
import os
from StringIO import StringIO
from subprocess import Popen, PIPE

WD = '/mit/ncurses/cron-working/ncurses'
GIT = '/mit/git/bin/git'
PATCHDIR = '/mit/ncurses/patches'

authorPattern = re.compile('# patch by (.*) <(.*)>')
datePattern = re.compile('# created  (.*)')
titlePattern = re.compile('# (.* - .*) - .*')
indexPattern = re.compile('Index: (.*)$')
rmPattern = re.compile('rm -f (.*)')
hunkPattern = re.compile('@@ ')
commitMsgPattern = re.compile(r'\+\t(.*)')
#patchUrlPattern = re.compile(r'# ftp://(?:ftp.)?invisible-island.net/ncurses/\d+.\d+/ncurses-\d+\.\d+-(\d+).patch.gz')
patchUrlPattern = re.compile(r'# https://invisible-island.net/archives/ncurses/\d+.\d+/ncurses-\d+\.\d+-(\d+).patch.gz')
dateStrPattern = re.compile(r'\d{8}')

def get_response(uri):
    try:
        return urllib2.urlopen(uri)
    except urllib2.URLError:
        puri = urlparse.urlparse(uri)
        if puri.scheme == 'ftp' and puri.netloc == 'ftp.invisible-island.net' and not puri.path.startswith('/pub/'):
            try:
                new_uri = puri._replace(path='/pub'+puri.path).geturl()
                return urllib2.urlopen(new_uri)
            except urllib2.URLError:
                pass
        raise

def process_patch(uri):
    resp = get_response(uri)
    title = None
    author = None
    email = None
    date = None
    dateStr = None
    rmSpec = []

    index = None
    hunk = 0
    capHunk = None
    commit_msg = ''

    patchData = resp.read()
    if not uri.startswith('file'):
        with open(os.path.join(PATCHDIR, os.path.basename(uri)), 'w') as f:
            f.write(patchData)
    lines = gzip.GzipFile(fileobj=StringIO(patchData)).readlines()
    for line in lines:
        line = line.rstrip()

        # Find commit information
        if not author:
            a = authorPattern.match(line)
            if a:
                (author, email) = a.group(1, 2)
                continue
        if not date:
            d = datePattern.match(line)
            if d:
                date = d.group(1)
                continue
        if not title:
            t = titlePattern.match(line)
            if t:
                title = t.group(1)
                if dateStrPattern.match(title[-8:]):
                    dateStr = title[-8:]
                continue
        if not dateStr:
            d = patchUrlPattern.match(line)
            if d:
                dateStr = d.group(1)
                title += dateStr
                continue

        # Anything to remove from the tree?
        r = rmPattern.match(line)
        if r:
            rmSpec.append(r.group(1))

        # Search for commit message from NEWS
        i = indexPattern.match(line)
        if i:
            if index == 'NEWS':
                break
            index = i.group(1)
            hunk = 0
            continue
        h = hunkPattern.match(line)
        if h:
            hunk += 1
            continue

        if index == 'NEWS':
            if line.startswith('+'+dateStr):
                capHunk = hunk
                continue
            if hunk == capHunk:
                c = commitMsgPattern.match(line)
                if c:
                    commit_msg += c.group(1)+"\n"

    commit_msg = '\n\n'.join([title, commit_msg])
    print uri
    print title
    print author
    print email
    print date
    print dateStr
    print rmSpec
    print commit_msg

    # rm any files that need removing
    if rmSpec:
        g = Popen([GIT, 'rm', '--ignore-unmatch'] + rmSpec,
                  stdin=PIPE,
                  stdout=PIPE,
                  stderr=PIPE,
                  cwd=WD)
        o, e = g.communicate(None)
        if o: print o
        if e: print e
        if g.returncode != 0:
            print 'error %i on git rm' % g.returncode
            return g.returncode

    # apply patch
    g = Popen([GIT, 'apply'],
              stdin=PIPE,
              stdout=PIPE,
              stderr=PIPE,
              cwd=WD)
    o, e = g.communicate(''.join(lines))
    if o: print o
    if e: print e
    if g.returncode != 0:
        print 'error %i on git apply' % g.returncode
        return g.returncode

    # add to index
    g = Popen([GIT, 'add', '-A'],
              stdin=PIPE,
              stdout=PIPE,
              stderr=PIPE,
              cwd=WD)
    o, e = g.communicate(None)
    if o: print o
    if e: print e
    if g.returncode != 0:
        print 'error %i on git add' % g.returncode
        return g.returncode

    # commit
    newEnv = os.environ
    newEnv['GIT_AUTHOR_DATE'] = date
    newEnv['GIT_AUTHOR_NAME'] = author
    newEnv['GIT_AUTHOR_EMAIL'] = email
    newEnv['GIT_COMMITTER_DATE'] = date
    newEnv['GIT_COMMITTER_NAME'] = author
    newEnv['GIT_COMMITTER_EMAIL'] = email
    g = Popen([GIT, 'commit',
               '-m', commit_msg],
              stdin=PIPE,
              stdout=PIPE,
              stderr=PIPE,
              env=newEnv,
              cwd=WD)
    o, e = g.communicate(None)
    if o: print o
    if e: print e
    if g.returncode != 0:
        print 'error %i on git commit' % g.returncode
        return g.returncode

    # force push
    g = Popen([GIT, 'push',
               '-f', 'Scripts'],
              stdin=PIPE,
              stdout=PIPE,
              stderr=PIPE,
              cwd=WD)
    o, e = g.communicate(None)
    if o: print o
    if e: print e
    if g.returncode != 0:
        print 'error %i on git push' % g.returncode
        return g.returncode
    return 0

if __name__ == '__main__':
    if len(sys.argv) == 2:
        process_patch(sys.argv[1])
    else:
        sys.stderr.write('Huh?\n')
        sys.stderr.write(str(sys.argv)+"\n")
        exit(1)
