#!/usr/bin/env python
"""
This Apt transport module extends https module to enable SAS token based authentication
for Azure blob storage based package repository.
"""
import subprocess as s
import sys
import signal
import select
import fcntl
import os
import urllib

def signal_handler(signum, frame): # pylint: disable=W0613
    """
    Exit cleanly
    """
    if signum == signal.SIGCHLD:
        ## print >> sys.stderr, "signal.SIGCHLD"
        azblob.poll()
        sys.exit(0)
    if signum == signal.SIGINT:
        ## print >> sys.stderr, "signal.SIGINT"
        os.kill(azblob.pid, signal.SIGINT)
        azblob.poll()
        sys.exit(0)

signal.signal(signal.SIGCHLD, signal_handler)
signal.signal(signal.SIGINT, signal_handler)

# FIXME: smarter detection of apt quirks # pylint: disable=fixme
specialquote = False
try:
    with open("/etc/debian_version") as f:
        ver = f.readline()
        if ver.startswith('8'):
            specialquote = True
        f.close()
except: # nosec (silently keep default value)
    pass

azblob = s.Popen(["/usr/lib/apt/methods/https"], stdin=s.PIPE, stdout=s.PIPE, stderr=sys.stderr, shell=False,
                 close_fds=True, bufsize=65536)
# d = open ("/tmp/azblob_debug", "w")

# set I/O nonblocking
fcntl.fcntl(azblob.stdout.fileno(), fcntl.F_SETFL,
            fcntl.fcntl(azblob.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL,
            fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)

inputs = [azblob.stdout, sys.stdin]
sastoken = ''
timeoutcnt = 0

while azblob.poll() is None:
    ## d.write('select()...\n')
    readfds, _, _ = select.select(inputs, [], [], 600)
    if readfds.__len__() == 0:
        print >> sys.stderr, "Select() timeout, this shouldn't happen!"
        timeoutcnt = timeoutcnt + 1
        sys.stdout.flush()
        azblob.stdin.flush()
        if timeoutcnt > 5:
            print >> sys.stderr, "Max. select() timeout count (5) reached, terminating..."
            sys.exit(1)

    for i in readfds:
        if i.fileno() == azblob.stdout.fileno():
            while azblob.poll() is None:
                try:
                    line = azblob.stdout.readline()
                except:
                    # d.write('...done reading from https...\n')
                    sys.stdout.flush()
                    break
                # d.write('<-' + line)
                if line.startswith('URI: https://'):
                    parts = line.split('https://')
                    if sastoken != '':
                        line = 'URI: https-sas://' + sastoken + '@' + parts[1].split('?')[0] + '\n'
                    else:
                        line = line.replace('URI: https://', 'URI: https-sas://')
                sys.stdout.write(line)
        if i.fileno() == sys.stdin.fileno():
            while azblob.poll() is None:
                try:
                    line = sys.stdin.readline()
                except:
                    # d.write('...done reading from apt(-get)...\n')
                    azblob.stdin.flush()
                    break
                # d.write('->' + line)
                if line.startswith('URI: https-sas://'):
                    if line.find('@') > -1:
                        sastoken = line.split('https-sas://')[1].split('@')[0]
                        url = line.split('https-sas://')[1].split('@')[1]
                        if specialquote:
                            line = 'URI: https://' + url.replace('\n', '') + '?' + urllib.quote(sastoken, '=&:') + '\n'
                        else:
                            line = 'URI: https://' + url.replace('\n', '') + '?' + sastoken + '\n'
                    else:
                        line = line.replace('URI: https-sas://', 'URI: https://')
                azblob.stdin.write(line)

sys.exit(azblob.poll())
