Skip to content

Commit 46ad1e9

Browse files
committed
Move building exe to pyinstaller
PyInstaller does not support pkgutil (or at least iter_modules) so the call in bush.py was replaced by a simple list. There is another call in localize.py but the function docs there say it's not meant to work when frozen so I let it be. This is not really an ideal solution for it should work for testing. Translation scripts are in the wrong(?) location. I guess some scripts expect them to be in Mopy/bash/ but not sure how that interacts with PyInstaller - needs further testing.
1 parent d1ef086 commit 46ad1e9

7 files changed

Lines changed: 101 additions & 173 deletions

File tree

.gitignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ desktop.ini
2424
.dropbox
2525
.DS_Store
2626

27-
# Release archives.
28-
scripts/dist/*.7z
27+
# Build-related folders
28+
scripts/build/standalone/dist/
29+
scripts/build/standalone/temp/
30+
scripts/dist/
2931

3032
# Local NSIS
3133
scripts/build/nsis/

Mopy/bash/bush.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
from .env import get_registry_game_path
3737
from .exception import BoltError
3838

39+
SUPPORTED_GAMES = [
40+
"enderal", "fallout3", "fallout4", "falloutnv",
41+
"oblivion", "skyrim", "skyrimse"
42+
]
43+
3944
# Game detection --------------------------------------------------------------
4045
game = None # type: game_init.GameInfo
4146
game_mod = None # type: game_init
@@ -59,10 +64,8 @@ def _supportedGames():
5964
"""Set games supported by Bash and return their paths from the registry."""
6065
# rebuilt cache
6166
reset_bush_globals()
62-
import pkgutil
6367
# Detect the known games
64-
for importer, modname, ispkg in pkgutil.iter_modules(game_init.__path__):
65-
if not ispkg: continue # game support modules are packages
68+
for modname in SUPPORTED_GAMES:
6669
# Equivalent of "from game import <modname>"
6770
try:
6871
module = __import__('game',globals(),locals(),[modname],-1)
@@ -79,7 +82,6 @@ def _supportedGames():
7982
if registry_path: _registryGames[game_type.fsName] = registry_path
8083
del module
8184
# unload some modules, _supportedGames is meant to run once
82-
del pkgutil
8385
_display_fsName.update({v: k for k, v in _fsName_display.iteritems()})
8486
# Dump out info about all games that we *could* launch, but wrap it
8587
deprint(u'The following games are supported by this version of Wrye Bash:')

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ scandir~=1.9
88
# Compile/Build-time
99
pygit2~=0.28
1010
pyfiglet~=0.8
11-
https://github.com/wrye-bash/dev-tools/raw/master/wheels/py2exe-0.6.9-cp27-cp27m-win32.whl
11+
pyinstaller~=3.4

scripts/build.py

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151

5252
import loot_api
5353
import pygit2
54+
import PyInstaller.__main__
5455

5556
import _winreg
5657
import utils
@@ -131,6 +132,17 @@ def setup_parser(parser):
131132
parser.set_defaults(version=nightly_version)
132133

133134

135+
# PyInstaller thinks it's fine to setup logging on import... -.-
136+
def setup_pyinstaller_logger(logfile):
137+
root_logger = logging.getLogger()
138+
stupid_handler = root_logger.handlers[0]
139+
stupid_formatter = stupid_handler.formatter
140+
root_logger.removeHandler(stupid_handler)
141+
file_handler = logging.FileHandler(logfile)
142+
file_handler.setFormatter(stupid_formatter)
143+
logging.getLogger("PyInstaller").addHandler(file_handler)
144+
145+
134146
def get_version_info(version):
135147
"""
136148
Generates version strings from the passed parameter.
@@ -257,35 +269,24 @@ def pack_manual(version):
257269
def build_executable(version, file_version):
258270
""" Builds the executable. """
259271
LOGGER.info("Building executable...")
260-
loot_orig = os.path.join(loot_api.__path__[0], u"loot.dll")
261-
loot_target = os.path.join(MOPY_PATH, u"loot.dll")
262-
build_folder = os.path.join(MOPY_PATH, u"build")
263-
dist_folder = os.path.join(MOPY_PATH, u"dist")
264-
setup_orig = os.path.join(WBSA_PATH, u"setup.py")
265-
setup_target = os.path.join(MOPY_PATH, u"setup.py")
266-
exe_orig = os.path.join(dist_folder, u"Wrye Bash Launcher.exe")
267-
exe_target = os.path.join(MOPY_PATH, u"Wrye Bash.exe")
268-
cpy(setup_orig, setup_target)
269-
# Call the setup script
270-
utils.run_subprocess(
271-
[sys.executable, setup_target, "py2exe", "--version", file_version],
272-
LOGGER,
273-
cwd=MOPY_PATH
274-
)
275-
# Copy the exe's to the Mopy folder
276-
cpy(exe_orig, exe_target)
277-
# py2exe can't read the loot.dll if it's in the exe
278-
# so we have to include it before and delete it after
279-
cpy(loot_orig, loot_target)
280-
# Clean up py2exe generated files/folders
281-
rm(setup_target)
282-
rm(build_folder)
283-
rm(dist_folder)
272+
temp_path = os.path.join(WBSA_PATH, u"temp")
273+
dist_path = os.path.join(WBSA_PATH, u"dist")
274+
spec_path = os.path.join(WBSA_PATH, u"pyinstaller.spec")
275+
orig_exe = os.path.join(dist_path, u"Wrye Bash.exe")
276+
dest_exe = os.path.join(MOPY_PATH, u"Wrye Bash.exe")
277+
PyInstaller.__main__.run([
278+
"--clean",
279+
"--noconfirm",
280+
"--distpath={}".format(dist_path),
281+
"--workpath={}".format(temp_path),
282+
spec_path,
283+
])
284+
# Copy the exe to the Mopy folder
285+
cpy(orig_exe, dest_exe)
284286
try:
285287
yield
286288
finally:
287-
rm(exe_target)
288-
rm(loot_target)
289+
rm(dest_exe)
289290

290291

291292
def pack_standalone(version):
@@ -426,6 +427,7 @@ def check_timestamp(build_version):
426427

427428

428429
def main(args):
430+
setup_pyinstaller_logger(LOGFILE)
429431
utils.setup_log(LOGGER, verbosity=args.verbosity, logfile=LOGFILE)
430432
# check nightly timestamp is different than previous
431433
if not check_timestamp(args.version):

scripts/build/installer/macros.nsh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
; Install the standalone only files
4646
SetOutPath "${GameDir}\Mopy"
4747
File "${WB_CLEAN_MOPY}\Wrye Bash.exe"
48-
File "${WB_CLEAN_MOPY}\loot.dll"
4948
; Write the installation path into the registry
5049
WriteRegStr HKLM "SOFTWARE\Wrye Bash" "${GameName} Standalone Version" "True"
5150
${ElseIf} ${RegValueExe} == $Empty
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# -*- mode: python -*-
2+
3+
import fnmatch
4+
import os
5+
import sys
6+
7+
def real_sys_prefix():
8+
if hasattr(sys, "real_prefix"): # running in virtualenv
9+
return sys.real_prefix
10+
elif hasattr(sys, "base_prefix"): # running in venv
11+
return sys.base_prefix
12+
else:
13+
return sys.prefix
14+
15+
TOOL_PATH = os.path.join(real_sys_prefix(), "Tools", "i18n")
16+
WBSA_PATH = SPECPATH # pyinstaller-defined global
17+
ROOT_PATH = os.path.join(WBSA_PATH, "..", "..", "..")
18+
MOPY_PATH = os.path.join(ROOT_PATH, "Mopy")
19+
GAME_PATH = os.path.join(MOPY_PATH, "bash", "game")
20+
21+
block_cipher = None
22+
entry_point = os.path.join(MOPY_PATH, "Wrye Bash Launcher.pyw")
23+
icon_path = os.path.join(WBSA_PATH, "bash.ico")
24+
manifest_path = os.path.join(WBSA_PATH, "manifest.xml")
25+
hiddenimports = ["pygettext", "msgfmt"]
26+
27+
for root, _, filenames in os.walk(GAME_PATH):
28+
for filename in fnmatch.filter(filenames, '*.py'):
29+
path = os.path.join(root, filename)
30+
path = path[:-3] # remove '.py'
31+
import_path = os.path.relpath(path, start=MOPY_PATH)
32+
hiddenimports.append(import_path.replace(os.sep, "."))
33+
34+
a = Analysis([entry_point],
35+
pathex=[TOOL_PATH, ROOT_PATH],
36+
binaries=[],
37+
datas=[],
38+
hiddenimports=hiddenimports,
39+
hookspath=[],
40+
runtime_hooks=[],
41+
excludes=[],
42+
win_no_prefer_redirects=False,
43+
win_private_assemblies=False,
44+
cipher=block_cipher,
45+
noarchive=False)
46+
pyz = PYZ(a.pure, a.zipped_data,
47+
cipher=block_cipher)
48+
exe = EXE(pyz,
49+
a.scripts,
50+
a.binaries,
51+
a.zipfiles,
52+
a.datas,
53+
[],
54+
name='Wrye Bash',
55+
debug=False,
56+
bootloader_ignore_signals=False,
57+
strip=False,
58+
upx=True,
59+
runtime_tmpdir=None,
60+
console=False,
61+
icon=icon_path,
62+
manifest=manifest_path)

scripts/build/standalone/setup.py

Lines changed: 0 additions & 139 deletions
This file was deleted.

0 commit comments

Comments
 (0)