diff --git a/.gitignore b/.gitignore index 73181df..20648d8 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ /dist/ /.idea/ /build/lib/exam_generator/ +/packaging/windows/build/exam_generator/ diff --git a/packaging/windows/build_windows_exe.py b/packaging/windows/build_windows_exe.py new file mode 100644 index 0000000..8ca1485 --- /dev/null +++ b/packaging/windows/build_windows_exe.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +""" +Builds a Windows executable of exam_generator using PyInstaller +""" +import os +import shutil +from PyInstaller.__main__ import run as pyinstaller_run + +# Specifications for PyInstaller +spec_file = "exam_generator.spec" + +# Directories where to build into +script_dir = os.getcwd() +build_dir = os.path.join(script_dir, "build") +temp_dir = os.path.join(script_dir, "temp") + +# Build the command string +cmd = ["--clean", f"--distpath={build_dir}", f"--workpath={temp_dir}", spec_file] + +# Clean-up environment +for dir in [build_dir, temp_dir]: + if os.path.exists(dir): + shutil.rmtree(dir, ignore_errors=True) + +# Call pyinstaller +print(f"Executing pyinstaller {' '.join(cmd)}") +pyinstaller_run(cmd) + +# Remove temp data +if os.path.exists(temp_dir): + shutil.rmtree(temp_dir, ignore_errors=True) diff --git a/packaging/windows/exam_generator.spec b/packaging/windows/exam_generator.spec new file mode 100644 index 0000000..91be682 --- /dev/null +++ b/packaging/windows/exam_generator.spec @@ -0,0 +1,58 @@ +# -*- mode: python ; coding: utf-8 -*- +import sys +import os +import glob +from PyInstaller.utils.hooks import get_module_file_attribute + +# Location of source and script files +repo_dir = os.path.realpath('../..') +module_dir = os.path.join(repo_dir, 'src/exam_generator') + +# Templates and settings of exam_generator needs to be shipped as well +data_files = [(filename, './templates') for filename in glob.glob(os.path.join(module_dir, 'templates', '*.tex'))] +data_files += [(os.path.join(repo_dir, 'settings'), './settings')] + +# It's open source, so we do not need to encrypt the python code +block_cipher = None + +# Catch really every package loaded by exam_generator +sys.setrecursionlimit(sys.getrecursionlimit() * 5) + +# Analyze what needs to be packaged +a = Analysis([os.path.join(repo_dir, 'run_exam_generator.py')], + pathex=[repo_dir, module_dir], + binaries=[], + datas=data_files, + hiddenimports=[], + hookspath=[], + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False) + +# Put everything together +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +# Specification for building the exe +exe = EXE(pyz, + a.scripts, + [], + exclude_binaries=True, + name='exam_generator', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=True) + +# Collection of all information needed for building the exe +coll = COLLECT(exe, + a.binaries, + a.zipfiles, + a.datas, + strip=False, + upx=True, + upx_exclude=[], + name='exam_generator') diff --git a/run_exam_generator.py b/run_exam_generator.py new file mode 100644 index 0000000..a97c7d3 --- /dev/null +++ b/run_exam_generator.py @@ -0,0 +1,2 @@ +import exam_generator as eg +eg.main()