"""This script is used by the py2exe to freeze the library into executables."""

from __future__ import annotations

import contextlib
import ctypes.util
import functools
import os
import platform
import shutil
import sys
from configparser import ConfigParser
from distutils.util import get_platform
from fnmatch import fnmatch
from time import strftime

from py2exe import freeze


# Borrowed from setuptools
def _find_all_simple(path: str) -> list[str]:
    """Find all files under 'path'.

    Args:
        path (str): The directory path to search for files.

    Returns:
        list[str]: A list of full filenames found under the specified path.
    """
    results = (
        os.path.join(base, file)
        for base, dirs, files in os.walk(path, followlinks=True)
        for file in files
    )
    return filter(os.path.isfile, results)


def findall(directory: str = os.curdir) -> list[str]:
    """Find all files under 'dir' and return the list of full filenames.

    Unless dir is '.', return full filenames with dir prepended.

    Args:
        directory (str, optional): The directory path to search for files.
            Defaults to the current directory.

    Returns:
        list[str]: A list of full filenames found under the specified
            directory.
    """
    files = _find_all_simple(directory)
    if directory == os.curdir:
        make_rel = functools.partial(os.path.relpath, start=directory)
        files = map(make_rel, files)
    return list(files)


import distutils.filelist

distutils.filelist.findall = findall  # Fix findall bug in distutils


bits = platform.architecture()[0][:2]
pypath = os.path.abspath(__file__)
pydir = os.path.dirname(pypath)
source_dir = os.path.dirname(pydir)

print(f"pydir     : {pydir}")
print(f"source_dir: {source_dir}")
sys.path.append(source_dir)


from DisplayCAL.meta import (
    APPSTREAM_ID,
    AUTHOR,
    AUTHOR_ASCII,
    AUTHOR_EMAIL,
    DESCRIPTION,
    DEVELOPMENT_HOME_PAGE,
    DOMAIN,
    LONG_DESCRIPTION,
    NAME,
    PY_MAXVERSION,
    PY_MINVERSION,
    VERSION_STRING,
    VERSION_TUPLE,
    script2pywname,
)
from DisplayCAL.util_os import getenvu, safe_glob
from DisplayCAL.util_str import safe_str

appname = NAME


if sys.platform in ("darwin", "win32"):
    # Adjust PATH so ctypes.util.find_library can find SDL2 DLLs (if present)
    pth = getenvu("PATH")
    libpth = os.path.join(pydir, "lib")
    if not pth.startswith(libpth + os.pathsep):
        pth = libpth + os.pathsep + pth
        os.environ["PATH"] = safe_str(pth)


config = {
    "data": ["tests/data/icc/*.icc"],
    "doc": [
        "CHANGES.html",
        "LICENSE.txt",
        "README.html",
        "README-fr.html",
        "screenshots/*.png",
        "theme/*.png",
        "theme/*.css",
        "theme/*.js",
        "theme/*.svg",
        "theme/icons/favicon.ico",
        "theme/slimbox2/*.css",
        "theme/slimbox2/*.js",
    ],
    # Excludes for .app/.exe builds
    # numpy.lib.utils imports pydoc, which imports Tkinter, but
    # numpy.lib.utils is not even used by DisplayCAL, so omit all
    # Tk stuff
    # Use pyglet with OpenAL as audio backend. pyglet 2.x media import paths
    # pull in additional submodules dynamically, so don't exclude pyglet.*
    "excludes": {
        "all": [
            "Tkconstants",
            "Tkinter",
            "pygame",
            "pyo",
            "setuptools",
            "tcl",
            "test",
            "yaml",
            "zeroconf",
        ],
        "darwin": ["gdbm"],
        "win32": ["gi", "win32com.client.genpy"],
    },
    "package_data": {
        NAME: [
            "beep.wav",
            "camera_shutter.wav",
            "ColorLookupTable.fx",
            "lang/*.yaml",
            "linear.cal",
            "pnp.ids",
            "presets/*.icc",
            "quirk.json",
            "ref/*.cie",
            "ref/*.gam",
            "ref/*.icm",
            "ref/*.ti1",
            "report/*.css",
            "report/*.html",
            "report/*.js",
            "test.cal",
            "theme/*.png",
            "theme/*.wav",
            "theme/icons/10x10/*.png",
            "theme/icons/16x16/*.png",
            "theme/icons/32x32/*.png",
            "theme/icons/48x48/*.png",
            "theme/icons/72x72/*.png",
            "theme/icons/128x128/*.png",
            "theme/icons/256x256/*.png",
            "theme/icons/512x512/*.png",
            "theme/jet_anim/*.png",
            "theme/patch_anim/*.png",
            "theme/splash_anim/*.png",
            "theme/shutter_anim/*.png",
            "ti1/*.ti1",
            "x3d-viewer/*.css",
            "x3d-viewer/*.html",
            "x3d-viewer/*.js",
            "xrc/*.xrc",
            "VERSION",
        ]
    },
    "xtra_package_data": {NAME: {"win32": [f"theme/icons/{NAME}-uninstall.ico"]}},
}


