mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-14 14:28:23 +00:00
Implement local transport's fetch
This commit is contained in:
parent
9d64128325
commit
505da062b8
@ -10,11 +10,19 @@
|
|||||||
#include "git2/repository.h"
|
#include "git2/repository.h"
|
||||||
#include "git2/object.h"
|
#include "git2/object.h"
|
||||||
#include "git2/tag.h"
|
#include "git2/tag.h"
|
||||||
#include "refs.h"
|
|
||||||
#include "git2/transport.h"
|
#include "git2/transport.h"
|
||||||
|
#include "git2/revwalk.h"
|
||||||
|
#include "git2/odb_backend.h"
|
||||||
|
#include "git2/pack.h"
|
||||||
|
#include "git2/commit.h"
|
||||||
|
#include "git2/revparse.h"
|
||||||
|
#include "pack-objects.h"
|
||||||
|
#include "refs.h"
|
||||||
#include "posix.h"
|
#include "posix.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
#include "repository.h"
|
||||||
|
#include "odb.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
git_transport parent;
|
git_transport parent;
|
||||||
@ -34,7 +42,7 @@ static int add_ref(transport_local *t, const char *name)
|
|||||||
git_object *obj = NULL, *target = NULL;
|
git_object *obj = NULL, *target = NULL;
|
||||||
git_buf buf = GIT_BUF_INIT;
|
git_buf buf = GIT_BUF_INIT;
|
||||||
|
|
||||||
head = (git_remote_head *)git__malloc(sizeof(git_remote_head));
|
head = (git_remote_head *)git__calloc(1, sizeof(git_remote_head));
|
||||||
GITERR_CHECK_ALLOC(head);
|
GITERR_CHECK_ALLOC(head);
|
||||||
|
|
||||||
head->name = git__strdup(name);
|
head->name = git__strdup(name);
|
||||||
@ -200,15 +208,137 @@ static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *pay
|
|||||||
static int local_negotiate_fetch(
|
static int local_negotiate_fetch(
|
||||||
git_transport *transport,
|
git_transport *transport,
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
const git_remote_head * const *refs, size_t count)
|
const git_remote_head * const *refs,
|
||||||
|
size_t count)
|
||||||
{
|
{
|
||||||
GIT_UNUSED(transport);
|
transport_local *t = (transport_local*)transport;
|
||||||
GIT_UNUSED(repo);
|
git_remote_head *rhead;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
GIT_UNUSED(refs);
|
GIT_UNUSED(refs);
|
||||||
GIT_UNUSED(count);
|
GIT_UNUSED(count);
|
||||||
|
|
||||||
giterr_set(GITERR_NET, "Fetch via local transport isn't implemented. Sorry");
|
/* Fill in the loids */
|
||||||
return -1;
|
git_vector_foreach(&t->refs, i, rhead) {
|
||||||
|
git_object *obj;
|
||||||
|
|
||||||
|
int error = git_revparse_single(&obj, repo, rhead->name);
|
||||||
|
if (!error)
|
||||||
|
git_oid_cpy(&rhead->loid, git_object_id(obj));
|
||||||
|
else if (error != GIT_ENOTFOUND)
|
||||||
|
return error;
|
||||||
|
giterr_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct foreach_data {
|
||||||
|
git_transfer_progress *stats;
|
||||||
|
git_transfer_progress_callback progress_cb;
|
||||||
|
void *progress_payload;
|
||||||
|
git_odb_writepack *writepack;
|
||||||
|
} foreach_data;
|
||||||
|
|
||||||
|
static int foreach_cb(void *buf, size_t len, void *payload)
|
||||||
|
{
|
||||||
|
foreach_data *data = (foreach_data*)payload;
|
||||||
|
|
||||||
|
data->stats->received_bytes += len;
|
||||||
|
return data->writepack->add(data->writepack, buf, len, data->stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int local_download_pack(
|
||||||
|
git_transport *transport,
|
||||||
|
git_repository *repo,
|
||||||
|
git_transfer_progress *stats,
|
||||||
|
git_transfer_progress_callback progress_cb,
|
||||||
|
void *progress_payload)
|
||||||
|
{
|
||||||
|
transport_local *t = (transport_local*)transport;
|
||||||
|
git_revwalk *walk = NULL;
|
||||||
|
git_remote_head *rhead;
|
||||||
|
unsigned int i;
|
||||||
|
int error = -1;
|
||||||
|
git_oid oid;
|
||||||
|
git_packbuilder *pack = NULL;
|
||||||
|
git_odb_writepack *writepack = NULL;
|
||||||
|
|
||||||
|
if ((error = git_revwalk_new(&walk, t->repo)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
git_revwalk_sorting(walk, GIT_SORT_TIME);
|
||||||
|
|
||||||
|
if ((error = git_packbuilder_new(&pack, t->repo)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
stats->total_objects = 0;
|
||||||
|
stats->indexed_objects = 0;
|
||||||
|
stats->received_objects = 0;
|
||||||
|
stats->received_bytes = 0;
|
||||||
|
|
||||||
|
git_vector_foreach(&t->refs, i, rhead) {
|
||||||
|
git_object *obj;
|
||||||
|
if ((error = git_object_lookup(&obj, t->repo, &rhead->oid, GIT_OBJ_ANY)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (git_object_type(obj) == GIT_OBJ_COMMIT) {
|
||||||
|
/* Revwalker includes only wanted commits */
|
||||||
|
error = git_revwalk_push(walk, &rhead->oid);
|
||||||
|
if (!git_oid_iszero(&rhead->loid))
|
||||||
|
error = git_revwalk_hide(walk, &rhead->loid);
|
||||||
|
} else {
|
||||||
|
/* Tag or some other wanted object. Add it on its own */
|
||||||
|
stats->total_objects++;
|
||||||
|
error = git_packbuilder_insert(pack, &rhead->oid, rhead->name);
|
||||||
|
}
|
||||||
|
git_object_free(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Walk the objects, building a packfile */
|
||||||
|
|
||||||
|
while ((error = git_revwalk_next(&oid, walk)) == 0) {
|
||||||
|
git_commit *commit;
|
||||||
|
|
||||||
|
stats->total_objects++;
|
||||||
|
|
||||||
|
if (!git_object_lookup((git_object**)&commit, t->repo, &oid, GIT_OBJ_COMMIT)) {
|
||||||
|
const git_oid *tree_oid = git_commit_tree_oid(commit);
|
||||||
|
git_commit_free(commit);
|
||||||
|
|
||||||
|
/* Add the commit and its tree */
|
||||||
|
if ((error = git_packbuilder_insert(pack, &oid, NULL)) < 0 ||
|
||||||
|
(error = git_packbuilder_insert_tree(pack, tree_oid)))
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress_cb) progress_cb(stats, progress_payload);
|
||||||
|
|
||||||
|
{
|
||||||
|
git_odb *odb;
|
||||||
|
if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
|
||||||
|
(error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the data to the ODB */
|
||||||
|
{
|
||||||
|
foreach_data data = {0};
|
||||||
|
data.stats = stats;
|
||||||
|
data.progress_cb = progress_cb;
|
||||||
|
data.progress_payload = progress_payload;
|
||||||
|
data.writepack = writepack;
|
||||||
|
|
||||||
|
if ((error = git_packbuilder_foreach(pack, foreach_cb, &data)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
error = writepack->commit(writepack, stats);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (writepack) writepack->free(writepack);
|
||||||
|
git_packbuilder_free(pack);
|
||||||
|
git_revwalk_free(walk);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_is_connected(git_transport *transport, int *connected)
|
static int local_is_connected(git_transport *transport, int *connected)
|
||||||
@ -283,6 +413,7 @@ int git_transport_local(git_transport **out, void *param)
|
|||||||
|
|
||||||
t->parent.connect = local_connect;
|
t->parent.connect = local_connect;
|
||||||
t->parent.negotiate_fetch = local_negotiate_fetch;
|
t->parent.negotiate_fetch = local_negotiate_fetch;
|
||||||
|
t->parent.download_pack = local_download_pack;
|
||||||
t->parent.close = local_close;
|
t->parent.close = local_close;
|
||||||
t->parent.free = local_free;
|
t->parent.free = local_free;
|
||||||
t->parent.ls = local_ls;
|
t->parent.ls = local_ls;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include "git2/clone.h"
|
#include "git2/clone.h"
|
||||||
#include "repository.h"
|
#include "repository.h"
|
||||||
|
|
||||||
#define DO_LOCAL_TEST 0
|
|
||||||
#define LIVE_REPO_URL "git://github.com/libgit2/TestGitRepository"
|
#define LIVE_REPO_URL "git://github.com/libgit2/TestGitRepository"
|
||||||
|
|
||||||
static git_repository *g_repo;
|
static git_repository *g_repo;
|
||||||
@ -73,12 +72,9 @@ void test_clone_nonetwork__local(void)
|
|||||||
{
|
{
|
||||||
git_buf src = GIT_BUF_INIT;
|
git_buf src = GIT_BUF_INIT;
|
||||||
build_local_file_url(&src, cl_fixture("testrepo.git"));
|
build_local_file_url(&src, cl_fixture("testrepo.git"));
|
||||||
|
|
||||||
#if DO_LOCAL_TEST
|
|
||||||
cl_set_cleanup(&cleanup_repository, "./local");
|
cl_set_cleanup(&cleanup_repository, "./local");
|
||||||
|
|
||||||
cl_git_pass(git_clone(&g_repo, git_buf_cstr(&src), "./local", NULL, NULL, NULL));
|
cl_git_pass(git_clone(&g_repo, git_buf_cstr(&src), "./local", NULL, NULL, NULL));
|
||||||
#endif
|
|
||||||
|
|
||||||
git_buf_free(&src);
|
git_buf_free(&src);
|
||||||
}
|
}
|
||||||
@ -87,12 +83,9 @@ void test_clone_nonetwork__local_bare(void)
|
|||||||
{
|
{
|
||||||
git_buf src = GIT_BUF_INIT;
|
git_buf src = GIT_BUF_INIT;
|
||||||
build_local_file_url(&src, cl_fixture("testrepo.git"));
|
build_local_file_url(&src, cl_fixture("testrepo.git"));
|
||||||
|
|
||||||
#if DO_LOCAL_TEST
|
|
||||||
cl_set_cleanup(&cleanup_repository, "./local.git");
|
cl_set_cleanup(&cleanup_repository, "./local.git");
|
||||||
|
|
||||||
cl_git_pass(git_clone_bare(&g_repo, git_buf_cstr(&src), "./local.git", NULL, NULL));
|
cl_git_pass(git_clone_bare(&g_repo, git_buf_cstr(&src), "./local.git", NULL, NULL));
|
||||||
#endif
|
|
||||||
|
|
||||||
git_buf_free(&src);
|
git_buf_free(&src);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user