1
1
use std:: collections:: BTreeMap ;
2
- use std:: io:: Write ;
3
2
use std:: path:: { Path , PathBuf } ;
4
3
5
4
use anyhow:: Error ;
5
+ use rinja:: Template ;
6
6
7
7
mod cargo_metadata;
8
8
9
- static TOP_BOILERPLATE : & str = r##"
10
- <!DOCTYPE html>
11
- <html>
12
- <head>
13
- <meta charset="UTF-8">
14
- <title>Copyright notices for The Rust Toolchain</title>
15
- </head>
16
- <body>
17
-
18
- <h1>Copyright notices for The Rust Toolchain</h1>
19
-
20
- <p>This file describes the copyright and licensing information for the source
21
- code within The Rust Project git tree, and the third-party dependencies used
22
- when building the Rust toolchain (including the Rust Standard Library).</p>
23
-
24
- <h2>Table of Contents</h2>
25
- <ul>
26
- <li><a href="#in-tree-files">In-tree files</a></li>
27
- <li><a href="#out-of-tree-dependencies">Out-of-tree dependencies</a></li>
28
- </ul>
29
- "## ;
30
-
31
- static BOTTOM_BOILERPLATE : & str = r#"
32
- </body>
33
- </html>
34
- "# ;
9
+ #[ derive( Template ) ]
10
+ #[ template( path = "COPYRIGHT.html" ) ]
11
+ struct CopyrightTemplate {
12
+ in_tree : Node ,
13
+ dependencies : BTreeMap < cargo_metadata:: Package , cargo_metadata:: PackageMetadata > ,
14
+ }
35
15
36
16
/// The entry point to the binary.
37
17
///
@@ -53,150 +33,114 @@ fn main() -> Result<(), Error> {
53
33
Path :: new ( "./src/tools/cargo/Cargo.toml" ) ,
54
34
Path :: new ( "./library/std/Cargo.toml" ) ,
55
35
] ;
56
- let collected_cargo_metadata =
36
+ let mut collected_cargo_metadata =
57
37
cargo_metadata:: get_metadata_and_notices ( & cargo, & out_dir, & root_path, & workspace_paths) ?;
58
38
59
39
let stdlib_set =
60
40
cargo_metadata:: get_metadata ( & cargo, & root_path, & [ Path :: new ( "./library/std/Cargo.toml" ) ] ) ?;
61
41
62
- let mut buffer = Vec :: new ( ) ;
42
+ for ( key, value) in collected_cargo_metadata. iter_mut ( ) {
43
+ value. is_in_libstd = Some ( stdlib_set. contains_key ( key) ) ;
44
+ }
63
45
64
- writeln ! ( buffer, "{}" , TOP_BOILERPLATE ) ?;
46
+ let template = CopyrightTemplate {
47
+ in_tree : collected_tree_metadata. files ,
48
+ dependencies : collected_cargo_metadata,
49
+ } ;
65
50
66
- writeln ! (
67
- buffer,
68
- 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>"#
69
- ) ?;
70
- render_tree_recursive ( & collected_tree_metadata. files , & mut buffer) ?;
51
+ let output = template. render ( ) ?;
71
52
72
- writeln ! (
73
- buffer,
74
- 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>"#
75
- ) ?;
76
- render_deps ( & collected_cargo_metadata, & stdlib_set, & mut buffer) ?;
53
+ std:: fs:: write ( & dest_file, output) ?;
77
54
78
- writeln ! ( buffer, "{}" , BOTTOM_BOILERPLATE ) ?;
55
+ Ok ( ( ) )
56
+ }
79
57
80
- std:: fs:: write ( & dest_file, & buffer) ?;
58
+ /// Describes a tree of metadata for our filesystem tree
59
+ #[ derive( serde:: Deserialize ) ]
60
+ struct Metadata {
61
+ files : Node ,
62
+ }
81
63
64
+ /// Describes one node in our metadata tree
65
+ #[ derive( serde:: Deserialize ) ]
66
+ #[ serde( rename_all = "kebab-case" , tag = "type" ) ]
67
+ pub ( crate ) enum Node {
68
+ Root { children : Vec < Node > } ,
69
+ Directory { name : String , children : Vec < Node > , license : Option < License > } ,
70
+ File { name : String , license : License } ,
71
+ Group { files : Vec < String > , directories : Vec < String > , license : License } ,
72
+ }
73
+
74
+ fn with_box < F > ( fmt : & mut std:: fmt:: Formatter < ' _ > , inner : F ) -> std:: fmt:: Result
75
+ where
76
+ F : FnOnce ( & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result ,
77
+ {
78
+ writeln ! ( fmt, r#"<div style="border:1px solid black; padding: 5px;">"# ) ?;
79
+ inner ( fmt) ?;
80
+ writeln ! ( fmt, "</div>" ) ?;
82
81
Ok ( ( ) )
83
82
}
84
83
85
- /// Recursively draw the tree of files/folders we found on disk and their licenses, as
86
- /// markdown, into the given Vec.
87
- fn render_tree_recursive ( node : & Node , buffer : & mut Vec < u8 > ) -> Result < ( ) , Error > {
88
- writeln ! ( buffer, r#"<div style="border:1px solid black; padding: 5px;">"# ) ?;
89
- match node {
90
- Node :: Root { children } => {
91
- for child in children {
92
- render_tree_recursive ( child, buffer) ?;
84
+ impl std:: fmt:: Display for Node {
85
+ fn fmt ( & self , fmt : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
86
+ match self {
87
+ Node :: Root { children } => {
88
+ if children. len ( ) > 1 {
89
+ with_box ( fmt, |f| {
90
+ for child in children {
91
+ writeln ! ( f, "{child}" ) ?;
92
+ }
93
+ Ok ( ( ) )
94
+ } )
95
+ } else {
96
+ for child in children {
97
+ writeln ! ( fmt, "{child}" ) ?;
98
+ }
99
+ Ok ( ( ) )
100
+ }
93
101
}
94
- }
95
- Node :: Directory { name , children , license } => {
96
- render_tree_license ( std :: iter :: once ( name ) , license . as_ref ( ) , buffer ) ? ;
97
- if !children . is_empty ( ) {
98
- writeln ! ( buffer , "<p><b>Exceptions:</b></p>" ) ? ;
99
- for child in children {
100
- render_tree_recursive ( child , buffer ) ? ;
102
+ Node :: Directory { name , children , license } => with_box ( fmt , |f| {
103
+ render_tree_license ( std :: iter :: once ( name ) , license . as_ref ( ) , f ) ? ;
104
+ if !children . is_empty ( ) {
105
+ writeln ! ( f , "<p><b>Exceptions:</b></p>" ) ? ;
106
+ for child in children {
107
+ writeln ! ( f , "{child}" ) ? ;
108
+ }
101
109
}
110
+ Ok ( ( ) )
111
+ } ) ,
112
+ Node :: Group { files, directories, license } => with_box ( fmt, |f| {
113
+ render_tree_license ( directories. iter ( ) . chain ( files. iter ( ) ) , Some ( license) , f)
114
+ } ) ,
115
+ Node :: File { name, license } => {
116
+ with_box ( fmt, |f| render_tree_license ( std:: iter:: once ( name) , Some ( license) , f) )
102
117
}
103
118
}
104
- Node :: Group { files, directories, license } => {
105
- render_tree_license ( directories. iter ( ) . chain ( files. iter ( ) ) , Some ( license) , buffer) ?;
106
- }
107
- Node :: File { name, license } => {
108
- render_tree_license ( std:: iter:: once ( name) , Some ( license) , buffer) ?;
109
- }
110
119
}
111
- writeln ! ( buffer, "</div>" ) ?;
112
-
113
- Ok ( ( ) )
114
120
}
115
121
116
- /// Draw a series of sibling files/folders, as markdown , into the given Vec .
122
+ /// Draw a series of sibling files/folders, as HTML , into the given formatter .
117
123
fn render_tree_license < ' a > (
118
124
names : impl Iterator < Item = & ' a String > ,
119
125
license : Option < & License > ,
120
- buffer : & mut Vec < u8 > ,
121
- ) -> Result < ( ) , Error > {
122
- writeln ! ( buffer , "<p><b>File/Directory:</b> " ) ?;
126
+ f : & mut std :: fmt :: Formatter < ' _ > ,
127
+ ) -> std :: fmt :: Result {
128
+ writeln ! ( f , "<p><b>File/Directory:</b> " ) ?;
123
129
for name in names {
124
- writeln ! ( buffer , "<code>{name }</code>" ) ?;
130
+ writeln ! ( f , "<code>{}</code>" , html_escape :: encode_text ( & name ) ) ?;
125
131
}
126
- writeln ! ( buffer , "</p>" ) ?;
132
+ writeln ! ( f , "</p>" ) ?;
127
133
128
134
if let Some ( license) = license {
129
- writeln ! ( buffer , "<p><b>License:</b> {}</p>" , license. spdx) ?;
135
+ writeln ! ( f , "<p><b>License:</b> {}</p>" , html_escape :: encode_text ( & license. spdx) ) ?;
130
136
for copyright in license. copyright . iter ( ) {
131
- writeln ! ( buffer , "<p><b>Copyright:</b> {copyright }</p>" ) ?;
137
+ writeln ! ( f , "<p><b>Copyright:</b> {}</p>" , html_escape :: encode_text ( & copyright ) ) ?;
132
138
}
133
139
}
134
140
135
141
Ok ( ( ) )
136
142
}
137
143
138
- /// Render a list of out-of-tree dependencies as markdown into the given Vec.
139
- fn render_deps (
140
- all_deps : & BTreeMap < cargo_metadata:: Package , cargo_metadata:: PackageMetadata > ,
141
- stdlib_set : & BTreeMap < cargo_metadata:: Package , cargo_metadata:: PackageMetadata > ,
142
- buffer : & mut Vec < u8 > ,
143
- ) -> Result < ( ) , Error > {
144
- for ( package, metadata) in all_deps {
145
- let authors_list = if metadata. authors . is_empty ( ) {
146
- "None Specified" . to_owned ( )
147
- } else {
148
- metadata. authors . join ( ", " )
149
- } ;
150
- let url = format ! ( "https://crates.io/crates/{}/{}" , package. name, package. version) ;
151
- writeln ! ( buffer) ?;
152
- writeln ! (
153
- buffer,
154
- r#"<h3>📦 {name}-{version}</h3>"# ,
155
- name = package. name,
156
- version = package. version,
157
- ) ?;
158
- writeln ! ( buffer, r#"<p><b>URL:</b> <a href="{url}">{url}</a></p>"# , ) ?;
159
- writeln ! (
160
- buffer,
161
- "<p><b>In libstd:</b> {}</p>" ,
162
- if stdlib_set. contains_key( package) { "Yes" } else { "No" }
163
- ) ?;
164
- writeln ! ( buffer, "<p><b>Authors:</b> {}</p>" , escape_html( & authors_list) ) ?;
165
- writeln ! ( buffer, "<p><b>License:</b> {}</p>" , escape_html( & metadata. license) ) ?;
166
- writeln ! ( buffer, "<p><b>Notices:</b> " ) ?;
167
- if metadata. notices . is_empty ( ) {
168
- writeln ! ( buffer, "None" ) ?;
169
- } else {
170
- for ( name, contents) in & metadata. notices {
171
- writeln ! (
172
- buffer,
173
- "<details><summary><code>{}</code></summary>" ,
174
- name. to_string_lossy( )
175
- ) ?;
176
- writeln ! ( buffer, "<pre>\n {}\n </pre>" , contents) ?;
177
- writeln ! ( buffer, "</details>" ) ?;
178
- }
179
- }
180
- writeln ! ( buffer, "</p>" ) ?;
181
- }
182
- Ok ( ( ) )
183
- }
184
- /// Describes a tree of metadata for our filesystem tree
185
- #[ derive( serde:: Deserialize ) ]
186
- struct Metadata {
187
- files : Node ,
188
- }
189
-
190
- /// Describes one node in our metadata tree
191
- #[ derive( serde:: Deserialize ) ]
192
- #[ serde( rename_all = "kebab-case" , tag = "type" ) ]
193
- pub ( crate ) enum Node {
194
- Root { children : Vec < Node > } ,
195
- Directory { name : String , children : Vec < Node > , license : Option < License > } ,
196
- File { name : String , license : License } ,
197
- Group { files : Vec < String > , directories : Vec < String > , license : License } ,
198
- }
199
-
200
144
/// A License has an SPDX license name and a list of copyright holders.
201
145
#[ derive( serde:: Deserialize ) ]
202
146
struct License {
@@ -212,13 +156,3 @@ fn env_path(var: &str) -> Result<PathBuf, Error> {
212
156
anyhow:: bail!( "missing environment variable {var}" )
213
157
}
214
158
}
215
-
216
- /// Escapes any invalid HTML characters
217
- fn escape_html ( input : & str ) -> String {
218
- static MAPPING : [ ( char , & str ) ; 3 ] = [ ( '&' , "&" ) , ( '<' , "<" ) , ( '>' , ">" ) ] ;
219
- let mut output = input. to_owned ( ) ;
220
- for ( ch, s) in & MAPPING {
221
- output = output. replace ( * ch, s) ;
222
- }
223
- output
224
- }
0 commit comments