mirror of
https://github.com/Noratrieb/target-tier-docs-experiment.git
synced 2026-01-16 09:25:08 +01:00
clean
This commit is contained in:
parent
a7cd3d46f9
commit
135c9bbbb1
4 changed files with 112 additions and 66 deletions
83
src/main.rs
83
src/main.rs
|
|
@ -11,12 +11,14 @@ use eyre::{bail, Context, OptionExt, Result};
|
||||||
use parse::ParsedTargetInfoFile;
|
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 markdown and rustc.
|
||||||
struct TargetDocs {
|
struct TargetInfo {
|
||||||
name: String,
|
name: String,
|
||||||
maintainers: Vec<String>,
|
maintainers: Vec<String>,
|
||||||
sections: Vec<(String, String)>,
|
sections: Vec<(String, String)>,
|
||||||
footnotes: Vec<String>,
|
footnotes: Vec<String>,
|
||||||
|
target_cfgs: Vec<(String, String)>,
|
||||||
|
metadata: RustcTargetMetadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All the sections that we want every doc page to have.
|
/// All the sections that we want every doc page to have.
|
||||||
|
|
@ -56,29 +58,48 @@ fn main() -> Result<()> {
|
||||||
.wrap_err("failed loading target_info")?
|
.wrap_err("failed loading target_info")?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|info| {
|
.map(|info| {
|
||||||
let footnotes_used =
|
let footnotes_used = info
|
||||||
info.footnotes.iter().map(|(target, _)| (target.clone(), false)).collect();
|
.footnotes
|
||||||
TargetPatternEntry { info, used: false, footnotes_used }
|
.keys()
|
||||||
|
.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()
|
||||||
.map(|target| target_doc_info(&mut info_patterns, target))
|
.map(|target| target_doc_info(&mut info_patterns, target))
|
||||||
.zip(rustc_infos)
|
.zip(rustc_infos)
|
||||||
|
.map(|(md, rustc)| TargetInfo {
|
||||||
|
name: md.name,
|
||||||
|
maintainers: md.maintainers,
|
||||||
|
sections: md.sections,
|
||||||
|
footnotes: md.footnotes,
|
||||||
|
target_cfgs: rustc.target_cfgs,
|
||||||
|
metadata: rustc.metadata,
|
||||||
|
})
|
||||||
.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")?;
|
||||||
}
|
}
|
||||||
for (info, rustc_info) in &targets {
|
for info in &targets {
|
||||||
let doc = render::render_target_md(info, rustc_info);
|
let doc = render::render_target_md(info);
|
||||||
|
|
||||||
if !check_only {
|
if !check_only {
|
||||||
std::fs::write(targets_dir.join(format!("{}.md", info.name)), doc)
|
std::fs::write(targets_dir.join(format!("{}.md", info.name)), doc)
|
||||||
|
|
@ -88,7 +109,10 @@ 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 footnote_target in target_pattern.info.footnotes.keys() {
|
for footnote_target in target_pattern.info.footnotes.keys() {
|
||||||
|
|
@ -115,7 +139,15 @@ struct TargetPatternEntry {
|
||||||
footnotes_used: HashMap<String, bool>,
|
footnotes_used: HashMap<String, bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn target_doc_info(info_patterns: &mut [TargetPatternEntry], target: &str) -> TargetDocs {
|
/// Information about a target obtained from the target_info markdown file.
|
||||||
|
struct TargetInfoMd {
|
||||||
|
name: String,
|
||||||
|
maintainers: Vec<String>,
|
||||||
|
sections: Vec<(String, String)>,
|
||||||
|
footnotes: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_doc_info(info_patterns: &mut [TargetPatternEntry], target: &str) -> TargetInfoMd {
|
||||||
let mut maintainers = Vec::new();
|
let mut maintainers = Vec::new();
|
||||||
let mut sections = Vec::new();
|
let mut sections = Vec::new();
|
||||||
|
|
||||||
|
|
@ -128,7 +160,6 @@ fn target_doc_info(info_patterns: &mut [TargetPatternEntry], target: &str) -> Ta
|
||||||
|
|
||||||
maintainers.extend_from_slice(&target_pattern.maintainers);
|
maintainers.extend_from_slice(&target_pattern.maintainers);
|
||||||
|
|
||||||
|
|
||||||
for (section_name, content) in &target_pattern.sections {
|
for (section_name, content) in &target_pattern.sections {
|
||||||
if sections.iter().any(|(name, _)| name == section_name) {
|
if sections.iter().any(|(name, _)| name == section_name) {
|
||||||
panic!(
|
panic!(
|
||||||
|
|
@ -139,7 +170,9 @@ 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.insert(target.to_owned(), 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");
|
||||||
|
|
@ -149,7 +182,12 @@ fn target_doc_info(info_patterns: &mut [TargetPatternEntry], target: &str) -> Ta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetDocs { name: target.to_owned(), maintainers, sections, footnotes }
|
TargetInfoMd {
|
||||||
|
name: target.to_owned(),
|
||||||
|
maintainers,
|
||||||
|
sections,
|
||||||
|
footnotes,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a target obtained from rustc.
|
/// Information about a target obtained from rustc.
|
||||||
|
|
@ -173,7 +211,7 @@ fn rustc_target_info(rustc: &Path, target: &str) -> RustcTargetInfo {
|
||||||
.lines()
|
.lines()
|
||||||
.filter_map(|line| {
|
.filter_map(|line| {
|
||||||
if line.starts_with("target_") {
|
if line.starts_with("target_") {
|
||||||
let Some((key, value)) = line.split_once("=") else {
|
let Some((key, value)) = line.split_once('=') else {
|
||||||
// For example `unix`
|
// For example `unix`
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
@ -191,12 +229,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");
|
.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 {
|
||||||
|
|
|
||||||
10
src/parse.rs
10
src/parse.rs
|
|
@ -70,7 +70,9 @@ fn load_single_target_info(entry: &DirEntry) -> Result<ParsedTargetInfoFile> {
|
||||||
fn parse_file(name: &str, content: &str) -> Result<ParsedTargetInfoFile> {
|
fn parse_file(name: &str, content: &str) -> Result<ParsedTargetInfoFile> {
|
||||||
let mut frontmatter_splitter = content.split("---\n");
|
let mut frontmatter_splitter = content.split("---\n");
|
||||||
|
|
||||||
let frontmatter = frontmatter_splitter.nth(1).ok_or_eyre("missing frontmatter")?;
|
let frontmatter = frontmatter_splitter
|
||||||
|
.nth(1)
|
||||||
|
.ok_or_eyre("missing frontmatter")?;
|
||||||
|
|
||||||
let frontmatter_line_count = frontmatter.lines().count() + 2; // 2 from ---
|
let frontmatter_line_count = frontmatter.lines().count() + 2; // 2 from ---
|
||||||
|
|
||||||
|
|
@ -86,7 +88,7 @@ fn parse_file(name: &str, content: &str) -> Result<ParsedTargetInfoFile> {
|
||||||
let number = frontmatter_line_count + idx + 1; // 1 because "line numbers" are off by 1
|
let number = frontmatter_line_count + idx + 1; // 1 because "line numbers" are off by 1
|
||||||
if line.starts_with("```") {
|
if line.starts_with("```") {
|
||||||
in_codeblock ^= true; // toggle
|
in_codeblock ^= true; // toggle
|
||||||
} else if line.starts_with("#") {
|
} else if line.starts_with('#') {
|
||||||
if in_codeblock {
|
if in_codeblock {
|
||||||
match sections.last_mut() {
|
match sections.last_mut() {
|
||||||
Some((_, content)) => {
|
Some((_, content)) => {
|
||||||
|
|
@ -121,7 +123,9 @@ fn parse_file(name: &str, content: &str) -> Result<ParsedTargetInfoFile> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sections.iter_mut().for_each(|section| section.1 = section.1.trim().to_owned());
|
sections
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|section| section.1 = section.1.trim().to_owned());
|
||||||
|
|
||||||
Ok(ParsedTargetInfoFile {
|
Ok(ParsedTargetInfoFile {
|
||||||
pattern: name.to_owned(),
|
pattern: name.to_owned(),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
use crate::parse::Tier;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_frontmatter() {
|
fn no_frontmatter() {
|
||||||
let name = "archlinux-unknown-linux-gnu.md"; // arch linux is an arch, right?
|
let name = "archlinux-unknown-linux-gnu.md"; // arch linux is an arch, right?
|
||||||
|
|
@ -38,7 +36,6 @@ fn parse_correctly() {
|
||||||
let name = "cat-unknown-linux-gnu.md";
|
let name = "cat-unknown-linux-gnu.md";
|
||||||
let content = r#"
|
let content = r#"
|
||||||
---
|
---
|
||||||
tier: "1" # first-class cats
|
|
||||||
maintainers: ["who maintains the cat?"]
|
maintainers: ["who maintains the cat?"]
|
||||||
---
|
---
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
@ -59,7 +56,6 @@ But it should be possible.
|
||||||
|
|
||||||
assert_eq!(info.maintainers, vec!["who maintains the cat?"]);
|
assert_eq!(info.maintainers, vec!["who maintains the cat?"]);
|
||||||
assert_eq!(info.pattern, name);
|
assert_eq!(info.pattern, name);
|
||||||
assert_eq!(info.tier, Some(Tier::One));
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
info.sections,
|
info.sections,
|
||||||
vec",
|
"[@{0}](https://github.com/{0})",
|
||||||
maintainer.strip_prefix("@").unwrap()
|
maintainer.strip_prefix("@").unwrap()
|
||||||
|
|
@ -62,16 +60,19 @@ 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(),
|
||||||
None => "Unknown.".to_owned(),
|
None => "Unknown.".to_owned(),
|
||||||
};
|
};
|
||||||
section(§ion_name, §ion_content);
|
section(section_name, §ion_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
let cfg_text = rustc_info
|
let cfg_text = target
|
||||||
.target_cfgs
|
.target_cfgs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(key, value)| format!("- `{key}` = `{value}`"))
|
.map(|(key, value)| format!("- `{key}` = `{value}`"))
|
||||||
|
|
@ -105,17 +106,13 @@ fn replace_section(prev_content: &str, section_name: &str, replacement: &str) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the non-target files like `SUMMARY.md` that depend on the target.
|
/// Renders the non-target files like `SUMMARY.md` that depend on the target.
|
||||||
pub fn render_static(
|
pub fn render_static(check_only: bool, src_output: &Path, targets: &[TargetInfo]) -> Result<()> {
|
||||||
check_only: bool,
|
|
||||||
src_output: &Path,
|
|
||||||
targets: &[(TargetDocs, RustcTargetInfo)],
|
|
||||||
) -> Result<()> {
|
|
||||||
let targets_file = src_output.join("platform-support").join("targets.md");
|
let targets_file = src_output.join("platform-support").join("targets.md");
|
||||||
let old_targets = fs::read_to_string(&targets_file).wrap_err("reading summary file")?;
|
let old_targets = fs::read_to_string(&targets_file).wrap_err("reading summary file")?;
|
||||||
|
|
||||||
let target_list = targets
|
let target_list = targets
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(target, _)| format!("- [{0}](platform-support/targets/{0}.md)", target.name))
|
.map(|target| format!("- [{0}](platform-support/targets/{0}.md)", target.name))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
|
|
||||||
|
|
@ -140,9 +137,12 @@ pub fn render_static(
|
||||||
let summary = src_output.join("SUMMARY.md");
|
let summary = src_output.join("SUMMARY.md");
|
||||||
let summary_old = fs::read_to_string(&summary).wrap_err("reading SUMMARY.md")?;
|
let summary_old = fs::read_to_string(&summary).wrap_err("reading SUMMARY.md")?;
|
||||||
// indent the list
|
// indent the list
|
||||||
let summary_new =
|
let summary_new = replace_section(
|
||||||
replace_section(&summary_old, "TARGET_LIST", &target_list.replace("- ", " - "))
|
&summary_old,
|
||||||
.wrap_err("replacig SUMMARY.md")?;
|
"TARGET_LIST",
|
||||||
|
&target_list.replace("- ", " - "),
|
||||||
|
)
|
||||||
|
.wrap_err("replacig SUMMARY.md")?;
|
||||||
if !check_only {
|
if !check_only {
|
||||||
fs::write(summary, summary_new).wrap_err("writing SUMAMRY.md")?;
|
fs::write(summary, summary_new).wrap_err("writing SUMAMRY.md")?;
|
||||||
}
|
}
|
||||||
|
|
@ -150,10 +150,13 @@ pub fn render_static(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_platform_support_tables(
|
impl TargetInfo {
|
||||||
content: &str,
|
fn has_host_tools(&self) -> bool {
|
||||||
targets: &[(TargetDocs, RustcTargetInfo)],
|
self.metadata.host_tools.unwrap_or(false)
|
||||||
) -> Result<String> {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_platform_support_tables(content: &str, targets: &[TargetInfo]) -> Result<String> {
|
||||||
let replace_table = |content, name, tier_table| -> Result<String> {
|
let replace_table = |content, name, tier_table| -> Result<String> {
|
||||||
let section_string = render_table(targets, tier_table)?;
|
let section_string = render_table(targets, tier_table)?;
|
||||||
replace_section(content, name, §ion_string).wrap_err("replacing platform support.md")
|
replace_section(content, name, §ion_string).wrap_err("replacing platform support.md")
|
||||||
|
|
@ -163,7 +166,7 @@ fn render_platform_support_tables(
|
||||||
content,
|
content,
|
||||||
"TIER1HOST",
|
"TIER1HOST",
|
||||||
TierTable {
|
TierTable {
|
||||||
filter: |target| target.1.metadata.tier == Some(1),
|
filter: |target| target.metadata.tier == Some(1),
|
||||||
include_host: false,
|
include_host: false,
|
||||||
include_std: false,
|
include_std: false,
|
||||||
},
|
},
|
||||||
|
|
@ -172,9 +175,7 @@ fn render_platform_support_tables(
|
||||||
&content,
|
&content,
|
||||||
"TIER2HOST",
|
"TIER2HOST",
|
||||||
TierTable {
|
TierTable {
|
||||||
filter: |target| {
|
filter: |target| target.metadata.tier == Some(2) && target.has_host_tools(),
|
||||||
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,
|
||||||
},
|
},
|
||||||
|
|
@ -183,9 +184,7 @@ fn render_platform_support_tables(
|
||||||
&content,
|
&content,
|
||||||
"TIER2",
|
"TIER2",
|
||||||
TierTable {
|
TierTable {
|
||||||
filter: |target| {
|
filter: |target| target.metadata.tier == Some(2) && !target.has_host_tools(),
|
||||||
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,
|
||||||
},
|
},
|
||||||
|
|
@ -194,7 +193,7 @@ fn render_platform_support_tables(
|
||||||
&content,
|
&content,
|
||||||
"TIER3",
|
"TIER3",
|
||||||
TierTable {
|
TierTable {
|
||||||
filter: |target| target.1.metadata.tier == Some(3),
|
filter: |target| target.metadata.tier == Some(3),
|
||||||
include_host: true,
|
include_host: true,
|
||||||
include_std: true,
|
include_std: true,
|
||||||
},
|
},
|
||||||
|
|
@ -212,18 +211,18 @@ fn render_table_option_bool(bool: Option<bool>) -> &'static str {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TierTable {
|
struct TierTable {
|
||||||
filter: fn(&(TargetDocs, RustcTargetInfo)) -> bool,
|
filter: fn(&TargetInfo) -> 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: &[TargetInfo], table: TierTable) -> Result<String> {
|
||||||
let mut rows = Vec::new();
|
let mut rows = Vec::new();
|
||||||
|
|
||||||
let targets = targets.into_iter().filter(|target| (table.filter)(&target));
|
let targets = targets.iter().filter(|target| (table.filter)(target));
|
||||||
|
|
||||||
for (target, rustc_info) in targets {
|
for target in targets {
|
||||||
let meta = &rustc_info.metadata;
|
let meta = &target.metadata;
|
||||||
|
|
||||||
let mut notes = meta.description.as_deref().unwrap_or("unknown").to_owned();
|
let mut notes = meta.description.as_deref().unwrap_or("unknown").to_owned();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue