#!/usr/bin/env python3 import argparse import os import re import frontmatter def get_md_files(content_dir: str) -> list[str]: md_files = [] for root, _, files in os.walk(content_dir): for filename in files: if filename.endswith(".md"): md_files.append(os.path.join(root, filename)) return md_files def convert(filepath: str) -> frontmatter.Post: page = frontmatter.load(filepath) try: page["aliases"] = page["redirect_from"] del page["redirect_from"] except: pass # handle CLI reference stubs if "/engine/reference/commandline/" in filepath: try: if page["datafolder"]: page = convert_cli(page) return page except: pass # handle sample stubs if "/samples/" in filepath: page = convert_sample(page) return page # all other files convert_other(page) return page def convert_cli(page: frontmatter.Post) -> frontmatter.Post: page["layout"] = "cli" page.content = re.sub(r"\{% include cli.*", "", page.content) page.content = re.sub( r"\{% include (.*(md|html)) %}", r'{{< include "\1" >}}', page.content ) return page def convert_sample(page: frontmatter.Post) -> frontmatter.Post: page.content = re.sub(r"\{% include_relative samples_body.*", "", page.content) return page def convert_other(page: frontmatter.Post) -> frontmatter.Post: page.content = re.sub(r"\{:\s*target=(.|\n)*?}", "", page.content) page.content = re.sub(r"\{%-?\s*include eula(.|\n)*?}", "", page.content) page.content = re.sub(r"\{%\sraw(.|\n)*?}", "", page.content) page.content = re.sub(r"\{%\sendraw(.|\n)*?}", "", page.content) page.content = re.sub( r"\{:\s*\.(important|warning|tip|experimental|restricted).*?}", r"{ .\1 }", page.content, ) page.content = re.sub( r"\{:\s*(\.invertible|\.text-center|style=|width=|height=|class=|\.accept-eula).*?}", "", page.content, ) page.content = re.sub( r"\{% include (.*(md|html)) %}", r'{{< include "\1" >}}', page.content ) page.content = re.sub( r"!\[(.*?)]\((.*?)\)\{:\s*.inline\s*}", r'{{< inline-image src="\2" alt="\1" >}}', page.content, ) page.content = re.sub( r"\[(.*)?]\((.*?)\)\{:\s*\.button.*}", r'{{< button text="\1" url="\2" >}}', page.content, ) page.content = re.sub( r"\{% include desktop-install\.md (.*) %}", r"{{< desktop-install \1 >}}", page.content, ) page.content = re.sub( r"\{% include release-date\.html (.*) %}", r"{{< release-date \1 >}}", page.content, ) page.content = re.sub( r"\{% include (admin-(.*)?)\.md (.*) %}", r"{{% admin-\2 \3 %}}", page.content, ) page.content = re.sub( r"\{\{\s*site\.(.*?)\s*}}", r'{{% param "\1" %}}', page.content ) page.content = re.sub(r'\{:\s*id="(.*)" ?}', r"{ #\1 }", page.content) # handle inline assign assign_pattern = re.compile(r"{% assign (.*) = (['\"].*) %}\n?") assign = assign_pattern.search(page.content) if assign: key = assign.group(1) value = assign.group(2) page[key] = value[1:-1] page.content = assign_pattern.sub("", page.content) page.content = re.sub( rf'{{{{\s*{key}\s*}}}}', rf'{{{{% param "{key}" %}}}}', page.content ) return page def write_results(filepath: str, page: frontmatter.Post) -> None: f = open(filepath, "w") if "/includes/" in filepath: # skip front matter for includes data = page.content else: data = frontmatter.dumps(page, sort_keys=False) f.write(data) f.close() if __name__ == "__main__": parser = argparse.ArgumentParser( prog="Migrate", description="Convert content from Jekyll to Hugo", ) parser.add_argument("-d", type=str, help="Content directory") parser.add_argument("-f", type=str, help="Single input file") args = parser.parse_args() if args.f: converted_page = convert(args.f) write_results(args.f, converted_page) os._exit(os.EX_OK) content_dir = os.path.join(os.getcwd(), "content") if args.d: content_dir = os.path.abspath(args.d) md_files = get_md_files(content_dir) for filepath in md_files: converted_page = convert(filepath) write_results(filepath, converted_page) os._exit(os.EX_OK)