diff --git a/include/git2/remote.h b/include/git2/remote.h index e6537ec52..576f5841b 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -150,7 +150,7 @@ GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void * @param filename where to store the temproray filename * @return GIT_SUCCESS or an error code */ -GIT_EXTERN(int) git_remote_download(char **filename, git_remote *remote); +GIT_EXTERN(int) git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats); /** * Check whether the remote is connected diff --git a/src/fetch.c b/src/fetch.c index 57a6d0265..8da4fd8cd 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -9,6 +9,7 @@ #include "git2/oid.h" #include "git2/refs.h" #include "git2/revwalk.h" +#include "git2/indexer.h" #include "common.h" #include "transport.h" @@ -101,30 +102,27 @@ int git_fetch_negotiate(git_remote *remote) return t->negotiate_fetch(t, remote->repo, &remote->refs); } -int git_fetch_download_pack(char **out, git_remote *remote) +int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats) { - if(!remote->need_pack) { - *out = NULL; + if(!remote->need_pack) return 0; - } - return remote->transport->download_pack(out, remote->transport, remote->repo); + return remote->transport->download_pack(remote->transport, remote->repo, bytes, stats); } /* Receiving data from a socket and storing it is pretty much the same for git and HTTP */ int git_fetch__download_pack( - char **out, const char *buffered, size_t buffered_size, GIT_SOCKET fd, - git_repository *repo) + git_repository *repo, + git_off_t *bytes, + git_indexer_stats *stats) { - git_filebuf file = GIT_FILEBUF_INIT; - int error; + int recvd; char buff[1024]; - git_buf path = GIT_BUF_INIT; - static const char suff[] = "/objects/pack/pack-received"; gitno_buffer buf; + git_indexer_stream *idx; gitno_buffer_setup(&buf, buff, sizeof(buff), fd); @@ -133,41 +131,33 @@ int git_fetch__download_pack( return -1; } - if (git_buf_joinpath(&path, repo->path_repository, suff) < 0) + if (git_indexer_stream_new(&idx, git_repository_path(repo)) < 0) + return -1; + + memset(stats, 0, sizeof(git_indexer_stats)); + if (git_indexer_stream_add(idx, buffered, buffered_size, stats) < 0) goto on_error; - if (git_filebuf_open(&file, path.ptr, GIT_FILEBUF_TEMPORARY) < 0) - goto on_error; + *bytes = buffered_size; - /* Part of the packfile has been received, don't loose it */ - if (git_filebuf_write(&file, buffered, buffered_size) < 0) - goto on_error; - - while (1) { - if (git_filebuf_write(&file, buf.data, buf.offset) < 0) + do { + if (git_indexer_stream_add(idx, buf.data, buf.offset, stats) < 0) goto on_error; gitno_consume_n(&buf, buf.offset); - error = gitno_recv(&buf); - if (error < GIT_SUCCESS) + if ((recvd = gitno_recv(&buf)) < 0) goto on_error; - if (error == 0) /* Orderly shutdown */ - break; - } - *out = git__strdup(file.path_lock); - if (*out == NULL) + *bytes += recvd; + } while(recvd > 0); + + if (git_indexer_stream_finalize(idx, stats)) goto on_error; - /* A bit dodgy, but we need to keep the pack at the temporary path */ - if (git_filebuf_commit_at(&file, file.path_lock, GIT_PACK_FILE_MODE) < 0) - goto on_error; - - git_buf_free(&path); - + git_indexer_stream_free(idx); return 0; + on_error: - git_buf_free(&path); - git_filebuf_cleanup(&file); + git_indexer_stream_free(idx); return -1; } diff --git a/src/fetch.h b/src/fetch.h index c1ab84034..03767be8d 100644 --- a/src/fetch.h +++ b/src/fetch.h @@ -10,9 +10,9 @@ #include "netops.h" int git_fetch_negotiate(git_remote *remote); -int git_fetch_download_pack(char **out, git_remote *remote); +int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats); -int git_fetch__download_pack(char **out, const char *buffered, size_t buffered_size, - GIT_SOCKET fd, git_repository *repo); +int git_fetch__download_pack(const char *buffered, size_t buffered_size, GIT_SOCKET fd, + git_repository *repo, git_off_t *bytes, git_indexer_stats *stats); #endif diff --git a/src/remote.c b/src/remote.c index b48a23339..bbb491dd8 100644 --- a/src/remote.c +++ b/src/remote.c @@ -297,16 +297,16 @@ int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload) return remote->transport->ls(remote->transport, list_cb, payload); } -int git_remote_download(char **filename, git_remote *remote) +int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats) { int error; - assert(filename && remote); + assert(remote && bytes && stats); if ((error = git_fetch_negotiate(remote)) < 0) return error; - return git_fetch_download_pack(filename, remote); + return git_fetch_download_pack(remote, bytes, stats); } int git_remote_update_tips(git_remote *remote) diff --git a/src/transport.h b/src/transport.h index 4c123571d..1cea32bee 100644 --- a/src/transport.h +++ b/src/transport.h @@ -81,7 +81,7 @@ struct git_transport { /** * Download the packfile */ - int (*download_pack)(char **out, struct git_transport *transport, git_repository *repo); + int (*download_pack)(struct git_transport *transport, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats); /** * Fetch the changes */ diff --git a/src/transports/git.c b/src/transports/git.c index 825f072c8..62106de22 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -382,7 +382,7 @@ static int git_send_done(git_transport *transport) return git_pkt_send_done(t->socket); } -static int git_download_pack(char **out, git_transport *transport, git_repository *repo) +static int git_download_pack(git_transport *transport, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats) { transport_git *t = (transport_git *) transport; int error = 0, read_bytes; @@ -410,7 +410,7 @@ static int git_download_pack(char **out, git_transport *transport, git_repositor if (pkt->type == GIT_PKT_PACK) { git__free(pkt); - return git_fetch__download_pack(out, buf->data, buf->offset, t->socket, repo); + return git_fetch__download_pack(buf->data, buf->offset, t->socket, repo, bytes, stats); } /* For now we don't care about anything */ diff --git a/src/transports/http.c b/src/transports/http.c index 0938fefff..e6a709403 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -529,7 +529,8 @@ cleanup: } typedef struct { - git_filebuf *file; + git_indexer_stream *idx; + git_indexer_stats *stats; transport_http *transport; } download_pack_cbdata; @@ -545,10 +546,10 @@ static int on_body_download_pack(http_parser *parser, const char *str, size_t le { download_pack_cbdata *data = (download_pack_cbdata *) parser->data; transport_http *t = data->transport; - git_filebuf *file = data->file; + git_indexer_stream *idx = data->idx; + git_indexer_stats *stats = data->stats; - - return t->error = git_filebuf_write(file, str, len); + return t->error = git_indexer_stream_add(idx, str, len, stats); } /* @@ -557,30 +558,16 @@ static int on_body_download_pack(http_parser *parser, const char *str, size_t le * the simple downloader. Furthermore, we're using keep-alive * connections, so the simple downloader would just hang. */ -static int http_download_pack(char **out, git_transport *transport, git_repository *repo) +static int http_download_pack(git_transport *transport, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats) { transport_http *t = (transport_http *) transport; git_buf *oldbuf = &t->buf; - int ret = 0; + int recvd; http_parser_settings settings; char buffer[1024]; gitno_buffer buf; + git_indexer_stream *idx = NULL; download_pack_cbdata data; - git_filebuf file = GIT_FILEBUF_INIT; - git_buf path = GIT_BUF_INIT; - char suff[] = "/objects/pack/pack-received\0"; - - /* - * This is part of the previous response, so we don't want to - * re-init the parser, just set these two callbacks. - */ - data.file = &file; - data.transport = t; - t->parser.data = &data; - t->transfer_finished = 0; - memset(&settings, 0x0, sizeof(settings)); - settings.on_message_complete = on_message_complete_download_pack; - settings.on_body = on_body_download_pack; gitno_buffer_setup(&buf, buffer, sizeof(buffer), t->socket); @@ -589,48 +576,50 @@ static int http_download_pack(char **out, git_transport *transport, git_reposito return -1; } - if (git_buf_joinpath(&path, repo->path_repository, suff) < 0) + if (git_indexer_stream_new(&idx, git_repository_path(repo)) < 0) + return -1; + + + /* + * This is part of the previous response, so we don't want to + * re-init the parser, just set these two callbacks. + */ + memset(stats, 0, sizeof(git_indexer_stats)); + data.stats = stats; + data.idx = idx; + data.transport = t; + t->parser.data = &data; + t->transfer_finished = 0; + memset(&settings, 0x0, sizeof(settings)); + settings.on_message_complete = on_message_complete_download_pack; + settings.on_body = on_body_download_pack; + *bytes = oldbuf->size; + + if (git_indexer_stream_add(idx, oldbuf->ptr, oldbuf->size, stats) < 0) goto on_error; - if (git_filebuf_open(&file, path.ptr, GIT_FILEBUF_TEMPORARY) < 0) - goto on_error; - - /* Part of the packfile has been received, don't loose it */ - if (git_filebuf_write(&file, oldbuf->ptr, oldbuf->size) < 0) - goto on_error; - - while(1) { + do { size_t parsed; - ret = gitno_recv(&buf); - if (ret < 0) + if ((recvd = gitno_recv(&buf)) < 0) goto on_error; parsed = http_parser_execute(&t->parser, &settings, buf.data, buf.offset); - /* Both should happen at the same time */ if (parsed != buf.offset || t->error < 0) - return t->error; + goto on_error; + *bytes += recvd; gitno_consume_n(&buf, parsed); + } while (recvd > 0 && !t->transfer_finished); - if (ret == 0 || t->transfer_finished) { - break; - } - } - - *out = git__strdup(file.path_lock); - GITERR_CHECK_ALLOC(*out); - - /* A bit dodgy, but we need to keep the pack at the temporary path */ - ret = git_filebuf_commit_at(&file, file.path_lock, GIT_PACK_FILE_MODE); - - git_buf_free(&path); + if (git_indexer_stream_finalize(idx, stats) < 0) + goto on_error; + git_indexer_stream_free(idx); return 0; on_error: - git_filebuf_cleanup(&file); - git_buf_free(&path); + git_indexer_stream_free(idx); return -1; }