summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2011-11-28 08:40:40 +0100
committerVicent Marti <tanoku@gmail.com>2011-11-28 08:40:40 +0100
commitd88d4311c7e08ad0d38edae006b50e2a548c937d (patch)
tree1b26cee0c3d383043902c599893299fd8fdc5302
parentc94785a9f373b6604402ba6a301b828b80ab8cd8 (diff)
downloadlibgit2-repo-ownership.tar.gz
remote: Cleanup the remotes coderepo-ownership
- Hide the remaining transports code - Drop `git_headarray`, switch to using a callback to list refs. Makes the code cleaner.
-rw-r--r--examples/network/Makefile11
-rw-r--r--examples/network/fetch.c32
-rw-r--r--examples/network/ls-remote.c46
-rw-r--r--include/git2.h1
-rw-r--r--include/git2/net.h8
-rw-r--r--include/git2/remote.h12
-rw-r--r--include/git2/transport.h40
-rw-r--r--include/git2/types.h6
-rw-r--r--src/fetch.c110
-rw-r--r--src/pkt.c24
-rw-r--r--src/pkt.h4
-rw-r--r--src/remote.c35
-rw-r--r--src/remote.h2
-rw-r--r--src/transport.c14
-rw-r--r--src/transport.h11
-rw-r--r--src/transports/git.c23
-rw-r--r--src/transports/http.c17
-rw-r--r--src/transports/local.c167
18 files changed, 226 insertions, 337 deletions
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 <stdlib.h>
#include <string.h>
-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 <string.h>
#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);
}