docmachine/scripts/update-toc

155 lines
4.6 KiB
Python
Executable file

#!/usr/bin/env python3
import click
import os
import re
import pdb
import pprint
from pathlib import Path
pp = pprint.PrettyPrinter(indent=4).pprint
class TocBuilder:
def __init__(self, root_path):
self.root_path = root_path
# Helper for titles
def __get_title(self, fn):
if not os.path.exists(fn):
return None
f1 = open(fn, "r")
for line in f1:
m = re.match(r"^#\s(.*)$", line)
if m:
f1.close()
return m.groups()[0]
f1.close()
return None
def is_masked(self, rel_path):
parts = rel_path.split('/')[::-1]
for part in parts:
# print(" * Testing for '_' {}".format(part))
if part[0] == '_':
return True
return False
def lookup(self):
md_files = []
for root, dirs, files in os.walk(self.root_path):
for fn in files:
print("Found {}".format(fn), end='\r')
# compute absolute and relative path
abs_path = os.path.join(root, fn)
rel_path = os.path.relpath(abs_path, self.root_path)
# split name into parts
bname = os.path.basename(rel_path)
bname_split = os.path.splitext(bname)
dname = os.path.dirname(rel_path)
# skip files in docs/ root
# if dname == "":
# continue
# skip files starting with '_'
#if bname_split[0][0] == '_':
if self.is_masked(rel_path):
print("Found {} which is masked. Ignoring".format(fn))
continue
# skip index files
if bname_split[0] == 'index':
print("Found {} which is an index file. Ignoring".format(fn))
continue
# keep only .md files
print("* keeping {}".format(rel_path))
if bname_split[1] == '.md':
md_files.append(rel_path)
print("Found {}. Keeping".format(fn))
return md_files
def format(self, md_files):
lines = ["nav:"]
lastdir=""
for f in sorted(md_files):
bname = os.path.basename(f)
bname_split = os.path.splitext(bname)
dname = os.path.dirname(f)
if lastdir != dname and dname != "":
lastdir = dname
title = self.__get_title(os.path.join(self.root_path, dname, 'index.md'))
if title is not None:
lines.append(" - \"%s\":" % title)
else:
lines.append(" - \"%s\":" % dname)
if dname != "":
lines.append(" - %s" % f)
else:
lines.append(" - %s" % f)
return lines
class FileInjector:
def __init__(self, delimiter):
self.delimiter = delimiter
def inject(self, filename, lines):
suffix = '~update_toc'
src_fh = open(filename, 'r')
dst_fh = open(filename + suffix, 'w')
inject_mode = False
end_pattern = r"^#\s+END {0}\s*$".format(self.delimiter)
begin_pattern = r"^#\s+BEGIN {0}\s*$".format(self.delimiter)
for src_line in src_fh:
if (not inject_mode) and re.match(begin_pattern, src_line):
# activate inject_mode, write begin pattern and lines
inject_mode = True
dst_fh.write(src_line)
for line in lines:
dst_fh.write(line + "\n")
elif inject_mode and re.match(end_pattern, src_line):
# disable inject_mode and write end pattern
inject_mode = False
dst_fh.write(src_line)
elif inject_mode:
# skip line if injection mode is active
next
else:
# simple copy if injection mode is NOT active
dst_fh.write(src_line)
# si la ligne <
# FIXME: error if inject_mode is still True
src_fh.close()
dst_fh.close()
os.rename(filename + suffix, filename)
# build TOC in-memory
#
# open mkdocs.yml file
# save part before
@click.command()
@click.argument('docs_directory')
def build(docs_directory):
root_path = Path(__file__).parent.parent
toc = TocBuilder(docs_directory)
md_files = toc.lookup()
md_toc = toc.format(md_files)
fi = FileInjector('MKDOCS-TOC')
fi.inject(str(root_path / 'mkdocs.yml'), md_toc)
if __name__ == '__main__':
build()