Skip to content

Commit 683153a

Browse files
agrngitster
authored andcommitted
sequencer: refactor sequencer_add_exec_commands() to work on a todo_list
This refactors sequencer_add_exec_commands() to work on a todo_list to avoid redundant reads and writes to the disk. Instead of inserting the `exec' commands between the other commands and re-parsing the buffer at the end, they are appended to the buffer once, and a new list of items is created. Items from the old list are copied across and new `exec' items are appended when necessary. This eliminates the need to reparse the buffer, but this also means we have to use todo_list_write_to_disk() to write the file. todo_list_add_exec_commands() and sequencer_add_exec_commands() are modified to take a string list instead of a string -- one item for each command. This makes it easier to insert a new command to the todo list for each command to execute. sequencer_add_exec_commands() still reads the todo list from the disk, as it is needed by rebase -p. complete_action() still uses sequencer_add_exec_commands() for now. This will be changed in a future commit. Signed-off-by: Alban Gruin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6ca89c6 commit 683153a

File tree

3 files changed

+91
-46
lines changed

3 files changed

+91
-46
lines changed

builtin/rebase--interactive.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,
6565
const char *onto, const char *onto_name,
6666
const char *squash_onto, const char *head_name,
6767
const char *restrict_revision, char *raw_strategies,
68-
const char *cmd, unsigned autosquash)
68+
struct string_list *commands, unsigned autosquash)
6969
{
7070
int ret;
7171
const char *head_hash = NULL;
@@ -116,7 +116,7 @@ static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,
116116
discard_cache();
117117
ret = complete_action(the_repository, opts, flags,
118118
shortrevisions, onto_name, onto,
119-
head_hash, cmd, autosquash);
119+
head_hash, commands, autosquash);
120120
}
121121

122122
free(revisions);
@@ -139,6 +139,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
139139
const char *onto = NULL, *onto_name = NULL, *restrict_revision = NULL,
140140
*squash_onto = NULL, *upstream = NULL, *head_name = NULL,
141141
*switch_to = NULL, *cmd = NULL;
142+
struct string_list commands = STRING_LIST_INIT_DUP;
142143
char *raw_strategies = NULL;
143144
enum {
144145
NONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,
@@ -221,14 +222,22 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
221222
warning(_("--[no-]rebase-cousins has no effect without "
222223
"--rebase-merges"));
223224

225+
if (cmd && *cmd) {
226+
string_list_split(&commands, cmd, '\n', -1);
227+
228+
/* rebase.c adds a new line to cmd after every command,
229+
* so here the last command is always empty */
230+
string_list_remove_empty_items(&commands, 0);
231+
}
232+
224233
switch (command) {
225234
case NONE:
226235
if (!onto && !upstream)
227236
die(_("a base commit must be provided with --upstream or --onto"));
228237

229238
ret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,
230239
onto_name, squash_onto, head_name, restrict_revision,
231-
raw_strategies, cmd, autosquash);
240+
raw_strategies, &commands, autosquash);
232241
break;
233242
case SKIP: {
234243
struct string_list merge_rr = STRING_LIST_INIT_DUP;
@@ -262,11 +271,12 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
262271
ret = rearrange_squash(the_repository);
263272
break;
264273
case ADD_EXEC:
265-
ret = sequencer_add_exec_commands(the_repository, cmd);
274+
ret = sequencer_add_exec_commands(the_repository, &commands);
266275
break;
267276
default:
268277
BUG("invalid command '%d'", command);
269278
}
270279

280+
string_list_clear(&commands, 0);
271281
return !!ret;
272282
}

sequencer.c

