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
18 changes: 3 additions & 15 deletions .github/workflows/users-guide.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ on:
paths:
- 'doc/Makefile'
- 'doc/pyproject.toml'
- 'doc/requirements.in'
- 'doc/*.inc'
- 'doc/*.py'
- 'doc/*.rst'
Expand All @@ -24,7 +23,6 @@ on:
paths:
- 'doc/Makefile'
- 'doc/pyproject.toml'
- 'doc/requirements.in'
- 'doc/*.inc'
- 'doc/*.py'
- 'doc/*.rst'
Expand Down Expand Up @@ -56,18 +54,8 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install pip-compile
run: |
pip install pip-tools

- name: Create requirements.txt from requirements.in
run: |
make users-guide-requirements

# Subsumed by make users-guide
# - name: Install dependencies
# run: |
# pip install -r doc/requirements.txt
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v7

- name: Build User's Guide in HTML
run: |
Expand All @@ -78,7 +66,7 @@ jobs:
name: users-guide-html
path: html/

- name: Check security of requirements.txt
- name: Check security of requirements (dependencies)
env:
SKJOLD_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ cabal-testsuite/**/haddocks
venv
.venv
/doc/.skjold_cache/
/doc/requirements.txt

# macOS folder metadata
.DS_Store
Expand Down
16 changes: 9 additions & 7 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ build:
tools:
python: "3.13"
jobs:
post_create_environment:
- pip install pip-tools
- make users-guide-requirements

python:
install:
- requirements: doc/requirements.txt
pre_create_environment:
- asdf plugin add uv
- asdf install uv latest
- asdf global uv latest
install:
- uv sync --project doc
build:
html:
- uv run --project doc sphinx-build -n -W --keep-going -E -T -d _build/doctrees -D language=en doc "${READTHEDOCS_OUTPUT}/html"
4 changes: 0 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -286,10 +286,6 @@ bootstrap-jsons: $(BOOTSTRAP_GHC_VERSIONS:%=bootstrap-json-%)
users-guide: ## Build the users guide.
$(MAKE) -C doc users-guide

.PHONY: users-guide-requirements
users-guide-requirements: ## Install the requirements for building the users guide.
$(MAKE) -C doc users-guide-requirements

ifeq ($(shell uname), Darwin)
PROCS := $(shell sysctl -n hw.logicalcpu)
else
Expand Down
12 changes: 12 additions & 0 deletions changelog.d/11382.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
synopsis: Replace pip with uv for building users guide
packages: [cabal-install]
prs: 11382
---

Aside from being faster, by using uv to build the user guide:

* We don't have to explicitly activate a python virtual environment, either in the shell or in our makefile.
* A clean git clone can `make users-guide` without first `make users-guide-requirements`.
* We require fewer variables, targets and recipes in the the makefiles.
* The `make users-guide` recipe output is much shorter as it doesn't include lengthy pip output.
45 changes: 8 additions & 37 deletions doc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,27 @@
#
#
SKJOLD_GITHUB_API_TOKEN ?= ${GITHUB_TOKEN}
# TODO: when we have sphinx-build2 ?
SPHINXCMD:=sphinx-build
# Flag -n ("nitpick") warns about broken references
# Flag -W turns warnings into errors
# Flag --keep-going continues after errors
SPHINX_FLAGS:=-n -W --keep-going -E
SPHINX_HTML_OUTDIR:=../dist-newstyle/doc/users-guide
USERGUIDE_STAMP:=$(SPHINX_HTML_OUTDIR)/index.html
PYTHON_VIRTUALENV_ACTIVATE:=../.python-sphinx-virtualenv/bin/activate

# Python virtual environment
##############################################################################

# Create a python virtual environment in the root of the cabal repository.
$(PYTHON_VIRTUALENV_ACTIVATE):
python3 -m venv ../.python-sphinx-virtualenv
(. $(PYTHON_VIRTUALENV_ACTIVATE))

# Users guide
##############################################################################

