1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-13 07:47:14 +03:00

build: Remove old setup.py and py2exe.cmd

Use the git, Ath.
This commit is contained in:
Athanasius 2022-09-24 10:39:38 +01:00
parent a3198c5e36
commit 9347f12723
No known key found for this signature in database
GPG Key ID: 8C392035DD80FD62
2 changed files with 0 additions and 430 deletions

View File

@ -1,2 +0,0 @@
@REM http://www.py2exe.org/index.cgi/OptimizedBytecode
"C:\Program Files (x86)\Python37-32\python.exe" -OO setup.py py2exe

428
setup.py
View File

@ -1,428 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script to build to .exe and .msi package.
.exe build is via py2exe on win32.
.msi packaging utilises Windows SDK.
"""
import codecs
import os
import pathlib
import platform
import re
import shutil
import sys
from distutils.core import setup
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
)
from constants import GITVERSION_FILE
if sys.version_info[0:2] != (3, 10):
raise AssertionError(f'Unexpected python version {sys.version}')
###########################################################################
# 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}')
###########################################################################
if sys.platform == 'win32':
assert platform.architecture()[0] == '32bit', 'Assumes a Python built for 32bit'
import py2exe # noqa: F401 # Yes, this *is* used
dist_dir = 'dist.win32'
elif sys.platform == 'darwin':
dist_dir = 'dist.macosx'
else:
assert False, f'Unsupported platform {sys.platform}'
# Split version, as py2exe wants the 'base' for version
semver = appversion()
appversion_str = str(semver)
base_appversion = str(semver.truncate('patch'))
if dist_dir and len(dist_dir) > 1 and isdir(dist_dir):
shutil.rmtree(dist_dir)
# "Developer ID Application" name for signing
macdeveloperid = None
# 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'
# OSX paths
SPARKLE = '/Library/Frameworks/Sparkle.framework'
if sys.platform == 'darwin':
# Patch py2app recipe enumerator to skip the sip recipe since it's too
# enthusiastic - we'll list additional Qt modules explicitly
import py2app.build_app
from py2app import recipes
# NB: 'Any' is because I don't have MacOS docs
def iter_recipes(module=recipes) -> Generator[str, Any]:
"""Enumerate recipes via alternate method."""
for name in dir(module):
if name.startswith('_') or name == 'sip':
continue
check = getattr(getattr(module, name), 'check', None)
if check is not None:
yield (name, check)
py2app.build_app.iterRecipes = iter_recipes
APP = 'EDMarketConnector.py'
APPCMD = 'EDMC.py'
PLUGINS = [
'plugins/coriolis.py',
'plugins/eddb.py',
'plugins/eddn.py',
'plugins/edsm.py',
'plugins/edsy.py',
'plugins/inara.py',
]
if sys.platform == 'darwin':
def get_cfbundle_localizations() -> Set:
"""
Build a set of the localisation files.
See https://github.com/sparkle-project/Sparkle/issues/238
"""
return sorted(
(
[x[:-len('.lproj')] for x in os.listdir(join(SPARKLE, 'Resources')) if x.endswith('.lproj')]
) | (
[x[:-len('.strings')] for x in os.listdir('L10n') if x.endswith('.strings')]
)
)
OPTIONS = {
'py2app': {
'dist_dir': dist_dir,
'optimize': 2,
'packages': [
'requests',
'sqlite3', # Included for plugins
],
'includes': [
'shutil', # Included for plugins
'zipfile', # Included for plugins
],
'frameworks': [
'Sparkle.framework'
],
'excludes': [
'distutils',
'_markerlib',
'PIL',
'pkg_resources',
'simplejson',
'unittest'
],
'iconfile': f'{appname}.icns',
'include_plugins': [
('plugins', x) for x in PLUGINS
],
'resources': [
'.gitversion', # Contains git short hash
'ChangeLog.md',
'snd_good.wav',
'snd_bad.wav',
'modules.p',
'ships.p',
('FDevIDs', [
join('FDevIDs', 'commodity.csv'),
join('FDevIDs', 'rare_commodity.csv'),
]),
],
'site_packages': False,
'plist': {
'CFBundleName': applongname,
'CFBundleIdentifier': f'uk.org.marginal.{appname.lower()}',
'CFBundleLocalizations': get_cfbundle_localizations(),
'CFBundleShortVersionString': appversion_str,
'CFBundleVersion': appversion_str,
'CFBundleURLTypes': [
{
'CFBundleTypeRole': 'Viewer',
'CFBundleURLName': f'uk.org.marginal.{appname.lower()}.URLScheme',
'CFBundleURLSchemes': [
'edmc'
],
}
],
'LSMinimumSystemVersion': '10.10',
'NSAppleScriptEnabled': True,
'NSHumanReadableCopyright': copyright,
'SUEnableAutomaticChecks': True,
'SUShowReleaseNotes': True,
'SUAllowsAutomaticUpdates': False,
'SUFeedURL': update_feed,
'SUScheduledCheckInterval': update_interval,
},
'graph': True, # output dependency graph in dist
}
}
DATA_FILES = []
elif sys.platform == 'win32':
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
'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),
]
setup(
name=applongname,
version=appversion_str,
windows=[
{
'dest_base': appname,
'script': APP,
'icon_resources': [(0, f'{appname}.ico')],
'company_name': 'EDCD', # Used by WinSparkle
'product_name': appname, # Used by WinSparkle
'version': base_appversion,
'product_version': appversion_str,
'copyright': copyright,
'other_resources': [(24, 1, open(f'{appname}.manifest').read())],
}
],
console=[
{
'dest_base': appcmdname,
'script': APPCMD,
'company_name': 'EDCD',
'product_name': appname,
'version': base_appversion,
'product_version': appversion_str,
'copyright': copyright,
'other_resources': [(24, 1, open(f'{appcmdname}.manifest').read())],
}
],
data_files=DATA_FILES,
options=OPTIONS,
py_modules=[],
)
package_filename = None
if sys.platform == 'darwin':
if isdir(f'{dist_dir}/{applongname}.app'): # from CFBundleName
os.rename(f'{dist_dir}/{applongname}.app', f'{dist_dir}/{appname}.app')
# Generate OSX-style localization files
for x in os.listdir('L10n'):
if x.endswith('.strings'):
lang = x[:-len('.strings')]
path = f'{dist_dir}/{appname}.app/Contents/Resources/{lang}.lproj'
os.mkdir(path)
codecs.open(
f'{path}/Localizable.strings',
'w',
'utf-16'
).write(codecs.open(f'L10n/{x}', 'r', 'utf-8').read())
if macdeveloperid:
os.system(f'codesign --deep -v -s "Developer ID Application: {macdeveloperid}" {dist_dir}/{appname}.app')
# Make zip for distribution, preserving signature
package_filename = f'{appname}_mac_{appversion_nobuild()}.zip'
os.system(f'cd {dist_dir}; ditto -ck --keepParent --sequesterRsrc {appname}.app ../{package_filename}; cd ..')
elif sys.platform == 'win32':
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:
#
# <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" -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}')
else:
raise AssertionError('Unsupported platform')