msiversion = ".".join(
    (
        str(VERSION_TUPLE[0]),
        str(VERSION_TUPLE[1]),
        str(VERSION_TUPLE[2]),
    )
)


class Target:
    """Target class for py2exe."""

    def __init__(self, **kwargs) -> None:
        self.__dict__.update(kwargs)


def get_data(
    tgt_dir: str,
    key: str,
    pkgname: None | str = None,
    subkey: None | str = None,
    excludes: None | list[str] = None,
) -> list[tuple[str, list[str]]]:
    """Return configured data files.

    Args:
        tgt_dir (str): Target directory where the files should be placed.
        key (str): Key in the config dictionary to retrieve the file paths.
        pkgname (None | str, optional): Package name to filter the files.
            Default is None.
        subkey (None | str, optional): Subkey to further filter the files.
            Default is None.
        excludes (None | list[str], optional): List of patterns to exclude
            files. Default is None.

    Returns:
        list[tuple[str, list[str]]]: List of tuples where each tuple contains
            the target directory and a list of file paths that match the
            specified key and package name.
    """
    files = config[key]
    src_dir = source_dir
    resource_dir = src_dir
    if pkgname:
        files = files[pkgname]
        resource_dir = os.path.join(src_dir, pkgname)
        if subkey:
            files = files.get(subkey, [])
    data = []
    for pth in files:
        if not [exclude for exclude in excludes or [] if fnmatch(pth, exclude)]:
            normalized_path = os.path.normpath(
                os.path.join(tgt_dir, os.path.dirname(pth))
            )
            safe_path = [
                os.path.relpath(p, src_dir)
                for p in safe_glob(os.path.join(resource_dir, pth))
            ]
            data.append((normalized_path, safe_path))
    return data


def sort_by_name(a: str, b: str) -> int:
    """Compare two script names for sorting.

    Args:
        a (str): First script name.
        b (str): Second script name.

    Returns:
        int: -1 if a < b, 1 if a > b, 0 if a == b.
    """
    a, b = [os.path.splitext(v)[0] for v in (a, b)]
    if a > b:
        return 1
    if a < b:
        return -1
    return 0


def get_scripts(excludes: None | list[str] = None) -> list[tuple[str, str]]:
    """Return a list of scripts with their descriptions.

    Args:
        excludes (None | list[str]): List of scripts to exclude. Default is
            None.

    Returns:
        list[tuple[str, str]]: List of tuples containing script names and their
            descriptions.
    """
    # It is required that each script has an accompanying .desktop file
    scripts_with_desc = []
    scripts = safe_glob(os.path.join(pydir, "..", "scripts", appname.lower() + "*"))

    scripts = sorted(scripts, key=functools.cmp_to_key(sort_by_name))
    for script in scripts:
        script = os.path.basename(script)
        if script == appname.lower() + "-apply-profiles-launcher":
            continue
        desktop_file = os.path.join(pydir, "..", "misc", f"{script}.desktop")
        if os.path.isfile(desktop_file):
            cfg = ConfigParser()
            cfg.read(desktop_file)
            script = cfg.get("Desktop Entry", "Exec").split()[0]
            desc = cfg.get("Desktop Entry", "Name")
        else:
            desc = ""
        if not [exclude for exclude in excludes or [] if fnmatch(script, exclude)]:
            scripts_with_desc.append((script, desc))
    return scripts_with_desc


def build_py2exe() -> None:
    """py2exe builder that uses the new freeze API."""
    use_sdl = False
    sys.path.insert(1, os.path.join(pydir, "..", "util"))

    setuptools = True
    debug = False
    dry_run = False
    # do_full_install = False

    doc = "."
    data = "."
    # Use CA file from certifi project
    import certifi

    if cacert := certifi.where():
        shutil.copyfile(cacert, os.path.join(pydir, "cacert.pem"))
        config["package_data"][NAME].append("cacert.pem")
    else:
        print("WARNING: cacert.pem from certifi project not found!")

    # on Mac OS X and Windows, we want data files in the package dir
    # (package_data will be ignored when using py2exe)
    package_data = {
        NAME: ["theme/icons/22x22/*.png", "theme/icons/24x24/*.png"],
    }
    scripts = get_scripts()
    # Doc files
    data_files = []
    data_files += get_data(doc, "doc", excludes=["LICENSE.txt"])
    if data_files:
        data_files.append(
            (
                doc,
                [os.path.relpath(os.path.join(pydir, "..", "LICENSE.txt"), source_dir)],
            )
        )
    # metainfo / appdata.xml
    data_files.append(
        (
            os.path.join(os.path.dirname(data), "metainfo"),
            [
                os.path.relpath(
                    os.path.normpath(
                        os.path.join(pydir, "..", "dist", f"{APPSTREAM_ID}.appdata.xml")
                    ),
                    source_dir,
                )
            ],
        )
    )
    data_files += get_data(data, "package_data", NAME, excludes=["theme/icons/*"])
    data_files += get_data(data, "data")
    data_files += get_data(data, "xtra_package_data", NAME, sys.platform)

    # Add python and pythonw
    data_files.extend(
        [
            (
                os.path.join(data, "lib"),
                [
                    sys.executable,
                    os.path.join(os.path.dirname(sys.executable), "pythonw.exe"),
                ],
            )
        ]
    )
    if use_sdl:
        # SDL DLLs for audio module
        sdl2 = ctypes.util.find_library("SDL2")
        sdl2_mixer = ctypes.util.find_library("SDL2_mixer")
        if sdl2:
            sdl2_libs = [sdl2]
            if sdl2_mixer:
                sdl2_libs.append(sdl2_mixer)
                data_files.append((os.path.join(data, "lib"), sdl2_libs))
                config["excludes"]["all"].append("pyglet")
            else:
                print("WARNING: SDL2_mixer not found!")
        else:
            print("WARNING: SDL2 not found!")
    if "pyglet" not in config["excludes"]["all"]:
        # OpenAL DLLs for pyglet
        openal32 = ctypes.util.find_library("OpenAL32.dll")
        wrap_oal = ctypes.util.find_library("wrap_oal.dll")
        if openal32:
            oal = [openal32]
            if wrap_oal:
                oal.append(wrap_oal)
            else:
                print("WARNING: wrap_oal.dll not found!")
            data_files.append((data, oal))
        else:
            print("WARNING: OpenAL32.dll not found!")

    for dname in (
        "10x10",
        "16x16",
        "22x22",
        "24x24",
        "32x32",
        "48x48",
        "72x72",
        "128x128",
        "256x256",
        "512x512",
    ):
        # Get all the icons needed, depending on platform
        # Only the icon sizes 10, 16, 32, 72, 256 and 512 include icons
        # that are used exclusively for UI elements.
        # These should be installed in an app-specific location, e.g.
        # under Linux $XDG_DATA_DIRS/DisplayCAL/theme/icons/
        # The app icon sizes 16, 32, 48 and 256 (128 under Mac OS X),
        # which are used for taskbar icons and the like, as well as the
        # other sizes can be installed in a generic location, e.g.
        # under Linux $XDG_DATA_DIRS/icons/hicolor/<size>/apps/
        # Generally, icon filenames starting with the lowercase app name
        # should be installed in the generic location.
        icons = []
        desktopicons = []
        if sys.platform == "darwin":
            largest_iconbundle_icon_size = "128x128"
        else:
            largest_iconbundle_icon_size = "256x256"
        for iconpath in safe_glob(
            os.path.join(pydir, "theme", "icons", dname, "*.png")
        ):
            if not os.path.basename(iconpath).startswith(NAME.lower()) or (
                sys.platform in ("darwin", "win32")
                and dname in ("16x16", "32x32", "48x48", largest_iconbundle_icon_size)
            ):
                # In addition to UI element icons, we also need all the app
                # icons we use in get_icon_bundle under macOS/Windows,
                # otherwise they wouldn't be included (under Linux, these
                # are included for installation to the system-wide icon
                # theme location instead)
                icons.append(iconpath)
            elif sys.platform not in ("darwin", "win32"):
                desktopicons.append(iconpath)
        if icons:
            data_files.append((os.path.join(data, "theme", "icons", dname), icons))
        if desktopicons:
            data_files.append(
                (
                    os.path.join(
                        os.path.dirname(data), "icons", "hicolor", dname, "apps"
                    ),
                    desktopicons,
                )
            )
    ext_modules = []
    requires = []
    requires.append("pywin32 (>= 213.0)")
    packages = [NAME, f"{NAME}.lib", f"{NAME}.lib.agw"]
    # On Windows we want separate libraries
    packages.extend(
        [
            f"{NAME}.lib{bits}",
            f"{NAME}.lib{bits}.python{sys.version_info[0]}{sys.version_info[1]}",
        ]
    )

    attrs = {
        "author": AUTHOR_ASCII,
        "author_email": AUTHOR_EMAIL,
        "classifiers": [
            "Development Status :: 5 - Production/Stable",
            "Environment :: MacOS X",
            "Environment :: Win32 (MS Windows)",
            "Environment :: X11 Applications",
            "Intended Audience :: End Users/Desktop",
            "License :: OSI Approved :: GNU General Public License v3 "
            "or later (GPLv3+)",
            "Operating System :: OS Independent",
            "Programming Language :: Python :: 3.9",
            "Programming Language :: Python :: 3.10",
            "Programming Language :: Python :: 3.11",
            "Programming Language :: Python :: 3.12",
            "Programming Language :: Python :: 3.13",
            "Programming Language :: Python :: 3.14",
            "Topic :: Multimedia :: Graphics",
        ],
        "data_files": data_files,
        "description": DESCRIPTION,
        "download_url": f"{DEVELOPMENT_HOME_PAGE}/releases/download/"
        f"{VERSION_STRING}/{NAME}-{VERSION_STRING}.tar.gz",
        "ext_modules": ext_modules,
        "license": "GPL v3",
        "long_description": LONG_DESCRIPTION,
        "long_description_content_type": "text/x-rst",
        "name": NAME,
        "packages": packages,
        "package_data": package_data,
        "package_dir": {NAME: NAME},
        "platforms": [
            "Python >= {} <= {}".format(
                ".".join(str(n) for n in PY_MINVERSION),
                ".".join(str(n) for n in PY_MAXVERSION),
            ),
            "Linux/Unix with X11",
            "Mac OS X >= 10.4",
            "Windows 2000 and newer",
        ],
        "requires": requires,
        "provides": [NAME],
        "scripts": [],
        "url": f"https://{DOMAIN}/",
        "version": msiversion if "bdist_msi" in sys.argv[1:] else VERSION_STRING,
    }
    if setuptools:
        attrs["entry_points"] = {
            "gui_scripts": [
                "{} = {}.main:main{}".format(
                    script,
                    NAME,
                    (
                        ""
                        if script == NAME.lower()
                        else script[len(NAME) :].lower().replace("-", "_")
                    ),
                )
                for script, desc in scripts
            ]
        }
        attrs["exclude_package_data"] = {}
        attrs["include_package_data"] = False
        install_requires = [req.replace("(", "").replace(")", "") for req in requires]
        attrs["install_requires"] = install_requires
        attrs["zip_safe"] = False
    else:
        attrs["scripts"].extend(
            os.path.join("scripts", script)
            for script, desc in [
                script_desc
                for script_desc in scripts
                if script_desc[0] != f"{NAME.lower()}-apply-profiles"
                or sys.platform != "darwin"
            ]
        )

    from winmanifest_util import getmanifestxml

    arch = "amd64" if platform.architecture()[0] == "64bit" else "x86"
    manifest_xml = getmanifestxml(
        os.path.join(
            pydir,
            "..",
            "misc",
            NAME
            + (
                f".exe.{arch}.VC90.manifest"
                if hasattr(sys, "version_info") and sys.version_info[:2] >= (3, 8)
                else ".exe.manifest"
            ),
        )
    )
    tmp_scripts_dir = os.path.join(source_dir, "build", "temp.scripts")
    if not os.path.isdir(tmp_scripts_dir):
        os.makedirs(tmp_scripts_dir)
    apply_profiles_launcher = (
        f"{appname.lower()}-apply-profiles-launcher",
        f"{appname} Profile Loader Launcher",
    )
    for script, _desc in [*scripts, apply_profiles_launcher]:
        shutil.copy(
            os.path.join(source_dir, "scripts", script),
            os.path.join(tmp_scripts_dir, script2pywname(script)),
        )
    attrs["windows"] = [
        Target(
            script=os.path.join(tmp_scripts_dir, script2pywname(script)),
            icon_resources=[
                (
                    1,
                    os.path.join(
                        pydir,
                        "theme",
                        "icons",
                        os.path.splitext(os.path.basename(script))[0] + ".ico",
                    ),
                )
            ],
            other_resources=[(24, 1, manifest_xml)],
            copyright="© {} {}".format(strftime("%Y"), AUTHOR),
            description=desc,
        )
        for script, desc in [
            script_desc1
            for script_desc1 in scripts
            if script_desc1[0] != appname.lower() + "-eecolor-to-madvr-converter"
            and not script_desc1[0].endswith("-console")
        ]
    ]

    # Add profile loader launcher
    attrs["windows"].append(
        Target(
            script=os.path.join(
                tmp_scripts_dir, script2pywname(apply_profiles_launcher[0])
            ),
            icon_resources=[
                (
                    1,
                    os.path.join(
                        pydir,
                        "theme",
                        "icons",
                        appname + "-apply-profiles" + ".ico",
                    ),
                )
            ],
            other_resources=[(24, 1, manifest_xml)],
            copyright="© {} {}".format(strftime("%Y"), AUTHOR),
            description=apply_profiles_launcher[1],
        )
    )

    # Programs that can run with and without GUI
    console_scripts = [f"{NAME}-VRML-to-X3D-converter"]  # No "-console" suffix!
    for console_script in console_scripts:
        console_script_path = os.path.join(tmp_scripts_dir, console_script + "-console")
        if not os.path.isfile(console_script_path):
            shutil.copy(
                os.path.join(
                    source_dir, "scripts", console_script.lower() + "-console"
                ),
                console_script_path,
            )
    attrs["console"] = [
        Target(
            script=os.path.join(tmp_scripts_dir, script2pywname(script) + "-console"),
            icon_resources=[
                (
                    1,
                    os.path.join(
                        pydir,
                        "theme",
                        "icons",
                        os.path.splitext(os.path.basename(script))[0] + ".ico",
                    ),
                )
            ],
            other_resources=[(24, 1, manifest_xml)],
            copyright="© {} {}".format(strftime("%Y"), AUTHOR),
            description=desc,
        )
        for script, desc in [
            script_desc2
            for script_desc2 in scripts
            if script2pywname(script_desc2[0]) in console_scripts
        ]
    ]

    # Programs without GUI
    attrs["console"].append(
        Target(
            script=os.path.join(
                tmp_scripts_dir, appname + "-eeColor-to-madVR-converter"
            ),
            icon_resources=[
                (
                    1,
                    os.path.join(pydir, "theme", "icons", appname + "-3DLUT-maker.ico"),
                )
            ],
            other_resources=[(24, 1, manifest_xml)],
            copyright="© {} {}".format(strftime("%Y"), AUTHOR),
            description="Convert eeColor 65^3 to madVR 256^3 3D LUT "
            "(video levels in, video levels out)",
        )
    )

    dist_dir = os.path.join(
        pydir,
        "..",
        "dist",
        f"py2exe.{get_platform()}-py{sys.version_info[0]}.{sys.version_info[1]}",
        f"{NAME}-{VERSION_STRING}",
    )
    os.makedirs(dist_dir, exist_ok=True)
    attrs["options"] = {
        "py2exe": {
            "dist_dir": dist_dir,
            "dll_excludes": [
                "iertutil.dll",
                "MPR.dll",
                "msvcm90.dll",
                "msvcp90.dll",
                "msvcr90.dll",
                "mswsock.dll",
                "urlmon.dll",
                "w9xpopen.exe",
                "gdiplus.dll",
                "mfc90.dll",
            ],
            "excludes": config["excludes"]["all"] + config["excludes"]["win32"],
            "bundle_files": 3,  # if wx.VERSION >= (2, 8, 10, 1) else 1,
            "compressed": 1,
            "optimize": 0,  # 0 = don't optimize (generate .pyc)
            # 1 = normal optimization (like python -O)
            # 2 = extra optimization (like python -OO)
        }
    }
    if debug:
        attrs["options"]["py2exe"].update(
            {"bundle_files": 3, "compressed": 0, "optimize": 0, "skip_archive": 1}
        )
    if setuptools:
        attrs["setup_requires"] = ["py2exe"]
    attrs["zipfile"] = os.path.join("lib", "library.zip")

    # To have a working sdist and bdist_rpm when using distutils,
    # we go to the length of generating MANIFEST.in from scratch everytime,
    # using the information available from setup.
    manifest_in = ["# This file will be re-generated by setup.py - do not edit"]
    manifest_in.extend(
        [
            "include LICENSE.txt",
            "include MANIFEST",
            "include MANIFEST.in",
            "include README.html",
            "include README-fr.html",
            "include CHANGES.html",
            f"include {NAME}*.pyw",
            f"include {NAME}-*.pyw",
            f"include {NAME}-*.py",
            "include use-distutils",
            f"include {NAME}/VERSION",
        ]
    )
    manifest_in.append("include " + os.path.basename(sys.argv[0]))
    manifest_in.append(
        "include " + os.path.splitext(os.path.basename(sys.argv[0]))[0] + ".cfg"
    )
    for _datadir, datafiles in attrs.get("data_files", []):
        for datafile in datafiles:
            datafile_relpath = None
            with contextlib.suppress(ValueError):
                datafile_relpath = os.path.relpath(
                    os.path.sep.join(datafile.split("/")), source_dir
                )
            manifest_in.append(f"include {datafile_relpath or datafile}")
    for extmod in attrs.get("ext_modules", []):
        manifest_in.extend(
            f"include {os.path.sep.join(src.split('/'))}" for src in extmod.sources
        )
    for pkg in attrs.get("packages", []):
        pkg = os.path.join(*pkg.split("."))
        pkgdir = os.path.sep.join(attrs.get("package_dir", {}).get(pkg, pkg).split("/"))
        manifest_in.append("include " + os.path.join(pkgdir, "*.py"))
        # manifest_in.append("include " + os.path.join(pkgdir, "*.pyd"))
        # manifest_in.append("include " + os.path.join(pkgdir, "*.so"))
        for obj in attrs.get("package_data", {}).get(pkg, []):
            print(f"obj: {obj}")
            manifest_in.append(f"include {os.path.sep.join([pkgdir, *obj.split('/')])}")
    manifest_in.extend(
        "include {}".format(os.path.join(*pymod.split(".")))
        for pymod in attrs.get("py_modules", [])
    )
    manifest_in.append(
        "include {}".format(os.path.join(NAME, "theme", "theme-info.txt"))
    )
    manifest_in.append(
        "recursive-include {} {} {}".format(
            os.path.join(NAME, "theme", "icons"), "*.icns", "*.ico"
        )
    )
    manifest_in.append("include {}".format(os.path.join("man", "*.1")))
    manifest_in.append("recursive-include misc *")
    # if skip_instrument_conf_files:
    #     manifest_in.extend(
    #         [
    #             "exclude misc/Argyll",
    #             "exclude misc/*.rules",
    #             "exclude misc/*.usermap",
    #         ]
    #     )
    manifest_in.append("include {}".format(os.path.join("screenshots", "*.png")))
    manifest_in.append("include {}".format(os.path.join("scripts", "*")))
    manifest_in.append("include {}".format(os.path.join("tests", "*")))
    manifest_in.append("recursive-include theme *")
    manifest_in.append("recursive-include util *.cmd *.py *.sh")
    manifest_in.append("global-exclude *~")
    manifest_in.append("global-exclude *.backup")
    manifest_in.append("global-exclude *.bak")
    manifest_in.append("global-exclude */__pycache__/*")
    if not dry_run:
        with open("MANIFEST.in", "w") as manifest:
            manifest.write("\n".join(manifest_in))
        if os.path.exists("MANIFEST"):
            os.remove("MANIFEST")

    py2exe_kwargs = {
        "console": attrs["console"],
        "windows": attrs["windows"],
        "data_files": attrs["data_files"],
        "zipfile": attrs["zipfile"],
        "options": attrs["options"],
    }

    print("Running py2exe.freeze!")
    freeze(**py2exe_kwargs)
    # setup(**attrs)
    print("py2exe.freeze DONE!")

    shutil.copy(
        os.path.join(dist_dir, f"python{sys.version_info[0]}{sys.version_info[1]}.dll"),
        os.path.join(
            dist_dir, "lib", f"python{sys.version_info[0]}{sys.version_info[1]}.dll"
        ),
    )

    from vc90crt import vc90crt_copy_files

    vc90crt_copy_files(dist_dir)
    vc90crt_copy_files(os.path.join(dist_dir, "lib"))


if __name__ == "__main__":
    build_py2exe()
