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:
committed by
Junio C Hamano
parent
7e2e1bbb24
commit
fa64a2fdbe
104
sub-process.c
104
sub-process.c
@ -105,3 +105,107 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co
|
||||
hashmap_add(hashmap, entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handshake_version(struct child_process *process,
|
||||
const char *welcome_prefix, int *versions,
|
||||
int *chosen_version)
|
||||
{
|
||||
int version_scratch;
|
||||
int i;
|
||||
char *line;
|
||||
const char *p;
|
||||
|
||||
if (!chosen_version)
|
||||
chosen_version = &version_scratch;
|
||||
|
||||
if (packet_write_fmt_gently(process->in, "%s-client\n",
|
||||
welcome_prefix))
|
||||
return error("Could not write client identification");
|
||||
for (i = 0; versions[i]; i++) {
|
||||
if (packet_write_fmt_gently(process->in, "version=%d\n",
|
||||
versions[i]))
|
||||
return error("Could not write requested version");
|
||||
}
|
||||
if (packet_flush_gently(process->in))
|
||||
return error("Could not write flush packet");
|
||||
|
||||
if (!(line = packet_read_line(process->out, NULL)) ||
|
||||
!skip_prefix(line, welcome_prefix, &p) ||
|
||||
strcmp(p, "-server"))
|
||||
return error("Unexpected line '%s', expected %s-server",
|
||||
line ? line : "<flush packet>", welcome_prefix);
|
||||
if (!(line = packet_read_line(process->out, NULL)) ||
|
||||
!skip_prefix(line, "version=", &p) ||
|
||||
strtol_i(p, 10, chosen_version))
|
||||
return error("Unexpected line '%s', expected version",
|
||||
line ? line : "<flush packet>");
|
||||
if ((line = packet_read_line(process->out, NULL)))
|
||||
return error("Unexpected line '%s', expected flush", line);
|
||||
|
||||
/* Check to make sure that the version received is supported */
|
||||
for (i = 0; versions[i]; i++) {
|
||||
if (versions[i] == *chosen_version)
|
||||
break;
|
||||
}
|
||||
if (!versions[i])
|
||||
return error("Version %d not supported", *chosen_version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handshake_capabilities(struct child_process *process,
|
||||
struct subprocess_capability *capabilities,
|
||||
unsigned int *supported_capabilities)
|
||||
{
|
||||
int i;
|
||||
char *line;
|
||||
|
||||
for (i = 0; capabilities[i].name; i++) {
|
||||
if (packet_write_fmt_gently(process->in, "capability=%s\n",
|
||||
capabilities[i].name))
|
||||
return error("Could not write requested capability");
|
||||
}
|
||||
if (packet_flush_gently(process->in))
|
||||
return error("Could not write flush packet");
|
||||
|
||||
while ((line = packet_read_line(process->out, NULL))) {
|
||||
const char *p;
|
||||
if (!skip_prefix(line, "capability=", &p))
|
||||
continue;
|
||||
|
||||
for (i = 0;
|
||||
capabilities[i].name && strcmp(p, capabilities[i].name);
|
||||
i++)
|
||||
;
|
||||
if (capabilities[i].name) {
|
||||
if (supported_capabilities)
|
||||
*supported_capabilities |= capabilities[i].flag;
|
||||
} else {
|
||||
warning("external filter requested unsupported filter capability '%s'",
|
||||
p);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int subprocess_handshake(struct subprocess_entry *entry,
|
||||
const char *welcome_prefix,
|
||||
int *versions,
|
||||
int *chosen_version,
|
||||
struct subprocess_capability *capabilities,
|
||||
unsigned int *supported_capabilities)
|
||||
{
|
||||
int retval;
|
||||
struct child_process *process = &entry->process;
|
||||
|
||||
sigchain_push(SIGPIPE, SIG_IGN);
|
||||
|
||||
retval = handshake_version(process, welcome_prefix, versions,
|
||||
chosen_version) ||
|
||||
handshake_capabilities(process, capabilities,
|
||||
supported_capabilities);
|
||||
|
||||
sigchain_pop(SIGPIPE);
|
||||
return retval;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user