Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate a landing page linking to each package's documentation #3076

Merged
merged 1 commit into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions resources/index.html.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<title>esp-rs docs</title>
<title>esp-rs Documentation</title>

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

<h2>{{ metadata[0].package }}</h2>
<h2>Packages</h2>

{%- for meta in metadata %}
<div class="crate">
<span class="crate-name">
<a href="{{ meta.chip }}/{{ meta.package }}/index.html">
{{ meta.chip_pretty }}
</a>
<a href="{{ meta.url }}">{{ meta.name }}</a>
</span>
<span class="crate-description">{{ meta.name }} (targeting {{ meta.chip_pretty }})</span>
<span class="crate-description">Documentation for <code>{{ meta.name }}</code> crate</span>
<span class="crate-version">{{ meta.version }}</span>
</div>
{%- endfor %}
Expand Down
115 changes: 115 additions & 0 deletions resources/package_index.html.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<title>{{ metadata[0].package }} Documentation</title>

<link rel="icon" href="../../esp-rs.svg" />
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;500&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Source+Serif+4:ital,wght@0,400;0,600;1,400;1,600&display=swap"
rel="stylesheet" />

<style>
body {
background-color: rgb(53, 53, 53);
font-family: "Fira Sans", sans-serif;
color: white;
margin: 0;
padding: 40px 20px;
display: flex;
height: 100vh;
width: 100vw;
justify-content: center;
box-sizing: border-box;
}

.logo {
text-align: center;
margin-bottom: 50px;
font-size: 2em;
font-weight: 500;
}

.logo img {
width: 100px;
height: auto;
margin-bottom: 20px;
}

.content {
width: 900px;
}

h2 {
margin-top: 3rem;
}

.crate {
display: flex;
align-items: center;
padding: 10px;
border-bottom: 2px solid #454444;
}

.crate-description {
flex: 1;
font-family: "Source Serif 4", serif;
color: #c0c0c0;
text-align: center;
}

.crate-name {
color: #d6991d;
width: 120px;
}

/* Ensure the link color does not change after being clicked */
.crate-name a:link,
.crate-name a:visited,
.crate-name a:hover,
.crate-name a:active,
.crate-name a:focus {
color: #d6991d;
}

.crate-version {
color: #c0c0c0;
text-align: center;
width: 120px;
}

@media screen and (min-height: 650px) {
body {
align-items: center;
}
}
</style>
</head>

<body>
<div class="content">
<div class="logo">
<img src="../../esp-rs.svg" alt="esp-rs logo" />
<div>{{ metadata[0].package }} Documentation</div>
</div>

<h2>{{ metadata[0].package }}</h2>

{%- for meta in metadata %}
<div class="crate">
<span class="crate-name">
<a href="{{ meta.chip }}/{{ meta.package }}/index.html">
{{ meta.chip_pretty }}
</a>
</span>
<span class="crate-description">{{ meta.name }} (targeting {{ meta.chip_pretty }})</span>
<span class="crate-version">{{ meta.version }}</span>
</div>
{%- endfor %}
</div>
</body>

</html>
Binary file removed resources/table-of-contents.png
Binary file not shown.
5 changes: 5 additions & 0 deletions xtask/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ impl Package {

matches!(self, EspHal | EspLpHal | EspWifi)
}

/// Should documentation be built for the package?
pub fn should_document(&self) -> bool {
!matches!(self, Package::Examples | Package::HilTest | Package::QaTest)
}
}

#[derive(Debug, Clone, Copy, Display, ValueEnum)]
Expand Down
113 changes: 80 additions & 33 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,10 +484,7 @@ fn build_documentation(workspace: &Path, mut args: BuildDocumentationArgs) -> Re

for package in args.packages {
// Not all packages need documentation built:
if matches!(
package,
Package::Examples | Package::HilTest | Package::QaTest
) {
if !package.should_document() {
continue;
}

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

args.packages.sort();

for package in args.packages {
// Not all packages have documentation built:
if matches!(
package,
Package::Examples | Package::HilTest | Package::QaTest
) {
if !package.should_document() {
continue;
}

Expand All @@ -548,14 +543,17 @@ fn build_documentation_index(

// Each path we iterate over should be the directory for a given version of
// the package's documentation:
for path in fs::read_dir(package_docs_path)? {
let path = path?.path();
if path.is_file() {
log::debug!("Path is not a directory, skipping: '{}'", path.display());
for version_path in fs::read_dir(package_docs_path)? {
let version_path = version_path?.path();
if version_path.is_file() {
log::debug!(
"Path is not a directory, skipping: '{}'",
version_path.display()
);
continue;
}

for path in fs::read_dir(&path)? {
for path in fs::read_dir(&version_path)? {
let path = path?.path();
if path.is_dir() {
device_doc_paths.push(path);
Expand All @@ -567,11 +565,11 @@ fn build_documentation_index(
.map(|path| {
let chip = path
.components()
.into_iter()
.last()
.unwrap()
.as_os_str()
.to_string_lossy();

let chip = Chip::from_str(&chip, true).unwrap();

chip
Expand All @@ -581,38 +579,87 @@ fn build_documentation_index(
chips.sort();

let meta = generate_documentation_meta_for_package(workspace, package, &chips)?;
generate_index(workspace, &path, &meta)?;
render_template(
"package_index.html.jinja",
"index.html",
&version_path,
&resources_path,
minijinja::context! { metadata => meta },
)?;
}
}

Ok(())
}

fn generate_index(workspace: &Path, package_version_path: &Path, meta: &[Value]) -> Result<()> {
let resources = workspace.join("resources");

// Copy any additional assets to the documentation's output path:
fs::copy(
resources.join("esp-rs.svg"),
package_version_path.join("esp-rs.svg"),
resources_path.join("esp-rs.svg"),
docs_path.join("esp-rs.svg"),
)
.context("Failed to copy esp-rs.svg")?;

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

let mut env = minijinja::Environment::new();
env.add_template("index", &source)?;
render_template(
"index.html.jinja",
"index.html",
&docs_path,
&resources_path,
minijinja::context! { metadata => meta },
)?;

Ok(())
}

fn generate_documentation_meta_for_index(workspace: &Path) -> Result<Vec<Value>> {
let mut metadata = Vec::new();

for package in Package::iter() {
// Not all packages have documentation built:
if !package.should_document() {
continue;
}

let version = xtask::package_version(workspace, package)?;

let tmpl = env.get_template("index")?;
let html = tmpl.render(minijinja::context! { metadata => meta })?;
let url = if package.chip_features_matter() {
format!("{package}/{version}/index.html")
} else {
let crate_name = package.to_string().replace('-', "_");
format!("{package}/{version}/{crate_name}/index.html")
};

let index = package_version_path.join("index.html");
metadata.push(minijinja::context! {
name => package,
version => version,
url => url,
});
}

Ok(metadata)
}

fn render_template<C>(
template: &str,
name: &str,
path: &Path,
resources: &Path,
ctx: C,
) -> Result<()>
where
C: serde::Serialize,
{
let source = fs::read_to_string(resources.join(template))
.context(format!("Failed to read {template}"))?;

let mut env = minijinja::Environment::new();
env.add_template(template, &source)?;

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

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

Ok(())
}
Expand Down