#!/usr/bin/env python3

# Copyright (C) 2017-2018 Robin Schneider <ypid@riseup.net>
# SPDX-License-Identifier: GPL-3.0-only

"""
Check if the proxy specified as Acquire::HTTP::Proxy or Acquire::HTTPS::Proxy
are currently reachable before promoting them to be used by the currently
running apt process. Without this script, apt will fail when the proxy can not
be reached.  With this script, apt silently falls back to "DIRECT" (no proxy)
if the proxy is (temporally) not reachable.

To use this script, set:

    Acquire::HTTP::Proxy-Auto-Detect "/usr/local/lib/get-reachable-apt-proxy";

in your APT configuration.
"""

from __future__ import (print_function, unicode_literals,
                        absolute_import, division)

import argparse
import logging

#  from future.standard_library import install_aliases
#  install_aliases()

from urllib.parse import urlparse
from urllib.request import urlopen
from urllib.error import URLError, HTTPError

import apt_pkg

__version__ = '0.1.1'

LOG = logging.getLogger(__name__)


def get_first_up_proxy(target_uri_raw):
    LOG.debug("Trying to find proxy for URI: {}".format(target_uri_raw))

    target_uri = urlparse(target_uri_raw)

    apt_config_key = "Acquire::{}::Proxy".format(
        target_uri.scheme.upper()
    )

    if apt_pkg.config.exists(apt_config_key):
        proxy_uris = apt_pkg.config.get(apt_config_key)
        for proxy_uri_raw in proxy_uris.split(' '):

            if proxy_uri_raw.upper() in ['DIRECT']:
                LOG.debug("Skipping special proxy keyword: {}".format(
                    proxy_uri_raw))
                continue
            else:
                LOG.debug("Checking possible proxy URI: {}".format(
                    proxy_uri_raw))

            proxy_uri = urlparse(proxy_uri_raw)

            if proxy_uri.scheme in ['https', 'http']:
                try:
                    urlopen(proxy_uri_raw, timeout=1)
                except HTTPError as err:
                    LOG.debug("Proxy responded with: {}".format(err))
                    pass
                except URLError as err:
                    LOG.debug("Proxy not suitable: {}".format(err))
                    continue

                LOG.info("Selected suitable proxy: {}".format(
                    proxy_uri_raw))
                return proxy_uri_raw
            else:
                raise NotImplementedError(
                    "URI scheme {} is not yet implemented.".format())

    return 'DIRECT'


def get_args_parser():
    args_parser = argparse.ArgumentParser(
        prog='get-reachable-apt-proxy',
        epilog=__doc__,
    )
    args_parser.add_argument(
        '-V', '--version',
        action='version',
        version=__version__,
    )
    args_parser.add_argument(
        '-d', '--debug',
        help="Write debugging and higher to STDOUT|STDERR.",
        action="store_const",
        dest="loglevel",
        const=logging.DEBUG,
    )
    args_parser.add_argument(
        '-v', '--verbose',
        help="Write information and higher to STDOUT|STDERR.",
        action="store_const",
        dest="loglevel",
        const=logging.INFO,
    )
    args_parser.add_argument(
        'uri',
    )

    return args_parser


def main():
    args_parser = get_args_parser()
    args_parser.set_defaults(loglevel=logging.WARN)
    args = args_parser.parse_args()

    logging.basicConfig(
        format='%(levelname)s{}, %(asctime)s: %(message)s'.format(
            ' (%(filename)s:%(lineno)s)'
            if args.loglevel <= logging.DEBUG else '',
        ),
        level=args.loglevel,
    )

    apt_pkg.init_config()
    print(get_first_up_proxy(args.uri))


if __name__ == '__main__':
    main()
