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

[RFC PATCH] revert: Persist per-session opts

From
Ramkumar Ramachandra <artagnon@gmail.com>
Date
Jul 9, 2011, 15:41 UTC
Message-ID
<1310226118-10201-2-git-send-email-artagnon@gmail.com>
In-Reply-To
<1310226118-10201-1-git-send-email-artagnon@gmail.com>

Save the replay_opts struct in .git/sequencer/opts using a simple "key = value" format. Parse it and populate the options structure before replaying.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 builtin/revert.c |  143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sequencer.h      |    8 +++
 2 files changed, 151 insertions(+), 0 deletions(-)
diff --git a/builtin/revert.c b/builtin/revert.c
index 1feecd5..0693fd8 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -635,6 +635,32 @@ static void read_and_refresh_cache(const char *me, struct replay_opts *opts)
 	rollback_lock_file(&index_lock);
 }
 
+static void format_opts(struct strbuf *buf, struct replay_opts *opts)
+{
+	int i;
+
+	if (opts->no_commit)
+		strbuf_addstr(buf, "no-commit = true\n");
+	if (opts->edit)
+		strbuf_addstr(buf, "edit = true\n");
+	if (opts->signoff)
+		strbuf_addstr(buf, "signoff = true\n");
+	if (opts->record_origin)
+		strbuf_addstr(buf, "record-origin = true\n");
+	if (opts->allow_ff)
+		strbuf_addstr(buf, "ff = true\n");
+	if (opts->mainline)
+		strbuf_addf(buf, "mainline = %d\n", opts->mainline);
+	if (opts->strategy)
+		strbuf_addf(buf, "strategy = %s\n", opts->strategy);
+	if (opts->xopts) {
+		strbuf_addf(buf, "strategy-option = ");
+		for (i = 0; i < opts->xopts_nr - 1; i ++)
+			strbuf_addf(buf, "%s | ", opts->xopts[i]);
+		strbuf_addf(buf, "%s\n", opts->xopts[i]);
+	}
+}
+
 static void format_todo(struct strbuf *buf, struct commit_list *todo_list,
 			struct replay_opts *opts)
 {
@@ -733,6 +759,102 @@ error:
 	die(_("Malformed instruction sheet: %s"), git_path(SEQ_TODO_FILE));
 }
 
+static char *parse_opt_value(char *p, void *key, enum seq_opt_type type,
+			parse_opt_cb *cb_function) {
+	struct option opt;
+	char *val, *cur, *end;
+
+	if (!(val = strchr(p, '=')))
+		goto error;
+	if (!*(val + 1))
+		goto error;
+	if (!(end = strchr(p, '\n')))
+		goto error;
+	val += 2;
+	*end = '\0'; /* Remove trailing '\n' */
+
+	switch (type) {
+	case SEQ_OPTION_BOOLEAN:
+		if (!strncmp(val, "true", strlen("true")))
+			*(int *)key = 1;
+		else if (!strncmp(val, "false", strlen("false")))
+			*(int *)key = 0;
+		else
+			goto error;
+		break;
+	case SEQ_OPTION_INTEGER:
+		*(int *)key = strtol(val, NULL, 10);
+		break;
+	case SEQ_OPTION_STRING:
+		*(char **)key = xstrdup(val);
+		break;
+	case SEQ_OPTION_CALLBACK:
+		opt.value = (struct replay_opts **)key;
+		while (val) {
+			if ((cur = strchr(val, '|'))) {
+				*(cur - 1) = '\0';
+				(*cb_function)(&opt, val, 0);
+				val = cur + 2;
+			} else {
+				(*cb_function)(&opt, val, 0);
+				break;
+			}
+		}
+		break;
+	default:
+		die(_("program error"));
+	}
+	return end + 1;
+error:
+	die(_("Malformed options sheet: %s"), git_path(SEQ_OPTS_FILE));
+}
+
+static void read_populate_opts(struct replay_opts **opts_ptr)
+{
+	struct replay_opts *opts = *opts_ptr;
+	struct strbuf buf = STRBUF_INIT;
+	char *p;
+	int fd;
+
+	fd = open(git_path(SEQ_OPTS_FILE), O_RDONLY);
+	if (fd < 0) {
+		strbuf_release(&buf);
+		die_errno(_("Could not open %s."), git_path(SEQ_OPTS_FILE));
+	}
+	if (strbuf_read(&buf, fd, 0) < buf.len) {
+		close(fd);
+		strbuf_release(&buf);
+		die(_("Could not read %s."), git_path(SEQ_OPTS_FILE));
+	}
+	close(fd);
+
+	for (p = buf.buf; *p;) {
+		if (!strncmp(p, "no-commit ", strlen("no-commit ")))
+			p = parse_opt_value(p, &opts->no_commit, SEQ_OPTION_BOOLEAN, NULL);
+		else if (!strncmp(p, "edit ", strlen("edit ")))
+			p = parse_opt_value(p, &opts->edit, SEQ_OPTION_BOOLEAN, NULL);
+		else if (!strncmp(p, "signoff ", strlen("signoff ")))
+			p = parse_opt_value(p, &opts->signoff, SEQ_OPTION_BOOLEAN, NULL);
+		else if (!strncmp(p, "mainline ", strlen("mainline ")))
+			p = parse_opt_value(p, &opts->mainline, SEQ_OPTION_INTEGER, NULL);
+		else if (!strncmp(p, "record-origin ", strlen("record-origin ")))
+			p = parse_opt_value(p, &opts->record_origin, SEQ_OPTION_BOOLEAN, NULL);
+		else if (!strncmp(p, "ff ", strlen("ff ")))
+			p = parse_opt_value(p, &opts->allow_ff, SEQ_OPTION_BOOLEAN, NULL);
+		else if (!strncmp(p, "strategy ", strlen("strategy ")))
+			p = parse_opt_value(p, &opts->strategy, SEQ_OPTION_STRING, NULL);
+		else if (!strncmp(p, "strategy-option ", strlen("strategy-option ")))
+			p = parse_opt_value(p, &opts, SEQ_OPTION_CALLBACK, option_parse_x);
+		else
+			goto error;
+	}
+	strbuf_release(&buf);
+	return;
+error:
+	strbuf_release(&buf);
+	die(_("Malformed options sheet: %s"), git_path(SEQ_OPTS_FILE));
+}
+
 static void walk_revs_populate_todo(struct commit_list **todo_list,
 				struct replay_opts *opts)
 {
@@ -800,6 +922,25 @@ static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
 	strbuf_release(&buf);
 }
 
