Updated Windows packaging code
This commit is contained in:
+84
-181
@@ -616,78 +616,6 @@ def copyPackageFiles(dst: Path, useCfg: bool = False) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Make Minimal Package (minimal-zip)
|
|
||||||
##
|
|
||||||
|
|
||||||
def makeWindowsZip() -> None:
|
|
||||||
"""Pack the core source file in a single zip file."""
|
|
||||||
from zipfile import ZIP_DEFLATED, ZipFile
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("Building Windows ZIP File")
|
|
||||||
print("=========================")
|
|
||||||
|
|
||||||
bldDir = "dist_minimal"
|
|
||||||
if not os.path.isdir(bldDir):
|
|
||||||
os.mkdir(bldDir)
|
|
||||||
|
|
||||||
if not checkAssetsExist():
|
|
||||||
print("ERROR: Missing build assets")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
pkgVers, _, _ = extractVersion()
|
|
||||||
zipFile = f"novelwriter-{pkgVers}-minimal-win.zip"
|
|
||||||
outFile = os.path.join(bldDir, zipFile)
|
|
||||||
if os.path.isfile(outFile):
|
|
||||||
os.unlink(outFile)
|
|
||||||
print("")
|
|
||||||
|
|
||||||
rootFiles = [
|
|
||||||
"README.md",
|
|
||||||
"LICENSE.md",
|
|
||||||
"CREDITS.md",
|
|
||||||
"CHANGELOG.md",
|
|
||||||
"requirements.txt",
|
|
||||||
"pkgutils.py",
|
|
||||||
"pyproject.toml",
|
|
||||||
]
|
|
||||||
|
|
||||||
with ZipFile(outFile, "w", compression=ZIP_DEFLATED, compresslevel=9) as zipObj:
|
|
||||||
|
|
||||||
for nRoot, _, nFiles in os.walk("novelwriter"):
|
|
||||||
if nRoot.endswith("__pycache__"):
|
|
||||||
print("Skipped: %s" % nRoot)
|
|
||||||
continue
|
|
||||||
|
|
||||||
print("Added: %s/* [Files: %d]" % (nRoot, len(nFiles)))
|
|
||||||
for aFile in nFiles:
|
|
||||||
if aFile.endswith(".pyc"):
|
|
||||||
print("Skipping File: %s" % aFile)
|
|
||||||
continue
|
|
||||||
zipObj.write(os.path.join(nRoot, aFile))
|
|
||||||
|
|
||||||
zipObj.write("novelWriter.py", "novelWriter.pyw")
|
|
||||||
print("Added: novelWriter.pyw")
|
|
||||||
|
|
||||||
for aFile in rootFiles:
|
|
||||||
print("Added: %s" % aFile)
|
|
||||||
zipObj.write(aFile)
|
|
||||||
|
|
||||||
zipObj.write(os.path.join("novelwriter", "assets", "manual.pdf"), "UserManual.pdf")
|
|
||||||
print("Added: UserManual.pdf")
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("Created File: %s" % outFile)
|
|
||||||
|
|
||||||
shaFile = makeCheckSum(zipFile, cwd=bldDir)
|
|
||||||
toUpload(outFile)
|
|
||||||
toUpload(shaFile)
|
|
||||||
print("")
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Make Debian Package
|
# Make Debian Package
|
||||||
##
|
##
|
||||||
@@ -961,6 +889,7 @@ def buildAppImage(args: argparse.Namespace) -> None:
|
|||||||
|
|
||||||
print("Copying novelWriter source ...")
|
print("Copying novelWriter source ...")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
copySourceCode(outDir)
|
copySourceCode(outDir)
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
@@ -1029,7 +958,7 @@ def buildAppImage(args: argparse.Namespace) -> None:
|
|||||||
# Make Windows Setup EXE (build-win-exe)
|
# Make Windows Setup EXE (build-win-exe)
|
||||||
##
|
##
|
||||||
|
|
||||||
def makeWindowsEmbedded(sysArgs: list[str]) -> None:
|
def makeWindowsEmbedded(args: argparse.Namespace) -> None:
|
||||||
"""Set up a package with embedded Python and dependencies for
|
"""Set up a package with embedded Python and dependencies for
|
||||||
Windows installation.
|
Windows installation.
|
||||||
"""
|
"""
|
||||||
@@ -1042,18 +971,8 @@ def makeWindowsEmbedded(sysArgs: list[str]) -> None:
|
|||||||
print("================================")
|
print("================================")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
minimalZip = None
|
numVers, hexVers, relDate = extractVersion()
|
||||||
packVersion = "none"
|
print("Version: %s" % numVers)
|
||||||
if len(sysArgs) >= 2:
|
|
||||||
if os.path.isfile(sysArgs[1]):
|
|
||||||
minimalZip = sysArgs[1]
|
|
||||||
|
|
||||||
if minimalZip is None:
|
|
||||||
print("Please provide the path to the minimal win package as an argument")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
packVersion = os.path.basename(minimalZip).split("-")[1]
|
|
||||||
print("Version: %s" % packVersion)
|
|
||||||
|
|
||||||
# Set Up Folder
|
# Set Up Folder
|
||||||
# =============
|
# =============
|
||||||
@@ -1061,27 +980,36 @@ def makeWindowsEmbedded(sysArgs: list[str]) -> None:
|
|||||||
if not os.path.isdir("dist"):
|
if not os.path.isdir("dist"):
|
||||||
os.mkdir("dist")
|
os.mkdir("dist")
|
||||||
|
|
||||||
outDir = os.path.join("dist", "novelWriter")
|
bldDir = CURR_DIR / "dist"
|
||||||
libDir = os.path.join(outDir, "lib")
|
outDir = bldDir / "novelWriter"
|
||||||
if os.path.isdir(outDir):
|
libDir = outDir / "lib"
|
||||||
|
if outDir.exists:
|
||||||
shutil.rmtree(outDir)
|
shutil.rmtree(outDir)
|
||||||
|
|
||||||
os.mkdir(outDir)
|
outDir.mkdir()
|
||||||
os.mkdir(libDir)
|
libDir.mkdir()
|
||||||
|
|
||||||
# Extract Source Files
|
# Copy novelWriter Source
|
||||||
# ====================
|
# =======================
|
||||||
|
|
||||||
print("Extracting source files ...")
|
print("Copying and compiling novelWriter source ...")
|
||||||
with zipfile.ZipFile(minimalZip, "r") as inFile:
|
print("")
|
||||||
inFile.extractall(outDir)
|
|
||||||
|
|
||||||
shutil.copyfile(
|
copySourceCode(outDir)
|
||||||
os.path.join(outDir, "novelwriter", "assets", "icons", "novelwriter.ico"),
|
|
||||||
os.path.join(outDir, "novelwriter.ico")
|
|
||||||
)
|
|
||||||
|
|
||||||
compileall.compile_dir(os.path.join(outDir, "novelwriter"))
|
files = [
|
||||||
|
CURR_DIR / "CREDITS.md",
|
||||||
|
CURR_DIR / "LICENSE.md",
|
||||||
|
CURR_DIR / "requirements.txt",
|
||||||
|
SETUP_DIR / "icons" / "novelwriter.ico",
|
||||||
|
SETUP_DIR / "iss_license.txt",
|
||||||
|
|
||||||
|
]
|
||||||
|
for item in files:
|
||||||
|
shutil.copyfile(item, outDir)
|
||||||
|
print(f"Copied: {item} > {outDir / item.name}")
|
||||||
|
|
||||||
|
compileall.compile_dir(outDir / "novelwriter")
|
||||||
|
|
||||||
print("Done")
|
print("Done")
|
||||||
print("")
|
print("")
|
||||||
@@ -1106,28 +1034,16 @@ def makeWindowsEmbedded(sysArgs: list[str]) -> None:
|
|||||||
print("Done")
|
print("Done")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
# Sort Out Licence Files
|
|
||||||
# ======================
|
|
||||||
|
|
||||||
os.rename(
|
|
||||||
os.path.join(outDir, "LICENSE.txt"),
|
|
||||||
os.path.join(outDir, "PYTHON-LICENSE.txt")
|
|
||||||
)
|
|
||||||
shutil.copyfile(
|
|
||||||
os.path.join("setup", "iss_license.txt"),
|
|
||||||
os.path.join(outDir, "LICENSES.txt")
|
|
||||||
)
|
|
||||||
|
|
||||||
# Install Dependencies
|
# Install Dependencies
|
||||||
# ====================
|
# ====================
|
||||||
|
|
||||||
print("Install dependencies ...")
|
print("Install dependencies ...")
|
||||||
|
|
||||||
sysCmd = [sys.executable]
|
|
||||||
sysCmd += "-m pip install -r requirements.txt --target".split()
|
|
||||||
sysCmd += [libDir]
|
|
||||||
try:
|
try:
|
||||||
subprocess.call(sysCmd)
|
subprocess.call([
|
||||||
|
sys.executable, "-m",
|
||||||
|
"pip", "install", "-r", "requirements.txt", "--target", str(libDir)
|
||||||
|
])
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print("Failed with error:")
|
print("Failed with error:")
|
||||||
print(str(exc))
|
print(str(exc))
|
||||||
@@ -1141,7 +1057,7 @@ def makeWindowsEmbedded(sysArgs: list[str]) -> None:
|
|||||||
|
|
||||||
print("Updating starting script ...")
|
print("Updating starting script ...")
|
||||||
|
|
||||||
writeFile(os.path.join(outDir, "novelWriter.pyw"), (
|
(outDir / "novelWriter.pyw").write_text(
|
||||||
"#!/usr/bin/env python3\n"
|
"#!/usr/bin/env python3\n"
|
||||||
"import os\n"
|
"import os\n"
|
||||||
"import sys\n"
|
"import sys\n"
|
||||||
@@ -1152,7 +1068,7 @@ def makeWindowsEmbedded(sysArgs: list[str]) -> None:
|
|||||||
"if __name__ == \"__main__\":\n"
|
"if __name__ == \"__main__\":\n"
|
||||||
" import novelwriter\n"
|
" import novelwriter\n"
|
||||||
" novelwriter.main(sys.argv[1:])\n"
|
" novelwriter.main(sys.argv[1:])\n"
|
||||||
))
|
)
|
||||||
|
|
||||||
print("Done")
|
print("Done")
|
||||||
print("")
|
print("")
|
||||||
@@ -1160,35 +1076,35 @@ def makeWindowsEmbedded(sysArgs: list[str]) -> None:
|
|||||||
# Clean Up Files
|
# Clean Up Files
|
||||||
# ==============
|
# ==============
|
||||||
|
|
||||||
def unlinkIfFound(delFile: str) -> None:
|
def unlinkIfFound(file: Path) -> None:
|
||||||
if os.path.isfile(delFile):
|
if file.is_file():
|
||||||
os.unlink(delFile)
|
file.unlink()
|
||||||
print("Deleted: %s" % delFile)
|
print(f"Deleted: {file}")
|
||||||
|
|
||||||
def deleteFolder(delPath: str) -> None:
|
def deleteFolder(folder: Path) -> None:
|
||||||
if os.path.isdir(delPath):
|
if folder.is_dir():
|
||||||
shutil.rmtree(delPath)
|
shutil.rmtree(folder)
|
||||||
print("Deleted: %s" % delPath)
|
print(f"Deleted: {folder}")
|
||||||
|
|
||||||
print("Deleting Redundant Files")
|
print("Deleting Redundant Files")
|
||||||
print("========================")
|
print("========================")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
pyQt5Dir = os.path.join(libDir, "PyQt5")
|
pyQt5Dir = libDir / "PyQt5"
|
||||||
bindDir = os.path.join(pyQt5Dir, "bindings")
|
bindDir = pyQt5Dir / "bindings"
|
||||||
qt5Dir = os.path.join(pyQt5Dir, "Qt5")
|
qt5Dir = pyQt5Dir / "Qt5"
|
||||||
binDir = os.path.join(qt5Dir, "bin")
|
binDir = qt5Dir / "bin"
|
||||||
plugDir = os.path.join(qt5Dir, "plugins")
|
plugDir = qt5Dir / "plugins"
|
||||||
qmDir = os.path.join(qt5Dir, "translations")
|
qmDir = qt5Dir / "translations"
|
||||||
dictDir = os.path.join(libDir, "enchant", "data", "mingw64", "share", "enchant", "hunspell")
|
dictDir = libDir / "enchant" / "data" / "mingw64" / "share" / "enchant" / "hunspell"
|
||||||
|
|
||||||
for dictFile in os.listdir(dictDir):
|
for item in dictDir.iterdir():
|
||||||
if not dictFile.startswith(("en_GB", "en_US")):
|
if not item.name.startswith(("en_GB", "en_US")):
|
||||||
unlinkIfFound(os.path.join(dictDir, dictFile))
|
unlinkIfFound(item)
|
||||||
|
|
||||||
for qmFile in os.listdir(qmDir):
|
for item in qmDir.iterdir():
|
||||||
if not qmFile.startswith("qtbase"):
|
if not item.name.startswith("qtbase"):
|
||||||
unlinkIfFound(os.path.join(qmDir, qmFile))
|
unlinkIfFound(item)
|
||||||
|
|
||||||
delQt5 = [
|
delQt5 = [
|
||||||
"Qt5Bluetooth", "Qt5DBus", "Qt5Designer", "Qt5Designer", "Qt5Help", "Qt5Location",
|
"Qt5Bluetooth", "Qt5DBus", "Qt5Designer", "Qt5Designer", "Qt5Help", "Qt5Location",
|
||||||
@@ -1200,30 +1116,28 @@ def makeWindowsEmbedded(sysArgs: list[str]) -> None:
|
|||||||
"Qt5SerialPort", "Qt5Sql", "Qt5Test", "Qt5TextToSpeech", "Qt5WebChannel", "Qt5WebSockets",
|
"Qt5SerialPort", "Qt5Sql", "Qt5Test", "Qt5TextToSpeech", "Qt5WebChannel", "Qt5WebSockets",
|
||||||
"Qt5WebView", "Qt5Xml", "Qt5XmlPatterns"
|
"Qt5WebView", "Qt5Xml", "Qt5XmlPatterns"
|
||||||
]
|
]
|
||||||
for qt5Item in delQt5:
|
for item in delQt5:
|
||||||
qtItem = qt5Item.replace("Qt5", "Qt")
|
qtItem = item.replace("Qt5", "Qt")
|
||||||
unlinkIfFound(os.path.join(binDir, qt5Item+".dll"))
|
unlinkIfFound(binDir / f"{item}.dll")
|
||||||
unlinkIfFound(os.path.join(pyQt5Dir, qtItem+".pyd"))
|
unlinkIfFound(pyQt5Dir / f"{qtItem}.pyd")
|
||||||
unlinkIfFound(os.path.join(pyQt5Dir, qtItem+".pyi"))
|
unlinkIfFound(pyQt5Dir / f"{qtItem}.pyi")
|
||||||
deleteFolder(os.path.join(bindDir, qtItem))
|
deleteFolder(bindDir / qtItem)
|
||||||
|
|
||||||
delList = [
|
delList = [
|
||||||
os.path.join(binDir, "opengl32sw.dll"),
|
binDir / "opengl32sw.dll",
|
||||||
os.path.join(qt5Dir, "qml"),
|
qt5Dir / "qml",
|
||||||
os.path.join(plugDir, "geoservices"),
|
plugDir / "geoservices",
|
||||||
os.path.join(plugDir, "playlistformats"),
|
plugDir / "playlistformats",
|
||||||
os.path.join(plugDir, "renderers"),
|
plugDir / "renderers",
|
||||||
os.path.join(plugDir, "sensorgestures"),
|
plugDir / "sensorgestures",
|
||||||
os.path.join(plugDir, "sensors"),
|
plugDir / "sensors",
|
||||||
os.path.join(plugDir, "sqldrivers"),
|
plugDir / "sqldrivers",
|
||||||
os.path.join(plugDir, "texttospeech"),
|
plugDir / "texttospeech",
|
||||||
os.path.join(plugDir, "webview"),
|
plugDir / "webview",
|
||||||
]
|
]
|
||||||
for delItem in delList:
|
for item in delList:
|
||||||
if os.path.isfile(delItem):
|
unlinkIfFound(item)
|
||||||
unlinkIfFound(delItem)
|
deleteFolder(item)
|
||||||
elif os.path.isdir(delItem):
|
|
||||||
deleteFolder(delItem)
|
|
||||||
|
|
||||||
print("Done")
|
print("Done")
|
||||||
print("")
|
print("")
|
||||||
@@ -1233,10 +1147,10 @@ def makeWindowsEmbedded(sysArgs: list[str]) -> None:
|
|||||||
print("")
|
print("")
|
||||||
|
|
||||||
# Read the iss template
|
# Read the iss template
|
||||||
issData = readFile(os.path.join("setup", "win_setup_embed.iss"))
|
issData = (SETUP_DIR / "win_setup_embed.iss").read_text()
|
||||||
issData = issData.replace(r"%%version%%", packVersion)
|
issData = issData.replace(r"%%version%%", numVers)
|
||||||
issData = issData.replace(r"%%dir%%", os.getcwd())
|
issData = issData.replace(r"%%dist%%", str(bldDir))
|
||||||
writeFile("setup.iss", issData)
|
(CURR_DIR / "setup.iss").write_text(issData)
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -1644,27 +1558,16 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
cmdBuildAppImage.set_defaults(func=buildAppImage)
|
cmdBuildAppImage.set_defaults(func=buildAppImage)
|
||||||
|
|
||||||
|
# Build Windows Inno Setup Installer
|
||||||
|
cmdBuildSetupExe = parsers.add_parser(
|
||||||
|
"build-win-exe", help="Build a setup.exe file with Python embedded for Windows."
|
||||||
|
)
|
||||||
|
cmdBuildSetupExe.set_defaults(func=makeWindowsEmbedded)
|
||||||
|
|
||||||
# if "gen-plist" in sysArgs:
|
# if "gen-plist" in sysArgs:
|
||||||
# sysArgs.remove("gen-plist")
|
# sysArgs.remove("gen-plist")
|
||||||
# genMacOSPlist()
|
# genMacOSPlist()
|
||||||
|
|
||||||
# if "windows-zip" in sysArgs:
|
|
||||||
# sysArgs.remove("windows-zip")
|
|
||||||
# makeWindowsZip()
|
|
||||||
|
|
||||||
# if "build-win-exe" in sysArgs:
|
|
||||||
# sysArgs.remove("build-win-exe")
|
|
||||||
# makeWindowsEmbedded(sysArgs)
|
|
||||||
# sys.exit(0) # Don't continue execution
|
|
||||||
|
|
||||||
# if "build-appimage" in sysArgs:
|
|
||||||
# sysArgs.remove("build-appimage")
|
|
||||||
# if hostOS == OS_LINUX:
|
|
||||||
# sysArgs = makeAppImage(sysArgs)
|
|
||||||
# else:
|
|
||||||
# print("ERROR: Command 'build-appimage' can only be used on Linux")
|
|
||||||
# sys.exit(1)
|
|
||||||
|
|
||||||
# # General Installers
|
# # General Installers
|
||||||
# # ==================
|
# # ==================
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
; Script for building setup.exe installer with Inno Setup
|
; Script for building setup.exe installer with Inno Setup
|
||||||
|
|
||||||
#define nwAppDir "%%dir%%\dist"
|
#define nwAppDir "%%dist%%"
|
||||||
#define nwAppName "novelWriter"
|
#define nwAppName "novelWriter"
|
||||||
#define nwAppVersion "%%version%%"
|
#define nwAppVersion "%%version%%"
|
||||||
#define nwAppPublisher "novelWriter"
|
#define nwAppPublisher "novelWriter"
|
||||||
|
|||||||
Reference in New Issue
Block a user