#!/usr/bin/env python3
"""
Auto-generates documentation from command defs in console.py.
"""
import html
import os
import re
import shutil
import textwrap
from twitchdl.console import COMMANDS
START_MARKER = ""
END_MARKER = ""
def main():
update_changelog()
for command in COMMANDS:
update_docs(command)
def update_changelog():
print("Updating: docs/changelog.md")
root = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
source = os.path.join(root, "CHANGELOG.md")
target = os.path.join(root, "docs/changelog.md")
shutil.copy(source, target)
def update_docs(command):
path = os.path.join("docs", "commands", f"{command.name}.md")
content = render_command(command)
if not os.path.exists(path):
print(f"Creating: {path}")
write(path, content)
else:
print(f"Updating: {path}")
[_, handwritten] = read(path).split(END_MARKER)
content = f"{content.strip()}\n\n{END_MARKER}\n\n{handwritten.strip()}"
write(path, content)
def render_command(command):
content = START_MARKER
content += f"\n# twitch-dl {command.name}\n\n"
content += command.description + "\n\n"
content += render_usage(command)
content += render_arguments(command)
content += render_flags(command)
content += render_options(command)
return content
def render_usage(command):
arguments = get_arguments(command)
arguments = " ".join(f"<{name}>" for [name, _] in arguments)
flags = get_flags(command)
options = get_options(command)
content = "### USAGE\n\n"
content += "```\n"
content += f"twitch-dl {command.name} {arguments}"
if flags:
content += " [FLAGS]"
if options:
content += " [OPTIONS]"
content += "\n```\n\n"
return content
def render_arguments(command):
arguments = get_arguments(command)
if not arguments:
return ""
content = "### ARGUMENTS\n\n"
content += "
\n"
content += ""
for [name, params] in arguments:
content += textwrap.dedent(f"""
<{escape(name)}> |
{escape(params['help'])} |
""")
content += "\n"
content += "
\n\n"
return content
def render_flags(command):
flags = get_flags(command)
if not flags:
return ""
content = "### FLAGS\n\n"
content += "\n"
content += ""
for [names, params] in flags:
names = ", ".join(f"{name}" for name in names)
content += textwrap.dedent(f"""
{escape(names)} |
{escape(params['help'])} |
""")
content += "\n"
content += "
\n\n"
return content
def render_options(command):
options = get_options(command)
if not options:
return ""
content = "### OPTIONS\n\n"
content += "\n"
content += ""
for [names, params] in options:
names = ", ".join(f"{name}" for name in names)
content += textwrap.dedent(f"""
{escape(names)} |
{escape(params['help'])}{choices(params)} |
""")
content += "\n"
content += "
\n\n"
return content
def choices(params):
if "choices" in params:
choices = ", ".join(code(c) for c in params["choices"])
return f" Possible values: {choices}."
return ""
def get_arguments(command):
return [
[names[0], options]
for names, options in command.arguments
if len(names) == 1 and not names[0].startswith("-")
]
def get_flags(command):
return [
[names, options]
for names, options in command.arguments
if names[0].startswith("-") and "type" not in options
]
def get_options(command):
return [
[names, options]
for names, options in command.arguments
if names[0].startswith("-") and "type" in options
]
def read(path):
with open(path, "r") as f:
return f.read()
def write(path, content):
with open(path, "w") as f:
return f.write(content)
def code(string):
return f"{string}
"
def escape(text: str):
text = html.escape(text)
text = re.sub(r"`([\S]+)`", "\\1
", text)
return text
if __name__ == "__main__":
main()