builtin/reflog.c: use parse-options api for expire, delete subcommands

Switching out manual arg parsing for the parse-options API for the expire and delete subcommands. Move explicit_expiry flag into cmd_reflog_expire_cb struct so callbacks can set both the value of the timestamp as well as the explicit_expiry flag. Signed-off-by: "John Cai" <johncai86@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

John Cai committed Jan 6, 2022 at 19:06 UTC 33d7bdd64592d6dc86583a817719f91d7344e958
1 file changed +97 -79
builtin/reflog.c
+97 -79
@@ -12,15 +12,6 @@
12 #include "reachable.h"
13 #include "worktree.h"
14
15 -/* NEEDSWORK: switch to using parse_options */
16 -static const char reflog_expire_usage[] =
17 -N_("git reflog expire [--expire=<time>] "
18 - "[--expire-unreachable=<time>] "
19 - "[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
20 - "[--verbose] [--all] <refs>...");
21 -static const char reflog_delete_usage[] =
22 -N_("git reflog delete [--rewrite] [--updateref] "
23 - "[--dry-run | -n] [--verbose] <refs>...");
15 static const char reflog_exists_usage[] =
16 N_("git reflog exists <ref>");
17
@@ -29,6 +20,7 @@ static timestamp_t default_reflog_expire_unreachable;
20
21 struct cmd_reflog_expire_cb {
22 int stalefix;
23 + int explicit_expiry;
24 timestamp_t expire_total;
25 timestamp_t expire_unreachable;
26 int recno;
@@ -520,18 +512,18 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)
512 return 0;
513 }
514
523 -static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, const char *ref)
515 +static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, const char *ref)
516 {
517 struct reflog_expire_cfg *ent;
518
527 - if (slot == (EXPIRE_TOTAL|EXPIRE_UNREACH))
519 + if (cb->explicit_expiry == (EXPIRE_TOTAL|EXPIRE_UNREACH))
520 return; /* both given explicitly -- nothing to tweak */
521
522 for (ent = reflog_expire_cfg; ent; ent = ent->next) {
523 if (!wildmatch(ent->pattern, ref, 0)) {
532 - if (!(slot & EXPIRE_TOTAL))
524 + if (!(cb->explicit_expiry & EXPIRE_TOTAL))
525 cb->expire_total = ent->expire_total;
534 - if (!(slot & EXPIRE_UNREACH))
526 + if (!(cb->explicit_expiry & EXPIRE_UNREACH))
527 cb->expire_unreachable = ent->expire_unreachable;
528 return;
529 }
@@ -541,29 +533,89 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c
533 * If unconfigured, make stash never expire
534 */
535 if (!strcmp(ref, "refs/stash")) {
544 - if (!(slot & EXPIRE_TOTAL))
536 + if (!(cb->explicit_expiry & EXPIRE_TOTAL))
537 cb->expire_total = 0;
546 - if (!(slot & EXPIRE_UNREACH))
538 + if (!(cb->explicit_expiry & EXPIRE_UNREACH))
539 cb->expire_unreachable = 0;
540 return;
541 }
542
543 /* Nothing matched -- use the default value */
552 - if (!(slot & EXPIRE_TOTAL))
544 + if (!(cb->explicit_expiry & EXPIRE_TOTAL))
545 cb->expire_total = default_reflog_expire;
554 - if (!(slot & EXPIRE_UNREACH))
546 + if (!(cb->explicit_expiry & EXPIRE_UNREACH))
547 cb->expire_unreachable = default_reflog_expire_unreachable;
548 }
549
550 +static const char * reflog_expire_usage[] = {
551 + N_("git reflog expire [--expire=<time>] "
552 + "[--expire-unreachable=<time>] "
553 + "[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
554 + "[--verbose] [--all] <refs>..."),
555 + NULL
556 +};
557 +
558 +static int expire_unreachable_callback(const struct option *opt,
559 + const char *arg,
560 + int unset)
561 +{
562 + struct cmd_reflog_expire_cb *cmd = opt->value;
563 +
564 + if (parse_expiry_date(arg, &cmd->expire_unreachable))
565 + die(_("invalid timestamp '%s' given to '--%s'"),
566 + arg, opt->long_name);
567 +
568 + cmd->explicit_expiry |= EXPIRE_UNREACH;
569 + return 0;
570 +}
571 +
572 +static int expire_total_callback(const struct option *opt,
573 + const char *arg,
574 + int unset)
575 +{
576 + struct cmd_reflog_expire_cb *cmd = opt->value;
577 +
578 + if (parse_expiry_date(arg, &cmd->expire_total))
579 + die(_("invalid timestamp '%s' given to '--%s'"),
580 + arg, opt->long_name);
581 +
582 + cmd->explicit_expiry |= EXPIRE_TOTAL;
583 + return 0;
584 +}
585 +
586 static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
587 {
588 struct cmd_reflog_expire_cb cmd = { 0 };
589 timestamp_t now = time(NULL);
590 int i, status, do_all, all_worktrees = 1;
563 - int explicit_expiry = 0;
591 unsigned int flags = 0;
592 int verbose = 0;
593 reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
594 + const struct option options[] = {
595 + OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
596 + EXPIRE_REFLOGS_DRY_RUN),
597 + OPT_BIT(0, "rewrite", &flags,
598 + N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
599 + EXPIRE_REFLOGS_REWRITE),
600 + OPT_BIT(0, "updateref", &flags,
601 + N_("update the reference to the value of the top reflog entry"),
602 + EXPIRE_REFLOGS_UPDATE_REF),
603 + OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen.")),
604 + OPT_CALLBACK_F(0, "expire", &cmd, N_("timestamp"),
605 + N_("prune entries older than the specified time"),
606 + PARSE_OPT_NONEG,
607 + expire_total_callback),
608 + OPT_CALLBACK_F(0, "expire-unreachable", &cmd, N_("timestamp"),
609 + N_("prune entries older than <time> that are not reachable from the current tip of the branch"),
610 + PARSE_OPT_NONEG,
611 + expire_unreachable_callback),
612 + OPT_BOOL(0, "stale-fix", &cmd.stalefix,
613 + N_("prune any reflog entries that point to broken commits")),
614 + OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
615 + OPT_BOOL(1, "single-worktree", &all_worktrees,
616 + N_("limits processing to reflogs from the current worktree only.")),
617 + OPT_END()
618 + };
619
620 default_reflog_expire_unreachable = now - 30 * 24 * 3600;
621 default_reflog_expire = now - 90 * 24 * 3600;
@@ -572,45 +624,11 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
624 save_commit_buffer = 0;
625 do_all = status = 0;
626
627 + cmd.explicit_expiry = 0;
628 cmd.expire_total = default_reflog_expire;
629 cmd.expire_unreachable = default_reflog_expire_unreachable;
630
578 - for (i = 1; i < argc; i++) {
579 - const char *arg = argv[i];
580 -
581 - if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
582 - flags |= EXPIRE_REFLOGS_DRY_RUN;
583 - else if (skip_prefix(arg, "--expire=", &arg)) {
584 - if (parse_expiry_date(arg, &cmd.expire_total))
585 - die(_("'%s' is not a valid timestamp"), arg);
586 - explicit_expiry |= EXPIRE_TOTAL;
587 - }
588 - else if (skip_prefix(arg, "--expire-unreachable=", &arg)) {
589 - if (parse_expiry_date(arg, &cmd.expire_unreachable))
590 - die(_("'%s' is not a valid timestamp"), arg);
591 - explicit_expiry |= EXPIRE_UNREACH;
592 - }
593 - else if (!strcmp(arg, "--stale-fix"))
594 - cmd.stalefix = 1;
595 - else if (!strcmp(arg, "--rewrite"))
596 - flags |= EXPIRE_REFLOGS_REWRITE;
597 - else if (!strcmp(arg, "--updateref"))
598 - flags |= EXPIRE_REFLOGS_UPDATE_REF;
599 - else if (!strcmp(arg, "--all"))
600 - do_all = 1;
601 - else if (!strcmp(arg, "--single-worktree"))
602 - all_worktrees = 0;
603 - else if (!strcmp(arg, "--verbose"))
604 - verbose = 1;
605 - else if (!strcmp(arg, "--")) {
606 - i++;
607 - break;
608 - }
609 - else if (arg[0] == '-')
610 - usage(_(reflog_expire_usage));
611 - else
612 - break;
613 - }
631 + argc = parse_options(argc, argv, prefix, options, reflog_expire_usage, 0);
632
633 if (verbose)
634 should_prune_fn = should_expire_reflog_ent_verbose;
@@ -657,7 +675,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
675 .dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
676 };
677
660 - set_reflog_expiry_param(&cb.cmd, explicit_expiry, item->string);
678 + set_reflog_expiry_param(&cb.cmd, item->string);
679 status |= reflog_expire(item->string, flags,
680 reflog_expiry_prepare,
681 should_prune_fn,
@@ -667,7 +685,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
685 string_list_clear(&collected.reflogs, 0);
686 }
687
670 - for (; i < argc; i++) {
688 + for (i = 0; i < argc; i++) {
689 char *ref;
690 struct expire_reflog_policy_cb cb = { .cmd = cmd };
691
@@ -675,7 +693,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
693 status |= error(_("%s points nowhere!"), argv[i]);
694 continue;
695 }
678 - set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
696 + set_reflog_expiry_param(&cb.cmd, ref);
697 status |= reflog_expire(ref, flags,
698 reflog_expiry_prepare,
699 should_prune_fn,
@@ -696,6 +714,12 @@ static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
714 return 0;
715 }
716
717 +static const char * reflog_delete_usage[] = {
718 + N_("git reflog delete [--rewrite] [--updateref] "
719 + "[--dry-run | -n] [--verbose] <refs>..."),
720 + NULL
721 +};
722 +
723 static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
724 {
725 struct cmd_reflog_expire_cb cmd = { 0 };
@@ -703,34 +727,28 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
727 unsigned int flags = 0;
728 int verbose = 0;
729 reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
706 -
707 - for (i = 1; i < argc; i++) {
708 - const char *arg = argv[i];
709 - if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
710 - flags |= EXPIRE_REFLOGS_DRY_RUN;
711 - else if (!strcmp(arg, "--rewrite"))
712 - flags |= EXPIRE_REFLOGS_REWRITE;
713 - else if (!strcmp(arg, "--updateref"))
714 - flags |= EXPIRE_REFLOGS_UPDATE_REF;
715 - else if (!strcmp(arg, "--verbose"))
716 - verbose = 1;
717 - else if (!strcmp(arg, "--")) {
718 - i++;
719 - break;
720 - }
721 - else if (arg[0] == '-')
722 - usage(_(reflog_delete_usage));
723 - else
724 - break;
725 - }
730 + const struct option options[] = {
731 + OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
732 + EXPIRE_REFLOGS_DRY_RUN),
733 + OPT_BIT(0, "rewrite", &flags,
734 + N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
735 + EXPIRE_REFLOGS_REWRITE),
736 + OPT_BIT(0, "updateref", &flags,
737 + N_("update the reference to the value of the top reflog entry"),
738 + EXPIRE_REFLOGS_UPDATE_REF),
739 + OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen.")),
740 + OPT_END()
741 + };
742 +
743 + argc = parse_options(argc, argv, prefix, options, reflog_delete_usage, 0);
744
745 if (verbose)
746 should_prune_fn = should_expire_reflog_ent_verbose;
747
730 - if (argc - i < 1)
748 + if (argc < 1)
749 return error(_("no reflog specified to delete"));
750
733 - for ( ; i < argc; i++) {
751 + for (i = 0; i < argc; i++) {
752 const char *spec = strstr(argv[i], "@{");
753 char *ep, *ref;
754 int recno;