Re: [RFC/PATCH v4 30/49] odb-helper: add read_object_process()
On 6/20/2017 3:55 AM, Christian Couder wrote: From: Ben PeartSigned-off-by: Ben Peart Signed-off-by: Christian Couder --- odb-helper.c | 202 --- odb-helper.h | 5 ++ sha1_file.c | 33 +- 3 files changed, 227 insertions(+), 13 deletions(-) diff --git a/odb-helper.c b/odb-helper.c index 5fb56c6135..20e83cb55a 100644 --- a/odb-helper.c +++ b/odb-helper.c @@ -4,6 +4,187 @@ #include "odb-helper.h" #include "run-command.h" #include "sha1-lookup.h" +#include "sub-process.h" +#include "pkt-line.h" +#include "sigchain.h" + +struct read_object_process { + struct subprocess_entry subprocess; + unsigned int supported_capabilities; +}; + +static int subprocess_map_initialized; +static struct hashmap subprocess_map; + +static void parse_capabilities(char *cap_buf, + unsigned int *supported_capabilities, + const char *process_name) +{ + struct string_list cap_list = STRING_LIST_INIT_NODUP; + + string_list_split_in_place(_list, cap_buf, '=', 1); + + if (cap_list.nr == 2 && !strcmp(cap_list.items[0].string, "capability")) { + const char *cap_name = cap_list.items[1].string; + + if (!strcmp(cap_name, "get")) { + *supported_capabilities |= ODB_HELPER_CAP_GET; + } else if (!strcmp(cap_name, "put")) { + *supported_capabilities |= ODB_HELPER_CAP_PUT; + } else if (!strcmp(cap_name, "have")) { + *supported_capabilities |= ODB_HELPER_CAP_HAVE; + } else { + warning("external process '%s' requested unsupported read-object capability '%s'", + process_name, cap_name); + } + } + + string_list_clear(_list, 0); +} + +static int start_read_object_fn(struct subprocess_entry *subprocess) +{ + int err; + struct read_object_process *entry = (struct read_object_process *)subprocess; + struct child_process *process = >process; + char *cap_buf; + + sigchain_push(SIGPIPE, SIG_IGN); + + err = packet_writel(process->in, "git-read-object-client", "version=1", NULL); + if (err) + goto done; + + err = strcmp(packet_read_line(process->out, NULL), "git-read-object-server"); + if (err) { + error("external process '%s' does not support read-object protocol version 1", subprocess->cmd); + goto done; + } + err = strcmp(packet_read_line(process->out, NULL), "version=1"); + if (err) + goto done; + err = packet_read_line(process->out, NULL) != NULL; + if (err) + goto done; + + err = packet_writel(process->in, "capability=get", NULL); + if (err) + goto done; + + while ((cap_buf = packet_read_line(process->out, NULL))) + parse_capabilities(cap_buf, >supported_capabilities, subprocess->cmd); + +done: + sigchain_pop(SIGPIPE); + + return err; +} + +static struct read_object_process *launch_read_object_process(const char *cmd) +{ + struct read_object_process *entry; + + if (!subprocess_map_initialized) { + subprocess_map_initialized = 1; + hashmap_init(_map, (hashmap_cmp_fn) cmd2process_cmp, 0); + entry = NULL; + } else { + entry = (struct read_object_process *)subprocess_find_entry(_map, cmd); + } + + fflush(NULL); + + if (!entry) { + entry = xmalloc(sizeof(*entry)); + entry->supported_capabilities = 0; + + if (subprocess_start(_map, >subprocess, cmd, start_read_object_fn)) { + free(entry); + return 0; + } + } + + return entry; +} + +static int check_object_process_error(int err, + const char *status, + struct read_object_process *entry, + const char *cmd, + unsigned int capability) +{ + if (!err) + return; + + if (!strcmp(status, "error")) { + /* The process signaled a problem with the file. */ + } else if (!strcmp(status, "notfound")) { + /* Object was not found */ + err = -1; + } else if (!strcmp(status, "abort")) { + /* +* The process signaled a permanent problem. Don't try to read +* objects with the same command for the lifetime of the current +* Git process. +*/ + if (capability) + entry->supported_capabilities &= ~capability; + } else { +
[RFC/PATCH v4 30/49] odb-helper: add read_object_process()
From: Ben PeartSigned-off-by: Ben Peart Signed-off-by: Christian Couder --- odb-helper.c | 202 --- odb-helper.h | 5 ++ sha1_file.c | 33 +- 3 files changed, 227 insertions(+), 13 deletions(-) diff --git a/odb-helper.c b/odb-helper.c index 5fb56c6135..20e83cb55a 100644 --- a/odb-helper.c +++ b/odb-helper.c @@ -4,6 +4,187 @@ #include "odb-helper.h" #include "run-command.h" #include "sha1-lookup.h" +#include "sub-process.h" +#include "pkt-line.h" +#include "sigchain.h" + +struct read_object_process { + struct subprocess_entry subprocess; + unsigned int supported_capabilities; +}; + +static int subprocess_map_initialized; +static struct hashmap subprocess_map; + +static void parse_capabilities(char *cap_buf, + unsigned int *supported_capabilities, + const char *process_name) +{ + struct string_list cap_list = STRING_LIST_INIT_NODUP; + + string_list_split_in_place(_list, cap_buf, '=', 1); + + if (cap_list.nr == 2 && !strcmp(cap_list.items[0].string, "capability")) { + const char *cap_name = cap_list.items[1].string; + + if (!strcmp(cap_name, "get")) { + *supported_capabilities |= ODB_HELPER_CAP_GET; + } else if (!strcmp(cap_name, "put")) { + *supported_capabilities |= ODB_HELPER_CAP_PUT; + } else if (!strcmp(cap_name, "have")) { + *supported_capabilities |= ODB_HELPER_CAP_HAVE; + } else { + warning("external process '%s' requested unsupported read-object capability '%s'", + process_name, cap_name); + } + } + + string_list_clear(_list, 0); +} + +static int start_read_object_fn(struct subprocess_entry *subprocess) +{ + int err; + struct read_object_process *entry = (struct read_object_process *)subprocess; + struct child_process *process = >process; + char *cap_buf; + + sigchain_push(SIGPIPE, SIG_IGN); + + err = packet_writel(process->in, "git-read-object-client", "version=1", NULL); + if (err) + goto done; + + err = strcmp(packet_read_line(process->out, NULL), "git-read-object-server"); + if (err) { + error("external process '%s' does not support read-object protocol version 1", subprocess->cmd); + goto done; + } + err = strcmp(packet_read_line(process->out, NULL), "version=1"); + if (err) + goto done; + err = packet_read_line(process->out, NULL) != NULL; + if (err) + goto done; + + err = packet_writel(process->in, "capability=get", NULL); + if (err) + goto done; + + while ((cap_buf = packet_read_line(process->out, NULL))) + parse_capabilities(cap_buf, >supported_capabilities, subprocess->cmd); + +done: + sigchain_pop(SIGPIPE); + + return err; +} + +static struct read_object_process *launch_read_object_process(const char *cmd) +{ + struct read_object_process *entry; + + if (!subprocess_map_initialized) { + subprocess_map_initialized = 1; + hashmap_init(_map, (hashmap_cmp_fn) cmd2process_cmp, 0); + entry = NULL; + } else { + entry = (struct read_object_process *)subprocess_find_entry(_map, cmd); + } + + fflush(NULL); + + if (!entry) { + entry = xmalloc(sizeof(*entry)); + entry->supported_capabilities = 0; + + if (subprocess_start(_map, >subprocess, cmd, start_read_object_fn)) { + free(entry); + return 0; + } + } + + return entry; +} + +static int check_object_process_error(int err, + const char *status, + struct read_object_process *entry, + const char *cmd, + unsigned int capability) +{ + if (!err) + return; + + if (!strcmp(status, "error")) { + /* The process signaled a problem with the file. */ + } else if (!strcmp(status, "notfound")) { + /* Object was not found */ + err = -1; + } else if (!strcmp(status, "abort")) { + /* +* The process signaled a permanent problem. Don't try to read +* objects with the same command for the lifetime of the current +* Git process. +*/ + if (capability) + entry->supported_capabilities &= ~capability; + } else { + /* +* Something went wrong with