summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2022-02-05 10:43:08 -0500
committerEdward Thomson <ethomson@edwardthomson.com>2022-02-05 11:15:27 -0500
commitb523776785e542792bd22f185ed0a678ab07c872 (patch)
tree6a2615a87f2bf0ece64f77acce2abb2080583755 /src
parentb1e83cca1bbc255627950b4e8d4fdb1174bf7a12 (diff)
downloadlibgit2-b523776785e542792bd22f185ed0a678ab07c872.tar.gz
remote: refactor update tips function
Move the functionality to update an individual tip out of the loop; although the update tip function remains rather gnarly, at least the outer function is a bit less onerous.
Diffstat (limited to 'src')
-rw-r--r--src/remote.c218
1 files changed, 118 insertions, 100 deletions
diff --git a/src/remote.c b/src/remote.c
index a0cb1efdb..fd470366e 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -1738,141 +1738,153 @@ static int update_ref(
return 0;
}
-static int update_tips_for_spec(
- git_remote *remote,
- const git_remote_callbacks *callbacks,
- int update_fetchhead,
- git_remote_autotag_option_t tagopt,
- git_refspec *spec,
- git_vector *refs,
- const char *log_message)
+static int update_one_tip(
+ git_vector *update_heads,
+ git_remote *remote,
+ git_refspec *spec,
+ git_remote_head *head,
+ git_refspec *tagspec,
+ git_remote_autotag_option_t tagopt,
+ const char *log_message,
+ const git_remote_callbacks *callbacks)
{
- int error = 0, autotag, valid;
- unsigned int i = 0;
+ git_odb *odb;
git_str refname = GIT_STR_INIT;
+ git_reference *ref = NULL;
+ bool autotag = false;
git_oid old;
- git_odb *odb;
- git_remote_head *head;
- git_reference *ref;
- git_refspec tagspec;
- git_vector update_heads;
+ int valid;
+ int error;
- GIT_ASSERT_ARG(remote);
+ if ((error = git_repository_odb__weakptr(&odb, remote->repo)) < 0)
+ goto done;
- if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
- return -1;
+ /* Ignore malformed ref names (which also saves us from tag^{} */
+ if ((error = git_reference_name_is_valid(&valid, head->name)) < 0)
+ goto done;
- if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
- return -1;
+ if (!valid)
+ goto done;
- /* Make a copy of the transport's refs */
- if (git_vector_init(&update_heads, 16, NULL) < 0)
- return -1;
+ /* If we have a tag, see if the auto-follow rules say to update it */
+ if (git_refspec_src_matches(tagspec, head->name)) {
+ if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
+ autotag = true;
- for (; i < refs->length; ++i) {
- head = git_vector_get(refs, i);
- autotag = 0;
- git_str_clear(&refname);
+ if (tagopt != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
+ if (git_str_puts(&refname, head->name) < 0)
+ goto done;
+ }
+ }
- /* Ignore malformed ref names (which also saves us from tag^{} */
- if (git_reference_name_is_valid(&valid, head->name) < 0)
- goto on_error;
+ /* If we didn't want to auto-follow the tag, check if the refspec matches */
+ if (!autotag && git_refspec_src_matches(spec, head->name)) {
+ if (spec->dst) {
+ if ((error = git_refspec__transform(&refname, spec, head->name)) < 0)
+ goto done;
+ } else {
+ /*
+ * no rhs means store it in FETCH_HEAD, even if we don't
+ * update anything else.
+ */
+ error = git_vector_insert(update_heads, head);
+ goto done;
+ }
+ }
- if (!valid)
- continue;
+ /* If we still don't have a refname, we don't want it */
+ if (git_str_len(&refname) == 0)
+ goto done;
- /* If we have a tag, see if the auto-follow rules say to update it */
- if (git_refspec_src_matches(&tagspec, head->name)) {
- if (tagopt != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
+ /* In autotag mode, only create tags for objects already in db */
+ if (autotag && !git_odb_exists(odb, &head->oid))
+ goto done;
- if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
- autotag = 1;
+ if (!autotag && (error = git_vector_insert(update_heads, head)) < 0)
+ goto done;
- git_str_clear(&refname);
- if (git_str_puts(&refname, head->name) < 0)
- goto on_error;
- }
- }
+ error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
- /* If we didn't want to auto-follow the tag, check if the refspec matches */
- if (!autotag && git_refspec_src_matches(spec, head->name)) {
- if (spec->dst) {
- if (git_refspec__transform(&refname, spec, head->name) < 0)
- goto on_error;
- } else {
- /*
- * no rhs mans store it in FETCH_HEAD, even if we don't
- update anything else.
- */
- if ((error = git_vector_insert(&update_heads, head)) < 0)
- goto on_error;
+ if (error < 0 && error != GIT_ENOTFOUND)
+ goto done;
- continue;
- }
- }
+ if (!spec->force &&
+ !git_graph_descendant_of(remote->repo, &head->oid, &old)) {
+ error = 0;
+ goto done;
+ }
- /* If we still don't have a refname, we don't want it */
- if (git_str_len(&refname) == 0) {
- continue;
- }
+ if (error == GIT_ENOTFOUND) {
+ memset(&old, 0, GIT_OID_RAWSZ);
+ error = 0;
- /* In autotag mode, only create tags for objects already in db */
- if (autotag && !git_odb_exists(odb, &head->oid))
- continue;
+ if (autotag && (error = git_vector_insert(update_heads, head)) < 0)
+ goto done;
+ }
- if (!autotag && git_vector_insert(&update_heads, head) < 0)
- goto on_error;
+ if (!git_oid__cmp(&old, &head->oid))
+ goto done;
- error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
- if (error < 0 && error != GIT_ENOTFOUND)
- goto on_error;
+ /* In autotag mode, don't overwrite any locally-existing tags */
+ error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
+ log_message);
- if (!(error || error == GIT_ENOTFOUND)
- && !spec->force
- && !git_graph_descendant_of(remote->repo, &head->oid, &old))
- continue;
+ if (error < 0) {
+ if (error == GIT_EEXISTS)
+ error = 0;
- if (error == GIT_ENOTFOUND) {
- memset(&old, 0, GIT_OID_RAWSZ);
+ goto done;
+ }
- if (autotag && git_vector_insert(&update_heads, head) < 0)
- goto on_error;
- }
+ if (callbacks && callbacks->update_tips != NULL &&
+ callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
+ git_error_set_after_callback_function(error, "git_remote_fetch");
- if (!git_oid__cmp(&old, &head->oid))
- continue;
+done:
+ git_reference_free(ref);
+ return error;
+}
- /* In autotag mode, don't overwrite any locally-existing tags */
- error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
- log_message);
+static int update_tips_for_spec(
+ git_remote *remote,
+ const git_remote_callbacks *callbacks,
+ int update_fetchhead,
+ git_remote_autotag_option_t tagopt,
+ git_refspec *spec,
+ git_vector *refs,
+ const char *log_message)
+{
+ git_refspec tagspec;
+ git_remote_head *head;
+ git_vector update_heads;
+ int error = 0;
+ size_t i;
- if (error == GIT_EEXISTS)
- continue;
+ GIT_ASSERT_ARG(remote);
- if (error < 0)
- goto on_error;
+ if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
+ return -1;
- git_reference_free(ref);
+ /* Make a copy of the transport's refs */
+ if (git_vector_init(&update_heads, 16, NULL) < 0)
+ return -1;
- if (callbacks && callbacks->update_tips != NULL) {
- if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
- goto on_error;
- }
+ git_vector_foreach(refs, i, head) {
+ if (update_one_tip(&update_heads, remote, spec, head, &tagspec, tagopt, log_message, callbacks) < 0)
+ goto on_error;
}
if (update_fetchhead &&
(error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
goto on_error;
- git_vector_free(&update_heads);
git_refspec__dispose(&tagspec);
- git_str_dispose(&refname);
+ git_vector_free(&update_heads);
return 0;
on_error:
- git_vector_free(&update_heads);
git_refspec__dispose(&tagspec);
- git_str_dispose(&refname);
+ git_vector_free(&update_heads);
return -1;
}
@@ -1938,8 +1950,11 @@ static int next_head(const git_remote *remote, git_vector *refs,
return GIT_ITEROVER;
}
-static int opportunistic_updates(const git_remote *remote, const git_remote_callbacks *callbacks,
- git_vector *refs, const char *msg)
+static int opportunistic_updates(
+ const git_remote *remote,
+ const git_remote_callbacks *callbacks,
+ git_vector *refs,
+ const char *msg)
{
size_t i, j, k;
git_refspec *spec;
@@ -1949,6 +1964,7 @@ static int opportunistic_updates(const git_remote *remote, const git_remote_call
i = j = k = 0;
+ /* Handle refspecs matching remote heads */
while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
/*
* If we got here, there is a refspec which was used
@@ -1964,8 +1980,10 @@ static int opportunistic_updates(const git_remote *remote, const git_remote_call
goto cleanup;
}
- if (error == GIT_ITEROVER)
- error = 0;
+ if (error != GIT_ITEROVER)
+ goto cleanup;
+
+ error = 0;
cleanup:
git_str_dispose(&refname);