Appimage Distribution (#1092)

This commit is contained in:
Veronica Berglyd Olsen
2022-07-15 16:53:37 +02:00
committed by GitHub
3 changed files with 254 additions and 2 deletions
+232
View File
@@ -197,6 +197,7 @@ def cleanBuildDirs():
removeFolder("dist")
removeFolder("dist_deb")
removeFolder("dist_minimal")
removeFolder("dist_appimage")
removeFolder("novelWriter.egg-info")
print("")
@@ -835,10 +836,231 @@ def makeForLaunchpad(doSign=False, isFirst=False, isSnapshot=False):
return
##
# Make AppImage (build-appimage)
##
def makeAppImage(sysArgs):
"""Build an Appimage
"""
import glob
import argparse
import platform
try:
import python_appimage # noqa F401
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)
print("")
print("Build AppImage")
print("==============")
print("")
parser = argparse.ArgumentParser(
prog="build_appimage",
description="Build an AppImage",
epilog="see https://appimage.org/ for more details",
)
parser.add_argument(
"--linux-tag",
nargs="?",
default=f"manylinux2010_{platform.machine()}",
help=(
"linux compatibility tag (e.g. manylinux1_x86_64) \n"
"see https://python-appimage.readthedocs.io/en/latest/#available-python-appimages \n"
"and https://github.com/pypa/manylinux for a list of valid tags"
),
)
parser.add_argument(
"--python-version", nargs="?", default="3.10", help="python version (e.g. 3.10)"
)
args, unparsedArgs = parser.parse_known_args(sysArgs)
linuxTag = args.linux_tag
pythonVer = args.python_version
# Version Info
# ============
numVers, _, relDate = extractVersion()
pkgVers = compactVersion(numVers)
relDate = datetime.datetime.strptime(relDate, "%Y-%m-%d")
print("")
# Set Up Folder
# =============
bldDir = "dist_appimage"
bldPkg = f"novelwriter_{pkgVers}"
outDir = f"{bldDir}/{bldPkg}"
imageDir = f"{bldDir}/appimage"
# Set Up Folders
# ==============
if not os.path.isdir(bldDir):
os.mkdir(bldDir)
if os.path.isdir(outDir):
print("Removing old build files ...")
print("")
shutil.rmtree(outDir)
os.mkdir(outDir)
if os.path.isdir(imageDir):
print("Removing old build metadata files ...")
print("")
shutil.rmtree(imageDir)
os.mkdir(imageDir)
# Remove old Appimages
outFiles = glob.glob(f"{bldDir}/*.AppImage")
if outFiles:
print("Removing old AppImages")
print("")
for image in outFiles:
try:
os.remove(image)
except OSError:
print("Error while deleting file : ", image)
# Build Additional Assets
# =======================
buildQtI18n()
buildSampleZip()
buildPdfManual()
# Copy novelWriter Source
# =======================
print("Copying novelWriter source ...")
print("")
for nPath, _, nFiles in os.walk("novelwriter"):
if nPath.endswith("__pycache__"):
print("Skipped: %s" % nPath)
continue
pPath = f"{outDir}/{nPath}"
if not os.path.isdir(pPath):
os.mkdir(pPath)
fCount = 0
for fFile in nFiles:
nFile = f"{nPath}/{fFile}"
pFile = f"{pPath}/{fFile}"
if fFile.endswith(".pyc"):
print("Skipped: %s" % nFile)
continue
shutil.copyfile(nFile, pFile)
fCount += 1
print("Copied: %s/* [Files: %d]" % (nPath, fCount))
print("")
print("Copying or generating additional files ...")
print("")
# Copy/Write Root Files
# =====================
copyFiles = ["LICENSE.md", "CREDITS.md", "CHANGELOG.md", "pyproject.toml"]
for copyFile in copyFiles:
shutil.copyfile(copyFile, f"{outDir}/{copyFile}")
print("Copied: %s" % copyFile)
writeFile(f"{outDir}/MANIFEST.in", (
"include LICENSE.md\n"
"include CREDITS.md\n"
"include CHANGELOG.md\n"
"include data/*\n"
"recursive-include novelwriter/assets *\n"
))
print("Wrote: MANIFEST.in")
writeFile(f"{outDir}/setup.py", (
"import setuptools\n"
"setuptools.setup()\n"
))
print("Wrote: setup.py")
setupCfg = readFile("setup.cfg").replace(
"file: setup/description_pypi.md", "file: data/description_short.txt"
)
writeFile(f"{outDir}/setup.cfg", setupCfg)
print("Wrote: setup.cfg")
# Write Metadata
# ==============
appDescription = readFile("setup/description_short.txt")
appdataXML = readFile("setup/novelwriter.appdata.xml").format(description=appDescription)
writeFile(f"{imageDir}/novelwriter.appdata.xml", appdataXML)
print("Wrote: novelwriter.appdata.xml")
writeFile(f"{imageDir}/entrypoint.sh", (
'#! /bin/bash \n'
'{{ python-executable }} -sE ${APPDIR}/opt/python{{ python-version }}/bin/novelwriter "$@"'
))
print("Wrote: entrypoint.sh")
writeFile(f"{imageDir}/requirements.txt", os.path.abspath(outDir))
print("Wrote: requirements.txt")
shutil.copyfile("setup/data/novelwriter.desktop", f"{imageDir}/novelwriter.desktop")
print("Copied: setup/data/novelwriter.desktop")
shutil.copyfile("setup/icons/novelwriter.svg", f"{imageDir}/novelwriter.svg")
print("Copied: setup/icons/novelwriter.svg")
shutil.copyfile("setup/data/hicolor/256x256/apps/novelwriter.png",
f"{imageDir}/novelwriter.png")
print("Copied: setup/data/hicolor/256x256/apps/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("")
print("Dependencies:")
print(" * pip install python-appimage")
print("")
sys.exit(1)
outFile = glob.glob(f"{bldDir}/*.AppImage")[0]
shaFile = makeCheckSum(os.path.basename(outFile), cwd=bldDir)
toUpload(outFile)
toUpload(shaFile)
return unparsedArgs
##
# Make Windows Setup EXE (build-win-exe)
##
def makeWindowsEmbedded(sysArgs):
"""Set up a package with embedded Python and dependencies for
Windows installation.
@@ -1581,6 +1803,8 @@ if __name__ == "__main__":
" Add --snapshot to make a snapshot package.",
" 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",
" manylinux1_x86_64 / i386, and --python-version to 3.10.",
"",
"System Install:",
"",
@@ -1679,6 +1903,14 @@ if __name__ == "__main__":
makeWindowsEmbedded(sys.argv)
sys.exit(0) # Don't continue execution
if "build-appimage" in sys.argv:
sys.argv.remove("build-appimage")
if hostOS == OS_LINUX:
sys.argv = makeAppImage(sys.argv) # Build appimage and prune its args
else:
print("ERROR: Command 'build-appimage' can only be used on Linux")
sys.exit(1)
# General Installers
# ==================
+1 -2
View File
@@ -1,10 +1,9 @@
[Desktop Entry]
Type=Application
Encoding=UTF-8
Name=novelWriter
Comment=A markdown-like text editor for planning and writing novels
Exec=novelwriter %f
Icon=novelwriter
Categories=Qt;Office;WordProcessor;
Terminal=false
MimeType=application/x-novelwriter-project
MimeType=application/x-novelwriter-project;
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>novelwriter</id>
<metadata_license>GPL-3.0</metadata_license>
<project_license>GPL-3.0</project_license>
<name>novelWriter</name>
<summary>A markdown-like text editor for planning and writing novels</summary>
<description>
<p>{description}</p>
</description>
<launchable type="desktop-id">novelwriter.desktop</launchable>
<url type="homepage">https://novelwriter.io/</url>
<screenshots>
<screenshot type="default">
<image>https://novelwriter.io/images/screenshot-multi.png</image>
</screenshot>
</screenshots>
<provides>
<id>novelwriter.desktop</id>
</provides>
</component>