Lines changed: 74 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4505,61 +4505,95 @@ int sequencer_make_script(struct repository *r, FILE *out,
45054505
* Add commands after pick and (series of) squash/fixup commands
45064506
* in the todo list.
45074507
*/
4508-
int sequencer_add_exec_commands(struct repository *r,
4509-
const char *commands)
4508+
static void todo_list_add_exec_commands(struct todo_list *todo_list,
4509+
struct string_list *commands)
45104510
{
4511-
const char *todo_file = rebase_path_todo();
4512-
struct todo_list todo_list = TODO_LIST_INIT;
4513-
struct strbuf *buf = &todo_list.buf;
4514-
size_t offset = 0, commands_len = strlen(commands);
4515-
int i, insert;
4511+
struct strbuf *buf = &todo_list->buf;
4512+
size_t base_offset = buf->len;
4513+
int i, insert, nr = 0, alloc = 0;
4514+
struct todo_item *items = NULL, *base_items = NULL;
45164515

4517-
if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
4518-
return error(_("could not read '%s'."), todo_file);
4516+
base_items = xcalloc(commands->nr, sizeof(struct todo_item));
4517+
for (i = 0; i < commands->nr; i++) {
4518+
size_t command_len = strlen(commands->items[i].string);
45194519

4520-
if (todo_list_parse_insn_buffer(r, todo_list.buf.buf, &todo_list)) {
4521-
todo_list_release(&todo_list);
4522-
return error(_("unusable todo list: '%s'"), todo_file);
4520+
strbuf_addstr(buf, commands->items[i].string);
4521+
strbuf_addch(buf, '\n');
4522+
4523+
base_items[i].command = TODO_EXEC;
4524+
base_items[i].offset_in_buf = base_offset;
4525+
base_items[i].arg_offset = base_offset + strlen("exec ");
4526+
base_items[i].arg_len = command_len - strlen("exec ");
4527+
4528+
base_offset += command_len + 1;
45234529
}
45244530

45254531
/*
45264532
* Insert <commands> after every pick. Here, fixup/squash chains
45274533
* are considered part of the pick, so we insert the commands *after*
45284534
* those chains if there are any.
4535+
*
4536+
* As we insert the exec commands immediatly after rearranging
4537+
* any fixups and before the user edits the list, a fixup chain
4538+
* can never contain comments (any comments are empty picks that
4539+
* have been commented out because the user did not specify
4540+
* --keep-empty). So, it is safe to insert an exec command
4541+
* without looking at the command following a comment.
45294542
*/
4530-
insert = -1;
4531-
for (i = 0; i < todo_list.nr; i++) {
4532-
enum todo_command command = todo_list.items[i].command;
4533-
4534-
if (insert >= 0) {
4535-
/* skip fixup/squash chains */
4536-
if (command == TODO_COMMENT)
4537-
continue;
4538-
else if (is_fixup(command)) {
4539-
insert = i + 1;
4540-
continue;
4541-
}
4542-
strbuf_insert(buf,
4543-
todo_list.items[insert].offset_in_buf +
4544-
offset, commands, commands_len);
4545-
offset += commands_len;
4546-
insert = -1;
4543+
insert = 0;
4544+
for (i = 0; i < todo_list->nr; i++) {
4545+
enum todo_command command = todo_list->items[i].command;
4546+
if (insert && !is_fixup(command)) {
4547+
ALLOC_GROW(items, nr + commands->nr, alloc);
4548+
COPY_ARRAY(items + nr, base_items, commands->nr);
4549+
nr += commands->nr;
4550+
4551+
insert = 0;
45474552
}
45484553

4554+
ALLOC_GROW(items, nr + 1, alloc);
4555+
items[nr++] = todo_list->items[i];
4556+
45494557
if (command == TODO_PICK || command == TODO_MERGE)
4550-
insert = i + 1;
4558+
insert = 1;
45514559
}
45524560

45534561
/* insert or append final <commands> */
4554-
if (insert >= 0 && insert < todo_list.nr)
4555-
strbuf_insert(buf, todo_list.items[insert].offset_in_buf +
4556-
offset, commands, commands_len);
4557-
else if (insert >= 0 || !offset)
4558-
strbuf_add(buf, commands, commands_len);
4562+
if (insert || nr == todo_list->nr) {
4563+
ALLOC_GROW(items, nr + commands->nr, alloc);
4564+
COPY_ARRAY(items + nr, base_items, commands->nr);
4565+
nr += commands->nr;
4566+
}
4567+
4568+
free(base_items);
4569+
FREE_AND_NULL(todo_list->items);
4570+
todo_list->items = items;
4571+
todo_list->nr = nr;
4572+
todo_list->alloc = alloc;
4573+
}
4574+
4575+
int sequencer_add_exec_commands(struct repository *r,
4576+
struct string_list *commands)
4577+
{
4578+
const char *todo_file = rebase_path_todo();
4579+
struct todo_list todo_list = TODO_LIST_INIT;
4580+
int res;
4581+
4582+
if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
4583+
return error_errno(_("could not read '%s'."), todo_file);
45594584

4560-
i = write_message(buf->buf, buf->len, todo_file, 0);
4585+
if (todo_list_parse_insn_buffer(r, todo_list.buf.buf, &todo_list)) {
4586+
todo_list_release(&todo_list);
4587+
return error(_("unusable todo list: '%s'"), todo_file);
4588+
}
4589+
4590+
todo_list_add_exec_commands(&todo_list, commands);
4591+
res = todo_list_write_to_file(r, &todo_list, todo_file, NULL, NULL, -1, 0);
45614592
todo_list_release(&todo_list);
4562-
return i;
4593+
4594+
if (res)
4595+
return error_errno(_("could not write '%s'."), todo_file);
4596+
return 0;
45634597
}
45644598

45654599
static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_list,
@@ -4790,7 +4824,7 @@ static int skip_unnecessary_picks(struct repository *r, struct object_id *output
47904824

47914825
int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
47924826
const char *shortrevisions, const char *onto_name,
4793-
const char *onto, const char *orig_head, const char *cmd,
4827+
const char *onto, const char *orig_head, struct string_list *commands,
47944828
unsigned autosquash)
47954829
{
47964830
const char *shortonto, *todo_file = rebase_path_todo();
@@ -4809,8 +4843,8 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
48094843
if (autosquash && rearrange_squash(r))
48104844
return -1;
48114845

4812-
if (cmd && *cmd)
4813-
sequencer_add_exec_commands(r, cmd);
4846+
if (commands->nr)
4847+
sequencer_add_exec_commands(r, commands);
48144848

48154849
if (strbuf_read_file(buf, todo_file, 0) < 0)
48164850
return error_errno(_("could not read '%s'."), todo_file);

sequencer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,13 @@ int sequencer_make_script(struct repository *r, FILE *out, int argc,
146146
const char **argv,
147147
unsigned flags);
148148

149-
int sequencer_add_exec_commands(struct repository *r, const char *command);
149+
int sequencer_add_exec_commands(struct repository *r,
150+
struct string_list *commands);
150151
int transform_todo_file(struct repository *r, unsigned flags);
151152
int check_todo_list_from_file(struct repository *r);
152153
int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
153154
const char *shortrevisions, const char *onto_name,
154-
const char *onto, const char *orig_head, const char *cmd,
155+
const char *onto, const char *orig_head, struct string_list *commands,
155156
unsigned autosquash);
156157
int rearrange_squash(struct repository *r);
157158

0 commit comments

Comments
 (0)