#!/usr/bin/env python

from setuptools import setup, Command, Extension
from setuptools.command.build_ext import build_ext
import distutils
from distutils.command import build
from subprocess import check_output, check_call

import sys, os

BUILD_MONO = True
BUILD_NETFX = True

PY_MAJOR = sys.version_info[0]
PY_MINOR = sys.version_info[1]

CONFIGURED_PROPS = "configured.props"


def _get_interop_filename():
    """interopXX.cs is auto-generated as part of the build.
    For common windows platforms pre-generated files are included
    as most windows users won't have Clang installed, which is
    required to generate the file.
    """
    interop_filename = "interop{0}{1}{2}.cs".format(
        PY_MAJOR, PY_MINOR, getattr(sys, "abiflags", "")
    )
    return os.path.join("src", "runtime", interop_filename)


# Write configuration to configured.props. This will go away once all of these
# can be decided at runtime.
def _write_configure_props():
    defines = [
        "PYTHON{0}{1}".format(PY_MAJOR, PY_MINOR),
    ]

    if sys.platform == "win32":
        defines.append("WINDOWS")

    if hasattr(sys, "abiflags"):
        if "d" in sys.abiflags:
            defines.append("PYTHON_WITH_PYDEBUG")
        if "m" in sys.abiflags:
            defines.append("PYTHON_WITH_PYMALLOC")

    # check the interop file exists, and create it if it doesn't
    interop_file = _get_interop_filename()
    if not os.path.exists(interop_file):
        print("Creating {0}".format(interop_file))
        geninterop = os.path.join("tools", "geninterop", "geninterop.py")
        check_call([sys.executable, geninterop, interop_file])

    import xml.etree.ElementTree as ET

    proj = ET.Element("Project")
    props = ET.SubElement(proj, "PropertyGroup")
    f = ET.SubElement(props, "PythonInteropFile")
    f.text = os.path.basename(interop_file)

    c = ET.SubElement(props, "ConfiguredConstants")
    c.text = " ".join(defines)

    ET.ElementTree(proj).write(CONFIGURED_PROPS)


class configure(Command):
    """Configure command"""

    description = "Configure the pythonnet build"
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        self.announce("Writing configured.props...", level=distutils.log.INFO)
        _write_configure_props()


class DotnetLib:
    def __init__(self, name, path, **kwargs):
        self.name = name
        self.path = path
        self.args = kwargs


class build_dotnet(Command):
    """Build command for dotnet-cli based builds"""

    description = "Build DLLs with dotnet-cli"
    user_options = [
        ("dotnet-config", None, "dotnet build configuration"),
        (
            "inplace",
            "i",
            "ignore build-lib and put compiled extensions into the source "
            + "directory alongside your pure Python modules",
        ),
    ]

    def initialize_options(self):
        self.dotnet_config = None
        self.build_lib = None
        self.inplace = False

    def finalize_options(self):
        if self.dotnet_config is None:
            self.dotnet_config = "release"

        build = self.distribution.get_command_obj("build")
        build.ensure_finalized()
        if self.inplace:
            self.build_lib = "."
        else:
            self.build_lib = build.build_lib

    def run(self):
        dotnet_modules = self.distribution.dotnet_libs
        self.run_command("configure")

        for lib in dotnet_modules:
            output = os.path.join(
                os.path.abspath(self.build_lib), lib.args.pop("output")
            )
            rename = lib.args.pop("rename", {})

            opts = sum(
                [
                    ["--" + name.replace("_", "-"), value]
                    for name, value in lib.args.items()
                ],
                [],
            )

            opts.extend(["--configuration", self.dotnet_config])
            opts.extend(["--output", output])

            self.announce("Running dotnet build...", level=distutils.log.INFO)
            self.spawn(["dotnet", "build", lib.path] + opts)

            for k, v in rename.items():
                source = os.path.join(output, k)
                dest = os.path.join(output, v)

                if os.path.isfile(source):
                    try:
                        os.remove(dest)
                    except OSError:
                        pass

                    self.move_file(src=source, dst=dest, level=distutils.log.INFO)
                else:
                    self.warn(
                        "Can't find file to rename: {}, current dir: {}".format(
                            source, os.getcwd()
                        )
                    )


# Add build_dotnet to the build tasks:
from distutils.command.build import build as _build
from setuptools.command.develop import develop as _develop
from setuptools import Distribution
import setuptools


class build(_build):
    sub_commands = _build.sub_commands + [("build_dotnet", None)]


class develop(_develop):
    def install_for_development(self):
        # Build extensions in-place
        self.reinitialize_command("build_dotnet", inplace=1)
        self.run_command("build_dotnet")

        return super().install_for_development()


# Monkey-patch Distribution s.t. it supports the dotnet_libs attribute
Distribution.dotnet_libs = None

cmdclass = {
    "build": build,
    "build_dotnet": build_dotnet,
    "configure": configure,
    "develop": develop,
}


with open("README.rst", "r") as f:
    long_description = f.read()

dotnet_libs = [
    DotnetLib(
        "python-runtime",
        "src/runtime/Python.Runtime.csproj",
        output="pythonnet/runtime",
    )
]

