Skip to content

Commit c74d614

Browse files
authored
Generate a landing page linking to each package's documentation (#3076)
1 parent 9a28bdf commit c74d614

File tree

5 files changed

+205
-40
lines changed

5 files changed

+205
-40
lines changed

resources/index.html.jinja

+5-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta charset="UTF-8" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77

8-
<title>esp-rs docs</title>
8+
<title>esp-rs Documentation</title>
99

1010
<link rel="icon" href="esp-rs.svg" />
1111
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;500&display=swap" rel="stylesheet" />
@@ -93,19 +93,17 @@
9393
<div class="content">
9494
<div class="logo">
9595
<img src="esp-rs.svg" alt="esp-rs logo" />
96-
<div>{{ metadata[0].package }} Documentation</div>
96+
<div>esp-rs Documentation</div>
9797
</div>
9898

99-
<h2>{{ metadata[0].package }}</h2>
99+
<h2>Packages</h2>
100100

101101
{%- for meta in metadata %}
102102
<div class="crate">
103103
<span class="crate-name">
104-
<a href="{{ meta.chip }}/{{ meta.package }}/index.html">
105-
{{ meta.chip_pretty }}
106-
</a>
104+
<a href="{{ meta.url }}">{{ meta.name }}</a>
107105
</span>
108-
<span class="crate-description">{{ meta.name }} (targeting {{ meta.chip_pretty }})</span>
106+
<span class="crate-description">Documentation for <code>{{ meta.name }}</code> crate</span>
109107
<span class="crate-version">{{ meta.version }}</span>
110108
</div>
111109
{%- endfor %}

resources/package_index.html.jinja

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
8+
<title>{{ metadata[0].package }} Documentation</title>
9+
10+
<link rel="icon" href="../../esp-rs.svg" />
11+
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;500&display=swap" rel="stylesheet" />
12+
<link href="https://fonts.googleapis.com/css2?family=Source+Serif+4:ital,wght@0,400;0,600;1,400;1,600&display=swap"
13+
rel="stylesheet" />
14+
15+
<style>
16+
body {
17+
background-color: rgb(53, 53, 53);
18+
font-family: "Fira Sans", sans-serif;
19+
color: white;
20+
margin: 0;
21+
padding: 40px 20px;
22+
display: flex;
23+
height: 100vh;
24+
width: 100vw;
25+
justify-content: center;
26+
box-sizing: border-box;
27+
}
28+
29+
.logo {
30+
text-align: center;
31+
margin-bottom: 50px;
32+
font-size: 2em;
33+
font-weight: 500;
34+
}
35+
36+
.logo img {
37+
width: 100px;
38+
height: auto;
39+
margin-bottom: 20px;
40+
}
41+
42+
.content {
43+
width: 900px;
44+
}
45+
46+
h2 {
47+
margin-top: 3rem;
48+
}
49+
50+
.crate {
51+
display: flex;
52+
align-items: center;
53+
padding: 10px;
54+
border-bottom: 2px solid #454444;
55+
}
56+
57+
.crate-description {
58+
flex: 1;
59+
font-family: "Source Serif 4", serif;
60+
color: #c0c0c0;
61+
text-align: center;
62+
}
63+
64+
.crate-name {
65+
color: #d6991d;
66+
width: 120px;
67+
}
68+
69+
/* Ensure the link color does not change after being clicked */
70+
.crate-name a:link,
71+
.crate-name a:visited,
72+
.crate-name a:hover,
73+
.crate-name a:active,
74+
.crate-name a:focus {
75+
color: #d6991d;
76+
}
77+
78+
.crate-version {
79+
color: #c0c0c0;
80+
text-align: center;
81+
width: 120px;
82+
}
83+
84+
@media screen and (min-height: 650px) {
85+
body {
86+
align-items: center;
87+
}
88+
}
89+
</style>
90+
</head>
91+
92+
<body>
93+
<div class="content">
94+
<div class="logo">
95+
<img src="../../esp-rs.svg" alt="esp-rs logo" />
96+
<div>{{ metadata[0].package }} Documentation</div>
97+
</div>
98+
99+
<h2>{{ metadata[0].package }}</h2>
100+
101+
{%- for meta in metadata %}
102+
<div class="crate">
103+
<span class="crate-name">
104+
<a href="{{ meta.chip }}/{{ meta.package }}/index.html">
105+
{{ meta.chip_pretty }}
106+
</a>
107+
</span>
108+
<span class="crate-description">{{ meta.name }} (targeting {{ meta.chip_pretty }})</span>
109+
<span class="crate-version">{{ meta.version }}</span>
110+
</div>
111+
{%- endfor %}
112+
</div>
113+
</body>
114+
115+
</html>

resources/table-of-contents.png

-3.93 KB
Binary file not shown.

xtask/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ impl Package {
8080

8181
matches!(self, EspHal | EspLpHal | EspWifi)
8282
}
83+
84+
/// Should documentation be built for the package?
85+
pub fn should_document(&self) -> bool {
86+
!matches!(self, Package::Examples | Package::HilTest | Package::QaTest)
87+
}
8388
}
8489

8590
#[derive(Debug, Clone, Copy, Display, ValueEnum)]

xtask/src/main.rs

+80-33
Original file line numberDiff line numberDiff line change
@@ -484,10 +484,7 @@ fn build_documentation(workspace: &Path, mut args: BuildDocumentationArgs) -> Re
484484

