6
Simpleminded include mechanism for podman man pages.
17
Doesn't really merit a whole OO approach, except we have a lot
18
of state variables to pass around, and self is a convenient
19
way to do that. Better than globals, anyway.
23
self.pod_or_container = ''
26
def process(self, infile:str):
28
Main calling point: preprocesses one file
33
self.pod_or_container = 'container'
34
if '-pod-' in infile or '-kube-' in infile:
35
self.pod_or_container = 'pod'
38
outfile = os.path.splitext(infile)[0]
39
outfile_tmp = outfile + '.tmp.' + str(os.getpid())
41
with open(infile, 'r', encoding='utf-8') as fh_in, open(outfile_tmp, 'w', encoding='utf-8', newline='\n') as fh_out:
44
if line.startswith('@@option '):
45
_, optionname = line.strip().split(" ")
46
optionfile = os.path.join("options", optionname + '.md')
47
self.track_optionfile(optionfile)
48
self.insert_file(fh_out, optionfile)
50
elif line.startswith('@@include '):
51
_, path = line.strip().split(" ")
52
self.insert_file(fh_out, path)
56
os.chmod(outfile_tmp, 0o444)
57
os.rename(outfile_tmp, outfile)
59
def track_optionfile(self, optionfile: str):
61
Keep track of which man pages use which option files
63
if optionfile not in self.used_by:
64
self.used_by[optionfile] = []
65
self.used_by[optionfile].append(self.podman_subcommand('full'))
67
def rewrite_optionfiles(self):
69
Rewrite all option files, such that they include header comments
70
cross-referencing all the man pages in which they're used.
72
for optionfile in self.used_by:
73
tmpfile = optionfile + '.tmp.' + str(os.getpid())
74
with open(optionfile, 'r', encoding='utf-8') as fh_in, open(tmpfile, 'w', encoding='utf-8', newline='\n') as fh_out:
75
fh_out.write("####> This option file is used in:\n")
76
used_by = ', '.join(x for x in self.used_by[optionfile])
77
fh_out.write(f"####> podman {used_by}\n")
78
fh_out.write("####> If file is edited, make sure the changes\n")
79
fh_out.write("####> are applicable to all of those.\n")
81
if not line.startswith('####>'):
84
if not filecmp.cmp(optionfile, tmpfile):
86
os.rename(tmpfile, optionfile)
90
def insert_file(self, fh_out, path: str):
92
Reads one option file, writes it out to the given output filehandle
99
fh_out.write("\n[//]: # (BEGIN included file " + path + ")\n")
100
with open(path, 'r', encoding='utf-8') as fh_included:
101
for opt_line in fh_included:
102
if opt_line.startswith('####>'):
104
opt_line = self.replace_type(opt_line)
105
opt_line = opt_line.replace('<<subcommand>>', self.podman_subcommand())
106
opt_line = opt_line.replace('<<fullsubcommand>>', self.podman_subcommand('full'))
107
fh_out.write(opt_line)
108
fh_out.write("\n[//]: # (END included file " + path + ")\n")
110
def podman_subcommand(self, full=None) -> str:
112
Returns the string form of the podman command, based on man page name;
113
e.g., 'foo bar' for podman-foo-bar.1.md.in
115
subcommand = self.infile
118
if subcommand.startswith("podman-pod-"):
119
subcommand = subcommand[len("podman-pod-"):]
120
if subcommand.startswith("podman-"):
121
subcommand = subcommand[len("podman-"):]
122
if subcommand.endswith(".1.md.in"):
123
subcommand = subcommand[:-len(".1.md.in")]
124
return subcommand.replace("-", " ")
126
def replace_type(self, line: str) -> str:
128
Replace instances of '<<pod string|container string>>' with the
129
appropriate one based on whether this is a pod-related man page
133
def replwith(matchobj):
134
lhs, rhs = matchobj[0].split('|')
137
rhs = rhs[:len(rhs)-2]
144
if re.match('.*pod([^m]|$)', lhs, re.IGNORECASE):
145
if re.match('.*pod([^m]|$)', rhs, re.IGNORECASE):
146
raise Exception(f"'{matchobj[0]}' matches 'pod' in both left and right sides")
148
if self.pod_or_container == 'pod':
153
if not re.match('.*pod([^m]|$)', rhs, re.IGNORECASE):
154
raise Exception(f"'{matchobj[0]}' does not match 'pod' in either side")
155
if self.pod_or_container == 'pod':
159
return re.sub(r'<<[^\|>]*\|[^\|>]*>>', replwith, line)
164
script_dir = os.path.abspath(os.path.dirname(__file__))
165
man_dir = os.path.join(script_dir,"../docs/source/markdown")
169
except FileNotFoundError as ex:
170
raise Exception("Please invoke me from the base repo dir") from ex
173
if len(sys.argv) > 1:
174
raise Exception("This script accepts no arguments")
176
preprocessor = Preprocessor()
177
for infile in sorted(glob.glob('*.md.in')):
178
preprocessor.process(infile)
181
preprocessor.rewrite_optionfiles()
183
if __name__ == "__main__":