acrn-hypervisor/doc/extensions/last_updated.py

162 lines
6.4 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 %}
#
# <!-- yourcopyright info goes here, possibly copied from the theme's # footer.html -->
#
# <span class="lastupdated">Last updated on {{last_updated}}. Published on {{last_published}}</span>
#
# {% 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)
time_format = "%Y-%m-%d"
for git_repo_path in git_repo:
new_path = os.path.join(git_repo_path, rel_path)
if os.path.isfile(new_path):
try:
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:
# we found the .rst file in one of the git_repo paths, either
# use the date of the last commit (from git) or today's date if
# there is no git history for this file.
try:
last_updated = datetime.strptime(output.decode('utf-8'), time_format).date()
return last_updated
except:
return date.today()
else:
# can't find a .rst file on that git_repo path, try the next
continue
# falling out of the loop means we can't find that file in any of the
# git_repo paths
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(s) in last_updated_git_path:\
\n {app.config.last_updated_git_path}\n')
context['last_updated'] = context['last_published']
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,
}