156 lines
4.6 KiB
Python
156 lines
4.6 KiB
Python
'''
|
|
Build Entrypoints
|
|
'''
|
|
import json
|
|
import platform
|
|
import os # for checking for dirs
|
|
import re
|
|
from json.decoder import JSONDecodeError
|
|
from subprocess import Popen, PIPE, STDOUT, CalledProcessError
|
|
|
|
DEST_DIRECTORY = "."
|
|
|
|
# UPX greatly reduces the filesize. You can get this utility from https://upx.github.io/
|
|
# just place it in a subdirectory named "upx" and this script will find it
|
|
UPX_DIR = "upx"
|
|
if os.path.isdir(os.path.join(".", UPX_DIR)):
|
|
upx_string = f"--upx-dir={UPX_DIR}"
|
|
else:
|
|
upx_string = ""
|
|
GO = True
|
|
DIFF_DLLS = False
|
|
|
|
# set a global var for Actions to try to read
|
|
def set_output(name, value):
|
|
with open(os.environ['GITHUB_OUTPUT'], 'a') as fh:
|
|
print(f'{name}={value}', file=fh)
|
|
|
|
# build the thing
|
|
def run_build(slug):
|
|
global GO
|
|
global DIFF_DLLS
|
|
|
|
print(f"Building '{slug}' via Python {platform.python_version()}")
|
|
|
|
# get template, mod to do the thing
|
|
specTemplateFile = open(os.path.join(".","source","Template.spec"))
|
|
specTemplate = specTemplateFile.read()
|
|
specTemplateFile.close()
|
|
with(open(os.path.join(".","source",f"{slug}.spec"), "w")) as specFile:
|
|
print(f"Writing '{slug}' PyInstaller spec file")
|
|
thisTemplate = specTemplate.replace("<BINARY_SLUG>", slug)
|
|
specFile.write(thisTemplate)
|
|
|
|
PYINST_EXECUTABLE = "pyinstaller"
|
|
args = [
|
|
os.path.join("source", f"{slug}.spec").replace(os.sep, os.sep * 2),
|
|
upx_string,
|
|
"-y",
|
|
f"--distpath={DEST_DIRECTORY}"
|
|
]
|
|
errs = []
|
|
strs = []
|
|
print("PyInstaller args: %s" % " ".join(args))
|
|
cmd = [
|
|
PYINST_EXECUTABLE,
|
|
*args
|
|
]
|
|
|
|
ret = {
|
|
"stdout": [],
|
|
"stderr": []
|
|
}
|
|
|
|
with Popen(cmd, stdout=PIPE, stderr=STDOUT, bufsize=1, universal_newlines=True) as p:
|
|
for line in p.stdout:
|
|
ret["stdout"].append(line)
|
|
print(line, end='')
|
|
# if p.stderr:
|
|
# for line in p.stderr:
|
|
# ret["stderr"].append(line)
|
|
# print(line, end='')
|
|
# if p.returncode != 0:
|
|
# raise CalledProcessError(p.returncode, p.args)
|
|
|
|
# check stdout & stderr
|
|
for key in ["stdout","stderr"]:
|
|
if len(ret[key]) > 0:
|
|
for line in ret[key]:
|
|
# UPX can't compress this file
|
|
if "NotCompressibleException" in line.strip():
|
|
print(line)
|
|
errs.append(line.strip())
|
|
# print UPX messages
|
|
if "UPX" in line:
|
|
print(line)
|
|
# try to get DLL filename
|
|
elif "NotCompressibleException" in line.strip():
|
|
matches = re.search(r'api-ms-win-(?:[^-]*)-([^-]*)', line.strip())
|
|
if matches:
|
|
strAdd = matches.group(1)
|
|
strs.append(strAdd)
|
|
errs.append(line.strip())
|
|
# print collected errors
|
|
if len(errs) > 0:
|
|
print("=" * 10)
|
|
print("| ERRORS |")
|
|
print("=" * 10)
|
|
print("\n".join(errs))
|
|
else:
|
|
GO = False
|
|
|
|
# if we identified DLLs to ignore
|
|
if len(strs) > 0:
|
|
# read DLLs manifest that we've already got saved
|
|
with open(os.path.join(".","resources","app","meta","manifests","excluded_dlls.json"), "w+", encoding="utf-8") as dllsManifest:
|
|
oldDLLs = []
|
|
try:
|
|
oldDLLs = json.load(dllsManifest)
|
|
except JSONDecodeError as e:
|
|
oldDLLs = []
|
|
# raise ValueError("Windows DLLs manifest malformed!")
|
|
|
|
# bucket for new list
|
|
newDLLs = sorted(list(set(oldDLLs)))
|
|
|
|
# items to add
|
|
addDLLs = sorted(list(set(strs)))
|
|
|
|
# add items
|
|
newDLLs += addDLLs
|
|
newDLLs = sorted(list(set(newDLLs)))
|
|
|
|
# if the lists differ, we've gotta update the included list
|
|
diffDLLs = newDLLs != oldDLLs
|
|
|
|
if diffDLLs:
|
|
DIFF_DLLS = True
|
|
dllsManifest.seek(0)
|
|
dllsManifest.truncate()
|
|
dllsManifest.write(json.dumps(sorted(newDLLs), indent=2))
|
|
|
|
print(f"Old DLLs: {json.dumps(sorted(oldDLLs))}")
|
|
print(f"Add DLLs: {json.dumps(sorted(addDLLs))}")
|
|
print(f"New DLLs: {json.dumps(sorted(newDLLs))}")
|
|
print(f"Diff DLLs: {DIFF_DLLS}")
|
|
print("")
|
|
|
|
def go_build(slug):
|
|
slug = slug or ""
|
|
if slug != "":
|
|
GO = True
|
|
while GO:
|
|
run_build(slug)
|
|
GO = False
|
|
|
|
if __name__ == "__main__":
|
|
binary_slugs = []
|
|
#TODO: Make sure we've got the proper binaries that we need
|
|
with open(os.path.join(".","resources","app","meta","manifests","binaries.json")) as binariesFile:
|
|
binary_slugs = json.load(binariesFile)
|
|
for file_slug in binary_slugs:
|
|
go_build(file_slug)
|
|
if DIFF_DLLS:
|
|
print("🔴Had to update Error DLLs list!")
|
|
exit(1)
|