summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-12-18 11:48:57 -0800
committerRussell Belfer <rb@github.com>2014-04-01 09:45:20 -0700
commit8286300a1e2d24dfe184316c0f9798f2c69d0ef4 (patch)
treeb0ffb64c15a84f0cb1d138587e395986da7b1c7a
parent18234b14ad55157581ca26ec763afc1af3ec6e76 (diff)
downloadlibgit2-8286300a1e2d24dfe184316c0f9798f2c69d0ef4.tar.gz
Fix git_submodule_sync and add new config helper
This fixes `git_submodule_sync` to correctly update the remote URL of the default branch of the submodule along with the URL in the parent repository config (i.e. match core Git's behavior). Also move some useful helper logic from the submodule code into a shared config API `git_config__update_entry` that can either set or delete an entry with constraints like not overwriting or not creating a new entry. I used that helper to update a couple other places in the code.
-rw-r--r--src/config.c30
-rw-r--r--src/config.h8
-rw-r--r--src/remote.c86
-rw-r--r--src/submodule.c138
4 files changed, 149 insertions, 113 deletions
diff --git a/src/config.c b/src/config.c
index 1a205fe13..b3168f735 100644
--- a/src/config.c
+++ b/src/config.c
@@ -615,6 +615,36 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
return error;
}
+int git_config__update_entry(
+ git_config *config,
+ const char *key,
+ const char *value,
+ bool overwrite_existing,
+ bool only_if_existing)
+{
+ int error = 0;
+ const git_config_entry *ce = NULL;
+
+ if ((error = git_config__lookup_entry(&ce, config, key, false)) < 0)
+ return error;
+
+ if (!ce && only_if_existing) /* entry doesn't exist */
+ return 0;
+ if (ce && !overwrite_existing) /* entry would be overwritten */
+ return 0;
+ if (value && ce && ce->value && !strcmp(ce->value, value)) /* no change */
+ return 0;
+ if (!value && (!ce || !ce->value)) /* asked to delete absent entry */
+ return 0;
+
+ if (!value)
+ error = git_config_delete_entry(config, key);
+ else
+ error = git_config_set_string(config, key, value);
+
+ return error;
+}
+
/***********
* Getters
***********/
diff --git a/src/config.h b/src/config.h
index 03d910616..00b6063e7 100644
--- a/src/config.h
+++ b/src/config.h
@@ -53,6 +53,14 @@ extern int git_config__lookup_entry(
const char *key,
bool no_errors);
+/* internal only: update and/or delete entry string with constraints */
+extern int git_config__update_entry(
+ git_config *cfg,
+ const char *key,
+ const char *value,
+ bool overwrite_existing,
+ bool only_if_existing);
+
/*
* Lookup functions that cannot fail. These functions look up a config
* value and return a fallback value if the value is missing or if any
diff --git a/src/remote.c b/src/remote.c
index 62ee90375..53ff79707 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -495,9 +495,10 @@ cleanup:
int git_remote_save(const git_remote *remote)
{
int error;
- git_config *config;
+ git_config *cfg;
const char *tagopt = NULL;
git_buf buf = GIT_BUF_INIT;
+ const git_config_entry *existing;
assert(remote);
@@ -509,43 +510,31 @@ int git_remote_save(const git_remote *remote)
if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
return error;
- if (git_repository_config__weakptr(&config, remote->repo) < 0)
- return -1;
+ if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
+ return error;
- if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
- return -1;
+ if ((error = git_buf_printf(&buf, "remote.%s.url", remote->name)) < 0)
+ return error;
- if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
- git_buf_free(&buf);
- return -1;
- }
+ /* after this point, buffer is allocated so end with cleanup */
+
+ if ((error = git_config_set_string(
+ cfg, git_buf_cstr(&buf), remote->url)) < 0)
+ goto cleanup;
git_buf_clear(&buf);
- if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
- return -1;
+ if ((error = git_buf_printf(&buf, "remote.%s.pushurl", remote->name)) < 0)
+ goto cleanup;
- if (remote->pushurl) {
- if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) {
- git_buf_free(&buf);
- return -1;
- }
- } else {
- int error = git_config_delete_entry(config, git_buf_cstr(&buf));
- if (error == GIT_ENOTFOUND) {
- error = 0;
- giterr_clear();
- }
- if (error < 0) {
- git_buf_free(&buf);
- return error;
- }
- }
+ if ((error = git_config__update_entry(
+ cfg, git_buf_cstr(&buf), remote->pushurl, true, false)) < 0)
+ goto cleanup;
- if (update_config_refspec(remote, config, GIT_DIRECTION_FETCH) < 0)
- goto on_error;
+ if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_FETCH)) < 0)
+ goto cleanup;
- if (update_config_refspec(remote, config, GIT_DIRECTION_PUSH) < 0)
- goto on_error;
+ if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_PUSH)) < 0)
+ goto cleanup;
/*
* What action to take depends on the old and new values. This
@@ -561,31 +550,26 @@ int git_remote_save(const git_remote *remote)
*/
git_buf_clear(&buf);
- if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
- goto on_error;
-
- error = git_config_get_string(&tagopt, config, git_buf_cstr(&buf));
- if (error < 0 && error != GIT_ENOTFOUND)
- goto on_error;
+ if ((error = git_buf_printf(&buf, "remote.%s.tagopt", remote->name)) < 0)
+ goto cleanup;
- if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
- if (git_config_set_string(config, git_buf_cstr(&buf), "--tags") < 0)
- goto on_error;
- } else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
- if (git_config_set_string(config, git_buf_cstr(&buf), "--no-tags") < 0)
- goto on_error;
- } else if (tagopt) {
- if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0)
- goto on_error;
- }
+ if ((error = git_config__lookup_entry(
+ &existing, cfg, git_buf_cstr(&buf), false)) < 0)
+ goto cleanup;
- git_buf_free(&buf);
+ if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL)
+ tagopt = "--tags";
+ else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE)
+ tagopt = "--no-tags";
+ else if (existing != NULL)
+ tagopt = NULL;
- return 0;
+ error = git_config__update_entry(
+ cfg, git_buf_cstr(&buf), tagopt, true, false);
-on_error:
+cleanup:
git_buf_free(&buf);
- return -1;
+ return error;
}
const char *git_remote_name(const git_remote *remote)
diff --git a/src/submodule.c b/src/submodule.c
index a0ce5317f..dc0ea435e 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -83,7 +83,6 @@ static int lookup_head_remote(git_buf *url, git_repository *repo);
static int submodule_get(git_submodule **, git_repository *, const char *, const char *);
static int submodule_load_from_config(const git_config_entry *, void *);
static int submodule_load_from_wd_lite(git_submodule *);
-static int submodule_update_config(git_submodule *, const char *, const char *, bool, bool);
static void submodule_get_index_status(unsigned int *, git_submodule *);
static void submodule_get_wd_status(unsigned int *, git_submodule *, git_repository *, git_submodule_ignore_t);
@@ -716,46 +715,105 @@ git_submodule_recurse_t git_submodule_set_fetch_recurse_submodules(
return old;
}
-int git_submodule_init(git_submodule *submodule, int overwrite)
+int git_submodule_init(git_submodule *sm, int overwrite)
{
int error;
const char *val;
+ git_buf key = GIT_BUF_INIT;
+ git_config *cfg = NULL;
- /* write "submodule.NAME.url" */
-
- if (!submodule->url) {
+ if (!sm->url) {
giterr_set(GITERR_SUBMODULE,
- "No URL configured for submodule '%s'", submodule->name);
+ "No URL configured for submodule '%s'", sm->name);
return -1;
}
- error = submodule_update_config(
- submodule, "url", submodule->url, overwrite != 0, false);
- if (error < 0)
+ if ((error = git_repository_config(&cfg, sm->repo)) < 0)
return error;
+ /* write "submodule.NAME.url" */
+
+ if ((error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
+ (error = git_config__update_entry(
+ cfg, key.ptr, sm->url, overwrite != 0, false)) < 0)
+ goto cleanup;
+
/* write "submodule.NAME.update" if not default */
- val = (submodule->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
- NULL : git_submodule_update_to_str(submodule->update);
- error = submodule_update_config(
- submodule, "update", val, (overwrite != 0), false);
+ val = (sm->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
+ NULL : git_submodule_update_to_str(sm->update);
+
+ if ((error = git_buf_printf(&key, "submodule.%s.update", sm->name)) < 0 ||
+ (error = git_config__update_entry(
+ cfg, key.ptr, val, overwrite != 0, false)) < 0)
+ goto cleanup;
+
+ /* success */
+
+cleanup:
+ git_config_free(cfg);
+ git_buf_free(&key);
return error;
}
-int git_submodule_sync(git_submodule *submodule)
+int git_submodule_sync(git_submodule *sm)
{
- if (!submodule->url) {
+ int error = 0;
+ git_config *cfg = NULL;
+ git_buf key = GIT_BUF_INIT;
+
+ if (!sm->url) {
giterr_set(GITERR_SUBMODULE,
- "No URL configured for submodule '%s'", submodule->name);
+ "No URL configured for submodule '%s'", sm->name);
return -1;
}
/* copy URL over to config only if it already exists */
- return submodule_update_config(
- submodule, "url", submodule->url, true, true);
+ if (!(error = git_repository_config__weakptr(&cfg, sm->repo)) &&
+ !(error = git_buf_printf(&key, "submodule.%s.url", sm->name)))
+ error = git_config__update_entry(cfg, key.ptr, sm->url, true, true);
+
+ /* if submodule exists in the working directory, update remote url */
+
+ if (!error && (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) != 0) {
+ git_repository *smrepo = NULL;
+ git_reference *smhead = NULL;
+ const char *remote = "origin";
+
+ if ((error = git_submodule_open(&smrepo, sm)) < 0 ||
+ (error = git_repository_head(&smhead, smrepo)) < 0 ||
+ (error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
+ goto smcleanup;
+
+ /* get remote for default branch and set remote.<name>.url */
+
+ if (git_reference_type(smhead) == GIT_REF_SYMBOLIC) {
+ const char *bname = git_reference_shorthand(smhead);
+ const git_config_entry *ce;
+
+ git_buf_clear(&key);
+ if ((error = git_buf_printf(&key, "branch.%s.remote", bname)) < 0 ||
+ (error = git_config__lookup_entry(&ce, cfg, key.ptr, 0)) < 0)
+ goto smcleanup;
+
+ if (ce && ce->value)
+ remote = ce->value;
+ }
+
+ git_buf_clear(&key);
+ if (!(error = git_buf_printf(&key, "remote.%s.url", remote)))
+ error = git_config__update_entry(cfg, key.ptr, sm->url, true, true);
+
+smcleanup:
+ git_reference_free(smhead);
+ git_repository_free(smrepo);
+ }
+
+ git_buf_free(&key);
+
+ return error;
}
static int git_submodule__open(
@@ -1640,50 +1698,6 @@ cleanup:
return error;
}
-static int submodule_update_config(
- git_submodule *submodule,
- const char *attr,
- const char *value,
- bool overwrite,
- bool only_existing)
-{
- int error;
- git_config *config;
- git_buf key = GIT_BUF_INIT;
- const git_config_entry *ce = NULL;
-
- assert(submodule);
-
- error = git_repository_config__weakptr(&config, submodule->repo);
- if (error < 0)
- return error;
-
- error = git_buf_printf(&key, "submodule.%s.%s", submodule->name, attr);
- if (error < 0)
- goto cleanup;
-
- if ((error = git_config__lookup_entry(&ce, config, key.ptr, false)) < 0)
- goto cleanup;
-
- if (!ce && only_existing)
- goto cleanup;
- if (ce && !overwrite)
- goto cleanup;
- if (value && ce && ce->value && !strcmp(ce->value, value))
- goto cleanup;
- if (!value && (!ce || !ce->value))
- goto cleanup;
-
- if (!value)
- error = git_config_delete_entry(config, key.ptr);
- else
- error = git_config_set_string(config, key.ptr, value);
-
-cleanup:
- git_buf_free(&key);
- return error;
-}
-
static void submodule_get_index_status(unsigned int *status, git_submodule *sm)
{
const git_oid *head_oid = git_submodule_head_id(sm);