From 73d98a33565c1a71e97a671b9d09487c368d5d79 Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Wed, 25 Aug 2021 17:19:17 -0700 Subject: [PATCH] projtool.pl: add new listalltags subcommand There is a preexisting toolbox/show-tags.pl utility. While it definitely works for a list of all tags and their counts, that's all it can do -- it cannot show which projects the tags belong to. Add a new listalltags subcommand to projtool.pl that brings some additional flexibility. It can list the tags only without their counts as well as include the projects that contain them. In addition, it can filter tag names by a Perl regular expression. As with the show-tags.pl utility, the new listalltags subcommand makes use of the gitweb.index.cache file in order to provide the results very quickly. In addition, there is a --cache-info option that can show the current state of the gitweb.index.cache file including how out-of-date it might be. Signed-off-by: Kyle J. McKay --- toolbox/projtool.pl | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 2 deletions(-) diff --git a/toolbox/projtool.pl b/toolbox/projtool.pl index d2cfbf1..ca90696 100755 --- a/toolbox/projtool.pl +++ b/toolbox/projtool.pl @@ -10,7 +10,7 @@ use strict; use warnings; use vars qw($VERSION); -BEGIN {*VERSION = \'1.0.9'} +BEGIN {*VERSION = \'1.10.0'} use File::Basename; use Digest::MD5 qw(md5_hex); use IO::Socket; @@ -148,11 +148,21 @@ Usage: %s [...] listheads list all available heads for and indicate current head + listalltags [--projects] [--counts] [--filter=] [...] + list all ctags on all projects or just the projects specified + using the gitweb project cache file. + with --cache-info (no projects allowed) show cache up-to-dateness + with --projects include indented list of projects under each ctag + with --counts include count after ctag and before project name + with --filter only include ctags matching Perl + with --ignore-case/-i pattern and ctags ignore case + See also show-tags.pl and clean-tags.pl toolbox utilities. + listtags [--verbose] list all ctags on project with --verbose include tag counts - deltags [-i] + deltags [--ignore-case/-i] remove any ctags on project present in is space or comma separated list of tags to remove with -i match against without regard to letter case @@ -1460,6 +1470,133 @@ sub cmd_listheads { return 0; } +sub is_cache_valid { + local $_ = $_[0]; + defined($_) or return 0; + ref($_) eq "ARRAY" or return 0; + @$_ == 2 or return 0; + defined($$_[0]) or return 0; + defined($$_[1]) or return 0; + !ref($$_[0]) or return 0; + $$_[0] =~ /^Gitweb Cache Format 3.*$/ or return 0; + ref($$_[1]) eq "ARRAY" or return 0; + $_ = $$_[1]; + @$_ == 2 or return 0; + defined($$_[0]) or return 0; + defined($$_[1]) or return 0; + ref($$_[0]) eq "ARRAY" or return 0; + ref($$_[1]) eq "HASH" or return 0; + my $cntprjs = () = grep({ref($_) eq "HASH"} @{$$_[0]}); + $cntprjs == @{$$_[0]} or return 0; + return 1; +} + +sub cmd_listalltags { + use Time::Local; # already use'd by Util.pm, this just brings in defs + my ($info, $prjnms, $cnts, $ic, $rregex) = (0, 0, 0, undef); + parse_options("cache-info" => \$info, "info" => \$info, + "projects" => \$prjnms, "counts" => \$cnts, + "ignore-case" => \$ic, "i" => \$ic, + ":filter" => \$rregex); + $info && ($prjnms || $cnts || defined($rregex) || @ARGV > 0) + and die_usage; + require Storable; + my $gwic = $Girocco::Config::projlist_cache_dir . "/gitweb.index.cache"; + my $cache; + if ($info) { + print "# Update cache with $Girocco::Config::basedir/jobs/gitwebcache.sh\n"; + print "Location: $gwic\n"; + if (-e $gwic && -f _ && -s _) { + my ($sz, $mt) = (stat $gwic)[7,9]; + defined($mt) && $mt ne "" && defined($sz) && $sz > 0 or do { + print "Status: unable to stat cache file\n"; + return 0; + }; + my ($sec,$min,$hour,$mday,$mon,$year) = localtime($mt); + $year += 1900; + my $gmtoff = timegm($sec,$min,$hour,$mday,$mon,$year) - $mt; + my $z = ($gmtoff >= 0 ? "+" : "-") . + sprintf("%02d%02d", int(abs($gmtoff)/3600), + int((abs($gmtoff)%3600)/60)); + my $ago = ""; + my $old = time() - $mt; + $old >= 0 and $ago = " (" . human_duration($old) . " ago)"; + printf "Modified: %04d-%02d-%02d %02d:%02d:%02d %s%s\n", + $year, $mon+1, $mday, $hour, $min, $sec, $z, $ago; + printf "Length: %d byte%s\n", $sz, ($sz==1?"":"s"); + my $loads = 0; + eval { $cache = Storable::retrieve($gwic); 1; } and $loads = 1; + print "Loadable: ", ($loads ? "yes" : "no"), "\n"; + my $valid = is_cache_valid($cache); + print "Format: ", ($valid ? $$cache[0] : "invalid"), "\n"; + if ($valid) { + my $idx = ${$$cache[1]}[1]; + print "Projects: ", scalar(keys(%$idx)), "\n"; + } + } else { + print "Status: does not exist, is not a readable file or is 0 bytes\n"; + } + return 0; + } + my $regex = undef; + if (defined($rregex)) { + eval { $regex = ($ic ? qr($rregex)i : qr($rregex)); 1; } or + die "bad regex \"$rregex\"\n".$@; + } + eval { $cache = Storable::retrieve($gwic); 1; } && is_cache_valid($cache) or + die "Could not load cache file (try listalltags --cache-info)\n"; + my $idx = ${$$cache[1]}[1]; + my %seen = (); + my %limit = (); + foreach (@ARGV) { + s/\.git$//i; + $_ ne "" or next; + $seen{$_.".git"} and next; + $seen{$_.".git"} = 1; + if (exists($$idx{$_.".git"})) { + $limit{$_.".git"} = 1; + } else { + warn "project not found in cache: $_\n"; + } + } + @ARGV && !keys(%limit) and return 0; # nothing to do + my @projlist = @ARGV ? keys(%limit) : keys(%$idx); + my %gather = (); + foreach (@projlist) { + my $p = $$idx{$_}; + s/\.git$//; + while (my ($k,$v) = each(%{$p->{ctags}})) { + !defined($regex) || $k =~ /$regex/ or next; + $ic and $k = lc($k); + $v =~ /^\d+$/ && $v or $v = 1; + exists($gather{$k}) or + $gather{$k} = [0, {}]; + $gather{$k}->[0] += $v; + $gather{$k}->[1]->{$_} += $v; + } + } + my @taglist = sort({lc($a) cmp lc($b) || $a cmp $b} keys(%gather)); + foreach (@taglist) { + if ($cnts) { + print $_, "\t", $gather{$_}->[0], "\n"; + } else { + print "$_\n"; + } + if ($prjnms) { + foreach my $p (sort({lc($a) cmp lc($b) || $a cmp $b} + keys(%{$gather{$_}->[1]}))) { + if ($cnts) { + printf " %5d %s\n", + $gather{$_}->[1]->{$p}, $p; + } else { + print " $p\n"; + } + } + } + } + return 0; +} + sub cmd_listtags { my $vcnt = 0; parse_options("verbose" => \$vcnt, "v" => \$vcnt); @@ -2290,6 +2427,7 @@ BEGIN { worktree => \&cmd_worktree, worktrees => \&cmd_worktree, urls => \&cmd_urls, + listalltags => \&cmd_listalltags, listheads => \&cmd_listheads, listtags => \&cmd_listtags, listctags => \&cmd_listtags, -- 2.11.4.GIT