generate_example_docs.py 6.59 KB
Newer Older
1
#!/usr/bin/env python3
2

3
import os
4
import json
5
import argparse
6
7
8
9
import sys

if sys.version_info[0] < 3:
    sys.exit("Python 3 or a more recent version is required.")
10

11
from convert_code_to_doc import *
12

13
class Navigation:
14
    """Add navigation bars to examples with subpages"""
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

    def __init__(self, config, dir):
        # read and check the configuration
        if "mainpage" not in config:
            raise IOError("The .doc_config navigation section has to contain a mainpage entry!")
        mainpage = config["mainpage"]
        if "subpages" not in config:
            raise IOError("The .doc_config navigation section has to contain a subpages entry!")
        if len(config["subpages"]) < 1:
            raise IOError("The .doc_config navigation:subpages array has to have at least one entry!")
        subpages = config["subpages"]
        if "subtitles" not in config:
            subtitles = ["Part {} of the documentation".format(i+1) for i in range(len(subpages))]
        else:
            if len(config["subtitles"]) != len(subpages):
                raise IOError("In the .doc_config navigation section the subpages array has to have the same length as the subtitles array!")
            subtitles = ["Part {}: {}".format(i+1, t) for i, t in enumerate(config["subtitles"])]
        self.dir = dir # the working directory

        # create the snippets to insert into the docs
        self.snippets = {}

        # first the navigation snippet for the main page
        self.snippets[mainpage] = { "header" : "", "footer" : "" }
        makeHead = lambda t: "\n## {}\n\n".format(t)
        makeEntry = lambda i,l: "| [:arrow_right: Click to continue with part {} of the documentation]({}) |\n|---:|\n\n".format(i,l)
41
        self.snippets[mainpage]["footer"] = "".join(
42
            [ makeHead(title) + makeEntry(index+1, self.getRelPath(mainpage, subpage)) for index, (subpage, title) in enumerate(zip(subpages, subtitles))]
43
        ).rstrip() + '\n' # end file with a single endline character
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

        # then the navigation snippets for the subpages
        pagetypes = ["mid" for i in range(len(subpages))]
        pagetypes[0] = "first"
        pagetypes[-1] = "last"
        for index, (subpage, pagetype) in enumerate(zip(subpages, pagetypes)):
            self.snippets[subpage] = { "header" : "", "footer" : "" }
            if pagetype == "mid":
                self.snippets[subpage]["header"] = " ".join(["\n|",
                    "[:arrow_left: Back to the main documentation](" + self.getRelPath(subpage, mainpage) +  ") |",
                    "[:arrow_left: Go back to part {}]".format(index) + "(" + self.getRelPath(subpage, subpages[index-1]) +  ") |",
                    "[:arrow_right: Continue with part {}]".format(index+2) + "(" + self.getRelPath(subpage, subpages[index+1]) +  ") |"
                ]) + "\n|---|---|---:|\n\n"
            elif pagetype == "last":
                self.snippets[subpage]["header"] = " ".join(["\n|",
                    "[:arrow_left: Back to the main documentation](" + self.getRelPath(subpage, mainpage) +  ") |",
                    "[:arrow_left: Go back to part {}]".format(index) + "(" + self.getRelPath(subpage, subpages[index-1]) +  ") |"
                ]) + "\n|---|---:|\n\n"
            else: # first subpage
                self.snippets[subpage]["header"] = " ".join(["\n|",
                    "[:arrow_left: Back to the main documentation](" + self.getRelPath(subpage, mainpage) +  ") |",
                    "[:arrow_right: Continue with part {}]".format(index+2) + "(" + self.getRelPath(subpage, subpages[index+1]) +  ") |"
                ]) + "\n|---|---:|\n\n"
            # for subpages header and footer are the same
            self.snippets[subpage]["footer"] = self.snippets[subpage]["header"]

    def getRelPath(self, page, target):
        absPageBasePath = os.path.split(os.path.abspath(os.path.join(self.dir, page)))[0]
        absTargetPath = os.path.abspath(os.path.join(self.dir, target))
        return os.path.relpath(absTargetPath, absPageBasePath)

    def header(self, page):
        return self.snippets[page]["header"]

    def footer(self, page):
        return self.snippets[page]["footer"]


def convertToMarkdownAndMerge(dir, config, navigation=None):
83
84
85
86
87
88
89
90
91
92
93

    for target, sources in config.items():

        targetExtension = os.path.splitext(target)[1]
        if not targetExtension == ".md":
            raise IOError("Markdown files expected as targets! Given target: {}".format(target))

        targetPath = os.path.join(dir, target)
        os.makedirs(os.path.dirname(targetPath), exist_ok=True)

        with open(targetPath, "w") as targetFile:
94
95
            thisScript = os.path.basename(__file__)
            targetFile.write("<!-- Important: This file has been automatically generated by {}. Do not edit this file directly! -->\n\n".format(thisScript))
96
97
            if navigation:
                targetFile.write(navigation.header(target))
98
99
100
101
102
103
104
            for source in sources:
                fileExtension = os.path.splitext(source)[1]
                if fileExtension == ".md":
                    with open(os.path.join(dir, source), "r") as markdown:
                        targetFile.write(markdown.read())
                elif fileExtension == ".hh" or fileExtension == ".cc":
                    with open(os.path.join(dir, source), "r") as cppCode:
105
                        sourceRelPath = os.path.relpath(os.path.abspath(os.path.join(dir, source)), os.path.split(os.path.abspath(targetPath))[0])
106
                        targetFile.write("\n\n" + transformCode(cppCode.read(), cppRules(), sourceRelPath) + "\n")
107
108
                else:
                    raise IOError("Unsupported or unknown file extension *{}".format(fileExtension))
109
110
            if navigation:
                targetFile.write(navigation.footer(target))
111
112

def generateReadme(dir):
113
    config = None
114
    # look for .doc_config, if not found we pass
115
116
    try:
        configname = os.path.join(dir, ".doc_config")
117
118
        with open(configname, 'r') as configFile:
            config = json.load(configFile)
119
    except FileNotFoundError:
120
        pass
121
    if config is not None:
122
123
124
125
        navigation = None
        if "navigation" in config:
            navigation = Navigation(config.pop("navigation"), dir)
        convertToMarkdownAndMerge(dir, config, navigation)
126

127
128
129
130
131
132
133
134
135
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-d", "--directory", help="The folder to look for examples", default=".")
    args = vars(parser.parse_args())

    for path in os.listdir(args["directory"]):
        abspath = os.path.join(os.path.abspath(args["directory"]), path)
        if os.path.isdir(abspath):
            generateReadme(abspath)