From 77cc60ce0fe0cbcf7b7d0478f1c4e9f2ba6b3806 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Mon, 16 Nov 2020 17:58:29 +0100 Subject: [PATCH 01/18] Pin tooling revisions --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 2ffd4262..651b110d 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -31,7 +31,7 @@ jobs: python-version: 3.7 - name: Install dependencies run: | - pip install Sphinx fluent.pygments + pip install Sphinx==3.0.3 fluent.pygments==1.0 - name: sphinx-build run: | ./scripts/build-docs --to-publish python-fluent From 9188b48df98ffdf80524d645c9b2abab51f3020b Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Mon, 16 Nov 2020 18:00:11 +0100 Subject: [PATCH 02/18] Remove unused files --- docs/Makefile | 20 ----- fluent.runtime/docs/Makefile | 19 ----- fluent.runtime/docs/conf.py | 143 ----------------------------------- fluent.syntax/docs/Makefile | 20 ----- fluent.syntax/docs/conf.py | 65 ---------------- 5 files changed, 267 deletions(-) delete mode 100644 docs/Makefile delete mode 100644 fluent.runtime/docs/Makefile delete mode 100644 fluent.runtime/docs/conf.py delete mode 100644 fluent.syntax/docs/Makefile delete mode 100644 fluent.syntax/docs/conf.py diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d4bb2cbb..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/fluent.runtime/docs/Makefile b/fluent.runtime/docs/Makefile deleted file mode 100644 index 51285967..00000000 --- a/fluent.runtime/docs/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/fluent.runtime/docs/conf.py b/fluent.runtime/docs/conf.py deleted file mode 100644 index 4cb314c3..00000000 --- a/fluent.runtime/docs/conf.py +++ /dev/null @@ -1,143 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/master/config - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys -sys.path.insert(0, os.path.abspath('..')) - - -# -- Project information ----------------------------------------------------- - -project = 'fluent.runtime' -copyright = '2020' - -# The short X.Y version -version = '0.3' -# The full version, including alpha/beta/rc tags -release = '0.3' - - -# -- General configuration --------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.intersphinx', - 'sphinx.ext.viewcode', - 'sphinx.ext.autodoc', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = None - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} - - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'fluentruntimedoc' - - -# -- Options for LaTeX output ------------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, - -# -- Extension configuration ------------------------------------------------- - -# -- Options for intersphinx extension --------------------------------------- - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} - -# -- Options for autodoc extension -------------------------------------------- - -autodoc_mock_imports = [ - 'attr', -] diff --git a/fluent.syntax/docs/Makefile b/fluent.syntax/docs/Makefile deleted file mode 100644 index d4bb2cbb..00000000 --- a/fluent.syntax/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/fluent.syntax/docs/conf.py b/fluent.syntax/docs/conf.py deleted file mode 100644 index 57e03b94..00000000 --- a/fluent.syntax/docs/conf.py +++ /dev/null @@ -1,65 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. - -import os -import sys -sys.path.insert(0, os.path.abspath('..')) - - -# -- Project information ----------------------------------------------------- - -project = 'Fluent Syntax' -copyright = '2020' - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.intersphinx', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'nature' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - - -# -- Extension configuration ------------------------------------------------- - -# -- Options for intersphinx extension --------------------------------------- - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/3/': None} - -# -- Options for autodoc extension ------------------------------------------- - -autodoc_member_order = 'bysource' From b6dd1e9148876f94be6cdf9a59da268d95ccdfd8 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Mon, 16 Nov 2020 19:21:54 +0100 Subject: [PATCH 03/18] Add publishing step --- .github/workflows/documentation.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 651b110d..bec6421c 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -40,3 +40,23 @@ jobs: with: name: html path: _build/python-fluent + + publish: + name: publish + needs: [build] + # if: github.event_name == 'push' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Download artifact + uses: actions/download-artifact@v2 + with: + name: html + path: _build + - name: Deploy 🚀 + uses: JamesIves/github-pages-deploy-action@releases/v4 + with: + branch: gh-pages # The branch the action should deploy to. + folder: _build # The folder the action should deploy. + clean: true # Automatically remove deleted files from the deploy branch + dry_run: ${{ github.event_name == 'pull_request' }} From adf0b248c7a6bf4d1de8201ca3af2a16d2f64e4d Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Fri, 18 Dec 2020 12:47:43 +0100 Subject: [PATCH 04/18] Allow manual trigger, and fetch full depth --- .github/workflows/documentation.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index bec6421c..5bb48135 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -1,6 +1,7 @@ name: documentation on: + workflow_dispatch: # Trigger the workflow on push or pull request, # but only for the master branch push: @@ -26,6 +27,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - uses: actions/setup-python@v2 with: python-version: 3.7 From aaaae9604e7d8a204c396d2d0c01688de1ee8726 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Sun, 20 Dec 2020 17:48:30 +0100 Subject: [PATCH 05/18] Refactor actual docs build code into fluent.docs --- .github/workflows/documentation.yml | 2 +- fluent.docs/README.rst | 5 +++ fluent.docs/fluent/__init__.py | 1 + fluent.docs/fluent/docs/__init__.py | 56 +++++++++++++++++++++++++++++ fluent.docs/setup.cfg | 2 ++ fluent.docs/setup.py | 6 ++++ scripts/build-docs | 56 +---------------------------- 7 files changed, 72 insertions(+), 56 deletions(-) create mode 100644 fluent.docs/README.rst create mode 100644 fluent.docs/fluent/__init__.py create mode 100755 fluent.docs/fluent/docs/__init__.py create mode 100644 fluent.docs/setup.cfg create mode 100644 fluent.docs/setup.py diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 5bb48135..60f7f5bb 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -34,7 +34,7 @@ jobs: python-version: 3.7 - name: Install dependencies run: | - pip install Sphinx==3.0.3 fluent.pygments==1.0 + pip install Sphinx==3.0.3 fluent.pygments==1.0 ./fluent.docs - name: sphinx-build run: | ./scripts/build-docs --to-publish python-fluent diff --git a/fluent.docs/README.rst b/fluent.docs/README.rst new file mode 100644 index 00000000..df742cce --- /dev/null +++ b/fluent.docs/README.rst @@ -0,0 +1,5 @@ +``fluent.docs`` +--------------- + +Python utilities used by the ``python-fluent`` documentation build +process. diff --git a/fluent.docs/fluent/__init__.py b/fluent.docs/fluent/__init__.py new file mode 100644 index 00000000..69e3be50 --- /dev/null +++ b/fluent.docs/fluent/__init__.py @@ -0,0 +1 @@ +__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/fluent.docs/fluent/docs/__init__.py b/fluent.docs/fluent/docs/__init__.py new file mode 100755 index 00000000..01becfbd --- /dev/null +++ b/fluent.docs/fluent/docs/__init__.py @@ -0,0 +1,56 @@ +from configparser import ConfigParser +import os +from pathlib import Path +import subprocess + + +def get_version(root): + if root == '.': + return + cp = ConfigParser() + cp.read(Path(root) / 'setup.cfg') + return cp.get('metadata', 'version') + + +def build(repo_name, doc_roots): + for doc_root in doc_roots: + env = os.environ.copy() + version = get_version(doc_root) + cmd = [ + 'sphinx-build', + '-c', 'docs', + '-a', '-E', '-W', + '-A', 'root_url=/' + repo_name, + '-d', '_build/doctrees/' + doc_root, + ] + if version: + env['PYTHONPATH'] = doc_root + cmd += [ + '-D', 'release=' + version, + '-D', 'project=' + doc_root, + ] + build_dir = '_build/' + repo_name + '/' + doc_root + '/stable' + else: + build_dir = '_build/' + repo_name + cmd += [ + doc_root + '/docs', + build_dir, + ] + subprocess.check_call(' '.join(cmd), env=env, shell=True) + if build_dir.endswith('/stable'): + with open(build_dir.replace('/stable', '/index.html'), 'w') as index: + index.write('\n') + + +def pre_pub(repo_name): + """Prepare staging area for publishing on Github pages.""" + root = Path('_build') / repo_name + # Ensure `.nojekyll` + with open(root / '.nojekyll', 'w') as fh: + fh.write('') + # Remove static files from subprojects, but leave + # `documentation_options.js` alone. That's per project, probably. + # We built to root/fluent.*/stable, so glob that. + for staticfile in root.glob('fluent.*/stable/_static/*'): + if staticfile.name != 'documentation_options.js': + staticfile.unlink() diff --git a/fluent.docs/setup.cfg b/fluent.docs/setup.cfg new file mode 100644 index 00000000..aa079ec5 --- /dev/null +++ b/fluent.docs/setup.cfg @@ -0,0 +1,2 @@ +[flake8] +max-line-length=120 diff --git a/fluent.docs/setup.py b/fluent.docs/setup.py new file mode 100644 index 00000000..6a2dea31 --- /dev/null +++ b/fluent.docs/setup.py @@ -0,0 +1,6 @@ +from setuptools import setup + +setup( + name='fluent.docs', + packages=['fluent', 'fluent.docs'], +) diff --git a/scripts/build-docs b/scripts/build-docs index a1b39533..51496404 100755 --- a/scripts/build-docs +++ b/scripts/build-docs @@ -1,62 +1,8 @@ #!/usr/bin/env python3 import argparse -from configparser import ConfigParser -import os -from pathlib import Path -import subprocess - -def get_version(root): - if root == '.': - return - cp = ConfigParser() - cp.read(Path(root) / 'setup.cfg') - return cp.get('metadata', 'version') - - -def build(repo_name, doc_roots): - for doc_root in doc_roots: - env = os.environ.copy() - version = get_version(doc_root) - cmd = [ - 'sphinx-build', - '-c', 'docs', - '-a', '-E', '-W', - '-A', 'root_url=/' + repo_name, - '-d', '_build/doctrees/' + doc_root, - ] - if version: - env['PYTHONPATH'] = doc_root - cmd += [ - '-D', 'release=' + version, - '-D', 'project=' + doc_root, - ] - build_dir = '_build/' + repo_name + '/' + doc_root + '/stable' - else: - build_dir = '_build/' + repo_name - cmd += [ - doc_root + '/docs', - build_dir, - ] - subprocess.check_call(' '.join(cmd), env=env, shell=True) - if build_dir.endswith('/stable'): - with open(build_dir.replace('/stable', '/index.html'), 'w') as index: - index.write('\n') - - -def pre_pub(repo_name): - """Prepare staging area for publishing on Github pages.""" - root = Path('_build') / repo_name - # Ensure `.nojekyll` - with open(root / '.nojekyll', 'w') as fh: - fh.write('') - # Remove static files from subprojects, but leave - # `documentation_options.js` alone. That's per project, probably. - # We built to root/fluent.*/stable, so glob that. - for staticfile in root.glob('fluent.*/stable/_static/*'): - if staticfile.name != 'documentation_options.js': - staticfile.unlink() +from fluent.docs import build, pre_pub if __name__ == "__main__": From fdd396f7f69c2130c5cf31c86ac64fefb7b95e17 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Wed, 23 Dec 2020 16:01:05 +0100 Subject: [PATCH 06/18] factor build into its own module --- fluent.docs/fluent/docs/__init__.py | 43 ++++------------------------- fluent.docs/fluent/docs/build.py | 42 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 38 deletions(-) create mode 100644 fluent.docs/fluent/docs/build.py diff --git a/fluent.docs/fluent/docs/__init__.py b/fluent.docs/fluent/docs/__init__.py index 01becfbd..b2909c0a 100755 --- a/fluent.docs/fluent/docs/__init__.py +++ b/fluent.docs/fluent/docs/__init__.py @@ -1,45 +1,12 @@ -from configparser import ConfigParser -import os from pathlib import Path -import subprocess +from .build import build -def get_version(root): - if root == '.': - return - cp = ConfigParser() - cp.read(Path(root) / 'setup.cfg') - return cp.get('metadata', 'version') - -def build(repo_name, doc_roots): - for doc_root in doc_roots: - env = os.environ.copy() - version = get_version(doc_root) - cmd = [ - 'sphinx-build', - '-c', 'docs', - '-a', '-E', '-W', - '-A', 'root_url=/' + repo_name, - '-d', '_build/doctrees/' + doc_root, - ] - if version: - env['PYTHONPATH'] = doc_root - cmd += [ - '-D', 'release=' + version, - '-D', 'project=' + doc_root, - ] - build_dir = '_build/' + repo_name + '/' + doc_root + '/stable' - else: - build_dir = '_build/' + repo_name - cmd += [ - doc_root + '/docs', - build_dir, - ] - subprocess.check_call(' '.join(cmd), env=env, shell=True) - if build_dir.endswith('/stable'): - with open(build_dir.replace('/stable', '/index.html'), 'w') as index: - index.write('\n') +__all__ = [ + 'build', + 'pre_pub', +] def pre_pub(repo_name): diff --git a/fluent.docs/fluent/docs/build.py b/fluent.docs/fluent/docs/build.py new file mode 100644 index 00000000..30c0247d --- /dev/null +++ b/fluent.docs/fluent/docs/build.py @@ -0,0 +1,42 @@ +from configparser import ConfigParser +import os +from pathlib import Path +import subprocess + + +def get_version(root): + if root == '.': + return + cp = ConfigParser() + cp.read(Path(root) / 'setup.cfg') + return cp.get('metadata', 'version') + + +def build(repo_name, doc_roots): + for doc_root in doc_roots: + env = os.environ.copy() + version = get_version(doc_root) + cmd = [ + 'sphinx-build', + '-c', 'docs', + '-a', '-E', '-W', + '-A', 'root_url=/' + repo_name, + '-d', '_build/doctrees/' + doc_root, + ] + if version: + env['PYTHONPATH'] = doc_root + cmd += [ + '-D', 'release=' + version, + '-D', 'project=' + doc_root, + ] + build_dir = '_build/' + repo_name + '/' + doc_root + '/stable' + else: + build_dir = '_build/' + repo_name + cmd += [ + doc_root + '/docs', + build_dir, + ] + subprocess.check_call(' '.join(cmd), env=env, shell=True) + if build_dir.endswith('/stable'): + with open(build_dir.replace('/stable', '/index.html'), 'w') as index: + index.write('\n') From 5281b513b1e00e1ffbffd31ef0109cfc395bfb87 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Fri, 25 Dec 2020 19:58:52 +0100 Subject: [PATCH 07/18] Refactor build code. Use classes for builders, use subclassing instead of code-flow ifs to distinguish the top-level builder from the project builders. This is in preparation for doing project builders per version. --- .github/workflows/documentation.yml | 2 +- fluent.docs/fluent/docs/__init__.py | 23 ------ fluent.docs/fluent/docs/build.py | 117 +++++++++++++++++++++++----- scripts/build-docs | 8 +- 4 files changed, 99 insertions(+), 51 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 60f7f5bb..9758f97b 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -37,7 +37,7 @@ jobs: pip install Sphinx==3.0.3 fluent.pygments==1.0 ./fluent.docs - name: sphinx-build run: | - ./scripts/build-docs --to-publish python-fluent + ./scripts/build-docs python-fluent - name: artifact uses: actions/upload-artifact@v2 with: diff --git a/fluent.docs/fluent/docs/__init__.py b/fluent.docs/fluent/docs/__init__.py index b2909c0a..e69de29b 100755 --- a/fluent.docs/fluent/docs/__init__.py +++ b/fluent.docs/fluent/docs/__init__.py @@ -1,23 +0,0 @@ -from pathlib import Path - -from .build import build - - -__all__ = [ - 'build', - 'pre_pub', -] - - -def pre_pub(repo_name): - """Prepare staging area for publishing on Github pages.""" - root = Path('_build') / repo_name - # Ensure `.nojekyll` - with open(root / '.nojekyll', 'w') as fh: - fh.write('') - # Remove static files from subprojects, but leave - # `documentation_options.js` alone. That's per project, probably. - # We built to root/fluent.*/stable, so glob that. - for staticfile in root.glob('fluent.*/stable/_static/*'): - if staticfile.name != 'documentation_options.js': - staticfile.unlink() diff --git a/fluent.docs/fluent/docs/build.py b/fluent.docs/fluent/docs/build.py index 30c0247d..29969778 100644 --- a/fluent.docs/fluent/docs/build.py +++ b/fluent.docs/fluent/docs/build.py @@ -14,29 +14,106 @@ def get_version(root): def build(repo_name, doc_roots): for doc_root in doc_roots: - env = os.environ.copy() version = get_version(doc_root) - cmd = [ + src_dir = doc_root + project = doc_root if doc_root != '.' else None + if project is not None: + version = get_version(project) + builder = ProjectBuilder(repo_name, src_dir, project, version) + else: + builder = DocBuilder(repo_name, src_dir) + with builder: + builder.build() + root = Path('_build') / repo_name + with open(root / '.nojekyll', 'w') as fh: + fh.write('') + for project in doc_roots: + if project == '.': + continue + with open(f'_build/{repo_name}/{project}/index.html', 'w') as index: + index.write('\n') + + +class DocBuilder: + '''Builder for the top-level documentation. + ''' + build_dir = '_build/doctrees' + + def __init__(self, repo_name, src_dir): + self.repo_name = repo_name + self.src_dir = src_dir + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + return False + + def build(self): + cmd = self.command() + env = self.environ() + subprocess.check_call(cmd, env=env) + + def command(self): + return self.cmd_prefix + self.cmd_opts + [ + f'{self.src_dir}/docs', + self.dest_dir, + ] + + def environ(self): + return os.environ.copy() + + @property + def cmd_prefix(self): + return [ 'sphinx-build', '-c', 'docs', '-a', '-E', '-W', - '-A', 'root_url=/' + repo_name, - '-d', '_build/doctrees/' + doc_root, + '-A', 'root_url=/' + self.repo_name, + '-d', self.doc_tree, ] - if version: - env['PYTHONPATH'] = doc_root - cmd += [ - '-D', 'release=' + version, - '-D', 'project=' + doc_root, + + @property + def cmd_opts(self): + return [] + + @property + def dest_dir(self): + return f'_build/{self.repo_name}' + + @property + def doc_tree(self): + return '_build/doctrees' + + +class ProjectBuilder(DocBuilder): + '''Builder for individual projects, with project name and version. + ''' + def __init__(self, repo_name, src_dir, project_name, version): + super().__init__(repo_name, src_dir) + self.project_name = project_name + self.version = version + + def __exit__(self, exc_type, exc_val, exc_tb): + # Remove static theme files from project static, they're + # used from the top-level _static. + for staticfile in Path(self.dest_dir).glob('_static/*'): + # The options are project-specific. + if staticfile.name != 'documentation_options.js': + staticfile.unlink() + + def environ(self): + env = super().environ() + env['PYTHONPATH'] = self.src_dir + return env + + @property + def cmd_opts(self): + return [ + '-D', 'release=' + self.version, + '-D', 'project=' + self.project_name, ] - build_dir = '_build/' + repo_name + '/' + doc_root + '/stable' - else: - build_dir = '_build/' + repo_name - cmd += [ - doc_root + '/docs', - build_dir, - ] - subprocess.check_call(' '.join(cmd), env=env, shell=True) - if build_dir.endswith('/stable'): - with open(build_dir.replace('/stable', '/index.html'), 'w') as index: - index.write('\n') + + @property + def dest_dir(self): + return f'_build/{self.repo_name}/{self.project_name}/stable' diff --git a/scripts/build-docs b/scripts/build-docs index 51496404..d400cc23 100755 --- a/scripts/build-docs +++ b/scripts/build-docs @@ -2,7 +2,7 @@ import argparse -from fluent.docs import build, pre_pub +from fluent.docs.build import build if __name__ == "__main__": @@ -11,10 +11,6 @@ if __name__ == "__main__": 'repo_name', help='URL prefix on the web. Repo name on gh-pages' ) - parser.add_argument( - '--to-publish', dest='pre_pub', action='store_true', - help='Use this to publish to Github. Builds faster without.' - ) default_docs = ['.', 'fluent.syntax', 'fluent.pygments', 'fluent.runtime'] parser.add_argument( '--doc', action='append', choices=default_docs, @@ -24,5 +20,3 @@ if __name__ == "__main__": if args.doc is None: args.doc = default_docs build(args.repo_name, args.doc) - if args.pre_pub: - pre_pub(args.repo_name) From a14be4de246e095a693cbc728a501ff0b9e96abf Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Tue, 29 Dec 2020 10:40:56 +0100 Subject: [PATCH 08/18] Factor root doc building into a separate code flow --- fluent.docs/fluent/docs/__init__.py | 13 +++++++++++++ fluent.docs/fluent/docs/build.py | 14 +++----------- scripts/build-docs | 7 ++++++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/fluent.docs/fluent/docs/__init__.py b/fluent.docs/fluent/docs/__init__.py index e69de29b..d5ca3afa 100755 --- a/fluent.docs/fluent/docs/__init__.py +++ b/fluent.docs/fluent/docs/__init__.py @@ -0,0 +1,13 @@ +from pathlib import Path +from .build import DocBuilder + + +def finalize_builddir(repo_name): + root = Path('_build') / repo_name + with open(root / '.nojekyll', 'w') as fh: + fh.write('') + + +def build_root(repo_name): + with DocBuilder(repo_name, '.') as builder: + builder.build() diff --git a/fluent.docs/fluent/docs/build.py b/fluent.docs/fluent/docs/build.py index 29969778..321e8221 100644 --- a/fluent.docs/fluent/docs/build.py +++ b/fluent.docs/fluent/docs/build.py @@ -16,20 +16,12 @@ def build(repo_name, doc_roots): for doc_root in doc_roots: version = get_version(doc_root) src_dir = doc_root - project = doc_root if doc_root != '.' else None - if project is not None: - version = get_version(project) - builder = ProjectBuilder(repo_name, src_dir, project, version) - else: - builder = DocBuilder(repo_name, src_dir) + project = doc_root + version = get_version(project) + builder = ProjectBuilder(repo_name, src_dir, project, version) with builder: builder.build() - root = Path('_build') / repo_name - with open(root / '.nojekyll', 'w') as fh: - fh.write('') for project in doc_roots: - if project == '.': - continue with open(f'_build/{repo_name}/{project}/index.html', 'w') as index: index.write('\n') diff --git a/scripts/build-docs b/scripts/build-docs index d400cc23..f8b156c2 100755 --- a/scripts/build-docs +++ b/scripts/build-docs @@ -2,6 +2,7 @@ import argparse +from fluent.docs import build_root, finalize_builddir from fluent.docs.build import build @@ -18,5 +19,9 @@ if __name__ == "__main__": ) args = parser.parse_args() if args.doc is None: - args.doc = default_docs + args.doc = default_docs[:] + if '.' in args.doc: + build_root(args.repo_name) + args.doc.remove('.') build(args.repo_name, args.doc) + finalize_builddir(args.repo_name) From 23269359d6704a1e7552029619b44f7a274efd79 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Wed, 30 Dec 2020 22:55:36 +0100 Subject: [PATCH 09/18] Add versions to the project docs. --- .gitignore | 1 + docs/_static/project-fluent.css | 20 ++++++ docs/_static/versions.js | 13 ++++ docs/_templates/versions.html | 4 ++ docs/conf.py | 10 ++- fluent.docs/fluent/docs/build.py | 119 ++++++++++++++++++++++++------- fluent.docs/fluent/docs/tags.py | 36 ++++++++++ 7 files changed, 177 insertions(+), 26 deletions(-) create mode 100644 docs/_static/versions.js create mode 100644 docs/_templates/versions.html create mode 100644 fluent.docs/fluent/docs/tags.py diff --git a/.gitignore b/.gitignore index 46040d3b..01deed64 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ _build build dist +/fluent.*/docs/_templates/versions.html diff --git a/docs/_static/project-fluent.css b/docs/_static/project-fluent.css index 5ea2ef0b..be908ce4 100644 --- a/docs/_static/project-fluent.css +++ b/docs/_static/project-fluent.css @@ -1,3 +1,23 @@ div.related { background-color: #356eb7; } + +#versions { + position: relative; + color: #444; +} + +#versions > span { + display: none; + position: absolute; + border: 1px solid; + background-color: #eee; + white-space: nowrap; + border-radius: 3px; + /* 5px - border-width */ + top: calc(5px - 1px); +} + +#versions > span.opened { + display: block; +} diff --git a/docs/_static/versions.js b/docs/_static/versions.js new file mode 100644 index 00000000..5ad75a95 --- /dev/null +++ b/docs/_static/versions.js @@ -0,0 +1,13 @@ +/* + * Show/hide versions when clicking on the versions paragraph + */ + +$(function() { + let versions = document.getElementById('versions'); + if (versions) { + versions.onclick = function(ev) { + let popup = this.querySelector('span'); + popup.classList.toggle('opened') + } + } +}) diff --git a/docs/_templates/versions.html b/docs/_templates/versions.html new file mode 100644 index 00000000..b12a6d88 --- /dev/null +++ b/docs/_templates/versions.html @@ -0,0 +1,4 @@ +{# +Intentionally left blank. +Project documtations fill in a sidebar control as part of the build process. +#} diff --git a/docs/conf.py b/docs/conf.py index 3b573da2..49f112f4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -34,6 +34,13 @@ # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] +# Add src_dir/docs/_templates in a hook as we only have the src_dir then. +def setup(app): + app.connect('config-inited', add_templates) + +def add_templates(app, config): + config.templates_path.insert(0, f'{app.srcdir}/_templates') + # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. @@ -52,9 +59,10 @@ # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] html_css_files = ['project-fluent.css'] +html_js_files = ['versions.js'] html_sidebars = { - '**': ['globaltoc.html', 'searchbox.html'], + '**': ['globaltoc.html', 'versions.html', 'searchbox.html'], } html_theme_options = { } diff --git a/fluent.docs/fluent/docs/build.py b/fluent.docs/fluent/docs/build.py index 321e8221..0d109a2b 100644 --- a/fluent.docs/fluent/docs/build.py +++ b/fluent.docs/fluent/docs/build.py @@ -1,29 +1,76 @@ -from configparser import ConfigParser +from collections import defaultdict +from datetime import date import os from pathlib import Path +import shutil import subprocess - - -def get_version(root): - if root == '.': - return - cp = ConfigParser() - cp.read(Path(root) / 'setup.cfg') - return cp.get('metadata', 'version') - - -def build(repo_name, doc_roots): - for doc_root in doc_roots: - version = get_version(doc_root) - src_dir = doc_root - project = doc_root - version = get_version(project) - builder = ProjectBuilder(repo_name, src_dir, project, version) +import tempfile +from .tags import get_tag_infos + + +def build(repo_name, projects): + tagged_versions = get_tag_infos(date(2020, 5, 1)) + versions_4_project = defaultdict(list) + last_vers = {} + for tag in tagged_versions: + if tag.project not in projects: + continue + versions_4_project[tag.project].append(tag.version) + for project in projects: + if project in versions_4_project: + last_vers[project] = versions_4_project[project][0] + versions_4_project[project][:0] = ['dev', 'stable'] + else: + last_vers[project] = 'dev' + versions_4_project[project].append('dev') + for project in projects: + src_dir = project + builder = ProjectBuilder( + repo_name, src_dir, project, versions_4_project[project], 'dev' + ) with builder: builder.build() - for project in doc_roots: - with open(f'_build/{repo_name}/{project}/index.html', 'w') as index: - index.write('\n') + index = Path(f'_build/{repo_name}/{project}/index.html') + target = 'stable' if last_vers[project] != 'dev' else 'dev' + index.write_text( + f'\n' + ) + worktree = None + for tag in tagged_versions: + if worktree is None: + worktree = tempfile.mkdtemp() + subprocess.run([ + 'git', + 'worktree', 'add', + '--detach', + worktree + ]) + subprocess.run([ + 'git', + 'checkout', + f'{tag.project}@{tag.version}' + ], cwd=worktree) + if tag.project not in projects: + continue + with ProjectBuilder( + repo_name, + os.path.join(worktree, tag.project), + tag.project, + versions_4_project[project], + tag.version + ) as builder: + builder.build() + if worktree is not None: + shutil.rmtree(worktree) + for project in projects: + if last_vers[project] == 'dev': + continue + stable = Path(f'_build/{repo_name}/{project}/stable') + if stable.is_symlink(): + stable.unlink() + if stable.exists(): + shutil.rmtree(stable) + stable.symlink_to(last_vers[project], target_is_directory=True) class DocBuilder: @@ -81,9 +128,10 @@ def doc_tree(self): class ProjectBuilder(DocBuilder): '''Builder for individual projects, with project name and version. ''' - def __init__(self, repo_name, src_dir, project_name, version): + def __init__(self, repo_name, src_dir, project_name, versions, version): super().__init__(repo_name, src_dir) self.project_name = project_name + self.versions = versions self.version = version def __exit__(self, exc_type, exc_val, exc_tb): @@ -94,6 +142,10 @@ def __exit__(self, exc_type, exc_val, exc_tb): if staticfile.name != 'documentation_options.js': staticfile.unlink() + def build(self): + self.create_versions_doc() + super().build() + def environ(self): env = super().environ() env['PYTHONPATH'] = self.src_dir @@ -101,11 +153,28 @@ def environ(self): @property def cmd_opts(self): - return [ - '-D', 'release=' + self.version, + opts = [ '-D', 'project=' + self.project_name, + ] + if self.version != 'dev': + opts += [ + '-D', f'release={self.version}', ] + return opts @property def dest_dir(self): - return f'_build/{self.repo_name}/{self.project_name}/stable' + return f'_build/{self.repo_name}/{self.project_name}/{self.version}' + + def create_versions_doc(self): + target_path = Path(self.src_dir) / 'docs' / '_templates' + target_path.mkdir(exist_ok=True) + target_path = target_path / 'versions.html' + links = ' '.join( + f'{v}' + for v in self.versions + ) + content = f'''

