Commit d88d4311 by Vicent Marti

remote: Cleanup the remotes code

- Hide the remaining transports code
- Drop `git_headarray`, switch to using a callback to list refs. Makes
the code cleaner.
parent c94785a9
default: all 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 CC = gcc
CFLAGS += -g CFLAGS += -g
CFLAGS += $(DEPS) CFLAGS += -I../../include -L../../ -lgit2
OBJECTS = \ OBJECTS = \
git2.o \ git2.o \
......
...@@ -4,23 +4,6 @@ ...@@ -4,23 +4,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.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) static int rename_packfile(char *packname, git_indexer *idx)
{ {
char path[GIT_PATH_MAX], oid[GIT_OID_HEXSZ + 1], *slash; char path[GIT_PATH_MAX], oid[GIT_OID_HEXSZ + 1], *slash;
...@@ -50,20 +33,14 @@ static int rename_packfile(char *packname, git_indexer *idx) ...@@ -50,20 +33,14 @@ static int rename_packfile(char *packname, git_indexer *idx)
int fetch(git_repository *repo, int argc, char **argv) int fetch(git_repository *repo, int argc, char **argv)
{ {
git_remote *remote = NULL; git_remote *remote = NULL;
git_config *cfg = NULL;
git_indexer *idx = NULL; git_indexer *idx = NULL;
git_indexer_stats stats; git_indexer_stats stats;
int error; int error;
char *packname = NULL; 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 // Get the remote and connect to it
printf("Fetching %s\n", argv[1]); 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) if (error < GIT_SUCCESS)
return error; return error;
...@@ -71,13 +48,6 @@ int fetch(git_repository *repo, int argc, char **argv) ...@@ -71,13 +48,6 @@ int fetch(git_repository *repo, int argc, char **argv)
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; 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 // Download the packfile from the server. As we don't know its hash
// yet, it will get a temporary filename // yet, it will get a temporary filename
error = git_remote_download(&packname, remote); error = git_remote_download(&packname, remote);
......
...@@ -4,31 +4,22 @@ ...@@ -4,31 +4,22 @@
#include <string.h> #include <string.h>
#include "common.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}; char oid[GIT_OID_HEXSZ + 1] = {0};
head = refs->heads[i];
git_oid_fmt(oid, &head->oid); git_oid_fmt(oid, &head->oid);
printf("%s\t%s\n", oid, head->name); printf("%s\t%s\n", oid, head->name);
} return GIT_SUCCESS;
} }
int use_unnamed(git_repository *repo, const char *url) int use_unnamed(git_repository *repo, const char *url)
{ {
git_remote *remote = NULL; git_remote *remote = NULL;
git_headarray refs;
int error; int error;
// Create an instance of a remote from the URL. The transport to use // Create an instance of a remote from the URL. The transport to use
// is detected from the URL // is detected from the URL
error = git_remote_new(&remote, repo, url); error = git_remote_new(&remote, repo, url, NULL);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -39,32 +30,20 @@ int use_unnamed(git_repository *repo, const char *url) ...@@ -39,32 +30,20 @@ int use_unnamed(git_repository *repo, const char *url)
goto cleanup; goto cleanup;
// With git_remote_ls we can retrieve the advertised heads // With git_remote_ls we can retrieve the advertised heads
error = git_remote_ls(remote, &refs); error = git_remote_ls(remote, &show_ref__cb, NULL);
if (error < GIT_SUCCESS)
goto cleanup;
show_refs(&refs);
cleanup: cleanup:
git_remote_free(remote); git_remote_free(remote);
return error; return error;
} }
int use_remote(git_repository *repo, char *name) int use_remote(git_repository *repo, char *name)
{ {
git_remote *remote = NULL; git_remote *remote = NULL;
git_config *cfg = NULL;
git_headarray refs;
int error; 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 // Find the remote by name
error = git_remote_get(&remote, cfg, name); error = git_remote_load(&remote, repo, name);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -72,15 +51,10 @@ int use_remote(git_repository *repo, char *name) ...@@ -72,15 +51,10 @@ int use_remote(git_repository *repo, char *name)
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
error = git_remote_ls(remote, &refs); error = git_remote_ls(remote, &show_ref__cb, NULL);
if (error < GIT_SUCCESS)
goto cleanup;
show_refs(&refs);
cleanup: cleanup:
git_remote_free(remote); git_remote_free(remote);
return error; return error;
} }
...@@ -89,8 +63,6 @@ cleanup: ...@@ -89,8 +63,6 @@ cleanup:
int ls_remote(git_repository *repo, int argc, char **argv) int ls_remote(git_repository *repo, int argc, char **argv)
{ {
git_headarray heads;
git_remote_head *head;
int error, i; int error, i;
/* If there's a ':' in the name, assume it's an URL */ /* If there's a ':' in the name, assume it's an URL */
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include "git2/refspec.h" #include "git2/refspec.h"
#include "git2/net.h" #include "git2/net.h"
#include "git2/transport.h"
#include "git2/status.h" #include "git2/status.h"
#include "git2/indexer.h" #include "git2/indexer.h"
......
...@@ -30,6 +30,7 @@ GIT_BEGIN_DECL ...@@ -30,6 +30,7 @@ GIT_BEGIN_DECL
#define GIT_DIR_FETCH 0 #define GIT_DIR_FETCH 0
#define GIT_DIR_PUSH 1 #define GIT_DIR_PUSH 1
/** /**
* Remote head description, given out on `ls` calls. * Remote head description, given out on `ls` calls.
*/ */
...@@ -41,12 +42,9 @@ struct git_remote_head { ...@@ -41,12 +42,9 @@ struct git_remote_head {
}; };
/** /**
* Array of remote heads * Callback for listing the remote heads
*/ */
struct git_headarray { typedef int (*git_headlist_cb)(git_remote_head *, void *);
unsigned int len;
struct git_remote_head **heads;
};
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include "common.h" #include "common.h"
#include "repository.h" #include "repository.h"
#include "refspec.h" #include "refspec.h"
#include "net.h"
/** /**
* @file git2/remote.h * @file git2/remote.h
* @brief Git remote management functions * @brief Git remote management functions
...@@ -107,7 +109,7 @@ GIT_EXTERN(int) git_remote_connect(git_remote *remote, int direction); ...@@ -107,7 +109,7 @@ GIT_EXTERN(int) git_remote_connect(git_remote *remote, int direction);
* @param remote the remote * @param remote the remote
* @return GIT_SUCCESS or an error code * @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 * Download the packfile
...@@ -161,6 +163,14 @@ GIT_EXTERN(void) git_remote_free(git_remote *remote); ...@@ -161,6 +163,14 @@ GIT_EXTERN(void) git_remote_free(git_remote *remote);
*/ */
GIT_EXTERN(int) git_remote_update_tips(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 GIT_END_DECL
#endif #endif
/*
* 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
...@@ -161,13 +161,7 @@ typedef enum { ...@@ -161,13 +161,7 @@ typedef enum {
typedef struct git_refspec git_refspec; typedef struct git_refspec git_refspec;
typedef struct git_remote git_remote; 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_remote_head git_remote_head;
typedef struct git_headarray git_headarray;
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -18,87 +18,62 @@ ...@@ -18,87 +18,62 @@
#include "fetch.h" #include "fetch.h"
#include "netops.h" #include "netops.h"
static int filter_wants(git_remote *remote) struct filter_payload {
{ git_remote *remote;
git_vector list;
git_headarray refs;
git_remote_head *head;
git_transport *t = remote->transport;
git_odb *odb = NULL;
const git_refspec *spec; const git_refspec *spec;
int error; git_odb *odb;
unsigned int i = 0; int found_head;
};
error = git_vector_init(&list, 16, NULL);
if (error < GIT_SUCCESS)
return error;
error = t->ls(t, &refs); static int filter_ref__cb(git_remote_head *head, void *payload)
if (error < GIT_SUCCESS) { {
error = git__rethrow(error, "Failed to get remote ref list"); struct filter_payload *p = payload;
goto cleanup; int error;
}
error = git_repository_odb__weakptr(&odb, remote->repo);
if (error < GIT_SUCCESS)
goto cleanup;
/* if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) {
* The fetch refspec can be NULL, and what this means is that the p->found_head = 1;
* user didn't specify one. This is fine, as it means that we're } else {
* not interested in any particular branch but just the remote's /* If it doesn't match the refpec, we don't want it */
* HEAD, which will be stored in FETCH_HEAD after the fetch. error = git_refspec_src_match(p->spec, head->name);
*/
spec = git_remote_fetchspec(remote);
/* if (error == GIT_ENOMATCH)
* We need to handle HEAD separately, as we always want it, but it return GIT_SUCCESS;
* 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) if (error < GIT_SUCCESS)
goto cleanup; return git__rethrow(error, "Error matching remote ref name");
}
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 we have the object, mark it so we don't ask for it */
if (git_odb_exists(odb, &head->oid)) if (git_odb_exists(p->odb, &head->oid))
head->local = 1; head->local = 1;
else else
remote->need_pack = 1; p->remote->need_pack = 1;
error = git_vector_insert(&list, head); return git_vector_insert(&p->remote->refs, head);
if (error < GIT_SUCCESS) }
goto cleanup;
} static int filter_wants(git_remote *remote)
{
int error;
struct filter_payload p;
remote->refs.len = list.length; git_vector_clear(&remote->refs);
remote->refs.heads = (git_remote_head **) list.contents;
return GIT_SUCCESS; /*
* The fetch refspec can be NULL, and what this means is that the
* user didn't specify one. This is fine, as it means that we're
* not interested in any particular branch but just the remote's
* HEAD, which will be stored in FETCH_HEAD after the fetch.
*/
p.spec = git_remote_fetchspec(remote);
p.found_head = 0;
p.remote = remote;
cleanup: error = git_repository_odb__weakptr(&p.odb, remote->repo);
git_vector_free(&list); if (error < GIT_SUCCESS)
return error; return error;
return remote->transport->ls(remote->transport, &filter_ref__cb, &p);
} }
/* /*
...@@ -116,8 +91,9 @@ int git_fetch_negotiate(git_remote *remote) ...@@ -116,8 +91,9 @@ int git_fetch_negotiate(git_remote *remote)
return git__rethrow(error, "Failed to filter the reference list for wants"); return git__rethrow(error, "Failed to filter the reference list for wants");
/* Don't try to negotiate when we don't want anything */ /* Don't try to negotiate when we don't want anything */
if (remote->refs.len == 0) if (remote->refs.length == 0)
return GIT_SUCCESS; return GIT_SUCCESS;
if (!remote->need_pack) if (!remote->need_pack)
return GIT_SUCCESS; return GIT_SUCCESS;
......
...@@ -316,30 +316,30 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, ...@@ -316,30 +316,30 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps,
* is overwrite the OID each time. * 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; unsigned int i = 0;
int error; int error;
git_remote_head *head; git_remote_head *head;
if (caps->common) { if (caps->common) {
for (; i < refs->len; ++i) { for (; i < refs->length; ++i) {
head = refs->heads[i]; head = refs->contents[i];
if (!head->local) if (!head->local)
break; 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) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to buffer want with caps"); return git__rethrow(error, "Failed to buffer want with caps");
i++; i++;
} }
for (; i < refs->len; ++i) { for (; i < refs->length; ++i) {
char oid[GIT_OID_HEXSZ]; char oid[GIT_OID_HEXSZ];
head = refs->heads[i]; head = refs->contents[i];
if (head->local) if (head->local)
continue; continue;
...@@ -352,7 +352,7 @@ int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf ...@@ -352,7 +352,7 @@ int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf
return git_pkt_buffer_flush(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; unsigned int i = 0;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
...@@ -365,15 +365,15 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) ...@@ -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 there are common caps, find the first one */
if (caps->common) { if (caps->common) {
for (; i < refs->len; ++i) { for (; i < refs->length; ++i) {
head = refs->heads[i]; head = refs->contents[i];
if (head->local) if (head->local)
continue; continue;
else else
break; 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) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send want pkt with caps"); return git__rethrow(error, "Failed to send want pkt with caps");
/* Increase it here so it's correct whether we run this or not */ /* 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) ...@@ -381,8 +381,8 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd)
} }
/* Continue from where we left off */ /* Continue from where we left off */
for (; i < refs->len; ++i) { for (; i < refs->length; ++i) {
head = refs->heads[i]; head = refs->contents[i];
if (head->local) if (head->local)
continue; continue;
......
...@@ -68,8 +68,8 @@ int git_pkt_buffer_flush(git_buf *buf); ...@@ -68,8 +68,8 @@ int git_pkt_buffer_flush(git_buf *buf);
int git_pkt_send_flush(int s); int git_pkt_send_flush(int s);
int git_pkt_buffer_done(git_buf *buf); int git_pkt_buffer_done(git_buf *buf);
int git_pkt_send_done(int s); 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_buffer_wants(const git_vector *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_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_buffer_have(git_oid *oid, git_buf *buf);
int git_pkt_send_have(git_oid *oid, int fd); int git_pkt_send_have(git_oid *oid, int fd);
void git_pkt_free(git_pkt *pkt); void git_pkt_free(git_pkt *pkt);
......
...@@ -70,16 +70,21 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *url, cons ...@@ -70,16 +70,21 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *url, cons
memset(remote, 0x0, sizeof(git_remote)); memset(remote, 0x0, sizeof(git_remote));
remote->repo = repo; remote->repo = repo;
if (git_vector_init(&remote->refs, 32, NULL) < 0) {
git_remote_free(remote);
return GIT_ENOMEM;
}
remote->url = git__strdup(url); remote->url = git__strdup(url);
if (remote->url == NULL) { if (remote->url == NULL) {
git__free(remote); git_remote_free(remote);
return GIT_ENOMEM; return GIT_ENOMEM;
} }
if (name != NULL) { if (name != NULL) {
remote->name = git__strdup(name); remote->name = git__strdup(name);
if (remote->name == NULL) { if (remote->name == NULL) {
git__free(remote); git_remote_free(remote);
return GIT_ENOMEM; return GIT_ENOMEM;
} }
} }
...@@ -113,6 +118,11 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) ...@@ -113,6 +118,11 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
goto cleanup; 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 */ /* "fetch" is the longest var name we're interested in */
buf_len = strlen("remote.") + strlen(".fetch") + strlen(name) + 1; buf_len = strlen("remote.") + strlen(".fetch") + strlen(name) + 1;
buf = git__malloc(buf_len); buf = git__malloc(buf_len);
...@@ -227,10 +237,14 @@ cleanup: ...@@ -227,10 +237,14 @@ cleanup:
return error; 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); assert(remote);
return remote->transport->ls(remote->transport, refs);
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) int git_remote_download(char **filename, git_remote *remote)
...@@ -250,7 +264,7 @@ int git_remote_update_tips(git_remote *remote) ...@@ -250,7 +264,7 @@ int git_remote_update_tips(git_remote *remote)
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
unsigned int i = 0; unsigned int i = 0;
char refname[GIT_PATH_MAX]; char refname[GIT_PATH_MAX];
git_headarray *refs = &remote->refs; git_vector *refs = &remote->refs;
git_remote_head *head; git_remote_head *head;
git_reference *ref; git_reference *ref;
struct git_refspec *spec = &remote->fetch; struct git_refspec *spec = &remote->fetch;
...@@ -259,11 +273,11 @@ int git_remote_update_tips(git_remote *remote) ...@@ -259,11 +273,11 @@ int git_remote_update_tips(git_remote *remote)
memset(refname, 0x0, sizeof(refname)); memset(refname, 0x0, sizeof(refname));
if (refs->len == 0) if (refs->length == 0)
return GIT_SUCCESS; return GIT_SUCCESS;
/* HEAD is only allowed to be the first in the list */ /* 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)) { if (!strcmp(head->name, GIT_HEAD_FILE)) {
error = git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1); error = git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1);
i = 1; i = 1;
...@@ -272,8 +286,8 @@ int git_remote_update_tips(git_remote *remote) ...@@ -272,8 +286,8 @@ int git_remote_update_tips(git_remote *remote)
return git__rethrow(error, "Failed to update FETCH_HEAD"); return git__rethrow(error, "Failed to update FETCH_HEAD");
} }
for (; i < refs->len; ++i) { for (; i < refs->length; ++i) {
head = refs->heads[i]; head = refs->contents[i];
error = git_refspec_transform(refname, sizeof(refname), spec, head->name); error = git_refspec_transform(refname, sizeof(refname), spec, head->name);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
...@@ -319,6 +333,7 @@ void git_remote_free(git_remote *remote) ...@@ -319,6 +333,7 @@ void git_remote_free(git_remote *remote)
git__free(remote->push.dst); git__free(remote->push.dst);
git__free(remote->url); git__free(remote->url);
git__free(remote->name); git__free(remote->name);
git_vector_free(&remote->refs);
git_remote_disconnect(remote); git_remote_disconnect(remote);
git__free(remote); git__free(remote);
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
struct git_remote { struct git_remote {
char *name; char *name;
char *url; char *url;
git_headarray refs; git_vector refs;
struct git_refspec fetch; struct git_refspec fetch;
struct git_refspec push; struct git_refspec push;
git_transport *transport; git_transport *transport;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
*/ */
#include "common.h" #include "common.h"
#include "git2/types.h" #include "git2/types.h"
#include "git2/transport.h" #include "git2/remote.h"
#include "git2/net.h" #include "git2/net.h"
#include "transport.h" #include "transport.h"
...@@ -49,11 +49,6 @@ int git_transport_dummy(git_transport **GIT_UNUSED(transport)) ...@@ -49,11 +49,6 @@ int git_transport_dummy(git_transport **GIT_UNUSED(transport))
return git__throw(GIT_ENOTIMPLEMENTED, "This protocol isn't implemented. Sorry"); 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) int git_transport_new(git_transport **out, const char *url)
{ {
git_transport_cb fn; git_transport_cb fn;
...@@ -81,3 +76,10 @@ int git_transport_new(git_transport **out, const char *url) ...@@ -81,3 +76,10 @@ int git_transport_new(git_transport **out, const char *url)
return GIT_SUCCESS; return GIT_SUCCESS;
} }
/* from remote.h */
int git_remote_valid_url(const char *url)
{
return transport_find_fn(url) != NULL;
}
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#ifndef INCLUDE_transport_h__ #ifndef INCLUDE_transport_h__
#define INCLUDE_transport_h__ #define INCLUDE_transport_h__
#include "git2/transport.h"
#include "git2/net.h" #include "git2/net.h"
#include "vector.h" #include "vector.h"
...@@ -61,7 +60,7 @@ struct git_transport { ...@@ -61,7 +60,7 @@ struct git_transport {
/** /**
* Give a list of references, useful for ls-remote * 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 * Push the changes over
*/ */
...@@ -74,7 +73,7 @@ struct git_transport { ...@@ -74,7 +73,7 @@ struct git_transport {
* Negotiate the minimal amount of objects that need to be * Negotiate the minimal amount of objects that need to be
* retrieved * 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 * Send a flush
*/ */
...@@ -97,9 +96,15 @@ struct git_transport { ...@@ -97,9 +96,15 @@ struct git_transport {
void (*free)(struct git_transport *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_local(struct git_transport **transport);
int git_transport_git(struct git_transport **transport); int git_transport_git(struct git_transport **transport);
int git_transport_http(struct git_transport **transport); int git_transport_http(struct git_transport **transport);
int git_transport_dummy(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 #endif
...@@ -226,32 +226,30 @@ cleanup: ...@@ -226,32 +226,30 @@ cleanup:
return error; 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; transport_git *t = (transport_git *) transport;
git_vector *refs = &t->refs; git_vector *refs = &t->refs;
int len = 0;
unsigned int i; unsigned int i;
git_pkt *p = NULL;
array->heads = git__calloc(refs->length, sizeof(git_remote_head *)); git_vector_foreach(refs, i, p) {
if (array->heads == NULL) git_pkt_ref *pkt = NULL;
return GIT_ENOMEM;
for (i = 0; i < refs->length; ++i) {
git_pkt *p = git_vector_get(refs, i);
if (p->type != GIT_PKT_REF) if (p->type != GIT_PKT_REF)
continue; continue;
++len; pkt = (git_pkt_ref *)p;
array->heads[i] = &(((git_pkt_ref *) p)->head);
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; 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; transport_git *t = (transport_git *) transport;
git_revwalk *walk; git_revwalk *walk;
...@@ -290,6 +288,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g ...@@ -290,6 +288,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
if (git_reference_type(ref) == GIT_REF_SYMBOLIC) if (git_reference_type(ref) == GIT_REF_SYMBOLIC)
continue; continue;
error = git_revwalk_push(walk, git_reference_oid(ref)); error = git_revwalk_push(walk, git_reference_oid(ref));
if (error < GIT_ERROR) { if (error < GIT_ERROR) {
error = git__rethrow(error, "Failed to push %s", refs.strings[i]); error = git__rethrow(error, "Failed to push %s", refs.strings[i]);
......
...@@ -301,29 +301,22 @@ cleanup: ...@@ -301,29 +301,22 @@ cleanup:
return error; 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; transport_http *t = (transport_http *) transport;
git_vector *refs = &t->refs; git_vector *refs = &t->refs;
unsigned int i; unsigned int i;
int len = 0;
git_pkt_ref *p; 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) { git_vector_foreach(refs, i, p) {
if (p->type != GIT_PKT_REF) if (p->type != GIT_PKT_REF)
continue; continue;
array->heads[len] = &p->head; if (list_cb(&p->head, opaque) < 0)
len++; return git__throw(GIT_ERROR,
"The user callback returned an error code");
} }
array->len = len;
t->heads = array->heads;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
...@@ -470,7 +463,7 @@ cleanup: ...@@ -470,7 +463,7 @@ cleanup:
return error; 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; transport_http *t = (transport_http *) transport;
int error; int error;
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
*/ */
#include "common.h" #include "common.h"
#include "git2/types.h" #include "git2/types.h"
#include "git2/transport.h"
#include "git2/net.h" #include "git2/net.h"
#include "git2/repository.h" #include "git2/repository.h"
#include "git2/object.h" #include "git2/object.h"
...@@ -18,39 +17,10 @@ ...@@ -18,39 +17,10 @@
typedef struct { typedef struct {
git_transport parent; git_transport parent;
git_repository *repo; git_repository *repo;
git_vector *refs; git_vector refs;
} transport_local; } transport_local;
/* static int add_ref(transport_local *t, const char *name)
* 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)
{ {
const char peeled[] = "^{}"; const char peeled[] = "^{}";
git_remote_head *head; git_remote_head *head;
...@@ -68,7 +38,7 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) ...@@ -68,7 +38,7 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec)
goto out; goto out;
} }
error = git_reference_lookup(&ref, repo, name); error = git_reference_lookup(&ref, t->repo, name);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto out; goto out;
...@@ -78,15 +48,17 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) ...@@ -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)); 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) if (error < GIT_SUCCESS)
goto out; goto out;
head = NULL;
/* If it's not a tag, we don't need to try to peel it */ /* If it's not a tag, we don't need to try to peel it */
if (git__prefixcmp(name, GIT_REFS_TAGS_DIR)) if (git__prefixcmp(name, GIT_REFS_TAGS_DIR))
goto out; 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) { if (error < GIT_SUCCESS) {
git__rethrow(error, "Failed to lookup object"); git__rethrow(error, "Failed to lookup object");
} }
...@@ -100,13 +72,12 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) ...@@ -100,13 +72,12 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec)
peel_len = strlen(name) + strlen(peeled); peel_len = strlen(name) + strlen(peeled);
head->name = git__malloc(peel_len + 1); head->name = git__malloc(peel_len + 1);
ret = p_snprintf(head->name, peel_len + 1, "%s%s", name, peeled); 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)); 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) if (error < GIT_SUCCESS)
goto out; goto out;
...@@ -115,70 +86,108 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) ...@@ -115,70 +86,108 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec)
git_reference_free(resolved_ref); git_reference_free(resolved_ref);
git_object_free(obj); git_object_free(obj);
if (error < GIT_SUCCESS) { if (head && error < GIT_SUCCESS) {
git__free(head->name); git__free(head->name);
git__free(head); git__free(head);
} }
return error; return error;
} }
static int local_ls(git_transport *transport, git_headarray *array) static int store_refs(transport_local *t)
{ {
int error; int error;
unsigned int i; unsigned int i;
git_repository *repo; git_strarray ref_names = {0};
git_vector *vec;
git_strarray refs;
transport_local *t = (transport_local *) transport;
assert(transport && transport->connected); assert(t);
repo = t->repo;
error = git_reference_listall(&refs, repo, GIT_REF_LISTALL); error = git_vector_init(&t->refs, ref_names.count, NULL);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to list remote heads"); return error;
vec = git__malloc(sizeof(git_vector));
if (vec == NULL) {
error = GIT_ENOMEM;
goto out;
}
error = git_vector_init(vec, refs.count, NULL); error = git_reference_listall(&ref_names, t->repo, GIT_REF_LISTALL);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return git__rethrow(error, "Failed to list remote heads");
/* Sort the references first */ /* 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 */ /* Add HEAD */
error = add_ref(GIT_HEAD_FILE, repo, vec); error = add_ref(t, GIT_HEAD_FILE);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto out; goto cleanup;
for (i = 0; i < refs.count; ++i) { for (i = 0; i < ref_names.count; ++i) {
error = add_ref(refs.strings[i], repo, vec); error = add_ref(t, ref_names.strings[i]);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto out; goto cleanup;
} }
array->len = vec->length; cleanup:
array->heads = (git_remote_head **)vec->contents; 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)) static int local_close(git_transport *GIT_UNUSED(transport))
{ {
/* Nothing to do */ transport_local *t = (transport_local *)transport;
GIT_UNUSED_ARG(transport);
git_repository_free(t->repo);
t->repo = NULL;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
...@@ -186,21 +195,17 @@ static void local_free(git_transport *transport) ...@@ -186,21 +195,17 @@ static void local_free(git_transport *transport)
{ {
unsigned int i; unsigned int i;
transport_local *t = (transport_local *) transport; transport_local *t = (transport_local *) transport;
git_vector *vec = t->refs; git_vector *vec = &t->refs;
git_remote_head *h; git_remote_head *h;
assert(transport); assert(transport);
if (t->refs != NULL) {
git_vector_foreach (vec, i, h) { git_vector_foreach (vec, i, h) {
git__free(h->name); git__free(h->name);
git__free(h); git__free(h);
} }
git_vector_free(vec); git_vector_free(vec);
git__free(vec);
}
git_repository_free(t->repo);
git__free(t->parent.url); git__free(t->parent.url);
git__free(t); git__free(t);
} }
......
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