diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 4b48d0901e8a9..ecd63a397e50d 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -209,11 +209,10 @@ impl Step for GenerateCopyright { } fn run(self, builder: &Builder<'_>) -> Self::Output { - // let license_metadata = builder.ensure(CollectLicenseMetadata); - let license_metadata = builder.out.join("license-metadata.json"); + let license_metadata = builder.ensure(CollectLicenseMetadata); // Temporary location, it will be moved to the proper one once it's accurate. - let dest = builder.out.join("COPYRIGHT.md"); + let dest = builder.out.join("COPYRIGHT.html"); let mut cmd = builder.tool_cmd(Tool::GenerateCopyright); cmd.env("LICENSE_METADATA", &license_metadata); diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs index 05f741e18d753..35b47082fb1a8 100644 --- a/src/tools/generate-copyright/src/main.rs +++ b/src/tools/generate-copyright/src/main.rs @@ -5,6 +5,33 @@ use std::path::{Path, PathBuf}; mod cargo_metadata; +static TOP_BOILERPLATE: &'static str = r##" + + + + + Copyright notices for The Rust Toolchain + + + +

Copyright notices for The Rust Toolchain

+ +

This file describes the copyright and licensing information for the source +code within The Rust Project git tree, and the third-party dependencies used +when building the Rust toolchain (including the Rust Standard Library).

+ +

Table of Contents

+ +"##; + +static BOTTOM_BOILERPLATE: &'static str = r#" + + +"#; + /// The entry point to the binary. /// /// You should probably let `bootstrap` execute this program instead of running it directly. @@ -32,40 +59,22 @@ fn main() -> Result<(), Error> { let mut buffer = Vec::new(); - writeln!(buffer, "# COPYRIGHT for Rust")?; - writeln!(buffer)?; - writeln!( - buffer, - "This file describes the copyright and licensing information for the source code within The Rust Project git tree, and the third-party dependencies used when building the Rust toolchain (including the Rust Standard Library)" - )?; - writeln!(buffer)?; - writeln!(buffer, "## Table of Contents")?; - writeln!(buffer)?; - writeln!(buffer, "* [In-tree files](#in-tree-files)")?; - writeln!(buffer, "* [Out-of-tree files](#out-of-tree-files)")?; - // writeln!(buffer, "* [License Texts](#license-texts)")?; - writeln!(buffer)?; - - writeln!(buffer, "## In-tree files")?; - writeln!(buffer)?; + writeln!(buffer, "{}", TOP_BOILERPLATE)?; + writeln!( buffer, - "The following licenses cover the in-tree source files that were used in this release:" + r#"

In-tree files

The following licenses cover the in-tree source files that were used in this release:

"# )?; - writeln!(buffer)?; render_tree_recursive(&collected_tree_metadata.files, &mut buffer, 0, &mut license_set)?; - writeln!(buffer)?; - - writeln!(buffer, "## Out-of-tree files")?; - writeln!(buffer)?; writeln!( buffer, - "The following licenses cover the out-of-tree crates that were used in this release:" + r#"

Out-of-tree dependencies

The following licenses cover the out-of-tree crates that were used in this release:

"# )?; - writeln!(buffer)?; render_deps(collected_cargo_metadata.iter(), &mut buffer, &mut license_set)?; + writeln!(buffer, "{}", BOTTOM_BOILERPLATE)?; + std::fs::write(&dest_file, &buffer)?; Ok(()) @@ -79,8 +88,7 @@ fn render_tree_recursive( depth: usize, license_set: &mut BTreeSet, ) -> Result<(), Error> { - let prefix = std::iter::repeat("> ").take(depth + 1).collect::(); - + writeln!(buffer, r#"
"#)?; match node { Node::Root { children } => { for child in children { @@ -88,34 +96,19 @@ fn render_tree_recursive( } } Node::Directory { name, children, license } => { - render_tree_license( - &prefix, - std::iter::once(name), - license.iter(), - buffer, - license_set, - )?; + render_tree_license(std::iter::once(name), license.iter(), buffer, license_set)?; if !children.is_empty() { - writeln!(buffer, "{prefix}")?; - writeln!(buffer, "{prefix}*Exceptions:*")?; + writeln!(buffer, "

Exceptions:

")?; for child in children { - writeln!(buffer, "{prefix}")?; render_tree_recursive(child, buffer, depth + 1, license_set)?; } } } Node::CondensedDirectory { name, licenses } => { - render_tree_license( - &prefix, - std::iter::once(name), - licenses.iter(), - buffer, - license_set, - )?; + render_tree_license(std::iter::once(name), licenses.iter(), buffer, license_set)?; } Node::Group { files, directories, license } => { render_tree_license( - &prefix, directories.iter().chain(files.iter()), std::iter::once(license), buffer, @@ -124,7 +117,6 @@ fn render_tree_recursive( } Node::File { name, license } => { render_tree_license( - &prefix, std::iter::once(name), std::iter::once(license), buffer, @@ -132,18 +124,19 @@ fn render_tree_recursive( )?; } } + writeln!(buffer, "
")?; Ok(()) } /// Draw a series of sibling files/folders, as markdown, into the given Vec. fn render_tree_license<'a>( - prefix: &str, names: impl Iterator, licenses: impl Iterator, buffer: &mut Vec, license_set: &mut BTreeSet, ) -> Result<(), Error> { + // de-duplicate and sort SPDX and Copyright strings let mut spdxs = BTreeSet::new(); let mut copyrights = BTreeSet::new(); for license in licenses { @@ -154,15 +147,21 @@ fn render_tree_license<'a>( } } + writeln!(buffer, "

File/Directory: ")?; for name in names { - writeln!(buffer, "{prefix}**`{name}`** ")?; + writeln!(buffer, "{name}")?; } - for spdx in spdxs.iter() { - writeln!(buffer, "{prefix}License: `{spdx}` ")?; + writeln!(buffer, "

")?; + + writeln!(buffer, "

License: ")?; + for (i, spdx) in spdxs.iter().enumerate() { + let suffix = if i == spdxs.len() - 1 { "" } else { ", " }; + writeln!(buffer, "{spdx}{suffix}")?; } - for (i, copyright) in copyrights.iter().enumerate() { - let suffix = if i == copyrights.len() - 1 { "" } else { " " }; - writeln!(buffer, "{prefix}Copyright: {copyright}{suffix}")?; + writeln!(buffer, "

")?; + + for copyright in copyrights.iter() { + writeln!(buffer, "

Copyright: {copyright}

")?; } Ok(()) @@ -175,30 +174,25 @@ fn render_deps<'a, 'b>( license_set: &mut BTreeSet, ) -> Result<(), Error> { for dep in deps { - let authors_list = dep.authors.join(", ").replace("<", "\\<").replace(">", "\\>"); + let authors_list = dep.authors.join(", "); let url = format!("https://crates.io/crates/{}/{}", dep.name, dep.version); writeln!(buffer)?; writeln!( buffer, - "### [{name} {version}]({url})", + r#"

{name} {version}

"#, name = dep.name, version = dep.version, url = url, )?; - writeln!(buffer)?; - writeln!(buffer, "* Authors: {}", authors_list)?; - writeln!(buffer, "* License: {}", dep.license)?; + writeln!(buffer, "

Authors

{}

", escape_html(&authors_list))?; + writeln!(buffer, "

License

{}

", escape_html(&dep.license))?; license_set.insert(dep.license.clone()); for (name, contents) in &dep.notices { writeln!(buffer)?; - writeln!(buffer, "#### {}", name.to_string_lossy())?; + writeln!(buffer, "

{}

", name.to_string_lossy())?; writeln!(buffer)?; writeln!(buffer, "
Click to expand")?; - writeln!(buffer)?; - writeln!(buffer, "```")?; - writeln!(buffer, "{}", contents)?; - writeln!(buffer, "```")?; - writeln!(buffer)?; + writeln!(buffer, "
\n{}\n
", contents)?; writeln!(buffer, "
")?; } } @@ -236,3 +230,13 @@ fn env_path(var: &str) -> Result { anyhow::bail!("missing environment variable {var}") } } + +/// Escapes any invalid HTML characters +fn escape_html(input: &str) -> String { + static MAPPING: [(char, &'static str); 3] = [('&', "&"), ('<', "<"), ('>', ">")]; + let mut output = input.to_owned(); + for (ch, s) in &MAPPING { + output = output.replace(*ch, s); + } + output +}