4
4
//! passes over the tree to remove redundant information.
5
5
6
6
use crate :: licenses:: { License , LicenseId , LicensesInterner } ;
7
- use std:: collections:: BTreeMap ;
7
+ use std:: collections:: { BTreeMap , BTreeSet } ;
8
8
use std:: path:: { Path , PathBuf } ;
9
9
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
+
10
15
#[ derive( serde:: Serialize ) ]
11
16
#[ serde( rename_all = "kebab-case" , tag = "type" ) ]
12
17
pub ( crate ) enum Node < L > {
13
18
Root { children : Vec < Node < L > > } ,
14
19
Directory { name : PathBuf , children : Vec < Node < L > > , license : Option < L > } ,
20
+ CondensedDirectory { name : PathBuf , licenses : Vec < L > } ,
15
21
File { name : PathBuf , license : L } ,
16
22
Group { files : Vec < PathBuf > , directories : Vec < PathBuf > , license : L } ,
17
23
Empty ,
@@ -57,9 +63,9 @@ impl Node<LicenseId> {
57
63
Node :: Directory { name, mut children, license : None } => {
58
64
directories. entry ( name) . or_insert_with ( Vec :: new) . append ( & mut children) ;
59
65
}
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 ) ,
63
69
Node :: Empty => { }
64
70
Node :: Root { .. } => {
65
71
panic ! ( "can't have a root inside another element" ) ;
@@ -86,6 +92,7 @@ impl Node<LicenseId> {
86
92
}
87
93
Node :: Empty => { }
88
94
Node :: File { .. } => { }
95
+ Node :: CondensedDirectory { .. } => { }
89
96
Node :: Group { .. } => {
90
97
panic ! ( "Group should not be present at this stage" ) ;
91
98
}
@@ -132,6 +139,7 @@ impl Node<LicenseId> {
132
139
}
133
140
}
134
141
Node :: File { .. } => { }
142
+ Node :: CondensedDirectory { .. } => { }
135
143
Node :: Group { .. } => panic ! ( "group should not be present at this stage" ) ,
136
144
Node :: Empty => { }
137
145
}
@@ -174,6 +182,9 @@ impl Node<LicenseId> {
174
182
Node :: Directory { name : child_child_name, .. } => {
175
183
* child_child_name = child_name. join ( & child_child_name) ;
176
184
}
185
+ Node :: CondensedDirectory { name : child_child_name, .. } => {
186
+ * child_child_name = child_name. join ( & child_child_name) ;
187
+ }
177
188
Node :: File { name : child_child_name, .. } => {
178
189
* child_child_name = child_name. join ( & child_child_name) ;
179
190
}
@@ -188,6 +199,7 @@ impl Node<LicenseId> {
188
199
}
189
200
Node :: Empty => { }
190
201
Node :: File { .. } => { }
202
+ Node :: CondensedDirectory { .. } => { }
191
203
Node :: Group { .. } => panic ! ( "Group should not be present at this stage" ) ,
192
204
}
193
205
}
@@ -255,6 +267,7 @@ impl Node<LicenseId> {
255
267
}
256
268
}
257
269
Node :: File { .. } => { }
270
+ Node :: CondensedDirectory { .. } => { }
258
271
Node :: Group { .. } => panic ! ( "FileGroup should not be present at this stage" ) ,
259
272
Node :: Empty => { }
260
273
}
@@ -270,6 +283,7 @@ impl Node<LicenseId> {
270
283
}
271
284
children. retain ( |child| !matches ! ( child, Node :: Empty ) ) ;
272
285
}
286
+ Node :: CondensedDirectory { .. } => { }
273
287
Node :: Group { .. } => { }
274
288
Node :: File { .. } => { }
275
289
Node :: Empty => { }
@@ -293,7 +307,19 @@ pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> {
293
307
// Ensure reproducibility of all future steps.
294
308
input. sort ( ) ;
295
309
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
+
297
323
let mut node = Node :: File { name : path. file_name ( ) . unwrap ( ) . into ( ) , license } ;
298
324
for component in path. parent ( ) . unwrap_or_else ( || Path :: new ( "." ) ) . components ( ) . rev ( ) {
299
325
node = Node :: Directory {
@@ -306,6 +332,22 @@ pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> {
306
332
children. push ( node) ;
307
333
}
308
334
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
+
309
351
Node :: Root { children }
310
352
}
311
353
@@ -334,6 +376,10 @@ pub(crate) fn expand_interned_licenses(
334
376
Node :: Group { files, directories, license } => {
335
377
Node :: Group { files, directories, license : interner. resolve ( license) }
336
378
}
379
+ Node :: CondensedDirectory { name, licenses } => Node :: CondensedDirectory {
380
+ name,
381
+ licenses : licenses. into_iter ( ) . map ( |license| interner. resolve ( license) ) . collect ( ) ,
382
+ } ,
337
383
Node :: Empty => Node :: Empty ,
338
384
}
339
385
}
0 commit comments