Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

SOURCES=$(wildcard *.py) $(PROJECT) tests

# Env vars for the docs Starter Pack. They must be exported so make can pass them to the
# Env vars for the docs Sphinx Stack. They must be exported so make can pass them to the
# docs Makefile.
export DOCS_BUILDDIR ?= _build
export DOCS_VENVDIR ?= ../.venv
export VALE_DIR ?= $(DOCS_VENVDIR)/lib/python*/site-packages/vale
export SPHINX_AUTOBUILD_OPTS ?= --ignore "$(DOCS_VENVDIR)/*" --ignore "reference/commands/*" -D=llms_txt_enabled=0

ifneq ($(OS),Windows_NT)
OS := $(shell uname)
Expand Down
16 changes: 8 additions & 8 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# Environment
*env*/
.sphinx/venv/
.venv/

# Sphinx
.sphinx/warnings.txt
.sphinx/.wordlist.dic
.sphinx/.doctrees/
.sphinx/update/
.sphinx/node_modules/
_dev/warnings.txt
_dev/.wordlist.dic
_dev/.doctrees/
_dev/update/
_dev/node_modules/

# Vale
.sphinx/styles/*
.sphinx/vale.ini
_dev/styles/*
_dev/vale.ini

# Build outputs
_build
Expand Down
1 change: 0 additions & 1 deletion docs/.sphinx/version

This file was deleted.

84 changes: 51 additions & 33 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@
# You can set these variables from the command line, and also
# from the environment for the first two.

SPHINX_DIR ?= .sphinx
SPHINX_OPTS ?= -c . -d $(SPHINX_DIR)/.doctrees -j auto
SPHINX_BUILD ?= $(DOCS_VENVDIR)/bin/sphinx-build
SPHINX_HOST ?= 127.0.0.1
SPHINX_PORT ?= 8000
DOCS_VENVDIR ?= $(SPHINX_DIR)/venv
DOCS_VENV ?= $(DOCS_VENVDIR)/bin/activate
DOCS_SOURCEDIR ?= .
DOCS_BUILDDIR ?= _build
DOCS_PDFPACKAGES ?= latexmk fonts-freefont-otf texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended texlive-font-utils texlive-lang-cjk texlive-xetex plantuml xindy tex-gyre dvipng
DOCS_VOCAB ?= $(SPHINX_DIR)/styles/config/vocabularies/Canonical
VALE_DIR ?= $(DOCS_VENVDIR)/lib/python*/site-packages/vale
VALE_CONFIG ?= $(SPHINX_DIR)/vale.ini
PA11Y_CMD ?= $(SPHINX_DIR)/node_modules/pa11y/bin/pa11y.js --config $(SPHINX_DIR)/pa11y.json
CONFIRM_SUDO ?= N
CHECK_PATH ?= *
DEV_DIR ?= _dev
SPHINX_OPTS ?= -c . -d $(DEV_DIR)/.doctrees -j auto
SPHINX_BUILD ?= $(DOCS_VENVDIR)/bin/sphinx-build
SPHINX_HOST ?= 127.0.0.1
SPHINX_PORT ?= 8000
SPHINX_AUTOBUILD_OPTS ?= -D=llms_txt_enabled=0
DOCS_VENVDIR ?= .venv
DOCS_VENV ?= $(DOCS_VENVDIR)/bin/activate
DOCS_SOURCEDIR ?= .
DOCS_BUILDDIR ?= _build
DOCS_PDFPACKAGES ?= latexmk fonts-freefont-otf texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended texlive-font-utils texlive-lang-cjk texlive-xetex plantuml xindy tex-gyre dvipng
DOCS_VOCAB ?= $(DEV_DIR)/styles/config/vocabularies/Canonical
VALE_DIR ?= $(DOCS_VENVDIR)/lib/python*/site-packages/vale
VALE_CONFIG ?= $(DEV_DIR)/vale.ini
PA11Y_CMD ?= $(DEV_DIR)/node_modules/pa11y/bin/pa11y.js --config $(DEV_DIR)/pa11y.json
CONFIRM_SUDO ?= N
CHECK_PATH ?= $(filter-out $(DOCS_VENVDIR) $(DOCS_BUILDDIR),$(wildcard *))