Versions

+

{self.version}{links}

+''' + target_path.write_text(content) diff --git a/fluent.docs/fluent/docs/tags.py b/fluent.docs/fluent/docs/tags.py new file mode 100644 index 00000000..8da0fcbe --- /dev/null +++ b/fluent.docs/fluent/docs/tags.py @@ -0,0 +1,36 @@ +from datetime import date +import subprocess + + +def get_tag_infos(cut_off_date): + '''Get fluent.* tags newer than cut_off_date. + TagInfo objects are ordered by committer date, newest first. + ''' + taglines = subprocess.run( + [ + 'git', 'tag', '--list', 'fluent.*', + '--sort=-committerdate', + '--format=%(refname:lstrip=2) %(committerdate:short)', + ], + encoding='utf-8', + stdout=subprocess.PIPE, + check=True + ).stdout.splitlines() + return [ + ti for ti in (TagInfo(line) for line in taglines) + if ti.date > cut_off_date + ] + + +class TagInfo: + def __init__(self, tagline): + tag, date_string = tagline.split(' ') + self.project, self.version = tag.split('@') + self.date = date.fromisoformat(date_string) + + @property + def tag(self): + return f'{self.project}@{self.version}' + + def __repr__(self): + return f'{self.tag} ({self.date})' From 74d8efdb3146ec27d05f9cf24da63cab813da2aa Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Wed, 30 Dec 2020 23:02:09 +0100 Subject: [PATCH 10/18] Add option to only build current source --- fluent.docs/fluent/docs/build.py | 6 ++++-- scripts/build-docs | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/fluent.docs/fluent/docs/build.py b/fluent.docs/fluent/docs/build.py index 0d109a2b..bb9d6d0f 100644 --- a/fluent.docs/fluent/docs/build.py +++ b/fluent.docs/fluent/docs/build.py @@ -8,8 +8,10 @@ from .tags import get_tag_infos -def build(repo_name, projects): - tagged_versions = get_tag_infos(date(2020, 5, 1)) +def build(repo_name, projects, show_releases=True): + tagged_versions = [] + if show_releases: + tagged_versions = get_tag_infos(date(2020, 5, 1)) versions_4_project = defaultdict(list) last_vers = {} for tag in tagged_versions: diff --git a/scripts/build-docs b/scripts/build-docs index f8b156c2..074cdb26 100755 --- a/scripts/build-docs +++ b/scripts/build-docs @@ -17,11 +17,15 @@ if __name__ == "__main__": '--doc', action='append', choices=default_docs, help='Only build select documentation roots.' ) + parser.add_argument( + '--dev', action='store_false', dest='show_releases', + help='Only build development versions of projects' + ) args = parser.parse_args() if args.doc is None: args.doc = default_docs[:] if '.' in args.doc: build_root(args.repo_name) args.doc.remove('.') - build(args.repo_name, args.doc) + build(args.repo_name, args.doc, show_releases=args.show_releases) finalize_builddir(args.repo_name) From e4aafd8efd965ab1a9a008fa2c3e9566292501c1 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Wed, 30 Dec 2020 23:30:29 +0100 Subject: [PATCH 11/18] fixes --- fluent.docs/fluent/docs/build.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fluent.docs/fluent/docs/build.py b/fluent.docs/fluent/docs/build.py index bb9d6d0f..c7895566 100644 --- a/fluent.docs/fluent/docs/build.py +++ b/fluent.docs/fluent/docs/build.py @@ -39,6 +39,8 @@ def build(repo_name, projects, show_releases=True): ) worktree = None for tag in tagged_versions: + if tag.project not in projects: + continue if worktree is None: worktree = tempfile.mkdtemp() subprocess.run([ @@ -52,13 +54,11 @@ def build(repo_name, projects, show_releases=True): 'checkout', f'{tag.project}@{tag.version}' ], cwd=worktree) - if tag.project not in projects: - continue with ProjectBuilder( repo_name, os.path.join(worktree, tag.project), tag.project, - versions_4_project[project], + versions_4_project[tag.project], tag.version ) as builder: builder.build() From ddaa750a0a557aa072393e106303acd2e453a5b4 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Mon, 18 Jan 2021 18:42:10 +0100 Subject: [PATCH 12/18] Update to latest v4 state --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 9758f97b..110ee6bf 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -62,4 +62,4 @@ jobs: branch: gh-pages # The branch the action should deploy to. folder: _build # The folder the action should deploy. clean: true # Automatically remove deleted files from the deploy branch - dry_run: ${{ github.event_name == 'pull_request' }} + dry-run: ${{ github.event_name == 'pull_request' }} From 0ee0919cb359c74414053dd8ae59be3fd9abbf2d Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Thu, 11 Feb 2021 13:01:02 +0100 Subject: [PATCH 13/18] Use released version of gpda --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 110ee6bf..9e64e876 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -57,7 +57,7 @@ jobs: name: html path: _build - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@releases/v4 + uses: JamesIves/github-pages-deploy-action@4.0.0 with: branch: gh-pages # The branch the action should deploy to. folder: _build # The folder the action should deploy. From b5d592732df5fe41eb888d3439e9488fc6b30dd3 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Thu, 11 Feb 2021 13:26:10 +0100 Subject: [PATCH 14/18] Remove .buildinfo files from gh-pages --- .github/workflows/documentation.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 9e64e876..8c0e68f1 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -42,7 +42,9 @@ jobs: uses: actions/upload-artifact@v2 with: name: html - path: _build/python-fluent + path: | + _build/python-fluent + !_build/**/.buildinfo publish: name: publish From 128607f70793b0eef0ee15bc5144865f34b44c34 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Thu, 11 Feb 2021 14:35:47 +0100 Subject: [PATCH 15/18] Slightly less ugly --- docs/_static/project-fluent.css | 21 +++++++++++---------- docs/_static/versions.js | 3 +-- fluent.docs/fluent/docs/build.py | 5 ++++- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/_static/project-fluent.css b/docs/_static/project-fluent.css index be908ce4..84e242c3 100644 --- a/docs/_static/project-fluent.css +++ b/docs/_static/project-fluent.css @@ -7,17 +7,18 @@ div.related { color: #444; } -#versions > span { +#versions > span.version { + cursor: pointer; +} + +#versions > span.version::after { + content: " ⮞"; +} + +#versions.opened > span.version { display: none; - position: absolute; - border: 1px solid; - background-color: #eee; - white-space: nowrap; - border-radius: 3px; - /* 5px - border-width */ - top: calc(5px - 1px); } -#versions > span.opened { - display: block; +#versions:not(.opened) > span.links { + display: none; } diff --git a/docs/_static/versions.js b/docs/_static/versions.js index 5ad75a95..4cb1474f 100644 --- a/docs/_static/versions.js +++ b/docs/_static/versions.js @@ -6,8 +6,7 @@ $(function() { let versions = document.getElementById('versions'); if (versions) { versions.onclick = function(ev) { - let popup = this.querySelector('span'); - popup.classList.toggle('opened') + this.classList.toggle('opened'); } } }) diff --git a/fluent.docs/fluent/docs/build.py b/fluent.docs/fluent/docs/build.py index c7895566..e54f18c8 100644 --- a/fluent.docs/fluent/docs/build.py +++ b/fluent.docs/fluent/docs/build.py @@ -177,6 +177,9 @@ def create_versions_doc(self): for v in self.versions ) content = f'''

