145 lines
4.2 KiB
Python
Executable file
145 lines
4.2 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:
|
|
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))
|
|
# 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):
|
|
continue
|
|
|
|
# skip index files
|
|
if bname_split[0] == 'index':
|
|
continue
|
|
|
|
# keep only .md files
|
|
print("* keeping {}".format(rel_path))
|
|
if bname_split[1] == '.md':
|
|
md_files.append(rel_path)
|
|
|
|
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:
|
|
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)
|
|
|
|
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()
|
|
|