22
33#include "builtin.h"
44#include "environment.h"
5+ #include "hex.h"
6+ #include "odb.h"
57#include "parse-options.h"
68#include "path-walk.h"
79#include "progress.h"
@@ -202,13 +204,19 @@ struct ref_stats {
202204 size_t others ;
203205};
204206
205- struct object_stats {
207+ struct object_values {
206208 size_t tags ;
207209 size_t commits ;
208210 size_t trees ;
209211 size_t blobs ;
210212};
211213
214+ struct object_stats {
215+ struct object_values type_counts ;
216+ struct object_values inflated_sizes ;
217+ struct object_values disk_sizes ;
218+ };
219+
212220struct repo_structure {
213221 struct ref_stats refs ;
214222 struct object_stats objects ;
@@ -219,13 +227,15 @@ struct stats_table {
219227
220228 int name_col_width ;
221229 int value_col_width ;
230+ int unit_col_width ;
222231};
223232
224233/*
225234 * Holds column data that gets stored for each row.
226235 */
227236struct stats_table_entry {
228237 char * value ;
238+ const char * unit ;
229239};
230240
231241static void stats_table_vaddf (struct stats_table * table ,
@@ -246,11 +256,18 @@ static void stats_table_vaddf(struct stats_table *table,
246256
247257 if (name_width > table -> name_col_width )
248258 table -> name_col_width = name_width ;
249- if (entry ) {
259+ if (!entry )
260+ return ;
261+ if (entry -> value ) {
250262 int value_width = utf8_strwidth (entry -> value );
251263 if (value_width > table -> value_col_width )
252264 table -> value_col_width = value_width ;
253265 }
266+ if (entry -> unit ) {
267+ int unit_width = utf8_strwidth (entry -> unit );
268+ if (unit_width > table -> unit_col_width )
269+ table -> unit_col_width = unit_width ;
270+ }
254271}
255272
256273static void stats_table_addf (struct stats_table * table , const char * format , ...)
@@ -269,7 +286,21 @@ static void stats_table_count_addf(struct stats_table *table, size_t value,
269286 va_list ap ;
270287
271288 CALLOC_ARRAY (entry , 1 );
272- entry -> value = xstrfmt ("%" PRIuMAX , (uintmax_t )value );
289+ humanise_count (value , & entry -> value , & entry -> unit );
290+
291+ va_start (ap , format );
292+ stats_table_vaddf (table , entry , format , ap );
293+ va_end (ap );
294+ }
295+
296+ static void stats_table_size_addf (struct stats_table * table , size_t value ,
297+ const char * format , ...)
298+ {
299+ struct stats_table_entry * entry ;
300+ va_list ap ;
301+
302+ CALLOC_ARRAY (entry , 1 );
303+ humanise_bytes (value , & entry -> value , & entry -> unit , HUMANISE_COMPACT );
273304
274305 va_start (ap , format );
275306 stats_table_vaddf (table , entry , format , ap );
@@ -281,17 +312,19 @@ static inline size_t get_total_reference_count(struct ref_stats *stats)
281312 return stats -> branches + stats -> remotes + stats -> tags + stats -> others ;
282313}
283314
284- static inline size_t get_total_object_count (struct object_stats * stats )
315+ static inline size_t get_total_object_values (struct object_values * values )
285316{
286- return stats -> tags + stats -> commits + stats -> trees + stats -> blobs ;
317+ return values -> tags + values -> commits + values -> trees + values -> blobs ;
287318}
288319
289320static void stats_table_setup_structure (struct stats_table * table ,
290321 struct repo_structure * stats )
291322{
292323 struct object_stats * objects = & stats -> objects ;
293324 struct ref_stats * refs = & stats -> refs ;
294- size_t object_total ;
325+ size_t inflated_object_total ;
326+ size_t object_count_total ;
327+ size_t disk_object_total ;
295328 size_t ref_total ;
296329
297330 ref_total = get_total_reference_count (refs );
@@ -302,59 +335,96 @@ static void stats_table_setup_structure(struct stats_table *table,
302335 stats_table_count_addf (table , refs -> remotes , " * %s" , _ ("Remotes" ));
303336 stats_table_count_addf (table , refs -> others , " * %s" , _ ("Others" ));
304337
305- object_total = get_total_object_count ( objects );
338+ object_count_total = get_total_object_values ( & objects -> type_counts );
306339 stats_table_addf (table , "" );
307340 stats_table_addf (table , "* %s" , _ ("Reachable objects" ));
308- stats_table_count_addf (table , object_total , " * %s" , _ ("Count" ));
309- stats_table_count_addf (table , objects -> commits , " * %s" , _ ("Commits" ));
310- stats_table_count_addf (table , objects -> trees , " * %s" , _ ("Trees" ));
311- stats_table_count_addf (table , objects -> blobs , " * %s" , _ ("Blobs" ));
312- stats_table_count_addf (table , objects -> tags , " * %s" , _ ("Tags" ));
341+ stats_table_count_addf (table , object_count_total , " * %s" , _ ("Count" ));
342+ stats_table_count_addf (table , objects -> type_counts .commits ,
343+ " * %s" , _ ("Commits" ));
344+ stats_table_count_addf (table , objects -> type_counts .trees ,
345+ " * %s" , _ ("Trees" ));
346+ stats_table_count_addf (table , objects -> type_counts .blobs ,
347+ " * %s" , _ ("Blobs" ));
348+ stats_table_count_addf (table , objects -> type_counts .tags ,
349+ " * %s" , _ ("Tags" ));
350+
351+ inflated_object_total = get_total_object_values (& objects -> inflated_sizes );
352+ stats_table_size_addf (table , inflated_object_total ,
353+ " * %s" , _ ("Inflated size" ));
354+ stats_table_size_addf (table , objects -> inflated_sizes .commits ,
355+ " * %s" , _ ("Commits" ));
356+ stats_table_size_addf (table , objects -> inflated_sizes .trees ,
357+ " * %s" , _ ("Trees" ));
358+ stats_table_size_addf (table , objects -> inflated_sizes .blobs ,
359+ " * %s" , _ ("Blobs" ));
360+ stats_table_size_addf (table , objects -> inflated_sizes .tags ,
361+ " * %s" , _ ("Tags" ));
362+
363+ disk_object_total = get_total_object_values (& objects -> disk_sizes );
364+ stats_table_size_addf (table , disk_object_total ,
365+ " * %s" , _ ("Disk size" ));
366+ stats_table_size_addf (table , objects -> disk_sizes .commits ,
367+ " * %s" , _ ("Commits" ));
368+ stats_table_size_addf (table , objects -> disk_sizes .trees ,
369+ " * %s" , _ ("Trees" ));
370+ stats_table_size_addf (table , objects -> disk_sizes .blobs ,
371+ " * %s" , _ ("Blobs" ));
372+ stats_table_size_addf (table , objects -> disk_sizes .tags ,
373+ " * %s" , _ ("Tags" ));
313374}
314375
315376static void stats_table_print_structure (const struct stats_table * table )
316377{
317378 const char * name_col_title = _ ("Repository structure" );
318379 const char * value_col_title = _ ("Value" );
319- int name_col_width = utf8_strwidth (name_col_title );
320- int value_col_width = utf8_strwidth (value_col_title );
380+ int title_name_width = utf8_strwidth (name_col_title );
381+ int title_value_width = utf8_strwidth (value_col_title );
382+ int name_col_width = table -> name_col_width ;
383+ int value_col_width = table -> value_col_width ;
384+ int unit_col_width = table -> unit_col_width ;
321385 struct string_list_item * item ;
322386 struct strbuf buf = STRBUF_INIT ;
323387
324- if (table -> name_col_width > name_col_width )
325- name_col_width = table -> name_col_width ;
326- if (table -> value_col_width > value_col_width )
327- value_col_width = table -> value_col_width ;
388+ if (title_name_width > name_col_width )
389+ name_col_width = title_name_width ;
390+ if (title_value_width > value_col_width + unit_col_width + 1 )
391+ value_col_width = title_value_width - unit_col_width ;
328392
329393 strbuf_addstr (& buf , "| " );
330394 strbuf_utf8_align (& buf , ALIGN_LEFT , name_col_width , name_col_title );
331395 strbuf_addstr (& buf , " | " );
332- strbuf_utf8_align (& buf , ALIGN_LEFT , value_col_width , value_col_title );
396+ strbuf_utf8_align (& buf , ALIGN_LEFT ,
397+ value_col_width + unit_col_width + 1 , value_col_title );
333398 strbuf_addstr (& buf , " |" );
334399 printf ("%s\n" , buf .buf );
335400
336401 printf ("| " );
337402 for (int i = 0 ; i < name_col_width ; i ++ )
338403 putchar ('-' );
339404 printf (" | " );
340- for (int i = 0 ; i < value_col_width ; i ++ )
405+ for (int i = 0 ; i < value_col_width + unit_col_width + 1 ; i ++ )
341406 putchar ('-' );
342407 printf (" |\n" );
343408
344409 for_each_string_list_item (item , & table -> rows ) {
345410 struct stats_table_entry * entry = item -> util ;
346411 const char * value = "" ;
412+ const char * unit = "" ;
347413
348414 if (entry ) {
349415 struct stats_table_entry * entry = item -> util ;
350416 value = entry -> value ;
417+ if (entry -> unit )
418+ unit = entry -> unit ;
351419 }
352420
353421 strbuf_reset (& buf );
354422 strbuf_addstr (& buf , "| " );
355423 strbuf_utf8_align (& buf , ALIGN_LEFT , name_col_width , item -> string );
356424 strbuf_addstr (& buf , " | " );
357425 strbuf_utf8_align (& buf , ALIGN_RIGHT , value_col_width , value );
426+ strbuf_addch (& buf , ' ' );
427+ strbuf_utf8_align (& buf , ALIGN_LEFT , unit_col_width , unit );
358428 strbuf_addstr (& buf , " |" );
359429 printf ("%s\n" , buf .buf );
360430 }
@@ -389,13 +459,31 @@ static void structure_keyvalue_print(struct repo_structure *stats,
389459 (uintmax_t )stats -> refs .others , value_delim );
390460
391461 printf ("objects.commits.count%c%" PRIuMAX "%c" , key_delim ,
392- (uintmax_t )stats -> objects .commits , value_delim );
462+ (uintmax_t )stats -> objects .type_counts . commits , value_delim );
393463 printf ("objects.trees.count%c%" PRIuMAX "%c" , key_delim ,
394- (uintmax_t )stats -> objects .trees , value_delim );
464+ (uintmax_t )stats -> objects .type_counts . trees , value_delim );
395465 printf ("objects.blobs.count%c%" PRIuMAX "%c" , key_delim ,
396- (uintmax_t )stats -> objects .blobs , value_delim );
466+ (uintmax_t )stats -> objects .type_counts . blobs , value_delim );
397467 printf ("objects.tags.count%c%" PRIuMAX "%c" , key_delim ,
398- (uintmax_t )stats -> objects .tags , value_delim );
468+ (uintmax_t )stats -> objects .type_counts .tags , value_delim );
469+
470+ printf ("objects.commits.inflated_size%c%" PRIuMAX "%c" , key_delim ,
471+ (uintmax_t )stats -> objects .inflated_sizes .commits , value_delim );
472+ printf ("objects.trees.inflated_size%c%" PRIuMAX "%c" , key_delim ,
473+ (uintmax_t )stats -> objects .inflated_sizes .trees , value_delim );
474+ printf ("objects.blobs.inflated_size%c%" PRIuMAX "%c" , key_delim ,
475+ (uintmax_t )stats -> objects .inflated_sizes .blobs , value_delim );
476+ printf ("objects.tags.inflated_size%c%" PRIuMAX "%c" , key_delim ,
477+ (uintmax_t )stats -> objects .inflated_sizes .tags , value_delim );
478+
479+ printf ("objects.commits.disk_size%c%" PRIuMAX "%c" , key_delim ,
480+ (uintmax_t )stats -> objects .disk_sizes .commits , value_delim );
481+ printf ("objects.trees.disk_size%c%" PRIuMAX "%c" , key_delim ,
482+ (uintmax_t )stats -> objects .disk_sizes .trees , value_delim );
483+ printf ("objects.blobs.disk_size%c%" PRIuMAX "%c" , key_delim ,
484+ (uintmax_t )stats -> objects .disk_sizes .blobs , value_delim );
485+ printf ("objects.tags.disk_size%c%" PRIuMAX "%c" , key_delim ,
486+ (uintmax_t )stats -> objects .disk_sizes .tags , value_delim );
399487
400488 fflush (stdout );
401489}
@@ -460,6 +548,7 @@ static void structure_count_references(struct ref_stats *stats,
460548}
461549
462550struct count_objects_data {
551+ struct object_database * odb ;
463552 struct object_stats * stats ;
464553 struct progress * progress ;
465554};
@@ -469,26 +558,53 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids,
469558{
470559 struct count_objects_data * data = cb_data ;
471560 struct object_stats * stats = data -> stats ;
561+ size_t inflated_total = 0 ;
562+ size_t disk_total = 0 ;
472563 size_t object_count ;
473564
565+ for (size_t i = 0 ; i < oids -> nr ; i ++ ) {
566+ struct object_info oi = OBJECT_INFO_INIT ;
567+ unsigned long inflated ;
568+ off_t disk ;
569+
570+ oi .sizep = & inflated ;
571+ oi .disk_sizep = & disk ;
572+
573+ if (odb_read_object_info_extended (data -> odb , & oids -> oid [i ], & oi ,
574+ OBJECT_INFO_SKIP_FETCH_OBJECT |
575+ OBJECT_INFO_QUICK ) < 0 )
576+ continue ;
577+
578+ inflated_total += inflated ;
579+ disk_total += disk ;
580+ }
581+
474582 switch (type ) {
475583 case OBJ_TAG :
476- stats -> tags += oids -> nr ;
584+ stats -> type_counts .tags += oids -> nr ;
585+ stats -> inflated_sizes .tags += inflated_total ;
586+ stats -> disk_sizes .tags += disk_total ;
477587 break ;
478588 case OBJ_COMMIT :
479- stats -> commits += oids -> nr ;
589+ stats -> type_counts .commits += oids -> nr ;
590+ stats -> inflated_sizes .commits += inflated_total ;
591+ stats -> disk_sizes .commits += disk_total ;
480592 break ;
481593 case OBJ_TREE :
482- stats -> trees += oids -> nr ;
594+ stats -> type_counts .trees += oids -> nr ;
595+ stats -> inflated_sizes .trees += inflated_total ;
596+ stats -> disk_sizes .trees += disk_total ;
483597 break ;
484598 case OBJ_BLOB :
485- stats -> blobs += oids -> nr ;
599+ stats -> type_counts .blobs += oids -> nr ;
600+ stats -> inflated_sizes .blobs += inflated_total ;
601+ stats -> disk_sizes .blobs += disk_total ;
486602 break ;
487603 default :
488604 BUG ("invalid object type" );
489605 }
490606
491- object_count = get_total_object_count ( stats );
607+ object_count = get_total_object_values ( & stats -> type_counts );
492608 display_progress (data -> progress , object_count );
493609
494610 return 0 ;
@@ -500,6 +616,7 @@ static void structure_count_objects(struct object_stats *stats,
500616{
501617 struct path_walk_info info = PATH_WALK_INFO_INIT ;
502618 struct count_objects_data data = {
619+ .odb = repo -> objects ,
503620 .stats = stats ,
504621 };
505622
0 commit comments