Add executable versioning support for Windows builds

- Implemented `set_exe_version` method in `WindowsBuilder` to set the version information for the generated executable.
- This ensures proper MSI updates by comparing file versions.
- Added error handling for missing `pefile` dependency and version resource.
- Updated `requirements-dev.txt` to include `pefile` as a dependency for building.
This commit is contained in:
claudi 2026-02-20 08:24:44 +01:00
parent a8aa54fa5e
commit bf7c7b5e5f
5 changed files with 2932 additions and 2874 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -145,6 +145,9 @@ class WindowsBuilder:
if total_size > 0:
print(f" Total size: {total_size / 1024 / 1024:.1f} MB")
# Set executable version information (required for MSI updates)
self.set_exe_version(exe_path)
# Generate SHA256 checksum
self.generate_checksum(exe_path)
@ -169,6 +172,52 @@ class WindowsBuilder:
print(f" File: {checksum_file}")
print(f" Hash: {checksum}")
def set_exe_version(self, exe_path: Path) -> None:
"""Set executable file version for Windows.
This is important for MSI updates: Windows Installer compares file versions
to determine if files should be updated during a major upgrade.
Args:
exe_path: Path to the executable file
"""
print("\n🏷️ Setting executable version information...")
try:
import pefile
except ImportError:
print("⚠️ pefile not installed - skipping EXE version update")
print(" Note: Install with: pip install pefile")
print(" EXE version info will be blank (MSI updates may not work correctly)")
return
try:
pe = pefile.PE(str(exe_path))
# Parse version into 4-part format (Major, Minor, Build, Revision)
version_parts = self.version.split(".")
while len(version_parts) < 4:
version_parts.append("0")
file_version = tuple(int(v) for v in version_parts[:4])
# Set version resource if it exists
if hasattr(pe, "VS_FIXEDFILEINFO"):
pe.VS_FIXEDFILEINFO[0].FileVersionMS = (file_version[0] << 16) | file_version[1]
pe.VS_FIXEDFILEINFO[0].FileVersionLS = (file_version[2] << 16) | file_version[3]
pe.VS_FIXEDFILEINFO[0].ProductVersionMS = (file_version[0] << 16) | file_version[1]
pe.VS_FIXEDFILEINFO[0].ProductVersionLS = (file_version[2] << 16) | file_version[3]
# Write modified PE back to file
pe.write(filename=str(exe_path))
print(f"✅ Version set to {self.version}")
else:
print("⚠️ No version resource found in EXE")
except Exception as e:
print(f"⚠️ Could not set EXE version: {e}")
print(" MSI updates may not work correctly without file version info")
def create_msi(self) -> bool:
"""Create MSI installer using WiX Toolset.