Merge branch 'main' into outline_updates
This commit is contained in:
@@ -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,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;
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user