44//! passes over the tree to remove redundant information.
55
66use crate :: licenses:: { License , LicenseId , LicensesInterner } ;
7- use std:: collections:: BTreeMap ;
7+ use std:: collections:: { BTreeMap , BTreeSet } ;
88use std:: path:: { Path , PathBuf } ;
99
10+ // Some directories have too many slight license differences that'd result in a huge report, and
11+ // could be considered a standalone project anyway. Those directories are "condensed" into a single
12+ // licensing block for ease of reading, merging the licensing information.
13+ const CONDENSED_DIRECTORIED : & [ & str ] = & [ "./src/llvm-project/" ] ;
14+
1015#[ derive( serde:: Serialize ) ]
1116#[ serde( rename_all = "kebab-case" , tag = "type" ) ]
1217pub ( crate ) enum Node < L > {
1318 Root { children : Vec < Node < L > > } ,
1419 Directory { name : PathBuf , children : Vec < Node < L > > , license : Option < L > } ,
20+ CondensedDirectory { name : PathBuf , licenses : Vec < L > } ,
1521 File { name : PathBuf , license : L } ,
1622 Group { files : Vec < PathBuf > , directories : Vec < PathBuf > , license : L } ,
1723 Empty ,
@@ -57,9 +63,9 @@ impl Node<LicenseId> {
5763 Node :: Directory { name, mut children, license : None } => {
5864 directories. entry ( name) . or_insert_with ( Vec :: new) . append ( & mut children) ;
5965 }
60- file @ Node :: File { .. } => {
61- files . push ( file ) ;
62- }
66+ file @ Node :: File { .. } => files . push ( file ) ,
67+ // Propagate condensed directories as-is.
68+ condensed @ Node :: CondensedDirectory { .. } => files . push ( condensed ) ,
6369 Node :: Empty => { }
6470 Node :: Root { .. } => {
6571 panic ! ( "can't have a root inside another element" ) ;
@@ -86,6 +92,7 @@ impl Node<LicenseId> {
8692 }
8793 Node :: Empty => { }
8894 Node :: File { .. } => { }
95+ Node :: CondensedDirectory { .. } => { }
8996 Node :: Group { .. } => {
9097 panic ! ( "Group should not be present at this stage" ) ;
9198 }
@@ -132,6 +139,7 @@ impl Node<LicenseId> {
132139 }
133140 }
134141 Node :: File { .. } => { }
142+ Node :: CondensedDirectory { .. } => { }
135143 Node :: Group { .. } => panic ! ( "group should not be present at this stage" ) ,
136144 Node :: Empty => { }
137145 }
@@ -174,6 +182,9 @@ impl Node<LicenseId> {
174182 Node :: Directory { name : child_child_name, .. } => {
175183 * child_child_name = child_name. join ( & child_child_name) ;
176184 }
185+ Node :: CondensedDirectory { name : child_child_name, .. } => {
186+ * child_child_name = child_name. join ( & child_child_name) ;
187+ }
177188 Node :: File { name : child_child_name, .. } => {
178189 * child_child_name = child_name. join ( & child_child_name) ;
179190 }
@@ -188,6 +199,7 @@ impl Node<LicenseId> {
188199 }
189200 Node :: Empty => { }
190201 Node :: File { .. } => { }
202+ Node :: CondensedDirectory { .. } => { }
191203 Node :: Group { .. } => panic ! ( "Group should not be present at this stage" ) ,
192204 }
193205 }
@@ -255,6 +267,7 @@ impl Node<LicenseId> {
255267 }
256268 }
257269 Node :: File { .. } => { }
270+ Node :: CondensedDirectory { .. } => { }
258271 Node :: Group { .. } => panic ! ( "FileGroup should not be present at this stage" ) ,
259272 Node :: Empty => { }
260273 }
@@ -270,6 +283,7 @@ impl Node<LicenseId> {
270283 }
271284 children. retain ( |child| !matches ! ( child, Node :: Empty ) ) ;
272285 }
286+ Node :: CondensedDirectory { .. } => { }
273287 Node :: Group { .. } => { }
274288 Node :: File { .. } => { }
275289 Node :: Empty => { }
@@ -293,7 +307,19 @@ pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> {
293307 // Ensure reproducibility of all future steps.
294308 input. sort ( ) ;
295309
296- for ( path, license) in input {
310+ let mut condensed_directories = BTreeMap :: new ( ) ;
311+ ' outer: for ( path, license) in input {
312+ // Files in condensed directories are handled separately.
313+ for directory in CONDENSED_DIRECTORIED {
314+ if path. starts_with ( directory) {
315+ condensed_directories
316+ . entry ( * directory)
317+ . or_insert_with ( BTreeSet :: new)
318+ . insert ( license) ;
319+ continue ' outer;
320+ }
321+ }
322+
297323 let mut node = Node :: File { name : path. file_name ( ) . unwrap ( ) . into ( ) , license } ;
298324 for component in path. parent ( ) . unwrap_or_else ( || Path :: new ( "." ) ) . components ( ) . rev ( ) {
299325 node = Node :: Directory {
@@ -306,6 +332,22 @@ pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> {
306332 children. push ( node) ;
307333 }
308334
335+ for ( path, licenses) in condensed_directories {
336+ let path = Path :: new ( path) ;
337+ let mut node = Node :: CondensedDirectory {
338+ name : path. file_name ( ) . unwrap ( ) . into ( ) ,
339+ licenses : licenses. iter ( ) . copied ( ) . collect ( ) ,
340+ } ;
341+ for name in path. parent ( ) . unwrap_or_else ( || Path :: new ( "." ) ) . components ( ) . rev ( ) {
342+ node = Node :: Directory {
343+ name : name. as_os_str ( ) . into ( ) ,
344+ children : vec ! [ node] ,
345+ license : None ,
346+ } ;
347+ }
348+ children. push ( node) ;
349+ }
350+
309351 Node :: Root { children }
310352}
311353
@@ -334,6 +376,10 @@ pub(crate) fn expand_interned_licenses(
334376 Node :: Group { files, directories, license } => {
335377 Node :: Group { files, directories, license : interner. resolve ( license) }
336378 }
379+ Node :: CondensedDirectory { name, licenses } => Node :: CondensedDirectory {
380+ name,
381+ licenses : licenses. into_iter ( ) . map ( |license| interner. resolve ( license) ) . collect ( ) ,
382+ } ,
337383 Node :: Empty => Node :: Empty ,
338384 }
339385}
0 commit comments