support doit for i18n and Sphinx docs
This commit is contained in:
@@ -48,8 +48,8 @@ jobs:
|
|||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
- run: pip install -e ".[docs]"
|
- run: pip install -e ".[dev,docs]"
|
||||||
- run: sphinx-build -b html -W --keep-going docs docs/_build/html
|
- run: doit docs
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build (${{ matrix.os }})
|
name: Build (${{ matrix.os }})
|
||||||
|
|||||||
@@ -116,12 +116,21 @@ Use `doit` for repeatable checks and package builds:
|
|||||||
```bash
|
```bash
|
||||||
pip install -e .[dev]
|
pip install -e .[dev]
|
||||||
doit list
|
doit list
|
||||||
doit wheel # build dist/nexus_sync-0.1.0-py3-none-any.whl
|
doit wheel # build dist/nexus_sync-0.1.0-py3-none-any.whl
|
||||||
doit package # build wheel and sdist
|
doit package # build wheel and sdist
|
||||||
doit # run tests, typecheck, format check, and wheel build
|
doit i18n_compile # compile nexus-cli translation catalogs
|
||||||
|
doit pyinstaller # build standalone binaries (nexus-cli bundles catalogs)
|
||||||
|
doit # run tests, typecheck, format check, and wheel build
|
||||||
```
|
```
|
||||||
|
|
||||||
PyInstaller standalone binaries are still available through Makefile targets:
|
Build the documentation (Sphinx) with the `docs` extra:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -e .[docs]
|
||||||
|
doit docs # output in docs/_build/html
|
||||||
|
```
|
||||||
|
|
||||||
|
PyInstaller standalone binaries are also available through Makefile targets:
|
||||||
|
|
||||||
```
|
```
|
||||||
make [client|server|cli]
|
make [client|server|cli]
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -6,6 +7,8 @@ DOIT_CONFIG = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PYTHON = sys.executable
|
PYTHON = sys.executable
|
||||||
|
PYBABEL = f"{PYTHON} -m babel.messages.frontend"
|
||||||
|
SPHINX = f"{PYTHON} -m sphinx"
|
||||||
PACKAGE_VERSION = "0.1.0"
|
PACKAGE_VERSION = "0.1.0"
|
||||||
WHEEL_TARGET = f"dist/nexus_sync-{PACKAGE_VERSION}-py3-none-any.whl"
|
WHEEL_TARGET = f"dist/nexus_sync-{PACKAGE_VERSION}-py3-none-any.whl"
|
||||||
SRC_FILES = list(Path("src").rglob("*.py"))
|
SRC_FILES = list(Path("src").rglob("*.py"))
|
||||||
@@ -13,6 +16,18 @@ TEST_FILES = list(Path("tests").rglob("*.py"))
|
|||||||
DOC_FILES = [Path("README.md"), *Path("docs").glob("*.md")]
|
DOC_FILES = [Path("README.md"), *Path("docs").glob("*.md")]
|
||||||
BUILD_DEPS = [Path("pyproject.toml"), Path("README.md"), *SRC_FILES]
|
BUILD_DEPS = [Path("pyproject.toml"), Path("README.md"), *SRC_FILES]
|
||||||
|
|
||||||
|
# Localization (nexus-cli catalogs only; daemon/server logs stay in English).
|
||||||
|
LOCALE_DIR = Path("src/nexus_sync/locale")
|
||||||
|
POT_FILE = LOCALE_DIR / "nexus.pot"
|
||||||
|
PO_FILES = sorted(LOCALE_DIR.rglob("*.po"))
|
||||||
|
MO_FILES = [po.with_suffix(".mo") for po in PO_FILES]
|
||||||
|
# PyInstaller --add-data separator: ';' on Windows, ':' elsewhere.
|
||||||
|
LOCALE_DATA = f"{LOCALE_DIR}{';' if os.name == 'nt' else ':'}nexus_sync/locale"
|
||||||
|
|
||||||
|
# Documentation (Sphinx).
|
||||||
|
DOCS_DIR = Path("docs")
|
||||||
|
DOCS_HTML = DOCS_DIR / "_build" / "html"
|
||||||
|
|
||||||
|
|
||||||
def task_test():
|
def task_test():
|
||||||
return {
|
return {
|
||||||
@@ -38,9 +53,51 @@ def task_format_check():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def task_i18n_extract():
|
||||||
|
"""Rebuild the .pot template from strings wrapped in _()/gettext()/ngettext()."""
|
||||||
|
return {
|
||||||
|
"actions": [f"{PYBABEL} extract -F babel.cfg -k _ -o {POT_FILE} src"],
|
||||||
|
"file_dep": [str(path) for path in SRC_FILES] + ["babel.cfg"],
|
||||||
|
"targets": [str(POT_FILE)],
|
||||||
|
"verbosity": 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def task_i18n_update():
|
||||||
|
"""Merge new/changed strings from the template into existing catalogs."""
|
||||||
|
return {
|
||||||
|
"actions": [f"{PYBABEL} update -i {POT_FILE} -d {LOCALE_DIR} -D nexus"],
|
||||||
|
"file_dep": [str(POT_FILE)],
|
||||||
|
"verbosity": 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def task_i18n_compile():
|
||||||
|
"""Compile .po catalogs into the .mo files bundled with nexus-cli."""
|
||||||
|
return {
|
||||||
|
"actions": [f"{PYBABEL} compile -d {LOCALE_DIR} -D nexus"],
|
||||||
|
"file_dep": [str(path) for path in PO_FILES],
|
||||||
|
"targets": [str(path) for path in MO_FILES],
|
||||||
|
"clean": True,
|
||||||
|
"verbosity": 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def task_docs():
|
||||||
|
"""Build the Sphinx HTML documentation (warnings are errors)."""
|
||||||
|
return {
|
||||||
|
"actions": [f"{SPHINX} -b html -W --keep-going {DOCS_DIR} {DOCS_HTML}"],
|
||||||
|
"file_dep": [str(path) for path in [*DOC_FILES, DOCS_DIR / "conf.py", *SRC_FILES]],
|
||||||
|
"targets": [str(DOCS_HTML / "index.html")],
|
||||||
|
"clean": ["rm -rf docs/_build"],
|
||||||
|
"verbosity": 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def task_wheel():
|
def task_wheel():
|
||||||
return {
|
return {
|
||||||
"actions": [f"{PYTHON} -m build --wheel"],
|
"actions": [f"{PYTHON} -m build --wheel"],
|
||||||
|
"task_dep": ["i18n_compile"],
|
||||||
"file_dep": [str(path) for path in BUILD_DEPS],
|
"file_dep": [str(path) for path in BUILD_DEPS],
|
||||||
"targets": [WHEEL_TARGET],
|
"targets": [WHEEL_TARGET],
|
||||||
"clean": True,
|
"clean": True,
|
||||||
@@ -69,9 +126,11 @@ def task_package():
|
|||||||
def task_pyinstaller_cli():
|
def task_pyinstaller_cli():
|
||||||
return {
|
return {
|
||||||
"actions": [
|
"actions": [
|
||||||
f"{PYTHON} -m PyInstaller --onefile src/nexus_sync/cli/__main__.py --name nexus-cli"
|
f"{PYTHON} -m PyInstaller --onefile src/nexus_sync/cli/__main__.py "
|
||||||
|
f'--name nexus-cli --add-data "{LOCALE_DATA}"'
|
||||||
],
|
],
|
||||||
"file_dep": [str(path) for path in BUILD_DEPS],
|
"task_dep": ["i18n_compile"],
|
||||||
|
"file_dep": [str(path) for path in [*BUILD_DEPS, *MO_FILES]],
|
||||||
"clean": True,
|
"clean": True,
|
||||||
"verbosity": 2,
|
"verbosity": 2,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,3 +43,30 @@ def test_doit_default_tasks_include_checks_and_wheel() -> None:
|
|||||||
dodo = _load_dodo()
|
dodo = _load_dodo()
|
||||||
|
|
||||||
assert dodo.DOIT_CONFIG["default_tasks"] == ["test", "typecheck", "format_check", "wheel"]
|
assert dodo.DOIT_CONFIG["default_tasks"] == ["test", "typecheck", "format_check", "wheel"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_doit_has_i18n_compile_task() -> None:
|
||||||
|
dodo = _load_dodo()
|
||||||
|
|
||||||
|
task = dodo.task_i18n_compile()
|
||||||
|
|
||||||
|
assert any("compile" in action for action in _actions(task))
|
||||||
|
assert any(target.endswith("nexus.mo") for target in task["targets"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_doit_has_docs_task() -> None:
|
||||||
|
dodo = _load_dodo()
|
||||||
|
|
||||||
|
task = dodo.task_docs()
|
||||||
|
|
||||||
|
assert any("sphinx" in action and "-W" in action for action in _actions(task))
|
||||||
|
assert "docs/conf.py" in task["file_dep"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_pyinstaller_cli_bundles_locale_catalogs() -> None:
|
||||||
|
dodo = _load_dodo()
|
||||||
|
|
||||||
|
task = dodo.task_pyinstaller_cli()
|
||||||
|
|
||||||
|
assert "i18n_compile" in task["task_dep"]
|
||||||
|
assert any("--add-data" in action and "locale" in action for action in _actions(task))
|
||||||
|
|||||||
Reference in New Issue
Block a user