mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-09 00:46:57 +00:00
When I added a new document that wasn't checked into GitHub yet, the doc build failed with an unhanded exception: Extension error (last_updated): (exception: time data '' does not match format '%Y-%m-%d') Problem is the git query looking up the last commit date for a file returns an empty string for the date if the file exists but it's not in the git repo (yet). The subsequent call to strptime raises an exception if passed an empty string. This patch handles the exception. Tracked-On: #7249 Signed-off-by: David B. Kinder <david.b.kinder@intel.com>
155 lines
5.9 KiB
Python
155 lines
5.9 KiB
Python
# 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 %}
|
||
#
|
||
# <!-- your copyright 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:
|
||
try:
|
||
last_updated = datetime.strptime(output.decode('utf-8'), time_format).date()
|
||
return last_updated
|
||
except:
|
||
continue
|
||
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,
|
||
}
|