sub-process: refactor handshake to common function

Refactor, into a common function, the version and capability negotiation
done when invoking a long-running process as a clean or smudge filter.
This will be useful for other Git code that needs to interact similarly
with a long-running process.

As you can see in the change to t0021, this commit changes the error
message reported when the long-running process does not introduce itself
with the expected "server"-terminated line. Originally, the error
message reports that the filter "does not support filter protocol
version 2", differentiating between the old single-file filter protocol
and the new multi-file filter protocol - I have updated it to something
more generic and useful.

Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jonathan Tan
2017-07-26 11:17:29 -07:00
committed by Junio C Hamano
parent 7e2e1bbb24
commit fa64a2fdbe
6 changed files with 138 additions and 90 deletions

View File

@ -513,78 +513,17 @@ static struct hashmap subprocess_map;
static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
{
int err, i;
struct cmd2process *entry = (struct cmd2process *)subprocess;
struct string_list cap_list = STRING_LIST_INIT_NODUP;
char *cap_buf;
const char *cap_name;
struct child_process *process = &subprocess->process;
const char *cmd = subprocess->cmd;
static const struct {
const char *name;
unsigned int cap;
} known_caps[] = {
static int versions[] = {2, 0};
static struct subprocess_capability capabilities[] = {
{ "clean", CAP_CLEAN },
{ "smudge", CAP_SMUDGE },
{ "delay", CAP_DELAY },
{ NULL, 0 }
};
sigchain_push(SIGPIPE, SIG_IGN);
err = packet_writel(process->in, "git-filter-client", "version=2", NULL);
if (err)
goto done;
err = strcmp(packet_read_line(process->out, NULL), "git-filter-server");
if (err) {
error("external filter '%s' does not support filter protocol version 2", cmd);
goto done;
}
err = strcmp(packet_read_line(process->out, NULL), "version=2");
if (err)
goto done;
err = packet_read_line(process->out, NULL) != NULL;
if (err)
goto done;
for (i = 0; i < ARRAY_SIZE(known_caps); ++i) {
err = packet_write_fmt_gently(
process->in, "capability=%s\n", known_caps[i].name);
if (err)
goto done;
}
err = packet_flush_gently(process->in);
if (err)
goto done;
for (;;) {
cap_buf = packet_read_line(process->out, NULL);
if (!cap_buf)
break;
string_list_split_in_place(&cap_list, cap_buf, '=', 1);
if (cap_list.nr != 2 || strcmp(cap_list.items[0].string, "capability"))
continue;
cap_name = cap_list.items[1].string;
i = ARRAY_SIZE(known_caps) - 1;
while (i >= 0 && strcmp(cap_name, known_caps[i].name))
i--;
if (i >= 0)
entry->supported_capabilities |= known_caps[i].cap;
else
warning("external filter '%s' requested unsupported filter capability '%s'",
cmd, cap_name);
string_list_clear(&cap_list, 0);
}
done:
sigchain_pop(SIGPIPE);
return err;
struct cmd2process *entry = (struct cmd2process *)subprocess;
return subprocess_handshake(subprocess, "git-filter", versions, NULL,
capabilities,
&entry->supported_capabilities);
}
static void handle_filter_error(const struct strbuf *filter_status,