Skip to content

Commit 4596f29

Browse files
committed
Add zensical config and post-build redirects helper
1 parent 0a62658 commit 4596f29

2 files changed

Lines changed: 248 additions & 0 deletions

File tree

scripts/zensical_redirects.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env python3
2+
"""Emit meta-refresh redirect HTML stubs for zensical builds.
3+
4+
Zensical does not implement an mkdocs-redirects equivalent, so we read the
5+
redirect map from a zensical config file ourselves and write the redirect
6+
HTML files into the build output after `zensical build` runs.
7+
"""
8+
from __future__ import annotations
9+
10+
import argparse
11+
import sys
12+
from pathlib import Path
13+
from posixpath import relpath as posix_relpath
14+
15+
# TODO: drop the tomli fallback once we require Python > 3.10 (tomllib is stdlib there).
16+
try:
17+
import tomllib
18+
except ModuleNotFoundError:
19+
import tomli as tomllib
20+
21+
REDIRECT_TEMPLATE = """\
22+
<!doctype html>
23+
<html lang="en">
24+
<head>
25+
<meta charset="utf-8">
26+
<title>Redirecting...</title>
27+
<link rel="canonical" href="{target}">
28+
<script>var anchor=window.location.hash.substr(1);location.href="{target}"+(anchor?"#"+anchor:"")</script>
29+
<meta http-equiv="refresh" content="0; url={target}">
30+
</head>
31+
<body>
32+
You're being redirected to a <a href="{target}">new destination</a>.
33+
</body>
34+
</html>
35+
"""
36+
37+
38+
def md_to_html(path: str) -> str:
39+
return path[:-3] + ".html" if path.endswith(".md") else path
40+
41+
42+
def main() -> int:
43+
parser = argparse.ArgumentParser(description=__doc__)
44+
parser.add_argument("--config", required=True, type=Path, help="Path to zensical.toml")
45+
parser.add_argument("--site-dir", required=True, type=Path, help="Built site directory")
46+
args = parser.parse_args()
47+
48+
with args.config.open("rb") as fp:
49+
config = tomllib.load(fp)
50+
redirect_maps = (
51+
config.get("project", {}).get("plugins", {}).get("redirects", {}).get("redirect_maps", {})
52+
)
53+
if not redirect_maps:
54+
return 0
55+
56+
written = 0
57+
for src, dst in redirect_maps.items():
58+
src_html = args.site_dir / md_to_html(src)
59+
dst_rel = posix_relpath(md_to_html(dst), start=str(Path(md_to_html(src)).parent))
60+
src_html.parent.mkdir(parents=True, exist_ok=True)
61+
src_html.write_text(REDIRECT_TEMPLATE.format(target=dst_rel))
62+
written += 1
63+
print(f"zensical_redirects: wrote {written} redirect stub(s)")
64+
return 0
65+
66+
67+
if __name__ == "__main__":
68+
sys.exit(main())

zensical.toml

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
[project]
2+
site_name = "Binary Ninja User Documentation"
3+
site_description = "Documentation for the Binary Ninja reverse engineering platform"
4+
site_author = "Vector 35 Inc"
5+
copyright = '(<a href="https://creativecommons.org/licenses/by/3.0/">cc</a>) <a href="https://vector35.com/">Vector 35 Inc</a>'
6+
site_url = "https://docs.binary.ninja/"
7+
repo_url = "https://binary.ninja/"
8+
repo_name = "binary.ninja"
9+
dev_addr = "0.0.0.0:8000"
10+
use_directory_urls = false
11+
extra_css = ["docs.css", "github.min.css", "juxtapose.min.css"]
12+
extra_javascript = ["highlight.min.js", "cpp.min.js", "python.min.js", "juxtapose.min.js", "tabsync.js"]
13+
14+
nav = [
15+
{ "User Documentation" = [
16+
{ "Getting Started" = "getting-started.md" },
17+
{ "User Guide" = [
18+
"guide/index.md",
19+
{ "Using Plugins" = "guide/plugins.md" },
20+
{ "Settings" = "guide/settings.md" },
21+
{ "Projects" = "guide/projects.md" },
22+
{ "Enterprise" = "guide/enterprise/index.md" },
23+
{ "Troubleshooting" = "guide/troubleshooting.md" },
24+
{ "Objective-C" = "guide/objectivec.md" },
25+
{ "Firmware Ninja" = "guide/firmwareninja.md" },
26+
{ "Shared Cache" = "guide/sharedcache.md" },
27+
{ "Kernel Cache" = "guide/kernelcache.md" },
28+
{ "EFI Resolver" = "guide/efiresolver.md" },
29+
{ "WARP" = "guide/warp.md" },
30+
{ "BinExport / BinDiff" = "guide/binexport.md" },
31+
{ "Guided Analysis" = "guide/guided_analysis.md" },
32+
] },
33+
{ "Debugger" = [
34+
{ "Overview" = "guide/debugger/index.md" },
35+
{ "Remote Debugging" = "guide/debugger/remote-debugging.md" },
36+
{ "Time Travel Debugging (Windows)" = "guide/debugger/dbgeng-ttd.md" },
37+
{ "Time Travel Debugging (Linux)" = "guide/debugger/gdbrsp-ttd.md" },
38+
{ "Kernel Debugging (Windows)" = "guide/debugger/windows-kd.md" },
39+
{ "Corellium Remote Debugging" = "guide/debugger/corellium-remote-debugging.md" },
40+
] },
41+
{ "Migration Guide" = [
42+
"guide/migration/index.md",
43+
{ "Migrating from IDA" = "guide/migration/migrationguideida.md" },
44+
{ "Migrating from Ghidra" = [
45+
"guide/migration/ghidra/index.md",
46+
{ "Ghidra Import" = "guide/migration/ghidra/ghidraimport.md" },
47+
{ "Ghidra Export" = "guide/migration/ghidra/ghidraexport.md" },
48+
] },
49+
] },
50+
{ "Types" = [
51+
"guide/types/index.md",
52+
{ "Basic Types" = "guide/types/basictypes.md" },
53+
{ "Working With Types" = "guide/types/type.md" },
54+
{ "Type Attributes and Annotations" = "guide/types/attributes.md" },
55+
{ "Importing/Exporting Types" = "guide/types/typeimportexport.md" },
56+
{ "Type Archives" = "guide/types/typearchives.md" },
57+
{ "Type Libraries" = "guide/types/typelibraries.md" },
58+
{ "Debug Info" = "guide/types/debuginfo.md" },
59+
{ "Platform Types" = "guide/types/platformtypes.md" },
60+
{ "C++ Types" = "guide/types/cpp.md" },
61+
] },
62+
] },
63+
{ "Developer Documentation" = [
64+
"dev/index.md",
65+
{ "Cookbook" = "dev/cookbook.md" },
66+
{ "Writing Plugins" = "dev/plugins.md" },
67+
{ "Container Transforms" = "dev/containertransforms.md" },
68+
{ "Automation" = "dev/batch.md" },
69+
{ "Architecture / Platform" = [
70+
{ "Part 1: Disassembly" = "dev/archplatform-disassembly.md" },
71+
{ "Part 2: Lifting" = "dev/archplatform-lifting.md" },
72+
{ "Part 3: Platform Support" = "dev/archplatform-platform.md" },
73+
{ "Flag Guide" = "dev/flags.md" },
74+
] },
75+
{ "BNIL" = [
76+
{ "BNIL Guide: Overview" = "dev/bnil-overview.md" },
77+
{ "BNIL Guide: LLIL" = "dev/bnil-llil.md" },
78+
{ "BNIL Guide: MLIL" = "dev/bnil-mlil.md" },
79+
{ "BNIL Guide: HLIL" = "dev/bnil-hlil.md" },
80+
{ "Modifying ILs" = "dev/bnil-modifying.md" },
81+
] },
82+
{ "Types" = [
83+
{ "Applying Annotations" = "dev/annotation.md" },
84+
{ "Type Libraries" = "dev/typelibraries.md" },
85+
] },
86+
{ "Important Concepts" = [
87+
"dev/concepts.md",
88+
{ "Outlining" = "dev/outlining.md" },
89+
{ "User Informed Data Flow" = "dev/uidf.md" },
90+
{ "Workflows" = "dev/workflows.md" },
91+
] },
92+
{ "Creating Themes" = "dev/themes.md" },
93+
{ "Contributing Documentation" = "dev/documentation.md" },
94+
] },
95+
{ "About" = [
96+
"about/index.md",
97+
{ "License" = [
98+
"about/license.md",
99+
{ "Non-commercial (Named)" = "about/license/noncommercial-named.md" },
100+
{ "Commercial (Named)" = "about/license/commercial-named.md" },
101+
{ "Non-commercial (Computer)" = "about/license/noncommercial-computer.md" },
102+
{ "Commercial (Computer)" = "about/license/commercial-computer.md" },
103+
{ "Free" = "about/license/free.md" },
104+
{ "Ultimate" = "about/license/ultimate.md" },
105+
{ "Ultimate Floating" = "about/license/ultimate-floating.md" },
106+
{ "Enterprise Server" = "about/license/enterprise-server.md" },
107+
] },
108+
{ "Open Source" = "about/open-source.md" },
109+
{ "Privacy" = "about/privacy.md" },
110+
{ "Icons" = "about/icons.md" },
111+
] },
112+
]
113+
114+
[project.theme]
115+
custom_dir = "overrides"
116+
favicon = "img/favicon.ico"
117+
font = false
118+
highlightjs = false
119+
features = [
120+
"navigation.tracking",
121+
"navigation.tabs",
122+
"navigation.tabs.sticky",
123+
"navigation.expand",
124+
"navigation.indexes",
125+
"navigation.top",
126+
"content.code.copy",
127+
"search.highlight",
128+
"toc.follow",
129+
]
130+
131+
[[project.theme.palette]]
132+
media = "(prefers-color-scheme: light)"
133+
scheme = "binja"
134+
primary = "red"
135+
accent = "red"
136+
toggle.icon = "material/brightness-7"
137+
toggle.name = "Switch to dark mode"
138+
139+
[[project.theme.palette]]
140+
media = "(prefers-color-scheme: dark)"
141+
scheme = "slate"
142+
primary = "red"
143+
accent = "red"
144+
toggle.icon = "material/brightness-4"
145+
toggle.name = "Switch to light mode"
146+
147+
[project.plugins.search]
148+
lang = "en"
149+
separator = '[\s\-,:!=\[\]()"/]+|(?!\b)(?=[A-Z][a-z])|\.(?!\d)|&[lg]t;'
150+
151+
[project.plugins.offline]
152+
153+
[project.plugins.privacy]
154+
155+
[project.plugins.redirects.redirect_maps]
156+
"index.md" = "getting-started.md"
157+
"guide/debugger.md" = "guide/debugger/index.md"
158+
"guide/remote-debugging.md" = "guide/debugger/remote-debugging.md"
159+
"guide/dbgeng-ttd.md" = "guide/debugger/dbgeng-ttd.md"
160+
161+
[project.markdown_extensions.attr_list]
162+
[project.markdown_extensions.md_in_html]
163+
[project.markdown_extensions.codehilite]
164+
[project.markdown_extensions.admonition]
165+
[project.markdown_extensions.pymdownx.details]
166+
167+
[project.markdown_extensions.pymdownx.superfences]
168+
preserve_tabs = true
169+
170+
[project.markdown_extensions.pymdownx.tabbed]
171+
alternate_style = true
172+
173+
[project.markdown_extensions.toc]
174+
permalink = true
175+
176+
[project.markdown_extensions.zensical.extensions.glightbox]
177+
178+
[project.extra]
179+
disablesearch = true
180+
logo = "images/logo.png"

0 commit comments

Comments
 (0)