#-----------------------------------------------------------------------------
# Copyright (c) 2005-2023, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License (version 2
# or later) with exception for distributing the bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#
# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
#-----------------------------------------------------------------------------
"""
Configure PyInstaller for the current Python installation.
"""

import os
import subprocess

from PyInstaller import compat
from PyInstaller import log as logging

logger = logging.getLogger(__name__)


def _check_upx_availability(upx_dir):
    logger.debug('Testing UPX availability ...')

    upx_exe = "upx"
    if upx_dir:
        upx_exe = os.path.normpath(os.path.join(upx_dir, upx_exe))

    # Check if we can call `upx -V`.
    try:
        output = subprocess.check_output(
            [upx_exe, '-V'],
            stdin=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            universal_newlines=True,
        )
    except Exception:
        logger.debug('UPX is not available.')
        return False

    # Read the first line to display version string
    try:
        version_string = output.splitlines()[0]
    except IndexError:
        version_string = 'version string unavailable'

    logger.debug('UPX is available: %s', version_string)
    return True


def _get_pyinstaller_cache_dir():
    old_cache_dir = None
    if compat.getenv('PYINSTALLER_CONFIG_DIR'):
        cache_dir = compat.getenv('PYINSTALLER_CONFIG_DIR')
    elif compat.is_win:
        cache_dir = compat.getenv('LOCALAPPDATA')
        if not cache_dir:
            cache_dir = os.path.expanduser('~\\Application Data')
    elif compat.is_darwin:
        cache_dir = os.path.expanduser('~/Library/Application Support')
    else:
        # According to XDG specification: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
        old_cache_dir = compat.getenv('XDG_DATA_HOME')
        if not old_cache_dir:
            old_cache_dir = os.path.expanduser('~/.local/share')
        cache_dir = compat.getenv('XDG_CACHE_HOME')
        if not cache_dir:
            cache_dir = os.path.expanduser('~/.cache')
    cache_dir = os.path.join(cache_dir, 'pyinstaller')
    # Move old cache-dir, if any, to new location.
    if old_cache_dir and not os.path.exists(cache_dir):
        old_cache_dir = os.path.join(old_cache_dir, 'pyinstaller')
        if os.path.exists(old_cache_dir):
            parent_dir = os.path.dirname(cache_dir)
            if not os.path.exists(parent_dir):
                os.makedirs(parent_dir)
            os.rename(old_cache_dir, cache_dir)
    return cache_dir


def get_config(upx_dir=None):
    config = {}

    config['cachedir'] = _get_pyinstaller_cache_dir()
    config['upx_dir'] = upx_dir

    # Disable UPX on non-Windows. Using UPX (3.96) on modern Linux shared libraries (for example, the python3.x.so
    # shared library) seems to result in segmentation fault when they are dlopen'd. This happens in recent versions
    # of Fedora and Ubuntu linux, as well as in Alpine containers. On macOS, UPX (3.96) fails with
    # UnknownExecutableFormatException on most .dylibs (and interferes with code signature on other occasions). And
    # even when it would succeed, compressed libraries cannot be (re)signed due to failed strict validation.
    upx_available = _check_upx_availability(upx_dir)
    if upx_available:
        if compat.is_win or compat.is_cygwin:
            logger.info("UPX is available and will be used if enabled on build targets.")
        elif os.environ.get("PYINSTALLER_FORCE_UPX", "0") != "0":
            logger.warning(
                "UPX is available and force-enabled on platform with known compatibility problems - use at own risk!"
            )
        else:
            upx_available = False
            logger.info("UPX is available but is disabled on non-Windows due to known compatibility problems.")
    config['upx_available'] = upx_available

    return config
