1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-05-31 07:39:44 +03:00

Merge pull request #1368 from EDCD/enhancement/1367/installer-all-files

Automate always including **all** files that py2exe places in `dist.win32`
This commit is contained in:
Athanasius 2021-12-16 13:05:40 +00:00 committed by GitHub
commit aedf0bf800
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 990 additions and 749 deletions

2
.gitignore vendored
View File

@ -23,3 +23,5 @@ venv
htmlcov/
.ignored
.coverage
EDMarketConnector.wxs
wix/components.wxs

View File

@ -33,7 +33,7 @@ appcmdname = 'EDMC'
# <https://semver.org/#semantic-versioning-specification-semver>
# 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'

50
l10n.py
View File

@ -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: <n/a> | 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

View File

@ -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'

110
setup.py
View File

@ -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:
#
# <Directory Id="dist.win32" Name="dist.win32">
#
# to:
#
# <Directory Id="INSTALLDIR" Name="$(var.PRODUCTNAME)">
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:
#
# <Component Id="EDMarketConnector.exe" Guid="*">
# <File Id="EDMarketConnector.exe" KeyPath="yes" Source="SourceDir\EDMarketConnector.exe" />
# </Component>
#
# to:
#
# <Component Id="MainExecutable" Guid="{D33BB66E-9664-4AB6-A044-3004B50A09B0}">
# <File Id="EDMarketConnector.exe" KeyPath="yes" Source="SourceDir\EDMarketConnector.exe" />
# <Shortcut Id="MainExeShortcut" Directory="ProgramMenuFolder" Name="$(var.PRODUCTLONGNAME)"
# Description="Downloads station data from Elite: Dangerous" WorkingDirectory="INSTALLDIR"
# Icon="EDMarketConnector.exe" IconIndex="0" Advertise="yes" />
# </Component>
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}')

File diff suppressed because it is too large Load Diff

125
wix/template.wxs Normal file
View File

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<?define PRODUCTNAME = "EDMarketConnector"?>
<?define PRODUCTLONGNAME = "Elite Dangerous Market Connector"?>
<?define PRODUCTVERSION = "!(bind.fileVersion.EDMarketConnector.exe)" ?>
<?define UPGRADECODE = "9df571ae-d56d-46e6-af79-4e72ad54efe6" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
Name="$(var.PRODUCTLONGNAME)"
Version="$(var.PRODUCTVERSION)"
UpgradeCode="$(var.UPGRADECODE)"
Language="!(bind.fileLanguage.EDMarketConnector.exe)"
Manufacturer="EDCD">
<Package Id="*" Keywords="Installer"
InstallScope="perMachine"
Description="$(var.PRODUCTLONGNAME) installer"
InstallerVersion="300" Compressed="yes"
Platform="x86"
Languages="1033,1029,1031,1034,1035,1036,1038,1040,1041,1043,1045,1046,1049,1058,1062,2052,2070,2074,6170,1060,1053,18,0" />
<!-- en cs, de es fi fr hu it ja nl pl pt-BR ru uk lv zh-CN pt-PT sr-Latn sr-Latn-BA sl sv-SE ko neutral -->
<!-- https://msdn.microsoft.com/en-gb/goglobal/bb964664.aspx -->
<!-- Always reinstall since patching is problematic -->
<!-- http://www.joyofsetup.com/2010/01/16/major-upgrades-now-easier-than-ever/ -->
<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
<Icon Id="EDMarketConnector.exe" SourceFile="EDMarketConnector.ico"/>
<!-- For Add/Remove programs -->
<Property Id="ARPPRODUCTICON" Value="EDMarketConnector.exe" />
<Property Id="ARPNOMODIFY" Value="yes" Secure="yes" /> <!-- Remove modify - also set by WixUI_Minimal -->
<Property Id="ARPHELPLINK" Value="https://github.com/EDCD/EDMarketConnector/wiki" />
<!-- Set INSTALLDIR from ARPINSTALLLOCATION if replacing/upgrading -->
<!-- https://wyrdfish.wordpress.com/2012/07/20/msi-writing-guidelines-this-may-be-out-of-date/ -->
<Property Id="ARPINSTALLLOCATION">
<RegistrySearch Id="GetARPINSTALLLOCATION"
Root="HKLM"
Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[WIX_UPGRADE_DETECTED]"
Name="InstallLocation"
Type="raw" />
</Property>
<CustomAction Id="SetINSTALLDIR" Property="INSTALLDIR" Value="[ARPINSTALLLOCATION]" />
<InstallUISequence>
<Custom Action="SetINSTALLDIR" After="AppSearch">
WIX_UPGRADE_DETECTED AND ARPINSTALLLOCATION
</Custom>
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="SetINSTALLDIR" After="AppSearch">
WIX_UPGRADE_DETECTED AND ARPINSTALLLOCATION
</Custom>
</InstallExecuteSequence>
<!-- Set ARPINSTALLLOCATION from INSTALLDIR if new install -->
<!-- http://blogs.technet.com/b/alexshev/archive/2008/02/09/from-msi-to-wix-part-2.aspx -->
<CustomAction Id="SetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
<InstallExecuteSequence>
<Custom Action="SetARPINSTALLLOCATION" After="InstallValidate">
NOT Installed
</Custom>
</InstallExecuteSequence>
<!-- Launch app after upgrade -->
<Property Id="LAUNCH" Value="yes" />
<CustomAction Id="DoLaunch"
Directory="INSTALLDIR"
ExeCommand='"[INSTALLDIR]EDMarketConnector.exe"'
Return="asyncNoWait"
Execute="deferred"
Impersonate="yes"
/>
<InstallExecuteSequence>
<!-- http://alekdavis.blogspot.co.uk/2013/05/wix-woes-what-is-your-installer-doing.html -->
<Custom Action="DoLaunch" Before="InstallFinalize">
NOT Installed AND LAUNCH ~= "yes"
</Custom>
</InstallExecuteSequence>
<Directory Id="TARGETDIR" Name="SourceDir">
<!-- http://wixtoolset.org/documentation/manual/v3/howtos/files_and_registry/write_a_registry_entry.html -->
<Component Id="RegistryEntries" Guid="*">
<RegistryKey Root="HKCR" Key="edmc">
<RegistryValue Type="string" Value="$(var.PRODUCTLONGNAME)"/>
<RegistryValue Type="string" Name="URL Protocol" Value=""/>
<RegistryKey Key="DefaultIcon">
<RegistryValue Type="string" Value="[INSTALLDIR]EDMarketConnector.exe,0"/>
</RegistryKey>
<RegistryKey Key="shell">
<RegistryKey Key="open">
<RegistryKey Key="command">
<RegistryValue Type="string" Value='"[INSTALLDIR]EDMarketConnector.exe" "%1"'/>
</RegistryKey>
<RegistryKey Key="ddeexec">
<RegistryValue Type="string" Value='Open("%1")'/>
</RegistryKey>
</RegistryKey>
</RegistryKey>
</RegistryKey>
</Component>
<!-- Contents auto-generated with heat.exe, see setup.py -->
<Directory Id="ProgramFilesFolder">
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
</Directory>
</Directory>
<!-- Contents auto-generated in setup.py -->
<Feature Id='Complete' Level='1'>
</Feature>
</Product>
</Wix>
<!-- Local Variables: -->
<!-- tab-width: 4 -->
<!-- End: -->