Commit da290220 by Carlos Martín Nieto Committed by Vicent Marti

Download pack

Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
parent 7e1a94db
......@@ -131,22 +131,6 @@ cleanup:
return error;
}
/* Push any (OID) ref it gets into the walker */
static int push_stuff(const char *name, void *data)
{
git_revwalk *walk = (git_revwalk *) data;
git_reference *ref;
git_repository *repo;
int error;
repo = git_revwalk_repository(walk);
error = git_reference_lookup(&ref, repo, name);
if (error < GIT_SUCCESS)
return error;
return git_revwalk_push(walk, git_reference_oid(ref));
}
/*
* In this first version, we push all our refs in and start sending
* them out. When we get an ACK we hide that commit and continue
......@@ -157,12 +141,14 @@ int git_fetch_negotiate(git_headarray *list, git_repository *repo, git_remote *r
git_revwalk *walk;
int error;
unsigned int i;
char local[1024];
git_refspec *spec;
git_reference *ref;
git_strarray refs;
git_oid oid;
/* Don't try to negotiate when we don't want anything */
if (list->len == 0)
return GIT_EINVALIDARGS;
/*
* Now we have everything set up so we can start tell the server
* what we want and what we have.
......@@ -201,17 +187,15 @@ int git_fetch_negotiate(git_headarray *list, git_repository *repo, git_remote *r
error = GIT_SUCCESS;
/* TODO: git_pkt_send_flush(fd), or git_transport_flush() */
printf("Wound send 0000\n");
git_transport_send_flush(remote->transport);
git_transport_send_done(remote->transport);
cleanup:
git_revwalk_free(walk);
return error;
}
int git_fetch_download_pack(git_remote *remote)
int git_fetch_download_pack(git_remote *remote, git_repository *repo)
{
/*
* First, we ignore any ACKs we receive and wait for a NACK
*/
return GIT_ENOTIMPLEMENTED;
return git_transport_download_pack(remote->transport, repo);
}
......@@ -52,9 +52,12 @@ static int flush_pkt(git_pkt **out)
return GIT_SUCCESS;
}
static int ack_pkt(git_pkt **out, const char *line, size_t len)
/* the rest of the line will be useful for multi_ack */
static int ack_pkt(git_pkt **out, const char *GIT_UNUSED(line), size_t GIT_UNUSED(len))
{
git_pkt *pkt;
GIT_UNUSED_ARG(line);
GIT_UNUSED_ARG(len);
pkt = git__malloc(sizeof(git_pkt));
if (pkt == NULL)
......@@ -66,7 +69,7 @@ static int ack_pkt(git_pkt **out, const char *line, size_t len)
return GIT_SUCCESS;
}
static int nack_pkt(git_pkt **out)
static int nak_pkt(git_pkt **out)
{
git_pkt *pkt;
......@@ -74,7 +77,21 @@ static int nack_pkt(git_pkt **out)
if (pkt == NULL)
return GIT_ENOMEM;
pkt->type = GIT_PKT_NACK;
pkt->type = GIT_PKT_NAK;
*out = pkt;
return GIT_SUCCESS;
}
static int pack_pkt(git_pkt **out)
{
git_pkt *pkt;
pkt = git__malloc(sizeof(git_pkt));
if (pkt == NULL)
return GIT_ENOMEM;
pkt->type = GIT_PKT_PACK;
*out = pkt;
return GIT_SUCCESS;
......@@ -184,6 +201,15 @@ int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_
error = parse_len(line);
if (error < GIT_SUCCESS) {
/*
* If we fail to parse the length, it might be because the
* server is trying to send us the packfile already.
*/
if (bufflen >= 4 && !git__prefixcmp(line, "PACK")) {
*out = line;
return pack_pkt(head);
}
return git__throw(error, "Failed to parse pkt length");
}
......@@ -216,8 +242,8 @@ int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_
/* Assming the minimal size is actually 4 */
if (!git__prefixcmp(line, "ACK"))
error = ack_pkt(head, line, len);
else if (!git__prefixcmp(line, "NACK"))
error = nack_pkt(head);
else if (!git__prefixcmp(line, "NAK"))
error = nak_pkt(head);
else
error = ref_pkt(head, line, len);
......@@ -266,11 +292,10 @@ int git_pkt_send_wants(git_headarray *refs, int fd)
continue;
git_oid_fmt(buf + STRLEN(WANT_PREFIX), &head->oid);
printf("would send %s", buf);
gitno_send(fd, buf, STRLEN(buf), 0);
}
/* TODO: git_pkt_send_flush(fd) */
printf("Would send 0000\n");
git_pkt_send_flush(fd);
return ret;
}
......@@ -283,19 +308,15 @@ int git_pkt_send_wants(git_headarray *refs, int fd)
int git_pkt_send_have(git_oid *oid, int fd)
{
int ret = GIT_SUCCESS;
char buf[] = "0032have 0000000000000000000000000000000000000000\n";
git_oid_fmt(buf + STRLEN(HAVE_PREFIX), oid);
printf("would send %s", buf);
return ret;
return gitno_send(fd, buf, STRLEN(buf), 0);
}
int git_pkt_send_have(int fd)
int git_pkt_send_done(int fd)
{
char buf[] = "0009done\n";
printf("Would send %s", buf);
return GIT_SUCCESS;
return gitno_send(fd, buf, STRLEN(buf), 0);
}
......@@ -35,7 +35,8 @@ enum git_pkt_type {
GIT_PKT_REF,
GIT_PKT_HAVE,
GIT_PKT_ACK,
GIT_PKT_NACK,
GIT_PKT_NAK,
GIT_PKT_PACK,
};
/* Used for multi-ack */
......@@ -74,6 +75,7 @@ typedef struct {
int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len);
int git_pkt_send_flush(int s);
int git_pkt_send_done(int s);
int git_pkt_send_wants(git_headarray *refs, int fd);
int git_pkt_send_have(git_oid *oid, int fd);
void git_pkt_free(git_pkt *pkt);
......
......@@ -90,10 +90,21 @@ int git_transport_send_have(struct git_transport *transport, git_oid *oid)
return transport->send_have(transport, oid);
}
int git_transport_send_flush(struct git_transport *transport)
{
return transport->send_flush(transport);
}
int git_transport_send_done(struct git_transport *transport)
{
return transport->send_done(transport);
}
int git_transport_download_pack(git_transport *transport, git_repository *repo)
{
return transport->download_pack(transport, repo);
}
int git_transport_close(git_transport *transport)
{
return transport->close(transport);
......
......@@ -65,6 +65,18 @@ struct git_transport {
*/
int (*send_have)(struct git_transport *transport, git_oid *oid);
/**
* Send a 'done' message
*/
int (*send_done)(struct git_transport *transport);
/**
* Send a flush
*/
int (*send_flush)(struct git_transport *transport);
/**
* Download the packfile
*/
int (*download_pack)(struct git_transport *transport, git_repository *repo);
/**
* Fetch the changes
*/
int (*fetch)(struct git_transport *transport);
......@@ -85,5 +97,7 @@ int git_transport_dummy(struct git_transport **transport);
int git_transport_send_wants(struct git_transport *transport, git_headarray *array);
int git_transport_send_have(struct git_transport *transport, git_oid *oid);
int git_transport_send_done(struct git_transport *transport);
int git_transport_send_flush(struct git_transport *transport);
int git_transport_download_pack(git_transport *transport, git_repository *repo);
#endif
......@@ -33,6 +33,8 @@
#include "pkt.h"
#include "common.h"
#include "netops.h"
#include "filebuf.h"
#include "repository.h"
typedef struct {
git_transport parent;
......@@ -288,6 +290,13 @@ static int git_send_have(git_transport *transport, git_oid *oid)
return git_pkt_send_have(oid, t->socket);
}
static int git_send_flush(git_transport *transport)
{
transport_git *t = (transport_git *) transport;
return git_pkt_send_flush(t->socket);
}
static int git_send_done(git_transport *transport)
{
transport_git *t = (transport_git *) transport;
......@@ -295,6 +304,88 @@ static int git_send_done(git_transport *transport)
return git_pkt_send_done(t->socket);
}
static int store_pack(gitno_buffer *buf, git_repository *repo)
{
git_filebuf file;
int error;
char path[GIT_PATH_MAX], suff[] = "/objects/pack/pack-XXXX.pack\0";
off_t off = 0;
memcpy(path, repo->path_repository, GIT_PATH_MAX - off);
off += strlen(repo->path_repository);
memcpy(path + off, suff, GIT_PATH_MAX - off - STRLEN(suff));
error = git_filebuf_open(&file, path, GIT_FILEBUF_TEMPORARY);
if (error < GIT_SUCCESS)
goto cleanup;
while (1) {
if (buf->offset == 0)
break;
error = git_filebuf_write(&file, buf->data, buf->offset);
if (error < GIT_SUCCESS)
goto cleanup;
gitno_consume_n(buf, buf->offset);
}
cleanup:
if (error < GIT_SUCCESS)
git_filebuf_cleanup(&file);
return error;
}
static int git_download_pack(git_transport *transport, git_repository *repo)
{
transport_git *t = (transport_git *) transport;
int s = t->socket, error = GIT_SUCCESS, pack = 0;
gitno_buffer buf;
char buffer[1024];
git_pkt *pkt;
const char *line_end, *ptr;
gitno_buffer_setup(&buf, buffer, sizeof(buffer), s);
/*
* First, we ignore any ACKs and wait for a NACK
*/
while (1) {
error = gitno_recv(&buf);
if (error < GIT_SUCCESS)
return git__rethrow(GIT_EOSERR, "Failed to receive data");
if (error < GIT_SUCCESS) /* Orderly shutdown */
return GIT_SUCCESS;
ptr = buf.data;
/* Whilst we're searching for the pack */
while (!pack) {
if (buf.offset == 0)
break;
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf.offset);
if (error == GIT_ESHORTBUFFER)
break;
if (error < GIT_SUCCESS)
return error;
gitno_consume(&buf, line_end);
if (pkt->type == GIT_PKT_PACK)
pack = 1;
/* For now we don't care about anything */
free(pkt);
}
/*
* No we have the packet, let's just put anything we get now
* into a packfile
*/
return store_pack(&buf, repo);
}
return error;
}
static int git_close(git_transport *transport)
{
transport_git *t = (transport_git*) transport;
......@@ -341,7 +432,9 @@ int git_transport_git(git_transport **out)
t->parent.ls = git_ls;
t->parent.send_wants = git_send_wants;
t->parent.send_have = git_send_have;
t->parent.send_flush = git_send_flush;
t->parent.send_done = git_send_done;
t->parent.download_pack = git_download_pack;
t->parent.close = git_close;
t->parent.free = git_free;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment