@@ -5,6 +5,33 @@ use std::path::{Path, PathBuf};
55
66mod cargo_metadata;
77
8+ static TOP_BOILERPLATE : & ' static str = r##"
9+ <!DOCTYPE html>
10+ <html>
11+ <head>
12+ <meta charset="UTF-8">
13+ <title>Copyright notices for The Rust Toolchain</title>
14+ </head>
15+ <body>
16+
17+ <h1>Copyright notices for The Rust Toolchain</h1>
18+
19+ <p>This file describes the copyright and licensing information for the source
20+ code within The Rust Project git tree, and the third-party dependencies used
21+ when building the Rust toolchain (including the Rust Standard Library).</p>
22+
23+ <h2>Table of Contents</h2>
24+ <ul>
25+ <li><a href="#in-tree-files">In-tree files</a></li>
26+ <li><a href="#out-of-tree-dependencies">Out-of-tree dependencies</a></li>
27+ </ul>
28+ "## ;
29+
30+ static BOTTOM_BOILERPLATE : & ' static str = r#"
31+ </body>
32+ </html>
33+ "# ;
34+
835/// The entry point to the binary.
936///
1037/// You should probably let `bootstrap` execute this program instead of running it directly.
@@ -32,40 +59,22 @@ fn main() -> Result<(), Error> {
3259
3360 let mut buffer = Vec :: new ( ) ;
3461
35- writeln ! ( buffer, "# COPYRIGHT for Rust" ) ?;
36- writeln ! ( buffer) ?;
37- writeln ! (
38- buffer,
39- "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)"
40- ) ?;
41- writeln ! ( buffer) ?;
42- writeln ! ( buffer, "## Table of Contents" ) ?;
43- writeln ! ( buffer) ?;
44- writeln ! ( buffer, "* [In-tree files](#in-tree-files)" ) ?;
45- writeln ! ( buffer, "* [Out-of-tree files](#out-of-tree-files)" ) ?;
46- // writeln!(buffer, "* [License Texts](#license-texts)")?;
47- writeln ! ( buffer) ?;
48-
49- writeln ! ( buffer, "## In-tree files" ) ?;
50- writeln ! ( buffer) ?;
62+ writeln ! ( buffer, "{}" , TOP_BOILERPLATE ) ?;
63+
5164 writeln ! (
5265 buffer,
53- " The following licenses cover the in-tree source files that were used in this release:"
66+ r#"<h2 id="in-tree-files">In-tree files</h2><p> The following licenses cover the in-tree source files that were used in this release:</p>"#
5467 ) ?;
55- writeln ! ( buffer) ?;
5668 render_tree_recursive ( & collected_tree_metadata. files , & mut buffer, 0 , & mut license_set) ?;
5769
58- writeln ! ( buffer) ?;
59-
60- writeln ! ( buffer, "## Out-of-tree files" ) ?;
61- writeln ! ( buffer) ?;
6270 writeln ! (
6371 buffer,
64- " The following licenses cover the out-of-tree crates that were used in this release:"
72+ r#"<h2 id="out-of-tree-dependencies">Out-of-tree dependencies</h2><p> The following licenses cover the out-of-tree crates that were used in this release:</p>"#
6573 ) ?;
66- writeln ! ( buffer) ?;
6774 render_deps ( collected_cargo_metadata. iter ( ) , & mut buffer, & mut license_set) ?;
6875
76+ writeln ! ( buffer, "{}" , BOTTOM_BOILERPLATE ) ?;
77+
6978 std:: fs:: write ( & dest_file, & buffer) ?;
7079
7180 Ok ( ( ) )
@@ -79,43 +88,27 @@ fn render_tree_recursive(
7988 depth : usize ,
8089 license_set : & mut BTreeSet < String > ,
8190) -> Result < ( ) , Error > {
82- let prefix = std:: iter:: repeat ( "> " ) . take ( depth + 1 ) . collect :: < String > ( ) ;
83-
91+ writeln ! ( buffer, r#"<div style="border:1px solid black; padding: 5px;">"# ) ?;
8492 match node {
8593 Node :: Root { children } => {
8694 for child in children {
8795 render_tree_recursive ( child, buffer, depth, license_set) ?;
8896 }
8997 }
9098 Node :: Directory { name, children, license } => {
91- render_tree_license (
92- & prefix,
93- std:: iter:: once ( name) ,
94- license. iter ( ) ,
95- buffer,
96- license_set,
97- ) ?;
99+ render_tree_license ( std:: iter:: once ( name) , license. iter ( ) , buffer, license_set) ?;
98100 if !children. is_empty ( ) {
99- writeln ! ( buffer, "{prefix}" ) ?;
100- writeln ! ( buffer, "{prefix}*Exceptions:*" ) ?;
101+ writeln ! ( buffer, "<p><b>Exceptions:</b></p>" ) ?;
101102 for child in children {
102- writeln ! ( buffer, "{prefix}" ) ?;
103103 render_tree_recursive ( child, buffer, depth + 1 , license_set) ?;
104104 }
105105 }
106106 }
107107 Node :: CondensedDirectory { name, licenses } => {
108- render_tree_license (
109- & prefix,
110- std:: iter:: once ( name) ,
111- licenses. iter ( ) ,
112- buffer,
113- license_set,
114- ) ?;
108+ render_tree_license ( std:: iter:: once ( name) , licenses. iter ( ) , buffer, license_set) ?;
115109 }
116110 Node :: Group { files, directories, license } => {
117111 render_tree_license (
118- & prefix,
119112 directories. iter ( ) . chain ( files. iter ( ) ) ,
120113 std:: iter:: once ( license) ,
121114 buffer,
@@ -124,26 +117,26 @@ fn render_tree_recursive(
124117 }
125118 Node :: File { name, license } => {
126119 render_tree_license (
127- & prefix,
128120 std:: iter:: once ( name) ,
129121 std:: iter:: once ( license) ,
130122 buffer,
131123 license_set,
132124 ) ?;
133125 }
134126 }
127+ writeln ! ( buffer, "</div>" ) ?;
135128
136129 Ok ( ( ) )
137130}
138131
139132/// Draw a series of sibling files/folders, as markdown, into the given Vec.
140133fn render_tree_license < ' a > (
141- prefix : & str ,
142134 names : impl Iterator < Item = & ' a String > ,
143135 licenses : impl Iterator < Item = & ' a License > ,
144136 buffer : & mut Vec < u8 > ,
145137 license_set : & mut BTreeSet < String > ,
146138) -> Result < ( ) , Error > {
139+ // de-duplicate and sort SPDX and Copyright strings
147140 let mut spdxs = BTreeSet :: new ( ) ;
148141 let mut copyrights = BTreeSet :: new ( ) ;
149142 for license in licenses {
@@ -154,15 +147,21 @@ fn render_tree_license<'a>(
154147 }
155148 }
156149
150+ writeln ! ( buffer, "<p><b>File/Directory:</b> " ) ?;
157151 for name in names {
158- writeln ! ( buffer, "{prefix}**`{ name}`** " ) ?;
152+ writeln ! ( buffer, "<code>{ name}</code> " ) ?;
159153 }
160- for spdx in spdxs. iter ( ) {
161- writeln ! ( buffer, "{prefix}License: `{spdx}` " ) ?;
154+ writeln ! ( buffer, "</p>" ) ?;
155+
156+ writeln ! ( buffer, "<p><b>License:</b> " ) ?;
157+ for ( i, spdx) in spdxs. iter ( ) . enumerate ( ) {
158+ let suffix = if i == spdxs. len ( ) - 1 { "" } else { ", " } ;
159+ writeln ! ( buffer, "{spdx}{suffix}" ) ?;
162160 }
163- for ( i, copyright) in copyrights. iter ( ) . enumerate ( ) {
164- let suffix = if i == copyrights. len ( ) - 1 { "" } else { " " } ;
165- writeln ! ( buffer, "{prefix}Copyright: {copyright}{suffix}" ) ?;
161+ writeln ! ( buffer, "</p>" ) ?;
162+
163+ for copyright in copyrights. iter ( ) {
164+ writeln ! ( buffer, "<p><b>Copyright:</b> {copyright}</p>" ) ?;
166165 }
167166
168167 Ok ( ( ) )
@@ -175,30 +174,25 @@ fn render_deps<'a, 'b>(
175174 license_set : & mut BTreeSet < String > ,
176175) -> Result < ( ) , Error > {
177176 for dep in deps {
178- let authors_list = dep. authors . join ( ", " ) . replace ( "<" , " \\ <" ) . replace ( ">" , " \\ >" ) ;
177+ let authors_list = dep. authors . join ( ", " ) ;
179178 let url = format ! ( "https://crates.io/crates/{}/{}" , dep. name, dep. version) ;
180179 writeln ! ( buffer) ?;
181180 writeln ! (
182181 buffer,
183- "### [{ name} {version}]({url})" ,
182+ r#"<h3><a href="{url}">{ name} {version}</a></h3>"# ,
184183 name = dep. name,
185184 version = dep. version,
186185 url = url,
187186 ) ?;
188- writeln ! ( buffer) ?;
189- writeln ! ( buffer, "* Authors: {}" , authors_list) ?;
190- writeln ! ( buffer, "* License: {}" , dep. license) ?;
187+ writeln ! ( buffer, "<h4>Authors</h4><p>{}</p>" , escape_html( & authors_list) ) ?;
188+ writeln ! ( buffer, "<h4>License</h4><p>{}</p>" , escape_html( & dep. license) ) ?;
191189 license_set. insert ( dep. license . clone ( ) ) ;
192190 for ( name, contents) in & dep. notices {
193191 writeln ! ( buffer) ?;
194- writeln ! ( buffer, "#### {} " , name. to_string_lossy( ) ) ?;
192+ writeln ! ( buffer, "<h4>{}</h3> " , name. to_string_lossy( ) ) ?;
195193 writeln ! ( buffer) ?;
196194 writeln ! ( buffer, "<details><summary>Click to expand</summary>" ) ?;
197- writeln ! ( buffer) ?;
198- writeln ! ( buffer, "```" ) ?;
199- writeln ! ( buffer, "{}" , contents) ?;
200- writeln ! ( buffer, "```" ) ?;
201- writeln ! ( buffer) ?;
195+ writeln ! ( buffer, "<pre>\n {}\n </pre>" , contents) ?;
202196 writeln ! ( buffer, "</details>" ) ?;
203197 }
204198 }
@@ -236,3 +230,13 @@ fn env_path(var: &str) -> Result<PathBuf, Error> {
236230 anyhow:: bail!( "missing environment variable {var}" )
237231 }
238232}
233+
234+ /// Escapes any invalid HTML characters
235+ fn escape_html ( input : & str ) -> String {
236+ static MAPPING : [ ( char , & ' static str ) ; 3 ] = [ ( '&' , "&" ) , ( '<' , "<" ) , ( '>' , ">" ) ] ;
237+ let mut output = input. to_owned ( ) ;
238+ for ( ch, s) in & MAPPING {
239+ output = output. replace ( * ch, s) ;
240+ }
241+ output
242+ }
0 commit comments