git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 0/2] reflog.c: switch to use parse-options API

From
John Cai via GitGitGadget <gitgitgadget@gmail.com>
Date
Jan 3, 2022, 15:20 UTC
Message-ID
<pull.1175.v2.git.git.1641223223.gitgitgadget@gmail.com>
In-Reply-To
<pull.1175.git.git.1640932151.gitgitgadget@gmail.com>

Switch out manual argv parsing for the reflog expire subcommand to use the parse-options API. This reduces code redundancy by consolidating option parsing logic.

changes since v1:
 * add helper parse_opt_expiry_date so we can use this shared logic to parse
   the expire date option.
 * place explicit_expiry inside of cmd_reflog_expire_cb to make it easier to
   use a callback to set both the value of the timestamp and the
   explicit_expiry flag.
John Cai (2):
  parse-options.h: add parse_opt_expiry_date helper
  builtin/reflog.c: switch to use parse-options API for delete
    subcommand
 builtin/reflog.c   | 168 +++++++++++++++++++++++----------------------
 parse-options-cb.c |   7 +-
 parse-options.h    |   1 +
 3 files changed, 94 insertions(+), 82 deletions(-)
base-commit: 55b058a8bbcc54bd93c733035c995abc7967e539
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1175%2Fjohn-cai%2Fjc%2Freflog-switch-to-option-parse-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1175/john-cai/jc/reflog-switch-to-option-parse-v2
Pull-Request: https://github.com/git/git/pull/1175
Range-diff vs v1:
 1:  9bd3c6672c4 < -:  ----------- builtin/reflog.c: use parse-options for expire subcommand
 -:  ----------- > 1:  bcd74559c24 parse-options.h: add parse_opt_expiry_date helper
 2:  fffea298642 ! 2:  f9de21e0f26 builtin/reflog.c: switch to use parse-options API for delete subcommand
     @@ Commit message
          Address NEEDSWORK by switching out manual arg parsing for the
          parse-options API for the delete subcommand.
      
     +    Moves explicit_expiry flag into cmd_reflog_expire_cb struct so a
     +    callback can set both the value of the expiration as well as the
     +    explicit_expiry flag.
     +
          Signed-off-by: "John Cai" <johncai86@gmail.com>
      
       ## builtin/reflog.c ##
      @@
     - #include "revision.h"
       #include "reachable.h"
       #include "worktree.h"
     --#include "parse-options.h"
       
     +-/* NEEDSWORK: switch to using parse_options */
     +-static const char reflog_expire_usage[] =
     +-N_("git reflog expire [--expire=<time>] "
     +-   "[--expire-unreachable=<time>] "
     +-   "[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
     +-   "[--verbose] [--all] <refs>...");
      -static const char reflog_delete_usage[] =
      -N_("git reflog delete [--rewrite] [--updateref] "
      -   "[--dry-run | -n] [--verbose] <refs>...");
       static const char reflog_exists_usage[] =
       N_("git reflog exists <ref>");
       
     +@@ builtin/reflog.c: static timestamp_t default_reflog_expire_unreachable;
     + struct cmd_reflog_expire_cb {
     + 	struct rev_info revs;
     + 	int stalefix;
     ++	int explicit_expiry;
     + 	timestamp_t expire_total;
     + 	timestamp_t expire_unreachable;
     + 	int recno;
     +@@ builtin/reflog.c: static int reflog_expire_config(const char *var, const char *value, void *cb)
     + 	return 0;
     + }
     + 
     +-static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, const char *ref)
     ++static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, const char *ref)
     + {
     + 	struct reflog_expire_cfg *ent;
     +-
     +-	if (slot == (EXPIRE_TOTAL|EXPIRE_UNREACH))
     ++	if (cb->explicit_expiry == (EXPIRE_TOTAL|EXPIRE_UNREACH))
     + 		return; /* both given explicitly -- nothing to tweak */
     + 
     + 	for (ent = reflog_expire_cfg; ent; ent = ent->next) {
     + 		if (!wildmatch(ent->pattern, ref, 0)) {
     +-			if (!(slot & EXPIRE_TOTAL))
     ++			if (!(cb->explicit_expiry & EXPIRE_TOTAL))
     + 				cb->expire_total = ent->expire_total;
     +-			if (!(slot & EXPIRE_UNREACH))
     ++			if (!(cb->explicit_expiry & EXPIRE_UNREACH))
     + 				cb->expire_unreachable = ent->expire_unreachable;
     + 			return;
     + 		}
     +@@ builtin/reflog.c: static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c
     + 	 * If unconfigured, make stash never expire
     + 	 */
     + 	if (!strcmp(ref, "refs/stash")) {
     +-		if (!(slot & EXPIRE_TOTAL))
     ++		if (!(cb->explicit_expiry & EXPIRE_TOTAL))
     + 			cb->expire_total = 0;
     +-		if (!(slot & EXPIRE_UNREACH))
     ++		if (!(cb->explicit_expiry & EXPIRE_UNREACH))
     + 			cb->expire_unreachable = 0;
     + 		return;
     + 	}
     + 
     + 	/* Nothing matched -- use the default value */
     +-	if (!(slot & EXPIRE_TOTAL))
     ++	if (!(cb->explicit_expiry & EXPIRE_TOTAL))
     + 		cb->expire_total = default_reflog_expire;
     +-	if (!(slot & EXPIRE_UNREACH))
     ++	if (!(cb->explicit_expiry & EXPIRE_UNREACH))
     + 		cb->expire_unreachable = default_reflog_expire_unreachable;
     + }
     + 
     ++static const char * reflog_expire_usage[] = {
     ++	N_("git reflog expire [--expire=<time>] "
     ++   "[--expire-unreachable=<time>] "
     ++   "[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
     ++   "[--verbose] [--all] <refs>..."),
     ++	NULL
     ++};
     ++
     ++static int expire_unreachable_callback(const struct option *opt,
     ++				 const char *arg,
     ++				 int unset)
     ++{
     ++	struct cmd_reflog_expire_cb *cmd = opt->value;
     ++	cmd->explicit_expiry |= EXPIRE_UNREACH;
     ++	return parse_opt_expiry_date(&cmd->expire_unreachable, arg, unset);
     ++}
     ++
     ++static int expire_total_callback(const struct option *opt,
     ++				 const char *arg,
     ++				 int unset)
     ++{
     ++	struct cmd_reflog_expire_cb *cmd = opt->value;
     ++	cmd->explicit_expiry |= EXPIRE_TOTAL;
     ++	return parse_opt_expiry_date(&cmd->expire_total, arg, unset);
     ++}
     ++
     + static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
     + {
     + 	struct expire_reflog_policy_cb cb;
     + 	timestamp_t now = time(NULL);
     + 	int i, status, do_all, all_worktrees = 1;
     +-	int explicit_expiry = 0;
     + 	unsigned int flags = 0;
     ++	const struct option options[] = {
     ++		OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
     ++				EXPIRE_REFLOGS_DRY_RUN),
     ++		OPT_BIT(0, "rewrite", &flags,
     ++				N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
     ++				EXPIRE_REFLOGS_REWRITE),
     ++		OPT_BIT(0, "updateref", &flags,
     ++				N_("update the reference to the value of the top reflog entry"),
     ++				EXPIRE_REFLOGS_UPDATE_REF),
     ++		OPT_BIT(0, "verbose", &flags, N_("print extra information on screen."),
     ++				EXPIRE_REFLOGS_VERBOSE),
     ++		OPT_CALLBACK(0, "expire", &cb.cmd, N_("timestamp"),
     ++				N_("prune entries older than the specified time"), expire_total_callback),
     ++		OPT_CALLBACK(0, "expire-unreachable", &cb.cmd, N_("timestamp"),
     ++			N_("prune entries older than <time> that are not reachable from the current tip of the branch"),
     ++			expire_unreachable_callback),
     ++		OPT_BOOL(0, "stale-fix", &cb.cmd.stalefix,
     ++				N_("prune any reflog entries that point to broken commits")),
     ++		OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
     ++		OPT_BOOL(1, "single-worktree", &all_worktrees,
     ++				N_("limits processing to reflogs from the current worktree only.")),
     ++		OPT_END()
     ++	};
     + 
     + 	default_reflog_expire_unreachable = now - 30 * 24 * 3600;
     + 	default_reflog_expire = now - 90 * 24 * 3600;
     +@@ builtin/reflog.c: static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
     + 	do_all = status = 0;
     + 	memset(&cb, 0, sizeof(cb));
     + 
     ++	cb.cmd.explicit_expiry = 0;
     + 	cb.cmd.expire_total = default_reflog_expire;
     + 	cb.cmd.expire_unreachable = default_reflog_expire_unreachable;
     + 
     +-	for (i = 1; i < argc; i++) {
     +-		const char *arg = argv[i];
     +-
     +-		if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
     +-			flags |= EXPIRE_REFLOGS_DRY_RUN;
     +-		else if (skip_prefix(arg, "--expire=", &arg)) {
     +-			if (parse_expiry_date(arg, &cb.cmd.expire_total))
     +-				die(_("'%s' is not a valid timestamp"), arg);
     +-			explicit_expiry |= EXPIRE_TOTAL;
     +-		}
     +-		else if (skip_prefix(arg, "--expire-unreachable=", &arg)) {
     +-			if (parse_expiry_date(arg, &cb.cmd.expire_unreachable))
     +-				die(_("'%s' is not a valid timestamp"), arg);
     +-			explicit_expiry |= EXPIRE_UNREACH;
     +-		}
     +-		else if (!strcmp(arg, "--stale-fix"))
     +-			cb.cmd.stalefix = 1;
     +-		else if (!strcmp(arg, "--rewrite"))
     +-			flags |= EXPIRE_REFLOGS_REWRITE;
     +-		else if (!strcmp(arg, "--updateref"))
     +-			flags |= EXPIRE_REFLOGS_UPDATE_REF;
     +-		else if (!strcmp(arg, "--all"))
     +-			do_all = 1;
     +-		else if (!strcmp(arg, "--single-worktree"))
     +-			all_worktrees = 0;
     +-		else if (!strcmp(arg, "--verbose"))
     +-			flags |= EXPIRE_REFLOGS_VERBOSE;
     +-		else if (!strcmp(arg, "--")) {
     +-			i++;
     +-			break;
     +-		}
     +-		else if (arg[0] == '-')
     +-			usage(_(reflog_expire_usage));
     +-		else
     +-			break;
     +-	}
     +-
     ++	argc = parse_options(argc, argv, prefix, options, reflog_expire_usage, 0);
     + 	/*
     + 	 * We can trust the commits and objects reachable from refs
     + 	 * even in older repository.  We cannot trust what's reachable
     +@@ builtin/reflog.c: static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
     + 		for (i = 0; i < collected.nr; i++) {
     + 			struct collected_reflog *e = collected.e[i];
     + 
     +-			set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
     ++			set_reflog_expiry_param(&cb.cmd,  e->reflog);
     + 			status |= reflog_expire(e->reflog, flags,
     + 						reflog_expiry_prepare,
     + 						should_expire_reflog_ent,
      @@ builtin/reflog.c: static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
       		free(collected.e);
       	}
     @@ builtin/reflog.c: static int cmd_reflog_expire(int argc, const char **argv, cons
       		char *ref;
       		if (!dwim_log(argv[i], strlen(argv[i]), NULL, &ref)) {
       			status |= error(_("%s points nowhere!"), argv[i]);
     + 			continue;
     + 		}
     +-		set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
     ++		set_reflog_expiry_param(&cb.cmd, ref);
     + 		status |= reflog_expire(ref, flags,
     + 					reflog_expiry_prepare,
     + 					should_expire_reflog_ent,
      @@ builtin/reflog.c: static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
       	return 0;
       }
-- 
gitgitgadget
Previous: John Cai via GitGitGadgetNext: John Cai via GitGitGadget
Message 8 of 19 in “reflog.c: switch to use parse-options API”
  1. 0/2 reflog.c: switch to use parse-options APIJohn Cai via GitGitGadget, Dec 31, 2021
  2. 1/2 builtin/reflog.c: use parse-options for expire subcommandJohn Cai via GitGitGadget, Dec 31, 2021
  3. John CaiJan 1, 2022
  4. René ScharfeJan 1, 2022
  5. John CaiJan 1, 2022
  6. René ScharfeJan 2, 2022
  7. 2/2 builtin/reflog.c: switch to use parse-options API for delete subcommandJohn Cai via GitGitGadget, Dec 31, 2021
  8. 0/2 reflog.c: switch to use parse-options APIJohn Cai via GitGitGadget, Jan 3, 2022
  9. 1/2 parse-options.h: add parse_opt_expiry_date helperJohn Cai via GitGitGadget, Jan 3, 2022
  10. Junio C HamanoJan 4, 2022
  11. 2/2 builtin/reflog.c: switch to use parse-options API for delete subcommandJohn Cai via GitGitGadget, Jan 3, 2022
  12. Junio C HamanoJan 4, 2022
  13. builtin/reflog.c: use parse-options api for expire, delete subcommandsJohn Cai via GitGitGadget, Jan 4, 2022
  14. Junio C HamanoJan 4, 2022
  15. builtin/reflog.c: use parse-options api for expire, delete subcommandsJohn Cai via GitGitGadget, Jan 5, 2022
  16. Junio C HamanoJan 5, 2022
  17. builtin/reflog.c: use parse-options api for expire, delete subcommandsJohn Cai via GitGitGadget, Jan 6, 2022
  18. Junio C HamanoJan 6, 2022
  19. John CaiJan 6, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.