bff6d70b17
Aplicatie Flask + SQLite pentru productie alimentara: cantarirea componentelor unui produs finit si tiparirea etichetei prin QZ Tray. - produse finite (retete) formate din componente cantarite - designer vizual de etichete (mm/px, zona sigura, campuri variabile, cod QR cu continut din mai multe bucati) - legare produs finit -> sablon de eticheta - navigare pe doua taburi: Cantarire / Setari - administrare: componente, produse finite, sabloane, campuri, istoric - backup, resetare baza de date, checklist de pregatire, /healthz - CLI de administrare si serviciu systemd pentru productie - vendor/syncpulse-scale-bridge (GPL-3.0-or-later) pentru citirea cantarului
78 lines
2.8 KiB
Python
78 lines
2.8 KiB
Python
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
# Copyright (C) 2026 Farshad Zamani - Cloudtart (https://cloudtart.com)
|
|
"""
|
|
Build dist/SyncPulseScaleBridge.exe — one file, nothing to install.
|
|
|
|
python scripts/build.py (needs: pip install -r requirements-dev.txt)
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
sys.path.insert(0, ROOT)
|
|
|
|
from scale_bridge import ABOUT, COMPANY, EXE_NAME, PRODUCT, __version__ # noqa: E402
|
|
|
|
|
|
def version_file(path: str) -> None:
|
|
parts = [int(p) for p in __version__.split(".")[:3]] + [0]
|
|
numbers = ", ".join(str(n) for n in (parts + [0, 0, 0, 0])[:4])
|
|
strings = {
|
|
"CompanyName": COMPANY,
|
|
"FileDescription": f"{PRODUCT} - RS-232 scale reader and network bridge",
|
|
"FileVersion": __version__,
|
|
"InternalName": EXE_NAME,
|
|
"LegalCopyright": f"{ABOUT['copyright']}. Licensed under {ABOUT['license']}.",
|
|
"OriginalFilename": f"{EXE_NAME}.exe",
|
|
"ProductName": PRODUCT,
|
|
"ProductVersion": __version__,
|
|
"Comments": f"Author: {ABOUT['author']} - {ABOUT['website']} - {ABOUT['repository']}",
|
|
}
|
|
entries = ",\n".join(f" StringStruct({k!r}, {v!r})" for k, v in strings.items())
|
|
text = f"""# UTF-8
|
|
VSVersionInfo(
|
|
ffi=FixedFileInfo(filevers=({numbers}), prodvers=({numbers}), mask=0x3f, flags=0x0,
|
|
OS=0x40004, fileType=0x1, subtype=0x0, date=(0, 0)),
|
|
kids=[
|
|
StringFileInfo([
|
|
StringTable('040904B0', [
|
|
{entries}
|
|
])
|
|
]),
|
|
VarFileInfo([VarStruct('Translation', [1033, 1200])])
|
|
]
|
|
)
|
|
"""
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
f.write(text)
|
|
|
|
|
|
def main() -> int:
|
|
build = os.path.join(ROOT, "build")
|
|
os.makedirs(build, exist_ok=True)
|
|
icon = os.path.join(ROOT, "assets", "icon.ico")
|
|
if not os.path.exists(icon):
|
|
subprocess.check_call([sys.executable, os.path.join(ROOT, "scripts", "make_icon.py")])
|
|
vfile = os.path.join(build, "version_info.txt")
|
|
version_file(vfile)
|
|
cmd = [sys.executable, "-m", "PyInstaller", "--noconfirm", "--clean", "--onefile", "--console",
|
|
"--name", EXE_NAME, "--icon", icon, "--version-file", vfile,
|
|
"--distpath", os.path.join(ROOT, "dist"), "--workpath", os.path.join(build, "pyinstaller"),
|
|
"--specpath", build, os.path.join(ROOT, "run_bridge.py")]
|
|
subprocess.check_call(cmd, cwd=ROOT)
|
|
exe = os.path.join(ROOT, "dist", EXE_NAME + (".exe" if os.name == "nt" else ""))
|
|
with open(exe, "rb") as f:
|
|
digest = hashlib.sha256(f.read()).hexdigest()
|
|
with open(exe + ".sha256", "w", encoding="ascii", newline="\n") as f:
|
|
f.write(f"{digest} {os.path.basename(exe)}\n")
|
|
print(f"\nbuilt {exe}\nSHA-256 {digest}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|