From 247d632cc67c420b32d9b38ee1b76d73cf51ef96 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Wed, 26 Jul 2023 22:31:43 -0400 Subject: [PATCH 01/16] #2040 First Pass - Update Build System --- .github/workflows/windows-build.yml | 6 +- Build-exe-and-msi.py | 298 --------------------------- ChangeLog.md | 2 +- Contributing.md | 4 +- build.py | 306 ++++++++++++++++++++++++++++ config/__init__.py | 2 +- docs/Releasing.md | 20 +- docs/Windows-Manifest.md | 2 +- plugins/coriolis.py | 2 +- plugins/eddn.py | 2 +- plugins/edsm.py | 2 +- plugins/edsy.py | 2 +- plugins/inara.py | 2 +- 13 files changed, 329 insertions(+), 321 deletions(-) delete mode 100644 Build-exe-and-msi.py create mode 100644 build.py diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index 37de619f..fc34c4bd 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -43,7 +43,7 @@ jobs: --exclude=.git* \ --exclude=.mypy.ini \ --exclude=.pre-commit-config.yaml \ - --exclude=Build-exe-and-msi.py \ + --exclude=build.py \ --exclude=*.manifest \ --exclude=coriolis-data \ --exclude=img \ @@ -92,7 +92,7 @@ jobs: # directory. # NB: If this gets too long it can cause zip 'Command Line Error', # presumably due to a Windows CL length limit. - exclusions: 'EDMarketConnector/EDMarketConnector-release-*.* EDMarketConnector/.editorconfig EDMarketConnector/.flake8 EDMarketConnector/.git* EDMarketConnector/.mypy.ini EDMarketConnector/.pre-commit-config.yaml EDMarketConnector/Build-exe-and-msi.py EDMarketConnector/*.manifest EDMarketConnector/coriolis-data/ EDMarketConnector/img/ EDMarketConnector/pyproject.toml EDMarketConnector/scripts/ EDMarketConnector/tests/ EDMarketConnector/wix/' + exclusions: 'EDMarketConnector/EDMarketConnector-release-*.* EDMarketConnector/.editorconfig EDMarketConnector/.flake8 EDMarketConnector/.git* EDMarketConnector/.mypy.ini EDMarketConnector/.pre-commit-config.yaml EDMarketConnector/build.py EDMarketConnector/*.manifest EDMarketConnector/coriolis-data/ EDMarketConnector/img/ EDMarketConnector/pyproject.toml EDMarketConnector/scripts/ EDMarketConnector/tests/ EDMarketConnector/wix/' - uses: actions/setup-python@v4 with: @@ -112,7 +112,7 @@ jobs: - name: Build EDMC run: | - python Build-exe-and-msi.py + python build.py - name: Upload build files uses: actions/upload-artifact@v3 diff --git a/Build-exe-and-msi.py b/Build-exe-and-msi.py deleted file mode 100644 index 20042ccb..00000000 --- a/Build-exe-and-msi.py +++ /dev/null @@ -1,298 +0,0 @@ -#!/usr/bin/env python3 -"""Build to executables and MSI installer using py2exe and other tools.""" -import os -import pathlib -import re -import shutil -import sys -from os.path import exists, isdir, join -from tempfile import gettempdir - -from lxml import etree -from py2exe import freeze - -from config import appcmdname, appname, appversion, appversion_nobuild, copyright, git_shorthash_from_head -from constants import GITVERSION_FILE - -########################################################################### -# Check we're on a supported platform -########################################################################### -if sys.version_info[0:2] != (3, 11): - raise AssertionError(f'Unexpected python version {sys.version}') - -if sys.platform == 'win32': - import py2exe # noqa: F401 # Yes, this *is* used - dist_dir = 'dist.win32' - -else: - raise AssertionError(f'Unsupported platform {sys.platform}') - -# This added to make mypy happy -assert sys.platform == 'win32' -########################################################################### - -########################################################################### -# Retrieve current git short hash and store in file GITVERSION_FILE -########################################################################### -git_shorthash = git_shorthash_from_head() -if git_shorthash is None: - exit(-1) - -with open(GITVERSION_FILE, 'w+', encoding='utf-8') as gvf: - gvf.write(git_shorthash) - -print(f'Git short hash: {git_shorthash}') -########################################################################### - -########################################################################### -# Misc. Configuration -########################################################################### -# Split version, as py2exe wants the 'base' for version -semver = appversion() -appversion_str = str(semver) -base_appversion = str(semver.truncate('patch')) - -# Ensure a clean `dist_dir` by first removing it. -if dist_dir and len(dist_dir) > 1 and isdir(dist_dir): - shutil.rmtree(dist_dir) - -# Windows paths -WIXPATH = r'C:\Program Files (x86)\WiX Toolset v3.11\bin' -SDKPATH = r'C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86' -########################################################################### - -########################################################################### - -########################################################################### -# Set up all the options, extra files etc. for py2exe build. -########################################################################### -APP = 'EDMarketConnector.py' -APPCMD = 'EDMC.py' -PLUGINS = [ - 'plugins/coriolis.py', - 'plugins/eddn.py', - 'plugins/edsm.py', - 'plugins/edsy.py', - 'plugins/inara.py', -] - -OPTIONS = { - 'py2exe': { - 'dist_dir': dist_dir, - 'optimize': 2, - 'packages': [ - 'asyncio', # No longer auto as of py3.10+py2exe 0.11 - 'multiprocessing', # No longer auto as of py3.10+py2exe 0.11 - 'pkg_resources._vendor.platformdirs', # Necessary 2023-01-17 - 'sqlite3', # Included for plugins - 'util', # 2022-02-01 only imported in plugins/eddn.py - ], - 'includes': [ - 'dataclasses', - 'shutil', # Included for plugins - 'timeout_session', - 'zipfile', # Included for plugins - ], - 'excludes': [ - 'distutils', - '_markerlib', - 'optparse', - 'PIL', - 'simplejson', - 'unittest' - ], - } -} - -DATA_FILES = [ - ('', [ - '.gitversion', # Contains git short hash - 'WinSparkle.dll', - 'WinSparkle.pdb', # For debugging - don't include in package - 'EUROCAPS.TTF', - 'ChangeLog.md', - 'snd_good.wav', - 'snd_bad.wav', - 'modules.p', - 'ships.p', - f'{appname}.VisualElementsManifest.xml', - f'{appname}.ico', - 'EDMarketConnector - TRACE.bat', - 'EDMarketConnector - localserver-auth.bat', - 'EDMarketConnector - reset-ui.bat', - ]), - ('L10n', [join('L10n', x) for x in os.listdir('L10n') if x.endswith('.strings')]), - ('FDevIDs', [ - join('FDevIDs', 'commodity.csv'), - join('FDevIDs', 'rare_commodity.csv'), - ]), - ('plugins', PLUGINS), -] -########################################################################### - -########################################################################### -# Use py2exe's `freeze()` to produce the executables. -########################################################################### -freeze( - version_info={ - 'description': 'Downloads commodity market and other station data from the game Elite Dangerous for use with' - ' all popular online and offline trading tools.', - 'company_name': 'EDCD', # Used by WinSparkle - 'product_name': appname, # Used by WinSparkle - 'version': base_appversion, - 'product_version': appversion_str, - 'copyright': copyright, - 'language': 'English (United States)', - }, - windows=[ - { - 'dest_base': appname, - 'script': APP, - 'icon_resources': [(0, f'{appname}.ico')], - 'other_resources': [(24, 1, open(f'{appname}.manifest').read())], - } - ], - console=[ - { - 'dest_base': appcmdname, - 'script': APPCMD, - 'other_resources': [(24, 1, open(f'{appcmdname}.manifest').read())], - } - ], - data_files=DATA_FILES, - options=OPTIONS, -) -########################################################################### - -########################################################################### -# Build installer(s) -########################################################################### -package_filename = None -template_file = pathlib.Path('wix/template.wxs') -components_file = pathlib.Path('wix/components.wxs') -final_wxs_file = pathlib.Path('EDMarketConnector.wxs') - -# Use heat.exe to generate the Component for all files inside dist.win32 -os.system(rf'"{WIXPATH}\heat.exe" dir {dist_dir}\ -ag -sfrag -srid -suid -out {components_file}') - -component_tree = etree.parse(str(components_file)) -# 1. Change the element: -# -# -# -# to: -# -# -directory_win32 = component_tree.find('.//{*}Directory[@Id="dist.win32"][@Name="dist.win32"]') -if directory_win32 is None: - raise ValueError(f'{components_file}: Expected Directory with Id="dist.win32"') - -directory_win32.set('Id', 'INSTALLDIR') -directory_win32.set('Name', '$(var.PRODUCTNAME)') -# 2. Change: -# -# -# -# -# -# to: -# -# -# -# -# -main_executable = directory_win32.find('.//{*}Component[@Id="EDMarketConnector.exe"]') -if main_executable is None: - raise ValueError(f'{components_file}: Expected Component with Id="EDMarketConnector.exe"') - -main_executable.set('Id', 'MainExecutable') -main_executable.set('Guid', '{D33BB66E-9664-4AB6-A044-3004B50A09B0}') -shortcut = etree.SubElement( - main_executable, - 'Shortcut', - nsmap=main_executable.nsmap, - attrib={ - 'Id': 'MainExeShortcut', - 'Directory': 'ProgramMenuFolder', - 'Name': '$(var.PRODUCTLONGNAME)', - 'Description': 'Downloads station data from Elite: Dangerous', - 'WorkingDirectory': 'INSTALLDIR', - 'Icon': 'EDMarketConnector.exe', - 'IconIndex': '0', - 'Advertise': 'yes' - } -) -# Now insert the appropriate parts as a child of the ProgramFilesFolder part -# of the template. -template_tree = etree.parse(str(template_file)) -program_files_folder = template_tree.find('.//{*}Directory[@Id="ProgramFilesFolder"]') -if program_files_folder is None: - raise ValueError(f'{template_file}: Expected Directory with Id="ProgramFilesFolder"') - -program_files_folder.insert(0, directory_win32) -# Append the Feature/ComponentRef listing to match -feature = template_tree.find('.//{*}Feature[@Id="Complete"][@Level="1"]') -if feature is None: - raise ValueError(f'{template_file}: Expected Feature element with Id="Complete" Level="1"') - -# This isn't part of the components -feature.append( - etree.Element( - 'ComponentRef', - attrib={ - 'Id': 'RegistryEntries' - }, - nsmap=directory_win32.nsmap - ) -) -for c in directory_win32.findall('.//{*}Component'): - feature.append( - etree.Element( - 'ComponentRef', - attrib={ - 'Id': c.get('Id') - }, - nsmap=directory_win32.nsmap - ) - ) - -# Insert what we now have into the template and write it out -template_tree.write( - str(final_wxs_file), encoding='utf-8', - pretty_print=True, - xml_declaration=True -) - -os.system(rf'"{WIXPATH}\candle.exe" {appname}.wxs') - -if not exists(f'{appname}.wixobj'): - raise AssertionError(f'No {appname}.wixobj: candle.exe failed?') - -package_filename = f'{appname}_win_{appversion_nobuild()}.msi' -os.system(rf'"{WIXPATH}\light.exe" -b {dist_dir}\ -sacl -spdb -sw1076 {appname}.wixobj -out {package_filename}') - -if not exists(package_filename): - raise AssertionError(f'light.exe failed, no {package_filename}') - -# Seriously, this is how you make Windows Installer use the user's display language for its dialogs. What a crock. -# http://www.geektieguy.com/2010/03/13/create-a-multi-lingual-multi-language-msi-using-wix-and-custom-build-scripts -lcids = [ - int(x) for x in re.search( # type: ignore - r'Languages\s*=\s*"(.+?)"', - open(f'{appname}.wxs').read() - ).group(1).split(',') -] -assert lcids[0] == 1033, f'Default language is {lcids[0]}, should be 1033 (en_US)' -shutil.copyfile(package_filename, join(gettempdir(), f'{appname}_1033.msi')) -for lcid in lcids[1:]: - shutil.copyfile( - join(gettempdir(), f'{appname}_1033.msi'), - join(gettempdir(), f'{appname}_{lcid}.msi') - ) - # Don't care about codepage because the displayed strings come from msiexec not our msi - os.system(rf'cscript /nologo "{SDKPATH}\WiLangId.vbs" {gettempdir()}\{appname}_{lcid}.msi Product {lcid}') - os.system(rf'"{SDKPATH}\MsiTran.Exe" -g {gettempdir()}\{appname}_1033.msi {gettempdir()}\{appname}_{lcid}.msi {gettempdir()}\{lcid}.mst') # noqa: E501 # Not going to get shorter - os.system(rf'cscript /nologo "{SDKPATH}\WiSubStg.vbs" {package_filename} {gettempdir()}\{lcid}.mst {lcid}') -########################################################################### diff --git a/ChangeLog.md b/ChangeLog.md index 08f08954..5dca72b3 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -611,7 +611,7 @@ Developers * We now build using the new, `setuptools` mediated py2exe `freeze()` method, so we're in the clear for when `distutils` is removed in Python 3.12. * The old `setup.py` file, along with associated `py2exe.cmd` have been removed - in favour of the new `Build-exe-and-msi.py` file. Documentation updated. + in favour of the new `build.py` file. Documentation updated. --- diff --git a/Contributing.md b/Contributing.md index 119f8957..5f7bc158 100644 --- a/Contributing.md +++ b/Contributing.md @@ -389,7 +389,7 @@ information about this build process. Thus, you **MUST** check if any imports you add in `plugins/*.py` files are only referenced in that file (or also only in any other core plugin), and if so -**YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN `Build-exe-and-msi.py` +**YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN `build.py` IN ORDER TO ENSURE THE FILES ARE ACTUALLY PRESENT IN AN END-USER INSTALLATION ON WINDOWS.** @@ -409,7 +409,7 @@ the appropriate `packages` definition to: Note that in this case it's in `packages` because we want the whole directory adding. For a single file an extra item in `includes` would suffice. -Such additions to `Build-exe-and-msi.py` should not cause any issues if +Such additions to `build.py` should not cause any issues if subsequent project changes cause `py2exe` to automatically pick up the same file(s). diff --git a/build.py b/build.py new file mode 100644 index 00000000..c3abc5df --- /dev/null +++ b/build.py @@ -0,0 +1,306 @@ +""" +build.py - Build the Installer +Copyright (c) EDCD, All Rights Reserved +Licensed under the GNU General Public License. +See LICENSE file. +""" +import os +import re +import shutil +import subprocess +import sys +import pathlib +from os.path import exists, join, isdir +from tempfile import gettempdir +from lxml import etree +import py2exe +from config import ( + appcmdname, + appname, + appversion, + appversion_nobuild, + copyright, + git_shorthash_from_head, +) + + +def system_check(dist_dir): + if sys.version_info < (3, 11): + sys.exit(f"Unexpected Python version {sys.version}") + + if sys.platform != "win32": + sys.exit(f"Unsupported platform {sys.platform}") + + git_shorthash = git_shorthash_from_head() + if git_shorthash is None: + sys.exit("Invalid Git Hash") + + gitversion_file = ".gitversion" + with open(gitversion_file, "w+", encoding="utf-8") as gvf: + gvf.write(git_shorthash) + + print(f"Git short hash: {git_shorthash}") + + if dist_dir and len(dist_dir) > 1 and isdir(dist_dir): + shutil.rmtree(dist_dir) + return gitversion_file + + +def generate_data_files(app_name, gitversion_file): + l10n_dir = "L10n" + fdevids_dir = "FDevIDs" + data_files = [ + ( + "", + [ + gitversion_file, + "WinSparkle.dll", + "WinSparkle.pdb", + "EUROCAPS.TTF", + "ChangeLog.md", + "snd_good.wav", + "snd_bad.wav", + "modules.p", + "ships.p", + f"{app_name}.VisualElementsManifest.xml", + f"{app_name}.ico", + "EDMarketConnector - TRACE.bat", + "EDMarketConnector - localserver-auth.bat", + "EDMarketConnector - reset-ui.bat", + ], + ), + ( + l10n_dir, + [join(l10n_dir, x) for x in os.listdir(l10n_dir) if x.endswith(".strings")], + ), + ( + fdevids_dir, + [ + join(fdevids_dir, "commodity.csv"), + join(fdevids_dir, "rare_commodity.csv"), + ], + ), + ("plugins", PLUGINS), + ] + return data_files + + +def windows_installer_display_lang(app_name, filename): + lcids = [ + int(x) + for x in re.search( # type: ignore + r'Languages\s*=\s*"(.+?)"', open(f"{app_name}.wxs", encoding="UTF8").read() + ) + .group(1) + .split(",") + ] + assert lcids[0] == 1033, f"Default language is {lcids[0]}, should be 1033 (en_US)" + shutil.copyfile(filename, join(gettempdir(), f"{app_name}_1033.msi")) + for lcid in lcids[1:]: + shutil.copyfile( + join(gettempdir(), f"{app_name}_1033.msi"), + join(gettempdir(), f"{app_name}_{lcid}.msi"), + ) + # Don't care about codepage because the displayed strings come from msiexec not our msi + os.system( + rf'cscript /nologo "{SDKPATH}\WiLangId.vbs" {gettempdir()}\{app_name}_{lcid}.msi Product {lcid}' + ) + os.system( + rf'"{SDKPATH}\MsiTran.Exe" -g {gettempdir()}\{app_name}_1033.msi {gettempdir()}\{app_name}_{lcid}.msi {gettempdir()}\{lcid}.mst' + ) # noqa: E501 # Not going to get shorter + os.system( + rf'cscript /nologo "{SDKPATH}\WiSubStg.vbs" {filename} {gettempdir()}\{lcid}.mst {lcid}' + ) + + +if __name__ == "__main__": + DIST_DIR = "dist.win32" + GITVERSION_FILENAME = system_check(DIST_DIR) + # Constants + WIXPATH = rf"{os.environ['WIX']}\bin" + SDKPATH = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86" + PLUGINS = [ + "plugins/coriolis.py", + "plugins/eddn.py", + "plugins/edsm.py", + "plugins/edsy.py", + "plugins/inara.py", + ] + OPTIONS = { + "py2exe": { + "dist_dir": DIST_DIR, + "optimize": 2, + "packages": [ + "asyncio", + "multiprocessing", + "pkg_resources._vendor.platformdirs", + "sqlite3", + "util", + ], + "includes": ["dataclasses", "shutil", "timeout_session", "zipfile"], + "excludes": [ + "distutils", + "_markerlib", + "optparse", + "PIL", + "simplejson", + "unittest", + "doctest", + "pdb", + "difflib", + ], + } + } + + # Function to generate DATA_FILES list + DATA_FILES = generate_data_files(appname, GITVERSION_FILENAME) + + version_info = { + "description": "Downloads commodity market and other station data from the game" + " Elite Dangerous for use with all popular online and offline trading tools.", + "company_name": "EDCD", # Used by WinSparkle + "product_name": appname, # Used by WinSparkle + "version": str(appversion().truncate()), + "product_version": str(appversion()), + "copyright": copyright, + "language": "English (United States)", + } + + windows_config = { + "dest_base": appname, + "script": "EDMarketConnector.py", + "icon_resources": [(0, f"{appname}.ico")], + "other_resources": [ + (24, 1, pathlib.Path(f"{appname}.manifest").read_text(encoding="UTF8")) + ], + } + + console_config = { + "dest_base": appcmdname, + "script": "EDMC.py", + "other_resources": [ + (24, 1, pathlib.Path(f"{appcmdname}.manifest").read_text(encoding="UTF8")) + ], + } + + py2exe.freeze( + version_info=version_info, + windows=[windows_config], + console=[console_config], + data_files=DATA_FILES, + options=OPTIONS, + ) + + ########################################################################### + # Build installer(s) + ########################################################################### + template_file = pathlib.Path("wix/template.wxs") + components_file = pathlib.Path("wix/components.wxs") + final_wxs_file = pathlib.Path("EDMarketConnector.wxs") + + # Use heat.exe to generate the Component for all files inside dist.win32 + heat_command = [ + str(join(WIXPATH, "heat.exe")), + "dir", + str(DIST_DIR), + "-ag", + "-sfrag", + "-srid", + "-suid", + "-out", + str(components_file), + ] + subprocess.run(heat_command, check=True) + + component_tree = etree.parse(str(components_file)) + # Modify component_tree as described in the original code... + + directory_win32 = component_tree.find( + './/{*}Directory[@Id="dist.win32"][@Name="dist.win32"]' + ) + if directory_win32 is None: + raise ValueError(f'{components_file}: Expected Directory with Id="dist.win32"') + + directory_win32.set("Id", "INSTALLDIR") + directory_win32.set("Name", "$(var.PRODUCTNAME)") + + main_executable = directory_win32.find( + './/{*}Component[@Id="EDMarketConnector.exe"]' + ) + if main_executable is None: + raise ValueError( + f'{components_file}: Expected Component with Id="EDMarketConnector.exe"' + ) + + main_executable.set("Id", "MainExecutable") + main_executable.set("Guid", "{D33BB66E-9664-4AB6-A044-3004B50A09B0}") + shortcut = etree.SubElement( + main_executable, + "Shortcut", + nsmap=main_executable.nsmap, + attrib={ + "Id": "MainExeShortcut", + "Directory": "ProgramMenuFolder", + "Name": "$(var.PRODUCTLONGNAME)", + "Description": "Downloads station data from Elite: Dangerous", + "WorkingDirectory": "INSTALLDIR", + "Icon": "EDMarketConnector.exe", + "IconIndex": "0", + "Advertise": "yes", + }, + ) + # Now insert the appropriate parts as a child of the ProgramFilesFolder part + # of the template. + template_tree = etree.parse(str(template_file)) + program_files_folder = template_tree.find( + './/{*}Directory[@Id="ProgramFilesFolder"]' + ) + if program_files_folder is None: + raise ValueError( + f'{template_file}: Expected Directory with Id="ProgramFilesFolder"' + ) + + program_files_folder.insert(0, directory_win32) + # Append the Feature/ComponentRef listing to match + feature = template_tree.find('.//{*}Feature[@Id="Complete"][@Level="1"]') + if feature is None: + raise ValueError( + f'{template_file}: Expected Feature element with Id="Complete" Level="1"' + ) + # This isn't part of the components + feature.append( + etree.Element( + "ComponentRef", + attrib={"Id": "RegistryEntries"}, + nsmap=directory_win32.nsmap, + ) + ) + for c in directory_win32.findall(".//{*}Component"): + feature.append( + etree.Element( + "ComponentRef", attrib={"Id": c.get("Id")}, nsmap=directory_win32.nsmap + ) + ) + + # Insert what we now have into the template and write it out + template_tree.write( + str(final_wxs_file), encoding="utf-8", pretty_print=True, xml_declaration=True + ) + + candle_command = rf'"{WIXPATH}\candle.exe" {appname}.wxs' + subprocess.run(candle_command, shell=True, check=True) + + if not exists(f"{appname}.wixobj"): + raise AssertionError(f"No {appname}.wixobj: candle.exe failed?") + + package_filename = f"{appname}_win_{appversion_nobuild()}.msi" + light_command = rf'"{WIXPATH}\light.exe" -b {DIST_DIR}\ -sacl -spdb -sw1076 {appname}.wixobj -out {package_filename}' + subprocess.run(light_command, shell=True, check=True) + + if not exists(package_filename): + raise AssertionError(f"light.exe failed, no {package_filename}") + + # Seriously, this is how you make Windows Installer use the user's display language for its dialogs. What a crock. + # http://www.geektieguy.com/2010/03/13/create-a-multi-lingual-multi-language-msi-using-wix-and-custom-build-scripts + windows_installer_display_lang(appname, package_filename) + ########################################################################### diff --git a/config/__init__.py b/config/__init__.py index defc364a..e4392067 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -52,7 +52,7 @@ appcmdname = 'EDMC' # # Major.Minor.Patch(-prerelease)(+buildmetadata) # NB: Do *not* import this, use the functions appversion() and appversion_nobuild() -_static_appversion = '5.9.0' +_static_appversion = '5.9.1-alpha0' _cached_version: Optional[semantic_version.Version] = None copyright = '© 2015-2019 Jonathan Harris, 2020-2023 EDCD' diff --git a/docs/Releasing.md b/docs/Releasing.md index a8c4dc80..0bd14838 100644 --- a/docs/Releasing.md +++ b/docs/Releasing.md @@ -61,7 +61,7 @@ You will need several pieces of software installed, or the files from their If you are using different versions of any of these tools then please ensure that the paths where they're installed match the associated lines in -`Build-exe-and-msi.py`. i.e. if you're using later WiX you might need to edit +`build.py`. i.e. if you're using later WiX you might need to edit the WIXPATH line, and likewise the SDKPATH line if you're using a later Windows SDK kit. @@ -100,13 +100,13 @@ resulting .exe and/or .msi files. **But** realise that the resulting program will still try to check for new versions at the main URL unless you change that. -1. Company is set in `Build-exe-and-msi.py`. Search for `company_name`. This +1. Company is set in `build.py`. Search for `company_name`. This is what appears in the EXE properties, and is also used as the location of WinSparkle registry entries on Windows. 1. Application names, version and URL of the file with latest release information. These are all in the `config/__init__.py` file. See the - `from config import ...` lines in `Build-exe-and-msi.py`: + `from config import ...` lines in `build.py`: 1. `appname`: The short appname, e.g. 'EDMarketConnector' 2. `applongname`: The long appname, e.g. 'E:D Market Connector' 3. `appcmdname`: The CLI appname, e.g. 'EDMC' @@ -144,9 +144,9 @@ that. If you add a new file to the program that needs to be distributed to users as well then you will need to properly add it to the build process. -### Build-exe-and-msi.py +### build.py -You'll need to add it in `Build-exe-and-msi.py` so that py2exe includes it in +You'll need to add it in `build.py` so that py2exe includes it in the build. Add the file to the DATA_FILES statement. ### WiX @@ -260,19 +260,19 @@ a 'Git bash' window. The 'Terminal' tab of PyCharm works fine. Assuming the correct python.exe is associated with .py files then simply run: ```batch -Build-exe-and-msi.py +build.py ``` else you might need this, which assumes correct python.exe is in your PATH: ```batch -python.exe Build-exe-and-msi.py +python.exe build.py ``` else you'll have to specify the path to python.exe, e.g.: ```batch -"C:\Program Files \(x86)\Python38-32\python.exe" Build-exe-and-msi.py +"C:\Program Files \(x86)\Python38-32\python.exe" build.py ``` Output will be something like (`...` denoting parts elided for brevity): @@ -308,7 +308,7 @@ Done **Do check the output** for things like not properly specifying extra files to be included in the install. If they're not picked up by current rules in -`Build-exe-and-msi.py` then you will need to add them to the `win32` +`build.py` then you will need to add them to the `win32` `DATA_FILES` array. You should now have one new/updated folder `dist.win32` and two new files @@ -456,6 +456,6 @@ When changing the Python version (Major.Minor.Patch) used: 1. Major or Minor level changes: - 1. `Build-exe-and-msi.py` will need its version check updating. + 1. `build.py` will need its version check updating. 2. `.pre-commit-config.yaml` will need the `default_language_version` section updated to the appropriate version. diff --git a/docs/Windows-Manifest.md b/docs/Windows-Manifest.md index ab0014a7..a9b7b2d8 100644 --- a/docs/Windows-Manifest.md +++ b/docs/Windows-Manifest.md @@ -6,7 +6,7 @@ this is to include an XML-format .manifest file at build time. ## Build time -We specify .manifest files in `Build-exe-and-msi.py`. +We specify .manifest files in `build.py`. ## Editing or changing a manifest diff --git a/plugins/coriolis.py b/plugins/coriolis.py index 29fddf26..9dae230d 100644 --- a/plugins/coriolis.py +++ b/plugins/coriolis.py @@ -16,7 +16,7 @@ # referenced in this file (or only in any other core plugin), and if so... # # YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN -# `Build-exe-and-msi.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT +# `build.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT # IN AN END-USER INSTALLATION ON WINDOWS. # # ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# diff --git a/plugins/eddn.py b/plugins/eddn.py index c7c5ca3e..25033c48 100644 --- a/plugins/eddn.py +++ b/plugins/eddn.py @@ -16,7 +16,7 @@ # referenced in this file (or only in any other core plugin), and if so... # # YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN -# `Build-exe-and-msi.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT +# `build.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT # IN AN END-USER INSTALLATION ON WINDOWS. # # ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# diff --git a/plugins/edsm.py b/plugins/edsm.py index a48177e0..256f89f2 100644 --- a/plugins/edsm.py +++ b/plugins/edsm.py @@ -25,7 +25,7 @@ # referenced in this file (or only in any other core plugin), and if so... # # YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN -# `Build-exe-and-msi.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT IN +# `build.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT IN # AN END-USER INSTALLATION ON WINDOWS. # # diff --git a/plugins/edsy.py b/plugins/edsy.py index 5ceb21d5..17b16ef0 100644 --- a/plugins/edsy.py +++ b/plugins/edsy.py @@ -16,7 +16,7 @@ # referenced in this file (or only in any other core plugin), and if so... # # YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN -# `Build-exe-and-msi.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT IN +# `build.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT IN # AN END-USER INSTALLATION ON WINDOWS. # # diff --git a/plugins/inara.py b/plugins/inara.py index 326b963b..a5b17bd0 100644 --- a/plugins/inara.py +++ b/plugins/inara.py @@ -16,7 +16,7 @@ # referenced in this file (or only in any other core plugin), and if so... # # YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN -# `Build-exe-and-msi.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT +# `build.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT # IN AN END-USER INSTALLATION ON WINDOWS. # # ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# From 1690f8f3a9b162090ff7ab4291349990d723bbe1 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Wed, 26 Jul 2023 23:18:18 -0400 Subject: [PATCH 02/16] #2040 Retire iSort Going to do a handover to black (New Maintainer Preference) --- build.py | 16 +++++++++++----- pyproject.toml | 3 --- requirements-dev.txt | 2 -- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/build.py b/build.py index c3abc5df..0f02afd3 100644 --- a/build.py +++ b/build.py @@ -1,5 +1,6 @@ """ -build.py - Build the Installer +build.py - Build the Installer. + Copyright (c) EDCD, All Rights Reserved Licensed under the GNU General Public License. See LICENSE file. @@ -10,10 +11,10 @@ import shutil import subprocess import sys import pathlib +import py2exe from os.path import exists, join, isdir from tempfile import gettempdir from lxml import etree -import py2exe from config import ( appcmdname, appname, @@ -25,6 +26,7 @@ from config import ( def system_check(dist_dir): + """Check if the system is able to build.""" if sys.version_info < (3, 11): sys.exit(f"Unexpected Python version {sys.version}") @@ -47,6 +49,7 @@ def system_check(dist_dir): def generate_data_files(app_name, gitversion_file): + """Create the required datafiles to build.""" l10n_dir = "L10n" fdevids_dir = "FDevIDs" data_files = [ @@ -86,6 +89,7 @@ def generate_data_files(app_name, gitversion_file): def windows_installer_display_lang(app_name, filename): + """Configure the Windows Installer Display Language.""" lcids = [ int(x) for x in re.search( # type: ignore @@ -106,8 +110,9 @@ def windows_installer_display_lang(app_name, filename): rf'cscript /nologo "{SDKPATH}\WiLangId.vbs" {gettempdir()}\{app_name}_{lcid}.msi Product {lcid}' ) os.system( - rf'"{SDKPATH}\MsiTran.Exe" -g {gettempdir()}\{app_name}_1033.msi {gettempdir()}\{app_name}_{lcid}.msi {gettempdir()}\{lcid}.mst' - ) # noqa: E501 # Not going to get shorter + rf'"{SDKPATH}\MsiTran.Exe" -g {gettempdir()}\{app_name}_1033.msi' + rf' {gettempdir()}\{app_name}_{lcid}.msi {gettempdir()}\{lcid}.mst' + ) os.system( rf'cscript /nologo "{SDKPATH}\WiSubStg.vbs" {filename} {gettempdir()}\{lcid}.mst {lcid}' ) @@ -294,7 +299,8 @@ if __name__ == "__main__": raise AssertionError(f"No {appname}.wixobj: candle.exe failed?") package_filename = f"{appname}_win_{appversion_nobuild()}.msi" - light_command = rf'"{WIXPATH}\light.exe" -b {DIST_DIR}\ -sacl -spdb -sw1076 {appname}.wixobj -out {package_filename}' + light_command = rf'"{WIXPATH}\light.exe" -b {DIST_DIR}\ -sacl -spdb ' \ + rf'-sw1076 {appname}.wixobj -out {package_filename}' subprocess.run(light_command, shell=True, check=True) if not exists(package_filename): diff --git a/pyproject.toml b/pyproject.toml index 16f8d6dd..e32ad617 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,9 +1,6 @@ [tool.autopep8] max_line_length = 120 -[tool.isort] -multi_line_output = 5 -line_length = 119 [tool.pytest.ini_options] testpaths = ["tests"] # Search for tests in tests/ diff --git a/requirements-dev.txt b/requirements-dev.txt index d9ad4abe..f46ff107 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -13,8 +13,6 @@ flake8-annotations-coverage==0.0.6 flake8-cognitive-complexity==0.1.0 flake8-comprehensions==3.14.0 flake8-docstrings==1.7.0 -isort==5.12.0 -flake8-isort==6.0.0 flake8-json==23.7.0 flake8-noqa==1.3.2 flake8-polyfill==1.0.2 From 58a3f4504f365bfd112fd12ad23ccd20173b0a95 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Wed, 26 Jul 2023 23:26:24 -0400 Subject: [PATCH 03/16] #2040 Type Annotations --- build.py | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/build.py b/build.py index 0f02afd3..ee5eea0e 100644 --- a/build.py +++ b/build.py @@ -23,9 +23,10 @@ from config import ( copyright, git_shorthash_from_head, ) +from typing import List, Tuple -def system_check(dist_dir): +def system_check(dist_dir: str) -> str: """Check if the system is able to build.""" if sys.version_info < (3, 11): sys.exit(f"Unexpected Python version {sys.version}") @@ -48,7 +49,9 @@ def system_check(dist_dir): return gitversion_file -def generate_data_files(app_name, gitversion_file): +def generate_data_files( + app_name: str, gitversion_file: str +) -> List[Tuple[str, List[str]]]: """Create the required datafiles to build.""" l10n_dir = "L10n" fdevids_dir = "FDevIDs" @@ -88,7 +91,7 @@ def generate_data_files(app_name, gitversion_file): return data_files -def windows_installer_display_lang(app_name, filename): +def windows_installer_display_lang(app_name: str, filename: str) -> None: """Configure the Windows Installer Display Language.""" lcids = [ int(x) @@ -111,7 +114,7 @@ def windows_installer_display_lang(app_name, filename): ) os.system( rf'"{SDKPATH}\MsiTran.Exe" -g {gettempdir()}\{app_name}_1033.msi' - rf' {gettempdir()}\{app_name}_{lcid}.msi {gettempdir()}\{lcid}.mst' + rf" {gettempdir()}\{app_name}_{lcid}.msi {gettempdir()}\{lcid}.mst" ) os.system( rf'cscript /nologo "{SDKPATH}\WiSubStg.vbs" {filename} {gettempdir()}\{lcid}.mst {lcid}' @@ -119,19 +122,20 @@ def windows_installer_display_lang(app_name, filename): if __name__ == "__main__": - DIST_DIR = "dist.win32" - GITVERSION_FILENAME = system_check(DIST_DIR) + DIST_DIR: str = "dist.win32" + GITVERSION_FILENAME: str = system_check(DIST_DIR) + # Constants - WIXPATH = rf"{os.environ['WIX']}\bin" - SDKPATH = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86" - PLUGINS = [ + WIXPATH: str = rf"{os.environ['WIX']}\bin" + SDKPATH: str = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86" + PLUGINS: List[str] = [ "plugins/coriolis.py", "plugins/eddn.py", "plugins/edsm.py", "plugins/edsy.py", "plugins/inara.py", ] - OPTIONS = { + OPTIONS: dict = { "py2exe": { "dist_dir": DIST_DIR, "optimize": 2, @@ -158,9 +162,11 @@ if __name__ == "__main__": } # Function to generate DATA_FILES list - DATA_FILES = generate_data_files(appname, GITVERSION_FILENAME) + DATA_FILES: List[Tuple[str, List[str]]] = generate_data_files( + appname, GITVERSION_FILENAME + ) - version_info = { + version_info: dict = { "description": "Downloads commodity market and other station data from the game" " Elite Dangerous for use with all popular online and offline trading tools.", "company_name": "EDCD", # Used by WinSparkle @@ -171,7 +177,7 @@ if __name__ == "__main__": "language": "English (United States)", } - windows_config = { + windows_config: dict = { "dest_base": appname, "script": "EDMarketConnector.py", "icon_resources": [(0, f"{appname}.ico")], @@ -180,7 +186,7 @@ if __name__ == "__main__": ], } - console_config = { + console_config: dict = { "dest_base": appcmdname, "script": "EDMC.py", "other_resources": [ @@ -299,8 +305,10 @@ if __name__ == "__main__": raise AssertionError(f"No {appname}.wixobj: candle.exe failed?") package_filename = f"{appname}_win_{appversion_nobuild()}.msi" - light_command = rf'"{WIXPATH}\light.exe" -b {DIST_DIR}\ -sacl -spdb ' \ - rf'-sw1076 {appname}.wixobj -out {package_filename}' + light_command = ( + rf'"{WIXPATH}\light.exe" -b {DIST_DIR}\ -sacl -spdb ' + rf"-sw1076 {appname}.wixobj -out {package_filename}" + ) subprocess.run(light_command, shell=True, check=True) if not exists(package_filename): From 8e7f7d658755ae0a706dee93dce20350911900ca Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Thu, 27 Jul 2023 11:00:51 -0400 Subject: [PATCH 04/16] #2040 Hand over WIX to InnoSetup --- .flake8 | 1 - .github/workflows/windows-build.yml | 14 +- .gitignore | 5 +- EDMC_Installer_Config.iss | 57 +++ build.py | 156 +----- docs/Releasing.md | 73 +-- docs/Translations.md | 32 -- installer.py | 42 ++ requirements-dev.txt | 4 - wix/static-EDMarketConnector.wxs | 720 ---------------------------- wix/template.wxs | 130 ----- 11 files changed, 116 insertions(+), 1118 deletions(-) create mode 100644 EDMC_Installer_Config.iss create mode 100644 installer.py delete mode 100644 wix/static-EDMarketConnector.wxs delete mode 100644 wix/template.wxs diff --git a/.flake8 b/.flake8 index 7207bf81..bdb25ca4 100644 --- a/.flake8 +++ b/.flake8 @@ -7,7 +7,6 @@ exclude = FDevIDs/ venv/ .venv/ - wix/ hotkey/darwin.py # FIXME: Check under macOS VM at some point # Show exactly where in a line the error happened diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index fc34c4bd..eaf29244 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -50,7 +50,6 @@ jobs: --exclude=pyproject.toml \ --exclude=scripts \ --exclude=tests \ - --exclude=wix \ EDMarketConnector mv ../EDMarketConnector-release-${{ needs.variables.outputs.sem_ver }}.tar.gz . @@ -92,7 +91,7 @@ jobs: # directory. # NB: If this gets too long it can cause zip 'Command Line Error', # presumably due to a Windows CL length limit. - exclusions: 'EDMarketConnector/EDMarketConnector-release-*.* EDMarketConnector/.editorconfig EDMarketConnector/.flake8 EDMarketConnector/.git* EDMarketConnector/.mypy.ini EDMarketConnector/.pre-commit-config.yaml EDMarketConnector/build.py EDMarketConnector/*.manifest EDMarketConnector/coriolis-data/ EDMarketConnector/img/ EDMarketConnector/pyproject.toml EDMarketConnector/scripts/ EDMarketConnector/tests/ EDMarketConnector/wix/' + exclusions: 'EDMarketConnector/EDMarketConnector-release-*.* EDMarketConnector/.editorconfig EDMarketConnector/.flake8 EDMarketConnector/.git* EDMarketConnector/.mypy.ini EDMarketConnector/.pre-commit-config.yaml EDMarketConnector/build.py EDMarketConnector/*.manifest EDMarketConnector/coriolis-data/ EDMarketConnector/img/ EDMarketConnector/pyproject.toml EDMarketConnector/scripts/ EDMarketConnector/tests/' - uses: actions/setup-python@v4 with: @@ -114,12 +113,17 @@ jobs: run: | python build.py + - name: InnoSetup + uses: nadeemjazmawe/inno-setup-action-cli@v6.0.5 + with: + filepath: './EDMC_Installer_Config.iss' + - name: Upload build files uses: actions/upload-artifact@v3 with: name: Built files path: | - EDMarketConnector_win_*.msi + EDMarketConnector_Installer_*.exe EDMarketConnector-release-*.zip release: @@ -136,7 +140,7 @@ jobs: path: ./ - name: Hash files - run: sha256sum EDMarketConnector_win_*.msi EDMarketConnector-release-*.{zip,tar.gz} > ./hashes.sum + run: sha256sum EDMarketConnector_Installer_*.exe EDMarketConnector-release-*.{zip,tar.gz} > ./hashes.sum - name: Create Draft Release uses: "softprops/action-gh-release@v1" @@ -146,7 +150,7 @@ jobs: prerelease: true discussion_category_name: "Announcement" files: | - ./EDMarketConnector_win_*.msi + ./EDMarketConnector_Installer_*.exe ./EDMarketConnector-release-*.zip ./EDMarketConnector-release-*.tar.gz ./hashes.sum diff --git a/.gitignore b/.gitignore index 4b13d5c3..720a84b3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,7 @@ dump *.pyo *.dll *.pdb -*.msi -*.wixobj +EDMarketConnector_Installer_*.exe appcast_win_*.xml appcast_mac_*.xml EDMarketConnector.VisualElementsManifest.xml @@ -24,5 +23,3 @@ venv/ htmlcov/ .ignored .coverage -EDMarketConnector.wxs -wix/components.wxs diff --git a/EDMC_Installer_Config.iss b/EDMC_Installer_Config.iss new file mode 100644 index 00000000..ee3556b7 --- /dev/null +++ b/EDMC_Installer_Config.iss @@ -0,0 +1,57 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +#define MyAppName "EDMarketConnector" +#define MyAppVersion "5.9.1-alpha1" +#define MyAppPublisher "EDCD" +#define MyAppURL "https://edcd.github.io/" +#define SuppURL "https://github.com/EDCD/EDMarketConnector/" +#define MyAppExeName "EDMarketConnector.exe" + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{5B5AB12D-23A6-47BB-B937-07F23FF0BF86} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#SuppURL} +AppUpdatesURL={#SuppURL} +AppCopyright=Copyright (C) 2015-2019 Jonathan Harris, 2020-2023 EDCD +AllowUNCPath=no +AllowNetworkDrive=no +DefaultDirName={autopf}\{#MyAppName} +DisableProgramGroupPage=yes +DirExistsWarning=yes +AllowNoIcons=yes +; Uncomment the following line to run in non administrative install mode (install for current user only.) +;PrivilegesRequired=lowest +OutputBaseFilename=EDMarketConnector_Installer_{#MyAppVersion} +SetupIconFile=dist.win32\EDMarketConnector.ico +Compression=lzma2/max +SolidCompression=yes +WizardStyle=modern +InfoBeforeFile=dist.win32\Changelog.md +OutputDir=. +LicenseFile=LICENSE + + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Files] +Source: "dist.win32\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion +Source: "dist.win32\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon + +[Run] +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent diff --git a/build.py b/build.py index ee5eea0e..1d2b55a7 100644 --- a/build.py +++ b/build.py @@ -1,25 +1,20 @@ """ -build.py - Build the Installer. +build.py - Build the program EXE. Copyright (c) EDCD, All Rights Reserved Licensed under the GNU General Public License. See LICENSE file. """ import os -import re import shutil -import subprocess import sys import pathlib import py2exe -from os.path import exists, join, isdir -from tempfile import gettempdir -from lxml import etree +from os.path import join, isdir from config import ( appcmdname, appname, appversion, - appversion_nobuild, copyright, git_shorthash_from_head, ) @@ -91,36 +86,6 @@ def generate_data_files( return data_files -def windows_installer_display_lang(app_name: str, filename: str) -> None: - """Configure the Windows Installer Display Language.""" - lcids = [ - int(x) - for x in re.search( # type: ignore - r'Languages\s*=\s*"(.+?)"', open(f"{app_name}.wxs", encoding="UTF8").read() - ) - .group(1) - .split(",") - ] - assert lcids[0] == 1033, f"Default language is {lcids[0]}, should be 1033 (en_US)" - shutil.copyfile(filename, join(gettempdir(), f"{app_name}_1033.msi")) - for lcid in lcids[1:]: - shutil.copyfile( - join(gettempdir(), f"{app_name}_1033.msi"), - join(gettempdir(), f"{app_name}_{lcid}.msi"), - ) - # Don't care about codepage because the displayed strings come from msiexec not our msi - os.system( - rf'cscript /nologo "{SDKPATH}\WiLangId.vbs" {gettempdir()}\{app_name}_{lcid}.msi Product {lcid}' - ) - os.system( - rf'"{SDKPATH}\MsiTran.Exe" -g {gettempdir()}\{app_name}_1033.msi' - rf" {gettempdir()}\{app_name}_{lcid}.msi {gettempdir()}\{lcid}.mst" - ) - os.system( - rf'cscript /nologo "{SDKPATH}\WiSubStg.vbs" {filename} {gettempdir()}\{lcid}.mst {lcid}' - ) - - if __name__ == "__main__": DIST_DIR: str = "dist.win32" GITVERSION_FILENAME: str = system_check(DIST_DIR) @@ -201,120 +166,3 @@ if __name__ == "__main__": data_files=DATA_FILES, options=OPTIONS, ) - - ########################################################################### - # Build installer(s) - ########################################################################### - template_file = pathlib.Path("wix/template.wxs") - components_file = pathlib.Path("wix/components.wxs") - final_wxs_file = pathlib.Path("EDMarketConnector.wxs") - - # Use heat.exe to generate the Component for all files inside dist.win32 - heat_command = [ - str(join(WIXPATH, "heat.exe")), - "dir", - str(DIST_DIR), - "-ag", - "-sfrag", - "-srid", - "-suid", - "-out", - str(components_file), - ] - subprocess.run(heat_command, check=True) - - component_tree = etree.parse(str(components_file)) - # Modify component_tree as described in the original code... - - directory_win32 = component_tree.find( - './/{*}Directory[@Id="dist.win32"][@Name="dist.win32"]' - ) - if directory_win32 is None: - raise ValueError(f'{components_file}: Expected Directory with Id="dist.win32"') - - directory_win32.set("Id", "INSTALLDIR") - directory_win32.set("Name", "$(var.PRODUCTNAME)") - - main_executable = directory_win32.find( - './/{*}Component[@Id="EDMarketConnector.exe"]' - ) - if main_executable is None: - raise ValueError( - f'{components_file}: Expected Component with Id="EDMarketConnector.exe"' - ) - - main_executable.set("Id", "MainExecutable") - main_executable.set("Guid", "{D33BB66E-9664-4AB6-A044-3004B50A09B0}") - shortcut = etree.SubElement( - main_executable, - "Shortcut", - nsmap=main_executable.nsmap, - attrib={ - "Id": "MainExeShortcut", - "Directory": "ProgramMenuFolder", - "Name": "$(var.PRODUCTLONGNAME)", - "Description": "Downloads station data from Elite: Dangerous", - "WorkingDirectory": "INSTALLDIR", - "Icon": "EDMarketConnector.exe", - "IconIndex": "0", - "Advertise": "yes", - }, - ) - # Now insert the appropriate parts as a child of the ProgramFilesFolder part - # of the template. - template_tree = etree.parse(str(template_file)) - program_files_folder = template_tree.find( - './/{*}Directory[@Id="ProgramFilesFolder"]' - ) - if program_files_folder is None: - raise ValueError( - f'{template_file}: Expected Directory with Id="ProgramFilesFolder"' - ) - - program_files_folder.insert(0, directory_win32) - # Append the Feature/ComponentRef listing to match - feature = template_tree.find('.//{*}Feature[@Id="Complete"][@Level="1"]') - if feature is None: - raise ValueError( - f'{template_file}: Expected Feature element with Id="Complete" Level="1"' - ) - # This isn't part of the components - feature.append( - etree.Element( - "ComponentRef", - attrib={"Id": "RegistryEntries"}, - nsmap=directory_win32.nsmap, - ) - ) - for c in directory_win32.findall(".//{*}Component"): - feature.append( - etree.Element( - "ComponentRef", attrib={"Id": c.get("Id")}, nsmap=directory_win32.nsmap - ) - ) - - # Insert what we now have into the template and write it out - template_tree.write( - str(final_wxs_file), encoding="utf-8", pretty_print=True, xml_declaration=True - ) - - candle_command = rf'"{WIXPATH}\candle.exe" {appname}.wxs' - subprocess.run(candle_command, shell=True, check=True) - - if not exists(f"{appname}.wixobj"): - raise AssertionError(f"No {appname}.wixobj: candle.exe failed?") - - package_filename = f"{appname}_win_{appversion_nobuild()}.msi" - light_command = ( - rf'"{WIXPATH}\light.exe" -b {DIST_DIR}\ -sacl -spdb ' - rf"-sw1076 {appname}.wixobj -out {package_filename}" - ) - subprocess.run(light_command, shell=True, check=True) - - if not exists(package_filename): - raise AssertionError(f"light.exe failed, no {package_filename}") - - # Seriously, this is how you make Windows Installer use the user's display language for its dialogs. What a crock. - # http://www.geektieguy.com/2010/03/13/create-a-multi-lingual-multi-language-msi-using-wix-and-custom-build-scripts - windows_installer_display_lang(appname, package_filename) - ########################################################################### diff --git a/docs/Releasing.md b/docs/Releasing.md index 0bd14838..4c2217bf 100644 --- a/docs/Releasing.md +++ b/docs/Releasing.md @@ -26,8 +26,6 @@ This is principally due to the Windows Registry handling in You will need several pieces of software installed, or the files from their .zip archives, in order to build the .exe and generate the .msi -1. [WiX Toolset](https://wixtoolset.org/): 3.11.2 is the most recently tested - version. 1. [WinSparkle](https://github.com/vslavik/winsparkle): `winsparkle.dll` and `winsparkle.pdb` from the release's .zip file. v0.7.0 is the most recently tested version. Copy the two files, found at `\\Release`, @@ -61,9 +59,8 @@ You will need several pieces of software installed, or the files from their If you are using different versions of any of these tools then please ensure that the paths where they're installed match the associated lines in -`build.py`. i.e. if you're using later WiX you might need to edit -the WIXPATH line, and likewise the SDKPATH line if you're using a later -Windows SDK kit. +`build.py`. i.e. if you're using later Windows SDK kit you might need to edit +the SDKPATH line. # Version Strings @@ -149,43 +146,6 @@ well then you will need to properly add it to the build process. You'll need to add it in `build.py` so that py2exe includes it in the build. Add the file to the DATA_FILES statement. -### WiX - -You will *also* need to add the file to the `EDMarketConnector.wxs` file so -that it's actually included in the installer. - -1. Location the the appropriate part of the: - - ```xml - - ``` - section and add a new sub-section: - - ```xml - - - - ``` - - Note that you only need `Id=""` if the filename itself - is not a valid Id, e.g. because it contains spaces. - - If the new file is in a new sub-directory then you'll need to add that as - well. See the `L10n` example. - -2. Now find the: - - ```xml - - ``` - - section and add an appropriate line to it. Remember to use either the - specific Id you set above or the filename (without directory) for this: - - ```xml - - ``` - # Pre-Packaging Steps Before you create a new install each time you should: @@ -284,26 +244,6 @@ INFO:runtime:Found 695 modules, 60 are missing, 0 may be missing ... Building 'dist.win32\EDMC.exe'. Building 'dist.win32\EDMarketConnector.exe'. -... -Windows Installer XML Toolset Toolset Harvester version 3.11.2.4516 -Copyright (c) .NET Foundation and contributors. All rights reserved. - -Windows Installer XML Toolset Compiler version 3.11.2.4516 -Copyright (c) .NET Foundation and contributors. All rights reserved. - -EDMarketConnector.wxs -Windows Installer XML Toolset Linker version 3.11.2.4516 -Copyright (c) .NET Foundation and contributors. All rights reserved. -... -Package language = 1033,1029,1031,1034,1035,1036,1038,1040,1041,1043,1045,1046,1049,1058,1062,2052,2070,2074,6170,1060,1053,18,0, ProductLanguage = 1029, Database codepage = 0 -MsiTran V 5.0 -Copyright (c) Microsoft Corporation. All Rights Reserved -... -DonePackage language = 1033,1029,1031,1034,1035,1036,1038,1040,1041,1043,1045,1046,1049,1058,1062,2052,2070,2074,6170,1060,1053,18,0, ProductLanguage = 0, Database codepage = 0 -MsiTran V 5.0 -Copyright (c) Microsoft Corporation. All Rights Reserved - -Done ``` **Do check the output** for things like not properly specifying extra files @@ -319,19 +259,16 @@ Check that the `EDMarketConnector.exe` in the `dist.win32` folder does run without errors. Finally, uninstall your current version of ED Market Connector and re-install -using the newly generated `EDMarketConnector_win_4.0.2.msi` file. Check the +using the newly generated `EDMarketConnector_installer_4.0.2.exe` file. Check the resulting installation does work (the installer will run the program for you). -If it doesn't then check if there are any files, particularly `.dll` or `.pyd` -files in `dist.win32` that aren't yet specified in the `EDMarketConnector.wxs` -file, i.e. they're not packaged into the installer. Update `edmarketconnector.xml` once more to set the `length=` attribute of the -enclosure to match the file size of the `EDMarketConnector_win_4.0.2.msi` file. +enclosure to match the file size of the `EDMarketConnector_win_4.0.2.exe` file. The git commit for this should end up being the release tag as below. # Distribution -Whether you built it manually or automatically you **MUST** test the `.msi` +Whether you built it manually or automatically you **MUST** test the `.exe` installer file prior to making the release live. Once that is done then for manually built installers: diff --git a/docs/Translations.md b/docs/Translations.md index 6516269d..333ce27b 100644 --- a/docs/Translations.md +++ b/docs/Translations.md @@ -101,35 +101,3 @@ To add a new language to the app: 1. Be sure to go through and Finalize any phrases that shouldn't be translated. See [Translations]() in the Wiki. Remember that until there are translations all strings will default to the English version (actually the key, which is always specified in English). - -1. You need to get the new `.strings` file added to the files the installer will install: - 1. Edit `EDMarketConnector.wxs` to add an appropriate section to the: - - `` - section, e.g.: - - - - ` - 1. You also need to add a line in the: - - - - section, e.g.: - - - Note how the `-` characters have been changed to `_`. If needs be run the build process once and look out for - lines like: - - \EDMarketConnector\EDMarketConnector.wxs(264) : error LGHT0204 : ICE21: Component: 'sr_Latn_BA.strings' does not belong to any Feature. - to see what the applicable string is. - -1. You will also want to add it to the installer's languages. This is simple enough, only requiring you add a number to an array in `EDMarketConnector.wxs`. - - 1. In `EDMarketConnector.wxs` find the line beginning `Languages="1033,`, e.g. - - Languages="1033,1029,1031,1034,1035,1036,1038,1040,1041,1043,1045,1046,1049,1058,1062,2052,2070,2074,6170,0" /> - 1. Now you'll need to consult the latest [[MS-LCID]: Windows Language Code Identifier (LCID) Reference](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f) for the correct numerical code to add to the list. - 1. Convert the hexadecimal Language ID to the equivalent in decimal. - 1. Add the new decimal value as the last but one value in the list, keeping the `,0` at the end. - 1. Update the comment on the next line to reflect what you added. diff --git a/installer.py b/installer.py new file mode 100644 index 00000000..8fd3acf3 --- /dev/null +++ b/installer.py @@ -0,0 +1,42 @@ +""" +installer.py - Build the Installer. + +Copyright (c) EDCD, All Rights Reserved +Licensed under the GNU General Public License. +See LICENSE file. +""" +import os +import subprocess + + +def run_inno_setup_installer(iss_file_path: str) -> None: + """Run the Inno installer, building the installation exe.""" + # Get the path to the Inno Setup compiler (iscc.exe) (Currently set to default path) + inno_setup_compiler_path: str = "C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe" + + # Check if the Inno Setup compiler executable exists + if not os.path.isfile(inno_setup_compiler_path): + print(f"Error: Inno Setup compiler not found at '{inno_setup_compiler_path}'.") + return + + # Check if the provided .iss file exists + if not os.path.isfile(iss_file_path): + print(f"Error: The provided .iss file '{iss_file_path}' not found.") + return + + # Run the Inno Setup compiler with the provided .iss file + try: + subprocess.run([inno_setup_compiler_path, iss_file_path], check=True) + except subprocess.CalledProcessError as e: + print( + f"Error: Inno Setup compiler returned an error (exit code {e.returncode}):" + ) + print(e.output.decode()) + except Exception as e: + print(f"Error: An unexpected error occurred: {e}") + + +if __name__ == "__main__": + # Replace 'your_iss_file.iss' with the path to your actual .iss file + iss_file_path: str = "./EDMC_Installer_Config.iss" + run_inno_setup_installer(iss_file_path) diff --git a/requirements-dev.txt b/requirements-dev.txt index f46ff107..c2ca4a6b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -34,11 +34,7 @@ pre-commit==3.3.3 grip==4.6.1 # Packaging -# Used to put together a WiX configuration from template/auto-gen -lxml==4.9.3 # We only need py2exe on windows. -# Pre-release version addressing semantic_version 2.9.0+ issues: -# py2exe==0.13.0.0; sys_platform == 'win32' # Testing diff --git a/wix/static-EDMarketConnector.wxs b/wix/static-EDMarketConnector.wxs deleted file mode 100644 index a0178579..00000000 --- a/wix/static-EDMarketConnector.wxs +++ /dev/null @@ -1,720 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WIX_UPGRADE_DETECTED AND ARPINSTALLLOCATION - - - - - WIX_UPGRADE_DETECTED AND ARPINSTALLLOCATION - - - - - - - - - NOT Installed - - - - - - - - - - NOT Installed AND LAUNCH ~= "yes" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/wix/template.wxs b/wix/template.wxs deleted file mode 100644 index 82da0c4e..00000000 --- a/wix/template.wxs +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WIX_UPGRADE_DETECTED AND ARPINSTALLLOCATION - - - - - WIX_UPGRADE_DETECTED AND ARPINSTALLLOCATION - - - - - - - - - NOT Installed - - - - - - - - - - NOT Installed AND LAUNCH ~= "yes" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From dd1442f37b9c2048e09f1551e5ae8ad313fe902f Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Thu, 27 Jul 2023 11:14:21 -0400 Subject: [PATCH 05/16] #2040 Remove Unused Code --- EDMC_Installer_Config.iss | 3 --- build.py | 2 -- 2 files changed, 5 deletions(-) diff --git a/EDMC_Installer_Config.iss b/EDMC_Installer_Config.iss index ee3556b7..e08c50d6 100644 --- a/EDMC_Installer_Config.iss +++ b/EDMC_Installer_Config.iss @@ -1,6 +1,3 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - #define MyAppName "EDMarketConnector" #define MyAppVersion "5.9.1-alpha1" #define MyAppPublisher "EDCD" diff --git a/build.py b/build.py index 1d2b55a7..b2af00ba 100644 --- a/build.py +++ b/build.py @@ -91,8 +91,6 @@ if __name__ == "__main__": GITVERSION_FILENAME: str = system_check(DIST_DIR) # Constants - WIXPATH: str = rf"{os.environ['WIX']}\bin" - SDKPATH: str = r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86" PLUGINS: List[str] = [ "plugins/coriolis.py", "plugins/eddn.py", From 6f91e6ce4ea08a9ccf5084c64e7ef5dfaec881e3 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Thu, 27 Jul 2023 14:14:36 -0400 Subject: [PATCH 06/16] #2040 Integrate Builder and Installer --- EDMC_Installer_Config.iss | 1 + build.py | 33 +++++++++++++++++++-------------- installer.py | 16 +++++++++------- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/EDMC_Installer_Config.iss b/EDMC_Installer_Config.iss index e08c50d6..28c7ef40 100644 --- a/EDMC_Installer_Config.iss +++ b/EDMC_Installer_Config.iss @@ -33,6 +33,7 @@ WizardStyle=modern InfoBeforeFile=dist.win32\Changelog.md OutputDir=. LicenseFile=LICENSE +LanguageDetectionMethod=uilanguage [Languages] diff --git a/build.py b/build.py index b2af00ba..729c0754 100644 --- a/build.py +++ b/build.py @@ -9,8 +9,9 @@ import os import shutil import sys import pathlib -import py2exe +from typing import List, Tuple from os.path import join, isdir +import py2exe from config import ( appcmdname, appname, @@ -18,7 +19,6 @@ from config import ( copyright, git_shorthash_from_head, ) -from typing import List, Tuple def system_check(dist_dir: str) -> str: @@ -45,7 +45,7 @@ def system_check(dist_dir: str) -> str: def generate_data_files( - app_name: str, gitversion_file: str + app_name: str, gitversion_file: str, plugins: List[str] ) -> List[Tuple[str, List[str]]]: """Create the required datafiles to build.""" l10n_dir = "L10n" @@ -81,26 +81,27 @@ def generate_data_files( join(fdevids_dir, "rare_commodity.csv"), ], ), - ("plugins", PLUGINS), + ("plugins", plugins), ] return data_files -if __name__ == "__main__": - DIST_DIR: str = "dist.win32" - GITVERSION_FILENAME: str = system_check(DIST_DIR) +def build() -> None: + """Build EDMarketConnector using Py2Exe.""" + dist_dir: str = "dist.win32" + gitversion_filename: str = system_check(dist_dir) # Constants - PLUGINS: List[str] = [ + plugins: List[str] = [ "plugins/coriolis.py", "plugins/eddn.py", "plugins/edsm.py", "plugins/edsy.py", "plugins/inara.py", ] - OPTIONS: dict = { + options: dict = { "py2exe": { - "dist_dir": DIST_DIR, + "dist_dir": dist_dir, "optimize": 2, "packages": [ "asyncio", @@ -125,8 +126,8 @@ if __name__ == "__main__": } # Function to generate DATA_FILES list - DATA_FILES: List[Tuple[str, List[str]]] = generate_data_files( - appname, GITVERSION_FILENAME + data_files: List[Tuple[str, List[str]]] = generate_data_files( + appname, gitversion_filename, plugins ) version_info: dict = { @@ -161,6 +162,10 @@ if __name__ == "__main__": version_info=version_info, windows=[windows_config], console=[console_config], - data_files=DATA_FILES, - options=OPTIONS, + data_files=data_files, + options=options, ) + + +if __name__ == "__main__": + build() diff --git a/installer.py b/installer.py index 8fd3acf3..659286ac 100644 --- a/installer.py +++ b/installer.py @@ -7,9 +7,10 @@ See LICENSE file. """ import os import subprocess +from build import build -def run_inno_setup_installer(iss_file_path: str) -> None: +def run_inno_setup_installer(iss_path: str) -> None: """Run the Inno installer, building the installation exe.""" # Get the path to the Inno Setup compiler (iscc.exe) (Currently set to default path) inno_setup_compiler_path: str = "C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe" @@ -21,22 +22,23 @@ def run_inno_setup_installer(iss_file_path: str) -> None: # Check if the provided .iss file exists if not os.path.isfile(iss_file_path): - print(f"Error: The provided .iss file '{iss_file_path}' not found.") + print(f"Error: The provided .iss file '{iss_path}' not found.") return # Run the Inno Setup compiler with the provided .iss file try: subprocess.run([inno_setup_compiler_path, iss_file_path], check=True) - except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError as err: print( - f"Error: Inno Setup compiler returned an error (exit code {e.returncode}):" + f"Error: Inno Setup compiler returned an error (exit code {err.returncode}):" ) - print(e.output.decode()) - except Exception as e: - print(f"Error: An unexpected error occurred: {e}") + print(err.output.decode()) + except Exception as err: + print(f"Error: An unexpected error occurred: {err}") if __name__ == "__main__": + build() # Replace 'your_iss_file.iss' with the path to your actual .iss file iss_file_path: str = "./EDMC_Installer_Config.iss" run_inno_setup_installer(iss_file_path) From ccf8888e74e4826c5295b0cf0f54060f10a79440 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Thu, 27 Jul 2023 16:51:22 -0400 Subject: [PATCH 07/16] #2040 Revert Anomalous Changelog Change --- ChangeLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 5dca72b3..08f08954 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -611,7 +611,7 @@ Developers * We now build using the new, `setuptools` mediated py2exe `freeze()` method, so we're in the clear for when `distutils` is removed in Python 3.12. * The old `setup.py` file, along with associated `py2exe.cmd` have been removed - in favour of the new `build.py` file. Documentation updated. + in favour of the new `Build-exe-and-msi.py` file. Documentation updated. --- From bec550a5e0405bbcb21ac21b9834c557d8d0a560 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Sat, 29 Jul 2023 14:53:02 -0400 Subject: [PATCH 08/16] #2040 Revert GITIGNORE Co-authored-by: Phoebe <40956085+C1701D@users.noreply.github.com> --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 720a84b3..deba150e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ dump *.pyo *.dll *.pdb +*.msi +*.wixobj EDMarketConnector_Installer_*.exe appcast_win_*.xml appcast_mac_*.xml From d0b0cd7c591a0df49bc93c72917d10941218887c Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Sat, 29 Jul 2023 14:54:25 -0400 Subject: [PATCH 09/16] #2040 Add more to GITIGNORE Co-authored-by: Phoebe <40956085+C1701D@users.noreply.github.com> --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index deba150e..b19207d9 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ venv/ htmlcov/ .ignored .coverage +EDMarketConnector.wxs +wix/components.wxs From 966247370600f370ae0815b68d3a07fa1bd8d56d Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Sat, 29 Jul 2023 18:20:16 -0400 Subject: [PATCH 10/16] #2040 Update docs/Releasing.md Co-authored-by: Phoebe <40956085+C1701D@users.noreply.github.com> --- docs/Releasing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Releasing.md b/docs/Releasing.md index 4c2217bf..f4c71483 100644 --- a/docs/Releasing.md +++ b/docs/Releasing.md @@ -263,7 +263,7 @@ using the newly generated `EDMarketConnector_installer_4.0.2.exe` file. Check t resulting installation does work (the installer will run the program for you). Update `edmarketconnector.xml` once more to set the `length=` attribute of the -enclosure to match the file size of the `EDMarketConnector_win_4.0.2.exe` file. +enclosure to match the file size of the `EDMarketConnector_installer_4.0.2.exe` file. The git commit for this should end up being the release tag as below. # Distribution From 89101fc73cc59c300353e5bb6ccb534871c27a70 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Mon, 31 Jul 2023 17:44:14 -0400 Subject: [PATCH 11/16] #2041 Uninstall Prior Versions of EDMC Removes installed versions of EDMC which use the old WiX build framework --- EDMC_Installer_Config.iss | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/EDMC_Installer_Config.iss b/EDMC_Installer_Config.iss index 28c7ef40..0a34f1ff 100644 --- a/EDMC_Installer_Config.iss +++ b/EDMC_Installer_Config.iss @@ -1,14 +1,12 @@ #define MyAppName "EDMarketConnector" -#define MyAppVersion "5.9.1-alpha1" +#define MyAppVersion "5.9.1-alpha2" #define MyAppPublisher "EDCD" #define MyAppURL "https://edcd.github.io/" #define SuppURL "https://github.com/EDCD/EDMarketConnector/" #define MyAppExeName "EDMarketConnector.exe" [Setup] -; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. -; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) -AppId={{5B5AB12D-23A6-47BB-B937-07F23FF0BF86} +AppId={{5E9AD4D3-0365-41D5-9586-9368745DD109} AppName={#MyAppName} AppVersion={#MyAppVersion} AppVerName={#MyAppName} {#MyAppVersion} @@ -23,8 +21,6 @@ DefaultDirName={autopf}\{#MyAppName} DisableProgramGroupPage=yes DirExistsWarning=yes AllowNoIcons=yes -; Uncomment the following line to run in non administrative install mode (install for current user only.) -;PrivilegesRequired=lowest OutputBaseFilename=EDMarketConnector_Installer_{#MyAppVersion} SetupIconFile=dist.win32\EDMarketConnector.ico Compression=lzma2/max @@ -45,7 +41,6 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{ [Files] Source: "dist.win32\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion Source: "dist.win32\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs -; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Icons] Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" @@ -53,3 +48,19 @@ Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: de [Run] Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent + +;Check if a WiX-based installation exists. If so, kill it with fire. +[Code] +procedure CurStepChanged(CurStep: TSetupStep); +var + ResultCode: Integer; + Uninstall: String; +begin + if (CurStep = ssInstall) then begin + if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{5E9AD4D3-0365-41D5-9586-9368745DD109}', 'UninstallString', Uninstall) then begin + MsgBox('Warning: an old version of EDMC is installed! Now the old one will be removed and installed the new!', mbInformation, MB_OK); + Uninstall := '/x {5E9AD4D3-0365-41D5-9586-9368745DD109}'; + Exec('MsiExec.exe', Uninstall, '', SW_SHOW, ewWaitUntilTerminated, ResultCode); + end; + end; +end; From 45804dafc179af8c7aedd62284cf100482dc09aa Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Tue, 1 Aug 2023 16:30:59 -0400 Subject: [PATCH 12/16] #2040 Dynamically Build iss File --- .gitignore | 1 + ...ig.iss => EDMC_Installer_Config_template.txt | 5 +++-- installer.py | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) rename EDMC_Installer_Config.iss => EDMC_Installer_Config_template.txt (95%) diff --git a/.gitignore b/.gitignore index b19207d9..35fa7565 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ appcast_win_*.xml appcast_mac_*.xml EDMarketConnector.VisualElementsManifest.xml *.zip +EDMC_Installer_Config.iss .idea .vscode diff --git a/EDMC_Installer_Config.iss b/EDMC_Installer_Config_template.txt similarity index 95% rename from EDMC_Installer_Config.iss rename to EDMC_Installer_Config_template.txt index 0a34f1ff..b7cb4052 100644 --- a/EDMC_Installer_Config.iss +++ b/EDMC_Installer_Config_template.txt @@ -1,5 +1,5 @@ #define MyAppName "EDMarketConnector" -#define MyAppVersion "5.9.1-alpha2" +#define MyAppVersion "$appver" #define MyAppPublisher "EDCD" #define MyAppURL "https://edcd.github.io/" #define SuppURL "https://github.com/EDCD/EDMarketConnector/" @@ -29,7 +29,8 @@ WizardStyle=modern InfoBeforeFile=dist.win32\Changelog.md OutputDir=. LicenseFile=LICENSE -LanguageDetectionMethod=uilanguage +AlwaysShowDirOnReadyPage=yes +UninstallDisplayIcon={app}\{#MyAppExeName} [Languages] diff --git a/installer.py b/installer.py index 659286ac..a96a8f08 100644 --- a/installer.py +++ b/installer.py @@ -7,7 +7,19 @@ See LICENSE file. """ import os import subprocess +from string import Template from build import build +from config import _static_appversion as appversion + + +def iss_build(template_path: str, output_file: str) -> None: + """Build the .iss file needed for building the installer EXE.""" + sub_vals = {"appver": appversion} + with open(template_path, encoding="UTF8") as template_file: + src = Template(template_file.read()) + newfile = src.substitute(sub_vals) + with open(output_file, "w", encoding="UTF8") as new_file: + new_file.write(newfile) def run_inno_setup_installer(iss_path: str) -> None: @@ -39,6 +51,9 @@ def run_inno_setup_installer(iss_path: str) -> None: if __name__ == "__main__": build() - # Replace 'your_iss_file.iss' with the path to your actual .iss file + # Add the ISS Template File + iss_template_path: str = "./EDMC_Installer_Config_template.txt" iss_file_path: str = "./EDMC_Installer_Config.iss" + # Build the ISS file + iss_build(iss_template_path, iss_file_path) run_inno_setup_installer(iss_file_path) From 0d3f3f4a52ef9b21f6d50920ea40de3d439cd4c9 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Wed, 2 Aug 2023 14:10:49 -0400 Subject: [PATCH 13/16] #2040 Move Template to Resource Dir --- installer.py | 2 +- .../EDMC_Installer_Config_template.txt | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename EDMC_Installer_Config_template.txt => resources/EDMC_Installer_Config_template.txt (100%) diff --git a/installer.py b/installer.py index a96a8f08..3405557f 100644 --- a/installer.py +++ b/installer.py @@ -52,7 +52,7 @@ def run_inno_setup_installer(iss_path: str) -> None: if __name__ == "__main__": build() # Add the ISS Template File - iss_template_path: str = "./EDMC_Installer_Config_template.txt" + iss_template_path: str = "./resources/EDMC_Installer_Config_template.txt" iss_file_path: str = "./EDMC_Installer_Config.iss" # Build the ISS file iss_build(iss_template_path, iss_file_path) diff --git a/EDMC_Installer_Config_template.txt b/resources/EDMC_Installer_Config_template.txt similarity index 100% rename from EDMC_Installer_Config_template.txt rename to resources/EDMC_Installer_Config_template.txt From 376ac667c9b41b2e800c6a93c5c754823b779436 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Wed, 2 Aug 2023 14:32:30 -0400 Subject: [PATCH 14/16] #2040 Move ISS File Build to Builder --- build.py | 17 +++++++++++++++++ installer.py | 14 -------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/build.py b/build.py index 729c0754..e48f299c 100644 --- a/build.py +++ b/build.py @@ -10,6 +10,7 @@ import shutil import sys import pathlib from typing import List, Tuple +from string import Template from os.path import join, isdir import py2exe from config import ( @@ -18,9 +19,20 @@ from config import ( appversion, copyright, git_shorthash_from_head, + _static_appversion, ) +def iss_build(template_path: str, output_file: str) -> None: + """Build the .iss file needed for building the installer EXE.""" + sub_vals = {"appver": _static_appversion} + with open(template_path, encoding="UTF8") as template_file: + src = Template(template_file.read()) + newfile = src.substitute(sub_vals) + with open(output_file, "w", encoding="UTF8") as new_file: + new_file.write(newfile) + + def system_check(dist_dir: str) -> str: """Check if the system is able to build.""" if sys.version_info < (3, 11): @@ -166,6 +178,11 @@ def build() -> None: options=options, ) + iss_template_path: str = "./resources/EDMC_Installer_Config_template.txt" + iss_file_path: str = "./EDMC_Installer_Config.iss" + # Build the ISS file + iss_build(iss_template_path, iss_file_path) + if __name__ == "__main__": build() diff --git a/installer.py b/installer.py index 3405557f..754b3373 100644 --- a/installer.py +++ b/installer.py @@ -7,19 +7,7 @@ See LICENSE file. """ import os import subprocess -from string import Template from build import build -from config import _static_appversion as appversion - - -def iss_build(template_path: str, output_file: str) -> None: - """Build the .iss file needed for building the installer EXE.""" - sub_vals = {"appver": appversion} - with open(template_path, encoding="UTF8") as template_file: - src = Template(template_file.read()) - newfile = src.substitute(sub_vals) - with open(output_file, "w", encoding="UTF8") as new_file: - new_file.write(newfile) def run_inno_setup_installer(iss_path: str) -> None: @@ -52,8 +40,6 @@ def run_inno_setup_installer(iss_path: str) -> None: if __name__ == "__main__": build() # Add the ISS Template File - iss_template_path: str = "./resources/EDMC_Installer_Config_template.txt" iss_file_path: str = "./EDMC_Installer_Config.iss" # Build the ISS file - iss_build(iss_template_path, iss_file_path) run_inno_setup_installer(iss_file_path) From f47f011f4b6183117938d0f0b1ff4c4d6c75ee98 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Wed, 2 Aug 2023 14:33:29 -0400 Subject: [PATCH 15/16] #2040 Update Submodules --- FDevIDs | 2 +- coriolis-data | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FDevIDs b/FDevIDs index 2aaf3cb0..e8dbd99d 160000 --- a/FDevIDs +++ b/FDevIDs @@ -1 +1 @@ -Subproject commit 2aaf3cb023fc8c06e092efd0b81315c167f455f5 +Subproject commit e8dbd99ddc00beabac140bf26f423a353bc98c5d diff --git a/coriolis-data b/coriolis-data index 566d768a..05b16a4c 160000 --- a/coriolis-data +++ b/coriolis-data @@ -1 +1 @@ -Subproject commit 566d768a711362c423748963c5f56d3bea68e6a5 +Subproject commit 05b16a4c716980ea95a46d29205f7d3b1f957fb4 From 8c2cbbc28f14e79ac47325867656ee90a2e32482 Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Wed, 2 Aug 2023 14:38:05 -0400 Subject: [PATCH 16/16] #2040 Update Uninstaller Logic Message --- resources/EDMC_Installer_Config_template.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/EDMC_Installer_Config_template.txt b/resources/EDMC_Installer_Config_template.txt index b7cb4052..ff00f4cf 100644 --- a/resources/EDMC_Installer_Config_template.txt +++ b/resources/EDMC_Installer_Config_template.txt @@ -59,7 +59,7 @@ var begin if (CurStep = ssInstall) then begin if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{5E9AD4D3-0365-41D5-9586-9368745DD109}', 'UninstallString', Uninstall) then begin - MsgBox('Warning: an old version of EDMC is installed! Now the old one will be removed and installed the new!', mbInformation, MB_OK); + MsgBox('Warning: an old version of EDMC is installed! Please close EDMC while we remove the old version!', mbInformation, MB_OK); Uninstall := '/x {5E9AD4D3-0365-41D5-9586-9368745DD109}'; Exec('MsiExec.exe', Uninstall, '', SW_SHOW, ewWaitUntilTerminated, ResultCode); end;