summaryrefslogtreecommitdiff
path: root/sequencer.c
diff options
context:
space:
mode:
authorJohannes Schindelin <johannes.schindelin@gmx.de>2017-01-02 16:26:47 +0100
committerJunio C Hamano <gitster@pobox.com>2017-01-09 14:57:29 -0800
commit311af5266b27523742e8be9d8297ea475137cfb5 (patch)
tree89f64758ee9f5d5bde39292681a6cabdb673a9eb /sequencer.c
parent56dc3ab04bf0f7bb8c73ebbba47469bdf8be8ac4 (diff)
downloadgit-311af5266b27523742e8be9d8297ea475137cfb5.tar.gz
sequencer (rebase -i): implement the 'exec' command
The 'exec' command is a little special among rebase -i's commands, as it does *not* have a SHA-1 as first parameter. Instead, everything after the `exec` command is treated as command-line to execute. Let's reuse the arg/arg_len fields of the todo_item structure (which hold the oneline for pick/edit commands) to point to the command-line. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'sequencer.c')
-rw-r--r--sequencer.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/sequencer.c b/sequencer.c
index b138a3906c..e9c10d7fe5 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -18,6 +18,7 @@
#include "quote.h"
#include "trailer.h"
#include "log-tree.h"
+#include "wt-status.h"
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
@@ -632,6 +633,8 @@ enum todo_command {
TODO_PICK = 0,
TODO_REVERT,
TODO_EDIT,
+ /* commands that do something else than handling a single commit */
+ TODO_EXEC,
/* commands that do nothing but are counted for reporting progress */
TODO_NOOP
};
@@ -640,6 +643,7 @@ static const char *todo_command_strings[] = {
"pick",
"revert",
"edit",
+ "exec",
"noop"
};
@@ -938,6 +942,12 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
return -1;
bol += padding;
+ if (item->command == TODO_EXEC) {
+ item->arg = bol;
+ item->arg_len = (int)(eol - bol);
+ return 0;
+ }
+
end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
saved = *end_of_object_name;
*end_of_object_name = '\0';
@@ -1397,6 +1407,46 @@ static int error_with_patch(struct commit *commit,
return exit_code;
}
+static int do_exec(const char *command_line)
+{
+ const char *child_argv[] = { NULL, NULL };
+ int dirty, status;
+
+ fprintf(stderr, "Executing: %s\n", command_line);
+ child_argv[0] = command_line;
+ status = run_command_v_opt(child_argv, RUN_USING_SHELL);
+
+ /* force re-reading of the cache */
+ if (discard_cache() < 0 || read_cache() < 0)
+ return error(_("could not read index"));
+
+ dirty = require_clean_work_tree("rebase", NULL, 1, 1);
+
+ if (status) {
+ warning(_("execution failed: %s\n%s"
+ "You can fix the problem, and then run\n"
+ "\n"
+ " git rebase --continue\n"
+ "\n"),
+ command_line,
+ dirty ? N_("and made changes to the index and/or the "
+ "working tree\n") : "");
+ if (status == 127)
+ /* command not found */
+ status = 1;
+ } else if (dirty) {
+ warning(_("execution succeeded: %s\nbut "
+ "left changes to the index and/or the working tree\n"
+ "Commit or stash your changes, and then run\n"
+ "\n"
+ " git rebase --continue\n"
+ "\n"), command_line);
+ status = 1;
+ }
+
+ return status;
+}
+
static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
{
int res = 0;
@@ -1425,6 +1475,13 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
item->arg, item->arg_len, opts, res,
!res);
}
+ } else if (item->command == TODO_EXEC) {
+ char *end_of_arg = (char *)(item->arg + item->arg_len);
+ int saved = *end_of_arg;
+
+ *end_of_arg = '\0';
+ res = do_exec(item->arg);
+ *end_of_arg = saved;
} else if (!is_noop(item->command))
return error(_("unknown command %d"), item->command);