# Put it first so that "make" without argument is like "make help".
help:
Expand Down Expand Up @@ -68,8 +69,8 @@ $(DOCS_VENVDIR):
pa11y-install:
@command -v $(PA11Y_CMD) >/dev/null || { \
echo "Installing \"pa11y\" from npm..."; echo; \
mkdir -p $(SPHINX_DIR)/node_modules/ ; \
npm install --prefix $(SPHINX_DIR) pa11y; \
mkdir -p $(DEV_DIR)/node_modules/ ; \
npm install --prefix $(DEV_DIR) pa11y; \
}

pymarkdownlnt-install: install
Expand All @@ -78,28 +79,28 @@ pymarkdownlnt-install: install
install: $(DOCS_VENVDIR)

run: install
. $(DOCS_VENV); $(DOCS_VENVDIR)/bin/sphinx-autobuild -b dirhtml --host $(SPHINX_HOST) --port $(SPHINX_PORT) "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS)
. $(DOCS_VENV); $(DOCS_VENVDIR)/bin/sphinx-autobuild -b dirhtml --host $(SPHINX_HOST) --port $(SPHINX_PORT) "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS) $(SPHINX_AUTOBUILD_OPTS)

# Does not depend on $(DOCS_BUILDDIR) to rebuild properly at every run.
html: install
. $(DOCS_VENV); $(SPHINX_BUILD) --fail-on-warning --keep-going -b dirhtml "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" -w $(SPHINX_DIR)/warnings.txt $(SPHINX_OPTS)
. $(DOCS_VENV); $(SPHINX_BUILD) --fail-on-warning --keep-going -b dirhtml "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" -w $(DEV_DIR)/warnings.txt $(SPHINX_OPTS)

epub: install
. $(DOCS_VENV); $(SPHINX_BUILD) -b epub "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" -w $(SPHINX_DIR)/warnings.txt $(SPHINX_OPTS)
. $(DOCS_VENV); $(SPHINX_BUILD) -b epub "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" -w $(DEV_DIR)/warnings.txt $(SPHINX_OPTS)

serve: html
cd "$(DOCS_BUILDDIR)"; python3 -m http.server --bind $(SPHINX_HOST) $(SPHINX_PORT)

clean: clean-doc
@test ! -e "$(DOCS_VENVDIR)" -o -d "$(DOCS_VENVDIR)" -a "$(abspath $(DOCS_VENVDIR))" != "$(DOCS_VENVDIR)"
rm -rf $(DOCS_VENVDIR)
rm -rf $(SPHINX_DIR)/node_modules/
rm -rf $(SPHINX_DIR)/styles
rm -rf $(DEV_DIR)/node_modules/
rm -rf $(DEV_DIR)/styles
rm -rf $(VALE_CONFIG)

clean-doc:
git clean -fx "$(DOCS_BUILDDIR)"
rm -rf $(SPHINX_DIR)/.doctrees
rm -rf $(DEV_DIR)/.doctrees

linkcheck: install
. $(DOCS_VENV) ; $(SPHINX_BUILD) -b linkcheck -q "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS) || { grep --color -F "[broken]" "$(DOCS_BUILDDIR)/output.txt"; exit 1; }
Expand All @@ -108,35 +109,52 @@ linkcheck: install
pa11y: pa11y-install html
find $(DOCS_BUILDDIR) -name *.html -print0 | xargs -n 1 -0 $(PA11Y_CMD)

