diff options
Diffstat (limited to 'convert.c')
-rw-r--r-- | convert.c | 218 |
1 files changed, 63 insertions, 155 deletions
@@ -1,9 +1,12 @@ +#define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" +#include "config.h" #include "attr.h" #include "run-command.h" #include "quote.h" #include "sigchain.h" #include "pkt-line.h" +#include "sub-process.h" /* * convert.c - convert a file when checking it out and checking it in. @@ -133,11 +136,12 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si } } -const char *get_cached_convert_stats_ascii(const char *path) +const char *get_cached_convert_stats_ascii(const struct index_state *istate, + const char *path) { const char *ret; unsigned long sz; - void *data = read_blob_data_from_cache(path, &sz); + void *data = read_blob_data_from_index(istate, path, &sz); ret = gather_convert_stats_ascii(data, sz); free(data); return ret; @@ -216,13 +220,13 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action, } } -static int has_cr_in_index(const char *path) +static int has_cr_in_index(const struct index_state *istate, const char *path) { unsigned long sz; void *data; int has_cr; - data = read_blob_data_from_cache(path, &sz); + data = read_blob_data_from_index(istate, path, &sz); if (!data) return 0; has_cr = memchr(data, '\r', sz) != NULL; @@ -252,7 +256,8 @@ static int will_convert_lf_to_crlf(size_t len, struct text_stat *stats, } -static int crlf_to_git(const char *path, const char *src, size_t len, +static int crlf_to_git(const struct index_state *istate, + const char *path, const char *src, size_t len, struct strbuf *buf, enum crlf_action crlf_action, enum safe_crlf checksafe) { @@ -284,7 +289,8 @@ static int crlf_to_git(const char *path, const char *src, size_t len, * unless we want to renormalize in a merge or * cherry-pick. */ - if ((checksafe != SAFE_CRLF_RENORMALIZE) && has_cr_in_index(path)) + if ((checksafe != SAFE_CRLF_RENORMALIZE) && + has_cr_in_index(istate, path)) convert_crlf_into_lf = 0; } if ((checksafe == SAFE_CRLF_WARN || @@ -497,126 +503,26 @@ static int apply_single_file_filter(const char *path, const char *src, size_t le #define CAP_SMUDGE (1u<<1) struct cmd2process { - struct hashmap_entry ent; /* must be the first member! */ + struct subprocess_entry subprocess; /* must be the first member! */ unsigned int supported_capabilities; - const char *cmd; - struct child_process process; }; -static int cmd_process_map_initialized; -static struct hashmap cmd_process_map; - -static int cmd2process_cmp(const struct cmd2process *e1, - const struct cmd2process *e2, - const void *unused) -{ - return strcmp(e1->cmd, e2->cmd); -} - -static struct cmd2process *find_multi_file_filter_entry(struct hashmap *hashmap, const char *cmd) -{ - struct cmd2process key; - hashmap_entry_init(&key, strhash(cmd)); - key.cmd = cmd; - return hashmap_get(hashmap, &key, NULL); -} - -static int packet_write_list(int fd, const char *line, ...) -{ - va_list args; - int err; - va_start(args, line); - for (;;) { - if (!line) - break; - if (strlen(line) > LARGE_PACKET_DATA_MAX) - return -1; - err = packet_write_fmt_gently(fd, "%s\n", line); - if (err) - return err; - line = va_arg(args, const char*); - } - va_end(args); - return packet_flush_gently(fd); -} - -static void read_multi_file_filter_status(int fd, struct strbuf *status) -{ - struct strbuf **pair; - char *line; - for (;;) { - line = packet_read_line(fd, NULL); - if (!line) - break; - pair = strbuf_split_str(line, '=', 2); - if (pair[0] && pair[0]->len && pair[1]) { - /* the last "status=<foo>" line wins */ - if (!strcmp(pair[0]->buf, "status=")) { - strbuf_reset(status); - strbuf_addbuf(status, pair[1]); - } - } - strbuf_list_free(pair); - } -} - -static void kill_multi_file_filter(struct hashmap *hashmap, struct cmd2process *entry) -{ - if (!entry) - return; - - entry->process.clean_on_exit = 0; - kill(entry->process.pid, SIGTERM); - finish_command(&entry->process); - - hashmap_remove(hashmap, entry, NULL); - free(entry); -} +static int subprocess_map_initialized; +static struct hashmap subprocess_map; -static void stop_multi_file_filter(struct child_process *process) -{ - sigchain_push(SIGPIPE, SIG_IGN); - /* Closing the pipe signals the filter to initiate a shutdown. */ - close(process->in); - close(process->out); - sigchain_pop(SIGPIPE); - /* Finish command will wait until the shutdown is complete. */ - finish_command(process); -} - -static struct cmd2process *start_multi_file_filter(struct hashmap *hashmap, const char *cmd) +static int start_multi_file_filter_fn(struct subprocess_entry *subprocess) { int err; - struct cmd2process *entry; - struct child_process *process; - const char *argv[] = { cmd, NULL }; + struct cmd2process *entry = (struct cmd2process *)subprocess; struct string_list cap_list = STRING_LIST_INIT_NODUP; char *cap_buf; const char *cap_name; - - entry = xmalloc(sizeof(*entry)); - entry->cmd = cmd; - entry->supported_capabilities = 0; - process = &entry->process; - - child_process_init(process); - process->argv = argv; - process->use_shell = 1; - process->in = -1; - process->out = -1; - process->clean_on_exit = 1; - process->clean_on_exit_handler = stop_multi_file_filter; - - if (start_command(process)) { - error("cannot fork to run external filter '%s'", cmd); - return NULL; - } - - hashmap_entry_init(entry, strhash(cmd)); + struct child_process *process = &subprocess->process; + const char *cmd = subprocess->cmd; sigchain_push(SIGPIPE, SIG_IGN); - err = packet_write_list(process->in, "git-filter-client", "version=2", NULL); + err = packet_writel(process->in, "git-filter-client", "version=2", NULL); if (err) goto done; @@ -632,7 +538,7 @@ static struct cmd2process *start_multi_file_filter(struct hashmap *hashmap, cons if (err) goto done; - err = packet_write_list(process->in, "capability=clean", "capability=smudge", NULL); + err = packet_writel(process->in, "capability=clean", "capability=smudge", NULL); for (;;) { cap_buf = packet_read_line(process->out, NULL); @@ -661,14 +567,7 @@ static struct cmd2process *start_multi_file_filter(struct hashmap *hashmap, cons done: sigchain_pop(SIGPIPE); - if (err || errno == EPIPE) { - error("initialization for external filter '%s' failed", cmd); - kill_multi_file_filter(hashmap, entry); - return NULL; - } - - hashmap_add(hashmap, entry); - return entry; + return err; } static int apply_multi_file_filter(const char *path, const char *src, size_t len, @@ -682,22 +581,26 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len struct strbuf filter_status = STRBUF_INIT; const char *filter_type; - if (!cmd_process_map_initialized) { - cmd_process_map_initialized = 1; - hashmap_init(&cmd_process_map, (hashmap_cmp_fn) cmd2process_cmp, 0); + if (!subprocess_map_initialized) { + subprocess_map_initialized = 1; + hashmap_init(&subprocess_map, (hashmap_cmp_fn) cmd2process_cmp, 0); entry = NULL; } else { - entry = find_multi_file_filter_entry(&cmd_process_map, cmd); + entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd); } fflush(NULL); if (!entry) { - entry = start_multi_file_filter(&cmd_process_map, cmd); - if (!entry) + entry = xmalloc(sizeof(*entry)); + entry->supported_capabilities = 0; + + if (subprocess_start(&subprocess_map, &entry->subprocess, cmd, start_multi_file_filter_fn)) { + free(entry); return 0; + } } - process = &entry->process; + process = &entry->subprocess.process; if (!(wanted_capability & entry->supported_capabilities)) return 0; @@ -737,7 +640,10 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len if (err) goto done; - read_multi_file_filter_status(process->out, &filter_status); + err = subprocess_read_status(process->out, &filter_status); + if (err) + goto done; + err = strcmp(filter_status.buf, "success"); if (err) goto done; @@ -746,13 +652,16 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len if (err) goto done; - read_multi_file_filter_status(process->out, &filter_status); + err = subprocess_read_status(process->out, &filter_status); + if (err) + goto done; + err = strcmp(filter_status.buf, "success"); done: sigchain_pop(SIGPIPE); - if (err || errno == EPIPE) { + if (err) { if (!strcmp(filter_status.buf, "error")) { /* The filter signaled a problem with the file. */ } else if (!strcmp(filter_status.buf, "abort")) { @@ -768,7 +677,8 @@ done: * Force shutdown and restart if another blob requires filtering. */ error("external filter '%s' failed", cmd); - kill_multi_file_filter(&cmd_process_map, entry); + subprocess_stop(&subprocess_map, &entry->subprocess); + free(entry); } } else { strbuf_swap(dst, &nbuf); @@ -1028,7 +938,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len, return 1; } -static enum crlf_action git_path_check_crlf(struct git_attr_check *check) +static enum crlf_action git_path_check_crlf(struct attr_check_item *check) { const char *value = check->value; @@ -1045,7 +955,7 @@ static enum crlf_action git_path_check_crlf(struct git_attr_check *check) return CRLF_UNDEFINED; } -static enum eol git_path_check_eol(struct git_attr_check *check) +static enum eol git_path_check_eol(struct attr_check_item *check) { const char *value = check->value; @@ -1058,7 +968,7 @@ static enum eol git_path_check_eol(struct git_attr_check *check) return EOL_UNSET; } -static struct convert_driver *git_path_check_convert(struct git_attr_check *check) +static struct convert_driver *git_path_check_convert(struct attr_check_item *check) { const char *value = check->value; struct convert_driver *drv; @@ -1071,7 +981,7 @@ static struct convert_driver *git_path_check_convert(struct git_attr_check *chec return NULL; } -static int git_path_check_ident(struct git_attr_check *check) +static int git_path_check_ident(struct attr_check_item *check) { const char *value = check->value; @@ -1085,24 +995,19 @@ struct conv_attrs { int ident; }; -static const char *conv_attr_name[] = { - "crlf", "ident", "filter", "eol", "text", -}; -#define NUM_CONV_ATTRS ARRAY_SIZE(conv_attr_name) - static void convert_attrs(struct conv_attrs *ca, const char *path) { - int i; - static struct git_attr_check ccheck[NUM_CONV_ATTRS]; + static struct attr_check *check; - if (!ccheck[0].attr) { - for (i = 0; i < NUM_CONV_ATTRS; i++) - ccheck[i].attr = git_attr(conv_attr_name[i]); + if (!check) { + check = attr_check_initl("crlf", "ident", "filter", + "eol", "text", NULL); user_convert_tail = &user_convert; git_config(read_convert_config, NULL); } - if (!git_check_attr(path, NUM_CONV_ATTRS, ccheck)) { + if (!git_check_attr(path, check)) { + struct attr_check_item *ccheck = check->items; ca->crlf_action = git_path_check_crlf(ccheck + 4); if (ca->crlf_action == CRLF_UNDEFINED) ca->crlf_action = git_path_check_crlf(ccheck + 0); @@ -1181,7 +1086,8 @@ const char *get_convert_attr_ascii(const char *path) return ""; } -int convert_to_git(const char *path, const char *src, size_t len, +int convert_to_git(const struct index_state *istate, + const char *path, const char *src, size_t len, struct strbuf *dst, enum safe_crlf checksafe) { int ret = 0; @@ -1197,7 +1103,7 @@ int convert_to_git(const char *path, const char *src, size_t len, src = dst->buf; len = dst->len; } - ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe); + ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, checksafe); if (ret && dst) { src = dst->buf; len = dst->len; @@ -1205,7 +1111,8 @@ int convert_to_git(const char *path, const char *src, size_t len, return ret | ident_to_git(path, src, len, dst, ca.ident); } -void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst, +void convert_to_git_filter_fd(const struct index_state *istate, + const char *path, int fd, struct strbuf *dst, enum safe_crlf checksafe) { struct conv_attrs ca; @@ -1217,7 +1124,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst, if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN)) die("%s: clean filter '%s' failed", path, ca.drv->name); - crlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe); + crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe); ident_to_git(path, dst->buf, dst->len, dst, ca.ident); } @@ -1260,14 +1167,15 @@ int convert_to_working_tree(const char *path, const char *src, size_t len, struc return convert_to_working_tree_internal(path, src, len, dst, 0); } -int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst) +int renormalize_buffer(const struct index_state *istate, const char *path, + const char *src, size_t len, struct strbuf *dst) { int ret = convert_to_working_tree_internal(path, src, len, dst, 1); if (ret) { src = dst->buf; len = dst->len; } - return ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE); + return ret | convert_to_git(istate, path, src, len, dst, SAFE_CRLF_RENORMALIZE); } /***************************************************************** |