diff --git a/.gitignore b/.gitignore index 7474987d..9bea3d5a 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ venv htmlcov/ .ignored .coverage +EDMarketConnector.wxs +wix/components.wxs diff --git a/config.py b/config.py index 7df3e218..ff0b7fed 100644 --- a/config.py +++ b/config.py @@ -33,7 +33,7 @@ appcmdname = 'EDMC' # # Major.Minor.Patch(-prerelease)(+buildmetadata) # NB: Do *not* import this, use the functions appversion() and appversion_nobuild() -_static_appversion = '5.3.0-beta1' +_static_appversion = '5.3.0-beta2' _cached_version: Optional[semantic_version.Version] = None copyright = '© 2015-2019 Jonathan Harris, 2020-2021 EDCD' diff --git a/l10n.py b/l10n.py index 7ffed54b..b77c07de 100755 --- a/l10n.py +++ b/l10n.py @@ -309,7 +309,7 @@ class _Locale: return None - def preferred_languages(self) -> Iterable[str]: + def preferred_languages(self) -> Iterable[str]: # noqa: CCR001 """ Return a list of preferred language codes. @@ -320,34 +320,46 @@ class _Locale: :return: The preferred language list """ + languages: Iterable[str] if platform == 'darwin': - return NSLocale.preferredLanguages() + languages = NSLocale.preferredLanguages() elif platform != 'win32': # POSIX lang = locale.getlocale()[0] - return lang and [lang.replace('_', '-')] or [] + languages = lang and [lang.replace('_', '-')] or [] - def wszarray_to_list(array): - offset = 0 - while offset < len(array): - sz = ctypes.wstring_at(ctypes.addressof(array) + offset*2) - if sz: - yield sz - offset += len(sz)+1 + else: + def wszarray_to_list(array): + offset = 0 + while offset < len(array): + sz = ctypes.wstring_at(ctypes.addressof(array) + offset*2) + if sz: + yield sz + offset += len(sz)+1 - else: - break + else: + break - num = ctypes.c_ulong() - size = ctypes.c_ulong(0) - if GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, ctypes.byref(num), None, ctypes.byref(size)) and size.value: - buf = ctypes.create_unicode_buffer(size.value) + num = ctypes.c_ulong() + size = ctypes.c_ulong(0) + languages = [] + if GetUserPreferredUILanguages( + MUI_LANGUAGE_NAME, ctypes.byref(num), None, ctypes.byref(size) + ) and size.value: + buf = ctypes.create_unicode_buffer(size.value) - if GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, ctypes.byref(num), ctypes.byref(buf), ctypes.byref(size)): - return wszarray_to_list(buf) + if GetUserPreferredUILanguages( + MUI_LANGUAGE_NAME, ctypes.byref(num), ctypes.byref(buf), ctypes.byref(size) + ): + languages = wszarray_to_list(buf) - return [] + # HACK: | 2021-12-11: OneSky calls "Chinese Simplified" "zh-Hans" + # in the name of the file, but that will be zh-CN in terms of + # locale. So map zh-CN -> zh-Hans + languages = ['zh-Hans' if lang == 'zh-CN' else lang for lang in languages] + + return languages # singletons diff --git a/requirements-dev.txt b/requirements-dev.txt index afc11caf..221b5997 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -27,6 +27,8 @@ autopep8==1.6.0 grip==4.5.2 # Packaging +# Used to put together a WiX configuration from template/auto-gen +lxml==4.6.4 # We only need py2exe on windows. py2exe==0.11.0.1; sys_platform == 'win32' diff --git a/setup.py b/setup.py index 52be2c78..8bb8fb30 100755 --- a/setup.py +++ b/setup.py @@ -9,6 +9,7 @@ Script to build to .exe and .msi package. import codecs import os +import pathlib import platform import re import shutil @@ -18,6 +19,8 @@ from os.path import exists, isdir, join from tempfile import gettempdir from typing import Any, Generator, Set +from lxml import etree + from config import ( appcmdname, applongname, appname, appversion, appversion_nobuild, copyright, git_shorthash_from_head, update_feed, update_interval @@ -209,7 +212,7 @@ elif sys.platform == 'win32': 'WinSparkle.dll', 'WinSparkle.pdb', # For debugging - don't include in package 'EUROCAPS.TTF', - 'Changelog.md', + 'ChangeLog.md', 'commodity.csv', 'rare_commodity.csv', 'snd_good.wav', @@ -283,13 +286,110 @@ if sys.platform == 'darwin': os.system(f'cd {dist_dir}; ditto -ck --keepParent --sequesterRsrc {appname}.app ../{package_filename}; cd ..') elif sys.platform == 'win32': - os.system(rf'"{WIXPATH}\candle.exe" -out {dist_dir}\ {appname}.wxs') + template_file = pathlib.Path('wix/template.wxs') + components_file = pathlib.Path('wix/components.wxs') + final_wxs_file = pathlib.Path('EDMarketConnector.wxs') - if not exists(f'{dist_dir}/{appname}.wixobj'): - raise AssertionError(f'No {dist_dir}/{appname}.wixobj: candle.exe failed?') + # 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" -sacl -spdb -sw1076 {dist_dir}\{appname}.wixobj -out {package_filename}') + 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}') diff --git a/EDMarketConnector.wxs b/wix/static-EDMarketConnector.wxs similarity index 97% rename from EDMarketConnector.wxs rename to wix/static-EDMarketConnector.wxs index 621aafa2..d19dfa67 100644 --- a/EDMarketConnector.wxs +++ b/wix/static-EDMarketConnector.wxs @@ -1,724 +1,724 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WIX_UPGRADE_DETECTED AND ARPINSTALLLOCATION - - - - - WIX_UPGRADE_DETECTED AND ARPINSTALLLOCATION - - - - - - - - - NOT Installed - - - - - - - - - - NOT Installed AND LAUNCH ~= "yes" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 new file mode 100644 index 00000000..a15e0fc1 --- /dev/null +++ b/wix/template.wxs @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WIX_UPGRADE_DETECTED AND ARPINSTALLLOCATION + + + + + WIX_UPGRADE_DETECTED AND ARPINSTALLLOCATION + + + + + + + + + NOT Installed + + + + + + + + + + NOT Installed AND LAUNCH ~= "yes" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +