#!/usr/bin/env python
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""This script is used to download prebuilt gn/ninja binaries."""

# TODO: Running stand-alone won't work on Windows due to the dia dll copying.

from __future__ import division
from __future__ import print_function
import argparse
import os
import shutil
import stat
import sys
import tarfile
import tempfile
import time

try:
    from urllib2 import HTTPError, URLError, urlopen
except ImportError:  # For Py3 compatibility
    from urllib.error import HTTPError, URLError
    from urllib.request import urlopen

URL = "https://s3.amazonaws.com/deno.land/gn_ninja_binaries.tar.gz"
DIR = None


def RmTree(dir):
    """Delete dir."""

    def ChmodAndRetry(func, path, _):
        # Subversion can leave read-only files around.
        if not os.access(path, os.W_OK):
            os.chmod(path, stat.S_IWUSR)
            return func(path)
        raise

    shutil.rmtree(dir, onerror=ChmodAndRetry)


def DownloadUrl(url, output_file):
    """Download url into output_file."""
    CHUNK_SIZE = 4096
    TOTAL_DOTS = 10
    num_retries = 3
    retry_wait_s = 5  # Doubled at each retry.

    while True:
        try:
            sys.stdout.write('Downloading %s ' % url)
            sys.stdout.flush()
            response = urlopen(url)
            total_size = int(response.info().get('Content-Length').strip())
            bytes_done = 0
            dots_printed = 0
            while True:
                chunk = response.read(CHUNK_SIZE)
                if not chunk:
                    break
                output_file.write(chunk)
                bytes_done += len(chunk)
                num_dots = TOTAL_DOTS * bytes_done // total_size
                sys.stdout.write('.' * (num_dots - dots_printed))
                sys.stdout.flush()
                dots_printed = num_dots
            if bytes_done != total_size:
                raise URLError(
                    "only got %d of %d bytes" % (bytes_done, total_size))
            print(' Done.')
            return
        except URLError as e:
            sys.stdout.write('\n')
            print(e)
            if num_retries == 0 or isinstance(e, HTTPError) and e.code == 404:
                raise e
            num_retries -= 1
            print('Retrying in %d s ...' % retry_wait_s)
            sys.stdout.flush()
            time.sleep(retry_wait_s)
            retry_wait_s *= 2


def EnsureDirExists(path):
    if not os.path.exists(path):
        os.makedirs(path)


def DownloadAndUnpack(url, output_dir):
    """Download an archive from url and extract into output_dir. If path_prefixes
     is not None, only extract files whose paths within the archive start with
     any prefix in path_prefixes."""
    with tempfile.TemporaryFile() as f:
        DownloadUrl(url, f)
        f.seek(0)
        EnsureDirExists(output_dir)
        t = tarfile.open(mode='r:gz', fileobj=f)
        t.extractall(path=output_dir)


def Update():
    if os.path.exists(DIR):
        RmTree(DIR)
    try:
        DownloadAndUnpack(URL, DIR)
    except URLError:
        print('Failed to download prebuilt ninja/gn binaries %s' % URL)
        print('Exiting.')
        sys.exit(1)

    return 0


def main():
    parser = argparse.ArgumentParser(description='Download ninja/gn binaries.')
    parser.add_argument('--dir', help='Where to extract the package.')
    args = parser.parse_args()

    if args.dir:
        global DIR
        DIR = os.path.abspath(args.dir)

    return Update()


if __name__ == '__main__':
    sys.exit(main())
