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) )