From e57f97a3c545e4171a9e94a2983159b85cb45dae Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Wed, 18 Aug 2021 10:13:02 -0700 Subject: [PATCH] projtool.pl: various minor improvements Update/correct some of the help text. Grok "worktrees" as well as "worktree". For nondestructive commands that perform a function with just a argument, attempt to use "." if no is given. Signed-off-by: Kyle J. McKay --- toolbox/projtool.pl | 148 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 53 deletions(-) diff --git a/toolbox/projtool.pl b/toolbox/projtool.pl index ffa214e..ba2d37c 100755 --- a/toolbox/projtool.pl +++ b/toolbox/projtool.pl @@ -46,6 +46,8 @@ Usage: %s [...] Since a matching project name takes precedence over a path, to force interpretation as a path, start the path with "/" or "./" or "../". Giving "." will find the project matching the current working directory. + Non-destructive commands that take only a name will attempt to + use "." as the project name if it has been omitted. help [] show full help or just for if given @@ -121,7 +123,7 @@ Usage: %s [...] an error (unless --quiet is used). Exit status will be 0 if project found, non-zero otherwise. - worktree [--force] + worktree[s] [--force] [] run 'git --git-dir= worktree ' except that if consists of the subcommand "add" and a single non-option argument and the @@ -131,6 +133,8 @@ Usage: %s [...] command to make the newly created worktree checkout the HEAD branch of the project (special logic makes that work even for an unborn HEAD). + With --force allow running on a mirror project + With no use "list" urls [--push] show available fetch/push URLs for @@ -199,7 +203,7 @@ Usage: %s [...] is markdown|plain|html (default is no change) is automatic|suppressed|-|[@]filename with "set" and/or is required - without "set" and only 2 args, just show current readme setting + without "set" and only 1 arg, just show current readme setting [set]head [--force] set project HEAD symbolic ref to @@ -315,6 +319,25 @@ sub get_ctag_counts { @ctags; } +sub reftype { + use Scalar::Util (); + return ref($_[0]) ? Scalar::Util::reftype($_[0]) : '' +}; + +sub get_project_harder_gently { + defined($_[0]) && return get_project_harder(@_); + my $proj = eval { get_project_harder(".") }; + reftype($proj) eq 'HASH' or $proj = undef; + return $proj; +} + +sub get_clean_project_gently { + defined($_[0]) && return get_clean_project(@_); + my $proj = eval { get_clean_project(".") }; + reftype($proj) eq 'HASH' or $proj = undef; + return $proj; +} + sub get_clean_project { my $project = get_project_harder(@_); delete $project->{loaded}; @@ -1228,8 +1251,9 @@ sub cmd_prune { sub cmd_show { use Data::Dumper; - @ARGV == 1 or die_usage; - my $project = get_clean_project($ARGV[0]); + @ARGV <= 1 or die_usage; + my $project = get_clean_project_gently($ARGV[0]); + defined($project) or die_usage; my %info = %$project; my $d = Data::Dumper->new([\%info], ['*'.$project->{name}]); $d->Sortkeys(sub {[sort({lc($a) cmp lc($b)} keys %{$_[0]})]}); @@ -1238,19 +1262,19 @@ sub cmd_show { } sub cmd_verify { - use Scalar::Util (); my $dirfp = 0; - my $rt = sub { return ref($_[0]) ? Scalar::Util::reftype($_[0]) : '' }; parse_options("quiet" => \$quiet, "dir" => \$dirfp, "directory" => \$dirfp, "git-dir" =>\$dirfp); - @ARGV == 1 or die_usage; + @ARGV <= 1 or die_usage; my $project = undef; my $pname = undef; eval { - $project = get_project_harder($ARGV[0]); + $project = get_project_harder(@ARGV >= 1 ? $ARGV[0] : "."); }; - $pname = $project->{name} if &$rt($project) eq 'HASH'; + @ARGV > 0 || reftype($project) eq 'HASH' or die_usage; + my $parg = @ARGV ? $ARGV[0] : $$project{name}; + $pname = $project->{name} if reftype($project) eq 'HASH'; defined($pname) && $pname ne "" or $project = undef; - !$@ && &$rt($project) ne 'HASH' and $@ = "No such project: \"$ARGV[0]\"\n"; + !$@ && reftype($project) ne 'HASH' and $@ = "No such project: \"$parg\"\n"; warn $@ if $@ && !$quiet; exit 1 if $@; $dirfp && defined($project->{path}) && $project->{path} ne "" and @@ -1285,15 +1309,16 @@ sub cmd_worktree { eval '$Girocco::Config::var_have_git_250' or die "worktree requires Git 2.5.0 or later\n"; my $force; parse_options("force" => \$force, quiet => \$quiet, q =>\$quiet); - @ARGV >= 2 or die_usage; - my $project = get_project_harder($ARGV[0]); + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; + shift @ARGV if @ARGV; + @ARGV or push(@ARGV, "list"); my $gd = $project->{path}; defined($gd) && -d $gd or die "Project \"$$project{name}\" does not actually exist\n"; if ($project->{mirror}) { die "Cannot use worktree command on mirror project\n" unless $force; warn "Continuing with --force even though project is a mirror\n" unless $quiet; } - shift @ARGV; my $symref = undef; my $mthash = undef; my $wantdwimadd = 0; @@ -1355,8 +1380,9 @@ sub cmd_urls { my $pushonly; parse_options("push" => \$pushonly); my @projs = @ARGV; - @ARGV == 1 or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV <= 1 or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; my $suffix = "/".$project->{name}.".git"; @Gitweb::Config::git_base_url_list = (); @Gitweb::Config::git_base_push_urls = (); @@ -1404,8 +1430,9 @@ sub cmd_urls { } sub cmd_listheads { - @ARGV == 1 or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV <= 1 or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; my @heads = sort({lc($a) cmp lc($b)} $project->get_heads); my $cur = $project->{HEAD}; defined($cur) or $cur = ''; @@ -1424,8 +1451,9 @@ sub cmd_listheads { sub cmd_listtags { my $vcnt = 0; parse_options("verbose" => \$vcnt, "v" => \$vcnt); - @ARGV == 1 or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV <= 1 or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; if ($vcnt) { print map("$$_[0]\t$$_[1]\n", get_ctag_counts($project)); } else { @@ -1549,8 +1577,9 @@ sub cmd_chpass { } sub cmd_checkpw { - @ARGV == 1 or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV <= 1 or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; my $pwhash = $project->{crypt}; defined($pwhash) or $pwhash = ""; if ($pwhash eq "") { @@ -1563,7 +1592,7 @@ sub cmd_checkpw { } my $checkpw; if (-t STDIN) { - $checkpw = prompt_noecho_nl_or_die("Admin password for project $ARGV[0] (echo is off)"); + $checkpw = prompt_noecho_nl_or_die("Admin password for project $$project{name} (echo is off)"); $checkpw ne "" or warn "checking for empty password as hash (very unlikely)\n" unless $quiet; } else { $checkpw = ; @@ -1586,9 +1615,9 @@ sub cmd_gc { aggressive => \$aggressive); $aggressive and $force = $redelta = 1; $force && $auto and die "--force and --auto are mutually exclusive options\n"; - @ARGV or die "Please give project name on command line.\n"; - @ARGV == 1 or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV <= 1 or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die "Please give project name on command line.\n"; delete $ENV{show_progress}; delete $ENV{force_gc}; $quiet or $ENV{"show_progress"} = 1; @@ -1615,10 +1644,10 @@ sub cmd_update { my ($force, $summary); parse_options(force => \$force, quiet => \$quiet, q => \$quiet, summary => \$summary); $quiet && $summary and die "--quiet and --summary are mutually exclusive options\n"; - @ARGV or die "Please give project name on command line.\n"; - @ARGV == 1 or die_usage; - my $project = get_project_harder($ARGV[0]); - $project->{mirror} or die "Project \"$ARGV[0]\" is a push project, not a mirror project.\n"; + @ARGV <= 1 or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die "Please give project name on command line.\n"; + $project->{mirror} or die "Project \"$$project{name}\" is a push project, not a mirror project.\n"; delete $ENV{show_progress}; delete $ENV{force_update}; if ($quiet) { @@ -1662,8 +1691,9 @@ sub cmd_remirror { sub cmd_setowner { my $force = 0; parse_options("force" => \$force); - @ARGV == 2 || (@ARGV == 1 && !$force && !$setopt) or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV == 2 || (@ARGV <= 1 && !$force && !$setopt) or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; if (@ARGV == 2 && !valid_email($ARGV[1])) { die "invalid owner/email (use --force to accept): \"$ARGV[1]\"\n" unless $force; @@ -1675,7 +1705,7 @@ sub cmd_setowner { warn "using longer than 96 char owner/email with --force\n" unless $quiet; } my $old = $project->{email}; - if (@ARGV == 1) { + if (@ARGV <= 1) { print "$old\n" if defined($old); return 0; } @@ -1694,8 +1724,10 @@ sub cmd_setowner { sub cmd_setdesc { my $force = 0; parse_options("force" => \$force); - @ARGV >= 2 || (@ARGV == 1 && !$force && !$setopt) or die_usage; - my $project = get_project_harder(shift @ARGV); + @ARGV >= 2 || (@ARGV <= 1 && !$force && !$setopt) or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; + shift(@ARGV) if @ARGV; if (@ARGV && !valid_desc(join(" ", @ARGV))) { die "invalid description (use --force to accept): \"".join(" ", @ARGV)."\"\n" unless $force; @@ -1727,12 +1759,13 @@ sub cmd_setreadme { my ($force, $readmetype) = (0, undef); parse_options(force => \$force, ":type" => \$readmetype, ":format" => \$readmetype); @ARGV == 1 && defined($readmetype) and push(@ARGV, undef); - @ARGV == 2 || (@ARGV == 1 && !$force && !defined($readmetype) && !$setopt) or die_usage; + @ARGV == 2 || (@ARGV <= 1 && !$force && !defined($readmetype) && !$setopt) or die_usage; defined($readmetype) and $readmetype = Girocco::Project::_normalize_rmtype($readmetype,1); defined($readmetype) && !$readmetype and die_usage; - my $project = get_project_harder($ARGV[0]); + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; my $old = $project->{READMEDATA}; - if (@ARGV == 1) { + if (@ARGV <= 1) { chomp $old if defined($old); print "$old\n" if defined($old) && $old ne ""; return 0; @@ -1815,8 +1848,9 @@ sub valid_head { sub cmd_sethead { my $force = 0; parse_options(force => \$force); - @ARGV == 2 || (@ARGV == 1 && !$setopt) or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV == 2 || (@ARGV <= 1 && !$setopt) or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; if (@ARGV == 2 && !valid_head($project, $ARGV[1])) { die "invalid head (try \"@{[basename($0)]} listheads $ARGV[0]\"): \"$ARGV[1]\"\n" unless $force; valid_branch_name($ARGV[1]) or @@ -1824,7 +1858,7 @@ sub cmd_sethead { warn "Continuing with --force even though requested branch does not exist\n" unless $quiet; } my $old = $project->{HEAD}; - if (@ARGV == 1) { + if (@ARGV <= 1) { print "$old\n" if defined($old); return 0; } @@ -1842,8 +1876,9 @@ sub cmd_sethead { sub cmd_sethooks { my $force = 0; parse_options(force => \$force); - @ARGV == 2 || (@ARGV == 1 && !$force && !$setopt) or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV == 2 || (@ARGV <= 1 && !$force && !$setopt) or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; my $projconfig = read_config_file_hash($project->{path}."/config"); my $ghp = $Girocco::Config::reporoot."/_global/hooks"; my $rghp = realpath($ghp); @@ -1855,7 +1890,7 @@ sub cmd_sethooks { $ahp = $projconfig->{"core.hookspath"}; $rahp = realpath($ahp); } - if (@ARGV == 1) { + if (@ARGV <= 1) { if (defined($rahp) && $rahp ne "") { if ($rahp eq $rghp) { my $nc = ($ahp eq $ghp ? "" : " non-canonical"); @@ -1957,8 +1992,9 @@ sub cmd_setbool { } sub cmd_setjsontype { - @ARGV == 2 || (@ARGV == 1 && !$setopt) or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV == 2 || (@ARGV <= 1 && !$setopt) or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; my $jsontype; if (@ARGV == 2) { my $jt = lc($ARGV[1]); @@ -1969,7 +2005,7 @@ sub cmd_setjsontype { $jsontype = $jt; } my $old = $project->{jsontype}; - if (@ARGV == 1) { + if (@ARGV <= 1) { print "$old\n" if defined($old); return 0; } @@ -1984,8 +2020,9 @@ sub cmd_setjsontype { } sub cmd_setjsonsecret { - @ARGV == 2 || (@ARGV == 1 && !$setopt) or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV == 2 || (@ARGV <= 1 && !$setopt) or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; my $jsonsecret; if (@ARGV == 2) { my $js = $ARGV[1]; @@ -1993,7 +2030,7 @@ sub cmd_setjsonsecret { $jsonsecret = $js; } my $old = $project->{jsonsecret}; - if (@ARGV == 1) { + if (@ARGV <= 1) { print "$old\n" if defined($old); return 0; } @@ -2008,8 +2045,9 @@ sub cmd_setjsonsecret { } sub cmd_setautogchack { - @ARGV == 2 || (@ARGV == 1 && !$setopt) or die_usage; - my $project = get_project_harder($ARGV[0]); + @ARGV == 2 || (@ARGV <= 1 && !$setopt) or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; my $aghok = $Girocco::Config::autogchack && ($project->{mirror} || $Girocco::Config::autogchack ne "mirror"); my $old = defined($project->{autogchack}) ? clean_bool($project->{autogchack}) : "unset"; @@ -2143,8 +2181,10 @@ sub cmd_setmsgs { sub cmd_setusers { my $force = 0; parse_options("force" => \$force); - @ARGV >= 2 || (@ARGV == 1 && !$force && !$setopt) or die_usage; - my $project = get_project_harder(shift @ARGV); + @ARGV >= 2 || (@ARGV <= 1 && !$force && !$setopt) or die_usage; + my $project = get_project_harder_gently($ARGV[0]); + defined($project) or die_usage; + shift(@ARGV) if @ARGV; my $projname = $project->{name}; !@ARGV || !$project->{mirror} or die "cannot set users list for mirror project: \"$projname\"\n"; my @newusers = (); @@ -2236,6 +2276,7 @@ BEGIN { show => \&cmd_show, verify => \&cmd_verify, worktree => \&cmd_worktree, + worktrees => \&cmd_worktree, urls => \&cmd_urls, listheads => \&cmd_listheads, listtags => \&cmd_listtags, @@ -2308,6 +2349,7 @@ BEGIN { %nopager = ( urls => -1, verify => 1, worktree => 1, + worktrees => 1, )} sub dohelp { -- 2.11.4.GIT