Mentions légales du service

Skip to content
Snippets Groups Projects
generate-w-pyinstaller.py 3.88 KiB
Newer Older
import glob as gb_
import os as os_
import os.path as ph_
import shutil as sh_
import subprocess as sp_
import sys as sy_
import zipfile as zp_
from os import name as OS_NAME
from os import pathsep as PATH_SEP
from typing import Sequence, Union

import pprint as pp_
import PyInstaller.__main__


PY_SCRIPT = "nutrimorph.py"
PARAMETERS = "parameters.py"
BRICK_FOLDER = "brick"
RES_PATH_CMPS = ("data",)
SRC_PATH_CMPS = ("..",)
README_PREFIX = "README"
RES_PREFIX = "DIO"

DIST_ROOT_FOLDER = "__dist__"
BUILD_ROOT_FOLDER = "__build__"
PER_OS_DIST_FOLDER = f"NutriMorph-4-{OS_NAME.upper()}"
DST_RES_FOLDER = "data"


def InBaseFolder(path: Union[str, Sequence[str]]) -> str:
    #
    if isinstance(path, str):
        return ph_.realpath(ph_.join(*SRC_PATH_CMPS, path))
    else:
        return ph_.realpath(ph_.join(*SRC_PATH_CMPS, *path))


SCRIPT_NAME = ph_.splitext(PY_SCRIPT)[0]
PER_OS_DIST_FOLDER_PATH = ph_.join(DIST_ROOT_FOLDER, PER_OS_DIST_FOLDER)
PER_OS_and_SCRIPT_DIST_PATH = ph_.join(PER_OS_DIST_FOLDER_PATH, SCRIPT_NAME)
PER_OS_BUILD_FOLDER_PATH = ph_.join(BUILD_ROOT_FOLDER, OS_NAME)

PY_SCRIPT_PATH = InBaseFolder(PY_SCRIPT)
PARAMETERS_PATH = InBaseFolder(PARAMETERS)
BRICK_FOLDER_PATH = InBaseFolder(BRICK_FOLDER)
RES_FOLDER_PATH = InBaseFolder(ph_.join(*RES_PATH_CMPS))

FRANGI3_PREFIX = "frangi3"
if OS_NAME == "nt":
    # In Wine on Linux, realpath does not resolve symbolic links (2020-02-03)
    FRANGI3_PY_FOLDER = r"G:\home\eric\Code\brick\def\frangi3\frangi_py"
    if not ph_.isdir(FRANGI3_PY_FOLDER):
        # On Windows, use the definition below instead:
        FRANGI3_PY_FOLDER = InBaseFolder(("brick", "processing"))
else:
    FRANGI3_PY_FOLDER = ph_.dirname(
        ph_.realpath(ph_.join(BRICK_FOLDER_PATH, "processing", f"{FRANGI3_PREFIX}.py"))
    )
DATA_ELEMENTS = (
    (BRICK_FOLDER_PATH, BRICK_FOLDER),
    (PARAMETERS_PATH, "."),
)
BINARY_ELEMENTS = (
    (f"{ph_.join(FRANGI3_PY_FOLDER, FRANGI3_PREFIX)}-{OS_NAME}.so", "."),
)

arguments = [
    f"--distpath={PER_OS_DIST_FOLDER_PATH}",
    f"--specpath={PER_OS_BUILD_FOLDER_PATH}",
    f"--workpath={PER_OS_BUILD_FOLDER_PATH}",
    "--noconfirm",
    "--onedir",
    PY_SCRIPT_PATH,
]
for elm_type, elm_list in zip(
    ("--add-data", "--add-binary"), (DATA_ELEMENTS, BINARY_ELEMENTS)
):
    for element in elm_list:
        arguments.insert(
            arguments.__len__() - 1, f"{elm_type}={element[0]}{PATH_SEP}{element[1]}"
        )

for resource in gb_.glob(ph_.join(RES_FOLDER_PATH, f"{RES_PREFIX}*.tif")):
    arguments.insert(
        arguments.__len__() - 1, f"--add-data={resource}{PATH_SEP}{DST_RES_FOLDER}"
    )

for readme in gb_.glob(InBaseFolder(f"{README_PREFIX}*")):
    readme = ph_.realpath(readme)
    arguments.insert(arguments.__len__() - 1, f"--add-data={readme}{PATH_SEP}.")

if OS_NAME == "nt":
    arguments.insert(arguments.__len__() - 1, "--console")

print("--- Launching PyInstaller with arguments:")
pp_.pprint(arguments)
PyInstaller.__main__.run(arguments)

print("--- Moving/copying elements into place")
if OS_NAME == "nt":
    sh_.copy(f"{SCRIPT_NAME}.bat", PER_OS_DIST_FOLDER_PATH)
else:
    print(f"    /!\\ TODO: MAKE a SHELL SCRIPT for {OS_NAME.upper()} and COPY IT")
sh_.move(ph_.join(PER_OS_and_SCRIPT_DIST_PATH, PARAMETERS), PER_OS_DIST_FOLDER_PATH)
sh_.move(ph_.join(PER_OS_and_SCRIPT_DIST_PATH, DST_RES_FOLDER), PER_OS_DIST_FOLDER_PATH)
for readme in gb_.glob(ph_.join(PER_OS_and_SCRIPT_DIST_PATH, f"{README_PREFIX}*")):
    sh_.move(readme, PER_OS_DIST_FOLDER_PATH)

print("--- Creating ZIP archive")
with zp_.ZipFile(
    ph_.join(DIST_ROOT_FOLDER, f"{PER_OS_DIST_FOLDER}.zip"),
    mode="w",
    compression=zp_.ZIP_DEFLATED,
    compresslevel=9,
) as archive:
    for folder, _, documents in os_.walk(PER_OS_DIST_FOLDER_PATH):
        for document in documents:
            doc_path = ph_.join(folder, document)
            archive.write(
                doc_path, arcname=ph_.relpath(doc_path, start=DIST_ROOT_FOLDER)
            )