diff --git a/contrib/write-mkdocs b/contrib/write-mkdocs index 38bd08ae2bd..686636b24a9 100644 --- a/contrib/write-mkdocs +++ b/contrib/write-mkdocs @@ -3,7 +3,6 @@ import os import pathlib import shutil import sys -from collections.abc import Callable import yaml from bs4 import BeautifulSoup @@ -128,308 +127,6 @@ def generate_nav(src: str, dest: str) -> None: yaml.dump(data, handler) -def modify_content_noop(lines: list[str], _) -> tuple[list[str], bool]: - """ - Simply returns the lines as is - """ - modified = False - updated_lines = [] - for line in lines: - updated_lines.append(line) - return updated_lines, modified - - -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/", "") - parts = filename.split("/") - parts.pop() - replacement = "](" + "/".join([".." for _ in parts]) + "/" - modified = False - updated_lines = [] - for line in lines: - if "](/docs/" in line: - line = line.replace("](/docs/", replacement) - modified = True - - updated_lines.append(line) - return updated_lines, modified - - -def modify_content_stripspace(lines: list[str], _) -> tuple[list[str], bool]: - """ - Removes trailing whitespace from each line - """ - modified = False - updated_lines = [] - for line in lines: - line = line.rstrip() - updated_lines.append(line) - return updated_lines, modified - - -def modify_content_inject_newlines(lines: list[str], _) -> tuple[list[str], bool]: - """ - Ensures every line has a trailing newline character - """ - modified = False - updated_lines = [] - for line in lines: - updated_lines.append(line.rstrip() + "\n") - return updated_lines, modified - - -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("> ") - - -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() - - -def is_note(line: str) -> bool: - """ - Checks if a given line is a "note" admonition - """ - return line.startswith("> Note:") - - -def is_warning(line: str) -> bool: - """ - Checks if a given line is a "warning" admonition - """ - return line.startswith("> Warning:") - - -def modify_content_admonition(lines: list[str], _) -> tuple[list[str], bool]: - """ - Applies adminition info to each line in the output - """ - modified = False - updated_lines = [] - admonition_lines = [] - is_admonition = False - replace_new_in_next_line = False - for index, line in enumerate(lines): - next_line: str | None = None - if index + 1 < len(lines): - next_line = lines[index + 1] - - 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 - admonition_lines.append(line) - elif is_admonition and line in [">", "> "]: - line = "" - admonition_lines.append(line) - elif is_admonition and line.startswith("> "): - line = " " + line.removeprefix("> ") - admonition_lines.append(line) - elif line == "": - is_admonition = False - if len(admonition_lines) > 0: - modified = True - updated_lines.extend(admonition_lines) - admonition_lines = [] - updated_lines.append("") - else: - updated_lines.append(line) - return updated_lines, modified - - -def is_shell_codeblock_start(line: str) -> bool: - """ - Checks to see if a line starts a codeblock - """ - return line == "```shell" - - -def modify_content_terminal_example(lines: list[str], _) -> tuple[list[str], bool]: - """ - Modifies content so that terminal output is shown appropriately - """ - modified = False - updated_lines = [] - command_block = [] - example_block = [] - in_command_block = False - in_example_block = False - previous_block = "" - next_line_must_be = None - for line in lines: - if is_shell_codeblock_start(line): - command_block.append(line) - modified = True - in_command_block = True - continue - elif in_command_block: - command_block.append(line) - if line == "```": - in_command_block = False - previous_block = "command_block" - next_line_must_be = "" - continue - elif line == "```": - if previous_block == "": - updated_lines.append(line) - continue - if previous_block == "command_block": - example_block.append(line) - - if in_example_block: - previous_block = "" - in_example_block = False - updated_lines.append('=== "Shell"') - updated_lines.append("") - for command_line in command_block: - updated_lines.append(f" {command_line}") - command_block = [] - - updated_lines.append("") - updated_lines.append('=== "Output"') - updated_lines.append("") - for example_line in example_block: - updated_lines.append(f" {example_line}") - example_block = [] - else: - in_example_block = True - continue - elif previous_block == "command_block": - if next_line_must_be is None: - if in_example_block: - example_block.append(line) - else: - updated_lines.extend(command_block) - updated_lines.append("") - updated_lines.append(line) - command_block = [] - previous_block = "" - continue - if next_line_must_be == "": - if line == "": - next_line_must_be = None - continue - - updated_lines.append(line) - - if len(command_block) > 0: - updated_lines.extend(command_block) - - return updated_lines, modified - - -def update_markdown(src): - """ - Updates all markdown files to be mkdocs compatible - """ - markdown_files = [] - allowed_extensions = [".md"] - for subdir, _, files in os.walk(src): - for file in files: - ext = os.path.splitext(file)[-1].lower() - file_path = os.path.join(subdir, file) - if ext in allowed_extensions: - markdown_files.append(file_path) - - modifiers: list[Callable[[list[str], str], tuple[list[str], bool]]] = [ - modify_content_noop, - modify_content_links, - modify_content_stripspace, - modify_content_admonition, - modify_content_terminal_example, - modify_content_inject_newlines, - ] - - for file in markdown_files: - is_modified = False - lines = [] - with open(file, "r", encoding="utf-8") as handler: - lines = handler.readlines() - for modifier in modifiers: - lines, modified = modifier(lines, file) - if modified: - is_modified = True - - if is_modified: - with open(file, "w", encoding="utf-8") as handler: - handler.writelines(lines) - - def main(): """ Main command that performs doc manipulation @@ -438,11 +135,6 @@ def main(): print(" Generating navigation") generate_nav("/usr/src/source/mkdocs.yml", "/usr/src/app/mkdocs.yml") - print("----> Copying docs folder") - update_markdown( - "/usr/src/source/docs", - ) - if os.path.exists("/usr/src/app/docs"): print(" Removing old docs folder") shutil.rmtree("/usr/src/app/docs") diff --git a/docs/_build/hooks.py b/docs/_build/hooks.py index 5246cd58380..fe3ac182305 100644 --- a/docs/_build/hooks.py +++ b/docs/_build/hooks.py @@ -3,13 +3,295 @@ import posixpath import re +from collections.abc import Callable from re import Match from mkdocs.config.defaults import MkDocsConfig from mkdocs.structure.files import File, Files from mkdocs.structure.pages import Page -def on_page_markdown(markdown: str, *, page: Page, config: MkDocsConfig, files: Files): +def on_page_markdown(markdown: str, *, page: Page, config: MkDocsConfig, files: Files) -> str | None: + resp = re_on_page_markdown(markdown, page=page, config=config, files=files) + if not resp: + return resp + + + modifiers: list[Callable[[list[str], str], tuple[list[str], bool]]] = [ + modify_content_noop, + modify_content_links, + modify_content_stripspace, + modify_content_admonition, + modify_content_terminal_example, + ] + + is_modified = False + lines = resp.split("\n") + for modifier in modifiers: + lines, modified = modifier(lines, page.file.src_path) + if modified: + is_modified = True + + if is_modified: + resp = "\n".join(lines) + + return resp + + +def modify_content_noop(lines: list[str], _) -> tuple[list[str], bool]: + """ + Simply returns the lines as is + """ + modified = False + updated_lines = [] + for line in lines: + updated_lines.append(line) + return updated_lines, modified + + +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/", "") + parts = filename.split("/") + parts.pop() + replacement = "](" + "/".join([".." for _ in parts]) + "/" + modified = False + updated_lines = [] + for line in lines: + if "](/docs/" in line: + line = line.replace("](/docs/", replacement) + modified = True + + updated_lines.append(line) + return updated_lines, modified + + +def modify_content_stripspace(lines: list[str], _) -> tuple[list[str], bool]: + """ + Removes trailing whitespace from each line + """ + modified = False + updated_lines = [] + for line in lines: + line = line.rstrip() + updated_lines.append(line) + return updated_lines, modified + + +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("> ") + + +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() + + +def is_note(line: str) -> bool: + """ + Checks if a given line is a "note" admonition + """ + return line.startswith("> Note:") + + +def is_warning(line: str) -> bool: + """ + Checks if a given line is a "warning" admonition + """ + return line.startswith("> Warning:") + + +def modify_content_admonition(lines: list[str], filename: str) -> tuple[list[str], bool]: + """ + Applies adminition info to each line in the output + """ + modified = False + updated_lines = [] + admonition_lines = [] + is_admonition = False + replace_new_in_next_line = False + for index, line in enumerate(lines): + next_line: str | None = None + if index + 1 < len(lines): + next_line = lines[index + 1] + + 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 + admonition_lines.append(line) + elif is_admonition and line in [">", "> "]: + line = "" + admonition_lines.append(line) + elif is_admonition and line.startswith("> "): + line = " " + line.removeprefix("> ") + admonition_lines.append(line) + elif line == "": + is_admonition = False + if len(admonition_lines) > 0: + modified = True + updated_lines.extend(admonition_lines) + admonition_lines = [] + updated_lines.append("") + else: + updated_lines.append(line) + return updated_lines, modified + + +def is_shell_codeblock_start(line: str) -> bool: + """ + Checks to see if a line starts a codeblock + """ + return line == "```shell" + + +def modify_content_terminal_example(lines: list[str], _) -> tuple[list[str], bool]: + """ + Modifies content so that terminal output is shown appropriately + """ + modified = False + updated_lines = [] + command_block = [] + example_block = [] + in_command_block = False + in_example_block = False + previous_block = "" + next_line_must_be = None + for line in lines: + if is_shell_codeblock_start(line): + command_block.append(line) + modified = True + in_command_block = True + continue + elif in_command_block: + command_block.append(line) + if line == "```": + in_command_block = False + previous_block = "command_block" + next_line_must_be = "" + continue + elif line == "```": + if previous_block == "": + updated_lines.append(line) + continue + if previous_block == "command_block": + example_block.append(line) + + if in_example_block: + previous_block = "" + in_example_block = False + updated_lines.append('=== "Shell"') + updated_lines.append("") + for command_line in command_block: + updated_lines.append(f" {command_line}") + command_block = [] + + updated_lines.append("") + updated_lines.append('=== "Output"') + updated_lines.append("") + for example_line in example_block: + updated_lines.append(f" {example_line}") + example_block = [] + else: + in_example_block = True + continue + elif previous_block == "command_block": + if next_line_must_be is None: + if in_example_block: + example_block.append(line) + else: + updated_lines.extend(command_block) + updated_lines.append("") + updated_lines.append(line) + command_block = [] + previous_block = "" + continue + if next_line_must_be == "": + if line == "": + next_line_must_be = None + continue + + updated_lines.append(line) + + if len(command_block) > 0: + updated_lines.extend(command_block) + + return updated_lines, modified + + +def re_on_page_markdown(markdown: str, *, page: Page, config: MkDocsConfig, files: Files) -> str | None: """ This hook is called after the page's markdown is loaded from file and can be """ diff --git a/docs/deployment/builders/nixpacks.md b/docs/deployment/builders/nixpacks.md index 0d6421f5334..77882bfb07e 100644 --- a/docs/deployment/builders/nixpacks.md +++ b/docs/deployment/builders/nixpacks.md @@ -1,5 +1,6 @@ # Nixpacks +> [!IMPORTANT] > New as of 0.32.0 The `nixpacks` builder builds apps via [Nixpacks](https://nixpacks.com/), a buildpack alternative. diff --git a/docs/deployment/schedulers/docker-local.md b/docs/deployment/schedulers/docker-local.md index 4e0a861c971..a5f78d27957 100644 --- a/docs/deployment/schedulers/docker-local.md +++ b/docs/deployment/schedulers/docker-local.md @@ -27,6 +27,7 @@ dokku scheduler:set node-js-app selected ### Deploying amd64 images on arm64 +> [!IMPORTANT] > New as of 0.33.0 Many builders only produce amd64-compatible images. The docker-local scheduler will automatically detect these and run them via the `--platform=linux/amd64` on arm64 deploy targets.