From d88d4311c7e08ad0d38edae006b50e2a548c937d Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 28 Nov 2011 08:40:40 +0100 Subject: remote: Cleanup the remotes code - Hide the remaining transports code - Drop `git_headarray`, switch to using a callback to list refs. Makes the code cleaner. --- examples/network/Makefile | 11 +-- examples/network/fetch.c | 32 +-------- examples/network/ls-remote.c | 46 +++--------- include/git2.h | 1 - include/git2/net.h | 8 +-- include/git2/remote.h | 12 +++- include/git2/transport.h | 40 ----------- include/git2/types.h | 6 -- src/fetch.c | 110 +++++++++++----------------- src/pkt.c | 24 +++---- src/pkt.h | 4 +- src/remote.c | 35 ++++++--- src/remote.h | 2 +- src/transport.c | 14 ++-- src/transport.h | 11 ++- src/transports/git.c | 23 +++--- src/transports/http.c | 17 ++--- src/transports/local.c | 167 ++++++++++++++++++++++--------------------- 18 files changed, 226 insertions(+), 337 deletions(-) delete mode 100644 include/git2/transport.h diff --git a/examples/network/Makefile b/examples/network/Makefile index 59a607632..ed0c2099f 100644 --- a/examples/network/Makefile +++ b/examples/network/Makefile @@ -1,17 +1,8 @@ default: all -# If you've installed libgit2 to a non-standard location, you can use -# these lines to make pkg-config find it. - -#LIBGIT2_PATH ?= $(HOME)/staging/libgit2/lib DEPS = -#$(shell PKG_CONFIG_PATH=$(LIBGIT2_PATH)/pkgconfig pkg-config --cflags -#--libs libgit2) - -DEPS = $(shell pkg-config --cflags --libs libgit2) - CC = gcc CFLAGS += -g -CFLAGS += $(DEPS) +CFLAGS += -I../../include -L../../ -lgit2 OBJECTS = \ git2.o \ diff --git a/examples/network/fetch.c b/examples/network/fetch.c index dd732f22e..cdd4a4662 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -4,23 +4,6 @@ #include #include -static void show_refs(git_headarray *refs) -{ - int i; - git_remote_head *head; - - if(refs->len == 0) - puts("Everything up-to-date"); - - for(i = 0; i < refs->len; ++i){ - char oid[GIT_OID_HEXSZ + 1] = {0}; - char *havewant; - head = refs->heads[i]; - git_oid_fmt(oid, &head->oid); - printf("%s\t%s\n", oid, head->name); - } -} - static int rename_packfile(char *packname, git_indexer *idx) { char path[GIT_PATH_MAX], oid[GIT_OID_HEXSZ + 1], *slash; @@ -50,20 +33,14 @@ static int rename_packfile(char *packname, git_indexer *idx) int fetch(git_repository *repo, int argc, char **argv) { git_remote *remote = NULL; - git_config *cfg = NULL; git_indexer *idx = NULL; git_indexer_stats stats; int error; char *packname = NULL; - // Load the repository's configuration - error = git_repository_config(&cfg, repo, NULL, NULL); - if (error < GIT_SUCCESS) - return error; - // Get the remote and connect to it printf("Fetching %s\n", argv[1]); - error = git_remote_get(&remote, cfg, argv[1]); + error = git_remote_new(&remote, repo, argv[1], NULL); if (error < GIT_SUCCESS) return error; @@ -71,13 +48,6 @@ int fetch(git_repository *repo, int argc, char **argv) if (error < GIT_SUCCESS) return error; - // Perform the packfile negotiation. This is where the two ends - // figure out the minimal amount of data that should be transmitted - // to bring the repository up-to-date - error = git_remote_negotiate(remote); - if (error < GIT_SUCCESS) - return error; - // Download the packfile from the server. As we don't know its hash // yet, it will get a temporary filename error = git_remote_download(&packname, remote); diff --git a/examples/network/ls-remote.c b/examples/network/ls-remote.c index 77a9f215d..02d432e8b 100644 --- a/examples/network/ls-remote.c +++ b/examples/network/ls-remote.c @@ -4,31 +4,22 @@ #include #include "common.h" -static void show_refs(git_headarray *refs) +static int show_ref__cb(git_remote_head *head, void *payload) { - int i; - git_remote_head *head; - -// Take each head that the remote has advertised, store the string -// representation of the OID in a buffer and print it - - for(i = 0; i < refs->len; ++i){ - char oid[GIT_OID_HEXSZ + 1] = {0}; - head = refs->heads[i]; - git_oid_fmt(oid, &head->oid); - printf("%s\t%s\n", oid, head->name); - } + char oid[GIT_OID_HEXSZ + 1] = {0}; + git_oid_fmt(oid, &head->oid); + printf("%s\t%s\n", oid, head->name); + return GIT_SUCCESS; } int use_unnamed(git_repository *repo, const char *url) { git_remote *remote = NULL; - git_headarray refs; int error; // Create an instance of a remote from the URL. The transport to use // is detected from the URL - error = git_remote_new(&remote, repo, url); + error = git_remote_new(&remote, repo, url, NULL); if (error < GIT_SUCCESS) goto cleanup; @@ -39,32 +30,20 @@ int use_unnamed(git_repository *repo, const char *url) goto cleanup; // With git_remote_ls we can retrieve the advertised heads - error = git_remote_ls(remote, &refs); - if (error < GIT_SUCCESS) - goto cleanup; - - show_refs(&refs); + error = git_remote_ls(remote, &show_ref__cb, NULL); cleanup: git_remote_free(remote); - return error; } int use_remote(git_repository *repo, char *name) { git_remote *remote = NULL; - git_config *cfg = NULL; - git_headarray refs; int error; - // Load the local configuration for the repository - error = git_repository_config(&cfg, repo, NULL, NULL); - if (error < GIT_SUCCESS) - return error; - // Find the remote by name - error = git_remote_get(&remote, cfg, name); + error = git_remote_load(&remote, repo, name); if (error < GIT_SUCCESS) goto cleanup; @@ -72,15 +51,10 @@ int use_remote(git_repository *repo, char *name) if (error < GIT_SUCCESS) goto cleanup; - error = git_remote_ls(remote, &refs); - if (error < GIT_SUCCESS) - goto cleanup; - - show_refs(&refs); + error = git_remote_ls(remote, &show_ref__cb, NULL); cleanup: git_remote_free(remote); - return error; } @@ -89,8 +63,6 @@ cleanup: int ls_remote(git_repository *repo, int argc, char **argv) { - git_headarray heads; - git_remote_head *head; int error, i; /* If there's a ':' in the name, assume it's an URL */ diff --git a/include/git2.h b/include/git2.h index 14c090e39..73b23aa63 100644 --- a/include/git2.h +++ b/include/git2.h @@ -38,7 +38,6 @@ #include "git2/refspec.h" #include "git2/net.h" -#include "git2/transport.h" #include "git2/status.h" #include "git2/indexer.h" diff --git a/include/git2/net.h b/include/git2/net.h index 5fb918599..08bc81f16 100644 --- a/include/git2/net.h +++ b/include/git2/net.h @@ -30,6 +30,7 @@ GIT_BEGIN_DECL #define GIT_DIR_FETCH 0 #define GIT_DIR_PUSH 1 + /** * Remote head description, given out on `ls` calls. */ @@ -41,12 +42,9 @@ struct git_remote_head { }; /** - * Array of remote heads + * Callback for listing the remote heads */ -struct git_headarray { - unsigned int len; - struct git_remote_head **heads; -}; +typedef int (*git_headlist_cb)(git_remote_head *, void *); /** @} */ GIT_END_DECL diff --git a/include/git2/remote.h b/include/git2/remote.h index 2bc2d16ec..0ae38165c 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -10,6 +10,8 @@ #include "common.h" #include "repository.h" #include "refspec.h" +#include "net.h" + /** * @file git2/remote.h * @brief Git remote management functions @@ -107,7 +109,7 @@ GIT_EXTERN(int) git_remote_connect(git_remote *remote, int direction); * @param remote the remote * @return GIT_SUCCESS or an error code */ -GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headarray *refs); +GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload); /** * Download the packfile @@ -161,6 +163,14 @@ GIT_EXTERN(void) git_remote_free(git_remote *remote); */ GIT_EXTERN(int) git_remote_update_tips(git_remote *remote); +/** + * Return whether a string is a valid remote URL + * + * @param tranport the url to check + * @param 1 if the url is valid, 0 otherwise + */ +GIT_EXTERN(int) git_remote_valid_url(const char *url); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/transport.h b/include/git2/transport.h deleted file mode 100644 index f56a2f40a..000000000 --- a/include/git2/transport.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2009-2011 the libgit2 contributors - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_git_transport_h__ -#define INCLUDE_git_transport_h__ - -#include "common.h" -#include "types.h" -#include "net.h" - -/** - * @file git2/transport.h - * @brief Git protocol transport abstraction - * @defgroup git_transport Git protocol transport abstraction - * @ingroup Git - * @{ - */ -GIT_BEGIN_DECL - -/** - * Get the appropriate transport for an URL. - * @param tranport the transport for the url - * @param url the url of the repo - */ -GIT_EXTERN(int) git_transport_new(git_transport **transport, const char *url); - -/** - * Return whether a string is a valid transport URL - * - * @param tranport the url to check - * @param 1 if the url is valid, 0 otherwise - */ -GIT_EXTERN(int) git_transport_valid_url(const char *url); - -/** @} */ -GIT_END_DECL -#endif diff --git a/include/git2/types.h b/include/git2/types.h index 1df18974a..ea97ee915 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -161,13 +161,7 @@ typedef enum { typedef struct git_refspec git_refspec; typedef struct git_remote git_remote; -/** A transport to use */ -typedef struct git_transport git_transport; - -typedef int (*git_transport_cb)(git_transport **transport); - typedef struct git_remote_head git_remote_head; -typedef struct git_headarray git_headarray; /** @} */ GIT_END_DECL diff --git a/src/fetch.c b/src/fetch.c index 93f0980ca..f447248c5 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -18,30 +18,46 @@ #include "fetch.h" #include "netops.h" -static int filter_wants(git_remote *remote) -{ - git_vector list; - git_headarray refs; - git_remote_head *head; - git_transport *t = remote->transport; - git_odb *odb = NULL; +struct filter_payload { + git_remote *remote; const git_refspec *spec; + git_odb *odb; + int found_head; +}; + +static int filter_ref__cb(git_remote_head *head, void *payload) +{ + struct filter_payload *p = payload; int error; - unsigned int i = 0; - error = git_vector_init(&list, 16, NULL); - if (error < GIT_SUCCESS) - return error; + if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) { + p->found_head = 1; + } else { + /* If it doesn't match the refpec, we don't want it */ + error = git_refspec_src_match(p->spec, head->name); - error = t->ls(t, &refs); - if (error < GIT_SUCCESS) { - error = git__rethrow(error, "Failed to get remote ref list"); - goto cleanup; + if (error == GIT_ENOMATCH) + return GIT_SUCCESS; + + if (error < GIT_SUCCESS) + return git__rethrow(error, "Error matching remote ref name"); } - error = git_repository_odb__weakptr(&odb, remote->repo); - if (error < GIT_SUCCESS) - goto cleanup; + /* If we have the object, mark it so we don't ask for it */ + if (git_odb_exists(p->odb, &head->oid)) + head->local = 1; + else + p->remote->need_pack = 1; + + return git_vector_insert(&p->remote->refs, head); +} + +static int filter_wants(git_remote *remote) +{ + int error; + struct filter_payload p; + + git_vector_clear(&remote->refs); /* * The fetch refspec can be NULL, and what this means is that the @@ -49,56 +65,15 @@ static int filter_wants(git_remote *remote) * not interested in any particular branch but just the remote's * HEAD, which will be stored in FETCH_HEAD after the fetch. */ - spec = git_remote_fetchspec(remote); + p.spec = git_remote_fetchspec(remote); + p.found_head = 0; + p.remote = remote; - /* - * We need to handle HEAD separately, as we always want it, but it - * probably won't matcht he refspec. - */ - head = refs.heads[0]; - if (refs.len > 0 && !strcmp(head->name, GIT_HEAD_FILE)) { - if (git_odb_exists(odb, &head->oid)) - head->local = 1; - else - remote->need_pack = 1; - - i = 1; - error = git_vector_insert(&list, refs.heads[0]); - if (error < GIT_SUCCESS) - goto cleanup; - } - - for (; i < refs.len; ++i) { - head = refs.heads[i]; - - /* If it doesn't match the refpec, we don't want it */ - error = git_refspec_src_match(spec, head->name); - if (error == GIT_ENOMATCH) - continue; - if (error < GIT_SUCCESS) { - error = git__rethrow(error, "Error matching remote ref name"); - goto cleanup; - } - - /* If we have the object, mark it so we don't ask for it */ - if (git_odb_exists(odb, &head->oid)) - head->local = 1; - else - remote->need_pack = 1; - - error = git_vector_insert(&list, head); - if (error < GIT_SUCCESS) - goto cleanup; - } - - remote->refs.len = list.length; - remote->refs.heads = (git_remote_head **) list.contents; - - return GIT_SUCCESS; + error = git_repository_odb__weakptr(&p.odb, remote->repo); + if (error < GIT_SUCCESS) + return error; -cleanup: - git_vector_free(&list); - return error; + return remote->transport->ls(remote->transport, &filter_ref__cb, &p); } /* @@ -116,8 +91,9 @@ int git_fetch_negotiate(git_remote *remote) return git__rethrow(error, "Failed to filter the reference list for wants"); /* Don't try to negotiate when we don't want anything */ - if (remote->refs.len == 0) + if (remote->refs.length == 0) return GIT_SUCCESS; + if (!remote->need_pack) return GIT_SUCCESS; diff --git a/src/pkt.c b/src/pkt.c index ff8c56eb2..9dfc40255 100644 --- a/src/pkt.c +++ b/src/pkt.c @@ -316,30 +316,30 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, * is overwrite the OID each time. */ -int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf *buf) +int git_pkt_buffer_wants(const git_vector *refs, git_transport_caps *caps, git_buf *buf) { unsigned int i = 0; int error; git_remote_head *head; if (caps->common) { - for (; i < refs->len; ++i) { - head = refs->heads[i]; + for (; i < refs->length; ++i) { + head = refs->contents[i]; if (!head->local) break; } - error = buffer_want_with_caps(refs->heads[i], caps, buf); + error = buffer_want_with_caps(refs->contents[i], caps, buf); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to buffer want with caps"); i++; } - for (; i < refs->len; ++i) { + for (; i < refs->length; ++i) { char oid[GIT_OID_HEXSZ]; - head = refs->heads[i]; + head = refs->contents[i]; if (head->local) continue; @@ -352,7 +352,7 @@ int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf return git_pkt_buffer_flush(buf); } -int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) +int git_pkt_send_wants(const git_vector *refs, git_transport_caps *caps, int fd) { unsigned int i = 0; int error = GIT_SUCCESS; @@ -365,15 +365,15 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) /* If there are common caps, find the first one */ if (caps->common) { - for (; i < refs->len; ++i) { - head = refs->heads[i]; + for (; i < refs->length; ++i) { + head = refs->contents[i]; if (head->local) continue; else break; } - error = send_want_with_caps(refs->heads[i], caps, fd); + error = send_want_with_caps(refs->contents[i], caps, fd); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to send want pkt with caps"); /* Increase it here so it's correct whether we run this or not */ @@ -381,8 +381,8 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) } /* Continue from where we left off */ - for (; i < refs->len; ++i) { - head = refs->heads[i]; + for (; i < refs->length; ++i) { + head = refs->contents[i]; if (head->local) continue; diff --git a/src/pkt.h b/src/pkt.h index 88711f2d8..7ce9c6cd9 100644 --- a/src/pkt.h +++ b/src/pkt.h @@ -68,8 +68,8 @@ int git_pkt_buffer_flush(git_buf *buf); int git_pkt_send_flush(int s); int git_pkt_buffer_done(git_buf *buf); int git_pkt_send_done(int s); -int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf *buf); -int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd); +int git_pkt_buffer_wants(const git_vector *refs, git_transport_caps *caps, git_buf *buf); +int git_pkt_send_wants(const git_vector *refs, git_transport_caps *caps, int fd); int git_pkt_buffer_have(git_oid *oid, git_buf *buf); int git_pkt_send_have(git_oid *oid, int fd); void git_pkt_free(git_pkt *pkt); diff --git a/src/remote.c b/src/remote.c index c6a9173af..75e861681 100644 --- a/src/remote.c +++ b/src/remote.c @@ -70,16 +70,21 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *url, cons memset(remote, 0x0, sizeof(git_remote)); remote->repo = repo; + if (git_vector_init(&remote->refs, 32, NULL) < 0) { + git_remote_free(remote); + return GIT_ENOMEM; + } + remote->url = git__strdup(url); if (remote->url == NULL) { - git__free(remote); + git_remote_free(remote); return GIT_ENOMEM; } if (name != NULL) { remote->name = git__strdup(name); if (remote->name == NULL) { - git__free(remote); + git_remote_free(remote); return GIT_ENOMEM; } } @@ -113,6 +118,11 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) goto cleanup; } + if (git_vector_init(&remote->refs, 32, NULL) < 0) { + error = GIT_ENOMEM; + goto cleanup; + } + /* "fetch" is the longest var name we're interested in */ buf_len = strlen("remote.") + strlen(".fetch") + strlen(name) + 1; buf = git__malloc(buf_len); @@ -227,10 +237,14 @@ cleanup: return error; } -int git_remote_ls(git_remote *remote, git_headarray *refs) +int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload) { - assert(remote && refs); - return remote->transport->ls(remote->transport, refs); + assert(remote); + + if (!remote->transport) + return git__throw(GIT_ERROR, "The remote is not connected"); + + return remote->transport->ls(remote->transport, list_cb, payload); } int git_remote_download(char **filename, git_remote *remote) @@ -250,7 +264,7 @@ int git_remote_update_tips(git_remote *remote) int error = GIT_SUCCESS; unsigned int i = 0; char refname[GIT_PATH_MAX]; - git_headarray *refs = &remote->refs; + git_vector *refs = &remote->refs; git_remote_head *head; git_reference *ref; struct git_refspec *spec = &remote->fetch; @@ -259,11 +273,11 @@ int git_remote_update_tips(git_remote *remote) memset(refname, 0x0, sizeof(refname)); - if (refs->len == 0) + if (refs->length == 0) return GIT_SUCCESS; /* HEAD is only allowed to be the first in the list */ - head = refs->heads[0]; + head = refs->contents[0]; if (!strcmp(head->name, GIT_HEAD_FILE)) { error = git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1); i = 1; @@ -272,8 +286,8 @@ int git_remote_update_tips(git_remote *remote) return git__rethrow(error, "Failed to update FETCH_HEAD"); } - for (; i < refs->len; ++i) { - head = refs->heads[i]; + for (; i < refs->length; ++i) { + head = refs->contents[i]; error = git_refspec_transform(refname, sizeof(refname), spec, head->name); if (error < GIT_SUCCESS) @@ -319,6 +333,7 @@ void git_remote_free(git_remote *remote) git__free(remote->push.dst); git__free(remote->url); git__free(remote->name); + git_vector_free(&remote->refs); git_remote_disconnect(remote); git__free(remote); } diff --git a/src/remote.h b/src/remote.h index 4b1db6c4e..a24e14845 100644 --- a/src/remote.h +++ b/src/remote.h @@ -14,7 +14,7 @@ struct git_remote { char *name; char *url; - git_headarray refs; + git_vector refs; struct git_refspec fetch; struct git_refspec push; git_transport *transport; diff --git a/src/transport.c b/src/transport.c index 0d67e1967..d836561b4 100644 --- a/src/transport.c +++ b/src/transport.c @@ -6,7 +6,7 @@ */ #include "common.h" #include "git2/types.h" -#include "git2/transport.h" +#include "git2/remote.h" #include "git2/net.h" #include "transport.h" @@ -49,11 +49,6 @@ int git_transport_dummy(git_transport **GIT_UNUSED(transport)) return git__throw(GIT_ENOTIMPLEMENTED, "This protocol isn't implemented. Sorry"); } -int git_transport_valid_url(const char *url) -{ - return transport_find_fn(url) != NULL; -} - int git_transport_new(git_transport **out, const char *url) { git_transport_cb fn; @@ -81,3 +76,10 @@ int git_transport_new(git_transport **out, const char *url) return GIT_SUCCESS; } + +/* from remote.h */ +int git_remote_valid_url(const char *url) +{ + return transport_find_fn(url) != NULL; +} + diff --git a/src/transport.h b/src/transport.h index 23b83b690..2ed8ad32a 100644 --- a/src/transport.h +++ b/src/transport.h @@ -7,7 +7,6 @@ #ifndef INCLUDE_transport_h__ #define INCLUDE_transport_h__ -#include "git2/transport.h" #include "git2/net.h" #include "vector.h" @@ -61,7 +60,7 @@ struct git_transport { /** * Give a list of references, useful for ls-remote */ - int (*ls)(struct git_transport *transport, git_headarray *headarray); + int (*ls)(struct git_transport *transport, git_headlist_cb list_cb, void *opaque); /** * Push the changes over */ @@ -74,7 +73,7 @@ struct git_transport { * Negotiate the minimal amount of objects that need to be * retrieved */ - int (*negotiate_fetch)(struct git_transport *transport, git_repository *repo, git_headarray *list); + int (*negotiate_fetch)(struct git_transport *transport, git_repository *repo, const git_vector *wants); /** * Send a flush */ @@ -97,9 +96,15 @@ struct git_transport { void (*free)(struct git_transport *transport); }; + +int git_transport_new(struct git_transport **transport, const char *url); int git_transport_local(struct git_transport **transport); int git_transport_git(struct git_transport **transport); int git_transport_http(struct git_transport **transport); int git_transport_dummy(struct git_transport **transport); +int git_transport_valid_url(const char *url); + +typedef struct git_transport git_transport; +typedef int (*git_transport_cb)(git_transport **transport); #endif diff --git a/src/transports/git.c b/src/transports/git.c index 2ee2e4831..bdb94d090 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -226,32 +226,30 @@ cleanup: return error; } -static int git_ls(git_transport *transport, git_headarray *array) +static int git_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque) { transport_git *t = (transport_git *) transport; git_vector *refs = &t->refs; - int len = 0; unsigned int i; + git_pkt *p = NULL; - array->heads = git__calloc(refs->length, sizeof(git_remote_head *)); - if (array->heads == NULL) - return GIT_ENOMEM; + git_vector_foreach(refs, i, p) { + git_pkt_ref *pkt = NULL; - for (i = 0; i < refs->length; ++i) { - git_pkt *p = git_vector_get(refs, i); if (p->type != GIT_PKT_REF) continue; - ++len; - array->heads[i] = &(((git_pkt_ref *) p)->head); + pkt = (git_pkt_ref *)p; + + if (list_cb(&pkt->head, opaque) < 0) + return git__throw(GIT_ERROR, + "The user callback returned an error code"); } - array->len = len; - t->heads = array->heads; return GIT_SUCCESS; } -static int git_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *wants) +static int git_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants) { transport_git *t = (transport_git *) transport; git_revwalk *walk; @@ -290,6 +288,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g if (git_reference_type(ref) == GIT_REF_SYMBOLIC) continue; + error = git_revwalk_push(walk, git_reference_oid(ref)); if (error < GIT_ERROR) { error = git__rethrow(error, "Failed to push %s", refs.strings[i]); diff --git a/src/transports/http.c b/src/transports/http.c index ae0c56a73..e463a0f59 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -301,29 +301,22 @@ cleanup: return error; } -static int http_ls(git_transport *transport, git_headarray *array) +static int http_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque) { transport_http *t = (transport_http *) transport; git_vector *refs = &t->refs; unsigned int i; - int len = 0; git_pkt_ref *p; - array->heads = git__calloc(refs->length, sizeof(git_remote_head*)); - if (array->heads == NULL) - return GIT_ENOMEM; - git_vector_foreach(refs, i, p) { if (p->type != GIT_PKT_REF) continue; - array->heads[len] = &p->head; - len++; + if (list_cb(&p->head, opaque) < 0) + return git__throw(GIT_ERROR, + "The user callback returned an error code"); } - array->len = len; - t->heads = array->heads; - return GIT_SUCCESS; } @@ -470,7 +463,7 @@ cleanup: return error; } -static int http_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *wants) +static int http_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants) { transport_http *t = (transport_http *) transport; int error; diff --git a/src/transports/local.c b/src/transports/local.c index afc17e55f..f50a96173 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -6,7 +6,6 @@ */ #include "common.h" #include "git2/types.h" -#include "git2/transport.h" #include "git2/net.h" #include "git2/repository.h" #include "git2/object.h" @@ -18,39 +17,10 @@ typedef struct { git_transport parent; git_repository *repo; - git_vector *refs; + git_vector refs; } transport_local; -/* - * Try to open the url as a git directory. The direction doesn't - * matter in this case because we're calulating the heads ourselves. - */ -static int local_connect(git_transport *transport, int GIT_UNUSED(direction)) -{ - git_repository *repo; - int error; - transport_local *t = (transport_local *) transport; - const char *path; - const char file_prefix[] = "file://"; - GIT_UNUSED_ARG(direction); - - /* The repo layer doesn't want the prefix */ - if (!git__prefixcmp(transport->url, file_prefix)) - path = transport->url + strlen(file_prefix); - else - path = transport->url; - - error = git_repository_open(&repo, path); - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to open remote"); - - t->repo = repo; - t->parent.connected = 1; - - return GIT_SUCCESS; -} - -static int add_ref(const char *name, git_repository *repo, git_vector *vec) +static int add_ref(transport_local *t, const char *name) { const char peeled[] = "^{}"; git_remote_head *head; @@ -68,7 +38,7 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) goto out; } - error = git_reference_lookup(&ref, repo, name); + error = git_reference_lookup(&ref, t->repo, name); if (error < GIT_SUCCESS) goto out; @@ -78,15 +48,17 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) git_oid_cpy(&head->oid, git_reference_oid(ref)); - error = git_vector_insert(vec, head); + error = git_vector_insert(&t->refs, head); if (error < GIT_SUCCESS) goto out; + head = NULL; + /* If it's not a tag, we don't need to try to peel it */ if (git__prefixcmp(name, GIT_REFS_TAGS_DIR)) goto out; - error = git_object_lookup(&obj, repo, &head->oid, GIT_OBJ_ANY); + error = git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJ_ANY); if (error < GIT_SUCCESS) { git__rethrow(error, "Failed to lookup object"); } @@ -100,13 +72,12 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) peel_len = strlen(name) + strlen(peeled); head->name = git__malloc(peel_len + 1); ret = p_snprintf(head->name, peel_len + 1, "%s%s", name, peeled); - if (ret >= peel_len + 1) { - error = git__throw(GIT_ERROR, "The string is magically to long"); - } + + assert(ret < peel_len + 1); git_oid_cpy(&head->oid, git_tag_target_oid((git_tag *) obj)); - error = git_vector_insert(vec, head); + error = git_vector_insert(&t->refs, head); if (error < GIT_SUCCESS) goto out; @@ -115,70 +86,108 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) git_reference_free(resolved_ref); git_object_free(obj); - if (error < GIT_SUCCESS) { + if (head && error < GIT_SUCCESS) { git__free(head->name); git__free(head); } + return error; } -static int local_ls(git_transport *transport, git_headarray *array) +static int store_refs(transport_local *t) { int error; unsigned int i; - git_repository *repo; - git_vector *vec; - git_strarray refs; - transport_local *t = (transport_local *) transport; + git_strarray ref_names = {0}; - assert(transport && transport->connected); - - repo = t->repo; + assert(t); - error = git_reference_listall(&refs, repo, GIT_REF_LISTALL); + error = git_vector_init(&t->refs, ref_names.count, NULL); if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to list remote heads"); - - vec = git__malloc(sizeof(git_vector)); - if (vec == NULL) { - error = GIT_ENOMEM; - goto out; - } + return error; - error = git_vector_init(vec, refs.count, NULL); + error = git_reference_listall(&ref_names, t->repo, GIT_REF_LISTALL); if (error < GIT_SUCCESS) - return error; + return git__rethrow(error, "Failed to list remote heads"); /* Sort the references first */ - git__tsort((void **)refs.strings, refs.count, &git__strcmp_cb); + git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb); /* Add HEAD */ - error = add_ref(GIT_HEAD_FILE, repo, vec); + error = add_ref(t, GIT_HEAD_FILE); if (error < GIT_SUCCESS) - goto out; + goto cleanup; - for (i = 0; i < refs.count; ++i) { - error = add_ref(refs.strings[i], repo, vec); + for (i = 0; i < ref_names.count; ++i) { + error = add_ref(t, ref_names.strings[i]); if (error < GIT_SUCCESS) - goto out; + goto cleanup; } - array->len = vec->length; - array->heads = (git_remote_head **)vec->contents; +cleanup: + git_strarray_free(&ref_names); + return error; +} - t->refs = vec; +static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *payload) +{ + transport_local *t = (transport_local *) transport; + git_vector *refs = &t->refs; + unsigned int i; + git_remote_head *h; - out: + assert(transport && transport->connected); - git_strarray_free(&refs); + git_vector_foreach(refs, i, h) { + if (list_cb(h, payload) < 0) + return git__throw(GIT_ERROR, + "The user callback returned an error code"); + } - return error; + return GIT_SUCCESS; +} + + +/* + * Try to open the url as a git directory. The direction doesn't + * matter in this case because we're calulating the heads ourselves. + */ +static int local_connect(git_transport *transport, int GIT_UNUSED(direction)) +{ + git_repository *repo; + int error; + transport_local *t = (transport_local *) transport; + const char *path; + const char file_prefix[] = "file://"; + GIT_UNUSED_ARG(direction); + + /* The repo layer doesn't want the prefix */ + if (!git__prefixcmp(transport->url, file_prefix)) + path = transport->url + strlen(file_prefix); + else + path = transport->url; + + error = git_repository_open(&repo, path); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to open remote"); + + error = store_refs(t); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to retrieve references"); + + t->repo = repo; + t->parent.connected = 1; + + return GIT_SUCCESS; } static int local_close(git_transport *GIT_UNUSED(transport)) { - /* Nothing to do */ - GIT_UNUSED_ARG(transport); + transport_local *t = (transport_local *)transport; + + git_repository_free(t->repo); + t->repo = NULL; + return GIT_SUCCESS; } @@ -186,21 +195,17 @@ static void local_free(git_transport *transport) { unsigned int i; transport_local *t = (transport_local *) transport; - git_vector *vec = t->refs; + git_vector *vec = &t->refs; git_remote_head *h; assert(transport); - if (t->refs != NULL) { - git_vector_foreach (vec, i, h) { - git__free(h->name); - git__free(h); - } - git_vector_free(vec); - git__free(vec); + git_vector_foreach (vec, i, h) { + git__free(h->name); + git__free(h); } + git_vector_free(vec); - git_repository_free(t->repo); git__free(t->parent.url); git__free(t); } -- cgit v1.2.1