summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Martí <tanoku@gmail.com>2011-11-21 17:12:23 -0800
committerVicent Martí <tanoku@gmail.com>2011-11-21 17:12:23 -0800
commitbec92f78bf169d3cb2c058263ddff699b5055dca (patch)
tree3ec1b406fa85a4604ddd598badc7340e2009a28d
parent2744806f32c895feb2ec241320d2b64ae58e992c (diff)
parent6ac3b707b14217602152c032a11304757c88612c (diff)
downloadlibgit2-bec92f78bf169d3cb2c058263ddff699b5055dca.tar.gz
Merge pull request #492 from carlosmn/networking
Networking improvements
-rw-r--r--include/git2/remote.h45
-rw-r--r--src/protocol.c50
-rw-r--r--src/protocol.h23
-rw-r--r--src/refspec.c9
-rw-r--r--src/refspec.h5
-rw-r--r--src/remote.c46
-rw-r--r--src/transports/git.c45
-rw-r--r--src/transports/http.c53
8 files changed, 177 insertions, 99 deletions
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 54116c22e..87f84f8e0 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -28,16 +28,18 @@ GIT_BEGIN_DECL
*/
/**
- * Create a new unnamed remote
+ * Create a remote in memory
*
- * Useful when you don't want to store the remote
+ * Create a remote with the default refspecs in memory. You can use
+ * this when you have a URL instead of a remote's name.
*
* @param out pointer to the new remote object
* @param repo the associtated repository
* @param url the remote repository's URL
+ * @param name the remote's name
* @return GIT_SUCCESS or an error code
*/
-int git_remote_new(git_remote **out, git_repository *repo, const char *url);
+int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name);
/**
* Get the information for a particular remote
@@ -107,20 +109,13 @@ GIT_EXTERN(int) git_remote_connect(struct git_remote *remote, int direction);
GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headarray *refs);
/**
- * Negotiate what data needs to be exchanged to synchroize the remtoe
- * and local references
- *
- * @param remote the remote you want to negotiate with
- */
-GIT_EXTERN(int) git_remote_negotiate(git_remote *remote);
-
-/**
* Download the packfile
*
- * The packfile is downloaded with a temporary filename, as it's final
- * name is not known yet. If there was no packfile needed (all the
- * objects were available locally), filename will be NULL and the
- * function will return success.
+ * Negotiate what objects should be downloaded and download the
+ * packfile with those objects. The packfile is downloaded with a
+ * temporary filename, as it's final name is not known yet. If there
+ * was no packfile needed (all the objects were available locally),
+ * filename will be NULL and the function will return success.
*
* @param remote the remote to download from
* @param filename where to store the temproray filename
@@ -129,6 +124,26 @@ GIT_EXTERN(int) git_remote_negotiate(git_remote *remote);
GIT_EXTERN(int) git_remote_download(char **filename, git_remote *remote);
/**
+ * Check whether the remote is connected
+ *
+ * Check whether the remote's underlying transport is connected to the
+ * remote host.
+ *
+ * @return 1 if it's connected, 0 otherwise.
+ */
+GIT_EXTERN(int) git_remote_connected(git_remote *remote);
+
+/**
+ * Disconnect from the remote
+ *
+ * Close the connection to the remote and free the underlying
+ * transport.
+ *
+ * @param remote the remote to disconnect from
+ */
+GIT_EXTERN(void) git_remote_disconnect(git_remote *remote);
+
+/**
* Free the memory associated with a remote
*
* @param remote the remote to free
diff --git a/src/protocol.c b/src/protocol.c
new file mode 100644
index 000000000..1f39f105b
--- /dev/null
+++ b/src/protocol.c
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+#include "common.h"
+#include "protocol.h"
+#include "pkt.h"
+#include "buffer.h"
+
+int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
+{
+ git_buf *buf = &p->buf;
+ git_vector *refs = p->refs;
+ int error;
+ const char *line_end, *ptr;
+
+ if (len == 0) { /* EOF */
+ if (buf->size != 0)
+ return p->error = git__throw(GIT_ERROR, "EOF and unprocessed data");
+ else
+ return 0;
+ }
+
+ git_buf_put(buf, data, len);
+ ptr = buf->ptr;
+ while (1) {
+ git_pkt *pkt;
+
+ if (buf->size == 0)
+ return 0;
+
+ error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->size);
+ if (error == GIT_ESHORTBUFFER)
+ return 0; /* Ask for more */
+ if (error < GIT_SUCCESS)
+ return p->error = git__rethrow(error, "Failed to parse pkt-line");
+
+ git_buf_consume(buf, line_end);
+ error = git_vector_insert(refs, pkt);
+ if (error < GIT_SUCCESS)
+ return p->error = git__rethrow(error, "Failed to add pkt to list");
+
+ if (pkt->type == GIT_PKT_FLUSH)
+ p->flush = 1;
+ }
+
+ return error;
+}
diff --git a/src/protocol.h b/src/protocol.h
new file mode 100644
index 000000000..e3315738a
--- /dev/null
+++ b/src/protocol.h
@@ -0,0 +1,23 @@
+/*
+ * 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_protocol_h__
+#define INCLUDE_protocol_h__
+
+#include "transport.h"
+#include "buffer.h"
+
+typedef struct {
+ git_transport *transport;
+ git_vector *refs;
+ git_buf buf;
+ int error;
+ unsigned int flush :1;
+} git_protocol;
+
+int git_protocol_store_refs(git_protocol *p, const char *data, size_t len);
+
+#endif
diff --git a/src/refspec.c b/src/refspec.c
index e60e8f5b5..62683e7b7 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -23,8 +23,13 @@ int git_refspec_parse(git_refspec *refspec, const char *str)
}
delim = strchr(str, ':');
- if (delim == NULL)
- return git__throw(GIT_EOBJCORRUPTED, "Failed to parse refspec. No ':'");
+ if (delim == NULL) {
+ refspec->src = git__strdup(str);
+ if (refspec->src == NULL)
+ return GIT_ENOMEM;
+
+ return GIT_SUCCESS;
+ }
refspec->src = git__strndup(str, delim - str);
if (refspec->src == NULL)
diff --git a/src/refspec.h b/src/refspec.h
index 58f3fe472..7c389719b 100644
--- a/src/refspec.h
+++ b/src/refspec.h
@@ -10,9 +10,12 @@
#include "git2/refspec.h"
struct git_refspec {
- int force;
+ struct git_refspec *next;
char *src;
char *dst;
+ unsigned int force :1,
+ pattern :1,
+ matching :1;
};
int git_refspec_parse(struct git_refspec *refspec, const char *str);
diff --git a/src/remote.c b/src/remote.c
index 3ff08a21e..e0c127bd3 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -56,22 +56,34 @@ static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const cha
return refspec_parse(refspec, val);
}
-int git_remote_new(git_remote **out, git_repository *repo, const char *url)
+int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name)
{
git_remote *remote;
+ if (url == NULL)
+ return git__throw(GIT_EINVALIDARGS, "No URL was given");
+
remote = git__malloc(sizeof(git_remote));
if (remote == NULL)
return GIT_ENOMEM;
memset(remote, 0x0, sizeof(git_remote));
remote->repo = repo;
+
remote->url = git__strdup(url);
if (remote->url == NULL) {
git__free(remote);
return GIT_ENOMEM;
}
+ if (name != NULL) {
+ remote->name = git__strdup(name);
+ if (remote->name == NULL) {
+ git__free(remote);
+ return GIT_ENOMEM;
+ }
+ }
+
*out = remote;
return GIT_SUCCESS;
}
@@ -206,13 +218,13 @@ int git_remote_ls(git_remote *remote, git_headarray *refs)
return remote->transport->ls(remote->transport, refs);
}
-int git_remote_negotiate(git_remote *remote)
-{
- return git_fetch_negotiate(remote);
-}
-
int git_remote_download(char **filename, git_remote *remote)
{
+ int error;
+
+ if ((error = git_fetch_negotiate(remote)) < 0)
+ return git__rethrow(error, "Error negotiating");
+
return git_fetch_download_pack(filename, remote);
}
@@ -255,6 +267,21 @@ int git_remote_update_tips(struct git_remote *remote)
return GIT_SUCCESS;
}
+int git_remote_connected(git_remote *remote)
+{
+ return remote->transport == NULL ? 0 : remote->transport->connected;
+}
+
+void git_remote_disconnect(git_remote *remote)
+{
+ if (remote->transport != NULL) {
+ if (remote->transport->connected)
+ remote->transport->close(remote->transport);
+
+ remote->transport->free(remote->transport);
+ }
+}
+
void git_remote_free(git_remote *remote)
{
if (remote == NULL)
@@ -266,11 +293,6 @@ void git_remote_free(git_remote *remote)
git__free(remote->push.dst);
git__free(remote->url);
git__free(remote->name);
- if (remote->transport != NULL) {
- if (remote->transport->connected)
- remote->transport->close(remote->transport);
-
- remote->transport->free(remote->transport);
- }
+ git_remote_disconnect(remote);
git__free(remote);
}
diff --git a/src/transports/git.c b/src/transports/git.c
index c2014529b..2ee2e4831 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -20,9 +20,11 @@
#include "filebuf.h"
#include "repository.h"
#include "fetch.h"
+#include "protocol.h"
typedef struct {
git_transport parent;
+ git_protocol proto;
GIT_SOCKET socket;
git_vector refs;
git_remote_head **heads;
@@ -126,11 +128,7 @@ static int do_connect(transport_git *t, const char *url)
static int store_refs(transport_git *t)
{
gitno_buffer *buf = &t->buf;
- git_vector *refs = &t->refs;
int error = GIT_SUCCESS;
- const char *line_end, *ptr;
- git_pkt *pkt;
-
while (1) {
error = gitno_recv(buf);
@@ -139,34 +137,20 @@ static int store_refs(transport_git *t)
if (error == GIT_SUCCESS) /* Orderly shutdown, so exit */
return GIT_SUCCESS;
- ptr = buf->data;
- while (1) {
- if (buf->offset == 0)
- break;
- error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
- /*
- * If the error is GIT_ESHORTBUFFER, it means the buffer
- * isn't long enough to satisfy the request. Break out and
- * wait for more input.
- * On any other error, fail.
- */
- if (error == GIT_ESHORTBUFFER) {
- break;
- }
- if (error < GIT_SUCCESS) {
- return error;
- }
-
- /* Get rid of the part we've used already */
- gitno_consume(buf, line_end);
+ error = git_protocol_store_refs(&t->proto, buf->data, buf->offset);
+ if (error == GIT_ESHORTBUFFER) {
+ gitno_consume_n(buf, buf->len);
+ continue;
+ }
- error = git_vector_insert(refs, pkt);
- if (error < GIT_SUCCESS)
- return error;
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to store refs");
- if (pkt->type == GIT_PKT_FLUSH)
- return GIT_SUCCESS;
+ gitno_consume_n(buf, buf->offset);
+ if (t->proto.flush) { /* No more refs */
+ t->proto.flush = 0;
+ return GIT_SUCCESS;
}
}
@@ -476,6 +460,7 @@ static void git_free(git_transport *transport)
git_vector_free(refs);
git__free(t->heads);
+ git_buf_free(&t->proto.buf);
git__free(t->parent.url);
git__free(t);
}
@@ -501,6 +486,8 @@ int git_transport_git(git_transport **out)
t->parent.download_pack = git_download_pack;
t->parent.close = git_close;
t->parent.free = git_free;
+ t->proto.refs = &t->refs;
+ t->proto.transport = (git_transport *) t;
*out = (git_transport *) t;
diff --git a/src/transports/http.c b/src/transports/http.c
index 66b6f252c..ae0c56a73 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -19,6 +19,7 @@
#include "fetch.h"
#include "filebuf.h"
#include "repository.h"
+#include "protocol.h"
enum last_cb {
NONE,
@@ -28,6 +29,7 @@ enum last_cb {
typedef struct {
git_transport parent;
+ git_protocol proto;
git_vector refs;
git_vector common;
int socket;
@@ -186,47 +188,8 @@ static int on_headers_complete(http_parser *parser)
static int on_body_store_refs(http_parser *parser, const char *str, size_t len)
{
transport_http *t = (transport_http *) parser->data;
- git_buf *buf = &t->buf;
- git_vector *refs = &t->refs;
- int error;
- const char *line_end, *ptr;
- static int first_pkt = 1;
-
- if (len == 0) { /* EOF */
- if (buf->size != 0)
- return t->error = git__throw(GIT_ERROR, "EOF and unprocessed data");
- else
- return 0;
- }
-
- git_buf_put(buf, str, len);
- ptr = buf->ptr;
- while (1) {
- git_pkt *pkt;
-
- if (buf->size == 0)
- return 0;
-
- error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->size);
- if (error == GIT_ESHORTBUFFER)
- return 0; /* Ask for more */
- if (error < GIT_SUCCESS)
- return t->error = git__rethrow(error, "Failed to parse pkt-line");
-
- git_buf_consume(buf, line_end);
- if (first_pkt) {
- first_pkt = 0;
- if (pkt->type != GIT_PKT_COMMENT)
- return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response");
- }
-
- error = git_vector_insert(refs, pkt);
- if (error < GIT_SUCCESS)
- return t->error = git__rethrow(error, "Failed to add pkt to list");
- }
-
- return error;
+ return git_protocol_store_refs(&t->proto, str, len);
}
static int on_message_complete(http_parser *parser)
@@ -243,6 +206,7 @@ static int store_refs(transport_http *t)
http_parser_settings settings;
char buffer[1024];
gitno_buffer buf;
+ git_pkt *pkt;
http_parser_init(&t->parser, HTTP_RESPONSE);
t->parser.data = t;
@@ -273,6 +237,12 @@ static int store_refs(transport_http *t)
return GIT_SUCCESS;
}
+ pkt = git_vector_get(&t->refs, 0);
+ if (pkt == NULL || pkt->type != GIT_PKT_COMMENT)
+ return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response");
+ else
+ git_vector_remove(&t->refs, 0);
+
return error;
}
@@ -750,6 +720,7 @@ static void http_free(git_transport *transport)
}
git_vector_free(common);
git_buf_free(&t->buf);
+ git_buf_free(&t->proto.buf);
git__free(t->heads);
git__free(t->content_type);
git__free(t->host);
@@ -775,6 +746,8 @@ int git_transport_http(git_transport **out)
t->parent.download_pack = http_download_pack;
t->parent.close = http_close;
t->parent.free = http_free;
+ t->proto.refs = &t->refs;
+ t->proto.transport = (git_transport *) t;
#ifdef GIT_WIN32
/* on win32, the WSA context needs to be initialized