show the modification time of each page individually

The old way of setting last_updated for the output showed a single
value on all pages, which makes it more difficult to know how up to
date a given resolution or policy is. The output was also formatted as
binary strings, which rendered poorly with b'' wrapped around the
actual timestamp.

This change uses the git history of each page to show when it was
modified. For pages generated from the project list, show the
modification time of the input data file. For pages rendered from
templates, without a source file, use the current build time. Always
return the value as a unicode string.

Change-Id: I82849176775484328b3939b4e0c66aaf7a35f49d
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
Doug Hellmann 2018-10-03 12:10:50 -04:00
parent bf83ea4b27
commit f7f0a065f6
2 changed files with 99 additions and 4 deletions

View File

@ -0,0 +1,96 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import os.path
import subprocess
from sphinx.util import logging
LOG = logging.getLogger('page_context')
_default_last_updated = datetime.datetime.now()
def _get_last_updated_file(src_file):
if not os.path.exists(src_file):
return None
try:
last_updated_t = subprocess.check_output(
[
'git', 'log', '-n1', '--format=%ad',
'--date=format:%Y-%m-%d %H:%M:%S',
'--', src_file,
]
).decode('utf-8').strip()
except subprocess.CalledProcessError as err:
LOG.info('[governance] Could not get modification time of %s: %s',
src_file, err)
else:
if last_updated_t:
try:
return datetime.datetime.strptime(last_updated_t,
'%Y-%m-%d %H:%M:%S')
except ValueError as err:
LOG.info('[governance] Could not parse modification time of '
'%s: %r',
src_file, last_updated_t)
return None
def _get_last_updated(app, pagename):
last_updated = None
full_src_file = app.builder.env.doc2path(pagename)
candidates = []
# Strip the prefix from the filename so the git command recognizes
# the file as part of the current repository.
src_file = full_src_file[len(app.builder.env.srcdir):].lstrip('/')
candidates.append(src_file)
if not os.path.exists(src_file):
# Some of the files are in doc/source and some are not. Some
# of the ones that are not are symlinked. If we can't find the
# file after stripping the full prefix, try looking for it in
# doc/source explicitly.
candidates.append(os.path.join('doc/source', src_file))
if pagename.startswith('reference/projects/'):
# If the file is in the reference/projects directory, it may
# be an auto-generated project page. In that case, use the
# YAML file as the source of the last_updated timestamp.
candidates.append('reference/projects.yaml')
for filename in candidates:
last_updated = _get_last_updated_file(filename)
if last_updated:
LOG.info('[governance] Last updated for %s is %s',
pagename, last_updated)
return last_updated
LOG.info('[governance] could not determine last_updated for %r',
pagename)
return _default_last_updated
def html_page_context(app, pagename, templatename, context, doctree):
# Use the last modified date from git instead of applying a single
# value to the entire site.
context['last_updated'] = _get_last_updated(app, pagename)
def setup(app):
LOG.info('[governance] connecting html-page-context event handler')
app.connect('html-page-context', html_page_context)
return {
'parallel_read_safe': True,
}

View File

@ -13,6 +13,7 @@
# flake8: noqa
import datetime
import subprocess
import sys
import os
@ -39,6 +40,7 @@ extensions = [
'teams',
'tags',
'badges',
'page_context',
]
todo_include_todos = True
@ -141,10 +143,7 @@ html_extra_path = ['_extra']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
git_cmd = ["git", "log", "--pretty=format:'%ad, commit %h'", "--date=local",
"-n1"]
html_last_updated_fmt = str(subprocess.Popen(
git_cmd, stdout=subprocess.PIPE).communicate()[0])
html_last_updated_fmt = '%Y-%m-%d'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.