@@ -6,63 +6,96 @@ use rinja::Template;
66
77mod cargo_metadata;
88
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- }
15-
169/// The entry point to the binary.
1710///
1811/// You should probably let `bootstrap` execute this program instead of running it directly.
1912///
2013/// Run `x.py run generate-copyright`
2114fn main ( ) -> Result < ( ) , Error > {
2215 let dest_file = env_path ( "DEST" ) ?;
16+ let libstd_dest_file = env_path ( "DEST_LIBSTD" ) ?;
2317 let out_dir = env_path ( "OUT_DIR" ) ?;
2418 let cargo = env_path ( "CARGO" ) ?;
2519 let license_metadata = env_path ( "LICENSE_METADATA" ) ?;
2620
27- let collected_tree_metadata: Metadata =
28- serde_json:: from_slice ( & std:: fs:: read ( & license_metadata) ?) ?;
29-
3021 let root_path = std:: path:: absolute ( "." ) ?;
31- let workspace_paths = [
32- Path :: new ( "./Cargo.toml" ) ,
33- Path :: new ( "./src/tools/cargo/Cargo.toml" ) ,
34- Path :: new ( "./library/Cargo.toml" ) ,
35- ] ;
36- let mut collected_cargo_metadata =
37- cargo_metadata:: get_metadata_and_notices ( & cargo, & out_dir, & root_path, & workspace_paths) ?;
3822
39- let stdlib_set =
40- cargo_metadata:: get_metadata ( & cargo, & root_path, & [ Path :: new ( "./library/std/Cargo.toml" ) ] ) ?;
23+ // Scan Cargo dependencies
24+ let mut collected_cargo_metadata =
25+ cargo_metadata:: get_metadata_and_notices ( & cargo, & out_dir. join ( "vendor" ) , & root_path, & [
26+ Path :: new ( "./Cargo.toml" ) ,
27+ Path :: new ( "./src/tools/cargo/Cargo.toml" ) ,
28+ Path :: new ( "./library/Cargo.toml" ) ,
29+ ] ) ?;
30+
31+ let library_collected_cargo_metadata = cargo_metadata:: get_metadata_and_notices (
32+ & cargo,
33+ & out_dir. join ( "library-vendor" ) ,
34+ & root_path,
35+ & [ Path :: new ( "./library/Cargo.toml" ) ] ,
36+ ) ?;
4137
4238 for ( key, value) in collected_cargo_metadata. iter_mut ( ) {
43- value. is_in_libstd = Some ( stdlib_set . contains_key ( key) ) ;
39+ value. is_in_libstd = Some ( library_collected_cargo_metadata . contains_key ( key) ) ;
4440 }
4541
42+ // Load JSON output by reuse
43+ let collected_tree_metadata: Metadata =
44+ serde_json:: from_slice ( & std:: fs:: read ( & license_metadata) ?) ?;
45+
46+ // Find libstd sub-set
47+ let library_collected_tree_metadata = Metadata {
48+ files : collected_tree_metadata
49+ . files
50+ . trim_clone ( & Path :: new ( "./library" ) , & Path :: new ( "." ) )
51+ . unwrap ( ) ,
52+ } ;
53+
54+ // Output main file
4655 let template = CopyrightTemplate {
4756 in_tree : collected_tree_metadata. files ,
4857 dependencies : collected_cargo_metadata,
4958 } ;
50-
5159 let output = template. render ( ) ?;
52-
5360 std:: fs:: write ( & dest_file, output) ?;
5461
62+ // Output libstd subset file
63+ let template = LibraryCopyrightTemplate {
64+ in_tree : library_collected_tree_metadata. files ,
65+ dependencies : library_collected_cargo_metadata,
66+ } ;
67+ let output = template. render ( ) ?;
68+ std:: fs:: write ( & libstd_dest_file, output) ?;
69+
5570 Ok ( ( ) )
5671}
5772
73+ /// The HTML template for the toolchain copyright file
74+ #[ derive( Template ) ]
75+ #[ template( path = "COPYRIGHT.html" ) ]
76+ struct CopyrightTemplate {
77+ in_tree : Node ,
78+ dependencies : BTreeMap < cargo_metadata:: Package , cargo_metadata:: PackageMetadata > ,
79+ }
80+
81+ /// The HTML template for the library copyright file
82+ #[ derive( Template ) ]
83+ #[ template( path = "COPYRIGHT-library.html" ) ]
84+ struct LibraryCopyrightTemplate {
85+ in_tree : Node ,
86+ dependencies : BTreeMap < cargo_metadata:: Package , cargo_metadata:: PackageMetadata > ,
87+ }
88+
5889/// Describes a tree of metadata for our filesystem tree
59- #[ derive( serde:: Deserialize ) ]
90+ ///
91+ /// Must match the JSON emitted by the `CollectLicenseMetadata` bootstrap tool.
92+ #[ derive( serde:: Deserialize , Clone , Debug , PartialEq , Eq ) ]
6093struct Metadata {
6194 files : Node ,
6295}
6396
6497/// Describes one node in our metadata tree
65- #[ derive( serde:: Deserialize , rinja:: Template ) ]
98+ #[ derive( serde:: Deserialize , rinja:: Template , Clone , Debug , PartialEq , Eq ) ]
6699#[ serde( rename_all = "kebab-case" , tag = "type" ) ]
67100#[ template( path = "Node.html" ) ]
68101pub ( crate ) enum Node {
@@ -72,8 +105,74 @@ pub(crate) enum Node {
72105 Group { files : Vec < String > , directories : Vec < String > , license : License } ,
73106}
74107
108+ impl Node {
109+ /// Clone, this node, but only if the path to the item is within the match path
110+ fn trim_clone ( & self , match_path : & Path , parent_path : & Path ) -> Option < Node > {
111+ match self {
112+ Node :: Root { children } => {
113+ let mut filtered_children = Vec :: new ( ) ;
114+ for node in children {
115+ if let Some ( child_node) = node. trim_clone ( match_path, parent_path) {
116+ filtered_children. push ( child_node) ;
117+ }
118+ }
119+ if filtered_children. is_empty ( ) {
120+ None
121+ } else {
122+ Some ( Node :: Root { children : filtered_children } )
123+ }
124+ }
125+ Node :: Directory { name, children, license } => {
126+ let child_name = parent_path. join ( name) ;
127+ if !( child_name. starts_with ( match_path) || match_path. starts_with ( & child_name) ) {
128+ return None ;
129+ }
130+ let mut filtered_children = Vec :: new ( ) ;
131+ for node in children {
132+ if let Some ( child_node) = node. trim_clone ( match_path, & child_name) {
133+ filtered_children. push ( child_node) ;
134+ }
135+ }
136+ Some ( Node :: Directory {
137+ name : name. clone ( ) ,
138+ children : filtered_children,
139+ license : license. clone ( ) ,
140+ } )
141+ }
142+ Node :: File { name, license } => {
143+ let child_name = parent_path. join ( name) ;
144+ if !( child_name. starts_with ( match_path) || match_path. starts_with ( & child_name) ) {
145+ return None ;
146+ }
147+ Some ( Node :: File { name : name. clone ( ) , license : license. clone ( ) } )
148+ }
149+ Node :: Group { files, directories, license } => {
150+ let mut filtered_child_files = Vec :: new ( ) ;
151+ for child in files {
152+ let child_name = parent_path. join ( child) ;
153+ if child_name. starts_with ( match_path) || match_path. starts_with ( & child_name) {
154+ filtered_child_files. push ( child. clone ( ) ) ;
155+ }
156+ }
157+ let mut filtered_child_dirs = Vec :: new ( ) ;
158+ for child in directories {
159+ let child_name = parent_path. join ( child) ;
160+ if child_name. starts_with ( match_path) || match_path. starts_with ( & child_name) {
161+ filtered_child_dirs. push ( child. clone ( ) ) ;
162+ }
163+ }
164+ Some ( Node :: Group {
165+ files : filtered_child_files,
166+ directories : filtered_child_dirs,
167+ license : license. clone ( ) ,
168+ } )
169+ }
170+ }
171+ }
172+ }
173+
75174/// A License has an SPDX license name and a list of copyright holders.
76- #[ derive( serde:: Deserialize ) ]
175+ #[ derive( serde:: Deserialize , Clone , Debug , PartialEq , Eq ) ]
77176struct License {
78177 spdx : String ,
79178 copyright : Vec < String > ,
0 commit comments