mirror of
https://github.com/Noratrieb/target-tier-docs-experiment.git
synced 2026-01-14 16:35:09 +01:00
stuff
This commit is contained in:
parent
720b23bd8e
commit
a00ca6ae97
3 changed files with 87 additions and 92 deletions
82
src/main.rs
82
src/main.rs
|
|
@ -2,12 +2,13 @@ mod parse;
|
||||||
mod render;
|
mod render;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
use eyre::{bail, Context, OptionExt, Result};
|
use eyre::{bail, Context, OptionExt, Result};
|
||||||
use parse::{Footnote, ParsedTargetInfoFile, Tier, TriStateBool};
|
use parse::ParsedTargetInfoFile;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
/// Information about a target obtained from the target_info markdown file.
|
/// Information about a target obtained from the target_info markdown file.
|
||||||
|
|
@ -52,14 +53,24 @@ fn main() -> Result<()> {
|
||||||
.wrap_err("failed loading target_info")?
|
.wrap_err("failed loading target_info")?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|info| {
|
.map(|info| {
|
||||||
let metadata_used = vec![false; info.metadata.len()];
|
let footnotes_used = info
|
||||||
TargetPatternEntry { info, used: false, footnotes_used: metadata_used }
|
.footnotes
|
||||||
|
.iter()
|
||||||
|
.map(|(target, _)| (target.clone(), false))
|
||||||
|
.collect();
|
||||||
|
TargetPatternEntry {
|
||||||
|
info,
|
||||||
|
used: false,
|
||||||
|
footnotes_used,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
eprintln!("Collecting rustc information");
|
eprintln!("Collecting rustc information");
|
||||||
let rustc_infos =
|
let rustc_infos = targets
|
||||||
targets.iter().map(|target| rustc_target_info(&rustc, target)).collect::<Vec<_>>();
|
.iter()
|
||||||
|
.map(|target| rustc_target_info(&rustc, target))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let targets = targets
|
let targets = targets
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -68,7 +79,9 @@ fn main() -> Result<()> {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
eprintln!("Rendering targets check_only={check_only}");
|
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 {
|
if !check_only {
|
||||||
std::fs::create_dir_all(&targets_dir).wrap_err("creating platform-support/targets dir")?;
|
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 {
|
for target_pattern in info_patterns {
|
||||||
if !target_pattern.used {
|
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
|
for footnote_target in target_pattern.info.footnotes.keys() {
|
||||||
std::iter::zip(target_pattern.footnotes_used, target_pattern.info.metadata)
|
let used = target_pattern.footnotes_used[footnote_target];
|
||||||
{
|
|
||||||
if !used {
|
if !used {
|
||||||
bail!(
|
bail!(
|
||||||
"in target pattern `{}`, the footnotes for target `{}` were never used",
|
"in target pattern `{}`, the footnotes for target `{}` were never used",
|
||||||
target_pattern.info.pattern,
|
target_pattern.info.pattern,
|
||||||
meta.target
|
footnote_target,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +123,7 @@ fn main() -> Result<()> {
|
||||||
struct TargetPatternEntry {
|
struct TargetPatternEntry {
|
||||||
info: ParsedTargetInfoFile,
|
info: ParsedTargetInfoFile,
|
||||||
used: bool,
|
used: bool,
|
||||||
footnotes_used: Vec<bool>,
|
footnotes_used: HashMap<String, bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn target_doc_info(info_patterns: &mut [TargetPatternEntry], target: &str) -> TargetDocs {
|
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 maintainers = Vec::new();
|
||||||
let mut sections = Vec::new();
|
let mut sections = Vec::new();
|
||||||
|
|
||||||
let mut metadata = None;
|
|
||||||
let mut footnotes = Vec::new();
|
let mut footnotes = Vec::new();
|
||||||
|
|
||||||
for target_pattern_entry in info_patterns {
|
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) {
|
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() {
|
if !footnotes.is_empty() {
|
||||||
panic!("target {target} is assigned metadata from more than one pattern");
|
panic!("target {target} is assigned metadata from more than one pattern");
|
||||||
}
|
}
|
||||||
footnotes = target_footnotes.clone();
|
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.
|
/// 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(
|
let json_spec = rustc_stdout(
|
||||||
rustc,
|
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 {
|
fn rustc_stdout(rustc: &Path, args: &[&str]) -> String {
|
||||||
|
|
|
||||||
|
|
@ -86,16 +86,9 @@ fn parse_file(name: &str, content: &str) -> Result<ParsedTargetInfoFile> {
|
||||||
|
|
||||||
let frontmatter_line_count = frontmatter.lines().count() + 2; // 2 from ---
|
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")?;
|
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 body = frontmatter_splitter.next().ok_or_eyre("no body")?;
|
||||||
|
|
||||||
let mut sections = Vec::<(String, String)>::new();
|
let mut sections = Vec::<(String, String)>::new();
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,18 @@
|
||||||
use eyre::{Context, OptionExt, Result};
|
use eyre::{Context, OptionExt, Result};
|
||||||
use std::{fs, path::Path};
|
use std::{fs, path::Path};
|
||||||
|
|
||||||
use crate::{
|
use crate::{RustcTargetInfo, TargetDocs};
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Renders a single target markdown file from the information obtained.
|
/// Renders a single target markdown file from the information obtained.
|
||||||
pub fn render_target_md(target: &TargetDocs, rustc_info: &RustcTargetInfo) -> String {
|
pub fn render_target_md(target: &TargetDocs, rustc_info: &RustcTargetInfo) -> String {
|
||||||
let mut doc = format!(
|
let mut doc = format!(
|
||||||
"# {}\n\n**Tier: {}**\n\n",
|
"# {}\n\n**Tier: {}**\n\n",
|
||||||
target.name,
|
target.name,
|
||||||
match target.tier {
|
match rustc_info.metadata.tier {
|
||||||
Some(Tier::One) => "1",
|
Some(1) => "1",
|
||||||
Some(Tier::Two) => "2",
|
Some(2) => "2",
|
||||||
Some(Tier::Three) => "3",
|
Some(3) => "3",
|
||||||
None => "UNKNOWN",
|
_ => "UNKNOWN",
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -61,7 +52,10 @@ pub fn render_target_md(target: &TargetDocs, rustc_info: &RustcTargetInfo) -> St
|
||||||
section("Maintainers", &maintainers_content);
|
section("Maintainers", &maintainers_content);
|
||||||
|
|
||||||
for section_name in crate::SECTIONS {
|
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 {
|
let section_content = match value {
|
||||||
Some((_, value)) => value.clone(),
|
Some((_, value)) => value.clone(),
|
||||||
|
|
@ -141,12 +135,6 @@ pub fn render_static(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Footnote {
|
|
||||||
fn reference(&self) -> String {
|
|
||||||
format!("[^{}]", self.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_platform_support_tables(
|
fn render_platform_support_tables(
|
||||||
content: &str,
|
content: &str,
|
||||||
targets: &[(TargetDocs, RustcTargetInfo)],
|
targets: &[(TargetDocs, RustcTargetInfo)],
|
||||||
|
|
@ -160,7 +148,7 @@ fn render_platform_support_tables(
|
||||||
content,
|
content,
|
||||||
"TIER1HOST",
|
"TIER1HOST",
|
||||||
TierTable {
|
TierTable {
|
||||||
filter: |target| target.tier == Some(Tier::One),
|
filter: |target| target.1.metadata.tier == Some(1),
|
||||||
include_host: false,
|
include_host: false,
|
||||||
include_std: false,
|
include_std: false,
|
||||||
},
|
},
|
||||||
|
|
@ -169,7 +157,9 @@ fn render_platform_support_tables(
|
||||||
&content,
|
&content,
|
||||||
"TIER2HOST",
|
"TIER2HOST",
|
||||||
TierTable {
|
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_host: false,
|
||||||
include_std: false,
|
include_std: false,
|
||||||
},
|
},
|
||||||
|
|
@ -178,7 +168,9 @@ fn render_platform_support_tables(
|
||||||
&content,
|
&content,
|
||||||
"TIER2",
|
"TIER2",
|
||||||
TierTable {
|
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_host: false,
|
||||||
include_std: true,
|
include_std: true,
|
||||||
},
|
},
|
||||||
|
|
@ -187,7 +179,7 @@ fn render_platform_support_tables(
|
||||||
&content,
|
&content,
|
||||||
"TIER3",
|
"TIER3",
|
||||||
TierTable {
|
TierTable {
|
||||||
filter: |target| target.tier == Some(Tier::Three),
|
filter: |target| target.1.metadata.tier == Some(3),
|
||||||
include_host: true,
|
include_host: true,
|
||||||
include_std: true,
|
include_std: true,
|
||||||
},
|
},
|
||||||
|
|
@ -196,49 +188,50 @@ fn render_platform_support_tables(
|
||||||
Ok(content)
|
Ok(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_table_tri_state_bool(bool: TriStateBool) -> &'static str {
|
fn render_table_option_bool(bool: Option<bool>) -> &'static str {
|
||||||
match bool {
|
match bool {
|
||||||
TriStateBool::True => "✓",
|
Some(true) => "✓",
|
||||||
TriStateBool::False => " ",
|
Some(false) => " ",
|
||||||
TriStateBool::Unknown => "?",
|
None => "?",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TierTable {
|
struct TierTable {
|
||||||
filter: fn(&TargetDocs) -> bool,
|
filter: fn(&(TargetDocs, RustcTargetInfo)) -> bool,
|
||||||
include_std: bool,
|
include_std: bool,
|
||||||
include_host: bool,
|
include_host: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_table(targets: &[(TargetDocs, RustcTargetInfo)], table: TierTable) -> Result<String> {
|
fn render_table(targets: &[(TargetDocs, RustcTargetInfo)], table: TierTable) -> Result<String> {
|
||||||
let mut rows = Vec::new();
|
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 {
|
for (target, rustc_info) in targets {
|
||||||
let meta = target.metadata.as_ref();
|
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()) {
|
if !target.footnotes.is_empty() {
|
||||||
let footnotes = &meta.unwrap().footnotes;
|
let footnotes_str = target
|
||||||
all_footnotes.extend(footnotes);
|
.footnotes
|
||||||
let footnotes_str =
|
.iter()
|
||||||
footnotes.iter().map(|footnote| footnote.reference()).collect::<Vec<_>>().join(" ");
|
.map(|footnote| format!("[^{}]", footnote))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
notes = format!("{notes} {footnotes_str}");
|
notes = format!("{notes} {footnotes_str}");
|
||||||
}
|
}
|
||||||
|
|
||||||
let std = if table.include_std {
|
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}")
|
format!(" | {std}")
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let host = if table.include_host {
|
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}")
|
format!(" | {host}")
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
|
|
@ -250,14 +243,7 @@ fn render_table(targets: &[(TargetDocs, RustcTargetInfo)], table: TierTable) ->
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result = rows.join("\n");
|
let 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue