#include "cache.h"
+#include "dir.h"
#include "repository.h"
#include "config.h"
#include "submodule-config.h"
};
static int config_path_cmp(const void *unused_cmp_data,
- const void *entry,
- const void *entry_or_key,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *unused_keydata)
{
- const struct submodule_entry *a = entry;
- const struct submodule_entry *b = entry_or_key;
+ const struct submodule_entry *a, *b;
+
+ a = container_of(eptr, const struct submodule_entry, ent);
+ b = container_of(entry_or_key, const struct submodule_entry, ent);
return strcmp(a->config->path, b->config->path) ||
- oidcmp(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
+ !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
}
static int config_name_cmp(const void *unused_cmp_data,
- const void *entry,
- const void *entry_or_key,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *unused_keydata)
{
- const struct submodule_entry *a = entry;
- const struct submodule_entry *b = entry_or_key;
+ const struct submodule_entry *a, *b;
+
+ a = container_of(eptr, const struct submodule_entry, ent);
+ b = container_of(entry_or_key, const struct submodule_entry, ent);
return strcmp(a->config->name, b->config->name) ||
- oidcmp(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
+ !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
}
static struct submodule_cache *submodule_cache_alloc(void)
* allocation of struct submodule entries. Each is allocated by
* their .gitmodules blob sha1 and submodule name.
*/
- hashmap_iter_init(&cache->for_name, &iter);
- while ((entry = hashmap_iter_next(&iter)))
+ hashmap_for_each_entry(&cache->for_name, &iter, entry,
+ ent /* member name */)
free_one_config(entry);
- hashmap_free(&cache->for_path, 1);
- hashmap_free(&cache->for_name, 1);
+ hashmap_free_entries(&cache->for_path, struct submodule_entry, ent);
+ hashmap_free_entries(&cache->for_name, struct submodule_entry, ent);
cache->initialized = 0;
cache->gitmodules_read = 0;
}
unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
submodule->path);
struct submodule_entry *e = xmalloc(sizeof(*e));
- hashmap_entry_init(e, hash);
+ hashmap_entry_init(&e->ent, hash);
e->config = submodule;
- hashmap_put(&cache->for_path, e);
+ hashmap_put(&cache->for_path, &e->ent);
}
static void cache_remove_path(struct submodule_cache *cache,
submodule->path);
struct submodule_entry e;
struct submodule_entry *removed;
- hashmap_entry_init(&e, hash);
+ hashmap_entry_init(&e.ent, hash);
e.config = submodule;
- removed = hashmap_remove(&cache->for_path, &e, NULL);
+ removed = hashmap_remove_entry(&cache->for_path, &e, ent, NULL);
free(removed);
}
unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
submodule->name);
struct submodule_entry *e = xmalloc(sizeof(*e));
- hashmap_entry_init(e, hash);
+ hashmap_entry_init(&e->ent, hash);
e->config = submodule;
- hashmap_add(&cache->for_name, e);
+ hashmap_add(&cache->for_name, &e->ent);
}
static const struct submodule *cache_lookup_path(struct submodule_cache *cache,
oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
key_config.path = path;
- hashmap_entry_init(&key, hash);
+ hashmap_entry_init(&key.ent, hash);
key.config = &key_config;
- entry = hashmap_get(&cache->for_path, &key, NULL);
+ entry = hashmap_get_entry(&cache->for_path, &key, ent, NULL);
if (entry)
return entry->config;
return NULL;
oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
key_config.name = name;
- hashmap_entry_init(&key, hash);
+ hashmap_entry_init(&key.ent, hash);
key.config = &key_config;
- entry = hashmap_get(&cache->for_name, &key, NULL);
+ entry = hashmap_get_entry(&cache->for_name, &key, ent, NULL);
if (entry)
return entry->config;
return NULL;
default:
if (!strcmp(arg, "on-demand"))
return RECURSE_SUBMODULES_ON_DEMAND;
-
+ /*
+ * Please update $__git_fetch_recurse_submodules in
+ * git-completion.bash when you add new options.
+ */
if (die_on_error)
die("bad %s argument: %s", opt, arg);
else
return RECURSE_SUBMODULES_CHECK;
else if (!strcmp(arg, "only"))
return RECURSE_SUBMODULES_ONLY;
+ /*
+ * Please update $__git_push_recurse_submodules in
+ * git-completion.bash when you add new modes.
+ */
else if (die_on_error)
die("bad %s argument: %s", opt, arg);
else
int overwrite;
};
+/*
+ * Parse a config item from .gitmodules.
+ *
+ * This does not handle submodule-related configuration from the main
+ * config store (.git/config, etc). Callers are responsible for
+ * checking for overrides in the main config store when appropriate.
+ */
static int parse_config(const char *var, const char *value, void *data)
{
struct parse_config_parameter *me = data;
warn_multiple_config(me->treeish_name, submodule->name,
"update");
else if (parse_submodule_update_strategy(value,
- &submodule->update_strategy) < 0)
- die(_("invalid value for %s"), var);
+ &submodule->update_strategy) < 0 ||
+ submodule->update_strategy.type == SM_UPDATE_COMMAND)
+ die(_("invalid value for %s"), var);
} else if (!strcmp(item.buf, "shallow")) {
if (!me->overwrite && submodule->recommend_shallow != -1)
warn_multiple_config(me->treeish_name, submodule->name,
struct hashmap_iter iter;
struct submodule_entry *entry;
- entry = hashmap_iter_first(&cache->for_name, &iter);
+ entry = hashmap_iter_first_entry(&cache->for_name, &iter,
+ struct submodule_entry,
+ ent /* member name */);
if (!entry)
return NULL;
return entry->config;
/*
* Note: This function is private for a reason, the '.gitmodules' file should
- * not be used as as a mechanism to retrieve arbitrary configuration stored in
+ * not be used as a mechanism to retrieve arbitrary configuration stored in
* the repository.
*
* Runs the provided config function on the '.gitmodules' file found in the
static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
{
if (repo->worktree) {
- char *file = repo_worktree_path(repo, GITMODULES_FILE);
- git_config_from_file(fn, file, data);
+ struct git_config_source config_source = { 0 };
+ const struct config_options opts = { 0 };
+ struct object_id oid;
+ char *file;
+ char *oidstr = NULL;
+
+ file = repo_worktree_path(repo, GITMODULES_FILE);
+ if (file_exists(file)) {
+ config_source.file = file;
+ } else if (repo_get_oid(repo, GITMODULES_INDEX, &oid) >= 0 ||
+ repo_get_oid(repo, GITMODULES_HEAD, &oid) >= 0) {
+ config_source.blob = oidstr = xstrdup(oid_to_hex(&oid));
+ if (repo != the_repository)
+ add_to_alternates_memory(repo->objects->odb->path);
+ } else {
+ goto out;
+ }
+
+ config_with_options(fn, data, &config_source, &opts);
+
+out:
+ free(oidstr);
free(file);
}
}
submodule_cache_clear(r->submodule_cache);
}
+static int config_print_callback(const char *var, const char *value, void *cb_data)
+{
+ char *wanted_key = cb_data;
+
+ if (!strcmp(wanted_key, var))
+ printf("%s\n", value);
+
+ return 0;
+}
+
+int print_config_from_gitmodules(struct repository *repo, const char *key)
+{
+ int ret;
+ char *store_key;
+
+ ret = git_config_parse_key(key, &store_key, NULL);
+ if (ret < 0)
+ return CONFIG_INVALID_KEY;
+
+ config_from_gitmodules(config_print_callback, repo, store_key);
+
+ free(store_key);
+ return 0;
+}
+
+int config_set_in_gitmodules_file_gently(const char *key, const char *value)
+{
+ int ret;
+
+ ret = git_config_set_in_file_gently(GITMODULES_FILE, key, value);
+ if (ret < 0)
+ /* Maybe the user already did that, don't error out here */
+ warning(_("Could not update .gitmodules entry %s"), key);
+
+ return ret;
+}
+
struct fetch_config {
int *max_children;
int *recurse_submodules;