From 81336a8ee47c3459e1a6e63137f3375fce54d779 Mon Sep 17 00:00:00 2001 From: "David B. Kinder" Date: Fri, 18 Mar 2022 10:18:35 -0700 Subject: [PATCH] doc: use Sphinx extension for showing last updated date in footers Remove the proof-of-concept shell script that post-processes the generated HTML to add the git date when the corresponding .rst file as the last modified date, augmenting the existing published date. Instead, use a custom last_updated.py Sphinx extension that's integrated into the Sphinx build itself. Remove the old fix-git-modified-date.sh script and calls to it. Signed-off-by: David B. Kinder --- doc/Makefile | 3 - doc/_templates/footer.html | 13 +++ doc/conf.py | 8 +- doc/extensions/last_updated.py | 151 +++++++++++++++++++++++++++ doc/scripts/fix-git-modified-date.sh | 22 ---- 5 files changed, 171 insertions(+), 26 deletions(-) create mode 100644 doc/_templates/footer.html create mode 100644 doc/extensions/last_updated.py delete mode 100755 doc/scripts/fix-git-modified-date.sh diff --git a/doc/Makefile b/doc/Makefile index 6b66c8186..7f48b6562 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -62,9 +62,6 @@ html: content doxy $(Q)./scripts/show-versions.py $(Q)$(SPHINXBUILD) -t $(DOC_TAG) -b html -d $(BUILDDIR)/doctrees $(SOURCEDIR) $(BUILDDIR)/html $(SPHINXOPTS) $(OPTS) >> $(BUILDDIR)/doc.log 2>&1 $(Q)./scripts/filter-doc-log.sh $(BUILDDIR)/doc.log -ifeq ($(BUILDDIR),_build) - $(Q)./scripts/fix-git-modified-date.sh -endif singlehtml: content doxy $(Q)$(SPHINXBUILD) -t $(DOC_TAG) -b singlehtml -d $(BUILDDIR)/doctrees $(SOURCEDIR) $(BUILDDIR)/html $(SPHINXOPTS) $(OPTS) >> $(BUILDDIR)/doc.log 2>&1 diff --git a/doc/_templates/footer.html b/doc/_templates/footer.html new file mode 100644 index 000000000..1ce60c2dc --- /dev/null +++ b/doc/_templates/footer.html @@ -0,0 +1,13 @@ +{% extends "!footer.html" %} +{% block contentinfo %} +

