Update build scripts for docs
This commit is contained in:
@@ -32,7 +32,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: nw-assets
|
name: nw-assets
|
||||||
path: |
|
path: |
|
||||||
novelwriter/assets/manual.pdf
|
novelwriter/assets/manual*.pdf
|
||||||
novelwriter/assets/sample.zip
|
novelwriter/assets/sample.zip
|
||||||
novelwriter/assets/i18n/*.qm
|
novelwriter/assets/i18n/*.qm
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|||||||
@@ -153,8 +153,9 @@ You can also build a PDF manual from the documentation using the ``pkgutils.py``
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
python pkgutils.py manual
|
python pkgutils.py docs-pdf en
|
||||||
|
|
||||||
This will build the documentation as a PDF using LaTeX. The file will then be copied into the
|
This will build the English documentation as a PDF using LaTeX. The file will then be copied into
|
||||||
assets folder and made available in the **Help** menu in novelWriter. The Sphinx build system has a
|
the assets folder and made available in the **Help** menu in novelWriter. Replace ``en`` with
|
||||||
few extra dependencies when building the PDF. Please check the `Sphinx Docs`_ for more details.
|
``all`` to build for all languages. The Sphinx build system has a few extra dependencies when
|
||||||
|
building the PDF. Please check the `Sphinx Docs`_ for more details.
|
||||||
|
|||||||
@@ -303,7 +303,8 @@ class Config:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def pdfDocs(self) -> Path | None:
|
def pdfDocs(self) -> Path | None:
|
||||||
return self._manuals.get(f"manual_{self.locale.name()}", self._manuals.get("manual"))
|
"""Return the local manual PDF file, if any exist."""
|
||||||
|
return self._manuals.get(f"manual_{self.locale.bcp47Name()}", self._manuals.get("manual"))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nwLangPath(self) -> Path:
|
def nwLangPath(self) -> Path:
|
||||||
|
|||||||
+18
-16
@@ -37,6 +37,7 @@ 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.docs
|
||||||
import utils.icon_themes
|
import utils.icon_themes
|
||||||
|
|
||||||
from utils.common import ROOT_DIR, SETUP_DIR, extractVersion, readFile, stripVersion, writeFile
|
from utils.common import ROOT_DIR, SETUP_DIR, extractVersion, readFile, stripVersion, writeFile
|
||||||
@@ -88,13 +89,13 @@ def cleanBuildDirs(args: argparse.Namespace) -> None:
|
|||||||
print("")
|
print("")
|
||||||
|
|
||||||
folders = [
|
folders = [
|
||||||
ROOT_DIR / "build",
|
|
||||||
ROOT_DIR / "build_bin",
|
ROOT_DIR / "build_bin",
|
||||||
ROOT_DIR / "dist",
|
ROOT_DIR / "build",
|
||||||
|
ROOT_DIR / "dist_appimage",
|
||||||
ROOT_DIR / "dist_bin",
|
ROOT_DIR / "dist_bin",
|
||||||
ROOT_DIR / "dist_deb",
|
ROOT_DIR / "dist_deb",
|
||||||
ROOT_DIR / "dist_minimal",
|
ROOT_DIR / "dist_doc",
|
||||||
ROOT_DIR / "dist_appimage",
|
ROOT_DIR / "dist",
|
||||||
ROOT_DIR / "novelWriter.egg-info",
|
ROOT_DIR / "novelWriter.egg-info",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -211,20 +212,21 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
cmdUpdateDocsPo.add_argument("lang", nargs="+")
|
cmdUpdateDocsPo.add_argument("lang", nargs="+")
|
||||||
cmdUpdateDocsPo.set_defaults(func=utils.assets.updateDocsTranslationSources)
|
cmdUpdateDocsPo.set_defaults(func=utils.docs.updateDocsTranslationSources)
|
||||||
|
|
||||||
# Build Docs i18n Files
|
# Build PDF Docs
|
||||||
cmdBuildU18nDocs = parsers.add_parser(
|
cmdBuildPdfDocs = parsers.add_parser(
|
||||||
"docs-lrelease", help="Build the translated PDF manual files."
|
"docs-pdf", help="Build the PDF manual files."
|
||||||
)
|
)
|
||||||
cmdBuildU18nDocs.add_argument("lang", nargs="+")
|
cmdBuildPdfDocs.add_argument("lang", nargs="+")
|
||||||
cmdBuildU18nDocs.set_defaults(func=utils.assets.buildDocsTranslationAssets)
|
cmdBuildPdfDocs.set_defaults(func=utils.docs.buildPdfDocAssets)
|
||||||
|
|
||||||
# Build Manual
|
# Build HTML Docs
|
||||||
cmdBuildManual = parsers.add_parser(
|
cmdBuildHtmlDocs = parsers.add_parser(
|
||||||
"manual", help="Build the help documentation as a PDF (requires LaTeX)."
|
"docs-html", help="Build the HTML docs."
|
||||||
)
|
)
|
||||||
cmdBuildManual.set_defaults(func=utils.assets.buildPdfManual)
|
cmdBuildHtmlDocs.add_argument("lang", nargs="+")
|
||||||
|
cmdBuildHtmlDocs.set_defaults(func=utils.docs.buildHtmlDocs)
|
||||||
|
|
||||||
# Build Sample
|
# Build Sample
|
||||||
cmdBuildSample = parsers.add_parser(
|
cmdBuildSample = parsers.add_parser(
|
||||||
@@ -234,13 +236,13 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# Clean Assets
|
# Clean Assets
|
||||||
cmdCleanAssets = parsers.add_parser(
|
cmdCleanAssets = parsers.add_parser(
|
||||||
"clean-assets", help="Delete assets built by manual, sample and qtlrelease."
|
"clean-assets", help="Delete assets built by docs-pdf, sample and qtlrelease."
|
||||||
)
|
)
|
||||||
cmdCleanAssets.set_defaults(func=utils.assets.cleanBuiltAssets)
|
cmdCleanAssets.set_defaults(func=utils.assets.cleanBuiltAssets)
|
||||||
|
|
||||||
# Build Assets
|
# Build Assets
|
||||||
cmdBuildAssets = parsers.add_parser(
|
cmdBuildAssets = parsers.add_parser(
|
||||||
"build-assets", help="Build all assets. Includes manual, sample and qtlrelease."
|
"build-assets", help="Build all assets. Includes docs-pdf, sample and qtlrelease."
|
||||||
)
|
)
|
||||||
cmdBuildAssets.set_defaults(func=utils.assets.buildAllAssets)
|
cmdBuildAssets.set_defaults(func=utils.assets.buildAllAssets)
|
||||||
|
|
||||||
|
|||||||
+2
-126
@@ -21,7 +21,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import zipfile
|
import zipfile
|
||||||
@@ -29,51 +28,7 @@ import zipfile
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from utils.common import ROOT_DIR, writeFile
|
from utils.common import ROOT_DIR, writeFile
|
||||||
|
from utils.docs import buildPdfDocAssets
|
||||||
|
|
||||||
def buildPdfManual(args: argparse.Namespace | None = None) -> None:
|
|
||||||
"""This function will build the documentation as manual.pdf."""
|
|
||||||
print("")
|
|
||||||
print("Building PDF Manual")
|
|
||||||
print("===================")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
buildFile = ROOT_DIR / "docs" / "build" / "latex" / "manual.pdf"
|
|
||||||
finalFile = ROOT_DIR / "novelwriter" / "assets" / "manual.pdf"
|
|
||||||
finalFile.unlink(missing_ok=True)
|
|
||||||
|
|
||||||
try:
|
|
||||||
subprocess.call(["make", "clean"], cwd="docs")
|
|
||||||
exCode = subprocess.call(["make", "latexpdf"], cwd="docs")
|
|
||||||
if exCode == 0:
|
|
||||||
print("")
|
|
||||||
buildFile.rename(finalFile)
|
|
||||||
else:
|
|
||||||
raise Exception(f"Build returned error code {exCode}")
|
|
||||||
|
|
||||||
print("PDF manual build: OK")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
except Exception as exc:
|
|
||||||
print("PDF manual build: FAILED")
|
|
||||||
print("")
|
|
||||||
print(str(exc))
|
|
||||||
print("")
|
|
||||||
print("Dependencies:")
|
|
||||||
print(" * pip install sphinx")
|
|
||||||
print(" * Package latexmk")
|
|
||||||
print(" * LaTeX build system")
|
|
||||||
print("")
|
|
||||||
print(" On Debian/Ubuntu, install: python3-sphinx latexmk texlive texlive-latex-extra")
|
|
||||||
print("")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if not finalFile.is_file():
|
|
||||||
print("No output file was found!")
|
|
||||||
print("")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def buildSampleZip(args: argparse.Namespace | None = None) -> None:
|
def buildSampleZip(args: argparse.Namespace | None = None) -> None:
|
||||||
@@ -251,84 +206,6 @@ def buildTranslationAssets(args: argparse.Namespace | None = None) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def updateDocsTranslationSources(args: argparse.Namespace) -> None:
|
|
||||||
"""Build the documentation .po files."""
|
|
||||||
print("")
|
|
||||||
print("Building Docs Translation Files")
|
|
||||||
print("===============================")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
docsDir = ROOT_DIR / "docs"
|
|
||||||
locsDir = ROOT_DIR / "docs" / "source" / "locales"
|
|
||||||
locsDir.mkdir(exist_ok=True)
|
|
||||||
|
|
||||||
print("Generating POT Files")
|
|
||||||
subprocess.call(["make", "gettext"], cwd=docsDir)
|
|
||||||
print("")
|
|
||||||
|
|
||||||
lang = args.lang
|
|
||||||
update = []
|
|
||||||
if lang == ["all"]:
|
|
||||||
update = [i.stem for i in locsDir.iterdir() if i.is_dir()]
|
|
||||||
else:
|
|
||||||
update = lang
|
|
||||||
|
|
||||||
print("Generating PO Files")
|
|
||||||
print("Languages: ", update)
|
|
||||||
print("")
|
|
||||||
|
|
||||||
for code in update:
|
|
||||||
subprocess.call(["sphinx-intl", "update", "-p", "build/gettext", "-l", code], cwd=docsDir)
|
|
||||||
print("")
|
|
||||||
|
|
||||||
print("Done")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def buildDocsTranslationAssets(args: argparse.Namespace | None = None) -> None:
|
|
||||||
"""Build the documentation i18n PDF files."""
|
|
||||||
from PyQt6.QtCore import QLocale
|
|
||||||
|
|
||||||
print("")
|
|
||||||
print("Building Docs Manuals")
|
|
||||||
print("=====================")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
docsDir = ROOT_DIR / "docs"
|
|
||||||
locsDir = ROOT_DIR / "docs" / "source" / "locales"
|
|
||||||
pdfFile = ROOT_DIR / "docs" / "build" / "latex" / "manual.pdf"
|
|
||||||
locsDir.mkdir(exist_ok=True)
|
|
||||||
|
|
||||||
lang = args.lang if args else ["all"]
|
|
||||||
build = []
|
|
||||||
if lang == ["all"]:
|
|
||||||
build = [i.stem for i in locsDir.iterdir() if i.is_dir()]
|
|
||||||
else:
|
|
||||||
build = lang
|
|
||||||
|
|
||||||
for code in build:
|
|
||||||
data = (locsDir / f"authors_{code}.conf").read_text(encoding="utf-8")
|
|
||||||
authors = [x for x in data.splitlines() if x and not x.startswith("#")]
|
|
||||||
env = os.environ.copy()
|
|
||||||
env["SPHINX_I18N_AUTHORS"] = ", ".join(authors)
|
|
||||||
exCode = subprocess.call(
|
|
||||||
f"make -e SPHINXOPTS=\"-D language='{code}'\" clean latexpdf",
|
|
||||||
cwd=docsDir, env=env, shell=True
|
|
||||||
)
|
|
||||||
if exCode == 0:
|
|
||||||
print("")
|
|
||||||
name = f"manual_{QLocale(code).name()}.pdf"
|
|
||||||
pdfFile.rename(ROOT_DIR / "novelwriter" / "assets" / name)
|
|
||||||
else:
|
|
||||||
raise Exception(f"Build returned error code {exCode}")
|
|
||||||
|
|
||||||
print("")
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def cleanBuiltAssets(args: argparse.Namespace | None = None) -> None:
|
def cleanBuiltAssets(args: argparse.Namespace | None = None) -> None:
|
||||||
"""Remove assets built by this script."""
|
"""Remove assets built by this script."""
|
||||||
print("")
|
print("")
|
||||||
@@ -352,8 +229,7 @@ def cleanBuiltAssets(args: argparse.Namespace | None = None) -> None:
|
|||||||
def buildAllAssets(args: argparse.Namespace) -> None:
|
def buildAllAssets(args: argparse.Namespace) -> None:
|
||||||
"""Build all assets."""
|
"""Build all assets."""
|
||||||
cleanBuiltAssets()
|
cleanBuiltAssets()
|
||||||
buildPdfManual()
|
|
||||||
buildSampleZip()
|
buildSampleZip()
|
||||||
buildTranslationAssets()
|
buildTranslationAssets()
|
||||||
buildDocsTranslationAssets()
|
buildPdfDocAssets()
|
||||||
return
|
return
|
||||||
|
|||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
"""
|
||||||
|
novelWriter – Documentation
|
||||||
|
===========================
|
||||||
|
|
||||||
|
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 os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from utils.common import ROOT_DIR
|
||||||
|
|
||||||
|
|
||||||
|
def updateDocsTranslationSources(args: argparse.Namespace) -> None:
|
||||||
|
"""Build the documentation .po files."""
|
||||||
|
print("")
|
||||||
|
print("Building Docs Translation Files")
|
||||||
|
print("===============================")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
docsDir = ROOT_DIR / "docs"
|
||||||
|
locsDir = ROOT_DIR / "docs" / "source" / "locales"
|
||||||
|
locsDir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
print("Generating POT Files")
|
||||||
|
subprocess.call(["make", "gettext"], cwd=docsDir)
|
||||||
|
print("")
|
||||||
|
|
||||||
|
lang = args.lang
|
||||||
|
update = []
|
||||||
|
if lang == ["all"]:
|
||||||
|
update = [i.stem for i in locsDir.iterdir() if i.is_dir()]
|
||||||
|
else:
|
||||||
|
update = lang
|
||||||
|
|
||||||
|
print("Generating PO Files")
|
||||||
|
print("Languages: ", update)
|
||||||
|
print("")
|
||||||
|
|
||||||
|
for code in update:
|
||||||
|
subprocess.call(["sphinx-intl", "update", "-p", "build/gettext", "-l", code], cwd=docsDir)
|
||||||
|
print("")
|
||||||
|
|
||||||
|
print("Done")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def buildHtmlDocs(args: argparse.Namespace | None = None) -> None:
|
||||||
|
"""Build the documentation files."""
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("Building HTML Docs")
|
||||||
|
print("==================")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
bldRoot = ROOT_DIR / "dist_doc"
|
||||||
|
docsDir = ROOT_DIR / "docs"
|
||||||
|
locsDir = ROOT_DIR / "docs" / "source" / "locales"
|
||||||
|
locsDir.mkdir(exist_ok=True)
|
||||||
|
bldRoot.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
lang = args.lang if args else ["all"]
|
||||||
|
build = []
|
||||||
|
if lang == ["all"]:
|
||||||
|
build = ["en"] + [i.stem for i in locsDir.iterdir() if i.is_dir()]
|
||||||
|
else:
|
||||||
|
build = lang
|
||||||
|
|
||||||
|
for code in build:
|
||||||
|
outDir = bldRoot / code
|
||||||
|
env = os.environ.copy()
|
||||||
|
cmd = "make clean html"
|
||||||
|
if code != "en":
|
||||||
|
data = (locsDir / f"authors_{code}.conf").read_text(encoding="utf-8")
|
||||||
|
authors = [x for x in data.splitlines() if x and not x.startswith("#")]
|
||||||
|
env["SPHINX_I18N_AUTHORS"] = ", ".join(authors)
|
||||||
|
cmd += f" -e SPHINXOPTS=\"-D language='{code}'\""
|
||||||
|
|
||||||
|
if (ex := subprocess.call(cmd, cwd=docsDir, env=env, shell=True)) == 0:
|
||||||
|
print("")
|
||||||
|
if outDir.exists():
|
||||||
|
shutil.rmtree(outDir)
|
||||||
|
outDir.mkdir()
|
||||||
|
(docsDir / "build" / "html").rename(outDir / "html")
|
||||||
|
else:
|
||||||
|
raise Exception(f"Build returned error code {ex}")
|
||||||
|
|
||||||
|
print("")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def buildPdfDocAssets(args: argparse.Namespace | None = None) -> None:
|
||||||
|
"""Build the documentation PDF files."""
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("Building Docs Manuals")
|
||||||
|
print("=====================")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
docsDir = ROOT_DIR / "docs"
|
||||||
|
locsDir = ROOT_DIR / "docs" / "source" / "locales"
|
||||||
|
pdfFile = ROOT_DIR / "docs" / "build" / "latex" / "manual.pdf"
|
||||||
|
locsDir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
lang = args.lang if args else ["all"]
|
||||||
|
build = []
|
||||||
|
if lang == ["all"]:
|
||||||
|
build = ["en"] + [i.stem for i in locsDir.iterdir() if i.is_dir()]
|
||||||
|
else:
|
||||||
|
build = lang
|
||||||
|
|
||||||
|
for code in build:
|
||||||
|
env = os.environ.copy()
|
||||||
|
cmd = "make clean latexpdf"
|
||||||
|
name = "manual.pdf"
|
||||||
|
if code != "en":
|
||||||
|
data = (locsDir / f"authors_{code}.conf").read_text(encoding="utf-8")
|
||||||
|
authors = [x for x in data.splitlines() if x and not x.startswith("#")]
|
||||||
|
env["SPHINX_I18N_AUTHORS"] = ", ".join(authors)
|
||||||
|
cmd += f" -e SPHINXOPTS=\"-D language='{code}'\""
|
||||||
|
name = f"manual_{code}.pdf"
|
||||||
|
|
||||||
|
if (ex := subprocess.call(cmd, cwd=docsDir, env=env, shell=True)) == 0:
|
||||||
|
print("")
|
||||||
|
pdfFile.rename(ROOT_DIR / "novelwriter" / "assets" / name)
|
||||||
|
else:
|
||||||
|
raise Exception(f"Build returned error code {ex}")
|
||||||
|
|
||||||
|
print("")
|
||||||
|
|
||||||
|
return
|
||||||
Reference in New Issue
Block a user