Updated Windows packaging code

This commit is contained in:
Veronica Berglyd Olsen
2024-07-04 21:00:15 +02:00
parent 4d716555af
commit d43a799389
2 changed files with 85 additions and 182 deletions
+84 -181
View File
@@ -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 -1
View File
@@ -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"