mirror of
https://github.com/containers/podman.git
synced 2025-05-17 23:26:08 +08:00

Updated build scripts and installer build scripts to include gvproxy.exe. Includes tutorial on setting up a Podman VM with QEMU and gvproxy on Windows. Signed-off-by: Arthur Sengileyev <arthur.sengileyev@gmail.com>
185 lines
7.3 KiB
Python
Executable File
185 lines
7.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# markdown-preprocess - filter *.md.in files, convert to .md
|
|
#
|
|
"""
|
|
Simpleminded include mechanism for podman man pages.
|
|
"""
|
|
|
|
import filecmp
|
|
import glob
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
class Preprocessor():
|
|
"""
|
|
Doesn't really merit a whole OO approach, except we have a lot
|
|
of state variables to pass around, and self is a convenient
|
|
way to do that. Better than globals, anyway.
|
|
"""
|
|
def __init__(self):
|
|
self.infile = ''
|
|
self.pod_or_container = ''
|
|
self.used_by = {}
|
|
|
|
def process(self, infile:str):
|
|
"""
|
|
Main calling point: preprocesses one file
|
|
"""
|
|
self.infile = infile
|
|
# Some options are the same between containers and pods; determine
|
|
# which description to use from the name of the source man page.
|
|
self.pod_or_container = 'container'
|
|
if '-pod-' in infile or '-kube-' in infile:
|
|
self.pod_or_container = 'pod'
|
|
|
|
# foo.md.in -> foo.md -- but always write to a tmpfile
|
|
outfile = os.path.splitext(infile)[0]
|
|
outfile_tmp = outfile + '.tmp.' + str(os.getpid())
|
|
|
|
with open(infile, 'r', encoding='utf-8') as fh_in, open(outfile_tmp, 'w', encoding='utf-8', newline='\n') 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')
|
|
self.track_optionfile(optionfile)
|
|
self.insert_file(fh_out, optionfile)
|
|
# '@@include relative-path/must-exist.md'
|
|
elif line.startswith('@@include '):
|
|
_, path = line.strip().split(" ")
|
|
self.insert_file(fh_out, path)
|
|
else:
|
|
fh_out.write(line)
|
|
|
|
os.chmod(outfile_tmp, 0o444)
|
|
os.rename(outfile_tmp, outfile)
|
|
|
|
def track_optionfile(self, optionfile: str):
|
|
"""
|
|
Keep track of which man pages use which option files
|
|
"""
|
|
if optionfile not in self.used_by:
|
|
self.used_by[optionfile] = []
|
|
self.used_by[optionfile].append(self.podman_subcommand('full'))
|
|
|
|
def rewrite_optionfiles(self):
|
|
"""
|
|
Rewrite all option files, such that they include header comments
|
|
cross-referencing all the man pages in which they're used.
|
|
"""
|
|
for optionfile in self.used_by:
|
|
tmpfile = optionfile + '.tmp'
|
|
with open(optionfile, 'r', encoding='utf-8') as fh_in, open(tmpfile, 'w', encoding='utf-8', newline='\n') as fh_out:
|
|
fh_out.write("####> This option file is used in:\n")
|
|
used_by = ', '.join(x for x in self.used_by[optionfile])
|
|
fh_out.write(f"####> podman {used_by}\n")
|
|
fh_out.write("####> If file is edited, make sure the changes\n")
|
|
fh_out.write("####> are applicable to all of those.\n")
|
|
for line in fh_in:
|
|
if not line.startswith('####>'):
|
|
fh_out.write(line)
|
|
# Compare files; only rewrite if the new one differs
|
|
if not filecmp.cmp(optionfile, tmpfile):
|
|
os.unlink(optionfile)
|
|
os.rename(tmpfile, optionfile)
|
|
else:
|
|
os.unlink(tmpfile)
|
|
|
|
def insert_file(self, fh_out, path: str):
|
|
"""
|
|
Reads one option file, writes it out to the given output filehandle
|
|
"""
|
|
# 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 " + path + ")\n")
|
|
with open(path, 'r', encoding='utf-8') as fh_included:
|
|
for opt_line in fh_included:
|
|
if opt_line.startswith('####>'):
|
|
continue
|
|
opt_line = self.replace_type(opt_line)
|
|
opt_line = opt_line.replace('<<subcommand>>', self.podman_subcommand())
|
|
opt_line = opt_line.replace('<<fullsubcommand>>', self.podman_subcommand('full'))
|
|
fh_out.write(opt_line)
|
|
fh_out.write("\n[//]: # (END included file " + path + ")\n")
|
|
|
|
def podman_subcommand(self, full=None) -> str:
|
|
"""
|
|
Returns the string form of the podman command, based on man page name;
|
|
e.g., 'foo bar' for podman-foo-bar.1.md.in
|
|
"""
|
|
subcommand = self.infile
|
|
# Special case: 'podman-pod-start' becomes just 'start'
|
|
if not full:
|
|
if subcommand.startswith("podman-pod-"):
|
|
subcommand = subcommand[len("podman-pod-"):]
|
|
if subcommand.startswith("podman-"):
|
|
subcommand = subcommand[len("podman-"):]
|
|
if subcommand.endswith(".1.md.in"):
|
|
subcommand = subcommand[:-len(".1.md.in")]
|
|
return subcommand.replace("-", " ")
|
|
|
|
def replace_type(self, line: str) -> str:
|
|
"""
|
|
Replace instances of '<<pod string|container string>>' with the
|
|
appropriate one based on whether this is a pod-related man page
|
|
or not.
|
|
"""
|
|
# 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(f"'{matchobj[0]}' matches 'pod' in both left and right sides")
|
|
# Only left-hand side has "pod"
|
|
if self.pod_or_container == 'pod':
|
|
return lhs
|
|
return rhs
|
|
|
|
# 'pod' not in lhs, must be in rhs
|
|
if not re.match('.*pod([^m]|$)', rhs, re.IGNORECASE):
|
|
raise Exception(f"'{matchobj[0]}' does not match 'pod' in either side")
|
|
if self.pod_or_container == 'pod':
|
|
return rhs
|
|
return lhs
|
|
|
|
return re.sub(r'<<[^\|>]*\|[^\|>]*>>', replwith, line)
|
|
|
|
|
|
def main():
|
|
"script entry point"
|
|
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 as ex:
|
|
raise Exception("Please invoke me from the base repo dir") from ex
|
|
|
|
# No longer possible to invoke us with args: reject any such invocation
|
|
if len(sys.argv) > 1:
|
|
raise Exception("This script accepts no arguments")
|
|
|
|
preprocessor = Preprocessor()
|
|
for infile in sorted(glob.glob('*.md.in')):
|
|
preprocessor.process(infile)
|
|
|
|
# Now rewrite all option files
|
|
preprocessor.rewrite_optionfiles()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|