This commit is contained in:
nora 2024-03-16 11:24:29 +01:00
parent 720b23bd8e
commit a00ca6ae97
3 changed files with 87 additions and 92 deletions

View file

@ -2,12 +2,13 @@ mod parse;
mod render;
use std::{
collections::HashMap,
path::{Path, PathBuf},
process::Command,
};
use eyre::{bail, Context, OptionExt, Result};
use parse::{Footnote, ParsedTargetInfoFile, Tier, TriStateBool};
use parse::ParsedTargetInfoFile;
use serde::Deserialize;
/// Information about a target obtained from the target_info markdown file.
@ -52,14 +53,24 @@ fn main() -> Result<()> {
.wrap_err("failed loading target_info")?
.into_iter()
.map(|info| {
let metadata_used = vec![false; info.metadata.len()];
TargetPatternEntry { info, used: false, footnotes_used: metadata_used }
let footnotes_used = info
.footnotes
.iter()
.map(|(target, _)| (target.clone(), false))
.collect();
TargetPatternEntry {
info,
used: false,
footnotes_used,
}
})
.collect::<Vec<_>>();
eprintln!("Collecting rustc information");
let rustc_infos =
targets.iter().map(|target| rustc_target_info(&rustc, target)).collect::<Vec<_>>();
let rustc_infos = targets
.iter()
.map(|target| rustc_target_info(&rustc, target))
.collect::<Vec<_>>();
let targets = targets
.into_iter()
@ -68,7 +79,9 @@ fn main() -> Result<()> {
.collect::<Vec<_>>();
eprintln!("Rendering targets check_only={check_only}");
let targets_dir = Path::new(output_src).join("platform-support").join("targets");
let targets_dir = Path::new(output_src)
.join("platform-support")
.join("targets");
if !check_only {
std::fs::create_dir_all(&targets_dir).wrap_err("creating platform-support/targets dir")?;
}
@ -83,17 +96,19 @@ fn main() -> Result<()> {
for target_pattern in info_patterns {
if !target_pattern.used {
bail!("target pattern `{}` was never used", target_pattern.info.pattern);
bail!(
"target pattern `{}` was never used",
target_pattern.info.pattern
);
}
for (used, meta) in
std::iter::zip(target_pattern.footnotes_used, target_pattern.info.metadata)
{
for footnote_target in target_pattern.info.footnotes.keys() {
let used = target_pattern.footnotes_used[footnote_target];
if !used {
bail!(
"in target pattern `{}`, the footnotes for target `{}` were never used",
target_pattern.info.pattern,
meta.target
footnote_target,
);
}
}
@ -108,7 +123,7 @@ fn main() -> Result<()> {
struct TargetPatternEntry {
info: ParsedTargetInfoFile,
used: bool,
footnotes_used: Vec<bool>,
footnotes_used: HashMap<String, bool>,
}
fn target_doc_info(info_patterns: &mut [TargetPatternEntry], target: &str) -> TargetDocs {
@ -116,7 +131,6 @@ fn target_doc_info(info_patterns: &mut [TargetPatternEntry], target: &str) -> Ta
let mut maintainers = Vec::new();
let mut sections = Vec::new();
let mut metadata = None;
let mut footnotes = Vec::new();
for target_pattern_entry in info_patterns {
@ -145,32 +159,24 @@ fn target_doc_info(info_patterns: &mut [TargetPatternEntry], target: &str) -> Ta
}
if let Some(target_footnotes) = target_pattern.footnotes.get(target) {
target_pattern_entry.footnotes_used[i] = true;
target_pattern_entry
.footnotes_used
.insert(target.to_owned(), true);
if !footnotes.is_empty() {
panic!("target {target} is assigned metadata from more than one pattern");
}
footnotes = target_footnotes.clone();
}
for (i, metadata_pattern) in target_pattern.metadata.iter().enumerate() {
if metadata_pattern.target == target {
target_pattern_entry.footnotes_used[i] = true;
if metadata.is_some() {
panic!("target {target} is assigned metadata from more than one pattern");
}
metadata = Some(TargetMetadata {
notes: metadata_pattern.notes.clone(),
host: metadata_pattern.host.clone(),
std: metadata_pattern.std.clone(),
footnotes: metadata_pattern.footnotes.clone(),
});
}
}
}
}
TargetDocs { name: target.to_owned(), maintainers, sections, footnotes }
TargetDocs {
name: target.to_owned(),
maintainers,
sections,
footnotes,
}
}
/// Information about a target obtained from rustc.
@ -212,11 +218,21 @@ fn rustc_target_info(rustc: &Path, target: &str) -> RustcTargetInfo {
let json_spec = rustc_stdout(
rustc,
&["-Zunstable-options", "--print", "target-spec-json", "--target", target],
&[
"-Zunstable-options",
"--print",
"target-spec-json",
"--target",
target,
],
);
let spec = serde_json::from_str::<TargetJson>(&json_spec);
let spec = serde_json::from_str::<TargetJson>(&json_spec)
.expect("parsing --print target-spec-json for metadata");
RustcTargetInfo { target_cfgs, metadata: spec.metadata }
RustcTargetInfo {
target_cfgs,
metadata: spec.metadata,
}
}
fn rustc_stdout(rustc: &Path, args: &[&str]) -> String {

View file

@ -86,16 +86,9 @@ fn parse_file(name: &str, content: &str) -> Result<ParsedTargetInfoFile> {
let frontmatter_line_count = frontmatter.lines().count() + 2; // 2 from ---
let mut frontmatter =
let frontmatter =
serde_yaml::from_str::<Frontmatter>(frontmatter).wrap_err("invalid frontmatter")?;
frontmatter.metadata.iter_mut().for_each(|meta| {
meta.footnotes.iter_mut().for_each(|footnote| {
footnote.content = footnote.content.replace("\r\n", " ").replace("\n", " ")
})
});
let frontmatter = frontmatter;
let body = frontmatter_splitter.next().ok_or_eyre("no body")?;
let mut sections = Vec::<(String, String)>::new();

View file

@ -1,27 +1,18 @@
use eyre::{Context, OptionExt, Result};
use std::{fs, path::Path};
use crate::{
parse::{Footnote, Tier, TriStateBool},
RustcTargetInfo, TargetDocs,
};
impl TargetDocs {
fn has_host_tools(&self) -> bool {
self.metadata.as_ref().map_or(false, |meta| meta.host == TriStateBool::True)
}
}
use crate::{RustcTargetInfo, TargetDocs};
/// Renders a single target markdown file from the information obtained.
pub fn render_target_md(target: &TargetDocs, rustc_info: &RustcTargetInfo) -> String {
let mut doc = format!(
"# {}\n\n**Tier: {}**\n\n",
target.name,
match target.tier {
Some(Tier::One) => "1",
Some(Tier::Two) => "2",
Some(Tier::Three) => "3",
None => "UNKNOWN",
match rustc_info.metadata.tier {
Some(1) => "1",
Some(2) => "2",
Some(3) => "3",
_ => "UNKNOWN",
}
);
@ -61,7 +52,10 @@ pub fn render_target_md(target: &TargetDocs, rustc_info: &RustcTargetInfo) -> St
section("Maintainers", &maintainers_content);
for section_name in crate::SECTIONS {
let value = target.sections.iter().find(|(name, _)| name == section_name);
let value = target
.sections
.iter()
.find(|(name, _)| name == section_name);
let section_content = match value {
Some((_, value)) => value.clone(),
@ -141,12 +135,6 @@ pub fn render_static(
Ok(())
}
impl Footnote {
fn reference(&self) -> String {
format!("[^{}]", self.name)
}
}
fn render_platform_support_tables(
content: &str,
targets: &[(TargetDocs, RustcTargetInfo)],
@ -160,7 +148,7 @@ fn render_platform_support_tables(
content,
"TIER1HOST",
TierTable {
filter: |target| target.tier == Some(Tier::One),
filter: |target| target.1.metadata.tier == Some(1),
include_host: false,
include_std: false,
},
@ -169,7 +157,9 @@ fn render_platform_support_tables(
&content,
"TIER2HOST",
TierTable {
filter: |target| target.tier == Some(Tier::Two) && target.has_host_tools(),
filter: |target| {
target.1.metadata.tier == Some(2) && target.1.metadata.host_tools.unwrap_or(false)
},
include_host: false,
include_std: false,
},
@ -178,7 +168,9 @@ fn render_platform_support_tables(
&content,
"TIER2",
TierTable {
filter: |target| target.tier == Some(Tier::Two) && !target.has_host_tools(),
filter: |target| {
target.1.metadata.tier == Some(2) && !target.1.metadata.host_tools.unwrap_or(false)
},
include_host: false,
include_std: true,
},
@ -187,7 +179,7 @@ fn render_platform_support_tables(
&content,
"TIER3",
TierTable {
filter: |target| target.tier == Some(Tier::Three),
filter: |target| target.1.metadata.tier == Some(3),
include_host: true,
include_std: true,
},
@ -196,49 +188,50 @@ fn render_platform_support_tables(
Ok(content)
}
fn render_table_tri_state_bool(bool: TriStateBool) -> &'static str {
fn render_table_option_bool(bool: Option<bool>) -> &'static str {
match bool {
TriStateBool::True => "",
TriStateBool::False => " ",
TriStateBool::Unknown => "?",
Some(true) => "",
Some(false) => " ",
None => "?",
}
}
struct TierTable {
filter: fn(&TargetDocs) -> bool,
filter: fn(&(TargetDocs, RustcTargetInfo)) -> bool,
include_std: bool,
include_host: bool,
}
fn render_table(targets: &[(TargetDocs, RustcTargetInfo)], table: TierTable) -> Result<String> {
let mut rows = Vec::new();
let mut all_footnotes = Vec::new();
let targets = targets.into_iter().filter(|target| (table.filter)(&target.0));
let targets = targets.into_iter().filter(|target| (table.filter)(&target));
for (target, _) in targets {
let meta = target.metadata.as_ref();
for (target, rustc_info) in targets {
let meta = &rustc_info.metadata;
let mut notes = meta.map(|meta| meta.notes.as_str()).unwrap_or("unknown").to_owned();
let mut notes = meta.description.as_deref().unwrap_or("unknown").to_owned();
if meta.map_or(false, |meta| !meta.footnotes.is_empty()) {
let footnotes = &meta.unwrap().footnotes;
all_footnotes.extend(footnotes);
let footnotes_str =
footnotes.iter().map(|footnote| footnote.reference()).collect::<Vec<_>>().join(" ");
if !target.footnotes.is_empty() {
let footnotes_str = target
.footnotes
.iter()
.map(|footnote| format!("[^{}]", footnote))
.collect::<Vec<_>>()
.join(" ");
notes = format!("{notes} {footnotes_str}");
}
let std = if table.include_std {
let std = meta.map(|meta| render_table_tri_state_bool(meta.std)).unwrap_or("?");
let std = render_table_option_bool(meta.std);
format!(" | {std}")
} else {
String::new()
};
let host = if table.include_host {
let host = meta.map(|meta| render_table_tri_state_bool(meta.host)).unwrap_or("?");
let host = render_table_option_bool(meta.host_tools);
format!(" | {host}")
} else {
String::new()
@ -250,14 +243,7 @@ fn render_table(targets: &[(TargetDocs, RustcTargetInfo)], table: TierTable) ->
));
}
let mut result = rows.join("\n");
for footnote in all_footnotes {
result.push_str("\n\n");
result.push_str(&footnote.reference());
result.push_str(": ");
result.push_str(&footnote.content);
}
let result = rows.join("\n");
Ok(result)
}