summaryrefslogtreecommitdiff
path: root/hack/markdown-preprocess
blob: 68e5890d8cb5c3a0dd041f74b474b5dd316e0744 (plain)
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env python3
#
# markdown-preprocess - filter *.md.in files, convert to .md
#

import glob
import os
import re
import sys

def main():
    script_dir = os.path.abspath(os.path.dirname(__file__))
    man_dir = os.path.join(script_dir,"../docs/source/markdown")

    try:
        os.chdir(man_dir)
    except FileNotFoundError:
        raise Exception("Please invoke me from the base repo dir")

    # If called with args, process only those files
    infiles = [ os.path.basename(x) for x in sys.argv[1:] ]
    if len(infiles) == 0:
        # Called without args: process all *.md.in files
        infiles = glob.glob('*.md.in')
    for infile in infiles:
        process(infile)

def process(infile):
    # Some options are the same between containers and pods; determine
    # which description to use from the name of the source man page.
    pod_or_container = 'container'
    if '-pod-' in infile or '-kube-' in infile:
        pod_or_container = 'pod'

    # Sometimes a man page includes the subcommand.
    subcommand = podman_subcommand(infile)

    # foo.md.in -> foo.md -- but always write to a tmpfile
    outfile = os.path.splitext(infile)[0]
    outfile_tmp = outfile + '.tmp.' + str(os.getpid())

#    print("got here: ",infile, " -> ", outfile)

    with open(infile, 'r') as fh_in, open(outfile_tmp, 'w') as fh_out:
        for line in fh_in:
            # '@@option foo' -> include file options/foo.md
            if line.startswith('@@option '):
                _, optionname = line.strip().split(" ")
                optionfile = os.path.join("options", optionname + '.md')

                # Comment intended to help someone viewing the .md file.
                # Leading newline is important because if two lines are
                # consecutive without a break, sphinx (but not go-md2man)
                # treats them as one line and will unwantedly render the
                # comment in its output.
                fh_out.write("\n[//]: # (BEGIN included file " + optionfile + ")\n")
                with open(optionfile, 'r') as fh_optfile:
                    for opt_line in fh_optfile:
                        opt_line = replace_type(opt_line, pod_or_container)
                        opt_line = opt_line.replace('<<subcommand>>', subcommand)
                        fh_out.write(opt_line)
                fh_out.write("\n[//]: # (END   included file " + optionfile + ")\n")
            else:
                fh_out.write(line)

    os.chmod(outfile_tmp, 0o444)
    os.rename(outfile_tmp, outfile)

# Given a file path of the form podman-foo-bar.1.md.in, return "foo bar"
def podman_subcommand(string: str) -> str:
    # Special case: 'podman-pod-start' becomes just 'start'
    if string.startswith("podman-pod-"):
        string = string[len("podman-pod-"):]
    if string.startswith("podman-"):
        string = string[len("podman-"):]
    if string.endswith(".1.md.in"):
        string = string[:-len(".1.md.in")]
    return string.replace("-", " ")

# Replace instances of '<<pod|container>>' with the desired one (based on
# 'type' which is 'pod' or 'container').
def replace_type(line: str, type: str) -> str:
    # Internal helper function: determines the desired half of the <a|b> string
    def replwith(matchobj):
        lhs, rhs = matchobj[0].split('|')
        # Strip off '<<' and '>>'
        lhs = lhs[2:]
        rhs = rhs[:len(rhs)-2]

        # Check both sides for 'pod' followed by (non-"m" or end-of-string).
        # The non-m prevents us from triggering on 'podman', which could
        # conceivably be present in both sides. And we check for 'pod',
        # not 'container', because it's possible to have something like
        # <<container in pod|container>>.
        if re.match('.*pod([^m]|$)', lhs, re.IGNORECASE):
            if re.match('.*pod([^m]|$)', rhs, re.IGNORECASE):
                raise Exception("'%s' matches 'pod' in both left and right sides" % matchobj[0])
            # Only left-hand side has "pod"
            if type == 'pod':
                return lhs
            else:
                return rhs
        else:
            if not re.match('.*pod([^m]|$)', rhs, re.IGNORECASE):
                raise Exception("'%s' does not match 'pod' in either side" % matchobj[0])
            if type == 'pod':
                return rhs
            else:
                return lhs

    return re.sub('<<[^\|>]*\|[^\|>]*>>', replwith, line)

if __name__ == "__main__":
    main()