+ {%- if show_copyright %} + {%- if hasdoc('copyright') %} + {%- trans path=pathto('copyright'), copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} + {%- else %} + {%- trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} + {%- endif %} + {%- endif %} + +Last updated on {{last_updated}}. Published on {{last_published}} +{% endblock %} diff --git a/doc/conf.py b/doc/conf.py index afbbc57ab..2d19a4085 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -40,7 +40,7 @@ sys.path.insert(0, os.path.join(os.path.abspath('.'), 'extensions')) extensions = [ 'breathe', 'sphinx.ext.graphviz', 'sphinx.ext.extlinks', 'eager_only', 'html_redirects', 'link_roles', - 'sphinx_tabs.tabs' + 'sphinx_tabs.tabs', 'last_updated' ] # extlinks provides a macro template @@ -388,3 +388,9 @@ html_redirect_pages = [ ('tutorials/using_zephyr_as_uos', 'tutorials/using_zephyr_as_user_vm'), ('tutorials/using_windows_as_uos', 'tutorials/using_windows_as_user_vm') ] + +# Custom last_updated extension for updating last updated date based on git information +# needs to know the folders where the cloned files can be found, relative to +# where the Sphinx .rst build folder + +last_updated_git_path = ['../..', '../../..', '../../../doc/'] diff --git a/doc/extensions/last_updated.py b/doc/extensions/last_updated.py new file mode 100644 index 000000000..a459ced4c --- /dev/null +++ b/doc/extensions/last_updated.py @@ -0,0 +1,151 @@ +# Copyright (c) 2022 Anton Bobkov, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Use git to retrieve a more meaningful last updated date than the usual +# Sphinx-generated date that's actually just the last published date. +# Inspired by a shell script by David Kinder. +# +# Add the extension to your conf.py file: +# extensions = ['last_updated'] +# +# If you copy documentation files from one or multiple git repositories prior to +# running Sphinx, specify the list of paths to the git folders in the +# last_updated_git_path parameter. You can either specify absolute paths or +# relative paths from the documentation root directory in this list. For +# example: +# +# last_updated_git_path = ['../../', '../../../'] +# +# Specify the date format in the html_last_updated_fmt parameter. For +# information about the strftime() format, see https://strftime.org. If you do +# not specify this parameter, the extension uses the default value of "%b %d, %Y" +# for short month name, date, and four-digit year. +# +# Use the variables provided by the extension in your jinja templates: +# +# last_updated. The date of the last update of the rst file in the specified +# git repository. +# last_published. The publication date of the rst file. +# +# Note: Sphinx already provides the last_updated variable. However, this +# variable includes the publication time. This extension overwrites the +# last_updated variable with the file modification time in git. +# +# To override the default footer in the sphinx_rtd_theme, create the footer.html +# file in the _templates directory: +# +# {% extends "!footer.html" %} +# {% block contentinfo %} +# +# +# +# Last updated on {{last_updated}}. Published on {{last_published}} +# +# {% endblock %} +# +# This snippet overrides the contentinfo block of the default footer.html +# template that initially contains the information about the copyright and +# publication date. + +__version__ = '0.1.0' + +import subprocess +from datetime import date, datetime +import os +import urllib.parse +from sphinx.util import logging + + +def _not_git_repo(dir): + res = subprocess.call(['git', '-C', dir, 'rev-parse'], + stderr=subprocess.STDOUT, stdout = open(os.devnull, 'w')) != 0 + return res + + +def _get_last_updated_from_git(file_path, git_repo, doc_root): + + rel_path = os.path.relpath(file_path, doc_root) + + for git_repo_path in git_repo: + + new_path = os.path.join(git_repo_path, rel_path) + if os.path.isfile(new_path): + try: + time_format = "%Y-%m-%d" + output=subprocess.check_output( + f'git --no-pager log -1 --date=format:"{time_format}" --pretty="format:%cd" {new_path}', + shell=True, cwd=git_repo_path) + except: + # Could not get git info for an existing file, try the next + # folder on the list + continue + else: + last_updated = datetime.strptime(output.decode('utf-8'), time_format).date() + return last_updated + else: + continue + + return None + + +def on_html_page_context(app, pagename, templatename, context, doctree): + if doctree: + + # If last_updated_git_path (with a list of potential folders where the + # actual git-managed files are) is not specified, + # then just use the doc source path + if app.config.last_updated_git_path is None: + app.config.last_updated_git_path = [app.srcdir] + + # If last_updated_git_path is a relative path, convert it to absolute + last_updated_git_path_abs = [] + for last_updated_git_path_el in app.config.last_updated_git_path: + if not os.path.isabs(last_updated_git_path_el): + last_updated_git_path_el_abs = os.path.normpath(os.path.join(app.srcdir, last_updated_git_path_el)) + last_updated_git_path_abs.append(last_updated_git_path_el_abs) + else: + last_updated_git_path_abs.append(last_updated_git_path_el) + + if _not_git_repo(last_updated_git_path_abs[-1]): + app.logger.error(f"The last_updated extension is disabled because of the error:\ + \n {last_updated_git_path_abs} is not a git repository.\ + \n Specify correct path(s) to the git source folder(s) in last_updated_git_path.") + app.disconnect(app.listener_id) + return + + app.config.last_updated_git_path = last_updated_git_path_abs + + + # Get the absolute path to the current rst document + rst_file_path = doctree.attributes['source'] + + # Set the date format based on html_last_updated_fmt or default of Mar 18, 2022 + if app.config.html_last_updated_fmt is None: + date_fmt = "%b %d, %Y" + else: + date_fmt = app.config.html_last_updated_fmt + + context['last_published'] = date.today().strftime(date_fmt) + + last_updated_value = _get_last_updated_from_git(file_path=rst_file_path, + git_repo=app.config.last_updated_git_path, + doc_root=app.srcdir) + if last_updated_value is None: + app.logger.warning(f'Could not get the last updated value from git for the following file:\ + \n {rst_file_path}\n Ensure that you specified the correct folder in last_updated_git_path.') + context['last_updated'] = None + else: + context['last_updated'] = last_updated_value.strftime(date_fmt) + + + +def setup(app): + app.logger = logging.getLogger(__name__) + app.add_config_value('last_updated_git_path', None, 'html') + + app.listener_id = app.connect('html-page-context', on_html_page_context) + + return { + 'version': '0.1', + 'parallel_read_safe': True, + } diff --git a/doc/scripts/fix-git-modified-date.sh b/doc/scripts/fix-git-modified-date.sh deleted file mode 100755 index 21faab913..000000000 --- a/doc/scripts/fix-git-modified-date.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# Copyright (C) 2021 Intel Corporation. -# SPDX-License-Identifier: BSD-3-Clause -# -# Run this script in the _build/html folder after generating the HTML content. -# -# Scan through HTML files look for the corresponding .rst file (in doc or misc -# for ACRN project). Replace the "Last updated" date in the footer with the last -# commit date for the corresponding .rst file (if we can find it). Tweak -# wording to mention Last modified and published dates. - -cd _build/html - -find -type f -name "*.html" | \ - while read filename; - do - f=${filename%.*}.rst - [[ -f "../../$f" ]] && prefix="../.." - [[ -f "../../../$f" ]] && prefix="../../.." - d="$(git log -1 --format="%ad" --date=format:"%b %d, %Y" -- "$prefix/$f")"; - [[ ! -z "$d" ]] && sed -i "s/\(^ *\)Last updated on \(.*\)\.$/\1Last modified: $d. Published: \2./" $filename; - done