Versions

-

{self.version}{links}

+

+ {self.version} + {links} +

''' target_path.write_text(content) From b0235df710577bb17383b7a4815b806b5bf2fa56 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Mon, 22 Feb 2021 11:40:49 +0100 Subject: [PATCH 16/18] self-review --- .github/workflows/documentation.yml | 1 - fluent.docs/README.rst | 21 +++++++++++++++++++-- fluent.docs/fluent/docs/__init__.py | 5 +++++ fluent.docs/fluent/docs/build.py | 28 ++++++++++++++++++---------- scripts/build-docs | 7 ++++++- 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 8c0e68f1..4fd5626b 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -49,7 +49,6 @@ jobs: publish: name: publish needs: [build] - # if: github.event_name == 'push' runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/fluent.docs/README.rst b/fluent.docs/README.rst index df742cce..b22e458d 100644 --- a/fluent.docs/README.rst +++ b/fluent.docs/README.rst @@ -1,5 +1,22 @@ ``fluent.docs`` ---------------- +=============== Python utilities used by the ``python-fluent`` documentation build -process. +process. The entry point is ``scripts/build-docs``. + +The generated documentation is in ``_build/python-fluent``, and you +can surf it locally via ``python3 -m http.server `` in ``_build``. + +The documentation is created for each tagged version after May 2020, +at which point we had good docs. The current branch (PR tips or +master) is versioned as *dev*, and *stable* is a symlink to the latest +release. The releases are in a dir with their corresponding version number. + +When cutting a new release, manually run the documentation workflow +to pick that up. + +The rationale for regenerating all historic documentation releases is +to provide an easy process to change style and renderering across +the full documentation. For that, the build setup is taken from +the current checkout, and release docs are generated from sources in +a git worktree. diff --git a/fluent.docs/fluent/docs/__init__.py b/fluent.docs/fluent/docs/__init__.py index d5ca3afa..e346cd58 100755 --- a/fluent.docs/fluent/docs/__init__.py +++ b/fluent.docs/fluent/docs/__init__.py @@ -3,11 +3,16 @@ def finalize_builddir(repo_name): + 'Bookkeeping on the docs build directory' root = Path('_build') / repo_name with open(root / '.nojekyll', 'w') as fh: fh.write('') def build_root(repo_name): + '''Build the top-level documentation. + + See :py:mod:`.build` on building sub-projects. + ''' with DocBuilder(repo_name, '.') as builder: builder.build() diff --git a/fluent.docs/fluent/docs/build.py b/fluent.docs/fluent/docs/build.py index e54f18c8..6ff1a3a8 100644 --- a/fluent.docs/fluent/docs/build.py +++ b/fluent.docs/fluent/docs/build.py @@ -1,5 +1,4 @@ from collections import defaultdict -from datetime import date import os from pathlib import Path import shutil @@ -8,23 +7,33 @@ from .tags import get_tag_infos -def build(repo_name, projects, show_releases=True): +def build(repo_name, projects, releases_after=None): + '''Build documentation for projects. + + Build the given projects in _build/repo_name. + Create versioned documentations for tags after ``releases_after``, + if given. + ''' tagged_versions = [] - if show_releases: - tagged_versions = get_tag_infos(date(2020, 5, 1)) + if releases_after: + tagged_versions = [ + tag for tag in get_tag_infos(releases_after) + if tag.project in projects + ] + # List of versions we have for each project versions_4_project = defaultdict(list) - last_vers = {} for tag in tagged_versions: - if tag.project not in projects: - continue versions_4_project[tag.project].append(tag.version) + last_vers = {} for project in projects: if project in versions_4_project: last_vers[project] = versions_4_project[project][0] versions_4_project[project][:0] = ['dev', 'stable'] else: + # No releases yet, just dev last_vers[project] = 'dev' versions_4_project[project].append('dev') + # Build current dev version for each project for project in projects: src_dir = project builder = ProjectBuilder( @@ -32,6 +41,7 @@ def build(repo_name, projects, show_releases=True): ) with builder: builder.build() + # Create redirect page from project to stable release or dev index = Path(f'_build/{repo_name}/{project}/index.html') target = 'stable' if last_vers[project] != 'dev' else 'dev' index.write_text( @@ -39,8 +49,6 @@ def build(repo_name, projects, show_releases=True): ) worktree = None for tag in tagged_versions: - if tag.project not in projects: - continue if worktree is None: worktree = tempfile.mkdtemp() subprocess.run([ @@ -78,7 +86,6 @@ def build(repo_name, projects, show_releases=True): class DocBuilder: '''Builder for the top-level documentation. ''' - build_dir = '_build/doctrees' def __init__(self, repo_name, src_dir): self.repo_name = repo_name @@ -143,6 +150,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): # The options are project-specific. if staticfile.name != 'documentation_options.js': staticfile.unlink() + return False def build(self): self.create_versions_doc() diff --git a/scripts/build-docs b/scripts/build-docs index 074cdb26..388c21df 100755 --- a/scripts/build-docs +++ b/scripts/build-docs @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import argparse +from datetime import date from fluent.docs import build_root, finalize_builddir from fluent.docs.build import build @@ -27,5 +28,9 @@ if __name__ == "__main__": if '.' in args.doc: build_root(args.repo_name) args.doc.remove('.') - build(args.repo_name, args.doc, show_releases=args.show_releases) + releases_after = None + if args.show_releases: + # python-fluent had descent docs since May 2020 + releases_after = date(2020, 5, 1) + build(args.repo_name, args.doc, releases_after) finalize_builddir(args.repo_name) From a23b498aa5180f318a132ac28ed8db3f9e01f366 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Mon, 22 Feb 2021 12:53:35 +0100 Subject: [PATCH 17/18] Freeze dependencies of the docs build process --- .github/workflows/documentation.yml | 3 +- docs/requirements.in | 3 + docs/requirements.txt | 168 ++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 docs/requirements.in create mode 100644 docs/requirements.txt diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 4fd5626b..cfa16321 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -34,7 +34,8 @@ jobs: python-version: 3.7 - name: Install dependencies run: | - pip install Sphinx==3.0.3 fluent.pygments==1.0 ./fluent.docs + pip install -r docs/requirements.txt + pip install ./fluent.docs - name: sphinx-build run: | ./scripts/build-docs python-fluent diff --git a/docs/requirements.in b/docs/requirements.in new file mode 100644 index 00000000..4e44e28f --- /dev/null +++ b/docs/requirements.in @@ -0,0 +1,3 @@ +Sphinx==3.0.3 +fluent.pygments==1.0 +wheel diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..46b9da96 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,168 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --generate-hashes requirements.in +# +alabaster==0.7.12 \ + --hash=sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359 \ + --hash=sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02 \ + # via sphinx +babel==2.9.0 \ + --hash=sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5 \ + --hash=sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05 \ + # via sphinx +certifi==2020.12.5 \ + --hash=sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c \ + --hash=sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830 \ + # via requests +chardet==4.0.0 \ + --hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \ + --hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5 \ + # via requests +docutils==0.16 \ + --hash=sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af \ + --hash=sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc \ + # via sphinx +fluent.pygments==1.0 \ + --hash=sha256:625c87a8a2362ef304146b161d359dcf652bed2a1ae4869b5607b8e06d117d97 \ + --hash=sha256:b44758f74f87e1aa9d78d8f53363962639c5bf99d88cf3e407d046b5249ec27f \ + # via -r requirements.in +fluent.syntax==0.18.1 \ + --hash=sha256:0e63679fa4f1b3042565220a5127b4bab842424f07d6a13c12299e3b3835486a \ + --hash=sha256:3a55f5e605d1b029a65cc8b6492c86ec4608e15447e73db1495de11fd46c104f \ + # via fluent.pygments +idna==2.10 \ + --hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \ + --hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0 \ + # via requests +imagesize==1.2.0 \ + --hash=sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1 \ + --hash=sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1 \ + # via sphinx +jinja2==2.11.3 \ + --hash=sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419 \ + --hash=sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6 \ + # via sphinx +markupsafe==1.1.1 \ + --hash=sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473 \ + --hash=sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161 \ + --hash=sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235 \ + --hash=sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5 \ + --hash=sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42 \ + --hash=sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f \ + --hash=sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39 \ + --hash=sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff \ + --hash=sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b \ + --hash=sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014 \ + --hash=sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f \ + --hash=sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1 \ + --hash=sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e \ + --hash=sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183 \ + --hash=sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66 \ + --hash=sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b \ + --hash=sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1 \ + --hash=sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15 \ + --hash=sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1 \ + --hash=sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85 \ + --hash=sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1 \ + --hash=sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e \ + --hash=sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b \ + --hash=sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905 \ + --hash=sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850 \ + --hash=sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0 \ + --hash=sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735 \ + --hash=sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d \ + --hash=sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb \ + --hash=sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e \ + --hash=sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d \ + --hash=sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c \ + --hash=sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1 \ + --hash=sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2 \ + --hash=sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21 \ + --hash=sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2 \ + --hash=sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5 \ + --hash=sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7 \ + --hash=sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b \ + --hash=sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8 \ + --hash=sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6 \ + --hash=sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193 \ + --hash=sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f \ + --hash=sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b \ + --hash=sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f \ + --hash=sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2 \ + --hash=sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5 \ + --hash=sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c \ + --hash=sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032 \ + --hash=sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7 \ + --hash=sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be \ + --hash=sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621 \ + # via jinja2 +packaging==20.9 \ + --hash=sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5 \ + --hash=sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a \ + # via sphinx +pygments==2.8.0 \ + --hash=sha256:37a13ba168a02ac54cc5891a42b1caec333e59b66addb7fa633ea8a6d73445c0 \ + --hash=sha256:b21b072d0ccdf29297a82a2363359d99623597b8a265b8081760e4d0f7153c88 \ + # via fluent.pygments, sphinx +pyparsing==2.4.7 \ + --hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1 \ + --hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b \ + # via packaging +pytz==2021.1 \ + --hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da \ + --hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 \ + # via babel +requests==2.25.1 \ + --hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804 \ + --hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e \ + # via sphinx +six==1.15.0 \ + --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ + --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \ + # via fluent.pygments +snowballstemmer==2.1.0 \ + --hash=sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2 \ + --hash=sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914 \ + # via sphinx +sphinx==3.0.3 \ + --hash=sha256:62edfd92d955b868d6c124c0942eba966d54b5f3dcb4ded39e65f74abac3f572 \ + --hash=sha256:f5505d74cf9592f3b997380f9bdb2d2d0320ed74dd69691e3ee0644b956b8d83 \ + # via -r requirements.in +sphinxcontrib-applehelp==1.0.2 \ + --hash=sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a \ + --hash=sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58 \ + # via sphinx +sphinxcontrib-devhelp==1.0.2 \ + --hash=sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e \ + --hash=sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4 \ + # via sphinx +sphinxcontrib-htmlhelp==1.0.3 \ + --hash=sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f \ + --hash=sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b \ + # via sphinx +sphinxcontrib-jsmath==1.0.1 \ + --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \ + --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8 \ + # via sphinx +sphinxcontrib-qthelp==1.0.3 \ + --hash=sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72 \ + --hash=sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6 \ + # via sphinx +sphinxcontrib-serializinghtml==1.1.4 \ + --hash=sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc \ + --hash=sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a \ + # via sphinx +urllib3==1.26.3 \ + --hash=sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80 \ + --hash=sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73 \ + # via requests +wheel==0.36.2 \ + --hash=sha256:78b5b185f0e5763c26ca1e324373aadd49182ca90e825f7853f4b2509215dc0e \ + --hash=sha256:e11eefd162658ea59a60a0f6c7d493a7190ea4b9a85e335b33489d9f17e0245e \ + # via -r requirements.in + +# WARNING: The following packages were not pinned, but pip requires them to be +# pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag. +# setuptools From a2b15eff2a2088eff6971d06de949ba2f3a75ecb Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Mon, 22 Feb 2021 13:07:03 +0100 Subject: [PATCH 18/18] Update Sphinx to 3.5.1 --- docs/requirements.in | 2 +- docs/requirements.txt | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/requirements.in b/docs/requirements.in index 4e44e28f..b49fca3d 100644 --- a/docs/requirements.in +++ b/docs/requirements.in @@ -1,3 +1,3 @@ -Sphinx==3.0.3 +Sphinx==3.5.1 fluent.pygments==1.0 wheel diff --git a/docs/requirements.txt b/docs/requirements.txt index 46b9da96..6c5a0815 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile # To update, run: # -# pip-compile --generate-hashes requirements.in +# pip-compile --generate-hashes docs/requirements.in # alabaster==0.7.12 \ --hash=sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359 \ @@ -27,7 +27,7 @@ docutils==0.16 \ fluent.pygments==1.0 \ --hash=sha256:625c87a8a2362ef304146b161d359dcf652bed2a1ae4869b5607b8e06d117d97 \ --hash=sha256:b44758f74f87e1aa9d78d8f53363962639c5bf99d88cf3e407d046b5249ec27f \ - # via -r requirements.in + # via -r docs/requirements.in fluent.syntax==0.18.1 \ --hash=sha256:0e63679fa4f1b3042565220a5127b4bab842424f07d6a13c12299e3b3835486a \ --hash=sha256:3a55f5e605d1b029a65cc8b6492c86ec4608e15447e73db1495de11fd46c104f \ @@ -126,10 +126,10 @@ snowballstemmer==2.1.0 \ --hash=sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2 \ --hash=sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914 \ # via sphinx -sphinx==3.0.3 \ - --hash=sha256:62edfd92d955b868d6c124c0942eba966d54b5f3dcb4ded39e65f74abac3f572 \ - --hash=sha256:f5505d74cf9592f3b997380f9bdb2d2d0320ed74dd69691e3ee0644b956b8d83 \ - # via -r requirements.in +sphinx==3.5.1 \ + --hash=sha256:11d521e787d9372c289472513d807277caafb1684b33eb4f08f7574c405893a9 \ + --hash=sha256:e90161222e4d80ce5fc811ace7c6787a226b4f5951545f7f42acf97277bfc35c \ + # via -r docs/requirements.in sphinxcontrib-applehelp==1.0.2 \ --hash=sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a \ --hash=sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58 \ @@ -161,7 +161,7 @@ urllib3==1.26.3 \ wheel==0.36.2 \ --hash=sha256:78b5b185f0e5763c26ca1e324373aadd49182ca90e825f7853f4b2509215dc0e \ --hash=sha256:e11eefd162658ea59a60a0f6c7d493a7190ea4b9a85e335b33489d9f17e0245e \ - # via -r requirements.in + # via -r docs/requirements.in # WARNING: The following packages were not pinned, but pip requires them to be # pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag.