Move AppImage builder functions
This commit is contained in:
+3
-189
@@ -35,35 +35,25 @@ import zipfile
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
import utils.build_appimage
|
||||||
import utils.build_binary
|
import utils.build_binary
|
||||||
import utils.build_debian
|
import utils.build_debian
|
||||||
import utils.build_windows
|
import utils.build_windows
|
||||||
import utils.icon_themes
|
import utils.icon_themes
|
||||||
|
|
||||||
from utils.common import (
|
from utils.common import ROOT_DIR, SETUP_DIR, extractVersion, readFile, stripVersion, writeFile
|
||||||
ROOT_DIR, SETUP_DIR, copySourceCode, extractVersion, makeCheckSum,
|
|
||||||
readFile, stripVersion, toUpload, writeFile
|
|
||||||
)
|
|
||||||
|
|
||||||
OS_LINUX = sys.platform.startswith("linux")
|
OS_LINUX = sys.platform.startswith("linux")
|
||||||
OS_DARWIN = sys.platform.startswith("darwin")
|
OS_DARWIN = sys.platform.startswith("darwin")
|
||||||
OS_WIN = sys.platform.startswith("win32")
|
OS_WIN = sys.platform.startswith("win32")
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Print Version
|
|
||||||
##
|
|
||||||
|
|
||||||
def printVersion(args: argparse.Namespace) -> None:
|
def printVersion(args: argparse.Namespace) -> None:
|
||||||
"""Print the novelWriter version and exit."""
|
"""Print the novelWriter version and exit."""
|
||||||
print(extractVersion(beQuiet=True)[0], end=None)
|
print(extractVersion(beQuiet=True)[0], end=None)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Package Installer (pip)
|
|
||||||
##
|
|
||||||
|
|
||||||
def installPackages(args: argparse.Namespace) -> None:
|
def installPackages(args: argparse.Namespace) -> None:
|
||||||
"""Install package dependencies both for this script and for running
|
"""Install package dependencies both for this script and for running
|
||||||
novelWriter itself.
|
novelWriter itself.
|
||||||
@@ -93,10 +83,6 @@ def installPackages(args: argparse.Namespace) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Clean Build and Dist Folders (build-clean)
|
|
||||||
##
|
|
||||||
|
|
||||||
def cleanBuildDirs(args: argparse.Namespace) -> None:
|
def cleanBuildDirs(args: argparse.Namespace) -> None:
|
||||||
"""Recursively delete the 'build' and 'dist' folders."""
|
"""Recursively delete the 'build' and 'dist' folders."""
|
||||||
print("")
|
print("")
|
||||||
@@ -415,178 +401,6 @@ def buildAllAssets(args: argparse.Namespace) -> None:
|
|||||||
# Python Packaging
|
# Python Packaging
|
||||||
# =============================================================================================== #
|
# =============================================================================================== #
|
||||||
|
|
||||||
##
|
|
||||||
# Copy Package Files
|
|
||||||
##
|
|
||||||
|
|
||||||
def copyPackageFiles(dst: Path, setupPy: bool = False) -> None:
|
|
||||||
"""Copy files needed for packaging."""
|
|
||||||
|
|
||||||
copyFiles = ["LICENSE.md", "CREDITS.md", "pyproject.toml"]
|
|
||||||
for copyFile in copyFiles:
|
|
||||||
shutil.copyfile(copyFile, dst / copyFile)
|
|
||||||
print("Copied: %s" % copyFile)
|
|
||||||
|
|
||||||
writeFile(dst / "MANIFEST.in", (
|
|
||||||
"include LICENSE.md\n"
|
|
||||||
"include CREDITS.md\n"
|
|
||||||
"recursive-include novelwriter/assets *\n"
|
|
||||||
))
|
|
||||||
print("Wrote: MANIFEST.in")
|
|
||||||
|
|
||||||
if setupPy:
|
|
||||||
writeFile(dst / "setup.py", (
|
|
||||||
"import setuptools\n"
|
|
||||||
"setuptools.setup()\n"
|
|
||||||
))
|
|
||||||
print("Wrote: setup.py")
|
|
||||||
|
|
||||||
text = readFile(ROOT_DIR / "pyproject.toml")
|
|
||||||
text = text.replace("setup/description_pypi.md", "data/description_short.txt")
|
|
||||||
writeFile(dst / "pyproject.toml", text)
|
|
||||||
print("Wrote: pyproject.toml")
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Build AppImage (build-appimage)
|
|
||||||
##
|
|
||||||
|
|
||||||
def buildAppImage(args: argparse.Namespace) -> None:
|
|
||||||
"""Build an AppImage."""
|
|
||||||
try:
|
|
||||||
import python_appimage # noqa: F401 # type: ignore
|
|
||||||
except ImportError:
|
|
||||||
print(
|
|
||||||
"ERROR: Package 'python-appimage' is missing on this system.\n"
|
|
||||||
" Please run 'pip install --user python-appimage' to install it.\n"
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if not OS_LINUX:
|
|
||||||
print("ERROR: Command 'build-ubuntu' can only be used on Linux")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("Build AppImage")
|
|
||||||
print("==============")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
linuxTag = args.linux_tag
|
|
||||||
pythonVer = args.python_version
|
|
||||||
|
|
||||||
# Version Info
|
|
||||||
# ============
|
|
||||||
|
|
||||||
pkgVers, _, relDate = extractVersion()
|
|
||||||
relDate = datetime.datetime.strptime(relDate, "%Y-%m-%d")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
# Set Up Folder
|
|
||||||
# =============
|
|
||||||
|
|
||||||
bldDir = ROOT_DIR / "dist_appimage"
|
|
||||||
bldPkg = f"novelwriter_{pkgVers}"
|
|
||||||
outDir = bldDir / bldPkg
|
|
||||||
imgDir = bldDir / "appimage"
|
|
||||||
|
|
||||||
# Set Up Folders
|
|
||||||
# ==============
|
|
||||||
|
|
||||||
bldDir.mkdir(exist_ok=True)
|
|
||||||
|
|
||||||
if outDir.exists():
|
|
||||||
print("Removing old build files ...")
|
|
||||||
print("")
|
|
||||||
shutil.rmtree(outDir)
|
|
||||||
|
|
||||||
outDir.mkdir()
|
|
||||||
|
|
||||||
if imgDir.exists():
|
|
||||||
print("Removing old build metadata files ...")
|
|
||||||
print("")
|
|
||||||
shutil.rmtree(imgDir)
|
|
||||||
|
|
||||||
imgDir.mkdir()
|
|
||||||
|
|
||||||
# Remove old AppImages
|
|
||||||
if images := bldDir.glob("*.AppImage"):
|
|
||||||
print("Removing old AppImages")
|
|
||||||
print("")
|
|
||||||
for image in images:
|
|
||||||
image.unlink()
|
|
||||||
|
|
||||||
# Copy novelWriter Source
|
|
||||||
# =======================
|
|
||||||
|
|
||||||
print("Copying novelWriter source ...")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
copySourceCode(outDir)
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("Copying or generating additional files ...")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
copyPackageFiles(outDir)
|
|
||||||
|
|
||||||
# Write Metadata
|
|
||||||
# ==============
|
|
||||||
|
|
||||||
appDescription = readFile(SETUP_DIR / "description_short.txt")
|
|
||||||
appdataXML = readFile(SETUP_DIR / "novelwriter.appdata.xml")
|
|
||||||
appdataXML = appdataXML.format(description=appDescription)
|
|
||||||
writeFile(imgDir / "novelwriter.appdata.xml", appdataXML)
|
|
||||||
print("Wrote: novelwriter.appdata.xml")
|
|
||||||
|
|
||||||
writeFile(imgDir / "entrypoint.sh", (
|
|
||||||
'#! /bin/bash \n'
|
|
||||||
'{{ python-executable }} -sE ${APPDIR}/opt/python{{ python-version }}/bin/novelwriter "$@"'
|
|
||||||
))
|
|
||||||
print("Wrote: entrypoint.sh")
|
|
||||||
|
|
||||||
writeFile(imgDir / "requirements.txt", str(outDir))
|
|
||||||
print("Wrote: requirements.txt")
|
|
||||||
|
|
||||||
shutil.copyfile(SETUP_DIR / "data" / "novelwriter.desktop", imgDir / "novelwriter.desktop")
|
|
||||||
print("Copied: novelwriter.desktop")
|
|
||||||
|
|
||||||
shutil.copyfile(SETUP_DIR / "icons" / "novelwriter.svg", imgDir / "novelwriter.svg")
|
|
||||||
print("Copied: novelwriter.svg")
|
|
||||||
|
|
||||||
shutil.copyfile(
|
|
||||||
SETUP_DIR / "data" / "hicolor" / "256x256" / "apps" / "novelwriter.png",
|
|
||||||
imgDir / "novelwriter.png"
|
|
||||||
)
|
|
||||||
print("Copied: novelwriter.png")
|
|
||||||
|
|
||||||
# Build AppImage
|
|
||||||
# ==============
|
|
||||||
|
|
||||||
try:
|
|
||||||
subprocess.call([
|
|
||||||
sys.executable, "-m", "python_appimage", "build", "app",
|
|
||||||
"-l", linuxTag, "-p", pythonVer, "appimage"
|
|
||||||
], cwd=bldDir)
|
|
||||||
except Exception as exc:
|
|
||||||
print("AppImage build: FAILED")
|
|
||||||
print("")
|
|
||||||
print(str(exc))
|
|
||||||
print("")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
bldFile = list(bldDir.glob("*.AppImage"))[0]
|
|
||||||
outFile = bldDir / f"novelWriter-{pkgVers}.AppImage"
|
|
||||||
bldFile.rename(outFile)
|
|
||||||
shaFile = makeCheckSum(outFile.name, cwd=bldDir)
|
|
||||||
|
|
||||||
toUpload(outFile)
|
|
||||||
toUpload(shaFile)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Generate MacOS PList
|
# Generate MacOS PList
|
||||||
##
|
##
|
||||||
@@ -752,7 +566,7 @@ if __name__ == "__main__":
|
|||||||
cmdBuildAppImage.add_argument(
|
cmdBuildAppImage.add_argument(
|
||||||
"--python-version", default="3.11", help="Python version (e.g. 3.11)"
|
"--python-version", default="3.11", help="Python version (e.g. 3.11)"
|
||||||
)
|
)
|
||||||
cmdBuildAppImage.set_defaults(func=buildAppImage)
|
cmdBuildAppImage.set_defaults(func=utils.build_appimage.main)
|
||||||
|
|
||||||
# Build Windows Inno Setup Installer
|
# Build Windows Inno Setup Installer
|
||||||
cmdBuildSetupExe = parsers.add_parser(
|
cmdBuildSetupExe = parsers.add_parser(
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
"""
|
||||||
|
novelWriter – AppImage Build
|
||||||
|
============================
|
||||||
|
|
||||||
|
This file is a part of novelWriter
|
||||||
|
Copyright (C) 2025 Veronica Berglyd Olsen and novelWriter contributors
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from utils.common import (
|
||||||
|
ROOT_DIR, SETUP_DIR, copyPackageFiles, copySourceCode, extractVersion,
|
||||||
|
makeCheckSum, readFile, toUpload, writeFile
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main(args: argparse.Namespace) -> None:
|
||||||
|
"""Build an AppImage."""
|
||||||
|
try:
|
||||||
|
import python_appimage # noqa: F401 # type: ignore
|
||||||
|
except ImportError:
|
||||||
|
print(
|
||||||
|
"ERROR: Package 'python-appimage' is missing on this system.\n"
|
||||||
|
" Please run 'pip install --user python-appimage' to install it.\n"
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if sys.platform == "linux":
|
||||||
|
print("ERROR: Command 'build-ubuntu' can only be used on Linux")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("Build AppImage")
|
||||||
|
print("==============")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
linuxTag = args.linux_tag
|
||||||
|
pythonVer = args.python_version
|
||||||
|
|
||||||
|
# Version Info
|
||||||
|
# ============
|
||||||
|
|
||||||
|
pkgVers, _, relDate = extractVersion()
|
||||||
|
relDate = datetime.datetime.strptime(relDate, "%Y-%m-%d")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Set Up Folder
|
||||||
|
# =============
|
||||||
|
|
||||||
|
bldDir = ROOT_DIR / "dist_appimage"
|
||||||
|
bldPkg = f"novelwriter_{pkgVers}"
|
||||||
|
outDir = bldDir / bldPkg
|
||||||
|
imgDir = bldDir / "appimage"
|
||||||
|
|
||||||
|
# Set Up Folders
|
||||||
|
# ==============
|
||||||
|
|
||||||
|
bldDir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
if outDir.exists():
|
||||||
|
print("Removing old build files ...")
|
||||||
|
print("")
|
||||||
|
shutil.rmtree(outDir)
|
||||||
|
|
||||||
|
outDir.mkdir()
|
||||||
|
|
||||||
|
if imgDir.exists():
|
||||||
|
print("Removing old build metadata files ...")
|
||||||
|
print("")
|
||||||
|
shutil.rmtree(imgDir)
|
||||||
|
|
||||||
|
imgDir.mkdir()
|
||||||
|
|
||||||
|
# Remove old AppImages
|
||||||
|
if images := bldDir.glob("*.AppImage"):
|
||||||
|
print("Removing old AppImages")
|
||||||
|
print("")
|
||||||
|
for image in images:
|
||||||
|
image.unlink()
|
||||||
|
|
||||||
|
# Copy novelWriter Source
|
||||||
|
# =======================
|
||||||
|
|
||||||
|
print("Copying novelWriter source ...")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
copySourceCode(outDir)
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("Copying or generating additional files ...")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
copyPackageFiles(outDir)
|
||||||
|
|
||||||
|
# Write Metadata
|
||||||
|
# ==============
|
||||||
|
|
||||||
|
appDescription = readFile(SETUP_DIR / "description_short.txt")
|
||||||
|
appdataXML = readFile(SETUP_DIR / "novelwriter.appdata.xml")
|
||||||
|
appdataXML = appdataXML.format(description=appDescription)
|
||||||
|
writeFile(imgDir / "novelwriter.appdata.xml", appdataXML)
|
||||||
|
print("Wrote: novelwriter.appdata.xml")
|
||||||
|
|
||||||
|
writeFile(imgDir / "entrypoint.sh", (
|
||||||
|
'#! /bin/bash \n'
|
||||||
|
'{{ python-executable }} -sE ${APPDIR}/opt/python{{ python-version }}/bin/novelwriter "$@"'
|
||||||
|
))
|
||||||
|
print("Wrote: entrypoint.sh")
|
||||||
|
|
||||||
|
writeFile(imgDir / "requirements.txt", str(outDir))
|
||||||
|
print("Wrote: requirements.txt")
|
||||||
|
|
||||||
|
shutil.copyfile(SETUP_DIR / "data" / "novelwriter.desktop", imgDir / "novelwriter.desktop")
|
||||||
|
print("Copied: novelwriter.desktop")
|
||||||
|
|
||||||
|
shutil.copyfile(SETUP_DIR / "icons" / "novelwriter.svg", imgDir / "novelwriter.svg")
|
||||||
|
print("Copied: novelwriter.svg")
|
||||||
|
|
||||||
|
shutil.copyfile(
|
||||||
|
SETUP_DIR / "data" / "hicolor" / "256x256" / "apps" / "novelwriter.png",
|
||||||
|
imgDir / "novelwriter.png"
|
||||||
|
)
|
||||||
|
print("Copied: novelwriter.png")
|
||||||
|
|
||||||
|
# Build AppImage
|
||||||
|
# ==============
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.call([
|
||||||
|
sys.executable, "-m", "python_appimage", "build", "app",
|
||||||
|
"-l", linuxTag, "-p", pythonVer, "appimage"
|
||||||
|
], cwd=bldDir)
|
||||||
|
except Exception as exc:
|
||||||
|
print("AppImage build: FAILED")
|
||||||
|
print("")
|
||||||
|
print(str(exc))
|
||||||
|
print("")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
bldFile = list(bldDir.glob("*.AppImage"))[0]
|
||||||
|
outFile = bldDir / f"novelWriter-{pkgVers}.AppImage"
|
||||||
|
bldFile.rename(outFile)
|
||||||
|
shaFile = makeCheckSum(outFile.name, cwd=bldDir)
|
||||||
|
|
||||||
|
toUpload(outFile)
|
||||||
|
toUpload(shaFile)
|
||||||
|
|
||||||
|
return
|
||||||
@@ -27,10 +27,9 @@ import shutil
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pkgutils import copyPackageFiles
|
|
||||||
from utils.common import (
|
from utils.common import (
|
||||||
ROOT_DIR, SETUP_DIR, checkAssetsExist, copySourceCode, extractVersion,
|
ROOT_DIR, SETUP_DIR, checkAssetsExist, copyPackageFiles, copySourceCode,
|
||||||
makeCheckSum, toUpload
|
extractVersion, makeCheckSum, toUpload
|
||||||
)
|
)
|
||||||
|
|
||||||
from tests.tools import writeFile
|
from tests.tools import writeFile
|
||||||
|
|||||||
@@ -90,6 +90,35 @@ def copySourceCode(dst: Path) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def copyPackageFiles(dst: Path, setupPy: bool = False) -> None:
|
||||||
|
"""Copy files needed for packaging."""
|
||||||
|
copyFiles = ["LICENSE.md", "CREDITS.md", "pyproject.toml"]
|
||||||
|
for copyFile in copyFiles:
|
||||||
|
shutil.copyfile(copyFile, dst / copyFile)
|
||||||
|
print("Copied: %s" % copyFile)
|
||||||
|
|
||||||
|
writeFile(dst / "MANIFEST.in", (
|
||||||
|
"include LICENSE.md\n"
|
||||||
|
"include CREDITS.md\n"
|
||||||
|
"recursive-include novelwriter/assets *\n"
|
||||||
|
))
|
||||||
|
print("Wrote: MANIFEST.in")
|
||||||
|
|
||||||
|
if setupPy:
|
||||||
|
writeFile(dst / "setup.py", (
|
||||||
|
"import setuptools\n"
|
||||||
|
"setuptools.setup()\n"
|
||||||
|
))
|
||||||
|
print("Wrote: setup.py")
|
||||||
|
|
||||||
|
text = readFile(ROOT_DIR / "pyproject.toml")
|
||||||
|
text = text.replace("setup/description_pypi.md", "data/description_short.txt")
|
||||||
|
writeFile(dst / "pyproject.toml", text)
|
||||||
|
print("Wrote: pyproject.toml")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
def toUpload(srcPath: str | Path, dstName: str | None = None) -> None:
|
def toUpload(srcPath: str | Path, dstName: str | None = None) -> None:
|
||||||
"""Copy a file produced by one of the build functions to the upload
|
"""Copy a file produced by one of the build functions to the upload
|
||||||
directory. The file can optionally be given a new name.
|
directory. The file can optionally be given a new name.
|
||||||
|
|||||||
Reference in New Issue
Block a user