Skip to content

Commit a0f3082

Browse files
committed
Improve documentation build and deployment tooling
1 parent 737cc39 commit a0f3082

10 files changed

Lines changed: 204 additions & 70 deletions

File tree

.github/workflows/docs-style.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Documentation Style
2+
3+
on:
4+
push:
5+
paths:
6+
- ".github/workflows/docs-style.yml"
7+
- "docs/brand.css"
8+
- "docs/docs.css"
9+
- "api-docs/cppdocs/binaryninja-docs.css"
10+
- "api-docs/source/_static/css/other.css"
11+
- "rust/rustdoc-brand.css"
12+
- "scripts/gen_admonitions.py"
13+
- "scripts/support-icons/**"
14+
pull_request:
15+
paths:
16+
- ".github/workflows/docs-style.yml"
17+
- "docs/brand.css"
18+
- "docs/docs.css"
19+
- "api-docs/cppdocs/binaryninja-docs.css"
20+
- "api-docs/source/_static/css/other.css"
21+
- "rust/rustdoc-brand.css"
22+
- "scripts/gen_admonitions.py"
23+
- "scripts/support-icons/**"
24+
25+
jobs:
26+
generated-css:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v4
30+
- name: Check generated admonition CSS
31+
run: python3 scripts/gen_admonitions.py --check

api-docs/cppdocs/build_min_docs.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# =-=--
1414

1515
import argparse
16+
import glob
1617
import os
1718
import sys
1819
import json
@@ -33,6 +34,18 @@ def system_with_output(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE):
3334
return proc.returncode, std_out, std_err
3435

3536

37+
def system_checked(cmd, description):
38+
stat, std_out, std_err = system_with_output(cmd)
39+
if stat != 0:
40+
print(f"{description} failed with status code {stat}: {cmd}", file=sys.stderr)
41+
if std_out:
42+
print(std_out, file=sys.stderr)
43+
if std_err:
44+
print(std_err, file=sys.stderr)
45+
sys.exit(1)
46+
return std_out
47+
48+
3649
deletion_queue = []
3750

3851

@@ -312,7 +325,7 @@ def minifier():
312325

313326
# The navtree indices also need to be loaded in since we're modifying how navbar.js::getScript works.
314327
# This also saves another ~60 files.
315-
for nav_tree_index_file in os.listdir("html"):
328+
for nav_tree_index_file in sorted(os.listdir("html")):
316329
if 'navtreeindex' in nav_tree_index_file:
317330
with open("html/" + nav_tree_index_file, "r") as fp:
318331
navtree_built_data += fp.read() + "\n"
@@ -349,7 +362,7 @@ def build_doxygen(args):
349362
if not os.path.exists('./Doxyfile-HTML'):
350363
print('No Doxyfile found. Are you in the right directory?')
351364
sys.exit(1)
352-
_, vers, _ = system_with_output(f"{doxygen} -V")
365+
vers = system_checked(f"{doxygen} -V", "Querying doxygen version")
353366

354367
if args.docset:
355368
stat, _, _ = system_with_output("doxygen2docset --help")
@@ -368,25 +381,19 @@ def build_doxygen(args):
368381
shutil.rmtree("./html/")
369382
print(f'Building doxygen docs...')
370383

371-
if args.docset:
372-
stat, out, err = system_with_output(f"{doxygen} Doxyfile-Docset")
373-
else:
374-
stat, out, err = system_with_output(f"{doxygen} Doxyfile-HTML")
375-
print(f"Built Doxygen with status code {stat}")
384+
doxyfile = "Doxyfile-Docset" if args.docset else "Doxyfile-HTML"
385+
system_checked(f"{doxygen} {doxyfile}", "Building doxygen docs")
376386
print("Output dir is ./html/")
377-
stat, out, err = system_with_output("cp _static/img/* html/")
378-
print(f"Copied images with status code {stat}")
387+
system_checked("cp _static/img/* html/", "Copying images")
379388
if args.docset:
380-
stat, out, err = system_with_output("doxygen2docset --doxygen html --docset docset")
381-
print(f"Created docset with status code {stat}")
389+
system_checked("doxygen2docset --doxygen html --docset docset", "Creating docset")
382390

383391

384392
def remove_navtreedata_references():
385393
"""
386394
Remove references to navtreedata.js from HTML files since we've inlined it into navtree.js
387395
"""
388-
import glob
389-
html_files = glob.glob("html/**/*.html", recursive=True)
396+
html_files = sorted(glob.glob("html/**/*.html", recursive=True))
390397
count = 0
391398
for html_file in html_files:
392399
with open(html_file, 'r') as f:
@@ -406,16 +413,37 @@ def remove_navtreedata_references():
406413
print(f'Removed navtreedata.js references from {count} HTML files')
407414

408415

416+
def remove_missing_jquery_references():
417+
if os.path.exists("html/jquery.js"):
418+
return
419+
420+
for html_file in sorted(glob.glob("html/**/*.html", recursive=True)):
421+
with open(html_file, 'r') as f:
422+
content = f.read()
423+
content = re.sub(
424+
r'<script type="text/javascript" src="(?:\.\./)*jquery\.js"></script>\s*\n',
425+
'',
426+
content
427+
)
428+
with open(html_file, 'w') as f:
429+
f.write(content)
430+
431+
409432
def main():
410433
parser = argparse.ArgumentParser(prog=sys.argv[0])
411434
parser.add_argument("--docset", action="store_true", default=False, help="Generate Dash docset")
412435
args = parser.parse_args()
413436