485485
for package in args.packages {
486486
// Not all packages need documentation built:
487-
if matches!(
488-
package,
489-
Package::Examples | Package::HilTest | Package::QaTest
490-
) {
487+
if !package.should_document() {
491488
continue;
492489
}
493490

@@ -524,15 +521,13 @@ fn build_documentation_index(
524521
mut args: BuildDocumentationIndexArgs,
525522
) -> Result<()> {
526523
let docs_path = workspace.join("docs");
524+
let resources_path = workspace.join("resources");
527525

528526
args.packages.sort();
529527

530528
for package in args.packages {
531529
// Not all packages have documentation built:
532-
if matches!(
533-
package,
534-
Package::Examples | Package::HilTest | Package::QaTest
535-
) {
530+
if !package.should_document() {
536531
continue;
537532
}
538533

@@ -548,14 +543,17 @@ fn build_documentation_index(
548543

549544
// Each path we iterate over should be the directory for a given version of
550545
// the package's documentation:
551-
for path in fs::read_dir(package_docs_path)? {
552-
let path = path?.path();
553-
if path.is_file() {
554-
log::debug!("Path is not a directory, skipping: '{}'", path.display());
546+
for version_path in fs::read_dir(package_docs_path)? {
547+
let version_path = version_path?.path();
548+
if version_path.is_file() {
549+
log::debug!(
550+
"Path is not a directory, skipping: '{}'",
551+
version_path.display()
552+
);
555553
continue;
556554
}
557555

558-
for path in fs::read_dir(&path)? {
556+
for path in fs::read_dir(&version_path)? {
559557
let path = path?.path();
560558
if path.is_dir() {
561559
device_doc_paths.push(path);
@@ -567,11 +565,11 @@ fn build_documentation_index(
567565
.map(|path| {
568566
let chip = path
569567
.components()
570-
.into_iter()
571568
.last()
572569
.unwrap()
573570
.as_os_str()
574571
.to_string_lossy();
572+
575573
let chip = Chip::from_str(&chip, true).unwrap();
576574

577575
chip
@@ -581,38 +579,87 @@ fn build_documentation_index(
581579
chips.sort();
582580

583581
let meta = generate_documentation_meta_for_package(workspace, package, &chips)?;
584-
generate_index(workspace, &path, &meta)?;
582+
render_template(
583+
"package_index.html.jinja",
584+
"index.html",
585+
&version_path,
586+
&resources_path,
587+
minijinja::context! { metadata => meta },
588+
)?;
585589
}
586590
}
587591

588-
Ok(())
589-
}
590-
591-
fn generate_index(workspace: &Path, package_version_path: &Path, meta: &[Value]) -> Result<()> {
592-
let resources = workspace.join("resources");
593-
594592
// Copy any additional assets to the documentation's output path:
595593
fs::copy(
596-
resources.join("esp-rs.svg"),
597-
package_version_path.join("esp-rs.svg"),
594+
resources_path.join("esp-rs.svg"),
595+
docs_path.join("esp-rs.svg"),
598596
)
599597
.context("Failed to copy esp-rs.svg")?;
600598

601-
// Render the index and write it out to the documentaiton's output path:
602-
let source = fs::read_to_string(resources.join("index.html.jinja"))
603-
.context("Failed to read index.html.jinja")?;
599+
let meta = generate_documentation_meta_for_index(&workspace)?;
604600

605-
let mut env = minijinja::Environment::new();
606-
env.add_template("index", &source)?;
601+
render_template(
602+
"index.html.jinja",
603+
"index.html",
604+
&docs_path,
605+
&resources_path,
606+
minijinja::context! { metadata => meta },
607+
)?;
608+
609+
Ok(())
610+
}
611+
612+
fn generate_documentation_meta_for_index(workspace: &Path) -> Result<Vec<Value>> {
613+
let mut metadata = Vec::new();
614+
615+
for package in Package::iter() {
616+
// Not all packages have documentation built:
617+
if !package.should_document() {
618+
continue;
619+
}
620+
621+
let version = xtask::package_version(workspace, package)?;
607622

608-
let tmpl = env.get_template("index")?;
609-
let html = tmpl.render(minijinja::context! { metadata => meta })?;
623+
let url = if package.chip_features_matter() {
624+
format!("{package}/{version}/index.html")
625+
} else {
626+
let crate_name = package.to_string().replace('-', "_");
627+
format!("{package}/{version}/{crate_name}/index.html")
628+
};
610629

611-
let index = package_version_path.join("index.html");
630+
metadata.push(minijinja::context! {
631+
name => package,
632+
version => version,
633+
url => url,
634+
});
635+
}
636+
637+
Ok(metadata)
638+
}
639+
640+
fn render_template<C>(
641+
template: &str,
642+
name: &str,
643+
path: &Path,
644+
resources: &Path,
645+
ctx: C,
646+
) -> Result<()>
647+
where
648+
C: serde::Serialize,
649+
{
650+
let source = fs::read_to_string(resources.join(template))
651+
.context(format!("Failed to read {template}"))?;
652+
653+
let mut env = minijinja::Environment::new();
654+
env.add_template(template, &source)?;
612655

613-
fs::write(&index, html).context("Failed to write index.html")?;
656+
let tmpl = env.get_template(template)?;
657+
let html = tmpl.render(ctx)?;
614658

615-
log::info!("Created {}", index.display());
659+
// Write out the rendered HTML to the desired path:
660+
let path = path.join(name);
661+
fs::write(&path, html).context(format!("Failed to write {name}"))?;
662+
log::info!("Created {}", path.display());
616663

617664
Ok(())
618665
}

0 commit comments

Comments
 (0)