From: Junio C Hamano Date: Fri, 11 Aug 2017 20:27:01 +0000 (-0700) Subject: Merge branch 'sb/hashmap-cleanup' X-Git-Tag: v2.15.0-rc0~198 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/55c965f3a27b3a36f84c56b6eba8ac5c95ff558a?ds=inline;hp=-c Merge branch 'sb/hashmap-cleanup' Many uses of comparision callback function the hashmap API uses cast the callback function type when registering it to hashmap_init(), which defeats the compile time type checking when the callback interface changes (e.g. gaining more parameters). The callback implementations have been updated to take "void *" pointers and cast them to the type they expect instead. * sb/hashmap-cleanup: t/helper/test-hashmap: use custom data instead of duplicate cmp functions name-hash.c: drop hashmap_cmp_fn cast submodule-config.c: drop hashmap_cmp_fn cast remote.c: drop hashmap_cmp_fn cast patch-ids.c: drop hashmap_cmp_fn cast convert/sub-process: drop cast to hashmap_cmp_fn config.c: drop hashmap_cmp_fn cast builtin/describe: drop hashmap_cmp_fn cast builtin/difftool.c: drop hashmap_cmp_fn cast attr.c: drop hashmap_cmp_fn cast --- 55c965f3a27b3a36f84c56b6eba8ac5c95ff558a diff --combined builtin/describe.c index 89ea1cdd60,f2f2edf935..9c13c6817b --- a/builtin/describe.c +++ b/builtin/describe.c @@@ -55,10 -55,13 +55,13 @@@ static const char *prio_names[] = }; static int commit_name_cmp(const void *unused_cmp_data, - const struct commit_name *cn1, - const struct commit_name *cn2, + const void *entry, + const void *entry_or_key, const void *peeled) { + const struct commit_name *cn1 = entry; + const struct commit_name *cn2 = entry_or_key; + return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled); } @@@ -145,7 -148,7 +148,7 @@@ static int get_name(const char *path, c return 0; for_each_string_list_item(item, &exclude_patterns) { - if (!wildmatch(item->string, path + 10, 0, NULL)) + if (!wildmatch(item->string, path + 10, 0)) return 0; } } @@@ -161,7 -164,7 +164,7 @@@ return 0; for_each_string_list_item(item, &patterns) { - if (!wildmatch(item->string, path + 10, 0, NULL)) + if (!wildmatch(item->string, path + 10, 0)) break; /* If we get here, no pattern matched. */ @@@ -503,7 -506,7 +506,7 @@@ int cmd_describe(int argc, const char * return cmd_name_rev(args.argc, args.argv, prefix); } - hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, NULL, 0); + hashmap_init(&names, commit_name_cmp, NULL, 0); for_each_rawref(get_name, NULL); if (!names.size && !always) die(_("No names found, cannot describe anything.")); diff --combined config.c index e04500d13b,30ff700629..9ec8c44882 --- a/config.c +++ b/config.c @@@ -7,7 -7,6 +7,7 @@@ */ #include "cache.h" #include "config.h" +#include "repository.h" #include "lockfile.h" #include "exec_cmd.h" #include "strbuf.h" @@@ -16,7 -15,6 +16,7 @@@ #include "string-list.h" #include "utf8.h" #include "dir.h" +#include "color.h" struct config_source { struct config_source *prev; @@@ -74,6 -72,13 +74,6 @@@ static int core_compression_seen static int pack_compression_seen; static int zlib_compression_seen; -/* - * Default config_set that contains key-value pairs from the usual set of config - * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG - * config file and the global /etc/gitconfig) - */ -static struct config_set the_config_set; - static int config_file_fgetc(struct config_source *conf) { return getc_unlocked(conf->u.file); @@@ -239,7 -244,7 +239,7 @@@ again } ret = !wildmatch(pattern.buf + prefix, text.buf + prefix, - icase ? WM_CASEFOLD : 0, NULL); + icase ? WM_CASEFOLD : 0); if (!ret && !already_tried_absolute) { /* @@@ -1351,9 -1356,6 +1351,9 @@@ int git_default_config(const char *var if (starts_with(var, "advice.")) return git_default_advice_config(var, value); + if (git_color_config(var, value, dummy) < 0) + return -1; + if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) { pager_use_color = git_config_bool(var,value); return 0; @@@ -1464,9 -1466,9 +1464,9 @@@ int git_config_from_mem(config_fn_t fn return do_config_from(&top, fn, data); } -int git_config_from_blob_sha1(config_fn_t fn, +int git_config_from_blob_oid(config_fn_t fn, const char *name, - const unsigned char *sha1, + const struct object_id *oid, void *data) { enum object_type type; @@@ -1474,7 -1476,7 +1474,7 @@@ unsigned long size; int ret; - buf = read_sha1_file(sha1, &type, &size); + buf = read_sha1_file(oid->hash, &type, &size); if (!buf) return error("unable to load config blob object '%s'", name); if (type != OBJ_BLOB) { @@@ -1492,11 -1494,11 +1492,11 @@@ static int git_config_from_blob_ref(con const char *name, void *data) { - unsigned char sha1[20]; + struct object_id oid; - if (get_sha1(name, sha1) < 0) + if (get_oid(name, &oid) < 0) return error("unable to resolve config blob '%s'", name); - return git_config_from_blob_sha1(fn, name, sha1, data); + return git_config_from_blob_oid(fn, name, &oid, data); } const char *git_etc_gitconfig(void) @@@ -1602,6 -1604,31 +1602,6 @@@ int config_with_options(config_fn_t fn return do_git_config_sequence(opts, fn, data); } -static void git_config_raw(config_fn_t fn, void *data) -{ - struct config_options opts = {0}; - - opts.respect_includes = 1; - if (have_git_dir()) { - opts.commondir = get_git_common_dir(); - opts.git_dir = get_git_dir(); - } - - if (config_with_options(fn, data, NULL, &opts) < 0) - /* - * config_with_options() normally returns only - * zero, as most errors are fatal, and - * non-fatal potential errors are guarded by "if" - * statements that are entered only when no error is - * possible. - * - * If we ever encounter a non-fatal error, it means - * something went really wrong and we should stop - * immediately. - */ - die(_("unknown error occurred while reading the configuration files")); -} - static void configset_iter(struct config_set *cs, config_fn_t fn, void *data) { int i, value_index; @@@ -1655,6 -1682,14 +1655,6 @@@ void read_early_config(config_fn_t cb, strbuf_release(&gitdir); } -static void git_config_check_init(void); - -void git_config(config_fn_t fn, void *data) -{ - git_config_check_init(); - configset_iter(&the_config_set, fn, data); -} - static struct config_set_element *configset_find_element(struct config_set *cs, const char *key) { struct config_set_element k; @@@ -1719,17 -1754,19 +1719,19 @@@ static int configset_add_value(struct c } static int config_set_element_cmp(const void *unused_cmp_data, - const struct config_set_element *e1, - const struct config_set_element *e2, + const void *entry, + const void *entry_or_key, const void *unused_keydata) { + const struct config_set_element *e1 = entry; + const struct config_set_element *e2 = entry_or_key; + return strcmp(e1->key, e2->key); } void git_configset_init(struct config_set *cs) { - hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp, - NULL, 0); + hashmap_init(&cs->config_hash, config_set_element_cmp, NULL, 0); cs->hash_initialized = 1; cs->list.nr = 0; cs->list.alloc = 0; @@@ -1867,194 -1904,87 +1869,194 @@@ int git_configset_get_pathname(struct c return 1; } -static void git_config_check_init(void) +/* Functions use to read configuration from a repository */ +static void repo_read_config(struct repository *repo) { - if (the_config_set.hash_initialized) + struct config_options opts; + + opts.respect_includes = 1; + opts.commondir = repo->commondir; + opts.git_dir = repo->gitdir; + + if (!repo->config) + repo->config = xcalloc(1, sizeof(struct config_set)); + else + git_configset_clear(repo->config); + + git_configset_init(repo->config); + + if (config_with_options(config_set_callback, repo->config, NULL, &opts) < 0) + /* + * config_with_options() normally returns only + * zero, as most errors are fatal, and + * non-fatal potential errors are guarded by "if" + * statements that are entered only when no error is + * possible. + * + * If we ever encounter a non-fatal error, it means + * something went really wrong and we should stop + * immediately. + */ + die(_("unknown error occurred while reading the configuration files")); +} + +static void git_config_check_init(struct repository *repo) +{ + if (repo->config && repo->config->hash_initialized) return; - git_configset_init(&the_config_set); - git_config_raw(config_set_callback, &the_config_set); + repo_read_config(repo); } -void git_config_clear(void) +static void repo_config_clear(struct repository *repo) { - if (!the_config_set.hash_initialized) + if (!repo->config || !repo->config->hash_initialized) return; - git_configset_clear(&the_config_set); + git_configset_clear(repo->config); } -int git_config_get_value(const char *key, const char **value) +void repo_config(struct repository *repo, config_fn_t fn, void *data) { - git_config_check_init(); - return git_configset_get_value(&the_config_set, key, value); + git_config_check_init(repo); + configset_iter(repo->config, fn, data); } -const struct string_list *git_config_get_value_multi(const char *key) +int repo_config_get_value(struct repository *repo, + const char *key, const char **value) { - git_config_check_init(); - return git_configset_get_value_multi(&the_config_set, key); + git_config_check_init(repo); + return git_configset_get_value(repo->config, key, value); } -int git_config_get_string_const(const char *key, const char **dest) +const struct string_list *repo_config_get_value_multi(struct repository *repo, + const char *key) +{ + git_config_check_init(repo); + return git_configset_get_value_multi(repo->config, key); +} + +int repo_config_get_string_const(struct repository *repo, + const char *key, const char **dest) { int ret; - git_config_check_init(); - ret = git_configset_get_string_const(&the_config_set, key, dest); + git_config_check_init(repo); + ret = git_configset_get_string_const(repo->config, key, dest); if (ret < 0) git_die_config(key, NULL); return ret; } +int repo_config_get_string(struct repository *repo, + const char *key, char **dest) +{ + git_config_check_init(repo); + return repo_config_get_string_const(repo, key, (const char **)dest); +} + +int repo_config_get_int(struct repository *repo, + const char *key, int *dest) +{ + git_config_check_init(repo); + return git_configset_get_int(repo->config, key, dest); +} + +int repo_config_get_ulong(struct repository *repo, + const char *key, unsigned long *dest) +{ + git_config_check_init(repo); + return git_configset_get_ulong(repo->config, key, dest); +} + +int repo_config_get_bool(struct repository *repo, + const char *key, int *dest) +{ + git_config_check_init(repo); + return git_configset_get_bool(repo->config, key, dest); +} + +int repo_config_get_bool_or_int(struct repository *repo, + const char *key, int *is_bool, int *dest) +{ + git_config_check_init(repo); + return git_configset_get_bool_or_int(repo->config, key, is_bool, dest); +} + +int repo_config_get_maybe_bool(struct repository *repo, + const char *key, int *dest) +{ + git_config_check_init(repo); + return git_configset_get_maybe_bool(repo->config, key, dest); +} + +int repo_config_get_pathname(struct repository *repo, + const char *key, const char **dest) +{ + int ret; + git_config_check_init(repo); + ret = git_configset_get_pathname(repo->config, key, dest); + if (ret < 0) + git_die_config(key, NULL); + return ret; +} + +/* Functions used historically to read configuration from 'the_repository' */ +void git_config(config_fn_t fn, void *data) +{ + repo_config(the_repository, fn, data); +} + +void git_config_clear(void) +{ + repo_config_clear(the_repository); +} + +int git_config_get_value(const char *key, const char **value) +{ + return repo_config_get_value(the_repository, key, value); +} + +const struct string_list *git_config_get_value_multi(const char *key) +{ + return repo_config_get_value_multi(the_repository, key); +} + +int git_config_get_string_const(const char *key, const char **dest) +{ + return repo_config_get_string_const(the_repository, key, dest); +} + int git_config_get_string(const char *key, char **dest) { - git_config_check_init(); - return git_config_get_string_const(key, (const char **)dest); + return repo_config_get_string(the_repository, key, dest); } int git_config_get_int(const char *key, int *dest) { - git_config_check_init(); - return git_configset_get_int(&the_config_set, key, dest); + return repo_config_get_int(the_repository, key, dest); } int git_config_get_ulong(const char *key, unsigned long *dest) { - git_config_check_init(); - return git_configset_get_ulong(&the_config_set, key, dest); + return repo_config_get_ulong(the_repository, key, dest); } int git_config_get_bool(const char *key, int *dest) { - git_config_check_init(); - return git_configset_get_bool(&the_config_set, key, dest); + return repo_config_get_bool(the_repository, key, dest); } int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest) { - git_config_check_init(); - return git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest); + return repo_config_get_bool_or_int(the_repository, key, is_bool, dest); } int git_config_get_maybe_bool(const char *key, int *dest) { - git_config_check_init(); - return git_configset_get_maybe_bool(&the_config_set, key, dest); + return repo_config_get_maybe_bool(the_repository, key, dest); } int git_config_get_pathname(const char *key, const char **dest) { - int ret; - git_config_check_init(); - ret = git_configset_get_pathname(&the_config_set, key, dest); - if (ret < 0) - git_die_config(key, NULL); - return ret; + return repo_config_get_pathname(the_repository, key, dest); } int git_config_get_expiry(const char *key, const char **output) diff --combined convert.c index 972bf8aec2,04966c723c..dbdbb24e4d --- a/convert.c +++ b/convert.c @@@ -501,7 -501,6 +501,7 @@@ static int apply_single_file_filter(con #define CAP_CLEAN (1u<<0) #define CAP_SMUDGE (1u<<1) +#define CAP_DELAY (1u<<2) struct cmd2process { struct subprocess_entry subprocess; /* must be the first member! */ @@@ -513,7 -512,7 +513,7 @@@ static struct hashmap subprocess_map static int start_multi_file_filter_fn(struct subprocess_entry *subprocess) { - int err; + int err, i; struct cmd2process *entry = (struct cmd2process *)subprocess; struct string_list cap_list = STRING_LIST_INIT_NODUP; char *cap_buf; @@@ -521,15 -520,6 +521,15 @@@ struct child_process *process = &subprocess->process; const char *cmd = subprocess->cmd; + static const struct { + const char *name; + unsigned int cap; + } known_caps[] = { + { "clean", CAP_CLEAN }, + { "smudge", CAP_SMUDGE }, + { "delay", CAP_DELAY }, + }; + sigchain_push(SIGPIPE, SIG_IGN); err = packet_writel(process->in, "git-filter-client", "version=2", NULL); @@@ -548,15 -538,7 +548,15 @@@ if (err) goto done; - err = packet_writel(process->in, "capability=clean", "capability=smudge", NULL); + 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); @@@ -568,15 -550,16 +568,15 @@@ continue; cap_name = cap_list.items[1].string; - if (!strcmp(cap_name, "clean")) { - entry->supported_capabilities |= CAP_CLEAN; - } else if (!strcmp(cap_name, "smudge")) { - entry->supported_capabilities |= CAP_SMUDGE; - } else { - warning( - "external filter '%s' requested unsupported filter capability '%s'", - cmd, cap_name - ); - } + 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); } @@@ -587,36 -570,11 +587,36 @@@ done return err; } +static void handle_filter_error(const struct strbuf *filter_status, + struct cmd2process *entry, + const unsigned int wanted_capability) { + if (!strcmp(filter_status->buf, "error")) + ; /* The filter signaled a problem with the file. */ + else if (!strcmp(filter_status->buf, "abort") && wanted_capability) { + /* + * The filter signaled a permanent problem. Don't try to filter + * files with the same command for the lifetime of the current + * Git process. + */ + entry->supported_capabilities &= ~wanted_capability; + } else { + /* + * Something went wrong with the protocol filter. + * Force shutdown and restart if another blob requires filtering. + */ + error("external filter '%s' failed", entry->subprocess.cmd); + subprocess_stop(&subprocess_map, &entry->subprocess); + free(entry); + } +} + static int apply_multi_file_filter(const char *path, const char *src, size_t len, int fd, struct strbuf *dst, const char *cmd, - const unsigned int wanted_capability) + const unsigned int wanted_capability, + struct delayed_checkout *dco) { int err; + int can_delay = 0; struct cmd2process *entry; struct child_process *process; struct strbuf nbuf = STRBUF_INIT; @@@ -625,8 -583,7 +625,7 @@@ if (!subprocess_map_initialized) { subprocess_map_initialized = 1; - hashmap_init(&subprocess_map, (hashmap_cmp_fn) cmd2process_cmp, - NULL, 0); + hashmap_init(&subprocess_map, cmd2process_cmp, NULL, 0); entry = NULL; } else { entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd); @@@ -645,12 -602,12 +644,12 @@@ } process = &entry->subprocess.process; - if (!(wanted_capability & entry->supported_capabilities)) + if (!(entry->supported_capabilities & wanted_capability)) return 0; - if (CAP_CLEAN & wanted_capability) + if (wanted_capability & CAP_CLEAN) filter_type = "clean"; - else if (CAP_SMUDGE & wanted_capability) + else if (wanted_capability & CAP_SMUDGE) filter_type = "smudge"; else die("unexpected filter type"); @@@ -672,14 -629,6 +671,14 @@@ if (err) goto done; + if ((entry->supported_capabilities & CAP_DELAY) && + dco && dco->state == CE_CAN_DELAY) { + can_delay = 1; + err = packet_write_fmt_gently(process->in, "can-delay=1\n"); + if (err) + goto done; + } + err = packet_flush_gently(process->in); if (err) goto done; @@@ -695,73 -644,14 +694,73 @@@ if (err) goto done; - err = strcmp(filter_status.buf, "success"); + if (can_delay && !strcmp(filter_status.buf, "delayed")) { + string_list_insert(&dco->filters, cmd); + string_list_insert(&dco->paths, path); + } else { + /* The filter got the blob and wants to send us a response. */ + err = strcmp(filter_status.buf, "success"); + if (err) + goto done; + + err = read_packetized_to_strbuf(process->out, &nbuf) < 0; + if (err) + goto done; + + err = subprocess_read_status(process->out, &filter_status); + if (err) + goto done; + + err = strcmp(filter_status.buf, "success"); + } + +done: + sigchain_pop(SIGPIPE); + + if (err) + handle_filter_error(&filter_status, entry, wanted_capability); + else + strbuf_swap(dst, &nbuf); + strbuf_release(&nbuf); + return !err; +} + + +int async_query_available_blobs(const char *cmd, struct string_list *available_paths) +{ + int err; + char *line; + struct cmd2process *entry; + struct child_process *process; + struct strbuf filter_status = STRBUF_INIT; + + assert(subprocess_map_initialized); + entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd); + if (!entry) { + error("external filter '%s' is not available anymore although " + "not all paths have been filtered", cmd); + return 0; + } + process = &entry->subprocess.process; + sigchain_push(SIGPIPE, SIG_IGN); + + err = packet_write_fmt_gently( + process->in, "command=list_available_blobs\n"); if (err) goto done; - err = read_packetized_to_strbuf(process->out, &nbuf) < 0; + err = packet_flush_gently(process->in); if (err) goto done; + while ((line = packet_read_line(process->out, NULL))) { + const char *path; + if (skip_prefix(line, "pathname=", &path)) + string_list_insert(available_paths, xstrdup(path)); + else + ; /* ignore unknown keys */ + } + err = subprocess_read_status(process->out, &filter_status); if (err) goto done; @@@ -771,8 -661,29 +770,8 @@@ done: sigchain_pop(SIGPIPE); - if (err) { - if (!strcmp(filter_status.buf, "error")) { - /* The filter signaled a problem with the file. */ - } else if (!strcmp(filter_status.buf, "abort")) { - /* - * The filter signaled a permanent problem. Don't try to filter - * files with the same command for the lifetime of the current - * Git process. - */ - entry->supported_capabilities &= ~wanted_capability; - } else { - /* - * Something went wrong with the protocol filter. - * Force shutdown and restart if another blob requires filtering. - */ - error("external filter '%s' failed", cmd); - subprocess_stop(&subprocess_map, &entry->subprocess); - free(entry); - } - } else { - strbuf_swap(dst, &nbuf); - } - strbuf_release(&nbuf); + if (err) + handle_filter_error(&filter_status, entry, 0); return !err; } @@@ -787,8 -698,7 +786,8 @@@ static struct convert_driver static int apply_filter(const char *path, const char *src, size_t len, int fd, struct strbuf *dst, struct convert_driver *drv, - const unsigned int wanted_capability) + const unsigned int wanted_capability, + struct delayed_checkout *dco) { const char *cmd = NULL; @@@ -798,16 -708,15 +797,16 @@@ if (!dst) return 1; - if ((CAP_CLEAN & wanted_capability) && !drv->process && drv->clean) + if ((wanted_capability & CAP_CLEAN) && !drv->process && drv->clean) cmd = drv->clean; - else if ((CAP_SMUDGE & wanted_capability) && !drv->process && drv->smudge) + else if ((wanted_capability & CAP_SMUDGE) && !drv->process && drv->smudge) cmd = drv->smudge; if (cmd && *cmd) return apply_single_file_filter(path, src, len, fd, dst, cmd); else if (drv->process && *drv->process) - return apply_multi_file_filter(path, src, len, fd, dst, drv->process, wanted_capability); + return apply_multi_file_filter(path, src, len, fd, dst, + drv->process, wanted_capability, dco); return 0; } @@@ -1148,7 -1057,7 +1147,7 @@@ int would_convert_to_git_filter_fd(cons if (!ca.drv->required) return 0; - return apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN); + return apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN, NULL); } const char *get_convert_attr_ascii(const char *path) @@@ -1186,7 -1095,7 +1185,7 @@@ int convert_to_git(const struct index_s convert_attrs(&ca, path); - ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN); + ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN, NULL); if (!ret && ca.drv && ca.drv->required) die("%s: clean filter '%s' failed", path, ca.drv->name); @@@ -1212,7 -1121,7 +1211,7 @@@ void convert_to_git_filter_fd(const str assert(ca.drv); assert(ca.drv->clean || ca.drv->process); - if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN)) + if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL)) die("%s: clean filter '%s' failed", path, ca.drv->name); crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe); @@@ -1221,7 -1130,7 +1220,7 @@@ static int convert_to_working_tree_internal(const char *path, const char *src, size_t len, struct strbuf *dst, - int normalizing) + int normalizing, struct delayed_checkout *dco) { int ret = 0, ret_filter = 0; struct conv_attrs ca; @@@ -1246,30 -1155,22 +1245,30 @@@ } } - ret_filter = apply_filter(path, src, len, -1, dst, ca.drv, CAP_SMUDGE); + ret_filter = apply_filter( + path, src, len, -1, dst, ca.drv, CAP_SMUDGE, dco); if (!ret_filter && ca.drv && ca.drv->required) die("%s: smudge filter %s failed", path, ca.drv->name); return ret | ret_filter; } +int async_convert_to_working_tree(const char *path, const char *src, + size_t len, struct strbuf *dst, + void *dco) +{ + return convert_to_working_tree_internal(path, src, len, dst, 0, dco); +} + int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst) { - return convert_to_working_tree_internal(path, src, len, dst, 0); + return convert_to_working_tree_internal(path, src, len, dst, 0, NULL); } 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); + int ret = convert_to_working_tree_internal(path, src, len, dst, 1, NULL); if (ret) { src = dst->buf; len = dst->len; diff --combined remote.c index 6a1be31bb1,3efa358558..43c317e4e9 --- a/remote.c +++ b/remote.c @@@ -134,10 -134,14 +134,14 @@@ struct remotes_hash_key }; static int remotes_hash_cmp(const void *unused_cmp_data, - const struct remote *a, - const struct remote *b, - const struct remotes_hash_key *key) + const void *entry, + const void *entry_or_key, + const void *keydata) { + const struct remote *a = entry; + const struct remote *b = entry_or_key; + const struct remotes_hash_key *key = keydata; + if (key) return strncmp(a->name, key->str, key->len) || a->name[key->len]; else @@@ -147,7 -151,7 +151,7 @@@ static inline void init_remotes_hash(void) { if (!remotes_hash.cmpfn) - hashmap_init(&remotes_hash, (hashmap_cmp_fn)remotes_hash_cmp, NULL, 0); + hashmap_init(&remotes_hash, remotes_hash_cmp, NULL, 0); } static struct remote *make_remote(const char *name, int len) @@@ -1081,7 -1085,7 +1085,7 @@@ static int try_explicit_object_name(con return 0; } - if (get_sha1(name, oid.hash)) + if (get_oid(name, &oid)) return -1; if (match) { @@@ -2297,8 -2301,8 +2301,8 @@@ static int parse_push_cas_option(struc if (!*colon) entry->use_tracking = 1; else if (!colon[1]) - hashclr(entry->expect); - else if (get_sha1(colon + 1, entry->expect)) + oidclr(&entry->expect); + else if (get_oid(colon + 1, &entry->expect)) return error("cannot parse expected object name '%s'", colon + 1); return 0; } @@@ -2345,7 -2349,7 +2349,7 @@@ static void apply_cas(struct push_cas_o continue; ref->expect_old_sha1 = 1; if (!entry->use_tracking) - hashcpy(ref->old_oid_expect.hash, cas->entry[i].expect); + oidcpy(&ref->old_oid_expect, &entry->expect); else if (remote_tracking(remote, ref->name, &ref->old_oid_expect)) oidclr(&ref->old_oid_expect); return; diff --combined submodule-config.c index d48403f25e,edc8dd04b6..bede338c85 --- a/submodule-config.c +++ b/submodule-config.c @@@ -1,10 -1,8 +1,10 @@@ #include "cache.h" +#include "repository.h" #include "config.h" #include "submodule-config.h" #include "submodule.h" #include "strbuf.h" +#include "parse-options.h" /* * submodule cache lookup structure @@@ -17,7 -15,6 +17,7 @@@ struct submodule_cache { struct hashmap for_path; struct hashmap for_name; + unsigned initialized:1; }; /* @@@ -34,34 -31,37 +34,40 @@@ enum lookup_type lookup_path }; -static struct submodule_cache the_submodule_cache; -static int is_cache_init; - static int config_path_cmp(const void *unused_cmp_data, - const struct submodule_entry *a, - const struct submodule_entry *b, + const void *entry, + const void *entry_or_key, const void *unused_keydata) { + const struct submodule_entry *a = entry; + const struct submodule_entry *b = entry_or_key; + return strcmp(a->config->path, b->config->path) || hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1); } static int config_name_cmp(const void *unused_cmp_data, - const struct submodule_entry *a, - const struct submodule_entry *b, + const void *entry, + const void *entry_or_key, const void *unused_keydata) { + const struct submodule_entry *a = entry; + const struct submodule_entry *b = entry_or_key; + return strcmp(a->config->name, b->config->name) || hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1); } -static void cache_init(struct submodule_cache *cache) +static struct submodule_cache *submodule_cache_alloc(void) +{ + return xcalloc(1, sizeof(struct submodule_cache)); +} + +static void submodule_cache_init(struct submodule_cache *cache) { - hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, NULL, 0); - hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, NULL, 0); + hashmap_init(&cache->for_path, config_path_cmp, NULL, 0); + hashmap_init(&cache->for_name, config_name_cmp, NULL, 0); + cache->initialized = 1; } static void free_one_config(struct submodule_entry *entry) @@@ -73,14 -73,11 +79,14 @@@ free(entry->config); } -static void cache_free(struct submodule_cache *cache) +static void submodule_cache_clear(struct submodule_cache *cache) { struct hashmap_iter iter; struct submodule_entry *entry; + if (!cache->initialized) + return; + /* * We iterate over the name hash here to be symmetric with the * allocation of struct submodule entries. Each is allocated by @@@ -92,13 -89,6 +98,13 @@@ hashmap_free(&cache->for_path, 1); hashmap_free(&cache->for_name, 1); + cache->initialized = 0; +} + +void submodule_cache_free(struct submodule_cache *cache) +{ + submodule_cache_clear(cache); + free(cache); } static unsigned int hash_sha1_string(const unsigned char *sha1, @@@ -253,27 -243,6 +259,27 @@@ int parse_fetch_recurse_submodules_arg( return parse_fetch_recurse(opt, arg, 1); } +int option_fetch_parse_recurse_submodules(const struct option *opt, + const char *arg, int unset) +{ + int *v; + + if (!opt->value) + return -1; + + v = opt->value; + + if (unset) { + *v = RECURSE_SUBMODULES_OFF; + } else { + if (arg) + *v = parse_fetch_recurse_submodules_arg(opt->long_name, arg); + else + *v = RECURSE_SUBMODULES_ON; + } + return 0; +} + static int parse_update_recurse(const char *opt, const char *arg, int die_on_error) { @@@ -441,19 -410,19 +447,19 @@@ static int parse_config(const char *var return ret; } -int gitmodule_sha1_from_commit(const unsigned char *treeish_name, - unsigned char *gitmodules_sha1, +int gitmodule_oid_from_commit(const struct object_id *treeish_name, + struct object_id *gitmodules_oid, struct strbuf *rev) { int ret = 0; - if (is_null_sha1(treeish_name)) { - hashclr(gitmodules_sha1); + if (is_null_oid(treeish_name)) { + oidclr(gitmodules_oid); return 1; } - strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(treeish_name)); - if (get_sha1(rev->buf, gitmodules_sha1) >= 0) + strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name)); + if (get_oid(rev->buf, gitmodules_oid) >= 0) ret = 1; return ret; @@@ -464,13 -433,13 +470,13 @@@ * revisions. */ static const struct submodule *config_from(struct submodule_cache *cache, - const unsigned char *treeish_name, const char *key, + const struct object_id *treeish_name, const char *key, enum lookup_type lookup_type) { struct strbuf rev = STRBUF_INIT; unsigned long config_size; char *config = NULL; - unsigned char sha1[20]; + struct object_id oid; enum object_type type; const struct submodule *submodule = NULL; struct parse_config_parameter parameter; @@@ -490,28 -459,28 +496,28 @@@ return entry->config; } - if (!gitmodule_sha1_from_commit(treeish_name, sha1, &rev)) + if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev)) goto out; switch (lookup_type) { case lookup_name: - submodule = cache_lookup_name(cache, sha1, key); + submodule = cache_lookup_name(cache, oid.hash, key); break; case lookup_path: - submodule = cache_lookup_path(cache, sha1, key); + submodule = cache_lookup_path(cache, oid.hash, key); break; } if (submodule) goto out; - config = read_sha1_file(sha1, &type, &config_size); + config = read_sha1_file(oid.hash, &type, &config_size); if (!config || type != OBJ_BLOB) goto out; /* fill the submodule config into the cache */ parameter.cache = cache; - parameter.treeish_name = treeish_name; - parameter.gitmodules_sha1 = sha1; + parameter.treeish_name = treeish_name->hash; + parameter.gitmodules_sha1 = oid.hash; parameter.overwrite = 0; git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf, config, config_size, ¶meter); @@@ -520,9 -489,9 +526,9 @@@ switch (lookup_type) { case lookup_name: - return cache_lookup_name(cache, sha1, key); + return cache_lookup_name(cache, oid.hash, key); case lookup_path: - return cache_lookup_path(cache, sha1, key); + return cache_lookup_path(cache, oid.hash, key); default: return NULL; } @@@ -533,62 -502,43 +539,62 @@@ out return submodule; } -static void ensure_cache_init(void) +static void submodule_cache_check_init(struct repository *repo) { - if (is_cache_init) + if (repo->submodule_cache && repo->submodule_cache->initialized) return; - cache_init(&the_submodule_cache); - is_cache_init = 1; + if (!repo->submodule_cache) + repo->submodule_cache = submodule_cache_alloc(); + + submodule_cache_init(repo->submodule_cache); } -int parse_submodule_config_option(const char *var, const char *value) +int submodule_config_option(struct repository *repo, + const char *var, const char *value) { struct parse_config_parameter parameter; - parameter.cache = &the_submodule_cache; + + submodule_cache_check_init(repo); + + parameter.cache = repo->submodule_cache; parameter.treeish_name = NULL; parameter.gitmodules_sha1 = null_sha1; parameter.overwrite = 1; - ensure_cache_init(); return parse_config(var, value, ¶meter); } -const struct submodule *submodule_from_name(const unsigned char *treeish_name, +int parse_submodule_config_option(const char *var, const char *value) +{ + return submodule_config_option(the_repository, var, value); +} + +const struct submodule *submodule_from_name(const struct object_id *treeish_name, const char *name) { - ensure_cache_init(); - return config_from(&the_submodule_cache, treeish_name, name, lookup_name); + submodule_cache_check_init(the_repository); + return config_from(the_repository->submodule_cache, treeish_name, name, lookup_name); } -const struct submodule *submodule_from_path(const unsigned char *treeish_name, +const struct submodule *submodule_from_path(const struct object_id *treeish_name, const char *path) { - ensure_cache_init(); - return config_from(&the_submodule_cache, treeish_name, path, lookup_path); + submodule_cache_check_init(the_repository); + return config_from(the_repository->submodule_cache, treeish_name, path, lookup_path); +} + +const struct submodule *submodule_from_cache(struct repository *repo, + const struct object_id *treeish_name, + const char *key) +{ + submodule_cache_check_init(repo); + return config_from(repo->submodule_cache, treeish_name, + key, lookup_path); } void submodule_free(void) { - cache_free(&the_submodule_cache); - is_cache_init = 0; + if (the_repository->submodule_cache) + submodule_cache_clear(the_repository->submodule_cache); }