414437
build_doxygen(args)
415438
print("Minifying Output")
439+
# The docset Doxyfile sets GENERATE_TREEVIEW = NO, so navtree.js only exists for HTML builds
416440
if os.path.exists("html/navtree.js"):
417441
minifier()
418442
remove_navtreedata_references()
443+
elif not args.docset:
444+
print("html/navtree.js missing after doxygen build, cannot minify output", file=sys.stderr)
445+
sys.exit(1)
446+
remove_missing_jquery_references()
419447
for file in deletion_queue:
420448
file = "./" + file
421449
os.remove(file)

docs/brand.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
* (gitignored) and registers it before other.css
88
* - Doxygen C++ API -> Doxyfile HTML_EXTRA_STYLESHEET references
99
* ../../docs/brand.css
10-
* - rustdoc Rust API -> scripts/build-rust-docs.sh copies it into
11-
* target/doc/brand/, linked by rust/doc-header.html
10+
* - rustdoc Rust API -> scripts/build-rust-docs.sh appends it through
11+
* rustdoc's --extend-css option
1212
*/
1313

1414
:root {

docs/s3_website.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ s3_id: <%= ENV['S3_ID'] %>
22
s3_secret: <%= ENV['S3_SECRET'] %>
33
s3_bucket: docs.binary.ninja
44

5-
site: <%= File.dirname(__FILE__) + "./site" %>
5+
site: <%= File.expand_path("../site", File.dirname(__FILE__)) %>
66

77
index_document: index.html
88
error_document: index.html

rust/doc-header.html

Lines changed: 0 additions & 2 deletions
This file was deleted.

rust/rustdoc-brand.css

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,65 @@
1-
/* Shared tokens are loaded first through doc-header.html. */
2-
31
@font-face {
42
font-display: swap;
53
font-family: 'Open Sans';
64
font-style: normal;
75
font-weight: 400;
8-
src: url('/brand/OpenSans-Regular.ttf') format('truetype');
6+
src: url('brand/OpenSans-Regular.ttf') format('truetype');
97
}
108

119
@font-face {
1210
font-display: swap;
1311
font-family: 'Open Sans';
1412
font-style: italic;
1513
font-weight: 400;
16-
src: url('/brand/OpenSans-Italic.ttf') format('truetype');
14+
src: url('brand/OpenSans-Italic.ttf') format('truetype');
1715
}
1816

1917
@font-face {
2018
font-display: swap;
2119
font-family: 'Open Sans';
2220
font-style: normal;
2321
font-weight: 700;
24-
src: url('/brand/OpenSans-Bold.ttf') format('truetype');
22+
src: url('brand/OpenSans-Bold.ttf') format('truetype');
2523
}
2624

2725
@font-face {
2826
font-display: swap;
2927
font-family: 'Open Sans';
3028
font-style: italic;
3129
font-weight: 700;
32-
src: url('/brand/OpenSans-BoldItalic.ttf') format('truetype');
30+
src: url('brand/OpenSans-BoldItalic.ttf') format('truetype');
3331
}
3432

3533
@font-face {
3634
font-display: swap;
3735
font-family: 'Roboto Mono';
3836
font-style: normal;
3937
font-weight: 400;
40-
src: url('/brand/roboto-mono-v22-latin-regular.woff2') format('woff2');
38+
src: url('brand/roboto-mono-v22-latin-regular.woff2') format('woff2');
4139
}
4240

4341
@font-face {
4442
font-display: swap;
4543
font-family: 'Roboto Mono';
4644
font-style: italic;
4745
font-weight: 400;
48-
src: url('/brand/roboto-mono-v22-latin-italic.woff2') format('woff2');
46+
src: url('brand/roboto-mono-v22-latin-italic.woff2') format('woff2');
4947
}
5048

5149
@font-face {
5250
font-display: swap;
5351
font-family: 'Roboto Mono';
5452
font-style: normal;
5553
font-weight: 700;
56-
src: url('/brand/roboto-mono-v22-latin-700.woff2') format('woff2');
54+
src: url('brand/roboto-mono-v22-latin-700.woff2') format('woff2');
5755
}
5856

5957
@font-face {
6058
font-display: swap;
6159
font-family: 'Roboto Mono';
6260
font-style: italic;
6361
font-weight: 700;
64-
src: url('/brand/roboto-mono-v22-latin-700italic.woff2') format('woff2');
62+
src: url('brand/roboto-mono-v22-latin-700italic.woff2') format('woff2');
6563
}
6664

6765
:root,
@@ -95,6 +93,26 @@ ul.all-items,
9593
.deprecated-count {
9694
font-family: var(--bn-font-body);
9795
}
96+
97+
:root:not([data-theme]),
98+
:root[data-theme="light"] {
99+
--target-background-color: var(--bn-night);
100+
--target-border-color: var(--bn-night);
101+
--bn-target-fg: var(--bn-white);
102+
}
103+
104+
:root[data-theme="dark"],
105+
:root[data-theme="ayu"] {
106+
--target-background-color: var(--bn-white);
107+
--target-border-color: var(--bn-white);
108+
--bn-target-fg: var(--bn-night);
109+
}
110+
111+
:target:not([data-nosnippet]),
112+
:target:not([data-nosnippet]) a {
113+
color: var(--bn-target-fg);
114+
}
115+
98116
.content .docblock div.warning {
99117
margin: var(--bn-adm-margin-block) 0;
100118
border: none;
@@ -162,7 +180,7 @@ ul.all-items,
162180
}
163181
:root[data-theme="dark"] .sidebar-crate .logo-container img,
164182
:root[data-theme="ayu"] .sidebar-crate .logo-container img {
165-
content: url("/brand/logo-vertical-light.svg");
183+
content: url("brand/logo-vertical-light.svg");
166184
}
167185
.sidebar-crate:has(.logo-container) h2 > a {
168186
display: none;

0 commit comments

Comments
 (0)