mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-06 21:08:56 +00:00
merge branch development
This commit is contained in:
commit
1eb0f68ec7
@ -135,6 +135,16 @@ GIT_EXTERN(const git_signature *) git_commit_author(git_commit *commit);
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_commit_tree(git_tree **tree_out, git_commit *commit);
|
GIT_EXTERN(int) git_commit_tree(git_tree **tree_out, git_commit *commit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the id of the tree pointed to by a commit. This differs from
|
||||||
|
* `git_commit_tree` in that no attempts are made to fetch an object
|
||||||
|
* from the ODB.
|
||||||
|
*
|
||||||
|
* @param commit a previously loaded commit.
|
||||||
|
* @return the id of tree pointed to by commit.
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const git_oid *) git_commit_tree_oid(git_commit *commit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of parents of this commit
|
* Get the number of parents of this commit
|
||||||
*
|
*
|
||||||
@ -153,6 +163,16 @@ GIT_EXTERN(unsigned int) git_commit_parentcount(git_commit *commit);
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n);
|
GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the oid of a specified parent for a commit. This is different from
|
||||||
|
* `git_commit_parent`, which will attempt to load the parent commit from
|
||||||
|
* the ODB.
|
||||||
|
*
|
||||||
|
* @param commit a previously loaded commit.
|
||||||
|
* @param n the position of the parent (from 0 to `parentcount`)
|
||||||
|
* @return the id of the parent, NULL on error.
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const git_oid *) git_commit_parent_oid(git_commit *commit, unsigned int n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new commit in the repository
|
* Create a new commit in the repository
|
||||||
|
@ -164,6 +164,12 @@
|
|||||||
/** A reference with this name already exists */
|
/** A reference with this name already exists */
|
||||||
#define GIT_EEXISTS (GIT_ERROR - 23)
|
#define GIT_EEXISTS (GIT_ERROR - 23)
|
||||||
|
|
||||||
|
/** The given integer literal is too large to be parsed */
|
||||||
|
#define GIT_EOVERFLOW (GIT_ERROR - 24)
|
||||||
|
|
||||||
|
/** The given literal is not a valid number */
|
||||||
|
#define GIT_ENOTNUM (GIT_ERROR - 25)
|
||||||
|
|
||||||
GIT_BEGIN_DECL
|
GIT_BEGIN_DECL
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -182,6 +182,36 @@ GIT_EXTERN(void) git_repository_free(git_repository *repo);
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare);
|
GIT_EXTERN(int) git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a repository is empty
|
||||||
|
*
|
||||||
|
* An empty repository has just been initialized and contains
|
||||||
|
* no commits.
|
||||||
|
*
|
||||||
|
* @param repo Repo to test
|
||||||
|
* @return 1 if the repository is empty, 0 if it isn't, error code
|
||||||
|
* if the repository is corrupted
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(int) git_repository_is_empty(git_repository *repo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the normalized path to the git repository.
|
||||||
|
*
|
||||||
|
* @param repo a repository object
|
||||||
|
* @return absolute path to the git directory
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const char *) git_repository_path(git_repository *repo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the normalized path to the working directory of the repository.
|
||||||
|
*
|
||||||
|
* If the repository is bare, there is no working directory and NULL we be returned.
|
||||||
|
*
|
||||||
|
* @param repo a repository object
|
||||||
|
* @return NULL if the repository is bare; absolute path to the working directory otherwise.
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
GIT_END_DECL
|
GIT_END_DECL
|
||||||
#endif
|
#endif
|
||||||
|
@ -41,19 +41,30 @@ GIT_BEGIN_DECL
|
|||||||
* Create a new action signature. The signature must be freed
|
* Create a new action signature. The signature must be freed
|
||||||
* manually or using git_signature_free
|
* manually or using git_signature_free
|
||||||
*
|
*
|
||||||
* @name name of the person
|
* @param name name of the person
|
||||||
* @email email of the person
|
* @param mail email of the person
|
||||||
* @time time when the action happened
|
* @param time time when the action happened
|
||||||
* @offset timezone offset in minutes for the time
|
* @param offset timezone offset in minutes for the time
|
||||||
* @return the new sig, NULL on out of memory
|
* @return the new sig, NULL on out of memory
|
||||||
*/
|
*/
|
||||||
GIT_EXTERN(git_signature *) git_signature_new(const char *name, const char *email, git_time_t time, int offset);
|
GIT_EXTERN(git_signature *) git_signature_new(const char *name, const char *email, git_time_t time, int offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new action signature with a timestamp of 'now'. The
|
||||||
|
* signature must be freed manually or using git_signature_free
|
||||||
|
*
|
||||||
|
* @param name name of the person
|
||||||
|
* @param email email of the person
|
||||||
|
* @return the new sig, NULL on out of memory
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(git_signature *) git_signature_now(const char *name, const char *email);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a copy of an existing signature.
|
* Create a copy of an existing signature.
|
||||||
*
|
*
|
||||||
* All internal strings are also duplicated.
|
* All internal strings are also duplicated.
|
||||||
* @sig signature to duplicated
|
* @param sig signature to duplicated
|
||||||
* @return a copy of sig, NULL on out of memory
|
* @return a copy of sig, NULL on out of memory
|
||||||
*/
|
*/
|
||||||
GIT_EXTERN(git_signature *) git_signature_dup(const git_signature *sig);
|
GIT_EXTERN(git_signature *) git_signature_dup(const git_signature *sig);
|
||||||
@ -61,7 +72,7 @@ GIT_EXTERN(git_signature *) git_signature_dup(const git_signature *sig);
|
|||||||
/**
|
/**
|
||||||
* Free an existing signature
|
* Free an existing signature
|
||||||
*
|
*
|
||||||
* @sig signature to free
|
* @param sig signature to free
|
||||||
*/
|
*/
|
||||||
GIT_EXTERN(void) git_signature_free(git_signature *sig);
|
GIT_EXTERN(void) git_signature_free(git_signature *sig);
|
||||||
|
|
||||||
|
200
src/backends/hiredis.c
Normal file
200
src/backends/hiredis.c
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License, version 2,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* In addition to the permissions in the GNU General Public License,
|
||||||
|
* the authors give you unlimited permission to link the compiled
|
||||||
|
* version of this file into combinations with other programs,
|
||||||
|
* and to distribute those combinations without any restriction
|
||||||
|
* coming from the use of this file. (The General Public License
|
||||||
|
* restrictions do apply in other respects; for example, they cover
|
||||||
|
* modification of the file, and distribution when not linked into
|
||||||
|
* a combined executable.)
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "git2/object.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "odb.h"
|
||||||
|
|
||||||
|
#include "git2/odb_backend.h"
|
||||||
|
|
||||||
|
#ifdef GIT2_HIREDIS_BACKEND
|
||||||
|
|
||||||
|
#include <hiredis/hiredis.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
git_odb_backend parent;
|
||||||
|
|
||||||
|
redisContext *db;
|
||||||
|
} hiredis_backend;
|
||||||
|
|
||||||
|
int hiredis_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *_backend, const git_oid *oid) {
|
||||||
|
hiredis_backend *backend;
|
||||||
|
int error;
|
||||||
|
redisReply *reply;
|
||||||
|
|
||||||
|
assert(len_p && type_p && _backend && oid);
|
||||||
|
|
||||||
|
backend = (hiredis_backend *) _backend;
|
||||||
|
error = GIT_ERROR;
|
||||||
|
|
||||||
|
reply = redisCommand(backend->db, "HMGET %b %s %s", oid->id, GIT_OID_RAWSZ,
|
||||||
|
"type", "size");
|
||||||
|
|
||||||
|
if (reply->type == REDIS_REPLY_ARRAY) {
|
||||||
|
if (reply->element[0]->type != REDIS_REPLY_NIL &&
|
||||||
|
reply->element[0]->type != REDIS_REPLY_NIL) {
|
||||||
|
*type_p = (git_otype) atoi(reply->element[0]->str);
|
||||||
|
*len_p = (size_t) atoi(reply->element[1]->str);
|
||||||
|
error = GIT_SUCCESS;
|
||||||
|
} else {
|
||||||
|
error = GIT_ENOTFOUND;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error = GIT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeReplyObject(reply);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hiredis_backend__read(void **data_p, size_t *len_p, git_otype *type_p, git_odb_backend *_backend, const git_oid *oid) {
|
||||||
|
hiredis_backend *backend;
|
||||||
|
int error;
|
||||||
|
redisReply *reply;
|
||||||
|
|
||||||
|
assert(data_p && len_p && type_p && _backend && oid);
|
||||||
|
|
||||||
|
backend = (hiredis_backend *) _backend;
|
||||||
|
error = GIT_ERROR;
|
||||||
|
|
||||||
|
reply = redisCommand(backend->db, "HMGET %b %s %s %s", oid->id, GIT_OID_RAWSZ,
|
||||||
|
"type", "size", "data");
|
||||||
|
|
||||||
|
if (reply->type == REDIS_REPLY_ARRAY) {
|
||||||
|
if (reply->element[0]->type != REDIS_REPLY_NIL &&
|
||||||
|
reply->element[1]->type != REDIS_REPLY_NIL &&
|
||||||
|
reply->element[2]->type != REDIS_REPLY_NIL) {
|
||||||
|
*type_p = (git_otype) atoi(reply->element[0]->str);
|
||||||
|
*len_p = (size_t) atoi(reply->element[1]->str);
|
||||||
|
*data_p = git__malloc(*len_p);
|
||||||
|
if (*data_p == NULL) {
|
||||||
|
error = GIT_ENOMEM;
|
||||||
|
} else {
|
||||||
|
memcpy(*data_p, reply->element[2]->str, *len_p);
|
||||||
|
error = GIT_SUCCESS;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error = GIT_ENOTFOUND;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error = GIT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeReplyObject(reply);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hiredis_backend__exists(git_odb_backend *_backend, const git_oid *oid) {
|
||||||
|
hiredis_backend *backend;
|
||||||
|
int found;
|
||||||
|
redisReply *reply;
|
||||||
|
|
||||||
|
assert(_backend && oid);
|
||||||
|
|
||||||
|
backend = (hiredis_backend *) _backend;
|
||||||
|
found = 0;
|
||||||
|
|
||||||
|
reply = redisCommand(backend->db, "exists %b", oid->id, GIT_OID_RAWSZ);
|
||||||
|
if (reply->type != REDIS_REPLY_NIL && reply->type != REDIS_REPLY_ERROR)
|
||||||
|
found = 1;
|
||||||
|
|
||||||
|
|
||||||
|
freeReplyObject(reply);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hiredis_backend__write(git_oid *id, git_odb_backend *_backend, const void *data, size_t len, git_otype type) {
|
||||||
|
hiredis_backend *backend;
|
||||||
|
int error;
|
||||||
|
redisReply *reply;
|
||||||
|
|
||||||
|
assert(id && _backend && data);
|
||||||
|
|
||||||
|
backend = (hiredis_backend *) _backend;
|
||||||
|
error = GIT_ERROR;
|
||||||
|
|
||||||
|
if ((error = git_odb_hash(id, data, len, type)) < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
reply = redisCommand(backend->db, "HMSET %b "
|
||||||
|
"type %d "
|
||||||
|
"size %d "
|
||||||
|
"data %b ", id->id, GIT_OID_RAWSZ,
|
||||||
|
(int) type, len, data, len);
|
||||||
|
error = reply->type == REDIS_REPLY_ERROR ? GIT_ERROR : GIT_SUCCESS;
|
||||||
|
|
||||||
|
freeReplyObject(reply);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hiredis_backend__free(git_odb_backend *_backend) {
|
||||||
|
hiredis_backend *backend;
|
||||||
|
assert(_backend);
|
||||||
|
backend = (hiredis_backend *) _backend;
|
||||||
|
|
||||||
|
redisFree(backend->db);
|
||||||
|
|
||||||
|
free(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_odb_backend_hiredis(git_odb_backend **backend_out, const char *host, int port) {
|
||||||
|
hiredis_backend *backend;
|
||||||
|
|
||||||
|
backend = git__calloc(1, sizeof (hiredis_backend));
|
||||||
|
if (backend == NULL)
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
|
|
||||||
|
backend->db = redisConnect(host, port);
|
||||||
|
if (backend->db->err)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
backend->parent.read = &hiredis_backend__read;
|
||||||
|
backend->parent.read_header = &hiredis_backend__read_header;
|
||||||
|
backend->parent.write = &hiredis_backend__write;
|
||||||
|
backend->parent.exists = &hiredis_backend__exists;
|
||||||
|
backend->parent.free = &hiredis_backend__free;
|
||||||
|
|
||||||
|
*backend_out = (git_odb_backend *) backend;
|
||||||
|
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
cleanup:
|
||||||
|
free(backend);
|
||||||
|
return GIT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int git_odb_backend_hiredis(git_odb_backend ** GIT_UNUSED(backend_out),
|
||||||
|
const char *GIT_UNUSED(host), int GIT_UNUSED(port)) {
|
||||||
|
GIT_UNUSED_ARG(backend_out);
|
||||||
|
GIT_UNUSED_ARG(host);
|
||||||
|
GIT_UNUSED_ARG(port);
|
||||||
|
return GIT_ENOTIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* HAVE_HIREDIS */
|
@ -318,6 +318,7 @@ GIT_COMMIT_GETTER(const char *, message_short, commit->message_short)
|
|||||||
GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time)
|
GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time)
|
||||||
GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
|
GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
|
||||||
GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length)
|
GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length)
|
||||||
|
GIT_COMMIT_GETTER(const git_oid *, tree_oid, &commit->tree_oid);
|
||||||
|
|
||||||
|
|
||||||
int git_commit_tree(git_tree **tree_out, git_commit *commit)
|
int git_commit_tree(git_tree **tree_out, git_commit *commit)
|
||||||
@ -338,4 +339,9 @@ int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n)
|
|||||||
return git_commit_lookup(parent, commit->object.repo, parent_oid);
|
return git_commit_lookup(parent, commit->object.repo, parent_oid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const git_oid *git_commit_parent_oid(git_commit *commit, unsigned int n)
|
||||||
|
{
|
||||||
|
assert(commit);
|
||||||
|
|
||||||
|
return git_vector_get(&commit->parent_oids, n);
|
||||||
|
}
|
||||||
|
@ -29,7 +29,9 @@ static struct {
|
|||||||
{GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"},
|
{GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"},
|
||||||
{GIT_EINVALIDREFSTATE, "The state of the reference is not valid"},
|
{GIT_EINVALIDREFSTATE, "The state of the reference is not valid"},
|
||||||
{GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"},
|
{GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"},
|
||||||
{GIT_EEXISTS, "A reference with this name already exists"}
|
{GIT_EEXISTS, "A reference with this name already exists"},
|
||||||
|
{GIT_EOVERFLOW, "The given integer literal is too large to be parsed"},
|
||||||
|
{GIT_ENOTNUM, "The given literal is not a valid number"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *git_strerror(int num)
|
const char *git_strerror(int num)
|
||||||
|
@ -178,7 +178,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
|
|||||||
if (flags & GIT_FILEBUF_DEFLATE_CONTENTS) {
|
if (flags & GIT_FILEBUF_DEFLATE_CONTENTS) {
|
||||||
|
|
||||||
/* Initialize the ZLib stream */
|
/* Initialize the ZLib stream */
|
||||||
if (deflateInit(&file->zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
|
if (deflateInit(&file->zs, Z_BEST_SPEED) != Z_OK) {
|
||||||
error = GIT_EZLIB;
|
error = GIT_EZLIB;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
15
src/index.c
15
src/index.c
@ -412,6 +412,7 @@ static git_index_tree *read_tree_internal(
|
|||||||
{
|
{
|
||||||
git_index_tree *tree;
|
git_index_tree *tree;
|
||||||
const char *name_start, *buffer;
|
const char *name_start, *buffer;
|
||||||
|
long count;
|
||||||
|
|
||||||
if ((tree = git__malloc(sizeof(git_index_tree))) == NULL)
|
if ((tree = git__malloc(sizeof(git_index_tree))) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -430,12 +431,22 @@ static git_index_tree *read_tree_internal(
|
|||||||
goto error_cleanup;
|
goto error_cleanup;
|
||||||
|
|
||||||
/* Blank-terminated ASCII decimal number of entries in this tree */
|
/* Blank-terminated ASCII decimal number of entries in this tree */
|
||||||
tree->entries = strtol(buffer, (char **)&buffer, 10);
|
if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS ||
|
||||||
|
count < 0)
|
||||||
|
goto error_cleanup;
|
||||||
|
|
||||||
|
tree->entries = (size_t)count;
|
||||||
|
|
||||||
if (*buffer != ' ' || ++buffer >= buffer_end)
|
if (*buffer != ' ' || ++buffer >= buffer_end)
|
||||||
goto error_cleanup;
|
goto error_cleanup;
|
||||||
|
|
||||||
/* Number of children of the tree, newline-terminated */
|
/* Number of children of the tree, newline-terminated */
|
||||||
tree->children_count = strtol(buffer, (char **)&buffer, 10);
|
if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS ||
|
||||||
|
count < 0)
|
||||||
|
goto error_cleanup;
|
||||||
|
|
||||||
|
tree->children_count = (size_t)count;
|
||||||
|
|
||||||
if (*buffer != '\n' || ++buffer >= buffer_end)
|
if (*buffer != '\n' || ++buffer >= buffer_end)
|
||||||
goto error_cleanup;
|
goto error_cleanup;
|
||||||
|
|
||||||
|
21
src/refs.c
21
src/refs.c
@ -746,7 +746,7 @@ static int packed_write_ref(reference_oid *ref, git_filebuf *file)
|
|||||||
*/
|
*/
|
||||||
static int packed_find_peel(reference_oid *ref)
|
static int packed_find_peel(reference_oid *ref)
|
||||||
{
|
{
|
||||||
git_tag *tag;
|
git_object *object;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (ref->ref.type & GIT_REF_HAS_PEEL)
|
if (ref->ref.type & GIT_REF_HAS_PEEL)
|
||||||
@ -760,14 +760,20 @@ static int packed_find_peel(reference_oid *ref)
|
|||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the tag in the repository. The tag must exist,
|
* Find the tagged object in the repository
|
||||||
* otherwise this reference is broken and we shouldn't
|
|
||||||
* pack it.
|
|
||||||
*/
|
*/
|
||||||
error = git_tag_lookup(&tag, ref->ref.owner, &ref->oid);
|
error = git_object_lookup(&object, ref->ref.owner, &ref->oid, GIT_OBJ_ANY);
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the tagged object is a Tag object, we need to resolve it;
|
||||||
|
* if the ref is actually a 'weak' ref, we don't need to resolve
|
||||||
|
* anything.
|
||||||
|
*/
|
||||||
|
if (git_object_type(object) == GIT_OBJ_TAG) {
|
||||||
|
git_tag *tag = (git_tag *)object;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the object pointed at by this tag
|
* Find the object pointed at by this tag
|
||||||
*/
|
*/
|
||||||
@ -779,6 +785,7 @@ static int packed_find_peel(reference_oid *ref)
|
|||||||
* marked at such. When written to the packfile, it'll be
|
* marked at such. When written to the packfile, it'll be
|
||||||
* accompanied by this resolved oid
|
* accompanied by this resolved oid
|
||||||
*/
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -1419,6 +1426,10 @@ int git_reference_delete(git_reference *ref)
|
|||||||
assert(ref);
|
assert(ref);
|
||||||
|
|
||||||
if (ref->type & GIT_REF_PACKED) {
|
if (ref->type & GIT_REF_PACKED) {
|
||||||
|
/* load the existing packfile */
|
||||||
|
if ((error = packed_load(ref->owner)) < GIT_SUCCESS)
|
||||||
|
return error;
|
||||||
|
|
||||||
git_hashtable_remove(ref->owner->references.packfile, ref->name);
|
git_hashtable_remove(ref->owner->references.packfile, ref->name);
|
||||||
error = packed_write(ref->owner);
|
error = packed_write(ref->owner);
|
||||||
} else {
|
} else {
|
||||||
|
@ -473,3 +473,29 @@ cleanup:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_repository_is_empty(git_repository *repo)
|
||||||
|
{
|
||||||
|
git_reference *head, *branch;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = git_reference_lookup(&head, repo, "HEAD");
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (git_reference_type(head) != GIT_REF_SYMBOLIC)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
return git_reference_resolve(&branch, head) == GIT_SUCCESS ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *git_repository_path(git_repository *repo)
|
||||||
|
{
|
||||||
|
assert(repo);
|
||||||
|
return repo->path_repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *git_repository_workdir(git_repository *repo)
|
||||||
|
{
|
||||||
|
assert(repo);
|
||||||
|
return repo->path_workdir;
|
||||||
|
}
|
||||||
|
@ -191,6 +191,7 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
|
|||||||
unsigned char *parents_start;
|
unsigned char *parents_start;
|
||||||
|
|
||||||
int i, parents = 0;
|
int i, parents = 0;
|
||||||
|
long commit_time;
|
||||||
|
|
||||||
buffer += STRLEN("tree ") + GIT_OID_HEXSZ + 1;
|
buffer += STRLEN("tree ") + GIT_OID_HEXSZ + 1;
|
||||||
|
|
||||||
@ -227,10 +228,10 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
|
|||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
commit->time = strtol((char *)buffer + 2, NULL, 10);
|
if (git__strtol32(&commit_time, (char *)buffer + 2, NULL, 10) < GIT_SUCCESS)
|
||||||
if (commit->time == 0)
|
|
||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
commit->time = (time_t)commit_time;
|
||||||
commit->parsed = 1;
|
commit->parsed = 1;
|
||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -65,14 +65,47 @@ git_signature *git_signature_dup(const git_signature *sig)
|
|||||||
return git_signature_new(sig->name, sig->email, sig->when.time, sig->when.offset);
|
return git_signature_new(sig->name, sig->email, sig->when.time, sig->when.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
git_signature *git_signature_now(const char *name, const char *email)
|
||||||
static int parse_timezone_offset(const char *buffer, int *offset_out)
|
|
||||||
{
|
{
|
||||||
int offset, dec_offset;
|
time_t now;
|
||||||
|
time_t offset;
|
||||||
|
struct tm *utc_tm, *local_tm;
|
||||||
|
|
||||||
|
#ifndef GIT_WIN32
|
||||||
|
struct tm _utc, _local;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On Win32, `gmtime_r` doesn't exist but
|
||||||
|
* `gmtime` is threadsafe, so we can use that
|
||||||
|
*/
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
utc_tm = gmtime(&now);
|
||||||
|
local_tm = localtime(&now);
|
||||||
|
#else
|
||||||
|
utc_tm = gmtime_r(&now, &_utc);
|
||||||
|
local_tm = localtime_r(&now, &_local);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
offset = mktime(local_tm) - mktime(utc_tm);
|
||||||
|
offset /= 60;
|
||||||
|
|
||||||
|
/* mktime takes care of setting tm_isdst correctly */
|
||||||
|
if (local_tm->tm_isdst)
|
||||||
|
offset += 60;
|
||||||
|
|
||||||
|
return git_signature_new(name, email, now, (int)offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_timezone_offset(const char *buffer, long *offset_out)
|
||||||
|
{
|
||||||
|
long offset, dec_offset;
|
||||||
int mins, hours;
|
int mins, hours;
|
||||||
|
|
||||||
const char *offset_start;
|
const char *offset_start;
|
||||||
char* offset_end;
|
const char *offset_end;
|
||||||
|
|
||||||
offset_start = buffer + 1;
|
offset_start = buffer + 1;
|
||||||
|
|
||||||
@ -84,7 +117,8 @@ static int parse_timezone_offset(const char *buffer, int *offset_out)
|
|||||||
if (offset_start[0] != '-' && offset_start[0] != '+')
|
if (offset_start[0] != '-' && offset_start[0] != '+')
|
||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
dec_offset = strtol(offset_start + 1, &offset_end, 10);
|
if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < GIT_SUCCESS)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
if (offset_end - offset_start != 5)
|
if (offset_end - offset_start != 5)
|
||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
@ -117,7 +151,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
|
|||||||
int name_length, email_length;
|
int name_length, email_length;
|
||||||
const char *buffer = *buffer_out;
|
const char *buffer = *buffer_out;
|
||||||
const char *line_end, *name_end, *email_end;
|
const char *line_end, *name_end, *email_end;
|
||||||
int offset = 0;
|
long offset = 0, time;
|
||||||
|
|
||||||
memset(sig, 0x0, sizeof(git_signature));
|
memset(sig, 0x0, sizeof(git_signature));
|
||||||
|
|
||||||
@ -139,6 +173,9 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
|
|||||||
|
|
||||||
name_length = name_end - buffer - 1;
|
name_length = name_end - buffer - 1;
|
||||||
sig->name = git__malloc(name_length + 1);
|
sig->name = git__malloc(name_length + 1);
|
||||||
|
if (sig->name == NULL)
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
memcpy(sig->name, buffer, name_length);
|
memcpy(sig->name, buffer, name_length);
|
||||||
sig->name[name_length] = 0;
|
sig->name[name_length] = 0;
|
||||||
buffer = name_end + 1;
|
buffer = name_end + 1;
|
||||||
@ -152,6 +189,9 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
|
|||||||
|
|
||||||
email_length = email_end - buffer;
|
email_length = email_end - buffer;
|
||||||
sig->email = git__malloc(email_length + 1);
|
sig->email = git__malloc(email_length + 1);
|
||||||
|
if (sig->name == NULL)
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
memcpy(sig->email, buffer, email_length);
|
memcpy(sig->email, buffer, email_length);
|
||||||
sig->email[email_length] = 0;
|
sig->email[email_length] = 0;
|
||||||
buffer = email_end + 1;
|
buffer = email_end + 1;
|
||||||
@ -159,11 +199,11 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
|
|||||||
if (buffer >= line_end)
|
if (buffer >= line_end)
|
||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
sig->when.time = strtol(buffer, (char **)&buffer, 10);
|
if (git__strtol32(&time, buffer, &buffer, 10) < GIT_SUCCESS)
|
||||||
|
|
||||||
if (sig->when.time == 0)
|
|
||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
sig->when.time = (time_t)time;
|
||||||
|
|
||||||
if (parse_timezone_offset(buffer, &offset) < GIT_SUCCESS)
|
if (parse_timezone_offset(buffer, &offset) < GIT_SUCCESS)
|
||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
29
src/tag.c
29
src/tag.c
@ -131,12 +131,17 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
|
|||||||
text_len = search - buffer;
|
text_len = search - buffer;
|
||||||
|
|
||||||
tag->tag_name = git__malloc(text_len + 1);
|
tag->tag_name = git__malloc(text_len + 1);
|
||||||
|
if (tag->tag_name == NULL)
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
memcpy(tag->tag_name, buffer, text_len);
|
memcpy(tag->tag_name, buffer, text_len);
|
||||||
tag->tag_name[text_len] = '\0';
|
tag->tag_name[text_len] = '\0';
|
||||||
|
|
||||||
buffer = search + 1;
|
buffer = search + 1;
|
||||||
|
|
||||||
tag->tagger = git__malloc(sizeof(git_signature));
|
tag->tagger = git__malloc(sizeof(git_signature));
|
||||||
|
if (tag->tagger == NULL)
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ")) != 0) {
|
if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ")) != 0) {
|
||||||
free(tag->tag_name);
|
free(tag->tag_name);
|
||||||
@ -147,6 +152,9 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
|
|||||||
text_len = buffer_end - ++buffer;
|
text_len = buffer_end - ++buffer;
|
||||||
|
|
||||||
tag->message = git__malloc(text_len + 1);
|
tag->message = git__malloc(text_len + 1);
|
||||||
|
if (tag->message == NULL)
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
memcpy(tag->message, buffer, text_len);
|
memcpy(tag->message, buffer, text_len);
|
||||||
tag->message[text_len] = '\0';
|
tag->message[text_len] = '\0';
|
||||||
|
|
||||||
@ -209,6 +217,17 @@ static int tag_create(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!git_odb_exists(repo->db, target))
|
||||||
|
return GIT_ENOTFOUND;
|
||||||
|
|
||||||
|
/* Try to find out what the type is */
|
||||||
|
if (target_type == GIT_OBJ_ANY) {
|
||||||
|
size_t _unused;
|
||||||
|
error = git_odb_read_header(&_unused, &target_type, repo->db, target);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
type_str = git_object_type2string(target_type);
|
type_str = git_object_type2string(target_type);
|
||||||
|
|
||||||
tagger_str_len = git_signature__write(&tagger_str, "tagger", tagger);
|
tagger_str_len = git_signature__write(&tagger_str, "tagger", tagger);
|
||||||
@ -260,7 +279,6 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
|
|||||||
{
|
{
|
||||||
git_tag tag;
|
git_tag tag;
|
||||||
int error;
|
int error;
|
||||||
git_object *obj;
|
|
||||||
|
|
||||||
assert(oid && buffer);
|
assert(oid && buffer);
|
||||||
|
|
||||||
@ -269,15 +287,8 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
|
|||||||
if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS)
|
if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
error = git_object_lookup(&obj, repo, &tag.target, tag.type);
|
error = git_tag_create(oid, repo, tag.tag_name, &tag.target, tag.type, tag.tagger, tag.message);
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
error = git_tag_create_o(oid, repo, tag.tag_name, obj, tag.tagger, tag.message);
|
|
||||||
|
|
||||||
git_object_close(obj);
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
git_signature_free(tag.tagger);
|
git_signature_free(tag.tagger);
|
||||||
free(tag.tag_name);
|
free(tag.tag_name);
|
||||||
free(tag.message);
|
free(tag.message);
|
||||||
|
@ -150,7 +150,8 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf
|
|||||||
if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)
|
if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)
|
||||||
return GIT_ENOMEM;
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
entry->attr = strtol(buffer, (char **)&buffer, 8);
|
if (git__strtol32((long *)&entry->attr, buffer, &buffer, 8) < GIT_SUCCESS)
|
||||||
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
if (*buffer++ != ' ') {
|
if (*buffer++ != ' ') {
|
||||||
error = GIT_EOBJCORRUPTED;
|
error = GIT_EOBJCORRUPTED;
|
||||||
@ -364,7 +365,7 @@ int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, con
|
|||||||
git_oid_cpy(&entry->oid, id);
|
git_oid_cpy(&entry->oid, id);
|
||||||
entry->attr = attributes;
|
entry->attr = attributes;
|
||||||
|
|
||||||
if (pos != GIT_ENOTFOUND) {
|
if (pos == GIT_ENOTFOUND) {
|
||||||
if (git_vector_insert(&bld->entries, entry) < 0)
|
if (git_vector_insert(&bld->entries, entry) < 0)
|
||||||
return GIT_ENOMEM;
|
return GIT_ENOMEM;
|
||||||
}
|
}
|
||||||
|
79
src/util.c
79
src/util.c
@ -2,6 +2,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
void git_strarray_free(git_strarray *array)
|
void git_strarray_free(git_strarray *array)
|
||||||
{
|
{
|
||||||
@ -12,6 +13,84 @@ void git_strarray_free(git_strarray *array)
|
|||||||
free(array->strings);
|
free(array->strings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git__strtol32(long *result, const char *nptr, const char **endptr, int base)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
long n, nn;
|
||||||
|
int c, ovfl, v, neg, ndig;
|
||||||
|
|
||||||
|
p = nptr;
|
||||||
|
neg = 0;
|
||||||
|
n = 0;
|
||||||
|
ndig = 0;
|
||||||
|
ovfl = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* White space
|
||||||
|
*/
|
||||||
|
while (isspace(*p))
|
||||||
|
p++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sign
|
||||||
|
*/
|
||||||
|
if (*p == '-' || *p == '+')
|
||||||
|
if (*p++ == '-')
|
||||||
|
neg = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Base
|
||||||
|
*/
|
||||||
|
if (base == 0) {
|
||||||
|
if (*p != '0')
|
||||||
|
base = 10;
|
||||||
|
else {
|
||||||
|
base = 8;
|
||||||
|
if (p[1] == 'x' || p[1] == 'X') {
|
||||||
|
p += 2;
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (base == 16 && *p == '0') {
|
||||||
|
if (p[1] == 'x' || p[1] == 'X')
|
||||||
|
p += 2;
|
||||||
|
} else if (base < 0 || 36 < base)
|
||||||
|
goto Return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Non-empty sequence of digits
|
||||||
|
*/
|
||||||
|
for (;; p++,ndig++) {
|
||||||
|
c = *p;
|
||||||
|
v = base;
|
||||||
|
if ('0'<=c && c<='9')
|
||||||
|
v = c - '0';
|
||||||
|
else if ('a'<=c && c<='z')
|
||||||
|
v = c - 'a' + 10;
|
||||||
|
else if ('A'<=c && c<='Z')
|
||||||
|
v = c - 'A' + 10;
|
||||||
|
if (v >= base)
|
||||||
|
break;
|
||||||
|
nn = n*base + v;
|
||||||
|
if (nn < n)
|
||||||
|
ovfl = 1;
|
||||||
|
n = nn;
|
||||||
|
}
|
||||||
|
|
||||||
|
Return:
|
||||||
|
if (ndig == 0)
|
||||||
|
return GIT_ENOTNUM;
|
||||||
|
|
||||||
|
if (endptr)
|
||||||
|
*endptr = p;
|
||||||
|
|
||||||
|
if (ovfl)
|
||||||
|
return GIT_EOVERFLOW;
|
||||||
|
|
||||||
|
*result = neg ? -n : n;
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int git__fmt(char *buf, size_t buf_sz, const char *fmt, ...)
|
int git__fmt(char *buf, size_t buf_sz, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
|
@ -22,6 +22,8 @@ extern int git__fmt(char *, size_t, const char *, ...)
|
|||||||
extern int git__prefixcmp(const char *str, const char *prefix);
|
extern int git__prefixcmp(const char *str, const char *prefix);
|
||||||
extern int git__suffixcmp(const char *str, const char *suffix);
|
extern int git__suffixcmp(const char *str, const char *suffix);
|
||||||
|
|
||||||
|
extern int git__strtol32(long *n, const char *buff, const char **end_buf, int base);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The dirname() function shall take a pointer to a character string
|
* The dirname() function shall take a pointer to a character string
|
||||||
* that contains a pathname, and return a pointer to a string that is a
|
* that contains a pathname, and return a pointer to a string that is a
|
||||||
|
Binary file not shown.
BIN
tests/resources/testrepo.git/refs/tags/point_to_blob
Normal file
BIN
tests/resources/testrepo.git/refs/tags/point_to_blob
Normal file
Binary file not shown.
@ -233,7 +233,7 @@ BEGIN_TEST(path3, "prettify and validate a path to a file")
|
|||||||
must_fail(ensure_file_path_normalized("d1/s1///s2/..//../s3/", NULL, 0));
|
must_fail(ensure_file_path_normalized("d1/s1///s2/..//../s3/", NULL, 0));
|
||||||
must_pass(ensure_file_path_normalized("d1/s1//../s2/../../d2", "d2", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
must_pass(ensure_file_path_normalized("d1/s1//../s2/../../d2", "d2", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||||
must_fail(ensure_file_path_normalized("dir/sub/../", NULL, 0));
|
must_fail(ensure_file_path_normalized("dir/sub/../", NULL, 0));
|
||||||
must_pass(ensure_file_path_normalized("../../a/../../b/c/d/../../e", "b/e", PATH_AS_SUFFIX));
|
must_pass(ensure_file_path_normalized("../a/../b/c/d/../../e", "b/e", PATH_AS_SUFFIX));
|
||||||
must_fail(ensure_file_path_normalized("....", NULL, 0));
|
must_fail(ensure_file_path_normalized("....", NULL, 0));
|
||||||
must_fail(ensure_file_path_normalized("...", NULL, 0));
|
must_fail(ensure_file_path_normalized("...", NULL, 0));
|
||||||
must_fail(ensure_file_path_normalized("./...", NULL, 0));
|
must_fail(ensure_file_path_normalized("./...", NULL, 0));
|
||||||
@ -309,7 +309,7 @@ BEGIN_TEST(path4, "validate and prettify a path to a folder")
|
|||||||
must_pass(ensure_dir_path_normalized("d1/s1///s2/..//../s3/", "d1/s3/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
must_pass(ensure_dir_path_normalized("d1/s1///s2/..//../s3/", "d1/s3/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||||
must_pass(ensure_dir_path_normalized("d1/s1//../s2/../../d2", "d2/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
must_pass(ensure_dir_path_normalized("d1/s1//../s2/../../d2", "d2/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||||
must_pass(ensure_dir_path_normalized("dir/sub/../", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
must_pass(ensure_dir_path_normalized("dir/sub/../", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX));
|
||||||
must_pass(ensure_dir_path_normalized("../../a/../../b/c/d/../../e", "b/e/", PATH_AS_SUFFIX));
|
must_pass(ensure_dir_path_normalized("../a/../b/c/d/../../e", "b/e/", PATH_AS_SUFFIX));
|
||||||
must_fail(ensure_dir_path_normalized("....", NULL, 0));
|
must_fail(ensure_dir_path_normalized("....", NULL, 0));
|
||||||
must_fail(ensure_dir_path_normalized("...", NULL, 0));
|
must_fail(ensure_dir_path_normalized("...", NULL, 0));
|
||||||
must_fail(ensure_dir_path_normalized("./...", NULL, 0));
|
must_fail(ensure_dir_path_normalized("./...", NULL, 0));
|
||||||
|
@ -119,13 +119,10 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again")
|
|||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
BEGIN_TEST(write1, "write a tag to the repository which points to an unknown oid and read it again")
|
BEGIN_TEST(write1, "write a tag to the repository which points to an unknown oid should fail")
|
||||||
git_repository *repo;
|
git_repository *repo;
|
||||||
git_tag *tag;
|
|
||||||
git_oid target_id, tag_id;
|
git_oid target_id, tag_id;
|
||||||
const git_signature *tagger;
|
const git_signature *tagger;
|
||||||
git_reference *ref_tag;
|
|
||||||
git_object *zombie;
|
|
||||||
|
|
||||||
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
|
||||||
|
|
||||||
@ -135,7 +132,7 @@ BEGIN_TEST(write1, "write a tag to the repository which points to an unknown oid
|
|||||||
tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
|
tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60);
|
||||||
must_be_true(tagger != NULL);
|
must_be_true(tagger != NULL);
|
||||||
|
|
||||||
must_pass(git_tag_create(
|
must_fail(git_tag_create(
|
||||||
&tag_id, /* out id */
|
&tag_id, /* out id */
|
||||||
repo,
|
repo,
|
||||||
"the-zombie-tag",
|
"the-zombie-tag",
|
||||||
@ -146,17 +143,6 @@ BEGIN_TEST(write1, "write a tag to the repository which points to an unknown oid
|
|||||||
|
|
||||||
git_signature_free((git_signature *)tagger);
|
git_signature_free((git_signature *)tagger);
|
||||||
|
|
||||||
must_pass(git_tag_lookup(&tag, repo, &tag_id));
|
|
||||||
|
|
||||||
/* The non existent target can not be looked up */
|
|
||||||
must_fail(git_tag_target(&zombie, tag));
|
|
||||||
|
|
||||||
must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/the-zombie-tag"));
|
|
||||||
|
|
||||||
must_pass(git_reference_delete(ref_tag));
|
|
||||||
must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tag));
|
|
||||||
|
|
||||||
git_tag_close(tag);
|
|
||||||
git_repository_free(repo);
|
git_repository_free(repo);
|
||||||
|
|
||||||
END_TEST
|
END_TEST
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
|
|
||||||
static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
|
static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
|
||||||
|
|
||||||
|
static const char *blob_oid = "fa49b077972391ad58037050f2a75f74e3671e92";
|
||||||
|
static const char *first_tree = "181037049a54a1eb5fab404658a3a250b44335d7";
|
||||||
|
static const char *second_tree = "f60079018b664e4e79329a7ef9559c8d9e0378d1";
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static int print_tree(git_repository *repo, const git_oid *tree_oid, int depth)
|
static int print_tree(git_repository *repo, const git_oid *tree_oid, int depth)
|
||||||
{
|
{
|
||||||
@ -126,11 +130,33 @@ BEGIN_TEST(write0, "write a tree from an index")
|
|||||||
END_TEST
|
END_TEST
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
BEGIN_TEST(write2, "write a tree from a memory")
|
||||||
|
git_repository *repo;
|
||||||
|
git_treebuilder *builder;
|
||||||
|
git_tree *tree;
|
||||||
|
git_oid id, bid, rid, id2;
|
||||||
|
|
||||||
|
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
|
||||||
|
git_oid_mkstr(&id, first_tree);
|
||||||
|
git_oid_mkstr(&id2, second_tree);
|
||||||
|
git_oid_mkstr(&bid, blob_oid);
|
||||||
|
|
||||||
|
//create a second tree from first tree using `git_treebuilder_insert` on REPOSITORY_FOLDER.
|
||||||
|
must_pass(git_tree_lookup(&tree, repo, &id));
|
||||||
|
must_pass(git_treebuilder_create(&builder, tree));
|
||||||
|
must_pass(git_treebuilder_insert(NULL,builder,"new.txt",&bid,0100644));
|
||||||
|
must_pass(git_treebuilder_write(&rid,repo,builder));
|
||||||
|
|
||||||
|
must_be_true(git_oid_cmp(&rid, &id2) == 0);
|
||||||
|
close_temp_repo(repo);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
BEGIN_SUITE(tree)
|
BEGIN_SUITE(tree)
|
||||||
//ADD_TEST(print0);
|
//ADD_TEST(print0);
|
||||||
ADD_TEST(read0);
|
ADD_TEST(read0);
|
||||||
ADD_TEST(read1);
|
ADD_TEST(read1);
|
||||||
//ADD_TEST(write0);
|
//ADD_TEST(write0);
|
||||||
//ADD_TEST(write1);
|
//ADD_TEST(write1);
|
||||||
|
ADD_TEST(write2);
|
||||||
END_SUITE
|
END_SUITE
|
||||||
|
|
||||||
|
@ -456,6 +456,11 @@ BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo")
|
|||||||
must_be_true((reference->type & GIT_REF_PACKED) == 0);
|
must_be_true((reference->type & GIT_REF_PACKED) == 0);
|
||||||
must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0);
|
must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are now trying to pack also a loose reference
|
||||||
|
* called `points_to_blob`, to make sure we can properly
|
||||||
|
* pack weak tags
|
||||||
|
*/
|
||||||
must_pass(git_reference_packall(repo));
|
must_pass(git_reference_packall(repo));
|
||||||
|
|
||||||
/* Ensure the packed-refs file exists */
|
/* Ensure the packed-refs file exists */
|
||||||
@ -877,10 +882,10 @@ BEGIN_TEST(list0, "try to list all the references in our test repo")
|
|||||||
printf("# %s\n", ref_list.strings[i]);
|
printf("# %s\n", ref_list.strings[i]);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
/* We have exactly 7 refs in total if we include the packed ones:
|
/* We have exactly 8 refs in total if we include the packed ones:
|
||||||
* there is a reference that exists both in the packfile and as
|
* there is a reference that exists both in the packfile and as
|
||||||
* loose, but we only list it once */
|
* loose, but we only list it once */
|
||||||
must_be_true(ref_list.count == 7);
|
must_be_true(ref_list.count == 8);
|
||||||
|
|
||||||
git_strarray_free(&ref_list);
|
git_strarray_free(&ref_list);
|
||||||
git_repository_free(repo);
|
git_repository_free(repo);
|
||||||
|
@ -194,6 +194,8 @@ BEGIN_TEST(open0, "Open a bare repository that has just been initialized by git"
|
|||||||
must_pass(remove_placeholders(TEMP_REPO_FOLDER, "dummy-marker.txt"));
|
must_pass(remove_placeholders(TEMP_REPO_FOLDER, "dummy-marker.txt"));
|
||||||
|
|
||||||
must_pass(git_repository_open(&repo, TEMP_REPO_FOLDER));
|
must_pass(git_repository_open(&repo, TEMP_REPO_FOLDER));
|
||||||
|
must_be_true(git_repository_path(repo) != NULL);
|
||||||
|
must_be_true(git_repository_workdir(repo) == NULL);
|
||||||
|
|
||||||
git_repository_free(repo);
|
git_repository_free(repo);
|
||||||
must_pass(rmdir_recurs(TEMP_REPO_FOLDER));
|
must_pass(rmdir_recurs(TEMP_REPO_FOLDER));
|
||||||
@ -211,6 +213,8 @@ BEGIN_TEST(open1, "Open a standard repository that has just been initialized by
|
|||||||
must_pass(remove_placeholders(DEST_REPOSITORY_FOLDER, "dummy-marker.txt"));
|
must_pass(remove_placeholders(DEST_REPOSITORY_FOLDER, "dummy-marker.txt"));
|
||||||
|
|
||||||
must_pass(git_repository_open(&repo, DEST_REPOSITORY_FOLDER));
|
must_pass(git_repository_open(&repo, DEST_REPOSITORY_FOLDER));
|
||||||
|
must_be_true(git_repository_path(repo) != NULL);
|
||||||
|
must_be_true(git_repository_workdir(repo) != NULL);
|
||||||
|
|
||||||
git_repository_free(repo);
|
git_repository_free(repo);
|
||||||
must_pass(rmdir_recurs(TEMP_REPO_FOLDER));
|
must_pass(rmdir_recurs(TEMP_REPO_FOLDER));
|
||||||
@ -244,6 +248,19 @@ BEGIN_TEST(open2, "Open a bare repository with a relative path escaping out of t
|
|||||||
rmdir_recurs(TEMP_REPO_FOLDER);
|
rmdir_recurs(TEMP_REPO_FOLDER);
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
BEGIN_TEST(empty0, "test if a repository is empty or not")
|
||||||
|
|
||||||
|
git_repository *repo_empty, *repo_normal;
|
||||||
|
|
||||||
|
must_pass(git_repository_open(&repo_normal, REPOSITORY_FOLDER));
|
||||||
|
must_be_true(git_repository_is_empty(repo_normal) == 0);
|
||||||
|
git_repository_free(repo_normal);
|
||||||
|
|
||||||
|
must_pass(git_repository_open(&repo_empty, EMPTY_BARE_REPOSITORY_FOLDER));
|
||||||
|
must_be_true(git_repository_is_empty(repo_empty) == 1);
|
||||||
|
git_repository_free(repo_empty);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
BEGIN_SUITE(repository)
|
BEGIN_SUITE(repository)
|
||||||
ADD_TEST(odb0);
|
ADD_TEST(odb0);
|
||||||
ADD_TEST(odb1);
|
ADD_TEST(odb1);
|
||||||
@ -253,5 +270,6 @@ BEGIN_SUITE(repository)
|
|||||||
ADD_TEST(open0);
|
ADD_TEST(open0);
|
||||||
ADD_TEST(open1);
|
ADD_TEST(open1);
|
||||||
ADD_TEST(open2);
|
ADD_TEST(open2);
|
||||||
|
ADD_TEST(empty0);
|
||||||
END_SUITE
|
END_SUITE
|
||||||
|
|
||||||
|
123
tests/t14-hiredis.c
Normal file
123
tests/t14-hiredis.c
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License, version 2,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* In addition to the permissions in the GNU General Public License,
|
||||||
|
* the authors give you unlimited permission to link the compiled
|
||||||
|
* version of this file into combinations with other programs,
|
||||||
|
* and to distribute those combinations without any restriction
|
||||||
|
* coming from the use of this file. (The General Public License
|
||||||
|
* restrictions do apply in other respects; for example, they cover
|
||||||
|
* modification of the file, and distribution when not linked into
|
||||||
|
* a combined executable.)
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "test_lib.h"
|
||||||
|
#include "odb.h"
|
||||||
|
|
||||||
|
#ifdef GIT2_HIREDIS_BACKEND
|
||||||
|
#include "t03-data.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
#include "git2/odb_backend.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int cmp_objects(git_odb_object *odb_obj, git_rawobj *raw)
|
||||||
|
{
|
||||||
|
if (raw->type != git_odb_object_type(odb_obj))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (raw->len != git_odb_object_size(odb_obj))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((raw->len > 0) && (memcmp(raw->data, git_odb_object_data(odb_obj), raw->len) != 0))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static git_odb *open_hiredis_odb(void)
|
||||||
|
{
|
||||||
|
git_odb *odb;
|
||||||
|
git_odb_backend *hiredis;
|
||||||
|
|
||||||
|
if (git_odb_new(&odb) < GIT_SUCCESS)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (git_odb_backend_hiredis(&hiredis, "127.0.0.1", 6379) < GIT_SUCCESS)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (git_odb_add_backend(odb, hiredis, 0) < GIT_SUCCESS)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return odb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_WRITE(PTR) {\
|
||||||
|
git_odb *db; \
|
||||||
|
git_oid id1, id2; \
|
||||||
|
git_odb_object *obj; \
|
||||||
|
db = open_hiredis_odb(); \
|
||||||
|
must_be_true(db != NULL); \
|
||||||
|
must_pass(git_oid_mkstr(&id1, PTR.id)); \
|
||||||
|
must_pass(git_odb_write(&id2, db, PTR##_obj.data, PTR##_obj.len, PTR##_obj.type)); \
|
||||||
|
must_be_true(git_oid_cmp(&id1, &id2) == 0); \
|
||||||
|
must_pass(git_odb_read(&obj, db, &id1)); \
|
||||||
|
must_pass(cmp_objects(obj, &PTR##_obj)); \
|
||||||
|
git_odb_object_close(obj); \
|
||||||
|
git_odb_close(db); \
|
||||||
|
}
|
||||||
|
|
||||||
|
BEGIN_TEST(hiredis0, "write a commit, read it back (hiredis backend)")
|
||||||
|
TEST_WRITE(commit);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
BEGIN_TEST(hiredis1, "write a tree, read it back (hiredis backend)")
|
||||||
|
TEST_WRITE(tree);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
BEGIN_TEST(hiredis2, "write a tag, read it back (hiredis backend)")
|
||||||
|
TEST_WRITE(tag);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
BEGIN_TEST(hiredis3, "write a zero-byte entry, read it back (hiredis backend)")
|
||||||
|
TEST_WRITE(zero);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
BEGIN_TEST(hiredis4, "write a one-byte entry, read it back (hiredis backend)")
|
||||||
|
TEST_WRITE(one);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
BEGIN_TEST(hiredis5, "write a two-byte entry, read it back (hiredis backend)")
|
||||||
|
TEST_WRITE(two);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
BEGIN_TEST(hiredis6, "write some bytes in an entry, read it back (hiredis backend)")
|
||||||
|
TEST_WRITE(some);
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_SUITE(hiredis)
|
||||||
|
ADD_TEST(hiredis0);
|
||||||
|
ADD_TEST(hiredis1);
|
||||||
|
ADD_TEST(hiredis2);
|
||||||
|
ADD_TEST(hiredis3);
|
||||||
|
ADD_TEST(hiredis4);
|
||||||
|
ADD_TEST(hiredis5);
|
||||||
|
ADD_TEST(hiredis6);
|
||||||
|
END_SUITE
|
||||||
|
|
||||||
|
#else /* no hiredis builtin */
|
||||||
|
BEGIN_SUITE(hiredis)
|
||||||
|
/* empty */
|
||||||
|
END_SUITE
|
||||||
|
#endif
|
@ -41,6 +41,7 @@ DECLARE_SUITE(tag);
|
|||||||
DECLARE_SUITE(tree);
|
DECLARE_SUITE(tree);
|
||||||
DECLARE_SUITE(refs);
|
DECLARE_SUITE(refs);
|
||||||
DECLARE_SUITE(sqlite);
|
DECLARE_SUITE(sqlite);
|
||||||
|
DECLARE_SUITE(hiredis);
|
||||||
DECLARE_SUITE(repository);
|
DECLARE_SUITE(repository);
|
||||||
DECLARE_SUITE(threads);
|
DECLARE_SUITE(threads);
|
||||||
|
|
||||||
@ -59,6 +60,7 @@ static libgit2_suite suite_methods[]= {
|
|||||||
SUITE_NAME(sqlite),
|
SUITE_NAME(sqlite),
|
||||||
SUITE_NAME(repository),
|
SUITE_NAME(repository),
|
||||||
SUITE_NAME(threads),
|
SUITE_NAME(threads),
|
||||||
|
SUITE_NAME(hiredis)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GIT_SUITE_COUNT (ARRAY_SIZE(suite_methods))
|
#define GIT_SUITE_COUNT (ARRAY_SIZE(suite_methods))
|
||||||
|
11
wscript
11
wscript
@ -1,3 +1,4 @@
|
|||||||
|
from __future__ import with_statement
|
||||||
from waflib.Context import Context
|
from waflib.Context import Context
|
||||||
from waflib.Build import BuildContext, CleanContext, \
|
from waflib.Build import BuildContext, CleanContext, \
|
||||||
InstallContext, UninstallContext
|
InstallContext, UninstallContext
|
||||||
@ -16,7 +17,7 @@ CFLAGS_WIN32_L = ['/RELEASE'] # used for /both/ debug and release builds.
|
|||||||
# sets the module's checksum in the header.
|
# sets the module's checksum in the header.
|
||||||
CFLAGS_WIN32_L_DBG = ['/DEBUG']
|
CFLAGS_WIN32_L_DBG = ['/DEBUG']
|
||||||
|
|
||||||
ALL_LIBS = ['crypto', 'pthread', 'sqlite3']
|
ALL_LIBS = ['crypto', 'pthread', 'sqlite3', 'hiredis']
|
||||||
|
|
||||||
def options(opt):
|
def options(opt):
|
||||||
opt.load('compiler_c')
|
opt.load('compiler_c')
|
||||||
@ -31,6 +32,8 @@ PPC optimized version (ppc) or the SHA1 functions from OpenSSL (openssl)")
|
|||||||
help='Select target architecture (ia64, x64, x86, x86_amd64, x86_ia64)')
|
help='Select target architecture (ia64, x64, x86, x86_amd64, x86_ia64)')
|
||||||
opt.add_option('--with-sqlite', action='store_true', default=False,
|
opt.add_option('--with-sqlite', action='store_true', default=False,
|
||||||
dest='use_sqlite', help='Enable sqlite support')
|
dest='use_sqlite', help='Enable sqlite support')
|
||||||
|
opt.add_option('--with-hiredis', action='store_true', default=False,
|
||||||
|
dest='use_hiredis', help='Enable redis support using hiredis')
|
||||||
opt.add_option('--threadsafe', action='store_true', default=False,
|
opt.add_option('--threadsafe', action='store_true', default=False,
|
||||||
help='Make libgit2 thread-safe (requires pthreads)')
|
help='Make libgit2 thread-safe (requires pthreads)')
|
||||||
|
|
||||||
@ -72,6 +75,12 @@ def configure(conf):
|
|||||||
lib='sqlite3', uselib_store='sqlite3', install_path=None, mandatory=False):
|
lib='sqlite3', uselib_store='sqlite3', install_path=None, mandatory=False):
|
||||||
conf.env.DEFINES += ['GIT2_SQLITE_BACKEND']
|
conf.env.DEFINES += ['GIT2_SQLITE_BACKEND']
|
||||||
|
|
||||||
|
# check for hiredis
|
||||||
|
if conf.options.use_hiredis and conf.check_cc(
|
||||||
|
lib='hiredis', uselib_store='hiredis', install_path=None, mandatory=False):
|
||||||
|
conf.env.DEFINES += ['GIT2_HIREDIS_BACKEND']
|
||||||
|
|
||||||
|
|
||||||
if conf.options.sha1 not in ['openssl', 'ppc', 'builtin']:
|
if conf.options.sha1 not in ['openssl', 'ppc', 'builtin']:
|
||||||
conf.fatal('Invalid SHA1 option')
|
conf.fatal('Invalid SHA1 option')
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user