if BUILD_NETFX:
    dotnet_libs.extend(
        [
            DotnetLib(
                "clrmodule-amd64",
                "src/clrmodule/",
                runtime="win-x64",
                output="pythonnet/netfx/amd64",
                rename={"clr.dll": "clr.pyd"},
            ),
            DotnetLib(
                "clrmodule-x86",
                "src/clrmodule/",
                runtime="win-x86",
                output="pythonnet/netfx/x86",
                rename={"clr.dll": "clr.pyd"},
            ),
        ]
    )

ext_modules = []

if BUILD_MONO:
    try:
        mono_libs = check_output(
            "pkg-config --libs mono-2", shell=True, encoding="utf8"
        )
        mono_cflags = check_output(
            "pkg-config --cflags mono-2", shell=True, encoding="utf8"
        )
        cflags = mono_cflags.strip()
        libs = mono_libs.strip()

        # build the clr python module
        clr_ext = Extension(
            "pythonnet.mono.clr",
            language="c++",
            sources=["src/monoclr/clrmod.c"],
            extra_compile_args=cflags.split(" "),
            extra_link_args=libs.split(" "),
        )
        ext_modules.append(clr_ext)
    except Exception:
        print(
            "Failed to find mono libraries via pkg-config, skipping the Mono CLR loader"
        )


setup(
    cmdclass=cmdclass,
    name="pythonnet",
    version="3.0.0.dev1",
    description=".Net and Mono integration for Python",
    url="https://pythonnet.github.io/",
    license="MIT",
    author="The Contributors of the Python.NET Project",
    author_email="<EMAIL>",
    packages=["pythonnet"],
    install_requires=["pycparser"],
    long_description=long_description,
    # data_files=[("{install_platlib}", ["{build_lib}/pythonnet"])],
    py_modules=["clr"],
    ext_modules=ext_modules,
    dotnet_libs=dotnet_libs,
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: C#",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.6",
        "Programming Language :: Python :: 3.7",
        "Programming Language :: Python :: 3.8",
        "Operating System :: Microsoft :: Windows",
        "Operating System :: POSIX :: Linux",
        "Operating System :: MacOS :: MacOS X",
    ],
    zip_safe=False,
)

#!/usr/bin/env python

from setuptools import setup, Command, Extension
from setuptools.command.build_ext import build_ext
import distutils
from distutils.command import build
from subprocess import check_output, check_call

import sys, os

BUILD_MONO = True
BUILD_NETFX = True

PY_MAJOR = sys.version_info[0]
PY_MINOR = sys.version_info[1]

CONFIGURED_PROPS = "configured.props"


def _get_interop_filename():
    """interopXX.cs is auto-generated as part of the build.
    For common windows platforms pre-generated files are included
    as most windows users won't have Clang installed, which is
    required to generate the file.
    """
    interop_filename = "interop{0}{1}{2}.cs".format(
        PY_MAJOR, PY_MINOR, getattr(sys, "abiflags", "")
    )
    return os.path.join("src", "runtime", interop_filename)


# Write configuration to configured.props. This will go away once all of these
# can be decided at runtime.
def _write_configure_props():
    defines = [
        "PYTHON{0}{1}".format(PY_MAJOR, PY_MINOR),
    ]

    if sys.platform == "win32":
        defines.append("WINDOWS")

    if hasattr(sys, "abiflags"):
        if "d" in sys.abiflags:
            defines.append("PYTHON_WITH_PYDEBUG")
        if "m" in sys.abiflags:
            defines.append("PYTHON_WITH_PYMALLOC")

    # check the interop file exists, and create it if it doesn't
    interop_file = _get_interop_filename()
    if not os.path.exists(interop_file):
        print("Creating {0}".format(interop_file))
        geninterop = os.path.join("tools", "geninterop", "geninterop.py")
        check_call([sys.executable, geninterop, interop_file])

    import xml.etree.ElementTree as ET

    proj = ET.Element("Project")
    props = ET.SubElement(proj, "PropertyGroup")
    f = ET.SubElement(props, "PythonInteropFile")
    f.text = os.path.basename(interop_file)

    c = ET.SubElement(props, "ConfiguredConstants")
    c.text = " ".join(defines)

    ET.ElementTree(proj).write(CONFIGURED_PROPS)


class configure(Command):
    """Configure command"""

    description = "Configure the pythonnet build"
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        self.announce("Writing configured.props...", level=distutils.log.INFO)
        _write_configure_props()


class DotnetLib:
    def __init__(self, name, path, **kwargs):
        self.name = name
        self.path = path
        self.args = kwargs


