docs: handle new github admonitions and cleanup write-mkdocs script
This commit is contained in:
@@ -1,13 +1,19 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
from collections.abc import Callable
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
def get_nav_from_selector(soup, selector, docs_dir):
|
|
||||||
|
def get_nav_from_selector(soup: BeautifulSoup, selector: str, docs_dir: str):
|
||||||
|
"""
|
||||||
|
Generates navigation from template file
|
||||||
|
"""
|
||||||
navigation = []
|
navigation = []
|
||||||
header_name = ""
|
header_name = ""
|
||||||
for anchor in soup.select(selector):
|
for anchor in soup.select(selector):
|
||||||
@@ -49,44 +55,50 @@ def get_nav_from_selector(soup, selector, docs_dir):
|
|||||||
children = os.listdir(docs_dir + "/" + child_dir)
|
children = os.listdir(docs_dir + "/" + child_dir)
|
||||||
children = [child_dir + c for c in children]
|
children = [child_dir + c for c in children]
|
||||||
children.sort()
|
children.sort()
|
||||||
children.insert(
|
children.insert(0, "getting-started/advanced-installation.md")
|
||||||
0, "getting-started/advanced-installation.md")
|
|
||||||
if os.path.exists(docs_dir + "/" + filename):
|
if os.path.exists(docs_dir + "/" + filename):
|
||||||
children.insert(0, filename)
|
children.insert(0, filename)
|
||||||
else:
|
else:
|
||||||
children.insert(
|
children.insert(0, "getting-started/installation/index.md")
|
||||||
0, "getting-started/installation/index.md")
|
nav[header_name].append(
|
||||||
nav[header_name].append({
|
{
|
||||||
"Getting Started with Dokku": children,
|
"Getting Started with Dokku": children,
|
||||||
})
|
}
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
elif filename == "getting-started/upgrading.md":
|
|
||||||
|
if filename == "getting-started/upgrading.md":
|
||||||
child_dir = "appendices/"
|
child_dir = "appendices/"
|
||||||
children = os.listdir(docs_dir + "/" + child_dir)
|
children = os.listdir(docs_dir + "/" + child_dir)
|
||||||
|
|
||||||
children.sort(key=lambda x: list(
|
children.sort(
|
||||||
map(int, x.split("-")[0].split('.'))),
|
key=lambda x: list(map(int, x.split("-")[0].split("."))),
|
||||||
reverse=True)
|
reverse=True,
|
||||||
|
)
|
||||||
children = [child_dir + c for c in children]
|
children = [child_dir + c for c in children]
|
||||||
if os.path.exists(docs_dir + "/" + filename):
|
if os.path.exists(docs_dir + "/" + filename):
|
||||||
children.insert(0, filename)
|
children.insert(0, filename)
|
||||||
else:
|
else:
|
||||||
children.insert(
|
children.insert(0, "getting-started/upgrading/index.md")
|
||||||
0, "getting-started/upgrading/index.md")
|
nav[header_name].append(
|
||||||
nav[header_name].append({
|
{
|
||||||
"Upgrading": children,
|
"Upgrading": children,
|
||||||
})
|
}
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
else:
|
|
||||||
nav[header_name].append(filename)
|
nav[header_name].append(filename)
|
||||||
return navigation
|
return navigation
|
||||||
|
|
||||||
|
|
||||||
def generate_nav(src, dest):
|
def generate_nav(src: str, dest: str) -> None:
|
||||||
|
"""
|
||||||
|
Writes out navigation information to the mkdocs yaml file
|
||||||
|
"""
|
||||||
navigation = []
|
navigation = []
|
||||||
repo_dir = pathlib.Path(__file__).parent.parent.resolve()
|
repo_dir = pathlib.Path(__file__).parent.parent.resolve()
|
||||||
docs_dir = str(repo_dir) + "/docs"
|
docs_dir = str(repo_dir) + "/docs"
|
||||||
with open(docs_dir + "/template.html") as response:
|
with open(docs_dir + "/template.html", encoding="utf-8") as response:
|
||||||
soup = BeautifulSoup(response, "html.parser")
|
soup = BeautifulSoup(response, "html.parser")
|
||||||
selectors = [
|
selectors = [
|
||||||
".container .row .list-group a",
|
".container .row .list-group a",
|
||||||
@@ -101,21 +113,26 @@ def generate_nav(src, dest):
|
|||||||
print("No navigation found")
|
print("No navigation found")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
with open(src) as f:
|
with open(src, encoding="utf-8") as handler:
|
||||||
data = yaml.unsafe_load(f)
|
data = yaml.unsafe_load(handler)
|
||||||
data["nav"] = [
|
data["nav"] = [
|
||||||
{"Docs": navigation},
|
{"Docs": navigation},
|
||||||
{"Pro": "https://pro.dokku.com/docs/getting-started/"},
|
{"Pro": "https://pro.dokku.com/docs/getting-started/"},
|
||||||
{"Blog": "https://dokku.com/blog/"},
|
{"Blog": "https://dokku.com/blog/"},
|
||||||
{"Tutorials": "https://dokku.com/tutorials/"},
|
{"Tutorials": "https://dokku.com/tutorials/"},
|
||||||
{"Purchase Dokku Pro": "https://dokku.dpdcart.com/cart/add?product_id=217344&method_id=236878"},
|
{
|
||||||
|
"Purchase Dokku Pro": "https://dokku.dpdcart.com/cart/add?product_id=217344&method_id=236878"
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
with open(dest, mode="wt", encoding="utf-8") as f:
|
with open(dest, mode="wt", encoding="utf-8") as handler:
|
||||||
yaml.dump(data, f)
|
yaml.dump(data, handler)
|
||||||
|
|
||||||
|
|
||||||
def modify_content_noop(lines, _):
|
def modify_content_noop(lines: list[str], _) -> tuple[list[str], bool]:
|
||||||
|
"""
|
||||||
|
Simply returns the lines as is
|
||||||
|
"""
|
||||||
modified = False
|
modified = False
|
||||||
updated_lines = []
|
updated_lines = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
@@ -123,11 +140,14 @@ def modify_content_noop(lines, _):
|
|||||||
return updated_lines, modified
|
return updated_lines, modified
|
||||||
|
|
||||||
|
|
||||||
def modify_content_links(lines, filename):
|
def modify_content_links(lines: list[str], filename: str) -> tuple[list[str], bool]:
|
||||||
|
"""
|
||||||
|
Modifies links to be relative instead of absolute
|
||||||
|
"""
|
||||||
filename = filename.replace("/usr/src/source/docs/", "")
|
filename = filename.replace("/usr/src/source/docs/", "")
|
||||||
parts = filename.split("/")
|
parts = filename.split("/")
|
||||||
parts.pop()
|
parts.pop()
|
||||||
replacement = "](" + '/'.join([".." for _ in parts]) + "/"
|
replacement = "](" + "/".join([".." for _ in parts]) + "/"
|
||||||
modified = False
|
modified = False
|
||||||
updated_lines = []
|
updated_lines = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
@@ -139,7 +159,10 @@ def modify_content_links(lines, filename):
|
|||||||
return updated_lines, modified
|
return updated_lines, modified
|
||||||
|
|
||||||
|
|
||||||
def modify_content_stripspace(lines, _):
|
def modify_content_stripspace(lines: list[str], _) -> tuple[list[str], bool]:
|
||||||
|
"""
|
||||||
|
Removes trailing whitespace from each line
|
||||||
|
"""
|
||||||
modified = False
|
modified = False
|
||||||
updated_lines = []
|
updated_lines = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
@@ -148,7 +171,10 @@ def modify_content_stripspace(lines, _):
|
|||||||
return updated_lines, modified
|
return updated_lines, modified
|
||||||
|
|
||||||
|
|
||||||
def modify_content_inject_newlines(lines, _):
|
def modify_content_inject_newlines(lines: list[str], _) -> tuple[list[str], bool]:
|
||||||
|
"""
|
||||||
|
Ensures every line has a trailing newline character
|
||||||
|
"""
|
||||||
modified = False
|
modified = False
|
||||||
updated_lines = []
|
updated_lines = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
@@ -156,47 +182,117 @@ def modify_content_inject_newlines(lines, _):
|
|||||||
return updated_lines, modified
|
return updated_lines, modified
|
||||||
|
|
||||||
|
|
||||||
def is_info(line):
|
def is_github_new(line: str, next_line: str | None) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if a given line is a github "new as of" admonition
|
||||||
|
"""
|
||||||
|
if not next_line:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return line.startswith("> [!IMPORTANT]") and "new as of" in next_line.lower()
|
||||||
|
|
||||||
|
|
||||||
|
def is_github_note(line: str) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if a given line is a github "note" admonition
|
||||||
|
"""
|
||||||
|
return line.startswith("> [!NOTE]")
|
||||||
|
|
||||||
|
|
||||||
|
def is_github_warning(line: str) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if a given line is a github "warning" admonition
|
||||||
|
"""
|
||||||
|
return line.startswith("> [!WARNING]")
|
||||||
|
|
||||||
|
|
||||||
|
def is_info(line: str) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if a given line is an "info" admonition
|
||||||
|
"""
|
||||||
return line.startswith("> ")
|
return line.startswith("> ")
|
||||||
|
|
||||||
|
|
||||||
def is_new(line):
|
def is_new(line: str) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if a given line is a "new as of" admonition
|
||||||
|
"""
|
||||||
return line.startswith("> ") and "new as of" in line.lower()
|
return line.startswith("> ") and "new as of" in line.lower()
|
||||||
|
|
||||||
|
|
||||||
def is_note(line):
|
def is_note(line: str) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if a given line is a "note" admonition
|
||||||
|
"""
|
||||||
return line.startswith("> Note:")
|
return line.startswith("> Note:")
|
||||||
|
|
||||||
|
|
||||||
def is_warning(line):
|
def is_warning(line: str) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if a given line is a "warning" admonition
|
||||||
|
"""
|
||||||
return line.startswith("> Warning:")
|
return line.startswith("> Warning:")
|
||||||
|
|
||||||
|
|
||||||
def modify_content_admonition(lines, _):
|
def modify_content_admonition(lines: list[str], _) -> tuple[list[str], bool]:
|
||||||
|
"""
|
||||||
|
Applies adminition info to each line in the output
|
||||||
|
"""
|
||||||
modified = False
|
modified = False
|
||||||
updated_lines = []
|
updated_lines = []
|
||||||
admonition_lines = []
|
admonition_lines = []
|
||||||
is_admonition = False
|
is_admonition = False
|
||||||
for line in lines:
|
replace_new_in_next_line = False
|
||||||
if is_info(line) or is_new(line) or is_note(line) or is_warning(line):
|
for index, line in enumerate(lines):
|
||||||
if is_new(line):
|
next_line: str | None = None
|
||||||
line = line.replace("> ", "!!! tip \"New\"\n\n ")
|
if index + 1 < len(lines):
|
||||||
line = line.replace("New as of", "Introduced in")
|
next_line = lines[index + 1]
|
||||||
line = line.replace("new as of", "introduced in")
|
|
||||||
if is_note(line):
|
|
||||||
line = line.replace(
|
|
||||||
"> Note: ", "!!! note \"Note\"\n\n ")
|
|
||||||
elif is_warning(line):
|
|
||||||
line = line.replace(
|
|
||||||
"> Warning: ", "!!! warning \"Warning\"\n\n ")
|
|
||||||
elif is_info(line):
|
|
||||||
if not is_admonition:
|
|
||||||
line = line.replace("> ", "!!! info \"Info\"\n\n ")
|
|
||||||
elif line in [">", "> "]:
|
|
||||||
line = ""
|
|
||||||
else:
|
|
||||||
line = " " + line.removeprefix("> ")
|
|
||||||
|
|
||||||
|
if replace_new_in_next_line:
|
||||||
|
line = line.replace("New as of", "Introduced in")
|
||||||
|
line = line.replace("new as of", "introduced in")
|
||||||
|
replace_new_in_next_line = False
|
||||||
|
|
||||||
|
if is_github_new(line, next_line):
|
||||||
|
line = line.replace("> [!IMPORTANT]", '!!! tip "New"')
|
||||||
|
is_admonition = True
|
||||||
|
admonition_lines.append(line)
|
||||||
|
admonition_lines.append("")
|
||||||
|
replace_new_in_next_line = True
|
||||||
|
elif is_github_note(line):
|
||||||
|
line = line.replace("> [!NOTE]", '!!! note "Note"')
|
||||||
|
is_admonition = True
|
||||||
|
admonition_lines.append(line)
|
||||||
|
admonition_lines.append("")
|
||||||
|
elif is_github_warning(line):
|
||||||
|
line = line.replace("> [!WARNING]", '!!! warning "Warning"')
|
||||||
|
is_admonition = True
|
||||||
|
admonition_lines.append(line)
|
||||||
|
admonition_lines.append("")
|
||||||
|
elif is_new(line):
|
||||||
|
print("is_new")
|
||||||
|
line = line.replace("> ", '!!! tip "New"\n\n ')
|
||||||
|
line = line.replace("New as of", "Introduced in")
|
||||||
|
line = line.replace("new as of", "introduced in")
|
||||||
|
is_admonition = True
|
||||||
|
admonition_lines.append(line)
|
||||||
|
elif is_note(line):
|
||||||
|
print("is_note")
|
||||||
|
line = line.replace("> Note: ", '!!! note "Note"\n\n ')
|
||||||
|
is_admonition = True
|
||||||
|
admonition_lines.append(line)
|
||||||
|
elif is_warning(line):
|
||||||
|
print("is_warning")
|
||||||
|
line = line.replace("> Warning: ", '!!! warning "Warning"\n\n ')
|
||||||
|
is_admonition = True
|
||||||
|
admonition_lines.append(line)
|
||||||
|
elif is_info(line):
|
||||||
|
if not is_admonition:
|
||||||
|
line = line.replace("> ", '!!! info "Info"\n\n ')
|
||||||
|
elif line in [">", "> "]:
|
||||||
|
line = ""
|
||||||
|
else:
|
||||||
|
line = " " + line.removeprefix("> ")
|
||||||
is_admonition = True
|
is_admonition = True
|
||||||
admonition_lines.append(line)
|
admonition_lines.append(line)
|
||||||
elif is_admonition and line in [">", "> "]:
|
elif is_admonition and line in [">", "> "]:
|
||||||
@@ -208,6 +304,7 @@ def modify_content_admonition(lines, _):
|
|||||||
elif line == "":
|
elif line == "":
|
||||||
is_admonition = False
|
is_admonition = False
|
||||||
if len(admonition_lines) > 0:
|
if len(admonition_lines) > 0:
|
||||||
|
modified = True
|
||||||
updated_lines.extend(admonition_lines)
|
updated_lines.extend(admonition_lines)
|
||||||
admonition_lines = []
|
admonition_lines = []
|
||||||
updated_lines.append("")
|
updated_lines.append("")
|
||||||
@@ -216,11 +313,17 @@ def modify_content_admonition(lines, _):
|
|||||||
return updated_lines, modified
|
return updated_lines, modified
|
||||||
|
|
||||||
|
|
||||||
def is_shell_codeblock_start(line):
|
def is_shell_codeblock_start(line: str) -> bool:
|
||||||
|
"""
|
||||||
|
Checks to see if a line starts a codeblock
|
||||||
|
"""
|
||||||
return line == "```shell"
|
return line == "```shell"
|
||||||
|
|
||||||
|
|
||||||
def modify_content_terminal_example(lines, _):
|
def modify_content_terminal_example(lines: list[str], _) -> tuple[list[str], bool]:
|
||||||
|
"""
|
||||||
|
Modifies content so that terminal output is shown appropriately
|
||||||
|
"""
|
||||||
modified = False
|
modified = False
|
||||||
updated_lines = []
|
updated_lines = []
|
||||||
command_block = []
|
command_block = []
|
||||||
@@ -246,20 +349,20 @@ def modify_content_terminal_example(lines, _):
|
|||||||
if previous_block == "":
|
if previous_block == "":
|
||||||
updated_lines.append(line)
|
updated_lines.append(line)
|
||||||
continue
|
continue
|
||||||
elif previous_block == "command_block":
|
if previous_block == "command_block":
|
||||||
example_block.append(line)
|
example_block.append(line)
|
||||||
|
|
||||||
if in_example_block:
|
if in_example_block:
|
||||||
previous_block = ""
|
previous_block = ""
|
||||||
in_example_block = False
|
in_example_block = False
|
||||||
updated_lines.append("=== \"Shell\"")
|
updated_lines.append('=== "Shell"')
|
||||||
updated_lines.append("")
|
updated_lines.append("")
|
||||||
for command_line in command_block:
|
for command_line in command_block:
|
||||||
updated_lines.append(f" {command_line}")
|
updated_lines.append(f" {command_line}")
|
||||||
command_block = []
|
command_block = []
|
||||||
|
|
||||||
updated_lines.append("")
|
updated_lines.append("")
|
||||||
updated_lines.append("=== \"Output\"")
|
updated_lines.append('=== "Output"')
|
||||||
updated_lines.append("")
|
updated_lines.append("")
|
||||||
for example_line in example_block:
|
for example_line in example_block:
|
||||||
updated_lines.append(f" {example_line}")
|
updated_lines.append(f" {example_line}")
|
||||||
@@ -278,7 +381,7 @@ def modify_content_terminal_example(lines, _):
|
|||||||
command_block = []
|
command_block = []
|
||||||
previous_block = ""
|
previous_block = ""
|
||||||
continue
|
continue
|
||||||
elif next_line_must_be == "":
|
if next_line_must_be == "":
|
||||||
if line == "":
|
if line == "":
|
||||||
next_line_must_be = None
|
next_line_must_be = None
|
||||||
continue
|
continue
|
||||||
@@ -292,6 +395,9 @@ def modify_content_terminal_example(lines, _):
|
|||||||
|
|
||||||
|
|
||||||
def update_markdown(src):
|
def update_markdown(src):
|
||||||
|
"""
|
||||||
|
Updates all markdown files to be mkdocs compatible
|
||||||
|
"""
|
||||||
markdown_files = []
|
markdown_files = []
|
||||||
allowed_extensions = [".md"]
|
allowed_extensions = [".md"]
|
||||||
for subdir, _, files in os.walk(src):
|
for subdir, _, files in os.walk(src):
|
||||||
@@ -301,7 +407,7 @@ def update_markdown(src):
|
|||||||
if ext in allowed_extensions:
|
if ext in allowed_extensions:
|
||||||
markdown_files.append(file_path)
|
markdown_files.append(file_path)
|
||||||
|
|
||||||
modifiers = [
|
modifiers: list[Callable[[list[str], str], tuple[list[str], bool]]] = [
|
||||||
modify_content_noop,
|
modify_content_noop,
|
||||||
modify_content_links,
|
modify_content_links,
|
||||||
modify_content_stripspace,
|
modify_content_stripspace,
|
||||||
@@ -311,27 +417,32 @@ def update_markdown(src):
|
|||||||
]
|
]
|
||||||
|
|
||||||
for file in markdown_files:
|
for file in markdown_files:
|
||||||
modified = False
|
is_modified = False
|
||||||
lines = []
|
lines = []
|
||||||
with open(file, 'r') as f:
|
with open(file, "r", encoding="utf-8") as handler:
|
||||||
lines = f.readlines()
|
lines = handler.readlines()
|
||||||
for modifier in modifiers:
|
for modifier in modifiers:
|
||||||
lines, m = modifier(lines, file)
|
lines, modified = modifier(lines, file)
|
||||||
if m:
|
if modified:
|
||||||
modified = True
|
is_modified = True
|
||||||
|
|
||||||
if modified:
|
if is_modified:
|
||||||
with open(file, 'w') as fp:
|
with open(file, "w", encoding="utf-8") as handler:
|
||||||
fp.writelines(lines)
|
handler.writelines(lines)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
"""
|
||||||
|
Main command that performs doc manipulation
|
||||||
|
"""
|
||||||
print("----> Copying mkdocs.yml")
|
print("----> Copying mkdocs.yml")
|
||||||
print(" Generating navigation")
|
print(" Generating navigation")
|
||||||
generate_nav("/usr/src/source/mkdocs.yml", "/usr/src/app/mkdocs.yml")
|
generate_nav("/usr/src/source/mkdocs.yml", "/usr/src/app/mkdocs.yml")
|
||||||
|
|
||||||
print("----> Copying docs folder")
|
print("----> Copying docs folder")
|
||||||
update_markdown("/usr/src/source/docs",)
|
update_markdown(
|
||||||
|
"/usr/src/source/docs",
|
||||||
|
)
|
||||||
|
|
||||||
if os.path.exists("/usr/src/app/docs"):
|
if os.path.exists("/usr/src/app/docs"):
|
||||||
print(" Removing old docs folder")
|
print(" Removing old docs folder")
|
||||||
|
|||||||
Reference in New Issue
Block a user