Move AppImage builder functions
This commit is contained in:
@@ -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 sys
|
||||
|
||||
from pkgutils import copyPackageFiles
|
||||
from utils.common import (
|
||||
ROOT_DIR, SETUP_DIR, checkAssetsExist, copySourceCode, extractVersion,
|
||||
makeCheckSum, toUpload
|
||||
ROOT_DIR, SETUP_DIR, checkAssetsExist, copyPackageFiles, copySourceCode,
|
||||
extractVersion, makeCheckSum, toUpload
|
||||
)
|
||||
|
||||
from tests.tools import writeFile
|
||||
|
||||
@@ -90,6 +90,35 @@ def copySourceCode(dst: Path) -> None:
|
||||
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:
|
||||
"""Copy a file produced by one of the build functions to the upload
|
||||
directory. The file can optionally be given a new name.
|
||||
|
||||
Reference in New Issue
Block a user