# do pip install every time so we have up to date requirements when we build
users-guide: $(PYTHON_VIRTUALENV_ACTIVATE) $(USERGUIDE_STAMP)
users-guide: $(USERGUIDE_STAMP)
$(USERGUIDE_STAMP) : *.rst
mkdir -p $(SPHINX_HTML_OUTDIR)
(. $(PYTHON_VIRTUALENV_ACTIVATE) && pip install -r requirements.txt && $(SPHINXCMD) $(SPHINX_FLAGS) . $(SPHINX_HTML_OUTDIR))
mkdir -p $(SPHINX_HTML_OUTDIR) \
&& uv sync \
&& uv run sphinx-build $(SPHINX_FLAGS) . $(SPHINX_HTML_OUTDIR)

# Requirements
##############################################################################

##
# This goal is intended for manual invocation, always rebuilds.
.PHONY: users-guide-requirements
users-guide-requirements: requirements.txt

.PHONY: build-and-check-requirements
build-and-check-requirements: requirements.txt check-requirements

# Always rebuild requirements.txt
.PHONY: requirements.txt
# requirements.txt is generated from requirements.in
# via pip-compile included in the pip-tools package.
# See https://modelpredict.com/wht-requirements-txt-is-not-enough
requirements.txt: requirements.in $(PYTHON_VIRTUALENV_ACTIVATE)
. $(PYTHON_VIRTUALENV_ACTIVATE) \
&& pip install --upgrade 'pip!=25.3' \
&& pip install pip-tools \
&& pip-compile requirements.in
requirements.txt:
uv export --frozen --format requirements.txt > requirements.txt

# Check requirements.txt for security violations via skjold,
# configured in pyproject.toml.
Expand All @@ -71,10 +44,8 @@ check-requirements:
echo "WARNING: Neither SKJOLD_GITHUB_API_TOKEN nor GITHUB_TOKEN is set." \
; echo "Vulnerability check via skjold might fail when using the GitHub GraphQL API." \
; fi
. $(PYTHON_VIRTUALENV_ACTIVATE) \
&& pip install skjold \
&& skjold audit
# NB: For portability, we use '.' (sh etc.) instead of 'source' (bash).
uvx skjold -c pyproject.toml config \
&& uv pip list --format freeze | uvx skjold -c pyproject.toml audit

# Debug print environment variables
debug:
Expand Down
39 changes: 26 additions & 13 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ http://cabal.readthedocs.io/

### How to build it

Building the documentation requires Python 3, PIP, and `pip-tools` (see the second note below for how to install it). Run the following command either from the root of the cabal repository or from the `docs/` subdirectory:
Building the documentation requires uv and Python 3. Run the following command
either from the root of the cabal repository or from the `docs/` subdirectory:

