From d971365bdbe30f376a0907ada3eaef7558261271 Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Mon, 1 Mar 2021 16:58:16 -0700 Subject: [PATCH] projtool.pl: add prune command Provide a prune command that can remove any project names from the group file that do not correspond to an existing project directory (aka GIT_DIR). Require explicit --dry-run or --force to operate. Signed-off-by: Kyle J. McKay --- toolbox/projtool.pl | 75 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/toolbox/projtool.pl b/toolbox/projtool.pl index 9eba59d..73b9a96 100755 --- a/toolbox/projtool.pl +++ b/toolbox/projtool.pl @@ -90,6 +90,15 @@ Usage: %s [...] do not move to _recyclebin with --really-delete (just rm -rf) remove projects with forks (by keeping forks) using --keep-forks + prune [--quiet] (--force | --dry-run) [...] + check to see if any projects (default is all projects) are + missing the associated project directory on disk. + Requires either --force or --dry-run option to operate. + With --dry-run only show what would be done. + With --prune actually remove any extraneous project(s). + With --dry-run exit code is non-zero if any action needed. + With --quiet, suppress output message, if any. + show show project @@ -1128,6 +1137,51 @@ sub cmd_remove { return 0; } +sub cmd_prune { + my ($force, $dryrun); + parse_options(force => \$force, "dry-run" => \$dryrun, "quiet" => \$quiet); + ($force && !$dryrun) || (!$force && $dryrun) or die_usage; + my @projs = @ARGV; + my @allprojs = sort({lc($a) cmp lc($b)} Girocco::Project::get_full_list()); + my %allprojs = map({$_ => 1} @allprojs); + my %seen = (); + @projs or @projs = @allprojs; + my $bd = $Girocco::Config::reporoot.'/'; + my @remove = (); + foreach (@projs) { + !$seen{$_} && $allprojs{$_} or next; + $seen{$_} = 1; + my $pd = $bd . $_ . '.git'; + if (! -e $pd) { + warn "$_: no such directory: $pd\n" unless $quiet; + push(@remove, $_); + } elsif (! -d _) { + warn "$_: exists but not directory: $pd\n" unless $quiet; + push(@remove, $_); + } + } + warn "\n" if @remove && !$quiet; + if ($dryrun) { + return 0 unless @remove; + my $msg = "Would remove ".scalar(@remove). " project"; + @remove == 1 or $msg .= "s"; + $msg .= ":\n"; + $msg .= join("", map("\t$_\n", @remove)); + print $msg unless $quiet; + return 1; + } + my $msg = "Removed ".scalar(@remove). " project"; + @remove == 1 or $msg .= "s"; + $msg .= ":\n"; + $msg .= join("", map("\t$_\n", @remove)); + my %remove = map({$_ => 1} @remove); + filedb_atomic_edit(jailed_file('/etc/group'), sub { + !exists($remove{(split /:/)[0]}) and return $_; + }); + print $msg unless $quiet; + return 0; +} + sub cmd_show { use Data::Dumper; @ARGV == 1 or die_usage; @@ -1961,6 +2015,7 @@ BEGIN { remove => \&cmd_remove, trash => \&cmd_remove, delete => \&cmd_remove, + prune => \&cmd_prune, show => \&cmd_show, listheads => \&cmd_listheads, listtags => \&cmd_listtags, @@ -1995,13 +2050,14 @@ BEGIN { ); } our %nopager; -BEGIN { - %nopager = map({$_ => 1} qw( - create - chpass - checkpw - )); -} +BEGIN { %nopager = ( + # 1 => pager never allowed + # -1 => pager defaults to off instead of on + create => 1, + chpass => 1, + checkpw => 1, + prune => -1, +)} sub dohelp { my $cmd = shift; @@ -2043,7 +2099,8 @@ sub main { exists($commands{$command}) or die "Unknown command \"$command\" -- try \"help\"\n"; dohelp($command) if @ARGV && ($ARGV[0] =~ /^(?:-h|-?-help)$/i || $ARGV[0] =~ /^help$/i && !Girocco::Project::does_exist("help",1)); - $nopager{$command} and $usepager = 0; - setup_pager_stdout($usepager); + $nopager{$command} && $nopager{$command} > 0 and $usepager = 0; + my $pgdfltoff = $nopager{$command} && $nopager{$command} < 0 ? 1 : 0; + setup_pager_stdout($usepager, $pgdfltoff); &{$commands{$command}}(@ARGV); } -- 2.11.4.GIT