2018-12-22 06:47:05 +00:00
import glob
2019-01-15 06:21:26 +00:00
import os
import shutil
2019-01-15 07:01:43 +00:00
import subprocess
2019-01-15 03:19:15 +00:00
from pathlib import Path
2019-03-08 13:16:01 +00:00
from typing import List, Tuple
2018-12-22 06:47:05 +00:00
from PyInstaller.building.api import PYZ, EXE, COLLECT
2019-01-05 03:22:27 +00:00
from PyInstaller.building.build_main import Analysis
2018-12-22 06:47:05 +00:00
from PyInstaller.building.datastruct import TOC
2019-01-15 03:19:15 +00:00
from corrscope import version as v
2019-01-14 01:20:35 +00:00
2018-12-22 06:47:05 +00:00
block_cipher = None
2019-01-05 03:00:05 +00:00
def keep(dir, wildcard):
includes = glob.glob(f"{dir}/{wildcard}")
2019-01-14 01:20:35 +00:00
assert includes, f"{dir}, {wildcard} has no matches"
2019-01-05 03:00:05 +00:00
return [(include, dir) for include in includes]
2018-12-22 06:47:05 +00:00
2019-01-05 03:00:05 +00:00
2019-03-08 13:16:01 +00:00
InFile = str
OutFolder = str
datas: List[Tuple[InFile, OutFolder]] = []
2018-12-22 06:47:05 +00:00
2019-01-15 03:19:15 +00:00
version = v.pyinstaller_write_version()
2019-03-08 13:16:01 +00:00
datas += [(str(v.version_txt), ".")]
2019-01-15 03:19:15 +00:00
app_name = "corrscope"
app_name_version = f"{app_name}-{version}"
2019-01-14 01:20:35 +00:00
2019-01-04 06:14:57 +00:00
a = Analysis(
2019-01-14 03:52:04 +00:00
["corrscope/__main__.py"],
2019-01-04 06:14:57 +00:00
pathex=["."],
binaries=[],
datas=datas,
hiddenimports=["corrscope.gui.__init__"],
hookspath=[],
runtime_hooks=[],
excludes=["FixTk", "tcl", "tk", "_tkinter", "tkinter", "Tkinter"],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
2018-12-22 06:47:05 +00:00
# Some dirs are included by PyInstaller hooks and must be removed after the fact.
2019-01-15 03:19:15 +00:00
_path_excludes = (
2018-12-22 06:47:05 +00:00
# Matplotlib
2019-09-11 08:30:23 +00:00
# Deleting mpl-data/fonts and rendering with an unrecognized font causes matplotlib
# to enter an infinite recursive loop of findfont(...DejaVu Sans) and crash.
# So don't delete the default fonts.
2019-01-04 06:14:57 +00:00
"""
2018-12-22 06:47:05 +00:00
mpl-data/images
mpl-data/sample_data
2019-01-04 06:14:57 +00:00
"""
2018-12-22 06:47:05 +00:00
# PyQt
2019-01-04 06:14:57 +00:00
"""
2018-12-22 06:47:05 +00:00
Qt5DBus.dll
Qt5Network.dll
Qt5Quick.dll
Qt5Qml.dll
Qt5Svg.dll
Qt5WebSockets.dll
2019-01-04 06:14:57 +00:00
"""
2018-12-22 06:47:05 +00:00
# QML file list taken from https://github.com/pyinstaller/pyinstaller/blob/0f31b35fe96de59e1a6faf692340a9ef93492472/PyInstaller/hooks/hook-PyQt5.py#L55
2019-01-04 06:14:57 +00:00
"""
2018-12-22 06:47:05 +00:00
libEGL.dll libGLESv2.dll d3dcompiler_ opengl32sw.dll
2019-01-04 06:14:57 +00:00
"""
2018-12-22 06:47:05 +00:00
).split()
2019-01-15 03:19:15 +00:00
path_excludes = {s.lower() for s in _path_excludes}
2018-12-22 06:47:05 +00:00
2019-01-04 06:14:57 +00:00
2018-12-22 06:47:05 +00:00
def path_contains(path: str) -> bool:
2019-01-04 06:14:57 +00:00
path = path.replace("\\", "/").lower()
2018-12-22 06:47:05 +00:00
ret = any(x in path for x in path_excludes)
return ret
# A TOC appears to be a list of tuples of the form (name, path, typecode).
# In fact, it's an ordered set, not a list.
# A TOC contains no duplicates, where uniqueness is based on name only.
def strip(arr: TOC):
arr[:] = [
2019-01-04 06:14:57 +00:00
(name, path, typecode)
for (name, path, typecode) in arr
2018-12-22 06:47:05 +00:00
if not path_contains(path)
]
strip(a.datas)
strip(a.binaries)
2019-01-04 06:14:57 +00:00
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
2019-01-15 03:19:15 +00:00
name=app_name,
2019-01-04 06:14:57 +00:00
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
)
2019-01-15 03:19:15 +00:00
2019-01-15 07:01:43 +00:00
2019-01-15 03:19:15 +00:00
class ZipCollect(COLLECT):
2019-01-15 07:01:43 +00:00
name: str # dist/dir-name, != __init__(name=)
2019-01-15 03:19:15 +00:00
def assemble(self):
ret = super().assemble()
2019-01-15 07:01:43 +00:00
if shutil.which("7z"):
cmd_7z = "7z a -mx=3".split()
# Don't use Path.with_suffix(), it removes trailing semver components.
out_name = str(Path(self.name).with_name(app_name_version)) + ".7z"
in_files = f"{self.name}/*" # asterisk removes root directory from archive
subprocess.run(cmd_7z + [out_name, in_files], check=True)
assert os.path.getsize(out_name) > 2 ** 20
2019-01-15 03:19:15 +00:00
return ret
coll = ZipCollect(
exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name=app_name
2019-01-04 06:14:57 +00:00
)