mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-01 18:47:31 +00:00
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.
This commit is contained in:
parent
c94785a9f3
commit
d88d4311c7
@ -1,17 +1,8 @@
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
#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;
|
char oid[GIT_OID_HEXSZ + 1] = {0};
|
||||||
git_remote_head *head;
|
git_oid_fmt(oid, &head->oid);
|
||||||
|
printf("%s\t%s\n", oid, head->name);
|
||||||
// Take each head that the remote has advertised, store the string
|
return GIT_SUCCESS;
|
||||||
// representation of the OID in a buffer and print it
|
|
||||||
|
|
||||||
for(i = 0; i < refs->len; ++i){
|
|
||||||
char oid[GIT_OID_HEXSZ + 1] = {0};
|
|
||||||
head = refs->heads[i];
|
|
||||||
git_oid_fmt(oid, &head->oid);
|
|
||||||
printf("%s\t%s\n", oid, head->name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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:
|
|||||||
|
|
||||||
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 @@
|
|||||||
|
|
||||||
#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
|
|||||||
#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 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 @@
|
|||||||
#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);
|
|||||||
* @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);
|
|||||||
*/
|
*/
|
||||||
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
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 {
|
|||||||
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
|
||||||
|
110
src/fetch.c
110
src/fetch.c
@ -18,30 +18,46 @@
|
|||||||
#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;
|
||||||
|
git_odb *odb;
|
||||||
|
int found_head;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int filter_ref__cb(git_remote_head *head, void *payload)
|
||||||
|
{
|
||||||
|
struct filter_payload *p = payload;
|
||||||
int error;
|
int error;
|
||||||
unsigned int i = 0;
|
|
||||||
|
|
||||||
error = git_vector_init(&list, 16, NULL);
|
if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) {
|
||||||
if (error < GIT_SUCCESS)
|
p->found_head = 1;
|
||||||
return error;
|
} else {
|
||||||
|
/* If it doesn't match the refpec, we don't want it */
|
||||||
|
error = git_refspec_src_match(p->spec, head->name);
|
||||||
|
|
||||||
error = t->ls(t, &refs);
|
if (error == GIT_ENOMATCH)
|
||||||
if (error < GIT_SUCCESS) {
|
return GIT_SUCCESS;
|
||||||
error = git__rethrow(error, "Failed to get remote ref list");
|
|
||||||
goto cleanup;
|
if (error < GIT_SUCCESS)
|
||||||
|
return git__rethrow(error, "Error matching remote ref name");
|
||||||
}
|
}
|
||||||
|
|
||||||
error = git_repository_odb__weakptr(&odb, remote->repo);
|
/* If we have the object, mark it so we don't ask for it */
|
||||||
if (error < GIT_SUCCESS)
|
if (git_odb_exists(p->odb, &head->oid))
|
||||||
goto cleanup;
|
head->local = 1;
|
||||||
|
else
|
||||||
|
p->remote->need_pack = 1;
|
||||||
|
|
||||||
|
return git_vector_insert(&p->remote->refs, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int filter_wants(git_remote *remote)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
struct filter_payload p;
|
||||||
|
|
||||||
|
git_vector_clear(&remote->refs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The fetch refspec can be NULL, and what this means is that the
|
* The fetch refspec can be NULL, and what this means is that the
|
||||||
@ -49,56 +65,15 @@ static int filter_wants(git_remote *remote)
|
|||||||
* not interested in any particular branch but just the remote's
|
* not interested in any particular branch but just the remote's
|
||||||
* HEAD, which will be stored in FETCH_HEAD after the fetch.
|
* HEAD, which will be stored in FETCH_HEAD after the fetch.
|
||||||
*/
|
*/
|
||||||
spec = git_remote_fetchspec(remote);
|
p.spec = git_remote_fetchspec(remote);
|
||||||
|
p.found_head = 0;
|
||||||
|
p.remote = remote;
|
||||||
|
|
||||||
/*
|
error = git_repository_odb__weakptr(&p.odb, remote->repo);
|
||||||
* We need to handle HEAD separately, as we always want it, but it
|
if (error < GIT_SUCCESS)
|
||||||
* probably won't matcht he refspec.
|
return error;
|
||||||
*/
|
|
||||||
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;
|
return remote->transport->ls(remote->transport, &filter_ref__cb, &p);
|
||||||
error = git_vector_insert(&list, refs.heads[0]);
|
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (git_odb_exists(odb, &head->oid))
|
|
||||||
head->local = 1;
|
|
||||||
else
|
|
||||||
remote->need_pack = 1;
|
|
||||||
|
|
||||||
error = git_vector_insert(&list, head);
|
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
remote->refs.len = list.length;
|
|
||||||
remote->refs.heads = (git_remote_head **) list.contents;
|
|
||||||
|
|
||||||
return GIT_SUCCESS;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
git_vector_free(&list);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -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;
|
||||||
|
|
||||||
|
24
src/pkt.c
24
src/pkt.c
@ -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
|
|||||||
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)
|
|||||||
|
|
||||||
/* 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
|||||||
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);
|
||||||
|
35
src/remote.c
35
src/remote.c
@ -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)
|
|||||||
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:
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
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 @@
|
|||||||
*/
|
*/
|
||||||
#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))
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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 {
|
|||||||
/**
|
/**
|
||||||
* 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 {
|
|||||||
* 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 {
|
|||||||
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:
|
|||||||
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
|
|||||||
|
|
||||||
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:
|
|||||||
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:
|
|||||||
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 @@
|
|||||||
*/
|
*/
|
||||||
#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,9 +17,137 @@
|
|||||||
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)
|
||||||
|
{
|
||||||
|
const char peeled[] = "^{}";
|
||||||
|
git_remote_head *head;
|
||||||
|
git_reference *ref, *resolved_ref;
|
||||||
|
git_object *obj = NULL;
|
||||||
|
int error = GIT_SUCCESS, peel_len, ret;
|
||||||
|
|
||||||
|
head = git__malloc(sizeof(git_remote_head));
|
||||||
|
if (head == NULL)
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
|
head->name = git__strdup(name);
|
||||||
|
if (head->name == NULL) {
|
||||||
|
error = GIT_ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = git_reference_lookup(&ref, t->repo, name);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
error = git_reference_resolve(&resolved_ref, ref);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
git_oid_cpy(&head->oid, git_reference_oid(ref));
|
||||||
|
|
||||||
|
error = git_vector_insert(&t->refs, head);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
head = NULL;
|
||||||
|
|
||||||
|
/* If it's not a tag, we don't need to try to peel it */
|
||||||
|
if (git__prefixcmp(name, GIT_REFS_TAGS_DIR))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
error = git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJ_ANY);
|
||||||
|
if (error < GIT_SUCCESS) {
|
||||||
|
git__rethrow(error, "Failed to lookup object");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If it's not an annotated tag, just get out */
|
||||||
|
if (git_object_type(obj) != GIT_OBJ_TAG)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* And if it's a tag, peel it, and add it to the list */
|
||||||
|
head = git__malloc(sizeof(git_remote_head));
|
||||||
|
peel_len = strlen(name) + strlen(peeled);
|
||||||
|
head->name = git__malloc(peel_len + 1);
|
||||||
|
ret = p_snprintf(head->name, peel_len + 1, "%s%s", name, peeled);
|
||||||
|
|
||||||
|
assert(ret < peel_len + 1);
|
||||||
|
|
||||||
|
git_oid_cpy(&head->oid, git_tag_target_oid((git_tag *) obj));
|
||||||
|
|
||||||
|
error = git_vector_insert(&t->refs, head);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
out:
|
||||||
|
git_reference_free(ref);
|
||||||
|
git_reference_free(resolved_ref);
|
||||||
|
|
||||||
|
git_object_free(obj);
|
||||||
|
if (head && error < GIT_SUCCESS) {
|
||||||
|
git__free(head->name);
|
||||||
|
git__free(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int store_refs(transport_local *t)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
unsigned int i;
|
||||||
|
git_strarray ref_names = {0};
|
||||||
|
|
||||||
|
assert(t);
|
||||||
|
|
||||||
|
error = git_vector_init(&t->refs, ref_names.count, NULL);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
error = git_reference_listall(&ref_names, t->repo, GIT_REF_LISTALL);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
return git__rethrow(error, "Failed to list remote heads");
|
||||||
|
|
||||||
|
/* Sort the references first */
|
||||||
|
git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb);
|
||||||
|
|
||||||
|
/* Add HEAD */
|
||||||
|
error = add_ref(t, GIT_HEAD_FILE);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
for (i = 0; i < ref_names.count; ++i) {
|
||||||
|
error = add_ref(t, ref_names.strings[i]);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
git_strarray_free(&ref_names);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
assert(transport && transport->connected);
|
||||||
|
|
||||||
|
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 GIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to open the url as a git directory. The direction doesn't
|
* Try to open the url as a git directory. The direction doesn't
|
||||||
* matter in this case because we're calulating the heads ourselves.
|
* matter in this case because we're calulating the heads ourselves.
|
||||||
@ -44,141 +171,23 @@ static int local_connect(git_transport *transport, int GIT_UNUSED(direction))
|
|||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
return git__rethrow(error, "Failed to open remote");
|
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->repo = repo;
|
||||||
t->parent.connected = 1;
|
t->parent.connected = 1;
|
||||||
|
|
||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_ref(const char *name, git_repository *repo, git_vector *vec)
|
|
||||||
{
|
|
||||||
const char peeled[] = "^{}";
|
|
||||||
git_remote_head *head;
|
|
||||||
git_reference *ref, *resolved_ref;
|
|
||||||
git_object *obj = NULL;
|
|
||||||
int error = GIT_SUCCESS, peel_len, ret;
|
|
||||||
|
|
||||||
head = git__malloc(sizeof(git_remote_head));
|
|
||||||
if (head == NULL)
|
|
||||||
return GIT_ENOMEM;
|
|
||||||
|
|
||||||
head->name = git__strdup(name);
|
|
||||||
if (head->name == NULL) {
|
|
||||||
error = GIT_ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = git_reference_lookup(&ref, repo, name);
|
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
error = git_reference_resolve(&resolved_ref, ref);
|
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
git_oid_cpy(&head->oid, git_reference_oid(ref));
|
|
||||||
|
|
||||||
error = git_vector_insert(vec, head);
|
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* If it's not a tag, we don't need to try to peel it */
|
|
||||||
if (git__prefixcmp(name, GIT_REFS_TAGS_DIR))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
error = git_object_lookup(&obj, repo, &head->oid, GIT_OBJ_ANY);
|
|
||||||
if (error < GIT_SUCCESS) {
|
|
||||||
git__rethrow(error, "Failed to lookup object");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If it's not an annotated tag, just get out */
|
|
||||||
if (git_object_type(obj) != GIT_OBJ_TAG)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* And if it's a tag, peel it, and add it to the list */
|
|
||||||
head = git__malloc(sizeof(git_remote_head));
|
|
||||||
peel_len = strlen(name) + strlen(peeled);
|
|
||||||
head->name = git__malloc(peel_len + 1);
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
git_oid_cpy(&head->oid, git_tag_target_oid((git_tag *) obj));
|
|
||||||
|
|
||||||
error = git_vector_insert(vec, head);
|
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
out:
|
|
||||||
git_reference_free(ref);
|
|
||||||
git_reference_free(resolved_ref);
|
|
||||||
|
|
||||||
git_object_free(obj);
|
|
||||||
if (error < GIT_SUCCESS) {
|
|
||||||
git__free(head->name);
|
|
||||||
git__free(head);
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int local_ls(git_transport *transport, git_headarray *array)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
unsigned int i;
|
|
||||||
git_repository *repo;
|
|
||||||
git_vector *vec;
|
|
||||||
git_strarray refs;
|
|
||||||
transport_local *t = (transport_local *) transport;
|
|
||||||
|
|
||||||
assert(transport && transport->connected);
|
|
||||||
|
|
||||||
repo = t->repo;
|
|
||||||
|
|
||||||
error = git_reference_listall(&refs, repo, GIT_REF_LISTALL);
|
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
return git__rethrow(error, "Failed to list remote heads");
|
|
||||||
|
|
||||||
vec = git__malloc(sizeof(git_vector));
|
|
||||||
if (vec == NULL) {
|
|
||||||
error = GIT_ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = git_vector_init(vec, refs.count, NULL);
|
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
/* Sort the references first */
|
|
||||||
git__tsort((void **)refs.strings, refs.count, &git__strcmp_cb);
|
|
||||||
|
|
||||||
/* Add HEAD */
|
|
||||||
error = add_ref(GIT_HEAD_FILE, repo, vec);
|
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
for (i = 0; i < refs.count; ++i) {
|
|
||||||
error = add_ref(refs.strings[i], repo, vec);
|
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
array->len = vec->length;
|
|
||||||
array->heads = (git_remote_head **)vec->contents;
|
|
||||||
|
|
||||||
t->refs = vec;
|
|
||||||
|
|
||||||
out:
|
|
||||||
|
|
||||||
git_strarray_free(&refs);
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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__free(vec);
|
|
||||||
}
|
}
|
||||||
|
git_vector_free(vec);
|
||||||
|
|
||||||
git_repository_free(t->repo);
|
|
||||||
git__free(t->parent.url);
|
git__free(t->parent.url);
|
||||||
git__free(t);
|
git__free(t);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user