3 # Show projects' pack and/or object counts
4 # Use "show-pack-counts.pl --sorted" to see in pack count order
5 # Use the --objects option to show pack object counts instead of pack counts
10 BEGIN {*VERSION = \'2.0'}
15 eval 'require Pod::Text::Termcap; 1;' and
16 @Pod::Usage::ISA = (qw( Pod::Text::Termcap ));
17 defined($ENV{PERLDOC
}) && $ENV{PERLDOC
} ne "" or
18 $ENV{PERLDOC
} = "-oterm -oman";
20 use lib
"__BASEDIR__";
27 $shbin = $Girocco::Config
::posix_sh_bin
;
28 defined($shbin) && $shbin ne "" or $shbin = "/bin/sh";
32 select((select(STDERR
), $| = 1)[0]);
33 exit(&main
(@ARGV)||0);
35 my ($quiet, $progress);
38 pod2usage
(-exitval
=> 2);
43 pod2usage
(-exitval
=> 2);
47 pod2usage
(-verbose
=> 2, -exitval
=> 0);
51 print basename
($0), " version ", $VERSION, "\n";
56 return defined($_[0]) ?
$_[0] : $_[1];
59 my ($lastpct, $lastts);
62 return unless $progress;
63 my ($prog, $total, $prefix) = @_;
64 $total or $total = 100;
65 defined $prefix or $prefix = "";
67 defined $lastts or $lastts = $now + 1;
70 defined $lastpct or $lastpct = "";
71 my $pct = int($prog * 100 / $total);
72 $pct = 100 if $pct > 100;
73 if ($pct ne $lastpct) {
75 $prefix ne "" and $prefix .= " ";
76 printf STDERR
"\r%s%3d%%", $prefix, $pct;
82 return unless $progress && defined($lastpct);
84 defined $prefix or $prefix = "";
85 $prefix ne "" and $prefix .= " ";
86 printf STDERR
"\r%s100%%, done.\n", $prefix;
89 my ($packs, $packobjs, $loose, $sorton);
93 my ($help, $version, $asc);
95 close(DATA
) if fileno(DATA
);
97 Getopt
::Long
::Configure
('bundling');
98 $_ eq "--sorted" || $_ eq "--sort" and $_ .= "=" foreach @_;
100 'help|h' => sub {do_help
},
101 'version|V' => sub {do_version
},
102 'quiet|q' => sub {$progress = 0},
103 'progress|P' => \
$progress,
104 'objects|packed' => sub {$packobjs = 1},
105 'no-objects|no-packed' => sub {$packobjs = 0},
106 'packs' => sub {$packs = 1},
107 'no-packs' => sub {$packs = 0},
108 'loose' => sub {$loose = 1},
109 'no-loose' => sub {$loose = 0},
110 'full' => sub {$packs = $packobjs = $loose = 1;
111 $sorton = "objects"},
112 'sorted|sort:s' => \
$sorton,
114 $packs = 1 if !defined($packs) && !defval
($packobjs,0) && !defval
($loose,0);
115 $packobjs = 1 if !defined($packobjs) && defined($packs) && !$packs && !defval
($loose,0);
116 $packobjs || $packs || $loose or
117 die_usage_msg
"At least one of --packs, --objects or --loose must be active\n";
118 if (defined($sorton)) {
119 $sorton =~ /^\+/ and $asc = 1;
120 $sorton =~ s/^[+-]//;
121 $sorton eq "" and $sorton = $packs ?
"packs" : "objects";
122 $sorton =~ tr/A-Z/a-z/;
123 if ($sorton eq "packs") {
124 $packs or die_usage_msg
"Sorting on \"packs\" requires the --packs option\n";
125 } elsif ($sorton eq "loose") {
126 $loose or die_usage_msg
"Sorting on \"loose\" requires the --loose option\n";
127 } elsif ($sorton eq "packed") {
128 $packobjs or die_usage_msg
"Sorting on \"packed\" requires the --objects option\n";
129 } elsif ($sorton eq "objects") {
130 $loose || $packobjs or
131 die_usage_msg
"Sorting on \"objects\" requires the --objects and/or --loose option\n";
132 if ($loose && !$packobjs) {
134 } elsif ($packobjs && !$loose) {
138 die_usage_msg
"Unknown sort field: $sorton\n";
146 my $reporoot = $Girocco::Config
::reporoot
;
148 my %projs = map {($_ => 1)} Girocco
::Project
::get_full_list
;
152 exists($projs{$p}) and push(@projlist, $p), next;
153 $p =~ s/\.git$//i && exists($projs{$p}) and push(@projlist, $p), next;
154 $p =~ s
,^\Q
$reporoot\E
/,, && exists($projs{$p}) and push(@projlist, $p), next;
155 warn "Ignoring unknown project: $_\n";
159 @projlist = sort({lc($a) cmp lc($b)} Girocco
::Project
::get_full_list
);
163 my $pmsg = "Inspecting projects:";
164 foreach my $proj (@projlist) {
165 my ($pcks, $pobjs, $lobjs) =
166 inspect_proj
("$reporoot/$proj.git", $packs, $packobjs, $loose);
168 push(@results, [$proj, $pcks, $pobjs, $lobjs]);
169 progress
(scalar(@results), scalar(@projlist), $pmsg);
171 show_one
($proj, $pcks, $pobjs, $lobjs);
175 progress_done
($pmsg);
177 my $desc = $asc ?
1 : -1;
178 $sorton eq "packs" and $sorter = sub {
179 my $x = $$a[1] <=> $$b[1];
181 $x or $x = lc($$a[0]) cmp lc($$b[0]);
184 $sorton eq "packed" and $sorter = sub {
185 my $x = $$a[2] <=> $$b[2];
187 $x or $x = lc($$a[0]) cmp lc($$b[0]);
190 $sorton eq "loose" and $sorter = sub {
191 my $x = $$a[3] <=> $$b[3];
193 $x or $x = lc($$a[0]) cmp lc($$b[0]);
196 $sorton eq "objects" and $sorter = sub {
197 my $x = ($$a[2] + $$a[3]) <=> ($$b[2] + $$b[3]);
199 $x or $x = lc($$a[0]) cmp lc($$b[0]);
202 foreach my $info (sort($sorter @results)) {
210 my ($name, $pcks, $pobjs, $lobjs) = @_;
212 if (defined($sorton)) {
213 $sorton eq "packs" and $line .= $pcks;
214 $sorton eq "packed" and $line .= $pobjs;
215 $sorton eq "loose" and $line .= $lobjs;
216 $sorton eq "objects" and $line .= ($pobjs + $lobjs);
220 } elsif ($packobjs && $loose) {
221 $line .= ($pobjs + $lobjs);
222 } elsif ($packobjs) {
230 $packs and push(@info, "packs: " . $pcks);
231 $packobjs and push(@info, "packed: " . $pobjs);
232 $loose and push(@info, "loose: " . $lobjs);
234 length($name) < 8 and $line .= "\t";
235 length($name) < 16 and $line .= "\t";
236 length($name) < 24 and $line .= "\t";
237 $line .= " \t(" . join(", ", @info) . ")";
244 $lpbin = $Girocco::Config
::basedir
. "/bin/list_packs";
245 @lpcmd = ($lpbin, "--exclude-no-idx");
248 sub count_proj_packs
{
251 my $pd = $projdir . "/objects/pack";
252 -d
$pd or warn("no such project path (anymore) $pd\n"), return undef;
253 open LPCMD
, '-|', @lpcmd, ($objs ?
"--count-objects" : "--count"), $pd or
254 warn("failed to run list_packs for project dir $pd\n"), return undef;
255 my $pcount = <LPCMD
>;
258 $pcount =~ /^\d+$/ or
259 warn("list_packs produced invalid output for project dir $pd\n"), return undef;
263 my ($octet, $octet19);
265 $octet = '[0-9a-f][0-9a-f]';
266 $octet19 = $octet x
19;
269 sub count_proj_loose
{
271 my $od = $projdir . "/objects";
272 -d
$od or warn("no such project path (anymore) $od\n"), return undef;
273 open FINDCMD
, '-|', $shbin, '-c', "cd " . quotemeta($od) . " && " .
274 "find -L $octet -maxdepth 1 -name '$octet19*' -print 2>/dev/null | wc -l" or
275 warn("failed to run find for project dir $od\n"), return undef;
276 my $ocount = <FINDCMD
>;
277 $ocount =~ s/\s+//gs;
279 $ocount =~ /^\d+$/ or
280 warn("find + wc produced invalid output for project dir $od\n"), return undef;
286 my ($pcks, $pobjs, $lobjs);
287 $pcks = count_proj_packs
($path) || 0 if $packs;
288 $pobjs = count_proj_packs
($path, 1) || 0 if $packobjs;
289 $lobjs = count_proj_loose
($path) || 0 if $loose;
290 return ($pcks, $pobjs, $lobjs);
297 show-pack-counts.pl - show projects' pack and/or object counts
301 show-pack-counts.pl [<options>] [<projname>...]
304 -h | --help detailed instructions
305 -V | --version show version
306 -q | --quiet suppress progress messages
307 -P | --progress show progress messages (default)
308 --sorted[=[+]<field>] sort output on <field>
309 --objects count objects in packs instead of packs
310 --no-objects omit objects in packs count (default)
311 --packs always include pack count
312 --no-packs always omit pack count
313 --loose count loose objects (implies --no-packs)
314 --no-loose omit loose objects count (default)
315 --full shortcut meta option that sets
316 --packs --objects --loose --sorted=objects
318 <field> can be loose, packed, packs or objects and may be preceded by an
319 optional + to sort in ascending rather than descending order.
320 If no sorted option is given output will be shown unsorted as it's gathered.
321 The default sort field depends on the options being packs if pack counts are
322 included and objects otherwise. Using a field name of + changes the
323 default sorting order to ascending without changing the default sort field.
325 <projname>... if given, only inspect these projects
331 =item B<-h>, B<--help>
333 Print the full description of show-pack-counts.pl's options.
335 =item B<-V>, B<--version>
337 Print the version of show-pack-counts.pl.
339 =item B<-q>, B<--quiet>
341 Suppress progress messages. There are never any progress messages unless
342 sorted output is active.
344 =item B<-P>, B<--progress>
346 Show progress information to STDERR while collecting sorted output. This is
347 the default unless STDERR is not a TTY.
349 =item B<--sorted[=>I<<fieldE<gt>>B<]>
351 Collect all the output first and then show it in sorted order.
353 Possible I<<fieldE<gt>> names are:
359 Sort by number of loose objects (requires B<--loose> option too)
363 Sort by total number of objects in packs (requires B<--objects> option too)
367 Sort by total number of packs (requires possibly implied B<--packs> option)
371 Sort by total objects counted (requires B<--objects> and/or B<--loose>)
375 Sort by total number of packs (requires possibly implied B<--packs> option)
379 Keep the default sort field but sort in ascending order rather than descending
380 order. When prefixed to one of the other sort field names, sort on that field
381 but in ascending rather than descending order.
385 If the B<--sorted=[+]<field>> option is given more than once then later options
386 override earlier ones (there is no multi-field sorting). This can be used to
387 change the sorting order used with B<--full>.
389 If B<--sorted> is used (or B<--sorted=+>) the sort field is chosen based on
390 what information is being collected. If packs are being counted the sort will
391 be on the number of packs (B<--sorted=packs>).
393 If packs are not being counted the sort will be on the total number of objects
394 in each project being either objects in packs, loose objects or the sum of
395 both objects in packs and loose objects depending on what options have been
396 given (B<--sorted=objects>).
400 Instead of counting packs, count objects in them. Implies B<--no-packs>
401 unless an explicit B<--packs> is given too.
403 =item B<--no-objects>
405 Omit the count of objects in packs. Included for completeness. Reactivates
406 implicit B<--packs> if given.
410 Count the number of packs present. This is implied by default but may be
411 given explicitly to always include the packs count.
415 Omit the count of packs. At least one other counting option must be specified
416 with this (either B<--objects> or B<--loose>).
424 Do not count loose objects.
428 A shortcut meta option that behaves the same as replacing it with B<--packs>
429 B<--objects> B<--loose> B<--sorted=objects> at that point.
431 =item I<<projnameE<gt>>
433 If no project names are specified then I<all> projects are processed.
435 If one or more project names are specified then only those projects are
436 processed. Specifying non-existent projects produces a warning for them,
437 but the rest of the projects specified will still be processed.
439 Each B<projname> may be either a full absolute path starting with
440 $Girocco::Config::reporoot or just the project name part with or without
443 Any explicitly specified projects that do exist but are not known to
444 Girocco will be skipped (with a warning).
450 Count the number of packs, objects contained in packs and/or loose objects
451 and show the results.
453 Output can be sorted and the projects inspected can be limited.