@@ -20,8 +20,10 @@ pub struct Context<W> {
20
20
pub ignore_bots : bool ,
21
21
/// Show personally identifiable information before the summary. Includes names and email addresses.
22
22
pub show_pii : bool ,
23
- /// Collect additional information like tree changes and changed lines.
24
- pub stats : bool ,
23
+ /// Collect how many files have been added, removed and modified (without rename tracking).
24
+ pub file_stats : bool ,
25
+ /// Collect how many lines in files have been added, removed and modified (without rename tracking).
26
+ pub line_stats : bool ,
25
27
/// Omit unifying identities by name and email which can lead to the same author appear multiple times
26
28
/// due to using different names or email addresses.
27
29
pub omit_unify_identities : bool ,
@@ -42,7 +44,8 @@ pub fn estimate<W, P>(
42
44
Context {
43
45
show_pii,
44
46
ignore_bots,
45
- stats,
47
+ file_stats,
48
+ line_stats,
46
49
omit_unify_identities,
47
50
mut out,
48
51
} : Context < W > ,
56
59
let mut string_heap = BTreeSet :: < & ' static [ u8 ] > :: new ( ) ;
57
60
58
61
let ( commit_authors, stats, is_shallow) = {
59
- let stat_progress = stats . then ( || progress. add_child ( "extract stats" ) ) . map ( |mut p| {
62
+ let stat_progress = file_stats . then ( || progress. add_child ( "extract stats" ) ) . map ( |mut p| {
60
63
p. init ( None , progress:: count ( "commits" ) ) ;
61
64
p
62
65
} ) ;
@@ -113,7 +116,7 @@ where
113
116
Ok ( out)
114
117
} ) ;
115
118
116
- let ( tx_tree_id, stat_threads) = stats
119
+ let ( tx_tree_id, stat_threads) = ( file_stats || line_stats )
117
120
. then ( || {
118
121
let num_threads = num_cpus:: get ( ) . saturating_sub ( 1 /*main thread*/ ) . max ( 1 ) ;
119
122
let ( tx, rx) = flume:: unbounded :: < ( u32 , Option < git:: hash:: ObjectId > , git:: hash:: ObjectId ) > ( ) ;
@@ -130,7 +133,7 @@ where
130
133
if let Some ( c) = counter. as_ref ( ) {
131
134
c. fetch_add ( 1 , Ordering :: SeqCst ) ;
132
135
}
133
- let mut stat = Stats :: default ( ) ;
136
+ let mut stat = FileStats :: default ( ) ;
134
137
let from = match parent_commit {
135
138
Some ( id) => {
136
139
match repo. find_object ( id) . ok ( ) . and_then ( |c| c. peel_to_tree ( ) . ok ( ) ) {
@@ -283,16 +286,15 @@ where
283
286
) ) ;
284
287
285
288
let num_unique_authors = results_by_hours. len ( ) ;
286
- let ( total_hours, total_commits, total_stats ) = results_by_hours
289
+ let ( total_hours, total_commits, total_files , total_lines ) = results_by_hours
287
290
. iter ( )
288
- . map ( |e| ( e. hours , e. num_commits , e. stats ) )
289
- . reduce ( |a, b| ( a. 0 + b. 0 , a. 1 + b. 1 , a. 2 . clone ( ) . added ( & b. 2 ) ) )
291
+ . map ( |e| ( e. hours , e. num_commits , e. files , e . lines ) )
292
+ . reduce ( |a, b| ( a. 0 + b. 0 , a. 1 + b. 1 , a. 2 . clone ( ) . added ( & b. 2 ) , a . 3 . clone ( ) . added ( & b . 3 ) ) )
290
293
. expect ( "at least one commit at this point" ) ;
291
294
if show_pii {
292
295
results_by_hours. sort_by ( |a, b| a. hours . partial_cmp ( & b. hours ) . unwrap_or ( std:: cmp:: Ordering :: Equal ) ) ;
293
- let show_stats = !stats. is_empty ( ) ;
294
296
for entry in results_by_hours. iter ( ) {
295
- entry. write_to ( total_hours, show_stats , & mut out) ?;
297
+ entry. write_to ( total_hours, file_stats , line_stats , & mut out) ?;
296
298
writeln ! ( out) ?;
297
299
}
298
300
}
@@ -305,11 +307,18 @@ where
305
307
is_shallow. then( || " (shallow)" ) . unwrap_or_default( ) ,
306
308
num_authors
307
309
) ?;
308
- if !stats . is_empty ( ) {
310
+ if file_stats {
309
311
writeln ! (
310
312
out,
311
313
"total files added/removed/modified: {}/{}/{}" ,
312
- total_stats. added, total_stats. removed, total_stats. modified
314
+ total_files. added, total_files. removed, total_files. modified
315
+ ) ?;
316
+ }
317
+ if line_stats {
318
+ writeln ! (
319
+ out,
320
+ "total lines added/removed: {}/{}" ,
321
+ total_lines. added, total_lines. removed
313
322
) ?;
314
323
}
315
324
if !omit_unify_identities {
@@ -334,7 +343,7 @@ where
334
343
const MINUTES_PER_HOUR : f32 = 60.0 ;
335
344
const HOURS_PER_WORKDAY : f32 = 8.0 ;
336
345
337
- fn estimate_hours ( commits : & [ ( u32 , actor:: SignatureRef < ' static > ) ] , stats : & [ ( u32 , Stats ) ] ) -> WorkByEmail {
346
+ fn estimate_hours ( commits : & [ ( u32 , actor:: SignatureRef < ' static > ) ] , stats : & [ ( u32 , FileStats ) ] ) -> WorkByEmail {
338
347
assert ! ( !commits. is_empty( ) ) ;
339
348
const MAX_COMMIT_DIFFERENCE_IN_MINUTES : f32 = 2.0 * MINUTES_PER_HOUR ;
340
349
const FIRST_COMMIT_ADDITION_IN_MINUTES : f32 = 2.0 * MINUTES_PER_HOUR ;
@@ -361,9 +370,9 @@ fn estimate_hours(commits: &[(u32, actor::SignatureRef<'static>)], stats: &[(u32
361
370
email : author. email ,
362
371
hours : FIRST_COMMIT_ADDITION_IN_MINUTES / 60.0 + hours_for_commits,
363
372
num_commits : commits. len ( ) as u32 ,
364
- stats : ( !stats. is_empty ( ) )
373
+ files : ( !stats. is_empty ( ) )
365
374
. then ( || {
366
- commits. iter ( ) . map ( |t| & t. 0 ) . fold ( Stats :: default ( ) , |mut acc, id| {
375
+ commits. iter ( ) . map ( |t| & t. 0 ) . fold ( FileStats :: default ( ) , |mut acc, id| {
367
376
match stats. binary_search_by ( |t| t. 0 . cmp ( id) ) {
368
377
Ok ( idx) => {
369
378
acc. add ( & stats[ idx] . 1 ) ;
@@ -374,6 +383,7 @@ fn estimate_hours(commits: &[(u32, actor::SignatureRef<'static>)], stats: &[(u32
374
383
} )
375
384
} )
376
385
. unwrap_or_default ( ) ,
386
+ lines : Default :: default ( ) ,
377
387
}
378
388
}
379
389
@@ -410,7 +420,8 @@ struct WorkByPerson {
410
420
email : Vec < & ' static BStr > ,
411
421
hours : f32 ,
412
422
num_commits : u32 ,
413
- stats : Stats ,
423
+ files : FileStats ,
424
+ lines : LineStats ,
414
425
}
415
426
416
427
impl < ' a > WorkByPerson {
@@ -423,7 +434,7 @@ impl<'a> WorkByPerson {
423
434
}
424
435
self . num_commits += other. num_commits ;
425
436
self . hours += other. hours ;
426
- self . stats . add ( & other. stats ) ;
437
+ self . files . add ( & other. files ) ;
427
438
}
428
439
}
429
440
@@ -434,13 +445,20 @@ impl<'a> From<&'a WorkByEmail> for WorkByPerson {
434
445
email : vec ! [ w. email] ,
435
446
hours : w. hours ,
436
447
num_commits : w. num_commits ,
437
- stats : w. stats ,
448
+ files : w. files ,
449
+ lines : w. lines ,
438
450
}
439
451
}
440
452
}
441
453
442
454
impl WorkByPerson {
443
- fn write_to ( & self , total_hours : f32 , show_stats : bool , mut out : impl std:: io:: Write ) -> std:: io:: Result < ( ) > {
455
+ fn write_to (
456
+ & self ,
457
+ total_hours : f32 ,
458
+ show_files : bool ,
459
+ show_lines : bool ,
460
+ mut out : impl std:: io:: Write ,
461
+ ) -> std:: io:: Result < ( ) > {
444
462
writeln ! (
445
463
out,
446
464
"{} <{}>" ,
@@ -455,11 +473,18 @@ impl WorkByPerson {
455
473
self . hours / HOURS_PER_WORKDAY ,
456
474
( self . hours / total_hours) * 100.0
457
475
) ?;
458
- if show_stats {
476
+ if show_files {
459
477
writeln ! (
460
478
out,
461
479
"total files added/removed/modified: {}/{}/{}" ,
462
- self . stats. added, self . stats. removed, self . stats. modified
480
+ self . files. added, self . files. removed, self . files. modified
481
+ ) ?;
482
+ }
483
+ if show_lines {
484
+ writeln ! (
485
+ out,
486
+ "total lines added/removed: {}/{}" ,
487
+ self . lines. added, self . lines. removed
463
488
) ?;
464
489
}
465
490
Ok ( ( ) )
@@ -472,12 +497,13 @@ struct WorkByEmail {
472
497
email : & ' static BStr ,
473
498
hours : f32 ,
474
499
num_commits : u32 ,
475
- stats : Stats ,
500
+ files : FileStats ,
501
+ lines : LineStats ,
476
502
}
477
503
478
- /// Statistics for a particular commit.
504
+ /// File statistics for a particular commit.
479
505
#[ derive( Debug , Default , Copy , Clone ) ]
480
- struct Stats {
506
+ struct FileStats {
481
507
/// amount of added files
482
508
added : usize ,
483
509
/// amount of removed files
@@ -486,15 +512,38 @@ struct Stats {
486
512
modified : usize ,
487
513
}
488
514
489
- impl Stats {
490
- fn add ( & mut self , other : & Stats ) -> & mut Self {
515
+ /// Line statistics for a particular commit.
516
+ #[ derive( Debug , Default , Copy , Clone ) ]
517
+ struct LineStats {
518
+ /// amount of added lines
519
+ added : usize ,
520
+ /// amount of removed lines
521
+ removed : usize ,
522
+ }
523
+
524
+ impl FileStats {
525
+ fn add ( & mut self , other : & FileStats ) -> & mut Self {
491
526
self . added += other. added ;
492
527
self . removed += other. removed ;
493
528
self . modified += other. modified ;
494
529
self
495
530
}
496
531
497
- fn added ( & self , other : & Stats ) -> Self {
532
+ fn added ( & self , other : & FileStats ) -> Self {
533
+ let mut a = * self ;
534
+ a. add ( other) ;
535
+ a
536
+ }
537
+ }
538
+
539
+ impl LineStats {
540
+ fn add ( & mut self , other : & LineStats ) -> & mut Self {
541
+ self . added += other. added ;
542
+ self . removed += other. removed ;
543
+ self
544
+ }
545
+
546
+ fn added ( & self , other : & LineStats ) -> Self {
498
547
let mut a = * self ;
499
548
a. add ( other) ;
500
549
a
0 commit comments