ci: use uv to install gcovr and sphinx

Change-Id: I560f2e32374e03be463c843823749de21bbe74f8
diff --git a/.jenkins b/.jenkins
index 92b9dae..1fa2f02 100755
--- a/.jenkins
+++ b/.jenkins
@@ -10,13 +10,17 @@
         fi
         export ID VERSION_ID
         export ID_LIKE="${ID} ${ID_LIKE} linux"
-        export PATH="${HOME}/.local/bin${PATH:+:}${PATH}"
+        if [[ -z $GITHUB_ACTIONS ]]; then
+            export PATH="${HOME}/.local/bin${PATH:+:}${PATH}"
+        fi
         ;;
     Darwin)
         # Emulate a subset of os-release(5)
         export ID=macos
         export VERSION_ID=$(sw_vers -productVersion)
-        export PATH="/usr/local/bin${PATH:+:}${PATH}"
+        if [[ -z $GITHUB_ACTIONS ]]; then
+            export PATH="/usr/local/bin${PATH:+:}${PATH}"
+        fi
         if [[ -x /opt/homebrew/bin/brew ]]; then
             eval "$(/opt/homebrew/bin/brew shellenv)"
         elif [[ -x /usr/local/bin/brew ]]; then
@@ -27,9 +31,9 @@
 
 export CACHE_DIR=${CACHE_DIR:-/tmp}
 
-if [[ $JOB_NAME == *"code-coverage" ]]; then
-    export DISABLE_ASAN=yes
-    export DISABLE_HEADERS_CHECK=yes
+if [[ $JOB_NAME == *code-coverage ]]; then
+    export DISABLE_ASAN=1
+    export DISABLE_HEADERS_CHECK=1
 fi
 
 # https://reproducible-builds.org/docs/source-date-epoch/
diff --git a/.jenkins.d/00-deps.sh b/.jenkins.d/00-deps.sh
index d211328..224edc6 100755
--- a/.jenkins.d/00-deps.sh
+++ b/.jenkins.d/00-deps.sh
@@ -28,22 +28,27 @@
     sqlite-devel
 )
 FORMULAE=(boost openssl pkgconf)
-PIP_PKGS=()
 case $JOB_NAME in
     *code-coverage)
-        APT_PKGS+=(lcov python3-pip)
-        PIP_PKGS+=('gcovr~=5.2')
+        APT_PKGS+=(lcov)
         ;;
     *Docs)
-        APT_PKGS+=(doxygen graphviz python3-pip)
+        APT_PKGS+=(doxygen graphviz)
         FORMULAE+=(doxygen graphviz)
-        PIP_PKGS+=(sphinx sphinxcontrib-doxylink)
         ;;
 esac
 
+install_uv() {
+    if [[ -z $GITHUB_ACTIONS && $ID_LIKE == *debian* ]]; then
+        sudo apt-get install -qy --no-install-recommends pipx
+        pipx upgrade uv || pipx install uv
+    fi
+}
+
 set -x
 
 if [[ $ID == macos ]]; then
+    export HOMEBREW_COLOR=1
     export HOMEBREW_NO_ENV_HINTS=1
     if [[ -n $GITHUB_ACTIONS ]]; then
         export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
@@ -57,6 +62,14 @@
     sudo dnf install -y "${DNF_PKGS[@]}"
 fi
 
-if (( ${#PIP_PKGS[@]} )); then
-    pip3 install --user --upgrade --upgrade-strategy=eager "${PIP_PKGS[@]}"
-fi
+case $JOB_NAME in
+    *code-coverage)
+        install_uv
+        ;;
+    *Docs)
+        install_uv
+        export FORCE_COLOR=1
+        export UV_NO_MANAGED_PYTHON=1
+        uv tool install sphinx --upgrade --with-requirements docs/requirements.txt
+        ;;
+esac
diff --git a/.jenkins.d/10-build.sh b/.jenkins.d/10-build.sh
index 5132317..347242f 100755
--- a/.jenkins.d/10-build.sh
+++ b/.jenkins.d/10-build.sh
@@ -4,13 +4,13 @@
 if [[ -z $DISABLE_ASAN ]]; then
     ASAN="--with-sanitizer=address"
 fi
-if [[ -n $GITHUB_ACTIONS && $ID == macos && ${VERSION_ID%%.*} -le 12 ]]; then
+if [[ -n $GITHUB_ACTIONS && $ID == macos && ${VERSION_ID%%.*} -le 13 ]]; then
     KEYCHAIN="--with-osx-keychain"
 fi
 
 set -x
 
-if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
+if [[ $JOB_NAME != *code-coverage && $JOB_NAME != *limited-build ]]; then
     # Build static library in release mode with tests and without precompiled headers
     ./waf --color=yes configure --enable-static --disable-shared --with-tests --without-pch
     ./waf --color=yes build
@@ -26,7 +26,7 @@
     ./waf --color=yes distclean
 fi
 
-if [[ $JOB_NAME == *"code-coverage" ]]; then
+if [[ $JOB_NAME == *code-coverage ]]; then
     # Build for coverage testing: enable instrumentation and unit tests only
     ./waf --color=yes configure --debug --with-coverage --with-unit-tests --without-tools
     ./waf --color=yes build
diff --git a/.jenkins.d/30-coverage.sh b/.jenkins.d/30-coverage.sh
index 4ee9510..740cc3b 100755
--- a/.jenkins.d/30-coverage.sh
+++ b/.jenkins.d/30-coverage.sh
@@ -1,32 +1,38 @@
 #!/usr/bin/env bash
-set -exo pipefail
+set -eo pipefail
 
-if [[ $JOB_NAME == *"code-coverage" ]]; then
-    # Generate an XML report (Cobertura format) and a detailed HTML report using gcovr
-    # Note: trailing slashes are important in the paths below. Do not remove them!
-    gcovr --object-directory build \
-          --filter ndn-cxx/ \
-          --exclude ndn-cxx/detail/nonstd/ \
-          --exclude-throw-branches \
-          --exclude-unreachable-branches \
-          --cobertura build/coverage.xml \
-          --html-details build/gcovr/ \
-          --print-summary
+[[ $JOB_NAME == *code-coverage ]] || exit 0
 
-    # Generate a detailed HTML report using lcov
-    lcov --quiet \
-         --capture \
-         --directory . \
-         --exclude "$PWD/ndn-cxx/detail/nonstd/*" \
-         --exclude "$PWD/tests/*" \
-         --no-external \
-         --rc lcov_branch_coverage=1 \
-         --output-file build/coverage.info
+export FORCE_COLOR=1
+export UV_NO_MANAGED_PYTHON=1
 
-    genhtml --branch-coverage \
-            --demangle-cpp \
-            --legend \
-            --output-directory build/lcov \
-            --title "ndn-cxx unit tests" \
-            build/coverage.info
-fi
+set -x
+
+# Generate an XML report (Cobertura format) and a detailed HTML report using gcovr
+# Note: trailing slashes are important in the paths below. Do not remove them!
+uvx gcovr@5.2 \
+    --object-directory build \
+    --filter ndn-cxx/ \
+    --exclude ndn-cxx/detail/nonstd/ \
+    --exclude-throw-branches \
+    --exclude-unreachable-branches \
+    --cobertura build/coverage.xml \
+    --html-details build/gcovr/ \
+    --print-summary
+
+# Generate a detailed HTML report using lcov
+lcov --quiet \
+     --capture \
+     --directory . \
+     --exclude "$PWD/ndn-cxx/detail/nonstd/*" \
+     --exclude "$PWD/tests/*" \
+     --no-external \
+     --rc lcov_branch_coverage=1 \
+     --output-file build/coverage.info
+
+genhtml --branch-coverage \
+        --demangle-cpp \
+        --legend \
+        --output-directory build/lcov \
+        --title "ndn-cxx unit tests" \
+        build/coverage.info
diff --git a/docs/INSTALL.rst b/docs/INSTALL.rst
index b104041..82fa64b 100644
--- a/docs/INSTALL.rst
+++ b/docs/INSTALL.rst
@@ -83,7 +83,7 @@
 
 - doxygen
 - graphviz
-- sphinx >= 4.0
+- sphinx
 - sphinxcontrib-doxylink
 
 The following lists the steps to install these prerequisites on various common platforms.
@@ -101,21 +101,21 @@
   .. code-block:: sh
 
     sudo apt install doxygen graphviz python3-pip
-    pip3 install --user sphinx sphinxcontrib-doxylink
+    python3 -m pip install --user -r docs/requirements.txt
 
 - On **CentOS** and **Fedora**:
 
   .. code-block:: sh
 
     sudo dnf install doxygen graphviz python3-pip
-    pip3 install --user sphinx sphinxcontrib-doxylink
+    python3 -m pip install --user -r docs/requirements.txt
 
 - On **macOS**:
 
   .. code-block:: sh
 
     brew install doxygen graphviz
-    sudo pip3 install sphinx sphinxcontrib-doxylink
+    python3 -m pip install --user -r docs/requirements.txt
 
 - On **FreeBSD**:
 
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..1348feb
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,3 @@
+docutils>=0.20
+sphinx>=7.0.1,<9
+sphinxcontrib-doxylink~=1.13