class build_dotnet(Command):
    """Build command for dotnet-cli based builds"""

    description = "Build DLLs with dotnet-cli"
    user_options = [
        ("dotnet-config", None, "dotnet build configuration"),
        (
            "inplace",
            "i",
            "ignore build-lib and put compiled extensions into the source "
            + "directory alongside your pure Python modules",
        ),
    ]

    def initialize_options(self):
        self.dotnet_config = None
        self.build_lib = None
        self.inplace = False

    def finalize_options(self):
        if self.dotnet_config is None:
            self.dotnet_config = "release"

        build = self.distribution.get_command_obj("build")
        build.ensure_finalized()
        if self.inplace:
            self.build_lib = "."
        else:
            self.build_lib = build.build_lib

    def run(self):
        dotnet_modules = self.distribution.dotnet_libs
        self.run_command("configure")

        for lib in dotnet_modules:
            output = os.path.join(
                os.path.abspath(self.build_lib), lib.args.pop("output")
            )
            rename = lib.args.pop("rename", {})

            opts = sum(
                [
                    ["--" + name.replace("_", "-"), value]
                    for name, value in lib.args.items()
                ],
                [],
            )

            opts.extend(["--configuration", self.dotnet_config])
            opts.extend(["--output", output])

            self.announce("Running dotnet build...", level=distutils.log.INFO)
            self.spawn(["dotnet", "build", lib.path] + opts)

            for k, v in rename.items():
                source = os.path.join(output, k)
                dest = os.path.join(output, v)

                if os.path.isfile(source):
                    try:
                        os.remove(dest)
                    except OSError:
                        pass

                    self.move_file(src=source, dst=dest, level=distutils.log.INFO)
                else:
                    self.warn(
                        "Can't find file to rename: {}, current dir: {}".format(
                            source, os.getcwd()
                        )
                    )


# Add build_dotnet to the build tasks:
from distutils.command.build import build as _build
from setuptools.command.develop import develop as _develop
from setuptools import Distribution
import setuptools


class build(_build):
    sub_commands = _build.sub_commands + [("build_dotnet", None)]


class develop(_develop):
    def install_for_development(self):
        # Build extensions in-place
        self.reinitialize_command("build_dotnet", inplace=1)
        self.run_command("build_dotnet")

        return super().install_for_development()


# Monkey-patch Distribution s.t. it supports the dotnet_libs attribute
Distribution.dotnet_libs = None

cmdclass = {
    "build": build,
    "build_dotnet": build_dotnet,
    "configure": configure,
    "develop": develop,
}


with open("README.rst", "r") as f:
    long_description = f.read()

dotnet_libs = [
    DotnetLib(
        "python-runtime",
        "src/runtime/Python.Runtime.csproj",
        output="pythonnet/runtime",
    )
]

if BUILD_NETFX:
    dotnet_libs.extend(
        [
            DotnetLib(
                "clrmodule-amd64",
                "src/clrmodule/",
                runtime="win-x64",
                output="pythonnet/netfx/amd64",
                rename={"clr.dll": "clr.pyd"},
            ),
            DotnetLib(
                "clrmodule-x86",
                "src/clrmodule/",
                runtime="win-x86",
                output="pythonnet/netfx/x86",
                rename={"clr.dll": "clr.pyd"},
            ),
        ]
    )

ext_modules = []

if BUILD_MONO:
    try:
        mono_libs = check_output(
            "pkg-config --libs mono-2", shell=True, encoding="utf8"
        )
        mono_cflags = check_output(
            "pkg-config --cflags mono-2", shell=True, encoding="utf8"
        )
        cflags = mono_cflags.strip()
        libs = mono_libs.strip()

        # build the clr python module
        clr_ext = Extension(
            "pythonnet.mono.clr",
            language="c++",
            sources=["src/monoclr/clrmod.c"],
            extra_compile_args=cflags.split(" "),
            extra_link_args=libs.split(" "),
        )
        ext_modules.append(clr_ext)
    except Exception:
        print(
            "Failed to find mono libraries via pkg-config, skipping the Mono CLR loader"
        )


setup(
    cmdclass=cmdclass,
    name="pythonnet",
    version="3.0.0.dev1",
    description=".Net and Mono integration for Python",
    url="https://pythonnet.github.io/",
    license="MIT",
    author="The Contributors of the Python.NET Project",
    author_email="<EMAIL>",
    packages=["pythonnet"],
    install_requires=["pycparser"],
    long_description=long_description,
    # data_files=[("{install_platlib}", ["{build_lib}/pythonnet"])],
    py_modules=["clr"],
    ext_modules=ext_modules,
    dotnet_libs=dotnet_libs,
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: C#",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.6",
        "Programming Language :: Python :: 3.7",
        "Programming Language :: Python :: 3.8",
        "Operating System :: Microsoft :: Windows",
        "Operating System :: POSIX :: Linux",
        "Operating System :: MacOS :: MacOS X",
    ],
    zip_safe=False,
)

#!/usr/bin/env python interopXX.cs is auto-generated as part of the build.     For common windows platforms pre-generated files are included     as most windows users won't have Clang installed, which is     required to generate the file. # Write configuration to configured.props. This will go away once all of these # can be decided at runtime. # check the interop file exists, and create it if it doesn't Configure command Build command for dotnet-cli based builds # Add build_dotnet to the build tasks: # Build extensions in-place # Monkey-patch Distribution s.t. it supports the dotnet_libs attribute # build the clr python module # data_files=[("{install_platlib}", ["{build_lib}/pythonnet"])], #",