Version 1 OneShot
This commit is contained in:
82
build.py
Normal file
82
build.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""Build a single-file GUI executable for the current OS with PyInstaller.
|
||||
|
||||
python build.py # -> dist/FFmpegWrapper(.exe)
|
||||
python build.py --ffmpeg-dir DIR # also copy ffmpeg + ffprobe from DIR next to the exe
|
||||
# and pack everything into a .zip / .tar.gz
|
||||
|
||||
PyInstaller cannot cross-compile: run this on Windows to get the .exe and on
|
||||
Linux to get the Linux binary (or use the CI workflow, which does both).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
NAME = "FFmpegWrapper"
|
||||
IS_WINDOWS = sys.platform.startswith("win")
|
||||
EXE = ".exe" if IS_WINDOWS else ""
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument("--ffmpeg-dir", type=Path, help="folder containing ffmpeg and ffprobe to bundle")
|
||||
ap.add_argument("--onedir", action="store_true", help="build a folder instead of a single file (faster start-up)")
|
||||
args = ap.parse_args()
|
||||
|
||||
import PyInstaller.__main__
|
||||
|
||||
from ffwrap import __version__
|
||||
|
||||
sep = ";" if IS_WINDOWS else ":"
|
||||
pyi_args = [
|
||||
str(ROOT / "run.py"),
|
||||
"--name", NAME,
|
||||
"--windowed",
|
||||
"--noconfirm",
|
||||
"--clean",
|
||||
"--onedir" if args.onedir else "--onefile",
|
||||
"--icon", str(ROOT / "assets" / "icon.ico"),
|
||||
"--add-data", f"{ROOT / 'assets' / 'icon.png'}{sep}assets",
|
||||
"--distpath", str(ROOT / "dist"),
|
||||
"--workpath", str(ROOT / "build"),
|
||||
"--specpath", str(ROOT / "build"),
|
||||
# Not needed and only add weight.
|
||||
"--exclude-module", "tkinter",
|
||||
"--exclude-module", "unittest",
|
||||
"--exclude-module", "pydoc",
|
||||
]
|
||||
PyInstaller.__main__.run(pyi_args)
|
||||
|
||||
dist = ROOT / "dist"
|
||||
built = dist / NAME if args.onedir else dist / f"{NAME}{EXE}"
|
||||
print(f"\nBuilt {built}")
|
||||
|
||||
if args.ffmpeg_dir:
|
||||
# Stage <exe or onedir tree> + ffmpeg + ffprobe in one folder and archive it.
|
||||
stage = dist / "package" / NAME
|
||||
shutil.rmtree(stage.parent, ignore_errors=True)
|
||||
if args.onedir:
|
||||
shutil.copytree(built, stage)
|
||||
else:
|
||||
stage.mkdir(parents=True)
|
||||
shutil.copy2(built, stage)
|
||||
for tool in ("ffmpeg", "ffprobe"):
|
||||
src = args.ffmpeg_dir / f"{tool}{EXE}"
|
||||
if not src.is_file():
|
||||
print(f"error: {src} not found", file=sys.stderr)
|
||||
return 1
|
||||
shutil.copy2(src, stage)
|
||||
plat = "windows-x64" if IS_WINDOWS else "linux-x64"
|
||||
archive = shutil.make_archive(
|
||||
str(dist / f"{NAME}-{__version__}-{plat}"), "zip" if IS_WINDOWS else "gztar",
|
||||
root_dir=stage.parent, base_dir=NAME)
|
||||
print(f"Packed {archive}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user