#!/usr/bin/env python
"""Script to create a pyinstaller executable.

This exe can then be wrapped in a platform specific installer for each
supported platform.
"""

import argparse
import json
import os
import shutil
import sys
from distutils.dir_util import copy_tree

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from install_deps import install_packages
from utils import run, save_to_zip, tmp_dir, update_metadata

ROOT = os.path.dirname(
    os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
EXE_DIR = os.path.join(ROOT, 'exe')
PYINSTALLER_DIR = os.path.join(EXE_DIR, 'pyinstaller')
ASSETS_DIR = os.path.join(EXE_DIR, 'assets')
DEFAULT_OUTPUT_ZIP = 'awscli-exe.zip'
AC_INDEX_INTERNAL_PATH = os.path.join('awscli', 'data', 'ac.index')
DISTRIBUTION_SOURCE = 'exe'


def make_exe(exe_zipfile, cleanup=True, ac_index=None):
    with tmp_dir() as workdir:
        delete_existing_exe_build()
        do_make_exe(workdir, exe_zipfile, ac_index)
        if cleanup:
            cleanup_build()
    print('Exe build is available at: %s' % exe_zipfile)


def do_make_exe(workdir, exe_zipfile, ac_index):
    exe_dir = os.path.join(workdir, 'aws')
    output_exe_dist_dir = os.path.join(exe_dir, 'dist')
    aws_exe_build = pyinstaller('aws.spec')
    if ac_index:
        full_internal_ac_index_path = os.path.join(
            aws_exe_build, AC_INDEX_INTERNAL_PATH
        )
        copy_file(ac_index, full_internal_ac_index_path)
    copy_directory(aws_exe_build, output_exe_dist_dir)
    aws_complete_exe_build = pyinstaller('aws_completer.spec')
    update_metadata(
        aws_complete_exe_build, distribution_source=DISTRIBUTION_SOURCE
    )
    copy_directory_contents_into(aws_complete_exe_build, output_exe_dist_dir)
    copy_directory_contents_into(ASSETS_DIR, exe_dir)
    save_to_zip(workdir, exe_zipfile)


def delete_existing_exe_build():
    build_dir = os.path.join(PYINSTALLER_DIR, 'dist')
    if os.path.isdir(build_dir):
        shutil.rmtree(build_dir)


def pyinstaller(specfile):
    aws_spec_path = os.path.join(PYINSTALLER_DIR, specfile)
    print(run('pyinstaller %s' % (aws_spec_path), cwd=PYINSTALLER_DIR))
    return os.path.join(PYINSTALLER_DIR, 'dist', os.path.splitext(specfile)[0])


def copy_directory(src, dst):
    print('Copying %s -> %s' % (src, dst))
    shutil.copytree(src, dst)


def copy_directory_contents_into(src, dst):
    print('Copying contents of %s into %s' % (src, dst))
    copy_tree(src, dst)


def copy_file(src, dst):
    print('Copying file %s -> %s' % (src, dst))
    shutil.copy2(src, dst)


def cleanup_build():
    locations = [
        os.path.join(PYINSTALLER_DIR, 'build'),
        os.path.join(PYINSTALLER_DIR, 'dist'),
    ]
    for location in locations:
        shutil.rmtree(location)
        print('Deleted build directory: %s' % location)


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        '--output',
        default=os.path.join(ROOT, 'dist', DEFAULT_OUTPUT_ZIP),
        help=(
            'The name of the file to save the exe zip. By default, '
            'this will be saved in "dist/%s" directory in the root of the '
            'awscli.' % DEFAULT_OUTPUT_ZIP
        ),
    )
    parser.add_argument(
        '--no-cleanup',
        dest='cleanup',
        action='store_false',
        default=True,
        help=(
            'Leave the build folder produced by pyinstaller. This can be '
            'useful for debugging.'
        ),
    )
    parser.add_argument(
        '--src-dir',
        default=None,
        help=(
            'Source directory for pinned installation dependencies. This '
            'provides the ability to do offline builds without PyPI.'
        ),
    )
    parser.add_argument(
        '--ac-index-path',
        default=None,
        help=('Path to ac.index file to include in the exe.'),
    )
    args = parser.parse_args()

    output = os.path.abspath(args.output)
    if args.src_dir:
        print(f'Installing dependencies from local directory: {args.src_dir}')
        install_packages(args.src_dir)
    else:
        run('pip install -r requirements-dev-lock.txt')
        run('pip install .')

    make_exe(output, cleanup=args.cleanup, ac_index=args.ac_index_path)


if __name__ == "__main__":
    main()
