mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-09 18:22:16 +00:00
commit
e3d55b2add
@ -19,12 +19,12 @@
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
#define GIT_ATTR_TRUE git_attr__true
|
||||
#define GIT_ATTR_FALSE git_attr__false
|
||||
#define GIT_ATTR_UNSPECIFIED NULL
|
||||
#define GIT_ATTR_TRUE(attr) ((attr) == git_attr__true)
|
||||
#define GIT_ATTR_FALSE(attr) ((attr) == git_attr__false)
|
||||
#define GIT_ATTR_UNSPECIFIED(attr) ((attr) == NULL)
|
||||
|
||||
GIT_EXTERN(const char *)git_attr__true;
|
||||
GIT_EXTERN(const char *)git_attr__false;
|
||||
GIT_EXTERN(const char *) git_attr__true;
|
||||
GIT_EXTERN(const char *) git_attr__false;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -37,6 +37,19 @@ struct git_config_file {
|
||||
void (*free)(struct git_config_file *);
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
GIT_CVAR_FALSE = 0,
|
||||
GIT_CVAR_TRUE = 1,
|
||||
GIT_CVAR_INT32,
|
||||
GIT_CVAR_STRING
|
||||
} git_cvar_t;
|
||||
|
||||
typedef struct {
|
||||
git_cvar_t cvar_type;
|
||||
const char *str_match;
|
||||
int map_value;
|
||||
} git_cvar_map;
|
||||
|
||||
/**
|
||||
* Locate the path to the global configuration file
|
||||
*
|
||||
@ -301,6 +314,43 @@ GIT_EXTERN(int) git_config_foreach(
|
||||
int (*callback)(const char *var_name, const char *value, void *payload),
|
||||
void *payload);
|
||||
|
||||
|
||||
/**
|
||||
* Query the value of a config variable and return it mapped to
|
||||
* an integer constant.
|
||||
*
|
||||
* This is a helper method to easily map different possible values
|
||||
* to a variable to integer constants that easily identify them.
|
||||
*
|
||||
* A mapping array looks as follows:
|
||||
*
|
||||
* git_cvar_map autocrlf_mapping[3] = {
|
||||
* {GIT_CVAR_FALSE, NULL, GIT_AUTO_CRLF_FALSE},
|
||||
* {GIT_CVAR_TRUE, NULL, GIT_AUTO_CRLF_TRUE},
|
||||
* {GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT},
|
||||
* {GIT_CVAR_STRING, "default", GIT_AUTO_CRLF_DEFAULT}};
|
||||
*
|
||||
* On any "false" value for the variable (e.g. "false", "FALSE", "no"), the
|
||||
* mapping will store `GIT_AUTO_CRLF_FALSE` in the `out` parameter.
|
||||
*
|
||||
* The same thing applies for any "true" value such as "true", "yes" or "1", storing
|
||||
* the `GIT_AUTO_CRLF_TRUE` variable.
|
||||
*
|
||||
* Otherwise, if the value matches the string "input" (with case insensitive comparison),
|
||||
* the given constant will be stored in `out`, and likewise for "default".
|
||||
*
|
||||
* If not a single match can be made to store in `out`, an error code will be
|
||||
* returned.
|
||||
*
|
||||
* @param cfg config file to get the variables from
|
||||
* @param name name of the config variable to lookup
|
||||
* @param maps array of `git_cvar_map` objects specifying the possible mappings
|
||||
* @param map_n number of mapping objects in `maps`
|
||||
* @param out place to store the result of the mapping
|
||||
* @return GIT_SUCCESS on success, error code otherwise
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n, int *out);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -111,7 +111,7 @@ int git_attr_file__from_file(
|
||||
git_repository *repo, const char *path, git_attr_file *file)
|
||||
{
|
||||
int error = GIT_SUCCESS;
|
||||
git_fbuffer fbuf = GIT_FBUFFER_INIT;
|
||||
git_buf fbuf = GIT_BUF_INIT;
|
||||
|
||||
assert(path && file);
|
||||
|
||||
@ -120,9 +120,9 @@ int git_attr_file__from_file(
|
||||
|
||||
if (error == GIT_SUCCESS &&
|
||||
(error = git_futils_readbuffer(&fbuf, path)) == GIT_SUCCESS)
|
||||
error = git_attr_file__from_buffer(repo, fbuf.data, file);
|
||||
error = git_attr_file__from_buffer(repo, fbuf.ptr, file);
|
||||
|
||||
git_futils_freebuffer(&fbuf);
|
||||
git_buf_free(&fbuf);
|
||||
if (error != GIT_SUCCESS)
|
||||
git__rethrow(error, "Could not open attribute file '%s'", path);
|
||||
|
||||
@ -458,12 +458,12 @@ int git_attr_assignment__parse(
|
||||
}
|
||||
|
||||
assign->name_hash = 5381;
|
||||
assign->value = GIT_ATTR_TRUE;
|
||||
assign->value = git_attr__true;
|
||||
assign->is_allocated = 0;
|
||||
|
||||
/* look for magic name prefixes */
|
||||
if (*scan == '-') {
|
||||
assign->value = GIT_ATTR_FALSE;
|
||||
assign->value = git_attr__false;
|
||||
scan++;
|
||||
} else if (*scan == '!') {
|
||||
assign->value = NULL; /* explicit unspecified state */
|
||||
@ -510,7 +510,7 @@ int git_attr_assignment__parse(
|
||||
}
|
||||
|
||||
/* expand macros (if given a repo with a macro cache) */
|
||||
if (repo != NULL && assign->value == GIT_ATTR_TRUE) {
|
||||
if (repo != NULL && assign->value == git_attr__true) {
|
||||
git_attr_rule *macro =
|
||||
git_hashtable_lookup(repo->attrcache.macros, assign->name);
|
||||
|
||||
|
170
src/blob.c
170
src/blob.c
@ -11,6 +11,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "blob.h"
|
||||
#include "filter.h"
|
||||
|
||||
const void *git_blob_rawcontent(git_blob *blob)
|
||||
{
|
||||
@ -24,6 +25,12 @@ size_t git_blob_rawsize(git_blob *blob)
|
||||
return blob->odb_object->raw.len;
|
||||
}
|
||||
|
||||
int git_blob__getbuf(git_buf *buffer, git_blob *blob)
|
||||
{
|
||||
return git_buf_set(
|
||||
buffer, blob->odb_object->raw.data, blob->odb_object->raw.len);
|
||||
}
|
||||
|
||||
void git_blob__free(git_blob *blob)
|
||||
{
|
||||
git_odb_object_free(blob->odb_object);
|
||||
@ -65,15 +72,100 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int write_file_stream(git_oid *oid, git_odb *odb, const char *path, git_off_t file_size)
|
||||
{
|
||||
int fd, error;
|
||||
char buffer[4096];
|
||||
git_odb_stream *stream = NULL;
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, odb, file_size, GIT_OBJ_BLOB)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if ((fd = p_open(path, O_RDONLY)) < 0) {
|
||||
error = git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (file_size > 0) {
|
||||
ssize_t read_len = p_read(fd, buffer, sizeof(buffer));
|
||||
|
||||
if (read_len < 0) {
|
||||
error = git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file");
|
||||
p_close(fd);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
stream->write(stream, buffer, read_len);
|
||||
file_size -= read_len;
|
||||
}
|
||||
|
||||
p_close(fd);
|
||||
error = stream->finalize_write(oid, stream);
|
||||
|
||||
cleanup:
|
||||
stream->free(stream);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int write_file_filtered(
|
||||
git_oid *oid,
|
||||
git_odb *odb,
|
||||
const char *full_path,
|
||||
git_vector *filters)
|
||||
{
|
||||
int error;
|
||||
git_buf source = GIT_BUF_INIT;
|
||||
git_buf dest = GIT_BUF_INIT;
|
||||
|
||||
error = git_futils_readbuffer(&source, full_path);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
error = git_filters_apply(&dest, &source, filters);
|
||||
|
||||
/* Free the source as soon as possible. This can be big in memory,
|
||||
* and we don't want to ODB write to choke */
|
||||
git_buf_free(&source);
|
||||
|
||||
if (error == GIT_SUCCESS) {
|
||||
/* Write the file to disk if it was properly filtered */
|
||||
error = git_odb_write(oid, odb, dest.ptr, dest.size, GIT_OBJ_BLOB);
|
||||
}
|
||||
|
||||
git_buf_free(&dest);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int write_symlink(git_oid *oid, git_odb *odb, const char *path, size_t link_size)
|
||||
{
|
||||
char *link_data;
|
||||
ssize_t read_len;
|
||||
int error;
|
||||
|
||||
link_data = git__malloc(link_size);
|
||||
if (!link_data)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
read_len = p_readlink(path, link_data, link_size);
|
||||
|
||||
if (read_len != (ssize_t)link_size) {
|
||||
free(link_data);
|
||||
return git__throw(GIT_EOSERR, "Failed to create blob. Can't read symlink");
|
||||
}
|
||||
|
||||
error = git_odb_write(oid, odb, (void *)link_data, link_size, GIT_OBJ_BLOB);
|
||||
free(link_data);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
|
||||
{
|
||||
int error = GIT_SUCCESS;
|
||||
git_buf full_path = GIT_BUF_INIT;
|
||||
git_off_t size;
|
||||
git_odb_stream *stream = NULL;
|
||||
struct stat st;
|
||||
const char *workdir;
|
||||
git_odb *odb;
|
||||
git_odb *odb = NULL;
|
||||
|
||||
workdir = git_repository_workdir(repo);
|
||||
if (workdir == NULL)
|
||||
@ -95,63 +187,45 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, odb, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
char *link_data;
|
||||
ssize_t read_len;
|
||||
|
||||
link_data = git__malloc((size_t)size);
|
||||
if (!link_data) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
read_len = p_readlink(full_path.ptr, link_data, (size_t)size);
|
||||
|
||||
if (read_len != (ssize_t)size) {
|
||||
error = git__throw(GIT_EOSERR, "Failed to create blob. Can't read symlink");
|
||||
free(link_data);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
stream->write(stream, link_data, (size_t)size);
|
||||
free(link_data);
|
||||
|
||||
error = write_symlink(oid, odb, full_path.ptr, (size_t)size);
|
||||
} else {
|
||||
int fd;
|
||||
char buffer[2048];
|
||||
git_vector write_filters = GIT_VECTOR_INIT;
|
||||
int filter_count;
|
||||
|
||||
if ((fd = p_open(full_path.ptr, O_RDONLY)) < 0) {
|
||||
error = git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", full_path.ptr);
|
||||
/* Load the filters for writing this file to the ODB */
|
||||
filter_count = git_filters_load(&write_filters, repo, path, GIT_FILTER_TO_ODB);
|
||||
|
||||
if (filter_count < 0) {
|
||||
/* Negative value means there was a critical error */
|
||||
error = filter_count;
|
||||
goto cleanup;
|
||||
} else if (filter_count == 0) {
|
||||
/* No filters need to be applied to the document: we can stream
|
||||
* directly from disk */
|
||||
error = write_file_stream(oid, odb, full_path.ptr, size);
|
||||
} else {
|
||||
/* We need to apply one or more filters */
|
||||
error = write_file_filtered(oid, odb, full_path.ptr, &write_filters);
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
ssize_t read_len = p_read(fd, buffer, sizeof(buffer));
|
||||
git_filters_free(&write_filters);
|
||||
|
||||
if (read_len < 0) {
|
||||
error = git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file");
|
||||
p_close(fd);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
stream->write(stream, buffer, read_len);
|
||||
size -= read_len;
|
||||
}
|
||||
|
||||
p_close(fd);
|
||||
/*
|
||||
* TODO: eventually support streaming filtered files, for files which are bigger
|
||||
* than a given threshold. This is not a priority because applying a filter in
|
||||
* streaming mode changes the final size of the blob, and without knowing its
|
||||
* final size, the blob cannot be written in stream mode to the ODB.
|
||||
*
|
||||
* The plan is to do streaming writes to a tempfile on disk and then opening
|
||||
* streaming that file to the ODB, using `write_file_stream`.
|
||||
*
|
||||
* CAREFULLY DESIGNED APIS YO
|
||||
*/
|
||||
}
|
||||
|
||||
error = stream->finalize_write(oid, stream);
|
||||
|
||||
cleanup:
|
||||
if (stream)
|
||||
stream->free(stream);
|
||||
|
||||
git_buf_free(&full_path);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -19,5 +19,6 @@ struct git_blob {
|
||||
|
||||
void git_blob__free(git_blob *blob);
|
||||
int git_blob__parse(git_blob *blob, git_odb_object *obj);
|
||||
int git_blob__getbuf(git_buf *buffer, git_blob *blob);
|
||||
|
||||
#endif
|
||||
|
56
src/buffer.c
56
src/buffer.c
@ -7,14 +7,17 @@
|
||||
#include "buffer.h"
|
||||
#include "posix.h"
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* Used as default value for git_buf->ptr so that people can always
|
||||
* assume ptr is non-NULL and zero terminated even for new git_bufs.
|
||||
*/
|
||||
char git_buf_initbuf[1];
|
||||
|
||||
static char git_buf__oom;
|
||||
|
||||
#define ENSURE_SIZE(b, d) \
|
||||
if ((ssize_t)(d) > buf->asize && git_buf_grow(b, (d)) < GIT_SUCCESS)\
|
||||
if ((d) > buf->asize && git_buf_grow(b, (d)) < GIT_SUCCESS)\
|
||||
return GIT_ENOMEM;
|
||||
|
||||
|
||||
@ -31,8 +34,10 @@ void git_buf_init(git_buf *buf, size_t initial_size)
|
||||
int git_buf_grow(git_buf *buf, size_t target_size)
|
||||
{
|
||||
int error = git_buf_try_grow(buf, target_size);
|
||||
if (error != GIT_SUCCESS)
|
||||
buf->asize = -1;
|
||||
if (error != GIT_SUCCESS) {
|
||||
buf->ptr = &git_buf__oom;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -41,17 +46,17 @@ int git_buf_try_grow(git_buf *buf, size_t target_size)
|
||||
char *new_ptr;
|
||||
size_t new_size;
|
||||
|
||||
if (buf->asize < 0)
|
||||
if (buf->ptr == &git_buf__oom)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
if (target_size <= (size_t)buf->asize)
|
||||
if (target_size <= buf->asize)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if (buf->asize == 0) {
|
||||
new_size = target_size;
|
||||
new_ptr = NULL;
|
||||
} else {
|
||||
new_size = (size_t)buf->asize;
|
||||
new_size = buf->asize;
|
||||
new_ptr = buf->ptr;
|
||||
}
|
||||
|
||||
@ -64,7 +69,6 @@ int git_buf_try_grow(git_buf *buf, size_t target_size)
|
||||
new_size = (new_size + 7) & ~7;
|
||||
|
||||
new_ptr = git__realloc(new_ptr, new_size);
|
||||
/* if realloc fails, return without modifying the git_buf */
|
||||
if (!new_ptr)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
@ -83,7 +87,7 @@ void git_buf_free(git_buf *buf)
|
||||
{
|
||||
if (!buf) return;
|
||||
|
||||
if (buf->ptr != git_buf_initbuf)
|
||||
if (buf->ptr != git_buf_initbuf && buf->ptr != &git_buf__oom)
|
||||
git__free(buf->ptr);
|
||||
|
||||
git_buf_init(buf, 0);
|
||||
@ -98,12 +102,12 @@ void git_buf_clear(git_buf *buf)
|
||||
|
||||
int git_buf_oom(const git_buf *buf)
|
||||
{
|
||||
return (buf->asize < 0);
|
||||
return (buf->ptr == &git_buf__oom);
|
||||
}
|
||||
|
||||
int git_buf_lasterror(const git_buf *buf)
|
||||
{
|
||||
return (buf->asize < 0) ? GIT_ENOMEM : GIT_SUCCESS;
|
||||
return (buf->ptr == &git_buf__oom) ? GIT_ENOMEM : GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_buf_set(git_buf *buf, const char *data, size_t len)
|
||||
@ -162,11 +166,12 @@ int git_buf_printf(git_buf *buf, const char *format, ...)
|
||||
va_end(arglist);
|
||||
|
||||
if (len < 0) {
|
||||
buf->asize = -1;
|
||||
free(buf->ptr);
|
||||
buf->ptr = &git_buf__oom;
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
if (len + 1 <= buf->asize - buf->size) {
|
||||
if ((size_t)len + 1 <= buf->asize - buf->size) {
|
||||
buf->size += len;
|
||||
break;
|
||||
}
|
||||
@ -205,9 +210,9 @@ void git_buf_consume(git_buf *buf, const char *end)
|
||||
}
|
||||
}
|
||||
|
||||
void git_buf_truncate(git_buf *buf, ssize_t len)
|
||||
void git_buf_truncate(git_buf *buf, size_t len)
|
||||
{
|
||||
if (len >= 0 && len < buf->size) {
|
||||
if (len < buf->size) {
|
||||
buf->size = len;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
@ -230,7 +235,7 @@ char *git_buf_detach(git_buf *buf)
|
||||
{
|
||||
char *data = buf->ptr;
|
||||
|
||||
if (buf->asize <= 0)
|
||||
if (buf->asize == 0 || buf->ptr == &git_buf__oom)
|
||||
return NULL;
|
||||
|
||||
git_buf_init(buf, 0);
|
||||
@ -238,7 +243,7 @@ char *git_buf_detach(git_buf *buf)
|
||||
return data;
|
||||
}
|
||||
|
||||
void git_buf_attach(git_buf *buf, char *ptr, ssize_t asize)
|
||||
void git_buf_attach(git_buf *buf, char *ptr, size_t asize)
|
||||
{
|
||||
git_buf_free(buf);
|
||||
|
||||
@ -372,3 +377,22 @@ int git_buf_join(
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void git_buf_rtrim(git_buf *buf)
|
||||
{
|
||||
while (buf->size > 0) {
|
||||
if (!isspace(buf->ptr[buf->size - 1]))
|
||||
break;
|
||||
|
||||
buf->size--;
|
||||
}
|
||||
|
||||
buf->ptr[buf->size] = '\0';
|
||||
}
|
||||
|
||||
int git_buf_cmp(const git_buf *a, const git_buf *b)
|
||||
{
|
||||
int result = memcmp(a->ptr, b->ptr, min(a->size, b->size));
|
||||
return (result != 0) ? result :
|
||||
(a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0;
|
||||
}
|
||||
|
11
src/buffer.h
11
src/buffer.h
@ -11,7 +11,7 @@
|
||||
|
||||
typedef struct {
|
||||
char *ptr;
|
||||
ssize_t asize, size;
|
||||
size_t asize, size;
|
||||
} git_buf;
|
||||
|
||||
extern char git_buf_initbuf[];
|
||||
@ -47,7 +47,7 @@ int git_buf_try_grow(git_buf *buf, size_t target_size);
|
||||
void git_buf_free(git_buf *buf);
|
||||
void git_buf_swap(git_buf *buf_a, git_buf *buf_b);
|
||||
char *git_buf_detach(git_buf *buf);
|
||||
void git_buf_attach(git_buf *buf, char *ptr, ssize_t asize);
|
||||
void git_buf_attach(git_buf *buf, char *ptr, size_t asize);
|
||||
|
||||
/**
|
||||
* Test if there have been any reallocation failures with this git_buf.
|
||||
@ -83,7 +83,7 @@ int git_buf_puts(git_buf *buf, const char *string);
|
||||
int git_buf_printf(git_buf *buf, const char *format, ...) GIT_FORMAT_PRINTF(2, 3);
|
||||
void git_buf_clear(git_buf *buf);
|
||||
void git_buf_consume(git_buf *buf, const char *end);
|
||||
void git_buf_truncate(git_buf *buf, ssize_t len);
|
||||
void git_buf_truncate(git_buf *buf, size_t len);
|
||||
void git_buf_rtruncate_at_char(git_buf *path, char separator);
|
||||
|
||||
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
|
||||
@ -115,4 +115,9 @@ GIT_INLINE(int) git_buf_rfind_next(git_buf *buf, char ch)
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* Remove whitespace from the end of the buffer */
|
||||
void git_buf_rtrim(git_buf *buf);
|
||||
|
||||
int git_buf_cmp(const git_buf *a, const git_buf *b);
|
||||
|
||||
#endif
|
||||
|
236
src/config.c
236
src/config.c
@ -209,85 +209,8 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
|
||||
return file->set(file, name, value);
|
||||
}
|
||||
|
||||
/***********
|
||||
* Getters
|
||||
***********/
|
||||
|
||||
int git_config_get_int64(git_config *cfg, const char *name, int64_t *out)
|
||||
static int parse_bool(int *out, const char *value)
|
||||
{
|
||||
const char *value, *num_end;
|
||||
int ret;
|
||||
int64_t num;
|
||||
|
||||
ret = git_config_get_string(cfg, name, &value);
|
||||
if (ret < GIT_SUCCESS)
|
||||
return git__rethrow(ret, "Failed to retrieve value for '%s'", name);
|
||||
|
||||
ret = git__strtol64(&num, value, &num_end, 0);
|
||||
if (ret < GIT_SUCCESS)
|
||||
return git__rethrow(ret, "Failed to convert value for '%s'", name);
|
||||
|
||||
switch (*num_end) {
|
||||
case 'g':
|
||||
case 'G':
|
||||
num *= 1024;
|
||||
/* fallthrough */
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
num *= 1024;
|
||||
/* fallthrough */
|
||||
|
||||
case 'k':
|
||||
case 'K':
|
||||
num *= 1024;
|
||||
|
||||
/* check that that there are no more characters after the
|
||||
* given modifier suffix */
|
||||
if (num_end[1] != '\0')
|
||||
return git__throw(GIT_EINVALIDTYPE,
|
||||
"Failed to get value for '%s'. Invalid type suffix", name);
|
||||
|
||||
/* fallthrough */
|
||||
|
||||
case '\0':
|
||||
*out = num;
|
||||
return GIT_SUCCESS;
|
||||
|
||||
default:
|
||||
return git__throw(GIT_EINVALIDTYPE,
|
||||
"Failed to get value for '%s'. Value is of invalid type", name);
|
||||
}
|
||||
}
|
||||
|
||||
int git_config_get_int32(git_config *cfg, const char *name, int32_t *out)
|
||||
{
|
||||
int64_t tmp_long;
|
||||
int32_t tmp_int;
|
||||
int ret;
|
||||
|
||||
ret = git_config_get_int64(cfg, name, &tmp_long);
|
||||
if (ret < GIT_SUCCESS)
|
||||
return git__rethrow(ret, "Failed to convert value for '%s'", name);
|
||||
|
||||
tmp_int = tmp_long & 0xFFFFFFFF;
|
||||
if (tmp_int != tmp_long)
|
||||
return git__throw(GIT_EOVERFLOW, "Value for '%s' is too large", name);
|
||||
|
||||
*out = tmp_int;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int git_config_get_bool(git_config *cfg, const char *name, int *out)
|
||||
{
|
||||
const char *value;
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
error = git_config_get_string(cfg, name, &value);
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to get value for %s", name);
|
||||
|
||||
/* A missing value means true */
|
||||
if (value == NULL) {
|
||||
*out = 1;
|
||||
@ -307,14 +230,161 @@ int git_config_get_bool(git_config *cfg, const char *name, int *out)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Try to parse it as an integer */
|
||||
error = git_config_get_int32(cfg, name, out);
|
||||
if (error == GIT_SUCCESS)
|
||||
*out = !!(*out);
|
||||
return GIT_EINVALIDTYPE;
|
||||
}
|
||||
|
||||
static int parse_int64(int64_t *out, const char *value)
|
||||
{
|
||||
const char *num_end;
|
||||
int64_t num;
|
||||
|
||||
if (git__strtol64(&num, value, &num_end, 0) < 0)
|
||||
return GIT_EINVALIDTYPE;
|
||||
|
||||
switch (*num_end) {
|
||||
case 'g':
|
||||
case 'G':
|
||||
num *= 1024;
|
||||
/* fallthrough */
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
num *= 1024;
|
||||
/* fallthrough */
|
||||
|
||||
case 'k':
|
||||
case 'K':
|
||||
num *= 1024;
|
||||
|
||||
/* check that that there are no more characters after the
|
||||
* given modifier suffix */
|
||||
if (num_end[1] != '\0')
|
||||
return GIT_EINVALIDTYPE;
|
||||
|
||||
/* fallthrough */
|
||||
|
||||
case '\0':
|
||||
*out = num;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return GIT_EINVALIDTYPE;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_int32(int32_t *out, const char *value)
|
||||
{
|
||||
int64_t tmp;
|
||||
int32_t truncate;
|
||||
|
||||
if (parse_int64(&tmp, value) < 0)
|
||||
return GIT_EINVALIDTYPE;
|
||||
|
||||
truncate = tmp & 0xFFFFFFFF;
|
||||
if (truncate != tmp)
|
||||
return GIT_EOVERFLOW;
|
||||
|
||||
*out = truncate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********
|
||||
* Getters
|
||||
***********/
|
||||
int git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n, int *out)
|
||||
{
|
||||
size_t i;
|
||||
const char *value;
|
||||
int error;
|
||||
|
||||
error = git_config_get_string(cfg, name, &value);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
for (i = 0; i < map_n; ++i) {
|
||||
git_cvar_map *m = maps + i;
|
||||
|
||||
switch (m->cvar_type) {
|
||||
case GIT_CVAR_FALSE:
|
||||
case GIT_CVAR_TRUE: {
|
||||
int bool_val;
|
||||
|
||||
if (parse_bool(&bool_val, value) == 0 &&
|
||||
bool_val == (int)m->cvar_type) {
|
||||
*out = m->map_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GIT_CVAR_INT32:
|
||||
if (parse_int32(out, value) == 0)
|
||||
return 0;
|
||||
|
||||
break;
|
||||
|
||||
case GIT_CVAR_STRING:
|
||||
if (strcasecmp(value, m->str_match) == 0) {
|
||||
*out = m->map_value;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return git__throw(GIT_ENOTFOUND,
|
||||
"Failed to map the '%s' config variable with a valid value", name);
|
||||
}
|
||||
|
||||
int git_config_get_int64(git_config *cfg, const char *name, int64_t *out)
|
||||
{
|
||||
const char *value;
|
||||
int ret;
|
||||
|
||||
ret = git_config_get_string(cfg, name, &value);
|
||||
if (ret < GIT_SUCCESS)
|
||||
return git__rethrow(ret, "Failed to retrieve value for '%s'", name);
|
||||
|
||||
if (parse_int64(out, value) < 0)
|
||||
return git__throw(GIT_EINVALIDTYPE, "Failed to parse '%s' as an integer", value);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_config_get_int32(git_config *cfg, const char *name, int32_t *out)
|
||||
{
|
||||
const char *value;
|
||||
int error;
|
||||
|
||||
error = git_config_get_string(cfg, name, &value);
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to get value for %s", name);
|
||||
return error;
|
||||
|
||||
error = parse_int32(out, value);
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__throw(GIT_EINVALIDTYPE, "Failed to parse '%s' as a 32-bit integer", value);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_config_get_bool(git_config *cfg, const char *name, int *out)
|
||||
{
|
||||
const char *value;
|
||||
int error = GIT_SUCCESS;
|
||||
|
||||
error = git_config_get_string(cfg, name, &value);
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to get value for %s", name);
|
||||
|
||||
if (parse_bool(out, value) == 0)
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if (parse_int32(out, value) == 0) {
|
||||
*out = !!(*out);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
return git__throw(GIT_EINVALIDTYPE, "Failed to parse '%s' as a boolean value", value);
|
||||
}
|
||||
|
||||
int git_config_get_string(git_config *cfg, const char *name, const char **out)
|
||||
|
95
src/config_cache.c
Normal file
95
src/config_cache.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2012 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.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "fileops.h"
|
||||
#include "hashtable.h"
|
||||
#include "config.h"
|
||||
#include "git2/config.h"
|
||||
#include "vector.h"
|
||||
#include "filter.h"
|
||||
#include "repository.h"
|
||||
|
||||
struct map_data {
|
||||
const char *cvar_name;
|
||||
git_cvar_map *maps;
|
||||
size_t map_count;
|
||||
int default_value;
|
||||
};
|
||||
|
||||
/*
|
||||
* core.eol
|
||||
* Sets the line ending type to use in the working directory for
|
||||
* files that have the text property set. Alternatives are lf, crlf
|
||||
* and native, which uses the platform’s native line ending. The default
|
||||
* value is native. See gitattributes(5) for more information on
|
||||
* end-of-line conversion.
|
||||
*/
|
||||
static git_cvar_map _cvar_map_eol[] = {
|
||||
{GIT_CVAR_FALSE, NULL, GIT_EOL_UNSET},
|
||||
{GIT_CVAR_STRING, "lf", GIT_EOL_LF},
|
||||
{GIT_CVAR_STRING, "crlf", GIT_EOL_CRLF},
|
||||
{GIT_CVAR_STRING, "native", GIT_EOL_NATIVE}
|
||||
};
|
||||
|
||||
/*
|
||||
* core.autocrlf
|
||||
* Setting this variable to "true" is almost the same as setting
|
||||
* the text attribute to "auto" on all files except that text files are
|
||||
* not guaranteed to be normalized: files that contain CRLF in the
|
||||
* repository will not be touched. Use this setting if you want to have
|
||||
* CRLF line endings in your working directory even though the repository
|
||||
* does not have normalized line endings. This variable can be set to input,
|
||||
* in which case no output conversion is performed.
|
||||
*/
|
||||
static git_cvar_map _cvar_map_autocrlf[] = {
|
||||
{GIT_CVAR_FALSE, NULL, GIT_AUTO_CRLF_FALSE},
|
||||
{GIT_CVAR_TRUE, NULL, GIT_AUTO_CRLF_TRUE},
|
||||
{GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT}
|
||||
};
|
||||
|
||||
static struct map_data _cvar_maps[] = {
|
||||
{"core.autocrlf", _cvar_map_autocrlf, ARRAY_SIZE(_cvar_map_autocrlf), GIT_AUTO_CRLF_DEFAULT},
|
||||
{"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT}
|
||||
};
|
||||
|
||||
int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar)
|
||||
{
|
||||
*out = repo->cvar_cache[(int)cvar];
|
||||
|
||||
if (*out == GIT_CVAR_NOT_CACHED) {
|
||||
struct map_data *data = &_cvar_maps[(int)cvar];
|
||||
git_config *config;
|
||||
int error;
|
||||
|
||||
error = git_repository_config__weakptr(&config, repo);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
error = git_config_get_mapped(
|
||||
config, data->cvar_name, data->maps, data->map_count, out);
|
||||
|
||||
if (error == GIT_ENOTFOUND)
|
||||
*out = data->default_value;
|
||||
|
||||
else if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
repo->cvar_cache[(int)cvar] = *out;
|
||||
}
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
void git_repository__cvar_cache_clear(git_repository *repo)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GIT_CVAR_CACHE_MAX; ++i)
|
||||
repo->cvar_cache[i] = GIT_CVAR_NOT_CACHED;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ typedef struct {
|
||||
git_hashtable *values;
|
||||
|
||||
struct {
|
||||
git_fbuffer buffer;
|
||||
git_buf buffer;
|
||||
char *read_ptr;
|
||||
int line_number;
|
||||
int eof;
|
||||
@ -151,6 +151,7 @@ static int config_open(git_config_file *cfg)
|
||||
if (b->values == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
git_buf_init(&b->reader.buffer, 0);
|
||||
error = git_futils_readbuffer(&b->reader.buffer, b->file_path);
|
||||
|
||||
/* It's fine if the file doesn't exist */
|
||||
@ -164,14 +165,14 @@ static int config_open(git_config_file *cfg)
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
git_futils_freebuffer(&b->reader.buffer);
|
||||
git_buf_free(&b->reader.buffer);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
free_vars(b->values);
|
||||
b->values = NULL;
|
||||
git_futils_freebuffer(&b->reader.buffer);
|
||||
git_buf_free(&b->reader.buffer);
|
||||
|
||||
return git__rethrow(error, "Failed to open config");
|
||||
}
|
||||
@ -765,7 +766,7 @@ static int skip_bom(diskfile_backend *cfg)
|
||||
{
|
||||
static const char utf8_bom[] = "\xef\xbb\xbf";
|
||||
|
||||
if (cfg->reader.buffer.len < sizeof(utf8_bom))
|
||||
if (cfg->reader.buffer.size < sizeof(utf8_bom))
|
||||
return GIT_SUCCESS;
|
||||
|
||||
if (memcmp(cfg->reader.read_ptr, utf8_bom, sizeof(utf8_bom)) == 0)
|
||||
@ -847,7 +848,7 @@ static int config_parse(diskfile_backend *cfg_file)
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
|
||||
/* Initialize the reading position */
|
||||
cfg_file->reader.read_ptr = cfg_file->reader.buffer.data;
|
||||
cfg_file->reader.read_ptr = cfg_file->reader.buffer.ptr;
|
||||
cfg_file->reader.eof = 0;
|
||||
|
||||
/* If the file is empty, there's nothing for us to do */
|
||||
@ -976,10 +977,9 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
|
||||
cfg->reader.read_ptr = NULL;
|
||||
cfg->reader.eof = 1;
|
||||
data_start = NULL;
|
||||
cfg->reader.buffer.len = 0;
|
||||
cfg->reader.buffer.data = NULL;
|
||||
git_buf_clear(&cfg->reader.buffer);
|
||||
} else {
|
||||
cfg->reader.read_ptr = cfg->reader.buffer.data;
|
||||
cfg->reader.read_ptr = cfg->reader.buffer.ptr;
|
||||
cfg->reader.eof = 0;
|
||||
data_start = cfg->reader.read_ptr;
|
||||
}
|
||||
@ -1093,7 +1093,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
|
||||
|
||||
/* And then the write out rest of the file */
|
||||
error = git_filebuf_write(&file, post_start,
|
||||
cfg->reader.buffer.len - (post_start - data_start));
|
||||
cfg->reader.buffer.size - (post_start - data_start));
|
||||
|
||||
if (error < GIT_SUCCESS) {
|
||||
git__rethrow(error, "Failed to write the rest of the file");
|
||||
@ -1128,7 +1128,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error = git_filebuf_write(&file, cfg->reader.buffer.data, cfg->reader.buffer.len);
|
||||
error = git_filebuf_write(&file, cfg->reader.buffer.ptr, cfg->reader.buffer.size);
|
||||
if (error < GIT_SUCCESS) {
|
||||
git__rethrow(error, "Failed to write original config content");
|
||||
goto cleanup;
|
||||
@ -1155,7 +1155,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
|
||||
else
|
||||
error = git_filebuf_commit(&file, GIT_CONFIG_FILE_MODE);
|
||||
|
||||
git_futils_freebuffer(&cfg->reader.buffer);
|
||||
git_buf_free(&cfg->reader.buffer);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
229
src/crlf.c
Normal file
229
src/crlf.c
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2012 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.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "fileops.h"
|
||||
#include "hash.h"
|
||||
#include "filter.h"
|
||||
#include "repository.h"
|
||||
|
||||
#include "git2/attr.h"
|
||||
|
||||
struct crlf_attrs {
|
||||
int crlf_action;
|
||||
int eol;
|
||||
};
|
||||
|
||||
struct crlf_filter {
|
||||
git_filter f;
|
||||
struct crlf_attrs attrs;
|
||||
};
|
||||
|
||||
static int check_crlf(const char *value)
|
||||
{
|
||||
if (GIT_ATTR_TRUE(value))
|
||||
return GIT_CRLF_TEXT;
|
||||
|
||||
if (GIT_ATTR_FALSE(value))
|
||||
return GIT_CRLF_BINARY;
|
||||
|
||||
if (GIT_ATTR_UNSPECIFIED(value))
|
||||
return GIT_CRLF_GUESS;
|
||||
|
||||
if (strcmp(value, "input") == 0)
|
||||
return GIT_CRLF_INPUT;
|
||||
|
||||
if (strcmp(value, "auto") == 0)
|
||||
return GIT_CRLF_AUTO;
|
||||
|
||||
return GIT_CRLF_GUESS;
|
||||
}
|
||||
|
||||
static int check_eol(const char *value)
|
||||
{
|
||||
if (GIT_ATTR_UNSPECIFIED(value))
|
||||
return GIT_EOL_UNSET;
|
||||
|
||||
if (strcmp(value, "lf") == 0)
|
||||
return GIT_EOL_LF;
|
||||
|
||||
if (strcmp(value, "crlf") == 0)
|
||||
return GIT_EOL_CRLF;
|
||||
|
||||
return GIT_EOL_UNSET;
|
||||
}
|
||||
|
||||
static int crlf_input_action(struct crlf_attrs *ca)
|
||||
{
|
||||
if (ca->crlf_action == GIT_CRLF_BINARY)
|
||||
return GIT_CRLF_BINARY;
|
||||
|
||||
if (ca->eol == GIT_EOL_LF)
|
||||
return GIT_CRLF_INPUT;
|
||||
|
||||
if (ca->eol == GIT_EOL_CRLF)
|
||||
return GIT_CRLF_CRLF;
|
||||
|
||||
return ca->crlf_action;
|
||||
}
|
||||
|
||||
static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, const char *path)
|
||||
{
|
||||
#define NUM_CONV_ATTRS 3
|
||||
|
||||
static const char *attr_names[NUM_CONV_ATTRS] = {
|
||||
"crlf", "eol", "text",
|
||||
};
|
||||
|
||||
const char *attr_vals[NUM_CONV_ATTRS];
|
||||
int error;
|
||||
|
||||
error = git_attr_get_many(repo, path, NUM_CONV_ATTRS, attr_names, attr_vals);
|
||||
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
ca->crlf_action = GIT_CRLF_GUESS;
|
||||
ca->eol = GIT_EOL_UNSET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (error == GIT_SUCCESS) {
|
||||
ca->crlf_action = check_crlf(attr_vals[2]); /* text */
|
||||
if (ca->crlf_action == GIT_CRLF_GUESS)
|
||||
ca->crlf_action = check_crlf(attr_vals[0]); /* clrf */
|
||||
|
||||
ca->eol = check_eol(attr_vals[1]); /* eol */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int drop_crlf(git_buf *dest, const git_buf *source)
|
||||
{
|
||||
const char *scan = source->ptr, *next;
|
||||
const char *scan_end = source->ptr + source->size;
|
||||
|
||||
/* Main scan loop. Find the next carriage return and copy the
|
||||
* whole chunk up to that point to the destination buffer.
|
||||
*/
|
||||
while ((next = memchr(scan, '\r', scan_end - scan)) != NULL) {
|
||||
/* copy input up to \r */
|
||||
if (next > scan)
|
||||
git_buf_put(dest, scan, next - scan);
|
||||
|
||||
/* Do not drop \r unless it is followed by \n */
|
||||
if (*(next + 1) != '\n')
|
||||
git_buf_putc(dest, '\r');
|
||||
|
||||
scan = next + 1;
|
||||
}
|
||||
|
||||
/* If there was no \r, then tell the library to skip this filter */
|
||||
if (scan == source->ptr)
|
||||
return -1;
|
||||
|
||||
/* Copy remaining input into dest */
|
||||
git_buf_put(dest, scan, scan_end - scan);
|
||||
|
||||
return git_buf_lasterror(dest);
|
||||
}
|
||||
|
||||
static int crlf_apply_to_odb(git_filter *self, git_buf *dest, const git_buf *source)
|
||||
{
|
||||
struct crlf_filter *filter = (struct crlf_filter *)self;
|
||||
|
||||
assert(self && dest && source);
|
||||
|
||||
/* Empty file? Nothing to do */
|
||||
if (source->size == 0)
|
||||
return 0;
|
||||
|
||||
/* Heuristics to see if we can skip the conversion.
|
||||
* Straight from Core Git.
|
||||
*/
|
||||
if (filter->attrs.crlf_action == GIT_CRLF_AUTO ||
|
||||
filter->attrs.crlf_action == GIT_CRLF_GUESS) {
|
||||
|
||||
git_text_stats stats;
|
||||
git_text_gather_stats(&stats, source);
|
||||
|
||||
/*
|
||||
* We're currently not going to even try to convert stuff
|
||||
* that has bare CR characters. Does anybody do that crazy
|
||||
* stuff?
|
||||
*/
|
||||
if (stats.cr != stats.crlf)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* And add some heuristics for binary vs text, of course...
|
||||
*/
|
||||
if (git_text_is_binary(&stats))
|
||||
return -1;
|
||||
|
||||
#if 0
|
||||
if (crlf_action == CRLF_GUESS) {
|
||||
/*
|
||||
* If the file in the index has any CR in it, do not convert.
|
||||
* This is the new safer autocrlf handling.
|
||||
*/
|
||||
if (has_cr_in_index(path))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!stats.cr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Actually drop the carriage returns */
|
||||
return drop_crlf(dest, source);
|
||||
}
|
||||
|
||||
int git_filter_add__crlf_to_odb(git_vector *filters, git_repository *repo, const char *path)
|
||||
{
|
||||
struct crlf_attrs ca;
|
||||
struct crlf_filter *filter;
|
||||
int error;
|
||||
|
||||
/* Load gitattributes for the path */
|
||||
if ((error = crlf_load_attributes(&ca, repo, path)) < 0)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Use the core Git logic to see if we should perform CRLF for this file
|
||||
* based on its attributes & the value of `core.auto_crlf`
|
||||
*/
|
||||
ca.crlf_action = crlf_input_action(&ca);
|
||||
|
||||
if (ca.crlf_action == GIT_CRLF_BINARY)
|
||||
return 0;
|
||||
|
||||
if (ca.crlf_action == GIT_CRLF_GUESS) {
|
||||
int auto_crlf;
|
||||
|
||||
if ((error = git_repository__cvar(
|
||||
&auto_crlf, repo, GIT_CVAR_AUTO_CRLF)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (auto_crlf == GIT_AUTO_CRLF_FALSE)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we're good, we create a new filter object and push it
|
||||
* into the filters array */
|
||||
filter = git__malloc(sizeof(struct crlf_filter));
|
||||
if (filter == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
filter->f.apply = &crlf_apply_to_odb;
|
||||
filter->f.do_free = NULL;
|
||||
memcpy(&filter->attrs, &ca, sizeof(struct crlf_attrs));
|
||||
|
||||
return git_vector_insert(filters, filter);
|
||||
}
|
||||
|
@ -97,87 +97,77 @@ mode_t git_futils_canonical_mode(mode_t raw_mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_futils_readbuffer_updated(git_fbuffer *obj, const char *path, time_t *mtime, int *updated)
|
||||
int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, int *updated)
|
||||
{
|
||||
git_file fd;
|
||||
size_t len;
|
||||
struct stat st;
|
||||
unsigned char *buff;
|
||||
|
||||
assert(obj && path && *path);
|
||||
assert(buf && path && *path);
|
||||
|
||||
if (updated != NULL)
|
||||
*updated = 0;
|
||||
|
||||
if (p_stat(path, &st) < 0)
|
||||
return git__throw(GIT_ENOTFOUND, "Failed to stat file %s", path);
|
||||
if ((fd = p_open(path, O_RDONLY)) < 0) {
|
||||
return git__throw(GIT_ENOTFOUND, "Failed to read file '%s': %s", path, strerror(errno));
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode))
|
||||
return git__throw(GIT_ERROR, "Can't read a dir into a buffer");
|
||||
if (p_fstat(fd, &st) < 0 || S_ISDIR(st.st_mode) || !git__is_sizet(st.st_size+1)) {
|
||||
close(fd);
|
||||
return git__throw(GIT_EOSERR, "Failed to stat file '%s'", path);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we were given a time, we only want to read the file if it
|
||||
* has been modified.
|
||||
*/
|
||||
if (mtime != NULL && *mtime >= st.st_mtime)
|
||||
return GIT_SUCCESS;
|
||||
if (mtime != NULL && *mtime >= st.st_mtime) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mtime != NULL)
|
||||
*mtime = st.st_mtime;
|
||||
if (!git__is_sizet(st.st_size+1))
|
||||
return git__throw(GIT_ERROR, "Failed to read file `%s`. An error occured while calculating its size", path);
|
||||
|
||||
len = (size_t) st.st_size;
|
||||
|
||||
if ((fd = p_open(path, O_RDONLY)) < 0)
|
||||
return git__throw(GIT_EOSERR, "Failed to open %s for reading", path);
|
||||
git_buf_clear(buf);
|
||||
|
||||
if ((buff = git__malloc(len + 1)) == NULL) {
|
||||
p_close(fd);
|
||||
if (git_buf_grow(buf, len + 1) < 0) {
|
||||
close(fd);
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
if (p_read(fd, buff, len) < 0) {
|
||||
p_close(fd);
|
||||
git__free(buff);
|
||||
return git__throw(GIT_ERROR, "Failed to read file `%s`", path);
|
||||
buf->ptr[len] = '\0';
|
||||
|
||||
while (len > 0) {
|
||||
ssize_t read_size = p_read(fd, buf->ptr, len);
|
||||
|
||||
if (read_size < 0) {
|
||||
close(fd);
|
||||
return git__throw(GIT_EOSERR, "Failed to read from FD");
|
||||
}
|
||||
|
||||
len -= read_size;
|
||||
buf->size += read_size;
|
||||
}
|
||||
buff[len] = '\0';
|
||||
|
||||
p_close(fd);
|
||||
|
||||
if (mtime != NULL)
|
||||
*mtime = st.st_mtime;
|
||||
|
||||
if (updated != NULL)
|
||||
*updated = 1;
|
||||
|
||||
obj->data = buff;
|
||||
obj->len = len;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_futils_readbuffer(git_fbuffer *obj, const char *path)
|
||||
int git_futils_readbuffer(git_buf *buf, const char *path)
|
||||
{
|
||||
return git_futils_readbuffer_updated(obj, path, NULL, NULL);
|
||||
return git_futils_readbuffer_updated(buf, path, NULL, NULL);
|
||||
}
|
||||
|
||||
void git_futils_fbuffer_rtrim(git_fbuffer *obj)
|
||||
{
|
||||
unsigned char *buff = obj->data;
|
||||
while (obj->len > 0 && isspace(buff[obj->len - 1]))
|
||||
obj->len--;
|
||||
buff[obj->len] = '\0';
|
||||
}
|
||||
|
||||
void git_futils_freebuffer(git_fbuffer *obj)
|
||||
{
|
||||
assert(obj);
|
||||
git__free(obj->data);
|
||||
obj->data = NULL;
|
||||
}
|
||||
|
||||
|
||||
int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode)
|
||||
{
|
||||
if (git_futils_mkpath2file(to, dirmode) < GIT_SUCCESS)
|
||||
|
@ -17,17 +17,8 @@
|
||||
*
|
||||
* Read whole files into an in-memory buffer for processing
|
||||
*/
|
||||
#define GIT_FBUFFER_INIT {NULL, 0}
|
||||
|
||||
typedef struct { /* file io buffer */
|
||||
void *data; /* data bytes */
|
||||
size_t len; /* data length */
|
||||
} git_fbuffer;
|
||||
|
||||
extern int git_futils_readbuffer(git_fbuffer *obj, const char *path);
|
||||
extern int git_futils_readbuffer_updated(git_fbuffer *obj, const char *path, time_t *mtime, int *updated);
|
||||
extern void git_futils_freebuffer(git_fbuffer *obj);
|
||||
extern void git_futils_fbuffer_rtrim(git_fbuffer *obj);
|
||||
extern int git_futils_readbuffer(git_buf *obj, const char *path);
|
||||
extern int git_futils_readbuffer_updated(git_buf *obj, const char *path, time_t *mtime, int *updated);
|
||||
|
||||
/**
|
||||
* File utils
|
||||
|
165
src/filter.c
Normal file
165
src/filter.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2012 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.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "fileops.h"
|
||||
#include "hash.h"
|
||||
#include "filter.h"
|
||||
#include "repository.h"
|
||||
#include "git2/config.h"
|
||||
|
||||
/* Tweaked from Core Git. I wonder what we could use this for... */
|
||||
void git_text_gather_stats(git_text_stats *stats, const git_buf *text)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
memset(stats, 0, sizeof(*stats));
|
||||
|
||||
for (i = 0; i < text->size; i++) {
|
||||
unsigned char c = text->ptr[i];
|
||||
|
||||
if (c == '\r') {
|
||||
stats->cr++;
|
||||
|
||||
if (i + 1 < text->size && text->ptr[i + 1] == '\n')
|
||||
stats->crlf++;
|
||||
}
|
||||
|
||||
else if (c == '\n')
|
||||
stats->lf++;
|
||||
|
||||
else if (c == 0x85)
|
||||
/* Unicode CR+LF */
|
||||
stats->crlf++;
|
||||
|
||||
else if (c == 127)
|
||||
/* DEL */
|
||||
stats->nonprintable++;
|
||||
|
||||
else if (c <= 0x1F || (c >= 0x80 && c <= 0x9F)) {
|
||||
switch (c) {
|
||||
/* BS, HT, ESC and FF */
|
||||
case '\b': case '\t': case '\033': case '\014':
|
||||
stats->printable++;
|
||||
break;
|
||||
case 0:
|
||||
stats->nul++;
|
||||
/* fall through */
|
||||
default:
|
||||
stats->nonprintable++;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
stats->printable++;
|
||||
}
|
||||
|
||||
/* If file ends with EOF then don't count this EOF as non-printable. */
|
||||
if (text->size >= 1 && text->ptr[text->size - 1] == '\032')
|
||||
stats->nonprintable--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fresh from Core Git
|
||||
*/
|
||||
int git_text_is_binary(git_text_stats *stats)
|
||||
{
|
||||
if (stats->nul)
|
||||
return 1;
|
||||
|
||||
if ((stats->printable >> 7) < stats->nonprintable)
|
||||
return 1;
|
||||
/*
|
||||
* Other heuristics? Average line length might be relevant,
|
||||
* as might LF vs CR vs CRLF counts..
|
||||
*
|
||||
* NOTE! It might be normal to have a low ratio of CRLF to LF
|
||||
* (somebody starts with a LF-only file and edits it with an editor
|
||||
* that adds CRLF only to lines that are added..). But do we
|
||||
* want to support CR-only? Probably not.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_filters_load(git_vector *filters, git_repository *repo, const char *path, int mode)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (mode == GIT_FILTER_TO_ODB) {
|
||||
/* Load the CRLF cleanup filter when writing to the ODB */
|
||||
error = git_filter_add__crlf_to_odb(filters, repo, path);
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
} else {
|
||||
return git__throw(GIT_ENOTIMPLEMENTED,
|
||||
"Worktree filters are not implemented yet");
|
||||
}
|
||||
|
||||
return (int)filters->length;
|
||||
}
|
||||
|
||||
void git_filters_free(git_vector *filters)
|
||||
{
|
||||
size_t i;
|
||||
git_filter *filter;
|
||||
|
||||
git_vector_foreach(filters, i, filter) {
|
||||
if (filter->do_free != NULL)
|
||||
filter->do_free(filter);
|
||||
else
|
||||
free(filter);
|
||||
}
|
||||
|
||||
git_vector_free(filters);
|
||||
}
|
||||
|
||||
int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters)
|
||||
{
|
||||
unsigned int i, src;
|
||||
git_buf *dbuffer[2];
|
||||
|
||||
dbuffer[0] = source;
|
||||
dbuffer[1] = dest;
|
||||
|
||||
src = 0;
|
||||
|
||||
if (source->size == 0) {
|
||||
git_buf_clear(dest);
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Pre-grow the destination buffer to more or less the size
|
||||
* we expect it to have */
|
||||
if (git_buf_grow(dest, source->size) < 0)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
for (i = 0; i < filters->length; ++i) {
|
||||
git_filter *filter = git_vector_get(filters, i);
|
||||
unsigned int dst = 1 - src;
|
||||
|
||||
git_buf_clear(dbuffer[dst]);
|
||||
|
||||
/* Apply the filter from dbuffer[src] to the other buffer;
|
||||
* if the filtering is canceled by the user mid-filter,
|
||||
* we skip to the next filter without changing the source
|
||||
* of the double buffering (so that the text goes through
|
||||
* cleanly).
|
||||
*/
|
||||
if (filter->apply(filter, dbuffer[dst], dbuffer[src]) == 0)
|
||||
src = dst;
|
||||
|
||||
if (git_buf_oom(dbuffer[dst]))
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
/* Ensure that the output ends up in dbuffer[1] (i.e. the dest) */
|
||||
if (src != 1)
|
||||
git_buf_swap(dest, source);
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
119
src/filter.h
Normal file
119
src/filter.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2012 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_filter_h__
|
||||
#define INCLUDE_filter_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "buffer.h"
|
||||
#include "git2/odb.h"
|
||||
#include "git2/repository.h"
|
||||
|
||||
typedef struct git_filter {
|
||||
int (*apply)(struct git_filter *self, git_buf *dest, const git_buf *source);
|
||||
void (*do_free)(struct git_filter *self);
|
||||
} git_filter;
|
||||
|
||||
typedef enum {
|
||||
GIT_FILTER_TO_WORKTREE,
|
||||
GIT_FILTER_TO_ODB
|
||||
} git_filter_mode;
|
||||
|
||||
typedef enum {
|
||||
GIT_CRLF_GUESS = -1,
|
||||
GIT_CRLF_BINARY = 0,
|
||||
GIT_CRLF_TEXT,
|
||||
GIT_CRLF_INPUT,
|
||||
GIT_CRLF_CRLF,
|
||||
GIT_CRLF_AUTO,
|
||||
} git_crlf_t;
|
||||
|
||||
typedef struct {
|
||||
/* NUL, CR, LF and CRLF counts */
|
||||
unsigned int nul, cr, lf, crlf;
|
||||
|
||||
/* These are just approximations! */
|
||||
unsigned int printable, nonprintable;
|
||||
} git_text_stats;
|
||||
|
||||
/*
|
||||
* FILTER API
|
||||
*/
|
||||
|
||||
/*
|
||||
* For any given path in the working directory, fill the `filters`
|
||||
* array with the relevant filters that need to be applied.
|
||||
*
|
||||
* Mode is either `GIT_FILTER_TO_WORKTREE` if you need to load the
|
||||
* filters that will be used when checking out a file to the working
|
||||
* directory, or `GIT_FILTER_TO_ODB` for the filters used when writing
|
||||
* a file to the ODB.
|
||||
*
|
||||
* @param filters Vector where to store all the loaded filters
|
||||
* @param repo Repository object that contains `path`
|
||||
* @param path Relative path of the file to be filtered
|
||||
* @param mode Filtering direction (WT->ODB or ODB->WT)
|
||||
* @return the number of filters loaded for the file (0 if the file
|
||||
* doesn't need filtering), or a negative error code
|
||||
*/
|
||||
extern int git_filters_load(git_vector *filters, git_repository *repo, const char *path, int mode);
|
||||
|
||||
/*
|
||||
* Apply one or more filters to a file.
|
||||
*
|
||||
* The file must have been loaded as a `git_buf` object. Both the `source`
|
||||
* and `dest` buffers are owned by the caller and must be freed once
|
||||
* they are no longer needed.
|
||||
*
|
||||
* NOTE: Because of the double-buffering schema, the `source` buffer that contains
|
||||
* the original file may be tampered once the filtering is complete. Regardless,
|
||||
* the `dest` buffer will always contain the final result of the filtering
|
||||
*
|
||||
* @param dest Buffer to store the result of the filtering
|
||||
* @param source Buffer containing the document to filter
|
||||
* @param filters A non-empty vector of filters as supplied by `git_filters_load`
|
||||
* @return GIT_SUCCESS on success, an error code otherwise
|
||||
*/
|
||||
extern int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters);
|
||||
|
||||
/*
|
||||
* Free the `filters` array generated by `git_filters_load`.
|
||||
*
|
||||
* Note that this frees both the array and its contents. The array will
|
||||
* be clean/reusable after this call.
|
||||
*
|
||||
* @param filters A filters array as supplied by `git_filters_load`
|
||||
*/
|
||||
extern void git_filters_free(git_vector *filters);
|
||||
|
||||
/*
|
||||
* Available filters
|
||||
*/
|
||||
|
||||
/* Strip CRLF, from Worktree to ODB */
|
||||
extern int git_filter_add__crlf_to_odb(git_vector *filters, git_repository *repo, const char *path);
|
||||
|
||||
|
||||
/*
|
||||
* PLAINTEXT API
|
||||
*/
|
||||
|
||||
/*
|
||||
* Gather stats for a piece of text
|
||||
*
|
||||
* Fill the `stats` structure with information on the number of
|
||||
* unreadable characters, carriage returns, etc, so it can be
|
||||
* used in heuristics.
|
||||
*/
|
||||
extern void git_text_gather_stats(git_text_stats *stats, const git_buf *text);
|
||||
|
||||
/*
|
||||
* Process `git_text_stats` data generated by `git_text_stat` to see
|
||||
* if it qualifies as a binary file
|
||||
*/
|
||||
extern int git_text_is_binary(git_text_stats *stats);
|
||||
|
||||
#endif
|
@ -11,7 +11,7 @@ static int load_ignore_file(
|
||||
git_repository *repo, const char *path, git_attr_file *ignores)
|
||||
{
|
||||
int error = GIT_SUCCESS;
|
||||
git_fbuffer fbuf = GIT_FBUFFER_INIT;
|
||||
git_buf fbuf = GIT_BUF_INIT;
|
||||
git_attr_fnmatch *match = NULL;
|
||||
const char *scan = NULL;
|
||||
char *context = NULL;
|
||||
@ -28,7 +28,7 @@ static int load_ignore_file(
|
||||
if (error == GIT_SUCCESS)
|
||||
error = git_futils_readbuffer(&fbuf, path);
|
||||
|
||||
scan = fbuf.data;
|
||||
scan = fbuf.ptr;
|
||||
|
||||
while (error == GIT_SUCCESS && *scan) {
|
||||
if (!match && !(match = git__calloc(1, sizeof(git_attr_fnmatch)))) {
|
||||
@ -53,7 +53,7 @@ static int load_ignore_file(
|
||||
}
|
||||
}
|
||||
|
||||
git_futils_freebuffer(&fbuf);
|
||||
git_buf_free(&fbuf);
|
||||
git__free(match);
|
||||
git__free(context);
|
||||
|
||||
|
@ -216,7 +216,7 @@ void git_index_clear(git_index *index)
|
||||
int git_index_read(git_index *index)
|
||||
{
|
||||
int error = GIT_SUCCESS, updated;
|
||||
git_fbuffer buffer = GIT_FBUFFER_INIT;
|
||||
git_buf buffer = GIT_BUF_INIT;
|
||||
time_t mtime;
|
||||
|
||||
assert(index->index_file_path);
|
||||
@ -235,12 +235,12 @@ int git_index_read(git_index *index)
|
||||
|
||||
if (updated) {
|
||||
git_index_clear(index);
|
||||
error = parse_index(index, buffer.data, buffer.len);
|
||||
error = parse_index(index, buffer.ptr, buffer.size);
|
||||
|
||||
if (error == GIT_SUCCESS)
|
||||
index->last_modified = mtime;
|
||||
|
||||
git_futils_freebuffer(&buffer);
|
||||
git_buf_free(&buffer);
|
||||
}
|
||||
|
||||
if (error < GIT_SUCCESS)
|
||||
|
@ -393,8 +393,8 @@ static int add_default_backends(git_odb *db, const char *objects_dir, int as_alt
|
||||
static int load_alternates(git_odb *odb, const char *objects_dir)
|
||||
{
|
||||
git_buf alternates_path = GIT_BUF_INIT;
|
||||
git_buf alternates_buf = GIT_BUF_INIT;
|
||||
char *buffer;
|
||||
git_fbuffer alternates_buf = GIT_FBUFFER_INIT;
|
||||
const char *alternate;
|
||||
int error;
|
||||
|
||||
@ -412,7 +412,7 @@ static int load_alternates(git_odb *odb, const char *objects_dir)
|
||||
return git__throw(GIT_EOSERR, "Failed to add backend. Can't read alternates");
|
||||
}
|
||||
|
||||
buffer = (char *)alternates_buf.data;
|
||||
buffer = (char *)alternates_buf.ptr;
|
||||
error = GIT_SUCCESS;
|
||||
|
||||
/* add each alternate as a new backend; one alternate per line */
|
||||
@ -433,7 +433,8 @@ static int load_alternates(git_odb *odb, const char *objects_dir)
|
||||
}
|
||||
|
||||
git_buf_free(&alternates_path);
|
||||
git_futils_freebuffer(&alternates_buf);
|
||||
git_buf_free(&alternates_buf);
|
||||
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to load alternates");
|
||||
return error;
|
||||
|
@ -75,13 +75,13 @@ static int object_file_name(git_buf *name, const char *dir, const git_oid *id)
|
||||
}
|
||||
|
||||
|
||||
static size_t get_binary_object_header(obj_hdr *hdr, git_fbuffer *obj)
|
||||
static size_t get_binary_object_header(obj_hdr *hdr, git_buf *obj)
|
||||
{
|
||||
unsigned char c;
|
||||
unsigned char *data = obj->data;
|
||||
unsigned char *data = (unsigned char *)obj->ptr;
|
||||
size_t shift, size, used = 0;
|
||||
|
||||
if (obj->len == 0)
|
||||
if (obj->size == 0)
|
||||
return 0;
|
||||
|
||||
c = data[used++];
|
||||
@ -90,7 +90,7 @@ static size_t get_binary_object_header(obj_hdr *hdr, git_fbuffer *obj)
|
||||
size = c & 15;
|
||||
shift = 4;
|
||||
while (c & 0x80) {
|
||||
if (obj->len <= used)
|
||||
if (obj->size <= used)
|
||||
return 0;
|
||||
if (sizeof(size_t) * 8 <= shift)
|
||||
return 0;
|
||||
@ -177,12 +177,12 @@ static void set_stream_output(z_stream *s, void *out, size_t len)
|
||||
}
|
||||
|
||||
|
||||
static int start_inflate(z_stream *s, git_fbuffer *obj, void *out, size_t len)
|
||||
static int start_inflate(z_stream *s, git_buf *obj, void *out, size_t len)
|
||||
{
|
||||
int status;
|
||||
|
||||
init_stream(s, out, len);
|
||||
set_stream_input(s, obj->data, obj->len);
|
||||
set_stream_input(s, obj->ptr, obj->size);
|
||||
|
||||
if ((status = inflateInit(s)) < Z_OK)
|
||||
return status;
|
||||
@ -287,7 +287,7 @@ static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)
|
||||
* of loose object data into packs. This format is no longer used, but
|
||||
* we must still read it.
|
||||
*/
|
||||
static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_fbuffer *obj)
|
||||
static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj)
|
||||
{
|
||||
unsigned char *in, *buf;
|
||||
obj_hdr hdr;
|
||||
@ -310,8 +310,8 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_fbuffer *obj)
|
||||
if (!buf)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
in = ((unsigned char *)obj->data) + used;
|
||||
len = obj->len - used;
|
||||
in = ((unsigned char *)obj->ptr) + used;
|
||||
len = obj->size - used;
|
||||
if (inflate_buffer(in, len, buf, hdr.size)) {
|
||||
git__free(buf);
|
||||
return git__throw(GIT_ERROR, "Failed to inflate loose object. Could not inflate buffer");
|
||||
@ -325,7 +325,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_fbuffer *obj)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int inflate_disk_obj(git_rawobj *out, git_fbuffer *obj)
|
||||
static int inflate_disk_obj(git_rawobj *out, git_buf *obj)
|
||||
{
|
||||
unsigned char head[64], *buf;
|
||||
z_stream zs;
|
||||
@ -335,7 +335,7 @@ static int inflate_disk_obj(git_rawobj *out, git_fbuffer *obj)
|
||||
/*
|
||||
* check for a pack-like loose object
|
||||
*/
|
||||
if (!is_zlib_compressed_data(obj->data))
|
||||
if (!is_zlib_compressed_data((unsigned char *)obj->ptr))
|
||||
return inflate_packlike_loose_disk_obj(out, obj);
|
||||
|
||||
/*
|
||||
@ -383,7 +383,7 @@ static int inflate_disk_obj(git_rawobj *out, git_fbuffer *obj)
|
||||
static int read_loose(git_rawobj *out, git_buf *loc)
|
||||
{
|
||||
int error;
|
||||
git_fbuffer obj = GIT_FBUFFER_INIT;
|
||||
git_buf obj = GIT_BUF_INIT;
|
||||
|
||||
assert(out && loc);
|
||||
|
||||
@ -398,7 +398,7 @@ static int read_loose(git_rawobj *out, git_buf *loc)
|
||||
return git__throw(GIT_ENOTFOUND, "Failed to read loose object. File not found");
|
||||
|
||||
error = inflate_disk_obj(out, &obj);
|
||||
git_futils_freebuffer(&obj);
|
||||
git_buf_free(&obj);
|
||||
|
||||
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to read loose object");
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ int git_reflog_read(git_reflog **reflog, git_reference *ref)
|
||||
{
|
||||
int error;
|
||||
git_buf log_path = GIT_BUF_INIT;
|
||||
git_fbuffer log_file = GIT_FBUFFER_INIT;
|
||||
git_buf log_file = GIT_BUF_INIT;
|
||||
git_reflog *log = NULL;
|
||||
|
||||
*reflog = NULL;
|
||||
@ -201,7 +201,7 @@ int git_reflog_read(git_reflog **reflog, git_reference *ref)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((error = reflog_parse(log, log_file.data, log_file.len)) < GIT_SUCCESS)
|
||||
if ((error = reflog_parse(log, log_file.ptr, log_file.size)) < GIT_SUCCESS)
|
||||
git__rethrow(error, "Failed to read reflog");
|
||||
else
|
||||
*reflog = log;
|
||||
@ -209,7 +209,7 @@ int git_reflog_read(git_reflog **reflog, git_reference *ref)
|
||||
cleanup:
|
||||
if (error != GIT_SUCCESS && log != NULL)
|
||||
git_reflog_free(log);
|
||||
git_futils_freebuffer(&log_file);
|
||||
git_buf_free(&log_file);
|
||||
git_buf_free(&log_path);
|
||||
|
||||
return error;
|
||||
|
48
src/refs.c
48
src/refs.c
@ -32,15 +32,15 @@ struct packref {
|
||||
static const int default_table_size = 32;
|
||||
|
||||
static int reference_read(
|
||||
git_fbuffer *file_content,
|
||||
git_buf *file_content,
|
||||
time_t *mtime,
|
||||
const char *repo_path,
|
||||
const char *ref_name,
|
||||
int *updated);
|
||||
|
||||
/* loose refs */
|
||||
static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content);
|
||||
static int loose_parse_oid(git_oid *ref, git_fbuffer *file_content);
|
||||
static int loose_parse_symbolic(git_reference *ref, git_buf *file_content);
|
||||
static int loose_parse_oid(git_oid *ref, git_buf *file_content);
|
||||
static int loose_lookup(git_reference *ref);
|
||||
static int loose_lookup_to_packfile(struct packref **ref_out,
|
||||
git_repository *repo, const char *name);
|
||||
@ -113,7 +113,7 @@ static int reference_alloc(
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int reference_read(git_fbuffer *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated)
|
||||
static int reference_read(git_buf *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated)
|
||||
{
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
int error = GIT_SUCCESS;
|
||||
@ -129,15 +129,15 @@ static int reference_read(git_fbuffer *file_content, time_t *mtime, const char *
|
||||
return error;
|
||||
}
|
||||
|
||||
static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content)
|
||||
static int loose_parse_symbolic(git_reference *ref, git_buf *file_content)
|
||||
{
|
||||
const unsigned int header_len = strlen(GIT_SYMREF);
|
||||
const char *refname_start;
|
||||
char *eol;
|
||||
|
||||
refname_start = (const char *)file_content->data;
|
||||
refname_start = (const char *)file_content->ptr;
|
||||
|
||||
if (file_content->len < (header_len + 1))
|
||||
if (file_content->size < (header_len + 1))
|
||||
return git__throw(GIT_EOBJCORRUPTED,
|
||||
"Failed to parse loose reference. Object too short");
|
||||
|
||||
@ -165,15 +165,15 @@ static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int loose_parse_oid(git_oid *oid, git_fbuffer *file_content)
|
||||
static int loose_parse_oid(git_oid *oid, git_buf *file_content)
|
||||
{
|
||||
int error;
|
||||
char *buffer;
|
||||
|
||||
buffer = (char *)file_content->data;
|
||||
buffer = (char *)file_content->ptr;
|
||||
|
||||
/* File format: 40 chars (OID) + newline */
|
||||
if (file_content->len < GIT_OID_HEXSZ + 1)
|
||||
if (file_content->size < GIT_OID_HEXSZ + 1)
|
||||
return git__throw(GIT_EOBJCORRUPTED,
|
||||
"Failed to parse loose reference. Reference too short");
|
||||
|
||||
@ -193,26 +193,26 @@ static int loose_parse_oid(git_oid *oid, git_fbuffer *file_content)
|
||||
|
||||
static git_rtype loose_guess_rtype(const git_buf *full_path)
|
||||
{
|
||||
git_fbuffer ref_file = GIT_FBUFFER_INIT;
|
||||
git_buf ref_file = GIT_BUF_INIT;
|
||||
git_rtype type;
|
||||
|
||||
type = GIT_REF_INVALID;
|
||||
|
||||
if (git_futils_readbuffer(&ref_file, full_path->ptr) == GIT_SUCCESS) {
|
||||
if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0)
|
||||
if (git__prefixcmp((const char *)(ref_file.ptr), GIT_SYMREF) == 0)
|
||||
type = GIT_REF_SYMBOLIC;
|
||||
else
|
||||
type = GIT_REF_OID;
|
||||
}
|
||||
|
||||
git_futils_freebuffer(&ref_file);
|
||||
git_buf_free(&ref_file);
|
||||
return type;
|
||||
}
|
||||
|
||||
static int loose_lookup(git_reference *ref)
|
||||
{
|
||||
int error = GIT_SUCCESS, updated;
|
||||
git_fbuffer ref_file = GIT_FBUFFER_INIT;
|
||||
git_buf ref_file = GIT_BUF_INIT;
|
||||
|
||||
if (reference_read(&ref_file, &ref->mtime,
|
||||
ref->owner->path_repository, ref->name, &updated) < GIT_SUCCESS)
|
||||
@ -228,7 +228,7 @@ static int loose_lookup(git_reference *ref)
|
||||
|
||||
ref->flags = 0;
|
||||
|
||||
if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) {
|
||||
if (git__prefixcmp((const char *)(ref_file.ptr), GIT_SYMREF) == 0) {
|
||||
ref->flags |= GIT_REF_SYMBOLIC;
|
||||
error = loose_parse_symbolic(ref, &ref_file);
|
||||
} else {
|
||||
@ -236,7 +236,7 @@ static int loose_lookup(git_reference *ref)
|
||||
error = loose_parse_oid(&ref->target.oid, &ref_file);
|
||||
}
|
||||
|
||||
git_futils_freebuffer(&ref_file);
|
||||
git_buf_free(&ref_file);
|
||||
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to lookup loose reference");
|
||||
@ -250,7 +250,7 @@ static int loose_lookup_to_packfile(
|
||||
const char *name)
|
||||
{
|
||||
int error = GIT_SUCCESS;
|
||||
git_fbuffer ref_file = GIT_FBUFFER_INIT;
|
||||
git_buf ref_file = GIT_BUF_INIT;
|
||||
struct packref *ref = NULL;
|
||||
size_t name_len;
|
||||
|
||||
@ -273,11 +273,11 @@ static int loose_lookup_to_packfile(
|
||||
ref->flags = GIT_PACKREF_WAS_LOOSE;
|
||||
|
||||
*ref_out = ref;
|
||||
git_futils_freebuffer(&ref_file);
|
||||
git_buf_free(&ref_file);
|
||||
return GIT_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
git_futils_freebuffer(&ref_file);
|
||||
git_buf_free(&ref_file);
|
||||
free(ref);
|
||||
return git__rethrow(error, "Failed to lookup loose reference");
|
||||
}
|
||||
@ -427,7 +427,7 @@ cleanup:
|
||||
static int packed_load(git_repository *repo)
|
||||
{
|
||||
int error = GIT_SUCCESS, updated;
|
||||
git_fbuffer packfile = GIT_FBUFFER_INIT;
|
||||
git_buf packfile = GIT_BUF_INIT;
|
||||
const char *buffer_start, *buffer_end;
|
||||
git_refcache *ref_cache = &repo->references;
|
||||
|
||||
@ -468,8 +468,8 @@ static int packed_load(git_repository *repo)
|
||||
|
||||
git_hashtable_clear(ref_cache->packfile);
|
||||
|
||||
buffer_start = (const char *)packfile.data;
|
||||
buffer_end = (const char *)(buffer_start) + packfile.len;
|
||||
buffer_start = (const char *)packfile.ptr;
|
||||
buffer_end = (const char *)(buffer_start) + packfile.size;
|
||||
|
||||
while (buffer_start < buffer_end && buffer_start[0] == '#') {
|
||||
buffer_start = strchr(buffer_start, '\n');
|
||||
@ -500,13 +500,13 @@ static int packed_load(git_repository *repo)
|
||||
}
|
||||
}
|
||||
|
||||
git_futils_freebuffer(&packfile);
|
||||
git_buf_free(&packfile);
|
||||
return GIT_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
git_hashtable_free(ref_cache->packfile);
|
||||
ref_cache->packfile = NULL;
|
||||
git_futils_freebuffer(&packfile);
|
||||
git_buf_free(&packfile);
|
||||
return git__rethrow(error, "Failed to load packed references");
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,8 @@ static void drop_config(git_repository *repo)
|
||||
git_config_free(repo->_config);
|
||||
repo->_config = NULL;
|
||||
}
|
||||
|
||||
git_repository__cvar_cache_clear(repo);
|
||||
}
|
||||
|
||||
static void drop_index(git_repository *repo)
|
||||
@ -111,6 +113,9 @@ static git_repository *repository_alloc(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set all the entries in the cvar cache to `unset` */
|
||||
git_repository__cvar_cache_clear(repo);
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
@ -467,7 +472,7 @@ static int retrieve_ceiling_directories_offset(
|
||||
*/
|
||||
static int read_gitfile(git_buf *path_out, const char *file_path, const char *base_path)
|
||||
{
|
||||
git_fbuffer file;
|
||||
git_buf file = GIT_BUF_INIT;
|
||||
int error;
|
||||
|
||||
assert(path_out && file_path);
|
||||
@ -476,22 +481,22 @@ static int read_gitfile(git_buf *path_out, const char *file_path, const char *ba
|
||||
if (error < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
if (git__prefixcmp((char *)file.data, GIT_FILE_CONTENT_PREFIX)) {
|
||||
git_futils_freebuffer(&file);
|
||||
if (git__prefixcmp((char *)file.ptr, GIT_FILE_CONTENT_PREFIX)) {
|
||||
git_buf_free(&file);
|
||||
return git__throw(GIT_ENOTFOUND, "Invalid gitfile format `%s`", file_path);
|
||||
}
|
||||
|
||||
git_futils_fbuffer_rtrim(&file);
|
||||
git_buf_rtrim(&file);
|
||||
|
||||
if (strlen(GIT_FILE_CONTENT_PREFIX) == file.len) {
|
||||
git_futils_freebuffer(&file);
|
||||
if (strlen(GIT_FILE_CONTENT_PREFIX) == file.size) {
|
||||
git_buf_free(&file);
|
||||
return git__throw(GIT_ENOTFOUND, "No path in git file `%s`", file_path);
|
||||
}
|
||||
|
||||
error = git_path_prettify_dir(path_out,
|
||||
((char *)file.data) + strlen(GIT_FILE_CONTENT_PREFIX), base_path);
|
||||
((char *)file.ptr) + strlen(GIT_FILE_CONTENT_PREFIX), base_path);
|
||||
|
||||
git_futils_freebuffer(&file);
|
||||
git_buf_free(&file);
|
||||
|
||||
if (error == GIT_SUCCESS && git_path_exists(path_out->ptr) == 0)
|
||||
return GIT_SUCCESS;
|
||||
|
@ -26,6 +26,49 @@
|
||||
#define GIT_DIR_MODE 0755
|
||||
#define GIT_BARE_DIR_MODE 0777
|
||||
|
||||
/** Cvar cache identifiers */
|
||||
typedef enum {
|
||||
GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */
|
||||
GIT_CVAR_EOL, /* core.eol */
|
||||
GIT_CVAR_CACHE_MAX
|
||||
} git_cvar_cached;
|
||||
|
||||
/**
|
||||
* CVAR value enumerations
|
||||
*
|
||||
* These are the values that are actually stored in the cvar cache, instead
|
||||
* of their string equivalents. These values are internal and symbolic;
|
||||
* make sure that none of them is set to `-1`, since that is the unique
|
||||
* identifier for "not cached"
|
||||
*/
|
||||
typedef enum {
|
||||
/* The value hasn't been loaded from the cache yet */
|
||||
GIT_CVAR_NOT_CACHED = -1,
|
||||
|
||||
/* core.safecrlf: false, 'fail', 'warn' */
|
||||
GIT_SAFE_CRLF_FALSE = 0,
|
||||
GIT_SAFE_CRLF_FAIL = 1,
|
||||
GIT_SAFE_CRLF_WARN = 2,
|
||||
|
||||
/* core.autocrlf: false, true, 'input; */
|
||||
GIT_AUTO_CRLF_FALSE = 0,
|
||||
GIT_AUTO_CRLF_TRUE = 1,
|
||||
GIT_AUTO_CRLF_INPUT = 2,
|
||||
GIT_AUTO_CRLF_DEFAULT = GIT_AUTO_CRLF_FALSE,
|
||||
|
||||
/* core.eol: unset, 'crlf', 'lf', 'native' */
|
||||
GIT_EOL_UNSET = 0,
|
||||
GIT_EOL_CRLF = 1,
|
||||
GIT_EOL_LF = 2,
|
||||
#ifdef GIT_WIN32
|
||||
GIT_EOL_NATIVE = GIT_EOL_CRLF,
|
||||
#else
|
||||
GIT_EOL_NATIVE = GIT_EOL_LF,
|
||||
#endif
|
||||
GIT_EOL_DEFAULT = GIT_EOL_NATIVE
|
||||
} git_cvar_value;
|
||||
|
||||
/** Base git object for inheritance */
|
||||
struct git_object {
|
||||
git_cached_obj cached;
|
||||
git_repository *repo;
|
||||
@ -46,6 +89,8 @@ struct git_repository {
|
||||
|
||||
unsigned is_bare:1;
|
||||
unsigned int lru_counter;
|
||||
|
||||
git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX];
|
||||
};
|
||||
|
||||
/* fully free the object; internal method, do not
|
||||
@ -55,8 +100,24 @@ void git_object__free(void *object);
|
||||
int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header);
|
||||
void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid);
|
||||
|
||||
/*
|
||||
* Weak pointers to repository internals.
|
||||
*
|
||||
* The returned pointers do not need to be freed. Do not keep
|
||||
* permanent references to these (i.e. between API calls), since they may
|
||||
* become invalidated if the user replaces a repository internal.
|
||||
*/
|
||||
int git_repository_config__weakptr(git_config **out, git_repository *repo);
|
||||
int git_repository_odb__weakptr(git_odb **out, git_repository *repo);
|
||||
int git_repository_index__weakptr(git_index **out, git_repository *repo);
|
||||
|
||||
/*
|
||||
* CVAR cache
|
||||
*
|
||||
* Efficient access to the most used config variables of a repository.
|
||||
* The cache is cleared everytime the config backend is replaced.
|
||||
*/
|
||||
int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar);
|
||||
void git_repository__cvar_cache_clear(git_repository *repo);
|
||||
|
||||
#endif
|
||||
|
42
tests-clar/attr/attr_expect.h
Normal file
42
tests-clar/attr/attr_expect.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef __CLAR_TEST_ATTR_EXPECT__
|
||||
#define __CLAR_TEST_ATTR_EXPECT__
|
||||
|
||||
enum attr_expect_t {
|
||||
EXPECT_FALSE,
|
||||
EXPECT_TRUE,
|
||||
EXPECT_UNDEFINED,
|
||||
EXPECT_STRING
|
||||
};
|
||||
|
||||
struct attr_expected {
|
||||
const char *path;
|
||||
const char *attr;
|
||||
enum attr_expect_t expected;
|
||||
const char *expected_str;
|
||||
};
|
||||
|
||||
static inline void attr_check_expected(
|
||||
enum attr_expect_t expected,
|
||||
const char *expected_str,
|
||||
const char *value)
|
||||
{
|
||||
switch (expected) {
|
||||
case EXPECT_TRUE:
|
||||
cl_assert(GIT_ATTR_TRUE(value));
|
||||
break;
|
||||
|
||||
case EXPECT_FALSE:
|
||||
cl_assert(GIT_ATTR_FALSE(value));
|
||||
break;
|
||||
|
||||
case EXPECT_UNDEFINED:
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(value));
|
||||
break;
|
||||
|
||||
case EXPECT_STRING:
|
||||
cl_assert_strequal(expected_str, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,5 +1,6 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "attr_file.h"
|
||||
#include "attr_expect.h"
|
||||
|
||||
#define get_rule(X) ((git_attr_rule *)git_vector_get(&file->rules,(X)))
|
||||
#define get_assign(R,Y) ((git_attr_assignment *)git_vector_get(&(R)->assigns,(Y)))
|
||||
@ -25,7 +26,7 @@ void test_attr_file__simple_read(void)
|
||||
assign = get_assign(rule, 0);
|
||||
cl_assert(assign != NULL);
|
||||
cl_assert_strequal("binary", assign->name);
|
||||
cl_assert(assign->value == GIT_ATTR_TRUE);
|
||||
cl_assert(GIT_ATTR_TRUE(assign->value));
|
||||
cl_assert(!assign->is_allocated);
|
||||
|
||||
git_attr_file__free(file);
|
||||
@ -54,7 +55,7 @@ void test_attr_file__match_variants(void)
|
||||
assign = get_assign(rule,0);
|
||||
cl_assert_strequal("attr0", assign->name);
|
||||
cl_assert(assign->name_hash == git_attr_file__name_hash(assign->name));
|
||||
cl_assert(assign->value == GIT_ATTR_TRUE);
|
||||
cl_assert(GIT_ATTR_TRUE(assign->value));
|
||||
cl_assert(!assign->is_allocated);
|
||||
|
||||
rule = get_rule(1);
|
||||
@ -83,7 +84,7 @@ void test_attr_file__match_variants(void)
|
||||
cl_assert(rule->assigns.length == 1);
|
||||
assign = get_assign(rule,0);
|
||||
cl_assert_strequal("attr7", assign->name);
|
||||
cl_assert(assign->value == GIT_ATTR_TRUE);
|
||||
cl_assert(GIT_ATTR_TRUE(assign->value));
|
||||
|
||||
rule = get_rule(8);
|
||||
cl_assert_strequal("pat8 with spaces", rule->match.pattern);
|
||||
@ -102,8 +103,8 @@ static void check_one_assign(
|
||||
int assign_idx,
|
||||
const char *pattern,
|
||||
const char *name,
|
||||
const char *value,
|
||||
int is_allocated)
|
||||
enum attr_expect_t expected,
|
||||
const char *expected_str)
|
||||
{
|
||||
git_attr_rule *rule = get_rule(rule_idx);
|
||||
git_attr_assignment *assign = get_assign(rule, assign_idx);
|
||||
@ -112,11 +113,8 @@ static void check_one_assign(
|
||||
cl_assert(rule->assigns.length == 1);
|
||||
cl_assert_strequal(name, assign->name);
|
||||
cl_assert(assign->name_hash == git_attr_file__name_hash(assign->name));
|
||||
cl_assert(assign->is_allocated == is_allocated);
|
||||
if (is_allocated)
|
||||
cl_assert_strequal(value, assign->value);
|
||||
else
|
||||
cl_assert(assign->value == value);
|
||||
|
||||
attr_check_expected(expected, expected_str, assign->value);
|
||||
}
|
||||
|
||||
void test_attr_file__assign_variants(void)
|
||||
@ -130,14 +128,14 @@ void test_attr_file__assign_variants(void)
|
||||
cl_assert_strequal(cl_fixture("attr/attr2"), file->path);
|
||||
cl_assert(file->rules.length == 11);
|
||||
|
||||
check_one_assign(file, 0, 0, "pat0", "simple", GIT_ATTR_TRUE, 0);
|
||||
check_one_assign(file, 1, 0, "pat1", "neg", GIT_ATTR_FALSE, 0);
|
||||
check_one_assign(file, 2, 0, "*", "notundef", GIT_ATTR_TRUE, 0);
|
||||
check_one_assign(file, 3, 0, "pat2", "notundef", NULL, 0);
|
||||
check_one_assign(file, 4, 0, "pat3", "assigned", "test-value", 1);
|
||||
check_one_assign(file, 5, 0, "pat4", "rule-with-more-chars", "value-with-more-chars", 1);
|
||||
check_one_assign(file, 6, 0, "pat5", "empty", GIT_ATTR_TRUE, 0);
|
||||
check_one_assign(file, 7, 0, "pat6", "negempty", GIT_ATTR_FALSE, 0);
|
||||
check_one_assign(file, 0, 0, "pat0", "simple", EXPECT_TRUE, NULL);
|
||||
check_one_assign(file, 1, 0, "pat1", "neg", EXPECT_FALSE, NULL);
|
||||
check_one_assign(file, 2, 0, "*", "notundef", EXPECT_TRUE, NULL);
|
||||
check_one_assign(file, 3, 0, "pat2", "notundef", EXPECT_UNDEFINED, NULL);
|
||||
check_one_assign(file, 4, 0, "pat3", "assigned", EXPECT_STRING, "test-value");
|
||||
check_one_assign(file, 5, 0, "pat4", "rule-with-more-chars", EXPECT_STRING, "value-with-more-chars");
|
||||
check_one_assign(file, 6, 0, "pat5", "empty", EXPECT_TRUE, NULL);
|
||||
check_one_assign(file, 7, 0, "pat6", "negempty", EXPECT_FALSE, NULL);
|
||||
|
||||
rule = get_rule(8);
|
||||
cl_assert_strequal("pat7", rule->match.pattern);
|
||||
@ -148,11 +146,11 @@ void test_attr_file__assign_variants(void)
|
||||
assign = git_attr_rule__lookup_assignment(rule, "multiple");
|
||||
cl_assert(assign);
|
||||
cl_assert_strequal("multiple", assign->name);
|
||||
cl_assert(assign->value == GIT_ATTR_TRUE);
|
||||
cl_assert(GIT_ATTR_TRUE(assign->value));
|
||||
assign = git_attr_rule__lookup_assignment(rule, "single");
|
||||
cl_assert(assign);
|
||||
cl_assert_strequal("single", assign->name);
|
||||
cl_assert(assign->value == GIT_ATTR_FALSE);
|
||||
cl_assert(GIT_ATTR_FALSE(assign->value));
|
||||
assign = git_attr_rule__lookup_assignment(rule, "values");
|
||||
cl_assert(assign);
|
||||
cl_assert_strequal("values", assign->name);
|
||||
@ -174,13 +172,13 @@ void test_attr_file__assign_variants(void)
|
||||
assign = git_attr_rule__lookup_assignment(rule, "again");
|
||||
cl_assert(assign);
|
||||
cl_assert_strequal("again", assign->name);
|
||||
cl_assert(assign->value == GIT_ATTR_TRUE);
|
||||
cl_assert(GIT_ATTR_TRUE(assign->value));
|
||||
assign = git_attr_rule__lookup_assignment(rule, "another");
|
||||
cl_assert(assign);
|
||||
cl_assert_strequal("another", assign->name);
|
||||
cl_assert_strequal("12321", assign->value);
|
||||
|
||||
check_one_assign(file, 10, 0, "pat9", "at-eof", GIT_ATTR_FALSE, 0);
|
||||
check_one_assign(file, 10, 0, "pat9", "at-eof", EXPECT_FALSE, NULL);
|
||||
|
||||
git_attr_file__free(file);
|
||||
}
|
||||
@ -204,10 +202,10 @@ void test_attr_file__check_attr_examples(void)
|
||||
cl_assert_strequal("java", assign->value);
|
||||
assign = git_attr_rule__lookup_assignment(rule, "crlf");
|
||||
cl_assert_strequal("crlf", assign->name);
|
||||
cl_assert(GIT_ATTR_FALSE == assign->value);
|
||||
cl_assert(GIT_ATTR_FALSE(assign->value));
|
||||
assign = git_attr_rule__lookup_assignment(rule, "myAttr");
|
||||
cl_assert_strequal("myAttr", assign->name);
|
||||
cl_assert(GIT_ATTR_TRUE == assign->value);
|
||||
cl_assert(GIT_ATTR_TRUE(assign->value));
|
||||
assign = git_attr_rule__lookup_assignment(rule, "missing");
|
||||
cl_assert(assign == NULL);
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "attr_file.h"
|
||||
|
||||
#include "attr_expect.h"
|
||||
|
||||
void test_attr_lookup__simple(void)
|
||||
{
|
||||
git_attr_file *file;
|
||||
@ -18,7 +20,7 @@ void test_attr_lookup__simple(void)
|
||||
cl_assert(!path.is_dir);
|
||||
|
||||
cl_git_pass(git_attr_file__lookup_one(file,&path,"binary",&value));
|
||||
cl_assert(value == GIT_ATTR_TRUE);
|
||||
cl_assert(GIT_ATTR_TRUE(value));
|
||||
|
||||
cl_git_pass(git_attr_file__lookup_one(file,&path,"missing",&value));
|
||||
cl_assert(!value);
|
||||
@ -26,36 +28,23 @@ void test_attr_lookup__simple(void)
|
||||
git_attr_file__free(file);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
const char *attr;
|
||||
const char *expected;
|
||||
int use_strcmp;
|
||||
int force_dir;
|
||||
} test_case;
|
||||
|
||||
static void run_test_cases(git_attr_file *file, test_case *cases)
|
||||
static void run_test_cases(git_attr_file *file, struct attr_expected *cases, int force_dir)
|
||||
{
|
||||
git_attr_path path;
|
||||
const char *value = NULL;
|
||||
test_case *c;
|
||||
struct attr_expected *c;
|
||||
int error;
|
||||
|
||||
for (c = cases; c->path != NULL; c++) {
|
||||
cl_git_pass(git_attr_path__init(&path, c->path, NULL));
|
||||
|
||||
if (c->force_dir)
|
||||
if (force_dir)
|
||||
path.is_dir = 1;
|
||||
|
||||
error = git_attr_file__lookup_one(file,&path,c->attr,&value);
|
||||
if (error != GIT_SUCCESS)
|
||||
fprintf(stderr, "failure with %s %s %s\n", c->path, c->attr, c->expected);
|
||||
cl_git_pass(error);
|
||||
|
||||
if (c->use_strcmp)
|
||||
cl_assert_strequal(c->expected, value);
|
||||
else
|
||||
cl_assert(c->expected == value);
|
||||
attr_check_expected(c->expected, c->expected_str, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,74 +52,79 @@ void test_attr_lookup__match_variants(void)
|
||||
{
|
||||
git_attr_file *file;
|
||||
git_attr_path path;
|
||||
test_case cases[] = {
|
||||
|
||||
struct attr_expected dir_cases[] = {
|
||||
{ "pat2", "attr2", EXPECT_TRUE, NULL },
|
||||
{ "/testing/for/pat2", "attr2", EXPECT_TRUE, NULL },
|
||||
{ "/not/pat2/yousee", "attr2", EXPECT_UNDEFINED, NULL },
|
||||
{ "/fun/fun/fun/pat4.dir", "attr4", EXPECT_TRUE, NULL },
|
||||
{ "foo.pat5", "attr5", EXPECT_TRUE, NULL },
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
struct attr_expected cases[] = {
|
||||
/* pat0 -> simple match */
|
||||
{ "pat0", "attr0", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "/testing/for/pat0", "attr0", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "relative/to/pat0", "attr0", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "this-contains-pat0-inside", "attr0", NULL, 0, 0 },
|
||||
{ "this-aint-right", "attr0", NULL, 0, 0 },
|
||||
{ "/this/pat0/dont/match", "attr0", NULL, 0, 0 },
|
||||
{ "pat0", "attr0", EXPECT_TRUE, NULL },
|
||||
{ "/testing/for/pat0", "attr0", EXPECT_TRUE, NULL },
|
||||
{ "relative/to/pat0", "attr0", EXPECT_TRUE, NULL },
|
||||
{ "this-contains-pat0-inside", "attr0", EXPECT_UNDEFINED, NULL },
|
||||
{ "this-aint-right", "attr0", EXPECT_UNDEFINED, NULL },
|
||||
{ "/this/pat0/dont/match", "attr0", EXPECT_UNDEFINED, NULL },
|
||||
/* negative match */
|
||||
{ "pat0", "attr1", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat1", "attr1", NULL, 0, 0 },
|
||||
{ "/testing/for/pat1", "attr1", NULL, 0, 0 },
|
||||
{ "/testing/for/pat0", "attr1", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "/testing/for/pat1/inside", "attr1", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "misc", "attr1", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat0", "attr1", EXPECT_TRUE, NULL },
|
||||
{ "pat1", "attr1", EXPECT_UNDEFINED, NULL },
|
||||
{ "/testing/for/pat1", "attr1", EXPECT_UNDEFINED, NULL },
|
||||
{ "/testing/for/pat0", "attr1", EXPECT_TRUE, NULL },
|
||||
{ "/testing/for/pat1/inside", "attr1", EXPECT_TRUE, NULL },
|
||||
{ "misc", "attr1", EXPECT_TRUE, NULL },
|
||||
/* dir match */
|
||||
{ "pat2", "attr2", NULL, 0, 0 },
|
||||
{ "pat2", "attr2", GIT_ATTR_TRUE, 0, 1 },
|
||||
{ "/testing/for/pat2", "attr2", NULL, 0, 0 },
|
||||
{ "/testing/for/pat2", "attr2", GIT_ATTR_TRUE, 0, 1 },
|
||||
{ "/not/pat2/yousee", "attr2", NULL, 0, 0 },
|
||||
{ "/not/pat2/yousee", "attr2", NULL, 0, 1 },
|
||||
{ "pat2", "attr2", EXPECT_UNDEFINED, NULL },
|
||||
{ "/testing/for/pat2", "attr2", EXPECT_UNDEFINED, NULL },
|
||||
{ "/not/pat2/yousee", "attr2", EXPECT_UNDEFINED, NULL },
|
||||
/* path match */
|
||||
{ "pat3file", "attr3", NULL, 0, 0 },
|
||||
{ "/pat3dir/pat3file", "attr3", NULL, 0, 0 },
|
||||
{ "pat3dir/pat3file", "attr3", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat3file", "attr3", EXPECT_UNDEFINED, NULL },
|
||||
{ "/pat3dir/pat3file", "attr3", EXPECT_UNDEFINED, NULL },
|
||||
{ "pat3dir/pat3file", "attr3", EXPECT_TRUE, NULL },
|
||||
/* pattern* match */
|
||||
{ "pat4.txt", "attr4", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "/fun/fun/fun/pat4.c", "attr4", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat4.", "attr4", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat4", "attr4", NULL, 0, 0 },
|
||||
{ "/fun/fun/fun/pat4.dir", "attr4", GIT_ATTR_TRUE, 0, 1 },
|
||||
{ "pat4.txt", "attr4", EXPECT_TRUE, NULL },
|
||||
{ "/fun/fun/fun/pat4.c", "attr4", EXPECT_TRUE, NULL },
|
||||
{ "pat4.", "attr4", EXPECT_TRUE, NULL },
|
||||
{ "pat4", "attr4", EXPECT_UNDEFINED, NULL },
|
||||
/* *pattern match */
|
||||
{ "foo.pat5", "attr5", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "foo.pat5", "attr5", GIT_ATTR_TRUE, 0, 1 },
|
||||
{ "/this/is/ok.pat5", "attr5", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "/this/is/bad.pat5/yousee.txt", "attr5", NULL, 0, 0 },
|
||||
{ "foo.pat5", "attr100", NULL, 0, 0 },
|
||||
{ "foo.pat5", "attr5", EXPECT_TRUE, NULL },
|
||||
{ "/this/is/ok.pat5", "attr5", EXPECT_TRUE, NULL },
|
||||
{ "/this/is/bad.pat5/yousee.txt", "attr5", EXPECT_UNDEFINED, NULL },
|
||||
{ "foo.pat5", "attr100", EXPECT_UNDEFINED, NULL },
|
||||
/* glob match with slashes */
|
||||
{ "foo.pat6", "attr6", NULL, 0, 0 },
|
||||
{ "pat6/pat6/foobar.pat6", "attr6", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat6/pat6/.pat6", "attr6", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat6/pat6/extra/foobar.pat6", "attr6", NULL, 0, 0 },
|
||||
{ "/prefix/pat6/pat6/foobar.pat6", "attr6", NULL, 0, 0 },
|
||||
{ "/pat6/pat6/foobar.pat6", "attr6", NULL, 0, 0 },
|
||||
{ "foo.pat6", "attr6", EXPECT_UNDEFINED, NULL },
|
||||
{ "pat6/pat6/foobar.pat6", "attr6", EXPECT_TRUE, NULL },
|
||||
{ "pat6/pat6/.pat6", "attr6", EXPECT_TRUE, NULL },
|
||||
{ "pat6/pat6/extra/foobar.pat6", "attr6", EXPECT_UNDEFINED, NULL },
|
||||
{ "/prefix/pat6/pat6/foobar.pat6", "attr6", EXPECT_UNDEFINED, NULL },
|
||||
{ "/pat6/pat6/foobar.pat6", "attr6", EXPECT_UNDEFINED, NULL },
|
||||
/* complex pattern */
|
||||
{ "pat7a12z", "attr7", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat7e__x", "attr7", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat7b/1y", "attr7", NULL, 0, 0 }, /* ? does not match / */
|
||||
{ "pat7e_x", "attr7", NULL, 0, 0 },
|
||||
{ "pat7aaaa", "attr7", NULL, 0, 0 },
|
||||
{ "pat7zzzz", "attr7", NULL, 0, 0 },
|
||||
{ "/this/can/be/anything/pat7a12z", "attr7", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "but/it/still/must/match/pat7aaaa", "attr7", NULL, 0, 0 },
|
||||
{ "pat7aaay.fail", "attr7", NULL, 0, 0 },
|
||||
{ "pat7a12z", "attr7", EXPECT_TRUE, NULL },
|
||||
{ "pat7e__x", "attr7", EXPECT_TRUE, NULL },
|
||||
{ "pat7b/1y", "attr7", EXPECT_UNDEFINED, NULL }, /* ? does not match / */
|
||||
{ "pat7e_x", "attr7", EXPECT_UNDEFINED, NULL },
|
||||
{ "pat7aaaa", "attr7", EXPECT_UNDEFINED, NULL },
|
||||
{ "pat7zzzz", "attr7", EXPECT_UNDEFINED, NULL },
|
||||
{ "/this/can/be/anything/pat7a12z", "attr7", EXPECT_TRUE, NULL },
|
||||
{ "but/it/still/must/match/pat7aaaa", "attr7", EXPECT_UNDEFINED, NULL },
|
||||
{ "pat7aaay.fail", "attr7", EXPECT_UNDEFINED, NULL },
|
||||
/* pattern with spaces */
|
||||
{ "pat8 with spaces", "attr8", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "/gotta love/pat8 with spaces", "attr8", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "failing pat8 with spaces", "attr8", NULL, 0, 0 },
|
||||
{ "spaces", "attr8", NULL, 0, 0 },
|
||||
{ "pat8 with spaces", "attr8", EXPECT_TRUE, NULL },
|
||||
{ "/gotta love/pat8 with spaces", "attr8", EXPECT_TRUE, NULL },
|
||||
{ "failing pat8 with spaces", "attr8", EXPECT_UNDEFINED, NULL },
|
||||
{ "spaces", "attr8", EXPECT_UNDEFINED, NULL },
|
||||
/* pattern at eof */
|
||||
{ "pat9", "attr9", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "/eof/pat9", "attr9", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat", "attr9", NULL, 0, 0 },
|
||||
{ "at9", "attr9", NULL, 0, 0 },
|
||||
{ "pat9.fail", "attr9", NULL, 0, 0 },
|
||||
{ "pat9", "attr9", EXPECT_TRUE, NULL },
|
||||
{ "/eof/pat9", "attr9", EXPECT_TRUE, NULL },
|
||||
{ "pat", "attr9", EXPECT_UNDEFINED, NULL },
|
||||
{ "at9", "attr9", EXPECT_UNDEFINED, NULL },
|
||||
{ "pat9.fail", "attr9", EXPECT_UNDEFINED, NULL },
|
||||
/* sentinel at end */
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
cl_git_pass(git_attr_file__new(&file));
|
||||
@ -141,7 +135,8 @@ void test_attr_lookup__match_variants(void)
|
||||
cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL));
|
||||
cl_assert_strequal("pat0", path.basename);
|
||||
|
||||
run_test_cases(file, cases);
|
||||
run_test_cases(file, cases, 0);
|
||||
run_test_cases(file, dir_cases, 1);
|
||||
|
||||
git_attr_file__free(file);
|
||||
}
|
||||
@ -149,54 +144,54 @@ void test_attr_lookup__match_variants(void)
|
||||
void test_attr_lookup__assign_variants(void)
|
||||
{
|
||||
git_attr_file *file;
|
||||
test_case cases[] = {
|
||||
struct attr_expected cases[] = {
|
||||
/* pat0 -> simple assign */
|
||||
{ "pat0", "simple", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "/testing/pat0", "simple", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat0", "fail", NULL, 0, 0 },
|
||||
{ "/testing/pat0", "fail", NULL, 0, 0 },
|
||||
{ "pat0", "simple", EXPECT_TRUE, NULL },
|
||||
{ "/testing/pat0", "simple", EXPECT_TRUE, NULL },
|
||||
{ "pat0", "fail", EXPECT_UNDEFINED, NULL },
|
||||
{ "/testing/pat0", "fail", EXPECT_UNDEFINED, NULL },
|
||||
/* negative assign */
|
||||
{ "pat1", "neg", GIT_ATTR_FALSE, 0, 0 },
|
||||
{ "/testing/pat1", "neg", GIT_ATTR_FALSE, 0, 0 },
|
||||
{ "pat1", "fail", NULL, 0, 0 },
|
||||
{ "/testing/pat1", "fail", NULL, 0, 0 },
|
||||
{ "pat1", "neg", EXPECT_FALSE, NULL },
|
||||
{ "/testing/pat1", "neg", EXPECT_FALSE, NULL },
|
||||
{ "pat1", "fail", EXPECT_UNDEFINED, NULL },
|
||||
{ "/testing/pat1", "fail", EXPECT_UNDEFINED, NULL },
|
||||
/* forced undef */
|
||||
{ "pat1", "notundef", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat2", "notundef", NULL, 0, 0 },
|
||||
{ "/lead/in/pat1", "notundef", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "/lead/in/pat2", "notundef", NULL, 0, 0 },
|
||||
{ "pat1", "notundef", EXPECT_TRUE, NULL },
|
||||
{ "pat2", "notundef", EXPECT_UNDEFINED, NULL },
|
||||
{ "/lead/in/pat1", "notundef", EXPECT_TRUE, NULL },
|
||||
{ "/lead/in/pat2", "notundef", EXPECT_UNDEFINED, NULL },
|
||||
/* assign value */
|
||||
{ "pat3", "assigned", "test-value", 1, 0 },
|
||||
{ "pat3", "notassigned", NULL, 0, 0 },
|
||||
{ "pat3", "assigned", EXPECT_STRING, "test-value" },
|
||||
{ "pat3", "notassigned", EXPECT_UNDEFINED, NULL },
|
||||
/* assign value */
|
||||
{ "pat4", "rule-with-more-chars", "value-with-more-chars", 1, 0 },
|
||||
{ "pat4", "notassigned-rule-with-more-chars", NULL, 0, 0 },
|
||||
{ "pat4", "rule-with-more-chars", EXPECT_STRING, "value-with-more-chars" },
|
||||
{ "pat4", "notassigned-rule-with-more-chars", EXPECT_UNDEFINED, NULL },
|
||||
/* empty assignments */
|
||||
{ "pat5", "empty", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat6", "negempty", GIT_ATTR_FALSE, 0, 0 },
|
||||
{ "pat5", "empty", EXPECT_TRUE, NULL },
|
||||
{ "pat6", "negempty", EXPECT_FALSE, NULL },
|
||||
/* multiple assignment */
|
||||
{ "pat7", "multiple", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat7", "single", GIT_ATTR_FALSE, 0, 0 },
|
||||
{ "pat7", "values", "1", 1, 0 },
|
||||
{ "pat7", "also", "a-really-long-value/*", 1, 0 },
|
||||
{ "pat7", "happy", "yes!", 1, 0 },
|
||||
{ "pat8", "again", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "pat8", "another", "12321", 1, 0 },
|
||||
{ "pat7", "multiple", EXPECT_TRUE, NULL },
|
||||
{ "pat7", "single", EXPECT_FALSE, NULL },
|
||||
{ "pat7", "values", EXPECT_STRING, "1" },
|
||||
{ "pat7", "also", EXPECT_STRING, "a-really-long-value/*" },
|
||||
{ "pat7", "happy", EXPECT_STRING, "yes!" },
|
||||
{ "pat8", "again", EXPECT_TRUE, NULL },
|
||||
{ "pat8", "another", EXPECT_STRING, "12321" },
|
||||
/* bad assignment */
|
||||
{ "patbad0", "simple", NULL, 0, 0 },
|
||||
{ "patbad0", "notundef", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "patbad1", "simple", NULL, 0, 0 },
|
||||
{ "patbad0", "simple", EXPECT_UNDEFINED, NULL },
|
||||
{ "patbad0", "notundef", EXPECT_TRUE, NULL },
|
||||
{ "patbad1", "simple", EXPECT_UNDEFINED, NULL },
|
||||
/* eof assignment */
|
||||
{ "pat9", "at-eof", GIT_ATTR_FALSE, 0, 0 },
|
||||
{ "pat9", "at-eof", EXPECT_FALSE, NULL },
|
||||
/* sentinel at end */
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
cl_git_pass(git_attr_file__new(&file));
|
||||
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr2"), file));
|
||||
cl_assert(file->rules.length == 11);
|
||||
|
||||
run_test_cases(file, cases);
|
||||
run_test_cases(file, cases, 0);
|
||||
|
||||
git_attr_file__free(file);
|
||||
}
|
||||
@ -204,34 +199,34 @@ void test_attr_lookup__assign_variants(void)
|
||||
void test_attr_lookup__check_attr_examples(void)
|
||||
{
|
||||
git_attr_file *file;
|
||||
test_case cases[] = {
|
||||
{ "foo.java", "diff", "java", 1, 0 },
|
||||
{ "foo.java", "crlf", GIT_ATTR_FALSE, 0, 0 },
|
||||
{ "foo.java", "myAttr", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "foo.java", "other", NULL, 0, 0 },
|
||||
{ "/prefix/dir/foo.java", "diff", "java", 1, 0 },
|
||||
{ "/prefix/dir/foo.java", "crlf", GIT_ATTR_FALSE, 0, 0 },
|
||||
{ "/prefix/dir/foo.java", "myAttr", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "/prefix/dir/foo.java", "other", NULL, 0, 0 },
|
||||
{ "NoMyAttr.java", "crlf", GIT_ATTR_FALSE, 0, 0 },
|
||||
{ "NoMyAttr.java", "myAttr", NULL, 0, 0 },
|
||||
{ "NoMyAttr.java", "other", NULL, 0, 0 },
|
||||
{ "/prefix/dir/NoMyAttr.java", "crlf", GIT_ATTR_FALSE, 0, 0 },
|
||||
{ "/prefix/dir/NoMyAttr.java", "myAttr", NULL, 0, 0 },
|
||||
{ "/prefix/dir/NoMyAttr.java", "other", NULL, 0, 0 },
|
||||
{ "README", "caveat", "unspecified", 1, 0 },
|
||||
{ "/specific/path/README", "caveat", "unspecified", 1, 0 },
|
||||
{ "README", "missing", NULL, 0, 0 },
|
||||
{ "/specific/path/README", "missing", NULL, 0, 0 },
|
||||
struct attr_expected cases[] = {
|
||||
{ "foo.java", "diff", EXPECT_STRING, "java" },
|
||||
{ "foo.java", "crlf", EXPECT_FALSE, NULL },
|
||||
{ "foo.java", "myAttr", EXPECT_TRUE, NULL },
|
||||
{ "foo.java", "other", EXPECT_UNDEFINED, NULL },
|
||||
{ "/prefix/dir/foo.java", "diff", EXPECT_STRING, "java" },
|
||||
{ "/prefix/dir/foo.java", "crlf", EXPECT_FALSE, NULL },
|
||||
{ "/prefix/dir/foo.java", "myAttr", EXPECT_TRUE, NULL },
|
||||
{ "/prefix/dir/foo.java", "other", EXPECT_UNDEFINED, NULL },
|
||||
{ "NoMyAttr.java", "crlf", EXPECT_FALSE, NULL },
|
||||
{ "NoMyAttr.java", "myAttr", EXPECT_UNDEFINED, NULL },
|
||||
{ "NoMyAttr.java", "other", EXPECT_UNDEFINED, NULL },
|
||||
{ "/prefix/dir/NoMyAttr.java", "crlf", EXPECT_FALSE, NULL },
|
||||
{ "/prefix/dir/NoMyAttr.java", "myAttr", EXPECT_UNDEFINED, NULL },
|
||||
{ "/prefix/dir/NoMyAttr.java", "other", EXPECT_UNDEFINED, NULL },
|
||||
{ "README", "caveat", EXPECT_STRING, "unspecified" },
|
||||
{ "/specific/path/README", "caveat", EXPECT_STRING, "unspecified" },
|
||||
{ "README", "missing", EXPECT_UNDEFINED, NULL },
|
||||
{ "/specific/path/README", "missing", EXPECT_UNDEFINED, NULL },
|
||||
/* sentinel at end */
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
cl_git_pass(git_attr_file__new(&file));
|
||||
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr3"), file));
|
||||
cl_assert(file->rules.length == 3);
|
||||
|
||||
run_test_cases(file, cases);
|
||||
run_test_cases(file, cases, 0);
|
||||
|
||||
git_attr_file__free(file);
|
||||
}
|
||||
@ -239,24 +234,24 @@ void test_attr_lookup__check_attr_examples(void)
|
||||
void test_attr_lookup__from_buffer(void)
|
||||
{
|
||||
git_attr_file *file;
|
||||
test_case cases[] = {
|
||||
{ "abc", "foo", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "abc", "bar", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "abc", "baz", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "aaa", "foo", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "aaa", "bar", NULL, 0, 0 },
|
||||
{ "aaa", "baz", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ "qqq", "foo", NULL, 0, 0 },
|
||||
{ "qqq", "bar", NULL, 0, 0 },
|
||||
{ "qqq", "baz", GIT_ATTR_TRUE, 0, 0 },
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
struct attr_expected cases[] = {
|
||||
{ "abc", "foo", EXPECT_TRUE, NULL },
|
||||
{ "abc", "bar", EXPECT_TRUE, NULL },
|
||||
{ "abc", "baz", EXPECT_TRUE, NULL },
|
||||
{ "aaa", "foo", EXPECT_TRUE, NULL },
|
||||
{ "aaa", "bar", EXPECT_UNDEFINED, NULL },
|
||||
{ "aaa", "baz", EXPECT_TRUE, NULL },
|
||||
{ "qqq", "foo", EXPECT_UNDEFINED, NULL },
|
||||
{ "qqq", "bar", EXPECT_UNDEFINED, NULL },
|
||||
{ "qqq", "baz", EXPECT_TRUE, NULL },
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
cl_git_pass(git_attr_file__new(&file));
|
||||
cl_git_pass(git_attr_file__from_buffer(NULL, "a* foo\nabc bar\n* baz", file));
|
||||
cl_assert(file->rules.length == 3);
|
||||
|
||||
run_test_cases(file, cases);
|
||||
run_test_cases(file, cases, 0);
|
||||
|
||||
git_attr_file__free(file);
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include "git2/attr.h"
|
||||
#include "attr.h"
|
||||
|
||||
#include "attr_expect.h"
|
||||
|
||||
static git_repository *g_repo = NULL;
|
||||
|
||||
void test_attr_repo__initialize(void)
|
||||
@ -28,67 +30,45 @@ void test_attr_repo__cleanup(void)
|
||||
void test_attr_repo__get_one(void)
|
||||
{
|
||||
const char *value;
|
||||
struct {
|
||||
const char *file;
|
||||
const char *attr;
|
||||
const char *expected;
|
||||
} test_cases[] = {
|
||||
{ "root_test1", "repoattr", GIT_ATTR_TRUE },
|
||||
{ "root_test1", "rootattr", GIT_ATTR_TRUE },
|
||||
{ "root_test1", "missingattr", NULL },
|
||||
{ "root_test1", "subattr", NULL },
|
||||
{ "root_test1", "negattr", NULL },
|
||||
{ "root_test2", "repoattr", GIT_ATTR_TRUE },
|
||||
{ "root_test2", "rootattr", GIT_ATTR_FALSE },
|
||||
{ "root_test2", "missingattr", NULL },
|
||||
{ "root_test2", "multiattr", GIT_ATTR_FALSE },
|
||||
{ "root_test3", "repoattr", GIT_ATTR_TRUE },
|
||||
{ "root_test3", "rootattr", NULL },
|
||||
{ "root_test3", "multiattr", "3" },
|
||||
{ "root_test3", "multi2", NULL },
|
||||
{ "sub/subdir_test1", "repoattr", GIT_ATTR_TRUE },
|
||||
{ "sub/subdir_test1", "rootattr", GIT_ATTR_TRUE },
|
||||
{ "sub/subdir_test1", "missingattr", NULL },
|
||||
{ "sub/subdir_test1", "subattr", "yes" },
|
||||
{ "sub/subdir_test1", "negattr", GIT_ATTR_FALSE },
|
||||
{ "sub/subdir_test1", "another", NULL },
|
||||
{ "sub/subdir_test2.txt", "repoattr", GIT_ATTR_TRUE },
|
||||
{ "sub/subdir_test2.txt", "rootattr", GIT_ATTR_TRUE },
|
||||
{ "sub/subdir_test2.txt", "missingattr", NULL },
|
||||
{ "sub/subdir_test2.txt", "subattr", "yes" },
|
||||
{ "sub/subdir_test2.txt", "negattr", GIT_ATTR_FALSE },
|
||||
{ "sub/subdir_test2.txt", "another", "zero" },
|
||||
{ "sub/subdir_test2.txt", "reposub", GIT_ATTR_TRUE },
|
||||
{ "sub/sub/subdir.txt", "another", "one" },
|
||||
{ "sub/sub/subdir.txt", "reposubsub", GIT_ATTR_TRUE },
|
||||
{ "sub/sub/subdir.txt", "reposub", NULL },
|
||||
{ "does-not-exist", "foo", "yes" },
|
||||
{ "sub/deep/file", "deepdeep", GIT_ATTR_TRUE },
|
||||
{ NULL, NULL, NULL }
|
||||
|
||||
struct attr_expected test_cases[] = {
|
||||
{ "root_test1", "repoattr", EXPECT_TRUE, NULL },
|
||||
{ "root_test1", "rootattr", EXPECT_TRUE, NULL },
|
||||
{ "root_test1", "missingattr", EXPECT_UNDEFINED, NULL },
|
||||
{ "root_test1", "subattr", EXPECT_UNDEFINED, NULL },
|
||||
{ "root_test1", "negattr", EXPECT_UNDEFINED, NULL },
|
||||
{ "root_test2", "repoattr", EXPECT_TRUE, NULL },
|
||||
{ "root_test2", "rootattr", EXPECT_FALSE, NULL },
|
||||
{ "root_test2", "missingattr", EXPECT_UNDEFINED, NULL },
|
||||
{ "root_test2", "multiattr", EXPECT_FALSE, NULL },
|
||||
{ "root_test3", "repoattr", EXPECT_TRUE, NULL },
|
||||
{ "root_test3", "rootattr", EXPECT_UNDEFINED, NULL },
|
||||
{ "root_test3", "multiattr", EXPECT_STRING, "3" },
|
||||
{ "root_test3", "multi2", EXPECT_UNDEFINED, NULL },
|
||||
{ "sub/subdir_test1", "repoattr", EXPECT_TRUE, NULL },
|
||||
{ "sub/subdir_test1", "rootattr", EXPECT_TRUE, NULL },
|
||||
{ "sub/subdir_test1", "missingattr", EXPECT_UNDEFINED, NULL },
|
||||
{ "sub/subdir_test1", "subattr", EXPECT_STRING, "yes" },
|
||||
{ "sub/subdir_test1", "negattr", EXPECT_FALSE, NULL },
|
||||
{ "sub/subdir_test1", "another", EXPECT_UNDEFINED, NULL },
|
||||
{ "sub/subdir_test2.txt", "repoattr", EXPECT_TRUE, NULL },
|
||||
{ "sub/subdir_test2.txt", "rootattr", EXPECT_TRUE, NULL },
|
||||
{ "sub/subdir_test2.txt", "missingattr", EXPECT_UNDEFINED, NULL },
|
||||
{ "sub/subdir_test2.txt", "subattr", EXPECT_STRING, "yes" },
|
||||
{ "sub/subdir_test2.txt", "negattr", EXPECT_FALSE, NULL },
|
||||
{ "sub/subdir_test2.txt", "another", EXPECT_STRING, "zero" },
|
||||
{ "sub/subdir_test2.txt", "reposub", EXPECT_TRUE, NULL },
|
||||
{ "sub/sub/subdir.txt", "another", EXPECT_STRING, "one" },
|
||||
{ "sub/sub/subdir.txt", "reposubsub", EXPECT_TRUE, NULL },
|
||||
{ "sub/sub/subdir.txt", "reposub", EXPECT_UNDEFINED, NULL },
|
||||
{ "does-not-exist", "foo", EXPECT_STRING, "yes" },
|
||||
{ "sub/deep/file", "deepdeep", EXPECT_TRUE, NULL },
|
||||
{ NULL, NULL, 0, NULL }
|
||||
}, *scan;
|
||||
|
||||
for (scan = test_cases; scan->file != NULL; scan++) {
|
||||
git_buf b = GIT_BUF_INIT;
|
||||
|
||||
git_buf_printf(&b, "%s:%s == expect %s",
|
||||
scan->file, scan->attr, scan->expected);
|
||||
|
||||
cl_must_pass_(
|
||||
git_attr_get(g_repo, scan->file, scan->attr, &value) == GIT_SUCCESS,
|
||||
b.ptr);
|
||||
|
||||
git_buf_printf(&b, ", got %s", value);
|
||||
|
||||
if (scan->expected == NULL ||
|
||||
scan->expected == GIT_ATTR_TRUE ||
|
||||
scan->expected == GIT_ATTR_FALSE)
|
||||
{
|
||||
cl_assert_(scan->expected == value, b.ptr);
|
||||
} else {
|
||||
cl_assert_strequal(scan->expected, value);
|
||||
}
|
||||
|
||||
git_buf_free(&b);
|
||||
for (scan = test_cases; scan->path != NULL; scan++) {
|
||||
cl_git_pass(git_attr_get(g_repo, scan->path, scan->attr, &value));
|
||||
attr_check_expected(scan->expected, scan->expected_str, value);
|
||||
}
|
||||
|
||||
cl_git_pass(git_attr_cache__is_cached(g_repo, ".git/info/attributes"));
|
||||
@ -103,25 +83,24 @@ void test_attr_repo__get_many(void)
|
||||
|
||||
cl_git_pass(git_attr_get_many(g_repo, "root_test1", 4, names, values));
|
||||
|
||||
cl_assert(values[0] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[1] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[2] == NULL);
|
||||
cl_assert(values[3] == NULL);
|
||||
cl_assert(GIT_ATTR_TRUE(values[0]));
|
||||
cl_assert(GIT_ATTR_TRUE(values[1]));
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
|
||||
|
||||
cl_git_pass(git_attr_get_many(g_repo, "root_test2", 4, names, values));
|
||||
|
||||
cl_assert(values[0] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[1] == GIT_ATTR_FALSE);
|
||||
cl_assert(values[2] == NULL);
|
||||
cl_assert(values[3] == NULL);
|
||||
cl_assert(GIT_ATTR_TRUE(values[0]));
|
||||
cl_assert(GIT_ATTR_FALSE(values[1]));
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
|
||||
|
||||
cl_git_pass(git_attr_get_many(g_repo, "sub/subdir_test1", 4, names, values));
|
||||
|
||||
cl_assert(values[0] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[1] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[2] == NULL);
|
||||
cl_assert(GIT_ATTR_TRUE(values[0]));
|
||||
cl_assert(GIT_ATTR_TRUE(values[1]));
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
|
||||
cl_assert_strequal("yes", values[3]);
|
||||
|
||||
}
|
||||
|
||||
static int count_attrs(
|
||||
@ -161,19 +140,19 @@ void test_attr_repo__manpage_example(void)
|
||||
const char *value;
|
||||
|
||||
cl_git_pass(git_attr_get(g_repo, "sub/abc", "foo", &value));
|
||||
cl_assert(value == GIT_ATTR_TRUE);
|
||||
cl_assert(GIT_ATTR_TRUE(value));
|
||||
|
||||
cl_git_pass(git_attr_get(g_repo, "sub/abc", "bar", &value));
|
||||
cl_assert(value == NULL);
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(value));
|
||||
|
||||
cl_git_pass(git_attr_get(g_repo, "sub/abc", "baz", &value));
|
||||
cl_assert(value == GIT_ATTR_FALSE);
|
||||
cl_assert(GIT_ATTR_FALSE(value));
|
||||
|
||||
cl_git_pass(git_attr_get(g_repo, "sub/abc", "merge", &value));
|
||||
cl_assert_strequal("filfre", value);
|
||||
|
||||
cl_git_pass(git_attr_get(g_repo, "sub/abc", "frotz", &value));
|
||||
cl_assert(value == NULL);
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(value));
|
||||
}
|
||||
|
||||
void test_attr_repo__macros(void)
|
||||
@ -185,24 +164,24 @@ void test_attr_repo__macros(void)
|
||||
|
||||
cl_git_pass(git_attr_get_many(g_repo, "binfile", 5, names, values));
|
||||
|
||||
cl_assert(values[0] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[1] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[2] == GIT_ATTR_FALSE);
|
||||
cl_assert(values[3] == GIT_ATTR_FALSE);
|
||||
cl_assert(values[4] == NULL);
|
||||
cl_assert(GIT_ATTR_TRUE(values[0]));
|
||||
cl_assert(GIT_ATTR_TRUE(values[1]));
|
||||
cl_assert(GIT_ATTR_FALSE(values[2]));
|
||||
cl_assert(GIT_ATTR_FALSE(values[3]));
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(values[4]));
|
||||
|
||||
cl_git_pass(git_attr_get_many(g_repo, "macro_test", 5, names2, values));
|
||||
|
||||
cl_assert(values[0] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[1] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[2] == GIT_ATTR_FALSE);
|
||||
cl_assert(values[3] == NULL);
|
||||
cl_assert(GIT_ATTR_TRUE(values[0]));
|
||||
cl_assert(GIT_ATTR_TRUE(values[1]));
|
||||
cl_assert(GIT_ATTR_FALSE(values[2]));
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
|
||||
cl_assert_strequal("77", values[4]);
|
||||
|
||||
cl_git_pass(git_attr_get_many(g_repo, "macro_test", 3, names3, values));
|
||||
|
||||
cl_assert(values[0] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[1] == GIT_ATTR_FALSE);
|
||||
cl_assert(GIT_ATTR_TRUE(values[0]));
|
||||
cl_assert(GIT_ATTR_FALSE(values[1]));
|
||||
cl_assert_strequal("answer", values[2]);
|
||||
}
|
||||
|
||||
@ -215,9 +194,9 @@ void test_attr_repo__bad_macros(void)
|
||||
cl_git_pass(git_attr_get_many(g_repo, "macro_bad", 6, names, values));
|
||||
|
||||
/* these three just confirm that the "mymacro" rule ran */
|
||||
cl_assert(values[0] == NULL);
|
||||
cl_assert(values[1] == GIT_ATTR_TRUE);
|
||||
cl_assert(values[2] == GIT_ATTR_FALSE);
|
||||
cl_assert(GIT_ATTR_UNSPECIFIED(values[0]));
|
||||
cl_assert(GIT_ATTR_TRUE(values[1]));
|
||||
cl_assert(GIT_ATTR_FALSE(values[2]));
|
||||
|
||||
/* file contains:
|
||||
* # let's try some malicious macro defs
|
||||
@ -241,7 +220,7 @@ void test_attr_repo__bad_macros(void)
|
||||
* so summary results should be:
|
||||
* -firstmacro secondmacro="hahaha" thirdmacro
|
||||
*/
|
||||
cl_assert(values[3] == GIT_ATTR_FALSE);
|
||||
cl_assert(GIT_ATTR_FALSE(values[3]));
|
||||
cl_assert_strequal("hahaha", values[4]);
|
||||
cl_assert(values[5] == GIT_ATTR_TRUE);
|
||||
cl_assert(GIT_ATTR_TRUE(values[5]));
|
||||
}
|
||||
|
@ -27,3 +27,15 @@ void cl_git_mkfile(const char *filename, const char *content)
|
||||
|
||||
cl_must_pass(p_close(fd));
|
||||
}
|
||||
|
||||
void cl_git_append2file(const char *filename, const char *new_content)
|
||||
{
|
||||
int fd = p_open(filename, O_WRONLY | O_APPEND | O_CREAT);
|
||||
cl_assert(fd != 0);
|
||||
if (!new_content)
|
||||
new_content = "\n";
|
||||
cl_must_pass(p_write(fd, new_content, strlen(new_content)));
|
||||
cl_must_pass(p_close(fd));
|
||||
cl_must_pass(p_chmod(filename, 0644));
|
||||
}
|
||||
|
||||
|
@ -53,5 +53,6 @@ GIT_INLINE(void) cl_assert_strequal_internal(
|
||||
|
||||
/* Write the contents of a buffer to disk */
|
||||
void cl_git_mkfile(const char *filename, const char *content);
|
||||
void cl_git_append2file(const char *filename, const char *new_content);
|
||||
|
||||
#endif
|
||||
|
@ -218,8 +218,8 @@ check_buf_append(
|
||||
const char* data_a,
|
||||
const char* data_b,
|
||||
const char* expected_data,
|
||||
ssize_t expected_size,
|
||||
ssize_t expected_asize)
|
||||
size_t expected_size,
|
||||
size_t expected_asize)
|
||||
{
|
||||
git_buf tgt = GIT_BUF_INIT;
|
||||
|
||||
@ -371,8 +371,8 @@ void test_core_buffer__7(void)
|
||||
git_buf_attach(&a, b, 0);
|
||||
|
||||
cl_assert_strequal(fun, a.ptr);
|
||||
cl_assert(a.size == (ssize_t)strlen(fun));
|
||||
cl_assert(a.asize == (ssize_t)strlen(fun) + 1);
|
||||
cl_assert(a.size == strlen(fun));
|
||||
cl_assert(a.asize == strlen(fun) + 1);
|
||||
|
||||
git_buf_free(&a);
|
||||
|
||||
@ -380,8 +380,8 @@ void test_core_buffer__7(void)
|
||||
git_buf_attach(&a, b, strlen(fun) + 1);
|
||||
|
||||
cl_assert_strequal(fun, a.ptr);
|
||||
cl_assert(a.size == (ssize_t)strlen(fun));
|
||||
cl_assert(a.asize == (ssize_t)strlen(fun) + 1);
|
||||
cl_assert(a.size == strlen(fun));
|
||||
cl_assert(a.asize == strlen(fun) + 1);
|
||||
|
||||
git_buf_free(&a);
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ void test_core_path__07_path_to_dir(void)
|
||||
void test_core_path__08_self_join(void)
|
||||
{
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
ssize_t asize = 0;
|
||||
size_t asize = 0;
|
||||
|
||||
asize = path.asize;
|
||||
cl_git_pass(git_buf_sets(&path, "/foo"));
|
||||
|
125
tests-clar/object/blob/filter.c
Normal file
125
tests-clar/object/blob/filter.c
Normal file
@ -0,0 +1,125 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "posix.h"
|
||||
#include "blob.h"
|
||||
#include "filter.h"
|
||||
|
||||
static git_repository *g_repo = NULL;
|
||||
#define NUM_TEST_OBJECTS 6
|
||||
static git_oid g_oids[NUM_TEST_OBJECTS];
|
||||
static const char *g_raw[NUM_TEST_OBJECTS] = {
|
||||
"",
|
||||
"foo\nbar\n",
|
||||
"foo\rbar\r",
|
||||
"foo\r\nbar\r\n",
|
||||
"foo\nbar\rboth\r\nreversed\n\ragain\nproblems\r",
|
||||
"123\n\000\001\002\003\004abc\255\254\253\r\n"
|
||||
};
|
||||
static int g_len[NUM_TEST_OBJECTS] = { -1, -1, -1, -1, -1, 17 };
|
||||
static git_text_stats g_stats[NUM_TEST_OBJECTS] = {
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 2, 0, 6, 0 },
|
||||
{ 0, 2, 0, 0, 6, 0 },
|
||||
{ 0, 2, 2, 2, 6, 0 },
|
||||
{ 0, 4, 4, 1, 31, 0 },
|
||||
{ 1, 1, 2, 1, 9, 5 }
|
||||
};
|
||||
static git_buf g_crlf_filtered[NUM_TEST_OBJECTS] = {
|
||||
{ "", 0, 0 },
|
||||
{ "foo\nbar\n", 0, 8 },
|
||||
{ "foo\rbar\r", 0, 8 },
|
||||
{ "foo\nbar\n", 0, 8 },
|
||||
{ "foo\nbar\rboth\nreversed\n\ragain\nproblems\r", 0, 38 },
|
||||
{ "123\n\000\001\002\003\004abc\255\254\253\n", 0, 16 }
|
||||
};
|
||||
|
||||
void test_object_blob_filter__initialize(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
cl_fixture_sandbox("empty_standard_repo");
|
||||
cl_git_pass(p_rename(
|
||||
"empty_standard_repo/.gitted", "empty_standard_repo/.git"));
|
||||
cl_git_pass(git_repository_open(&g_repo, "empty_standard_repo"));
|
||||
|
||||
for (i = 0; i < NUM_TEST_OBJECTS; i++) {
|
||||
size_t len = (g_len[i] < 0) ? strlen(g_raw[i]) : (size_t)g_len[i];
|
||||
g_len[i] = (int)len;
|
||||
|
||||
cl_git_pass(
|
||||
git_blob_create_frombuffer(&g_oids[i], g_repo, g_raw[i], len)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void test_object_blob_filter__cleanup(void)
|
||||
{
|
||||
git_repository_free(g_repo);
|
||||
g_repo = NULL;
|
||||
cl_fixture_cleanup("empty_standard_repo");
|
||||
}
|
||||
|
||||
void test_object_blob_filter__unfiltered(void)
|
||||
{
|
||||
int i;
|
||||
git_blob *blob;
|
||||
|
||||
for (i = 0; i < NUM_TEST_OBJECTS; i++) {
|
||||
cl_git_pass(git_blob_lookup(&blob, g_repo, &g_oids[i]));
|
||||
cl_assert((size_t)g_len[i] == git_blob_rawsize(blob));
|
||||
cl_assert(memcmp(git_blob_rawcontent(blob), g_raw[i], g_len[i]) == 0);
|
||||
git_blob_free(blob);
|
||||
}
|
||||
}
|
||||
|
||||
void test_object_blob_filter__stats(void)
|
||||
{
|
||||
int i;
|
||||
git_blob *blob;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
git_text_stats stats;
|
||||
|
||||
for (i = 0; i < NUM_TEST_OBJECTS; i++) {
|
||||
cl_git_pass(git_blob_lookup(&blob, g_repo, &g_oids[i]));
|
||||
cl_git_pass(git_blob__getbuf(&buf, blob));
|
||||
git_text_gather_stats(&stats, &buf);
|
||||
cl_assert(memcmp(&g_stats[i], &stats, sizeof(stats)) == 0);
|
||||
git_blob_free(blob);
|
||||
}
|
||||
|
||||
git_buf_free(&buf);
|
||||
}
|
||||
|
||||
void test_object_blob_filter__to_odb(void)
|
||||
{
|
||||
git_vector filters = GIT_VECTOR_INIT;
|
||||
git_config *cfg;
|
||||
int i;
|
||||
git_blob *blob;
|
||||
git_buf orig = GIT_BUF_INIT, out = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||
cl_assert(cfg);
|
||||
|
||||
git_attr_cache_flush(g_repo);
|
||||
cl_git_append2file("empty_standard_repo/.gitattributes", "*.txt text\n");
|
||||
|
||||
cl_assert(git_filters_load(
|
||||
&filters, g_repo, "filename.txt", GIT_FILTER_TO_ODB) > 0);
|
||||
cl_assert(filters.length == 1);
|
||||
|
||||
for (i = 0; i < NUM_TEST_OBJECTS; i++) {
|
||||
cl_git_pass(git_blob_lookup(&blob, g_repo, &g_oids[i]));
|
||||
cl_git_pass(git_blob__getbuf(&orig, blob));
|
||||
|
||||
cl_git_pass(git_filters_apply(&out, &orig, &filters));
|
||||
cl_assert(git_buf_cmp(&out, &g_crlf_filtered[i]) == 0);
|
||||
|
||||
git_blob_free(blob);
|
||||
}
|
||||
|
||||
git_filters_free(&filters);
|
||||
git_buf_free(&orig);
|
||||
git_buf_free(&out);
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ int cmp_objects(git_rawobj *o, object_data *d)
|
||||
|
||||
int copy_file(const char *src, const char *dst)
|
||||
{
|
||||
git_fbuffer source_buf;
|
||||
git_buf source_buf = GIT_BUF_INIT;
|
||||
git_file dst_fd;
|
||||
int error = GIT_ERROR;
|
||||
|
||||
@ -193,10 +193,10 @@ int copy_file(const char *src, const char *dst)
|
||||
if (dst_fd < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = p_write(dst_fd, source_buf.data, source_buf.len);
|
||||
error = p_write(dst_fd, source_buf.ptr, source_buf.size);
|
||||
|
||||
cleanup:
|
||||
git_futils_freebuffer(&source_buf);
|
||||
git_buf_free(&source_buf);
|
||||
p_close(dst_fd);
|
||||
|
||||
return error;
|
||||
@ -204,22 +204,23 @@ cleanup:
|
||||
|
||||
int cmp_files(const char *a, const char *b)
|
||||
{
|
||||
git_fbuffer buf_a, buf_b;
|
||||
git_buf buf_a = GIT_BUF_INIT;
|
||||
git_buf buf_b = GIT_BUF_INIT;
|
||||
int error = GIT_ERROR;
|
||||
|
||||
if (git_futils_readbuffer(&buf_a, a) < GIT_SUCCESS)
|
||||
return GIT_ERROR;
|
||||
|
||||
if (git_futils_readbuffer(&buf_b, b) < GIT_SUCCESS) {
|
||||
git_futils_freebuffer(&buf_a);
|
||||
git_buf_free(&buf_a);
|
||||
return GIT_ERROR;
|
||||
}
|
||||
|
||||
if (buf_a.len == buf_b.len && !memcmp(buf_a.data, buf_b.data, buf_a.len))
|
||||
if (buf_a.size == buf_b.size && !memcmp(buf_a.ptr, buf_b.ptr, buf_a.size))
|
||||
error = GIT_SUCCESS;
|
||||
|
||||
git_futils_freebuffer(&buf_a);
|
||||
git_futils_freebuffer(&buf_b);
|
||||
git_buf_free(&buf_a);
|
||||
git_buf_free(&buf_b);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user