# Without --return-code-scheme explicit, pymarkdownlnt returns 1 for multiple scenarios
# By using the explicit scheme, it only returns 1 when no files are found,
# which should not result in failure
lint-md: pymarkdownlnt-install
@. $(DOCS_VENV); pymarkdownlnt --config $(SPHINX_DIR)/.pymarkdown.json scan --recurse --exclude=$(SPHINX_DIR)/** $(DOCS_SOURCEDIR)
@. $(DOCS_VENV); pymarkdownlnt \
--config $(DEV_DIR)/.pymarkdown.json \
--return-code-scheme explicit \
scan \
--recurse \
--exclude=$(DEV_DIR)/** \
--exclude=$(DOCS_VENVDIR)/** \
$(DOCS_SOURCEDIR); \
status=$$?; \
if [ $$status -eq 1 ]; then \
echo "No Markdown files selected for linting"; \
exit 0; \
fi; \
echo "pymarkdownlnt exited with code $$status"; \
exit $$status;

vale-install: install
@. $(DOCS_VENV); test -f $(VALE_CONFIG) || python3 $(SPHINX_DIR)/get_vale_conf.py
@echo '.Name=="Canonical.400-Enforce-inclusive-terms"' > $(SPHINX_DIR)/styles/woke.filter
@echo '.Level=="error" and .Name!="Canonical.500-Repeated-words" and .Name!="Canonical.000-US-spellcheck"' > $(SPHINX_DIR)/styles/error.filter
@echo '.Name=="Canonical.000-US-spellcheck"' > $(SPHINX_DIR)/styles/spelling.filter
@. $(DOCS_VENV); test -f $(VALE_CONFIG) || python3 $(DEV_DIR)/get_vale_conf.py
@echo '.Name=="Canonical.400-Enforce-inclusive-terms"' > $(DEV_DIR)/styles/woke.filter
@echo '.Level=="error" and .Name!="Canonical.500-Repeated-words" and .Name!="Canonical.000-US-spellcheck"' > $(DEV_DIR)/styles/error.filter
@echo '.Name=="Canonical.000-US-spellcheck"' > $(DEV_DIR)/styles/spelling.filter
@. $(DOCS_VENV); find $(VALE_DIR)/vale_bin -size 195c -exec vale --version \;

woke: vale-install
@cat $(DOCS_VOCAB)/accept.txt > $(DOCS_VOCAB)/accept_backup.txt
@cat $(DOCS_SOURCEDIR)/.custom_wordlist.txt >> $(DOCS_VOCAB)/accept.txt
@echo "Running Vale acceptable term check against $(CHECK_PATH). To change target set CHECK_PATH= with make command"
@. $(DOCS_VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINX_DIR)/styles/woke.filter' --glob='*.{md,rst}' $(CHECK_PATH)
@. $(DOCS_VENV); vale --config="$(VALE_CONFIG)" --filter='$(DEV_DIR)/styles/woke.filter' --glob='*.{md,rst}' $(CHECK_PATH)
@cat $(DOCS_VOCAB)/accept_backup.txt > $(DOCS_VOCAB)/accept.txt && rm $(DOCS_VOCAB)/accept_backup.txt

vale: vale-install
@cat $(DOCS_VOCAB)/accept.txt > $(DOCS_VOCAB)/accept_backup.txt
@cat $(DOCS_SOURCEDIR)/.custom_wordlist.txt >> $(DOCS_VOCAB)/accept.txt
@echo "Running Vale against $(CHECK_PATH). To change target set CHECK_PATH= with make command"
@. $(DOCS_VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINX_DIR)/styles/error.filter' --glob='*.{md,rst}' $(CHECK_PATH)
@. $(DOCS_VENV); vale --config="$(VALE_CONFIG)" --filter='$(DEV_DIR)/styles/error.filter' --glob='*.{md,rst}' $(CHECK_PATH)
@cat $(DOCS_VOCAB)/accept_backup.txt > $(DOCS_VOCAB)/accept.txt && rm $(DOCS_VOCAB)/accept_backup.txt

spelling: vale-install
@cat $(DOCS_VOCAB)/accept.txt > $(DOCS_VOCAB)/accept_backup.txt
@cat $(DOCS_SOURCEDIR)/.custom_wordlist.txt >> $(DOCS_VOCAB)/accept.txt
@echo "Running Vale against $(CHECK_PATH). To change target set CHECK_PATH= with make command"
@. $(DOCS_VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINX_DIR)/styles/spelling.filter' --glob='*.{md,rst}' $(CHECK_PATH)
@. $(DOCS_VENV); vale --config="$(VALE_CONFIG)" --filter='$(DEV_DIR)/styles/spelling.filter' --glob='*.{md,rst}' $(CHECK_PATH)
@cat $(DOCS_VOCAB)/accept_backup.txt > $(DOCS_VOCAB)/accept.txt && rm $(DOCS_VOCAB)/accept_backup.txt

spellcheck: spelling
Expand Down Expand Up @@ -165,7 +183,7 @@ pdf: pdf-prep
@echo

update: install
@. $(DOCS_VENV); .sphinx/update_sp.py
@. $(DOCS_VENV); _dev/update_sp.py

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINX_OPTS).
Expand Down
18 changes: 9 additions & 9 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# Documentation subproject

The documentation build configuration is stored as its own subproject, a copy of
[Canonical's Sphinx Starter
Pack](https://github.com/canonical/sphinx-docs-starter-pack). Updating and managing this
subproject happens separately from the main app.
The documentation build configuration is stored as its own subproject, a copy of the
[Sphinx Stack](https://github.com/canonical/sphinx-stack). Updating and
managing this subproject happens separately from the main app.

The [Starter Pack documentation](https://canonical-starter-pack.readthedocs-hosted.com)
The [Sphinx Stack documentation](https://documentation.ubuntu.com/sphinx-stack)
describes the officially-supported features and provides guidance for customizing the docs.

## Update the docs subproject

The goal is to override the build configuration of the starter pack as little as
possible, so when changes come we don't have to create them. The process isn't completely automatic.
The goal is to override the build configuration of the Sphinx Stack as little as
possible, so when changes come we don't have to create them. The process isn't
completely automatic.

First, run the update script:

Expand All @@ -22,14 +22,14 @@ make docs-update
The script will inform you of the files that have changed. Go through each notification
and make the proper adjustments so the new and updated features work properly.

In `pyproject.toml`, remove everything in the `docs-starter-pack` group.
In `pyproject.toml`, remove everything in the `docs-sphinx-stack` group.

Then, sync the docs dependencies to the parent project:

```bash
make clean
make docs-setup
uv add -r docs/requirements.txt --group docs-starter-pack
uv add -r docs/requirements.txt --group docs-sphinx-stack
```

In `docs/Makefile`, make sure these lines are changed like so:
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions docs/.sphinx/get_vale_conf.py → docs/_dev/get_vale_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
datefmt='%Y-%m-%d %H:%M:%S'
)

SPHINX_DIR = os.path.join(os.getcwd(), ".sphinx")
DEV_DIR = os.path.join(os.getcwd(), "_dev")

GITHUB_REPO = "canonical/documentation-style-guide"
GITHUB_CLONE_URL = f"https://github.com/{GITHUB_REPO}.git"
Expand Down Expand Up @@ -133,7 +133,7 @@ def parse_arguments():

def main():
# Define local directory paths
vale_files_dict = {file: os.path.join(SPHINX_DIR, file) for file in VALE_FILE_LIST}
vale_files_dict = {file: os.path.join(DEV_DIR, file) for file in VALE_FILE_LIST}

# Parse command line arguments, default to overwrite_enabled = True
overwrite_enabled = not parse_arguments().no_overwrite
Expand Down
File renamed without changes.
46 changes: 22 additions & 24 deletions docs/.sphinx/update_sp.py → docs/_dev/update_sp.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#! /usr/bin/env python

# Initial update script for the starter pack.
# Initial update script for the Sphinx Stack.
#
# Requires some manual intervention, but makes identifying updates and differences easier.
#
# For debugging, please run this script with DEBUGGING=1
# e.g. user@device:~/git/Canonical/sphinx-docs-starter-pack/docs$ DEBUGGING=1 python .sphinx/update_sp.py
# e.g. user@device:~/git/Canonical/sphinx-stack/docs$ DEBUGGING=1 python _dev/update_sp.py


import glob
Expand All @@ -19,12 +19,12 @@
from packaging.version import parse as parse_version

SPHINX_DIR = os.path.abspath(os.path.dirname(__file__))
DOCS_DIR = os.path.abspath(os.path.join(SPHINX_DIR, '..'))
DOCS_DIR = os.path.abspath(os.path.join(SPHINX_DIR, ".."))
REQUIREMENTS = os.path.join(DOCS_DIR, "requirements.txt")
SPHINX_UPDATE_DIR = os.path.join(SPHINX_DIR, "update")
GITHUB_REPO = "canonical/sphinx-docs-starter-pack"
GITHUB_REPO = "canonical/sphinx-stack"
GITHUB_API_BASE = f"https://api.github.com/repos/{GITHUB_REPO}"
GITHUB_API_SPHINX_DIR = f"{GITHUB_API_BASE}/contents/docs/.sphinx"
GITHUB_API_DEV_DIR = f"{GITHUB_API_BASE}/contents/docs/_dev"
GITHUB_RAW_BASE = f"https://raw.githubusercontent.com/{GITHUB_REPO}/main"

TIMEOUT = 10 # seconds
Expand All @@ -43,7 +43,7 @@ def main():
except FileNotFoundError:
print("WARNING\nWARNING\nWARNING")
print(
"You need to update to at least version 1.0.0 of the starter pack to start using the update function."
"You need to update to at least version 1.0.0 of the Sphinx Stack to start using the update function."
)
print("You may experience issues using this functionality.")
logging.debug("No local version found. Setting version to None")
Expand All @@ -61,15 +61,15 @@ def main():
logging.debug("Comparing versions")
if parse_version(local_version) < parse_version(latest_release):
logging.debug("Local version is older than the release version.")
print("Starter pack is out of date.\n")
print("Sphinx Stack is out of date.\n")

# Identify and download '.sphinx' dir files to '.sphinx/update'
# Identify and download '_dev' dir files to '_dev/update'
files_updated, new_files = update_static_files()

# Write new version to file to '.sphinx/update'
# Write new version to file to '_dev/update'

download_file(
GITHUB_RAW_BASE + "/docs/.sphinx/version",
GITHUB_RAW_BASE + "/docs/_dev/version",
os.path.join(SPHINX_UPDATE_DIR, "version"),
)

Expand All @@ -84,8 +84,8 @@ def main():
if files_updated:
logging.debug("Updated files found and downloaded")
print("Differences have been identified in static files.")
print("Updated files have been downloaded to '.sphinx/update'.")
print("Validate and move these files into your '.sphinx/' directory.")
print("Updated files have been downloaded to '_dev/update'.")
print("Validate and move these files into your '_dev/' directory.")
else:
logging.debug("No files found to update")
# Provide information on NEW files
Expand All @@ -94,7 +94,7 @@ def main():
print(
"NOTE: New files have been downloaded\n",
"See 'NEWFILES.txt' for all downloaded files\n",
"Validate and merge these files into your '.sphinx/' directory",
"Validate and merge these files into your '_dev/' directory",
)
else:
logging.debug("No new files found to download")
Expand Down Expand Up @@ -130,19 +130,19 @@ def main():
except FileNotFoundError:
print("requirements.txt not found")
print(
"The updated starter pack has moved requirements.txt out of the '.sphinx' dir"
"The updated Sphinx Stack has moved requirements.txt out of the '_dev' dir"
)
print("requirements.txt not checked, please update your requirements manually")


def update_static_files():
"""Checks local files against remote for new and different files, downloads to '.sphinx/updates'"""
"""Checks local files against remote for new and different files, downloads to '_dev/updates'"""
files, paths = get_local_files_and_paths()
new_file_list = []

for item in query_api(GITHUB_API_SPHINX_DIR).json():
for item in query_api(GITHUB_API_DEV_DIR).json():
logging.debug(f"Checking {item['name']}")
# Checks existing files in '.sphinx' starter pack static root for changed SHA
# Checks existing files in '_dev' Sphinx Stack static root for changed SHA
if item["name"] in files and item["type"] == "file":
index = files.index(item["name"])
if item["sha"] != get_git_revision_hash(paths[index]):
Expand All @@ -154,17 +154,15 @@ def update_static_files():
# Indicate update script needs to be updated and re-run
print("WARNING")
print(
"THIS UPDATE SCRIPT IS OUT OF DATE. YOU MAY NEED TO RUN ANOTHER UPDATE AFTER UPDATING TO THE FILE IN '.sphinx/updates'."
"THIS UPDATE SCRIPT IS OUT OF DATE. YOU MAY NEED TO RUN ANOTHER UPDATE AFTER UPDATING TO THE FILE IN '_dev/updates'."
)
print("WARNING\n")
else:
logging.debug("File hashes are equal")
# Checks nested files '.sphinx/**/**.*' for changed SHA (single level of depth)
# Checks nested files '_dev/**/**.*' for changed SHA (single level of depth)
elif item["type"] == "dir":
logging.debug(item["name"] + " is a directory")
for nested_item in query_api(
f"{GITHUB_API_SPHINX_DIR}/{item['name']}"
).json():
for nested_item in query_api(f"{GITHUB_API_DEV_DIR}/{item['name']}").json():
logging.debug(f"Checking {nested_item['name']}")
if nested_item["name"] in files:
index = files.index(nested_item["name"])
Expand All @@ -189,7 +187,7 @@ def update_static_files():
SPHINX_UPDATE_DIR, item["name"], nested_item["name"]
),
)
# Downloads NEW files in '.sphinx' starter pack static root
# Downloads NEW files in '_dev' Sphinx Stack static root
else:
if item["type"] == "file":
logging.debug(f"No local version found of {item['name']}")
Expand Down Expand Up @@ -225,7 +223,7 @@ def get_git_revision_hash(file) -> str:

# Examines local files
def get_local_files_and_paths():
"""Identify '.sphinx' local files and paths"""
"""Identify '_dev' local files and paths"""
logging.debug("Checking local files and paths")
try:
files = []
Expand Down
Loading
Loading