Update XDG tools, clean up and fix a deb build issue
This commit is contained in:
+54
-101
@@ -28,7 +28,6 @@ from __future__ import annotations
|
|||||||
import argparse
|
import argparse
|
||||||
import datetime
|
import datetime
|
||||||
import email.utils
|
import email.utils
|
||||||
import os
|
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@@ -113,22 +112,22 @@ def toUpload(srcPath: str | Path, dstName: str | None = None) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def makeCheckSum(sumFile: str, cwd: Path | str | None = None) -> str:
|
def makeCheckSum(sumFile: str, cwd: Path | None = None) -> str:
|
||||||
"""Create a SHA256 checksum file."""
|
"""Create a SHA256 checksum file."""
|
||||||
try:
|
try:
|
||||||
if cwd is None:
|
if cwd is None:
|
||||||
shaFile = sumFile+".sha256"
|
shaFile = f"{sumFile}.sha256"
|
||||||
else:
|
else:
|
||||||
shaFile = os.path.join(cwd, sumFile+".sha256")
|
shaFile = cwd / f"{sumFile}.sha256"
|
||||||
with open(shaFile, mode="w") as fOut:
|
with open(shaFile, mode="w") as fOut:
|
||||||
subprocess.call(["shasum", "-a", "256", sumFile], stdout=fOut, cwd=cwd)
|
subprocess.call(["shasum", "-a", "256", sumFile], stdout=fOut, cwd=cwd)
|
||||||
print("SHA256 Sum: %s" % shaFile)
|
print(f"SHA256 Sum: {shaFile}")
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print("Could not generate sha256 file")
|
print("Could not generate sha256 file")
|
||||||
print(str(exc))
|
print(str(exc))
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
return shaFile
|
return str(shaFile)
|
||||||
|
|
||||||
|
|
||||||
def checkAssetsExist() -> bool:
|
def checkAssetsExist() -> bool:
|
||||||
@@ -137,22 +136,20 @@ def checkAssetsExist() -> bool:
|
|||||||
hasManual = False
|
hasManual = False
|
||||||
hasQmData = False
|
hasQmData = False
|
||||||
|
|
||||||
sampleZip = os.path.join("novelwriter", "assets", "sample.zip")
|
sampleZip = CURR_DIR / "novelwriter" / "assets" / "sample.zip"
|
||||||
if os.path.isfile(sampleZip):
|
if sampleZip.is_file():
|
||||||
print(f"Found: {sampleZip}")
|
print(f"Found: {sampleZip}")
|
||||||
hasSample = True
|
hasSample = True
|
||||||
|
|
||||||
pdfManual = os.path.join("novelwriter", "assets", "manual.pdf")
|
pdfManual = CURR_DIR / "novelwriter" / "assets" / "manual.pdf"
|
||||||
if os.path.isfile(pdfManual):
|
if pdfManual.is_file():
|
||||||
print(f"Found: {pdfManual}")
|
print(f"Found: {pdfManual}")
|
||||||
hasManual = True
|
hasManual = True
|
||||||
|
|
||||||
i18nAssets = os.path.join("novelwriter", "assets", "i18n")
|
i18nAssets = CURR_DIR / "novelwriter" / "assets" / "i18n"
|
||||||
for i18nItem in os.listdir(i18nAssets):
|
if len(list(i18nAssets.glob("*.qm"))) > 0:
|
||||||
i18nPath = os.path.join(i18nAssets, i18nItem)
|
print(f"Found: {i18nAssets}/*.qm")
|
||||||
if os.path.isfile(i18nPath) and i18nPath.endswith(".qm"):
|
hasQmData = True
|
||||||
print(f"Found: {i18nPath}")
|
|
||||||
hasQmData = True
|
|
||||||
|
|
||||||
return hasSample and hasManual and hasQmData
|
return hasSample and hasManual and hasQmData
|
||||||
|
|
||||||
@@ -283,7 +280,7 @@ def buildPdfManual(args: argparse.Namespace | None = None) -> None:
|
|||||||
print("")
|
print("")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if not os.path.isfile(finalFile):
|
if not finalFile.is_file():
|
||||||
print("No output file was found!")
|
print("No output file was found!")
|
||||||
print("")
|
print("")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -551,7 +548,7 @@ def copySourceCode(dst: Path) -> None:
|
|||||||
# Copy Package Files
|
# Copy Package Files
|
||||||
##
|
##
|
||||||
|
|
||||||
def copyPackageFiles(dst: Path, useCfg: bool = False) -> None:
|
def copyPackageFiles(dst: Path, setupPy: bool = False, useCfg: bool = False) -> None:
|
||||||
"""Copy files needed for packaging."""
|
"""Copy files needed for packaging."""
|
||||||
|
|
||||||
copyFiles = ["LICENSE.md", "CREDITS.md", "pyproject.toml"]
|
copyFiles = ["LICENSE.md", "CREDITS.md", "pyproject.toml"]
|
||||||
@@ -562,11 +559,17 @@ def copyPackageFiles(dst: Path, useCfg: bool = False) -> None:
|
|||||||
(dst / "MANIFEST.in").write_text(
|
(dst / "MANIFEST.in").write_text(
|
||||||
"include LICENSE.md\n"
|
"include LICENSE.md\n"
|
||||||
"include CREDITS.md\n"
|
"include CREDITS.md\n"
|
||||||
# "include data/*\n"
|
|
||||||
"recursive-include novelwriter/assets *\n"
|
"recursive-include novelwriter/assets *\n"
|
||||||
)
|
)
|
||||||
print("Wrote: MANIFEST.in")
|
print("Wrote: MANIFEST.in")
|
||||||
|
|
||||||
|
if setupPy:
|
||||||
|
(dst / "setup.py").write_text(
|
||||||
|
"import setuptools\n"
|
||||||
|
"setuptools.setup()\n"
|
||||||
|
)
|
||||||
|
print("Wrote: setup.py")
|
||||||
|
|
||||||
if useCfg:
|
if useCfg:
|
||||||
# This is needed for Ubuntu up to 22.04
|
# This is needed for Ubuntu up to 22.04
|
||||||
text = (SETUP_DIR / "launchpad_setup.cfg").read_text()
|
text = (SETUP_DIR / "launchpad_setup.cfg").read_text()
|
||||||
@@ -655,7 +658,7 @@ def makeDebianPackage(
|
|||||||
print("Copying or generating additional files ...")
|
print("Copying or generating additional files ...")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
copyPackageFiles(outDir, oldSetuptools)
|
copyPackageFiles(outDir, setupPy=True, useCfg=oldSetuptools)
|
||||||
|
|
||||||
# Copy/Write Debian Files
|
# Copy/Write Debian Files
|
||||||
# =======================
|
# =======================
|
||||||
@@ -950,15 +953,13 @@ def makeWindowsEmbedded(args: argparse.Namespace) -> None:
|
|||||||
# Set Up Folder
|
# Set Up Folder
|
||||||
# =============
|
# =============
|
||||||
|
|
||||||
if not os.path.isdir("dist"):
|
|
||||||
os.mkdir("dist")
|
|
||||||
|
|
||||||
bldDir = CURR_DIR / "dist"
|
bldDir = CURR_DIR / "dist"
|
||||||
outDir = bldDir / "novelWriter"
|
outDir = bldDir / "novelWriter"
|
||||||
libDir = outDir / "lib"
|
libDir = outDir / "lib"
|
||||||
if outDir.exists:
|
if outDir.exists:
|
||||||
shutil.rmtree(outDir)
|
shutil.rmtree(outDir)
|
||||||
|
|
||||||
|
bldDir.mkdir(exist_ok=True)
|
||||||
outDir.mkdir()
|
outDir.mkdir()
|
||||||
libDir.mkdir()
|
libDir.mkdir()
|
||||||
|
|
||||||
@@ -993,9 +994,9 @@ def makeWindowsEmbedded(args: argparse.Namespace) -> None:
|
|||||||
print("Adding Python embeddable ...")
|
print("Adding Python embeddable ...")
|
||||||
|
|
||||||
pyVers = "%d.%d.%d" % (sys.version_info[:3])
|
pyVers = "%d.%d.%d" % (sys.version_info[:3])
|
||||||
zipFile = "python-%s-embed-amd64.zip" % pyVers
|
zipFile = f"python-{pyVers}-embed-amd64.zip"
|
||||||
pyZip = os.path.join("dist", zipFile)
|
pyZip = bldDir / zipFile
|
||||||
if not os.path.isfile(pyZip):
|
if not pyZip.is_file():
|
||||||
pyUrl = f"https://www.python.org/ftp/python/{pyVers}/{zipFile}"
|
pyUrl = f"https://www.python.org/ftp/python/{pyVers}/{zipFile}"
|
||||||
print("Downloading: %s" % pyUrl)
|
print("Downloading: %s" % pyUrl)
|
||||||
urllib.request.urlretrieve(pyUrl, pyZip)
|
urllib.request.urlretrieve(pyUrl, pyZip)
|
||||||
@@ -1175,7 +1176,7 @@ def genMacOSPlist(args: argparse.Namespace) -> None:
|
|||||||
# XDG Installation (xdg-install)
|
# XDG Installation (xdg-install)
|
||||||
##
|
##
|
||||||
|
|
||||||
def xdgInstall() -> None:
|
def xdgInstall(args: argparse.Namespace) -> None:
|
||||||
"""Will attempt to install icons and make a launcher."""
|
"""Will attempt to install icons and make a launcher."""
|
||||||
print("")
|
print("")
|
||||||
print("XDG Install")
|
print("XDG Install")
|
||||||
@@ -1195,9 +1196,9 @@ def xdgInstall() -> None:
|
|||||||
if testExec is not None:
|
if testExec is not None:
|
||||||
exOpts.append(testExec)
|
exOpts.append(testExec)
|
||||||
|
|
||||||
testExec = os.path.join(os.getcwd(), "novelWriter.py")
|
testExec = CURR_DIR / "novelWriter.py"
|
||||||
if os.path.isfile(testExec):
|
if testExec.is_file():
|
||||||
exOpts.append(testExec)
|
exOpts.append(str(testExec))
|
||||||
|
|
||||||
useExec = ""
|
useExec = ""
|
||||||
nOpts = len(exOpts)
|
nOpts = len(exOpts)
|
||||||
@@ -1228,9 +1229,10 @@ def xdgInstall() -> None:
|
|||||||
# ===========================
|
# ===========================
|
||||||
|
|
||||||
# Generate launcher
|
# Generate launcher
|
||||||
desktopData = readFile(os.path.join("setup", "data", "novelwriter.desktop"))
|
desktopFile = CURR_DIR / "novelwriter.desktop"
|
||||||
|
desktopData = (SETUP_DIR / "data" / "novelwriter.desktop").read_text()
|
||||||
desktopData = desktopData.replace("Exec=novelwriter", f"Exec={useExec}")
|
desktopData = desktopData.replace("Exec=novelwriter", f"Exec={useExec}")
|
||||||
writeFile("novelwriter.desktop", desktopData)
|
desktopFile.write_text(desktopData)
|
||||||
|
|
||||||
# Remove old desktop icon
|
# Remove old desktop icon
|
||||||
exCode = subprocess.call(
|
exCode = subprocess.call(
|
||||||
@@ -1297,8 +1299,7 @@ def xdgInstall() -> None:
|
|||||||
print(f"Error {exCode}: Could not update icon cache")
|
print(f"Error {exCode}: Could not update icon cache")
|
||||||
|
|
||||||
# Clean up
|
# Clean up
|
||||||
if os.path.isfile("./novelwriter.desktop"):
|
desktopFile.unlink(missing_ok=True)
|
||||||
os.unlink("./novelwriter.desktop")
|
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
print("Done!")
|
print("Done!")
|
||||||
@@ -1311,7 +1312,7 @@ def xdgInstall() -> None:
|
|||||||
# XDG Uninstallation (xdg-uninstall)
|
# XDG Uninstallation (xdg-uninstall)
|
||||||
##
|
##
|
||||||
|
|
||||||
def xdgUninstall() -> None:
|
def xdgUninstall(args: argparse.Namespace) -> None:
|
||||||
"""Will attempt to uninstall icons and the launcher."""
|
"""Will attempt to uninstall icons and the launcher."""
|
||||||
print("")
|
print("")
|
||||||
print("XDG Uninstall")
|
print("XDG Uninstall")
|
||||||
@@ -1386,56 +1387,6 @@ if __name__ == "__main__":
|
|||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parsers = parser.add_subparsers()
|
parsers = parser.add_subparsers()
|
||||||
|
|
||||||
helpMsg = [
|
|
||||||
"",
|
|
||||||
"novelWriter Setup Tool",
|
|
||||||
"======================",
|
|
||||||
"",
|
|
||||||
"This tool provides setup and build commands for installing or distibuting",
|
|
||||||
"novelWriter as a package on Linux, Mac and Windows. The available options",
|
|
||||||
"are as follows:",
|
|
||||||
"",
|
|
||||||
"General:",
|
|
||||||
"",
|
|
||||||
" help Print the help message.",
|
|
||||||
" pip Install all package dependencies for novelWriter using pip.",
|
|
||||||
" version Print the novelWriter version.",
|
|
||||||
" build-clean Will attempt to delete 'build' and 'dist' folders.",
|
|
||||||
"",
|
|
||||||
"Additional Builds:",
|
|
||||||
"",
|
|
||||||
" manual Build the help documentation as PDF (requires LaTeX).",
|
|
||||||
" sample Build the sample project zip file and add it to assets.",
|
|
||||||
" qtlupdate Update translation files for internationalisation.",
|
|
||||||
" The files to be updated must be provided as arguments.",
|
|
||||||
" qtlrelease Build the language files for internationalisation.",
|
|
||||||
" clean-assets Delete assets built by manual, sample and qtlrelease.",
|
|
||||||
" gen-plist Generates an Info.plist for use in a MacOS Bundle",
|
|
||||||
"",
|
|
||||||
"Python Packaging:",
|
|
||||||
"",
|
|
||||||
" import-i18n Import updated i18n files from a zip file.",
|
|
||||||
" windows-zip Creates a minimal zip file of the core application without",
|
|
||||||
" all the other source files. Used for Windows builds.",
|
|
||||||
" build-deb Build a .deb package for Debian and Ubuntu. Add --sign to ",
|
|
||||||
" sign package.",
|
|
||||||
" build-ubuntu Build a .deb packages Launchpad. Add --sign to ",
|
|
||||||
" sign package. Add --first to set build number to 0.",
|
|
||||||
" build-win-exe Build a setup.exe file with Python embedded for Windows.",
|
|
||||||
" The package must be built from a minimal windows zip file.",
|
|
||||||
" build-appimage Build an AppImage. Argument --linux-tag defaults to",
|
|
||||||
" manylinux_2_28_x86_64, and --python-version to 3.11.",
|
|
||||||
"",
|
|
||||||
"System Install:",
|
|
||||||
"",
|
|
||||||
" xdg-install Install launcher and icons for freedesktop systems. Run as",
|
|
||||||
" root or with sudo for system-wide install, or as user for",
|
|
||||||
" single user install.",
|
|
||||||
" xdg-uninstall Remove the launcher and icons for the current system as",
|
|
||||||
" installed by the 'xdg-install' command.",
|
|
||||||
"",
|
|
||||||
]
|
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
cmdVersion = parsers.add_parser(
|
cmdVersion = parsers.add_parser(
|
||||||
"version", help="Print the novelWriter version."
|
"version", help="Print the novelWriter version."
|
||||||
@@ -1570,24 +1521,26 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
cmdBuildMacOSPlist.set_defaults(func=genMacOSPlist)
|
cmdBuildMacOSPlist.set_defaults(func=genMacOSPlist)
|
||||||
|
|
||||||
# # General Installers
|
# General Installers
|
||||||
# # ==================
|
# ==================
|
||||||
|
|
||||||
# if "xdg-install" in sysArgs:
|
# Linux XDG Install
|
||||||
# sysArgs.remove("xdg-install")
|
cmdXDGInstall = parsers.add_parser(
|
||||||
# if hostOS == OS_WIN:
|
"xdg-install", help=(
|
||||||
# print("ERROR: Command 'xdg-install' cannot be used on Windows")
|
"Install launcher and icons for freedesktop systems. Run as root or with sudo for "
|
||||||
# sys.exit(1)
|
"system-wide install, or as user for single user install."
|
||||||
# else:
|
)
|
||||||
# xdgInstall()
|
)
|
||||||
|
cmdXDGInstall.set_defaults(func=xdgInstall)
|
||||||
|
|
||||||
# if "xdg-uninstall" in sysArgs:
|
# Linux XDG Uninstall
|
||||||
# sysArgs.remove("xdg-uninstall")
|
cmdXDGUninstall = parsers.add_parser(
|
||||||
# if hostOS == OS_WIN:
|
"xdg-uninstall", help=(
|
||||||
# print("ERROR: Command 'xdg-uninstall' cannot be used on Windows")
|
"Remove the launcher and icons for the current system "
|
||||||
# sys.exit(1)
|
"as installed by the 'xdg-install' command."
|
||||||
# else:
|
)
|
||||||
# xdgUninstall()
|
)
|
||||||
|
cmdXDGUninstall.set_defaults(func=xdgUninstall)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
args.func(args)
|
args.func(args)
|
||||||
|
|||||||
Reference in New Issue
Block a user