#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
struct submodule_cache {
struct hashmap for_path;
struct hashmap for_name;
+ unsigned initialized:1;
};
/*
lookup_path
};
-static struct submodule_cache the_submodule_cache;
-static int is_cache_init;
-
-static int config_path_cmp(const struct submodule_entry *a,
+static int config_path_cmp(const void *unused_cmp_data,
+ const struct submodule_entry *a,
const struct submodule_entry *b,
- const void *unused)
+ const void *unused_keydata)
{
return strcmp(a->config->path, b->config->path) ||
hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
}
-static int config_name_cmp(const struct submodule_entry *a,
+static int config_name_cmp(const void *unused_cmp_data,
+ const struct submodule_entry *a,
const struct submodule_entry *b,
- const void *unused)
+ const void *unused_keydata)
{
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, 0);
- hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);
+ 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);
+ cache->initialized = 1;
}
static void free_one_config(struct submodule_entry *entry)
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
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,
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)
+{
+ switch (git_config_maybe_bool(opt, arg)) {
+ case 1:
+ return RECURSE_SUBMODULES_ON;
+ case 0:
+ return RECURSE_SUBMODULES_OFF;
+ default:
+ if (die_on_error)
+ die("bad %s argument: %s", opt, arg);
+ return RECURSE_SUBMODULES_ERROR;
+ }
+}
+
+int parse_update_recurse_submodules_arg(const char *opt, const char *arg)
+{
+ return parse_update_recurse(opt, arg, 1);
+}
+
static int parse_push_recurse(const char *opt, const char *arg,
int die_on_error)
{
return RECURSE_SUBMODULES_ON_DEMAND;
else if (!strcmp(arg, "check"))
return RECURSE_SUBMODULES_CHECK;
+ else if (!strcmp(arg, "only"))
+ return RECURSE_SUBMODULES_ONLY;
else if (die_on_error)
die("bad %s argument: %s", opt, arg);
else
return parse_push_recurse(opt, arg, 1);
}
-static void warn_multiple_config(const unsigned char *commit_sha1,
+static void warn_multiple_config(const unsigned char *treeish_name,
const char *name, const char *option)
{
const char *commit_string = "WORKTREE";
- if (commit_sha1)
- commit_string = sha1_to_hex(commit_sha1);
+ if (treeish_name)
+ commit_string = sha1_to_hex(treeish_name);
warning("%s:.gitmodules, multiple configurations found for "
"'submodule.%s.%s'. Skipping second one!",
commit_string, name, option);
struct parse_config_parameter {
struct submodule_cache *cache;
- const unsigned char *commit_sha1;
+ const unsigned char *treeish_name;
const unsigned char *gitmodules_sha1;
int overwrite;
};
if (!value)
ret = config_error_nonbool(var);
else if (!me->overwrite && submodule->path)
- warn_multiple_config(me->commit_sha1, submodule->name,
+ warn_multiple_config(me->treeish_name, submodule->name,
"path");
else {
if (submodule->path)
int die_on_error = is_null_sha1(me->gitmodules_sha1);
if (!me->overwrite &&
submodule->fetch_recurse != RECURSE_SUBMODULES_NONE)
- warn_multiple_config(me->commit_sha1, submodule->name,
+ warn_multiple_config(me->treeish_name, submodule->name,
"fetchrecursesubmodules");
else
submodule->fetch_recurse = parse_fetch_recurse(
if (!value)
ret = config_error_nonbool(var);
else if (!me->overwrite && submodule->ignore)
- warn_multiple_config(me->commit_sha1, submodule->name,
+ warn_multiple_config(me->treeish_name, submodule->name,
"ignore");
else if (strcmp(value, "untracked") &&
strcmp(value, "dirty") &&
strcmp(value, "all") &&
strcmp(value, "none"))
warning("Invalid parameter '%s' for config option "
- "'submodule.%s.ignore'", value, var);
+ "'submodule.%s.ignore'", value, name.buf);
else {
free((void *) submodule->ignore);
submodule->ignore = xstrdup(value);
if (!value) {
ret = config_error_nonbool(var);
} else if (!me->overwrite && submodule->url) {
- warn_multiple_config(me->commit_sha1, submodule->name,
+ warn_multiple_config(me->treeish_name, submodule->name,
"url");
} else {
free((void *) submodule->url);
ret = config_error_nonbool(var);
else if (!me->overwrite &&
submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED)
- warn_multiple_config(me->commit_sha1, submodule->name,
+ 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);
} else if (!strcmp(item.buf, "shallow")) {
if (!me->overwrite && submodule->recommend_shallow != -1)
- warn_multiple_config(me->commit_sha1, submodule->name,
+ warn_multiple_config(me->treeish_name, submodule->name,
"shallow");
else
submodule->recommend_shallow =
git_config_bool(var, value);
} else if (!strcmp(item.buf, "branch")) {
if (!me->overwrite && submodule->branch)
- warn_multiple_config(me->commit_sha1, submodule->name,
+ warn_multiple_config(me->treeish_name, submodule->name,
"branch");
else {
free((void *)submodule->branch);
return ret;
}
-static int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,
+int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
unsigned char *gitmodules_sha1,
struct strbuf *rev)
{
int ret = 0;
- if (is_null_sha1(commit_sha1)) {
+ if (is_null_sha1(treeish_name)) {
hashclr(gitmodules_sha1);
return 1;
}
- strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(commit_sha1));
+ strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(treeish_name));
if (get_sha1(rev->buf, gitmodules_sha1) >= 0)
ret = 1;
* revisions.
*/
static const struct submodule *config_from(struct submodule_cache *cache,
- const unsigned char *commit_sha1, const char *key,
+ const unsigned char *treeish_name, const char *key,
enum lookup_type lookup_type)
{
struct strbuf rev = STRBUF_INIT;
* return the first submodule. Can be used to check whether
* there are any submodules parsed.
*/
- if (!commit_sha1 || !key) {
+ if (!treeish_name || !key) {
struct hashmap_iter iter;
struct submodule_entry *entry;
return entry->config;
}
- if (!gitmodule_sha1_from_commit(commit_sha1, sha1, &rev))
+ if (!gitmodule_sha1_from_commit(treeish_name, sha1, &rev))
goto out;
switch (lookup_type) {
/* fill the submodule config into the cache */
parameter.cache = cache;
- parameter.commit_sha1 = commit_sha1;
+ parameter.treeish_name = treeish_name;
parameter.gitmodules_sha1 = sha1;
parameter.overwrite = 0;
git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
return submodule;
}
-static const struct submodule *config_from_path(struct submodule_cache *cache,
- const unsigned char *commit_sha1, const char *path)
-{
- return config_from(cache, commit_sha1, path, lookup_path);
-}
-
-static const struct submodule *config_from_name(struct submodule_cache *cache,
- const unsigned char *commit_sha1, const char *name)
-{
- return config_from(cache, commit_sha1, name, lookup_name);
-}
-
-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;
- parameter.commit_sha1 = NULL;
+
+ 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 *commit_sha1,
+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 unsigned char *treeish_name,
const char *name)
{
- ensure_cache_init();
- return config_from_name(&the_submodule_cache, commit_sha1, 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 *commit_sha1,
+const struct submodule *submodule_from_path(const unsigned char *treeish_name,
const char *path)
{
- ensure_cache_init();
- return config_from_path(&the_submodule_cache, commit_sha1, 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 unsigned char *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);
}