otbGenerateExamplesRstDoc.py 4.85 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#!/usr/bin/env python3
#
# Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
#
# This file is part of Orfeo Toolbox
#
#     https://www.orfeo-toolbox.org/
#
# 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 argparse
import os
import os.path
from os.path import join
from collections import defaultdict
import re
import glob

30
from rst_utils import rst_section, RstPageHeading, examples_usage_regex
31 32 33 34 35 36 37 38 39 40 41 42 43 44

def generate_examples_index(rst_dir, list_of_examples):

    # Compute dictionary of tag -> (list of examples)
    tag_files = defaultdict(list)
    for filename in list_of_examples:
        tag = filename.split("/")[1]
        name, _ = os.path.splitext(filename.split("/")[2])

        tag_files[tag].append(join(tag, name + ".rst"))

    # Render index file and tag index files
    os.makedirs(join(rst_dir, "Examples"), exist_ok=True)
    index_f = open(join(rst_dir, "Examples.rst"), "w")
45
    index_f.write(RstPageHeading("C++ Examples", 3, ref="cpp-examples"))
46

47
    for tag, examples_filenames in sorted(tag_files.items()):
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
        tag_filename = join("Examples", tag + ".rst")
        index_f.write("\t" + tag_filename + "\n")

        with open(join(rst_dir, tag_filename), "w") as tag_f:
            tag_f.write(RstPageHeading(tag, 3))

            for examples_filename in examples_filenames:
                tag_f.write("\t" + examples_filename + "\n")

def indent(str):
    return "\n".join(["    " + line for line in str.split("\n")])

def cpp_uncomment(code):
    # Strip '//  '
    return "\n".join([line[4:] for line in code.split("\n")])

def render_example(filename, otb_root):
    "Render a cxx example to rst"

    # Read the source code of the cxx example
    code = open(join(otb_root, filename)).read()

    # Don't show the license header to make it nicer,
    # and the cookbook is already under a CC license
    examples_license_header = open("templates/examples_license_header.txt").read()
    code = code.replace(examples_license_header, "")

75 76 77 78 79 80 81
    # Extract usages
    example_usage = ""
    usage_matches = list(re.finditer(examples_usage_regex, code, flags = re.MULTILINE | re.DOTALL))

    examples_usage_template = open("templates/example_usage.rst").read()
    for match in usage_matches:
        example_usage += examples_usage_template.format(indent(match.group(1).strip()))
82 83

    # Don't show usage in example source
84
    code = re.sub(examples_usage_regex, "", code, flags = re.MULTILINE | re.DOTALL)
85 86 87 88 89 90 91 92 93 94 95 96 97

    # Make the link to the source code
    link_name = os.path.basename(filename)
    link_href = "https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/raw/develop/" + filename + "?inline=false"

    # Read the description from the example .rst file if it exists
    example_rst_file = join(otb_root, filename.replace(".cxx", ".rst"))
    if os.path.isfile(example_rst_file):
        rst_description = open(example_rst_file).read()
    else:
        rst_description = ""

    # Render the template
98
    name = os.path.basename(filename)
99 100
    template_example = open("templates/example.rst").read()
    output_rst = template_example.format(
101
        label=name,
102 103 104 105 106 107 108 109 110 111
        heading=rst_section(name, "="),
        description=rst_description,
        usage=example_usage,
        code=indent(code.strip()),
        link_name=link_name,
        link_href=link_href
    )

    return output_rst

112
def main():
113 114 115 116 117 118
    parser = argparse.ArgumentParser(usage="Export examples to rst")
    parser.add_argument("rst_dir", help="Directory where rst files are generated")
    parser.add_argument("otb_root", help="OTB repository root")
    args = parser.parse_args()

    # Get list of cxx examples as relative paths from otb_root
119
    list_of_examples = [os.path.relpath(p, start=args.otb_root) for p in sorted(glob.glob(join(args.otb_root, "Examples/*/*.cxx")))]
120 121 122 123 124 125 126 127 128 129 130 131 132 133
    print("Generating rst for {} examples".format(len(list_of_examples)))

    # Generate example index and tag indexes
    generate_examples_index(join(args.rst_dir, "C++"), list_of_examples)

    # Generate examples rst
    for filename in list_of_examples:
        name = os.path.basename(filename)
        tag = filename.split("/")[1]
        root, ext = os.path.splitext(name)

        os.makedirs(join(args.rst_dir, "C++", "Examples", tag), exist_ok=True)
        with open(join(args.rst_dir, "C++", "Examples", tag, root + ".rst"), "w") as output_file:
            output_file.write(render_example(filename, args.otb_root))
134 135 136

if __name__ == "__main__":
    main()