+static void save_opts(struct replay_opts *opts)
+{
+	static struct lock_file opts_lock;
+	struct strbuf buf = STRBUF_INIT;
+	int fd;
+
+	fd = hold_lock_file_for_update(&opts_lock, git_path(SEQ_OPTS_FILE), LOCK_DIE_ON_ERROR);
+	format_opts(&buf, opts);
+	if (write_in_full(fd, buf.buf, buf.len) < 0) {
+		strbuf_release(&buf);
+		die_errno(_("Could not write to %s."), git_path(SEQ_OPTS_FILE));
+	}
+	if (commit_lock_file(&opts_lock) < 0) {
+		strbuf_release(&buf);
+		die(_("Error wrapping up %s"), git_path(SEQ_OPTS_FILE));
+	}
+	strbuf_release(&buf);
+}
+
 static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
 {
 	struct commit_list *cur;
@@ -849,6 +990,7 @@ static int process_continuation(struct replay_opts *opts)
 	} else if (opts->subcommand == REPLAY_CONTINUE) {
 		if (!file_exists(git_path(SEQ_TODO_FILE)))
 			goto error;
+		read_populate_opts(&opts);
 		read_populate_todo(&todo_list, opts);
 
 		/* Verify that the conflict has been resolved */
@@ -871,6 +1013,7 @@ static int process_continuation(struct replay_opts *opts)
 		create_seq_dir();
 		if (!get_sha1("HEAD", sha1))
 			save_head(sha1_to_hex(sha1));
+		save_opts(opts);
 		save_todo(todo_list, opts);
 	}
 	return pick_commits(todo_list, opts);
diff --git a/sequencer.h b/sequencer.h
index d6fe6e0..e7bef5d 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -5,6 +5,14 @@
 #define SEQ_OLD_DIR	"sequencer-old"
 #define SEQ_HEAD_FILE	"sequencer/head"
 #define SEQ_TODO_FILE	"sequencer/todo"
+#define SEQ_OPTS_FILE	"sequencer/opts"
+
+enum seq_opt_type {
+	SEQ_OPTION_BOOLEAN,
+	SEQ_OPTION_INTEGER,
+	SEQ_OPTION_STRING,
+	SEQ_OPTION_CALLBACK,
+};
 
 /* Removes SEQ_OLD_DIR and renames SEQ_DIR to SEQ_OLD_DIR, ignoring
  * any errors.  Intended to be used by 'git reset --hard'.
-- 
1.7.5.GIT
Previous: Ramkumar RamachandraNext: Christian Couder
Message 2 of 6 in “An option parser for the sequencer”
  1. An option parser for the sequencerRamkumar Ramachandra, Jul 9, 2011
  2. revert: Persist per-session optsRamkumar Ramachandra, Jul 9, 2011
  3. Christian CouderJul 10, 2011
  4. Ramkumar RamachandraJul 11, 2011
  5. Christian CouderJul 10, 2011
  6. Ramkumar RamachandraJul 11, 2011

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.