#!/usr/bin/env python3
# This is free and unencumbered software released into the public
# domain.
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a
# compiled binary, for any purpose, commercial or non-commercial, and
# by any means.
# In jurisdictions that recognize copyright laws, the author or
# authors of this software dedicate any and all copyright interest in
# the software to the public domain. We make this dedication for the
# benefit of the public at large and to the detriment of our heirs
# and successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to
# this software under copyright law.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# For more information, please refer to
"""Update ends of markdown files."""
import posixpath
import re
import common
END_TEMPLATE = """\
If you have trouble with this tutorial please [tell me about
it]({toplevel}/contact-me.md) and I'll make this tutorial better. If you
like this tutorial, please [give it a
star]({toplevel}/README.md#how-can-i-thank-you-for-writing-and-sharing-\
this-tutorial).
You may use this tutorial freely at your own risk. See
[LICENSE]({toplevel}/LICENSE).
{extralinks}[List of contents]({toplevel}/README.md#{readmeheader})
"""
CHAPTER_LINK_REGEX = r'^\d+\. \[.*\]\((.*\.md)\)$'
def get_filenames():
"""Get chapter files and other files from README.
Return a two-tuple of chapter file names and other file names as
iterables of strings.
"""
chapters = []
with open('README.md', 'r') as f:
# move to where the content list starts
while f.readline().strip() != "## List of contents":
pass
# now let's read the content list
for line in f:
line = line.strip()
if line.startswith('## '):
# end of content list
break
if line:
# not empty line
match = re.search(CHAPTER_LINK_REGEX, line)
if match is not None:
# it's a link to a chapter
chapters.append(match.group(1))
others = set(common.get_markdown_files()) - set(chapters)
return chapters, others
def update_end(filename, end):
"""Add *** and end to a file if it doesn't have them already.
filename should be relative to the toplevel using / as a path
separator.
"""
end = '\n***\n\n' + end
with common.slashfix_open(filename, 'r') as f:
content = f.read()
if content.endswith(end):
# No need to do anything.
print(" Has correct end:", filename)
return
if '\n***\n' in content:
# We need to remove the old ending first.
print(" Removing old end:", filename)
where = content.index('\n***\n')
with common.slashfix_open(filename, 'w') as f:
f.write(content[:where])
print(" Adding end:", filename)
with common.slashfix_open(filename, 'a') as f:
f.write(end)
def main():
chapter_files, other_files = get_filenames()
# make previous of first file and next of last file to just bring
# back to README
prevs = ['README.md'] + chapter_files[:-1]
nexts = chapter_files[1:] + ['README.md']
print("Chapter files:")
for prevpath, thispath, nextpath in zip(prevs, chapter_files, nexts):
# all paths should be like 'section/file.md'
where = posixpath.dirname(thispath)
prev = posixpath.relpath(prevpath, where)
next_ = posixpath.relpath(nextpath, where)
extralinks = "[Previous](%s) | [Next](%s) |\n" % (prev, next_)
end = END_TEMPLATE.format(
toplevel='..', extralinks=extralinks, readmeheader=where)
update_end(thispath, end)
print()
print("Other files:")
for filename in other_files:
where = posixpath.dirname(filename)
end = END_TEMPLATE.format(
toplevel=posixpath.relpath('.', where),
extralinks="", readmeheader='list-of-contents')
update_end(filename, end)
if __name__ == '__main__':
main()