Complete the zipapp packaging for Windows
This commit is contained in:
+10
-4
@@ -269,10 +269,16 @@ class Config:
|
|||||||
logger.verbose("Config path: %s" % self.confPath)
|
logger.verbose("Config path: %s" % self.confPath)
|
||||||
logger.verbose("Data path: %s" % self.dataPath)
|
logger.verbose("Data path: %s" % self.dataPath)
|
||||||
|
|
||||||
self.confFile = self.appHandle+".conf"
|
self.confFile = self.appHandle+".conf"
|
||||||
self.lastPath = os.path.expanduser("~")
|
self.lastPath = os.path.expanduser("~")
|
||||||
self.appPath = getattr(sys, "_MEIPASS", os.path.abspath(os.path.dirname(__file__)))
|
self.appPath = getattr(sys, "_MEIPASS", os.path.abspath(os.path.dirname(__file__)))
|
||||||
self.appRoot = os.path.join(self.appPath, os.path.pardir)
|
self.appRoot = os.path.abspath(os.path.join(self.appPath, os.path.pardir))
|
||||||
|
|
||||||
|
if self.appRoot.endswith(".pyz"):
|
||||||
|
self.appRoot = os.path.abspath(os.path.join(self.appRoot, os.path.pardir))
|
||||||
|
self.appPath = self.appRoot
|
||||||
|
|
||||||
|
# Assets
|
||||||
self.assetPath = os.path.join(self.appPath, "assets")
|
self.assetPath = os.path.join(self.appPath, "assets")
|
||||||
self.themeRoot = os.path.join(self.assetPath, "themes")
|
self.themeRoot = os.path.join(self.assetPath, "themes")
|
||||||
self.dictPath = os.path.join(self.assetPath, "dict")
|
self.dictPath = os.path.join(self.assetPath, "dict")
|
||||||
|
|||||||
@@ -216,12 +216,13 @@ def buildSampleZip():
|
|||||||
# Make Simple Package (winpack)
|
# Make Simple Package (winpack)
|
||||||
##
|
##
|
||||||
|
|
||||||
def makeWindowsPackage():
|
def makeSimplePackage(embedPython):
|
||||||
"""Run zipapp to freeze the packages. This assumes zipapp and pip
|
"""Run zipapp to freeze the packages. This assumes zipapp and pip
|
||||||
are already installed.
|
are already installed.
|
||||||
"""
|
"""
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import zipfile
|
import zipfile
|
||||||
|
import zipapp
|
||||||
|
|
||||||
# Set Up Folder
|
# Set Up Folder
|
||||||
# =============
|
# =============
|
||||||
@@ -230,7 +231,10 @@ def makeWindowsPackage():
|
|||||||
os.mkdir("dist")
|
os.mkdir("dist")
|
||||||
|
|
||||||
outDir = os.path.join("dist", "novelWriter")
|
outDir = os.path.join("dist", "novelWriter")
|
||||||
|
zipDir = os.path.join("dist", "zipapp_temp")
|
||||||
libDir = os.path.join(outDir, "lib")
|
libDir = os.path.join(outDir, "lib")
|
||||||
|
if os.path.isdir(zipDir):
|
||||||
|
shutil.rmtree(zipDir)
|
||||||
if os.path.isdir(outDir):
|
if os.path.isdir(outDir):
|
||||||
shutil.rmtree(outDir)
|
shutil.rmtree(outDir)
|
||||||
|
|
||||||
@@ -240,23 +244,24 @@ def makeWindowsPackage():
|
|||||||
# Download Python Embeddable
|
# Download Python Embeddable
|
||||||
# ==========================
|
# ==========================
|
||||||
|
|
||||||
print("")
|
if embedPython:
|
||||||
print("# Downloading Python Embeddable")
|
print("")
|
||||||
print("# =============================")
|
print("# Downloading Python Embeddable")
|
||||||
print("")
|
print("# =============================")
|
||||||
|
print("")
|
||||||
|
|
||||||
pyUrl = "https://www.python.org/ftp/python/3.8.7/python-3.8.7-embed-amd64.zip"
|
pyUrl = "https://www.python.org/ftp/python/3.8.7/python-3.8.7-embed-amd64.zip"
|
||||||
pyZip = os.path.join(outDir, "python_embed.zip")
|
pyZip = os.path.join(outDir, "python_embed.zip")
|
||||||
print("URL: %s" % pyUrl)
|
print("URL: %s" % pyUrl)
|
||||||
|
|
||||||
urllib.request.urlretrieve(pyUrl, pyZip)
|
urllib.request.urlretrieve(pyUrl, pyZip)
|
||||||
|
|
||||||
print("Extracting ...")
|
print("Extracting ...")
|
||||||
with zipfile.ZipFile(pyZip, "r") as inFile:
|
with zipfile.ZipFile(pyZip, "r") as inFile:
|
||||||
inFile.extractall(outDir)
|
inFile.extractall(outDir)
|
||||||
|
|
||||||
os.unlink(pyZip)
|
os.unlink(pyZip)
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
# Make sample.zip
|
# Make sample.zip
|
||||||
# ===============
|
# ===============
|
||||||
@@ -281,7 +286,7 @@ def makeWindowsPackage():
|
|||||||
cpIgnore = shutil.ignore_patterns("__pycache__")
|
cpIgnore = shutil.ignore_patterns("__pycache__")
|
||||||
|
|
||||||
print("Copying: nw")
|
print("Copying: nw")
|
||||||
shutil.copytree("nw", os.path.join(outDir, "nw"), ignore=cpIgnore)
|
shutil.copytree("nw", os.path.join(zipDir, "nw"), ignore=cpIgnore)
|
||||||
for copyFile in copyList:
|
for copyFile in copyList:
|
||||||
print("Copying: %s" % copyFile)
|
print("Copying: %s" % copyFile)
|
||||||
shutil.copy2(copyFile, os.path.join(outDir, copyFile))
|
shutil.copy2(copyFile, os.path.join(outDir, copyFile))
|
||||||
@@ -289,8 +294,11 @@ def makeWindowsPackage():
|
|||||||
print("Copying: %s" % iconFile)
|
print("Copying: %s" % iconFile)
|
||||||
shutil.copy2(os.path.join("setup", "icons", iconFile), os.path.join(outDir, iconFile))
|
shutil.copy2(os.path.join("setup", "icons", iconFile), os.path.join(outDir, iconFile))
|
||||||
|
|
||||||
print("Writing: novelWriter.pyw")
|
nwDir = os.path.join(outDir, "nw")
|
||||||
with open(os.path.join(outDir, "novelWriter.pyw"), mode="w") as outFile:
|
os.rename(os.path.join(zipDir, "nw", "assets"), os.path.join(outDir, "assets"))
|
||||||
|
|
||||||
|
print("Writing: __main__.py")
|
||||||
|
with open(os.path.join(zipDir, "__main__.py"), mode="w") as outFile:
|
||||||
outFile.write(
|
outFile.write(
|
||||||
"#!\"pythonw.exe\"\n"
|
"#!\"pythonw.exe\"\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -298,7 +306,9 @@ def makeWindowsPackage():
|
|||||||
"import sys\n"
|
"import sys\n"
|
||||||
"\n"
|
"\n"
|
||||||
"sys.path.insert(\n"
|
"sys.path.insert(\n"
|
||||||
" 0, os.path.abspath(os.path.join(os.path.dirname(__file__), \"lib\"))\n"
|
" 0, os.path.abspath(\n"
|
||||||
|
" os.path.join(os.path.dirname(__file__), os.path.pardir, \"lib\")\n"
|
||||||
|
" )\n"
|
||||||
")\n\n"
|
")\n\n"
|
||||||
"if __name__ == \"__main__\":\n"
|
"if __name__ == \"__main__\":\n"
|
||||||
" import nw\n"
|
" import nw\n"
|
||||||
@@ -306,6 +316,9 @@ def makeWindowsPackage():
|
|||||||
)
|
)
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
pyzFile = os.path.join(outDir, "novelWriter.pyz")
|
||||||
|
zipapp.create_archive(zipDir, target=pyzFile, interpreter="python3")
|
||||||
|
|
||||||
# Install Dependencies
|
# Install Dependencies
|
||||||
# ====================
|
# ====================
|
||||||
|
|
||||||
@@ -722,9 +735,9 @@ if __name__ == "__main__":
|
|||||||
"\n"
|
"\n"
|
||||||
"Python Packaging:\n"
|
"Python Packaging:\n"
|
||||||
"\n"
|
"\n"
|
||||||
" winpack Creates a pyz package in a folder with all dependencies using the\n"
|
" pack-pyz Creates a pyz package in a folder with all dependencies using the\n"
|
||||||
" zipapp tool. This option is intended for Windows deployment.\n"
|
" zipapp tool. This option is intended for Windows deployment.\n"
|
||||||
" freeze Freeze the package and produces a folder with all dependencies using\n"
|
" pack-exe Freeze the package and produces a folder with all dependencies using\n"
|
||||||
" the pyinstaller tool. This option is not designed for a specific OS.\n"
|
" the pyinstaller tool. This option is not designed for a specific OS.\n"
|
||||||
" onefile Build a standalone executable with all dependencies bundled using the\n"
|
" onefile Build a standalone executable with all dependencies bundled using the\n"
|
||||||
" pyinstaller tool. Implies 'freeze', cannot be used with 'setup-exe'.\n"
|
" pyinstaller tool. Implies 'freeze', cannot be used with 'setup-exe'.\n"
|
||||||
@@ -751,7 +764,8 @@ if __name__ == "__main__":
|
|||||||
makeSetupExe = False
|
makeSetupExe = False
|
||||||
makeSetupPyz = False
|
makeSetupPyz = False
|
||||||
doFreeze = False
|
doFreeze = False
|
||||||
winPack = False
|
simplePack = False
|
||||||
|
embedPython = False
|
||||||
|
|
||||||
# General
|
# General
|
||||||
# =======
|
# =======
|
||||||
@@ -783,16 +797,14 @@ if __name__ == "__main__":
|
|||||||
# Python Packaging
|
# Python Packaging
|
||||||
# ================
|
# ================
|
||||||
|
|
||||||
if "winpack" in sys.argv:
|
if "pack-pyz" in sys.argv:
|
||||||
sys.argv.remove("winpack")
|
sys.argv.remove("pack-pyz")
|
||||||
|
simplePack = True
|
||||||
if hostOS == OS_WIN:
|
if hostOS == OS_WIN:
|
||||||
winPack = True
|
embedPython = True
|
||||||
else:
|
|
||||||
print("Error: Command 'winpack' is Windows only.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if "freeze" in sys.argv:
|
if "pack-exe" in sys.argv:
|
||||||
sys.argv.remove("freeze")
|
sys.argv.remove("pack-exe")
|
||||||
doFreeze = True
|
doFreeze = True
|
||||||
|
|
||||||
if "onefile" in sys.argv:
|
if "onefile" in sys.argv:
|
||||||
@@ -843,8 +855,8 @@ if __name__ == "__main__":
|
|||||||
# For functions that are controlled by multiple flags, or need to be
|
# For functions that are controlled by multiple flags, or need to be
|
||||||
# run in a specific order.
|
# run in a specific order.
|
||||||
|
|
||||||
if winPack:
|
if simplePack:
|
||||||
makeWindowsPackage()
|
makeSimplePackage(embedPython)
|
||||||
|
|
||||||
if doFreeze:
|
if doFreeze:
|
||||||
freezePackage(buildWindowed, oneFile, makeSetupExe, hostOS)
|
freezePackage(buildWindowed, oneFile, makeSetupExe, hostOS)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#define nwAppVersion "%%version%%"
|
#define nwAppVersion "%%version%%"
|
||||||
#define nwAppPublisher "novelWriter"
|
#define nwAppPublisher "novelWriter"
|
||||||
#define nwAppURL "http://novelWriter.io"
|
#define nwAppURL "http://novelWriter.io"
|
||||||
#define nwAppExeName "novelWriter.pyw"
|
#define nwAppExeName "novelWriter.pyz"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
|
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
|
||||||
@@ -54,6 +54,6 @@ Filename: "{app}\pythonw.exe"; Parameters: "{#nwAppExeName}"; Description: "{cm
|
|||||||
[Registry]
|
[Registry]
|
||||||
Root: HKA; Subkey: "Software\Classes\.nwx\OpenWithProgids"; ValueType: string; ValueName: "novelWriterProject.nwx"; ValueData: ""; Flags: uninsdeletevalue
|
Root: HKA; Subkey: "Software\Classes\.nwx\OpenWithProgids"; ValueType: string; ValueName: "novelWriterProject.nwx"; ValueData: ""; Flags: uninsdeletevalue
|
||||||
Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx"; ValueType: string; ValueName: ""; ValueData: "novelWriter Project File"; Flags: uninsdeletekey
|
Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx"; ValueType: string; ValueName: ""; ValueData: "novelWriter Project File"; Flags: uninsdeletekey
|
||||||
Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\nw\assets\icons\x-novelwriter-project.ico"
|
Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\assets\icons\x-novelwriter-project.ico"
|
||||||
Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\pythonw.exe"" ""{app}\{#nwAppExeName}"" ""%1"""
|
Root: HKA; Subkey: "Software\Classes\novelWriterProject.nwx\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\pythonw.exe"" ""{app}\{#nwAppExeName}"" ""%1"""
|
||||||
Root: HKA; Subkey: "Software\Classes\Applications\{#nwAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".nwx"; ValueData: ""
|
Root: HKA; Subkey: "Software\Classes\Applications\{#nwAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".nwx"; ValueData: ""
|
||||||
|
|||||||
Reference in New Issue
Block a user