``` console
> make users-guide
Expand All @@ -20,25 +21,37 @@ Building the documentation requires Python 3, PIP, and `pip-tools` (see the seco
Note: Python on Mac OS X dislikes `LC_CTYPE=UTF-8`, so unset the variable
and instead set `LC_ALL=en_US.UTF-8`.

Note: You can use a vendor package for `pip-tools`, or run

``` console
> pip install pip-tools
```

Make sure the installation directory (often `$HOME/.local/bin`) is on your `$PATH`.

### How to update dependencies

The list of transitive dependencies (`requirements.txt`) is generated from the list of direct dependencies in `requirements.in`. To perform the generation step, run
The list of transitive dependencies (`requirements.txt`) is generated from the
list of direct dependencies in `pyproject.toml`. Find outdated dependencies with:

```console
> make users-guide-requirements
> cd doc
> uv pip list --outdated
Package Version Latest Type
------------------ ---------- -------- -----
certifi 2025.11.12 2026.1.4 wheel
docutils 0.21.2 0.22.4 wheel
sphinx 8.2.3 9.1.0 wheel
sphinxnotes-strike 1.5 2.0 wheel
urllib3 2.6.2 2.6.3 wheel
```

either from the root of the cabal repository or from the `docs/` subdirectory. You will need to do this before building documentation the first time, but should only need to repeat it after a `git clean` or if the dependencies in `requirements.in` change.
Upgrade the lock file to the latest satisfiable requirements with:

```console
> uv sync --upgrade
...
- certifi==2025.11.12
+ certifi==2026.1.4
- sphinxnotes-strike==1.5
+ sphinxnotes-strike==2.0
- urllib3==2.6.2
+ urllib3==2.6.3
```

In some cases, you may have to add a bound manually to `requirements.in`, e.g. `requests >= 2.31.0`.
In some cases, you may have to add a bound manually to `pyproject.toml`, e.g. `requests >= 2.31.0`.

### How to check spelling

Expand Down
24 changes: 12 additions & 12 deletions doc/cabaldomain.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
import pygments.lexer as lexer
import pygments.token as token

from distutils.version import StrictVersion
from packaging.version import Version

from sphinx import addnodes
from sphinx.directives import ObjectDescription
Expand All @@ -131,7 +131,7 @@ def parse_deprecated(txt):
if txt is None:
return True
try:
return StrictVersion(txt)
return Version(txt)
except ValueError:
return True

Expand Down Expand Up @@ -218,8 +218,8 @@ class CabalSection(Directive):
option_spec = {
'name': lambda x: x,
'deprecated': parse_deprecated,
'removed': StrictVersion,
'since' : StrictVersion,
'removed': Version,
'since' : Version,
'synopsis' : lambda x:x,
}
section_key = 'cabal:pkg-section'
Expand Down Expand Up @@ -281,8 +281,8 @@ class CabalObject(ObjectDescription):
option_spec = {
'noindex' : directives.flag,
'deprecated': parse_deprecated,
'removed' : StrictVersion,
'since' : StrictVersion,
'removed' : Version,
'since' : Version,
'synopsis' : lambda x:x
}

Expand Down Expand Up @@ -408,7 +408,7 @@ def run(self):
if self.cabal_meta.deprecated is not None:
field = nodes.field('')
field_name = nodes.field_name('Deprecated', 'Deprecated')
if isinstance(self.cabal_meta.deprecated, StrictVersion):
if isinstance(self.cabal_meta.deprecated, Version):
since = 'Cabal ' + str(self.cabal_meta.deprecated)
else:
since = ''
Expand All @@ -421,7 +421,7 @@ def run(self):
if self.cabal_meta.removed is not None:
field = nodes.field('')
field_name = nodes.field_name('Removed', 'Removed')
if isinstance(self.cabal_meta.removed, StrictVersion):
if isinstance(self.cabal_meta.removed, Version):
since = 'Cabal ' + str(self.cabal_meta.removed)
else:
since = ''
Expand Down Expand Up @@ -480,8 +480,8 @@ class CabalField(CabalObject):
option_spec = {
'noindex' : directives.flag,
'deprecated': parse_deprecated,
'removed' : StrictVersion,
'since' : StrictVersion,
'removed' : Version,
'since' : Version,
'synopsis' : lambda x:x
}

Expand Down Expand Up @@ -752,13 +752,13 @@ def make_data_keys(typ, target, node):


def render_deprecated(deprecated):
if isinstance(deprecated, StrictVersion):
if isinstance(deprecated, Version):
return 'deprecated since: '+str(deprecated)
else:
return 'deprecated'

def render_removed(deprecated, removed):
if isinstance(deprecated, StrictVersion):
if isinstance(deprecated, Version):
return 'removed in: ' + str(removed) + '; deprecated since: '+str(deprecated)
else:
return 'removed in: ' + str(removed)
Expand Down
2 changes: 1 addition & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['.build', "*.gen.rst"]
exclude_patterns = ['.build', '*.gen.rst', '.venv']

# -- Options for HTML output ---------------------------------------------

Expand Down
22 changes: 22 additions & 0 deletions doc/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,25 @@ verbose = true
cache_dir = '.skjold_cache'
cache_expires = 43200 # Cache max. age. (43200 = 12hrs)
ignore_file = '.skjoldignore'

# CVE suggestions
# certifi>=2023.07.22 by CVE-2023-37920
# idna>=3.7 by CVE-2024-3651
# jinja2>=3.1.4 by CVE-2024-34064
# pygments>=2.7.4 by CVE-2021-20270 CVE-2021-27291
# requests>=2.32.0 by CVE-2024-35195
# urllib3>=2.0.7 by CVE-2023-45803
[dependency-groups]
dev = [
"certifi>=2023.7.22",
"idna>=3.7",
"jinja2>=3.1.4",
"packaging>=25.0",
"pygments>=2.7.4",
"requests>=2.32.0",
"sphinx>=8.2.3",
"sphinx-jsonschema>=1.19.2",
"sphinx-rtd-theme>=3.0.2",
"sphinxnotes-strike>=1.5",
"urllib3>=2.0.7",
]
16 changes: 0 additions & 16 deletions doc/requirements.in

This file was deleted.

Loading
Loading