Skip to content

Commit f44b63c

Browse files
author
github-actions
committed
"Build docs workflow broke while I was on vacation; updated list of allowed sub-actions so it should be fixed"
1 parent 953ca82 commit f44b63c

File tree

4 files changed

+262
-0
lines changed

4 files changed

+262
-0
lines changed

docs/packages/drunc/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ mkdocs-section-index
77
mkdocstrings
88
mkdocstrings-python
99
pymdown-extensions
10+
mkdocs-exclude

docs/packages/drunc/generate_ref_nav_ghpages.py renamed to docs/packages/drunc/utils/generate_ghpages_docstrings.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
if any(part in excluded_folders for part in path.parts):
1818
continue
1919

20+
# Skip if parent folder has no __init__.py. mkdocstrings currently
21+
# fails for directories without __init__
22+
if not (path.parent / "__init__.py").exists():
23+
continue
24+
2025
# Module and documentation paths relative to root
2126
module_path = path.relative_to(root_folder).with_suffix("")
2227
doc_path = path.relative_to(root_folder).with_suffix(".md")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from pathlib import Path
2+
3+
4+
def on_nav(env, config, files):
5+
for file in files:
6+
if file.page:
7+
# Restore origin file name (without extension) as title.
8+
if "index" in str(Path(file.src_uri).stem):
9+
continue
10+
if "README" in str(Path(file.src_uri).stem):
11+
continue
12+
file.page.title = Path(file.src_uri).stem.replace("-", " ")
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
"""
2+
Script to covert wiki links to be used in Github Pages Docs. GitHub Wiki uses a Wiki-style link while GitHub Pages uses standard Markdown links.
3+
"""
4+
5+
import os
6+
import re
7+
import sys
8+
from pathlib import Path
9+
from typing import Dict, List
10+
11+
# Configuration
12+
base_url = sys.argv[1].rstrip("/")
13+
wiki_subfolder = sys.argv[2].strip("/")
14+
github_pages_base = base_url + "/"
15+
wiki_link_base = r"https://github.com/DUNE-DAQ/drunc/wiki/"
16+
17+
GH_pages_folder_name = "developer-documentation"
18+
19+
20+
def parse_markdown_nav(file_path: Path) -> List[tuple[list[str], str]]:
21+
"""
22+
Convert Wiki sidebar navigation into (stack, url).
23+
24+
Args:
25+
file_path: The path to the _Sidebar.md file to parse.
26+
Returns:
27+
A list of tuples containing (stack, url) representing the navigation structure.
28+
"""
29+
stack, entries = [], []
30+
with open(file_path) as f:
31+
for line in f:
32+
indent = len(line) - len(line.lstrip(" "))
33+
# Check if line is a list item
34+
match = re.match(r"\s*[-*]\s*(.+)", line)
35+
36+
if not match:
37+
continue
38+
39+
content = match.group(1).strip()
40+
level = indent // 2
41+
42+
stack = stack[:level] # rewind stack to current level
43+
link_match = re.match(r"\[([^\]]+)\]\(([^)]+)\)", content)
44+
45+
if link_match:
46+
title, url = link_match.groups()
47+
stack.append(title)
48+
entries.append((tuple(stack), url))
49+
stack.pop() # remove the curent file path, go back to root folder
50+
else:
51+
# section header without link
52+
stack.append(content)
53+
54+
return entries
55+
56+
57+
def process_wiki_content(
58+
filename: str, folder_base: str, index_dict: Dict[str, str]
59+
) -> None:
60+
"""
61+
Process a wiki file and write converted output in GH Pages format.
62+
63+
Args:
64+
filename: The name of the wiki file to process (an .md file).
65+
folder_base: The folder name under developer-documentation where the file will be written.
66+
index_dict: A mapping of page names to their new GH Pages location.
67+
"""
68+
69+
with open(filename, "r", encoding="utf-8") as f:
70+
content = f.read()
71+
72+
# Replace GitHub Wiki links with GitHub Pages links
73+
# Wiki links point to other wiki pages but we need to point to the GitHub Pages site
74+
content = re.sub(wiki_link_base, github_pages_base, content)
75+
76+
# Update links based on index dictionary containing page names and the new page location
77+
for page_name, new_page_location in index_dict.items():
78+
content = re.sub(f"/{page_name}", f"/{new_page_location}", content)
79+
80+
# Convert [[Link Name]] to [Link Name](Link-Name.html)
81+
content = re.sub(
82+
r"\[ \[([^\|\]]+)\]\]",
83+
lambda m: f"[{m.group(1)}]({m.group(1).replace(' ', '-')}.html)",
84+
content,
85+
)
86+
# Convert [[Link Text|Page Name]] to [Link Text](Page-Name.html)
87+
content = re.sub(
88+
r"\[\[([^\|\]]+)\|([^\|\]]+)\]\]",
89+
lambda m: f"[{m.group(1)}]({m.group(2).replace(' ', '-')}.html)",
90+
content,
91+
)
92+
# Ensure code block fences have blank lines before and after
93+
content = re.sub(
94+
r"([^\n])(```.*?```)([^\n])",
95+
r"\1\n\2\n\3",
96+
content,
97+
flags=re.DOTALL,
98+
)
99+
content = re.sub(r"([^\n])(```)", r"\1\n\2", content)
100+
content = re.sub(r"(```)([^\n])", r"\1\n\2", content)
101+
102+
# Remove checbokex in lists
103+
content = re.sub(r"- \[(?: |x|X)\]", "- ", content)
104+
105+
# Fix leading spaces before list markers
106+
content = re.sub(r"^\s+-", "-", content, flags=re.MULTILINE)
107+
108+
# Make sure a blank line exists before list items
109+
content = re.sub(r"([^\n])\n(?=\s*[-*+]\s)", r"\1\n\n", content)
110+
111+
# The folder where the new files will be written and will be the base for the GH Pages wiki docs
112+
new_wiki_dir = Path("..") / GH_pages_folder_name
113+
114+
# Make sure the folder structure exists
115+
os.makedirs(new_wiki_dir / folder_base, exist_ok=True)
116+
117+
# Write to index file a list of pages incuded in the folder
118+
with open(
119+
os.path.join(new_wiki_dir / folder_base, "index.md"), "a", encoding="utf-8"
120+
) as f:
121+
print(
122+
f"* [{filename.removesuffix('.md').replace('-', ' ')}]({filename}) \n",
123+
file=f,
124+
)
125+
126+
# Write converted content to new file in the developer-documentation folder to be displayed on GH Pages
127+
new_file_name = os.path.join(new_wiki_dir / folder_base, filename)
128+
129+
with open(new_file_name, "a", encoding="utf-8") as f:
130+
f.write(content)
131+
132+
133+
def clean_filename(filename: str) -> str | None:
134+
"""
135+
Check if a markdown file exists, rename it
136+
to replace spaces with hyphens, and return the base name (without .md).
137+
138+
Args:
139+
filename: The original filename to check and rename (with .md extension).
140+
"""
141+
if (
142+
not os.path.exists(filename)
143+
or not filename.endswith(".md")
144+
or filename == "index.md"
145+
):
146+
return None
147+
148+
# Rename file to replace spaces with hyphens if necessary
149+
new_name = filename.replace(" ", "-")
150+
if filename != new_name:
151+
os.rename(filename, new_name)
152+
153+
# Return filename base (without .md)
154+
return new_name.removesuffix(".md")
155+
156+
157+
def generate_index_dict(sidebar_nav: list[tuple[list[str], str]]) -> dict[str, str]:
158+
"""
159+
Create the index dictionary mapping filename bases
160+
to their final destination paths. Renames files as a side effect.
161+
162+
Args:
163+
sidebar_nav: The parsed sidebar navigation entries as a list of tuples.
164+
Returns:
165+
index_dict: A dictionary mapping filenames to their new paths to be displayed in GH Pages.
166+
"""
167+
index_dict = {}
168+
169+
for entry in sidebar_nav:
170+
# Only process entries with group and page (len == 2)
171+
if len(entry[0]) != 2:
172+
continue
173+
174+
group, _ = entry[0]
175+
link = entry[1]
176+
177+
folder_base = group
178+
filename = link.split("/")[-1] + ".md"
179+
180+
standard_base_name = clean_filename(filename)
181+
182+
if standard_base_name:
183+
# Construct the final path using the standardised base name
184+
new_file_name = os.path.join(
185+
GH_pages_folder_name, folder_base, standard_base_name
186+
)
187+
index_dict[standard_base_name] = new_file_name
188+
189+
return index_dict
190+
191+
192+
def generate_gh_pages(
193+
sidebar_nav: list[tuple[list[str], str]], index_dict: dict[str, str]
194+
) -> None:
195+
"""
196+
Generate the files GH Pages markdown files using the generated index dictionary.
197+
198+
Args:
199+
sidebar_nav: The parsed sidebar navigation entries as a list of tuples.
200+
index_dict: A dictionary mapping filenames to their new paths to be displayed in GH Pages.
201+
"""
202+
for entry in sidebar_nav:
203+
if len(entry[0]) != 2:
204+
continue
205+
206+
group, _ = entry[0]
207+
link = entry[1]
208+
209+
folder_base = group
210+
filename = link.split("/")[-1] + ".md"
211+
standard_base_name = clean_filename(filename)
212+
213+
if standard_base_name:
214+
current_filename = standard_base_name + ".md"
215+
process_wiki_content(current_filename, folder_base, index_dict)
216+
217+
218+
# Main script execution
219+
wiki_dir = os.path.join("docs", wiki_subfolder)
220+
os.chdir(wiki_dir)
221+
sidebar_nav = parse_markdown_nav("_Sidebar.md")
222+
223+
# Generate index of page names and their GH pages location
224+
index_dict = generate_index_dict(sidebar_nav)
225+
226+
# Process files and generate GH pages
227+
generate_gh_pages(sidebar_nav, index_dict)
228+
229+
# Write top-level index file for Developer Documentation
230+
gh_wiki_dir = Path("..") / GH_pages_folder_name
231+
index_path = os.path.join(gh_wiki_dir, "index.md")
232+
233+
with open(index_path, "w", encoding="utf-8") as f:
234+
f.write("# Developer documentation \n\n")
235+
# Add subfolders and their files as nested lists
236+
for folder_base, subdirs, files in os.walk(gh_wiki_dir):
237+
for subdir in sorted(subdirs):
238+
f.write(f"* [{subdir}]({subdir}/index.md)\n")
239+
240+
sub_path = os.path.join(folder_base, subdir)
241+
for subfile in os.listdir(sub_path):
242+
if subfile != "index.md" and subfile.endswith(".md"):
243+
display_name = subfile.removesuffix(".md").replace("-", " ")
244+
f.write(f" - [{display_name}]({subdir}/{subfile})\n")

0 commit comments

Comments
 (0)