Commit 4ef14af9 by Vicent Martí

Merge pull request #664 from arrbee/attrs-from-index

Support git attrs from index (and bare repo)
parents f95e8cc0 282283ac
...@@ -43,6 +43,7 @@ Ramsay Jones ...@@ -43,6 +43,7 @@ Ramsay Jones
Robert G. Jakabosky Robert G. Jakabosky
Romain Geissler Romain Geissler
Romain Muller Romain Muller
Russell Belfer
Sakari Jokinen Sakari Jokinen
Sam Sam
Sarath Lakshman Sarath Lakshman
......
...@@ -19,42 +19,186 @@ ...@@ -19,42 +19,186 @@
*/ */
GIT_BEGIN_DECL GIT_BEGIN_DECL
/**
* GIT_ATTR_TRUE checks if an attribute is set on. In core git
* parlance, this the value for "Set" attributes.
*
* For example, if the attribute file contains:
*
* *.c foo
*
* Then for file `xyz.c` looking up attribute "foo" gives a value for
* which `GIT_ATTR_TRUE(value)` is true.
*/
#define GIT_ATTR_TRUE(attr) ((attr) == git_attr__true) #define GIT_ATTR_TRUE(attr) ((attr) == git_attr__true)
/**
* GIT_ATTR_FALSE checks if an attribute is set off. In core git
* parlance, this is the value for attributes that are "Unset" (not to
* be confused with values that a "Unspecified").
*
* For example, if the attribute file contains:
*
* *.h -foo
*
* Then for file `zyx.h` looking up attribute "foo" gives a value for
* which `GIT_ATTR_FALSE(value)` is true.
*/
#define GIT_ATTR_FALSE(attr) ((attr) == git_attr__false) #define GIT_ATTR_FALSE(attr) ((attr) == git_attr__false)
#define GIT_ATTR_UNSPECIFIED(attr) ((attr) == NULL)
/**
* GIT_ATTR_UNSPECIFIED checks if an attribute is unspecified. This
* may be due to the attribute not being mentioned at all or because
* the attribute was explicitly set unspecified via the `!` operator.
*
* For example, if the attribute file contains:
*
* *.c foo
* *.h -foo
* onefile.c !foo
*
* Then for `onefile.c` looking up attribute "foo" yields a value with
* `GIT_ATTR_UNSPECIFIED(value)` of true. Also, looking up "foo" on
* file `onefile.rb` or looking up "bar" on any file will all give
* `GIT_ATTR_UNSPECIFIED(value)` of true.
*/
#define GIT_ATTR_UNSPECIFIED(attr) (!(attr) || (attr) == git_attr__unset)
/**
* GIT_ATTR_SET_TO_VALUE checks if an attribute is set to a value (as
* opposied to TRUE, FALSE or UNSPECIFIED). This would be the case if
* for a file with something like:
*
* *.txt eol=lf
*
* Given this, looking up "eol" for `onefile.txt` will give back the
* string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true.
*/
#define GIT_ATTR_SET_TO_VALUE(attr) \
((attr) && (attr) != git_attr__unset && \
(attr) != git_attr__true && (attr) != git_attr__false)
GIT_EXTERN(const char *) git_attr__true; GIT_EXTERN(const char *) git_attr__true;
GIT_EXTERN(const char *) git_attr__false; GIT_EXTERN(const char *) git_attr__false;
GIT_EXTERN(const char *) git_attr__unset;
/**
* Check attribute flags: Reading values from index and working directory.
*
* When checking attributes, it is possible to check attribute files
* in both the working directory (if there is one) and the index (if
* there is one). You can explicitly choose where to check and in
* which order using the following flags.
*
* Core git usually checks the working directory then the index,
* except during a checkout when it checks the index first. It will
* use index only for creating archives or for a bare repo (if an
* index has been specified for the bare repo).
*/
#define GIT_ATTR_CHECK_FILE_THEN_INDEX 0
#define GIT_ATTR_CHECK_INDEX_THEN_FILE 1
#define GIT_ATTR_CHECK_INDEX_ONLY 2
/**
* Check attribute flags: Using the system attributes file.
*
* Normally, attribute checks include looking in the /etc (or system
* equivalent) directory for a `gitattributes` file. Passing this
* flag will cause attribute checks to ignore that file.
*/
#define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2)
/** /**
* Lookup attribute for path returning string caller must free * Look up the value of one git attribute for path.
*
* @param repo The repository containing the path.
* @param flags A combination of GIT_ATTR_CHECK... flags.
* @param path The path to check for attributes. Relative paths are
* interpreted relative to the repo root. The file does
* not have to exist, but if it does not, then it will be
* treated as a plain file (not a directory).
* @param name The name of the attribute to look up.
* @param value Output of the value of the attribute. Use the GIT_ATTR_...
* macros to test for TRUE, FALSE, UNSPECIFIED, etc. or just
* use the string value for attributes set to a value. You
* should NOT modify or free this value.
*/ */
GIT_EXTERN(int) git_attr_get( GIT_EXTERN(int) git_attr_get(
git_repository *repo, const char *path, const char *name, git_repository *repo,
uint32_t flags,
const char *path,
const char *name,
const char **value); const char **value);
/** /**
* Lookup list of attributes for path, populating array of strings * Look up a list of git attributes for path.
*
* Use this if you have a known list of attributes that you want to
* look up in a single call. This is somewhat more efficient than
* calling `git_attr_get()` multiple times.
*
* For example, you might write:
*
* const char *attrs[] = { "crlf", "diff", "foo" };
* const char **values[3];
* git_attr_get_many(repo, 0, "my/fun/file.c", 3, attrs, values);
*
* Then you could loop through the 3 values to get the settings for
* the three attributes you asked about.
*
* @param repo The repository containing the path.
* @param flags A combination of GIT_ATTR_CHECK... flags.
* @param path The path inside the repo to check attributes. This
* does not have to exist, but if it does not, then
* it will be treated as a plain file (i.e. not a directory).
* @param num_attr The number of attributes being looked up
* @param names An array of num_attr strings containing attribute names.
* @param values An array of num_attr entries that will have string
* pointers written into it for the values of the attributes.
* You should not modify or free the values that are written
* into this array (although of course, you should free the
* array itself if you allocated it).
*/ */
GIT_EXTERN(int) git_attr_get_many( GIT_EXTERN(int) git_attr_get_many(
git_repository *repo, const char *path, git_repository *repo,
size_t num_attr, const char **names, uint32_t flags,
const char *path,
size_t num_attr,
const char **names,
const char **values); const char **values);
/** /**
* Perform an operation on each attribute of a path. * Loop over all the git attributes for a path.
*
* @param repo The repository containing the path.
* @param flags A combination of GIT_ATTR_CHECK... flags.
* @param path The path inside the repo to check attributes. This
* does not have to exist, but if it does not, then
* it will be treated as a plain file (i.e. not a directory).
* @param callback The function that will be invoked on each attribute
* and attribute value. The name parameter will be the name
* of the attribute and the value will be the value it is
* set to, including possibly NULL if the attribute is
* explicitly set to UNSPECIFIED using the ! sign. This
* will be invoked only once per attribute name, even if
* there are multiple rules for a given file. The highest
* priority rule will be used.
* @param payload Passed on as extra parameter to callback function.
*/ */
GIT_EXTERN(int) git_attr_foreach( GIT_EXTERN(int) git_attr_foreach(
git_repository *repo, const char *path, git_repository *repo,
uint32_t flags,
const char *path,
int (*callback)(const char *name, const char *value, void *payload), int (*callback)(const char *name, const char *value, void *payload),
void *payload); void *payload);
/** /**
* Flush the gitattributes cache. * Flush the gitattributes cache.
* *
* Call this if you have reason to believe that the attributes files * Call this if you have reason to believe that the attributes files on
* on disk no longer match the cached contents of memory. * disk no longer match the cached contents of memory. This will cause
* the attributes files to be reloaded the next time that an attribute
* access function is called.
*/ */
GIT_EXTERN(void) git_attr_cache_flush( GIT_EXTERN(void) git_attr_cache_flush(
git_repository *repo); git_repository *repo);
...@@ -62,7 +206,7 @@ GIT_EXTERN(void) git_attr_cache_flush( ...@@ -62,7 +206,7 @@ GIT_EXTERN(void) git_attr_cache_flush(
/** /**
* Add a macro definition. * Add a macro definition.
* *
* Macros will automatically be loaded from the top level .gitattributes * Macros will automatically be loaded from the top level `.gitattributes`
* file of the repository (plus the build-in "binary" macro). This * file of the repository (plus the build-in "binary" macro). This
* function allows you to add others. For example, to add the default * function allows you to add others. For example, to add the default
* macro, you would call: * macro, you would call:
......
...@@ -22,6 +22,9 @@ typedef struct { ...@@ -22,6 +22,9 @@ typedef struct {
const char *cfg_excl_file; /* cached value of core.excludesfile */ const char *cfg_excl_file; /* cached value of core.excludesfile */
} git_attr_cache; } git_attr_cache;
typedef int (*git_attr_file_parser)(
git_repository *, const char *, git_attr_file *);
extern int git_attr_cache__init(git_repository *repo); extern int git_attr_cache__init(git_repository *repo);
extern int git_attr_cache__insert_macro( extern int git_attr_cache__insert_macro(
...@@ -30,21 +33,24 @@ extern int git_attr_cache__insert_macro( ...@@ -30,21 +33,24 @@ extern int git_attr_cache__insert_macro(
extern git_attr_rule *git_attr_cache__lookup_macro( extern git_attr_rule *git_attr_cache__lookup_macro(
git_repository *repo, const char *name); git_repository *repo, const char *name);
extern int git_attr_cache__lookup_or_create_file( extern int git_attr_cache__push_file(
git_repository *repo, git_repository *repo,
const char *key, const char *base,
const char *filename, const char *filename,
int (*loader)(git_repository *, const char *, git_attr_file *), git_attr_file_source source,
git_attr_file **file_ptr); git_attr_file_parser parse,
git_vector *stack);
extern int git_attr_cache__push_file( extern int git_attr_cache__internal_file(
git_repository *repo, git_repository *repo,
git_vector *stack, const char *key,
const char *base, git_attr_file **file_ptr);
const char *filename,
int (*loader)(git_repository *, const char *, git_attr_file *));
/* returns true if path is in cache */ /* returns true if path is in cache */
extern bool git_attr_cache__is_cached(git_repository *repo, const char *path); extern bool git_attr_cache__is_cached(
git_repository *repo, git_attr_file_source source, const char *path);
extern int git_attr_cache__decide_sources(
uint32_t flags, bool has_wd, bool has_index, git_attr_file_source *srcs);
#endif #endif
#include "common.h" #include "common.h"
#include "repository.h" #include "repository.h"
#include "filebuf.h" #include "filebuf.h"
#include "git2/blob.h"
#include "git2/tree.h"
#include <ctype.h> #include <ctype.h>
const char *git_attr__true = "[internal]__TRUE__"; const char *git_attr__true = "[internal]__TRUE__";
const char *git_attr__false = "[internal]__FALSE__"; const char *git_attr__false = "[internal]__FALSE__";
const char *git_attr__unset = "[internal]__UNSET__";
static int sort_by_hash_and_name(const void *a_raw, const void *b_raw); static int sort_by_hash_and_name(const void *a_raw, const void *b_raw);
static void git_attr_rule__clear(git_attr_rule *rule); static void git_attr_rule__clear(git_attr_rule *rule);
int git_attr_file__new(git_attr_file **attrs_ptr, git_pool *pool) int git_attr_file__new(
git_attr_file **attrs_ptr,
git_attr_file_source from,
const char *path,
git_pool *pool)
{ {
git_attr_file *attrs = NULL; git_attr_file *attrs = NULL;
...@@ -25,6 +32,18 @@ int git_attr_file__new(git_attr_file **attrs_ptr, git_pool *pool) ...@@ -25,6 +32,18 @@ int git_attr_file__new(git_attr_file **attrs_ptr, git_pool *pool)
attrs->pool_is_allocated = true; attrs->pool_is_allocated = true;
} }
if (path) {
size_t len = strlen(path);
attrs->key = git_pool_malloc(attrs->pool, len + 3);
GITERR_CHECK_ALLOC(attrs->key);
attrs->key[0] = '0' + from;
attrs->key[1] = '#';
memcpy(&attrs->key[2], path, len);
attrs->key[len + 2] = '\0';
}
if (git_vector_init(&attrs->rules, 4, NULL) < 0) if (git_vector_init(&attrs->rules, 4, NULL) < 0)
goto fail; goto fail;
...@@ -37,31 +56,7 @@ fail: ...@@ -37,31 +56,7 @@ fail:
return -1; return -1;
} }
int git_attr_file__set_path( int git_attr_file__parse_buffer(
git_repository *repo, const char *path, git_attr_file *file)
{
if (file->path != NULL) {
git__free(file->path);
file->path = NULL;
}
if (repo == NULL)
file->path = git__strdup(path);
else {
const char *workdir = git_repository_workdir(repo);
if (workdir && git__prefixcmp(path, workdir) == 0)
file->path = git__strdup(path + strlen(workdir));
else
file->path = git__strdup(path);
}
GITERR_CHECK_ALLOC(file->path);
return 0;
}
int git_attr_file__from_buffer(
git_repository *repo, const char *buffer, git_attr_file *attrs) git_repository *repo, const char *buffer, git_attr_file *attrs)
{ {
int error = 0; int error = 0;
...@@ -73,10 +68,10 @@ int git_attr_file__from_buffer( ...@@ -73,10 +68,10 @@ int git_attr_file__from_buffer(
scan = buffer; scan = buffer;
if (attrs->path && git__suffixcmp(attrs->path, GIT_ATTR_FILE) == 0) { /* if subdir file path, convert context for file paths */
context = git__strndup(attrs->path, if (attrs->key && git__suffixcmp(attrs->key, "/" GIT_ATTR_FILE) == 0) {
strlen(attrs->path) - strlen(GIT_ATTR_FILE)); context = attrs->key + 2;
GITERR_CHECK_ALLOC(context); context[strlen(context) - strlen(GIT_ATTR_FILE)] = '\0';
} }
while (!error && *scan) { while (!error && *scan) {
...@@ -112,28 +107,34 @@ int git_attr_file__from_buffer( ...@@ -112,28 +107,34 @@ int git_attr_file__from_buffer(
} }
git_attr_rule__free(rule); git_attr_rule__free(rule);
git__free(context);
/* restore file path used for context */
if (context)
context[strlen(context)] = '.'; /* first char of GIT_ATTR_FILE */
return error; return error;
} }
int git_attr_file__from_file( int git_attr_file__new_and_load(
git_repository *repo, const char *path, git_attr_file *file) git_attr_file **attrs_ptr,
const char *path)
{ {
int error; int error;
git_buf fbuf = GIT_BUF_INIT; git_buf content = GIT_BUF_INIT;
assert(path && file); if ((error = git_attr_file__new(attrs_ptr, 0, path, NULL)) < 0)
return error;
if (file->path == NULL && git_attr_file__set_path(repo, path, file) < 0) if (!(error = git_futils_readbuffer(&content, path)))
return -1; error = git_attr_file__parse_buffer(
NULL, git_buf_cstr(&content), *attrs_ptr);
if (git_futils_readbuffer(&fbuf, path) < 0)
return -1;
error = git_attr_file__from_buffer(repo, fbuf.ptr, file); git_buf_free(&content);
git_buf_free(&fbuf); if (error) {
git_attr_file__free(*attrs_ptr);
*attrs_ptr = NULL;
}
return error; return error;
} }
...@@ -151,9 +152,6 @@ void git_attr_file__free(git_attr_file *file) ...@@ -151,9 +152,6 @@ void git_attr_file__free(git_attr_file *file)
git_vector_free(&file->rules); git_vector_free(&file->rules);
git__free(file->path);
file->path = NULL;
if (file->pool_is_allocated) { if (file->pool_is_allocated) {
git_pool_clear(file->pool); git_pool_clear(file->pool);
git__free(file->pool); git__free(file->pool);
...@@ -504,7 +502,7 @@ int git_attr_assignment__parse( ...@@ -504,7 +502,7 @@ int git_attr_assignment__parse(
assign->value = git_attr__false; assign->value = git_attr__false;
scan++; scan++;
} else if (*scan == '!') { } else if (*scan == '!') {
assign->value = NULL; /* explicit unspecified state */ assign->value = git_attr__unset; /* explicit unspecified state */
scan++; scan++;
} else if (*scan == '#') /* comment rest of line */ } else if (*scan == '#') /* comment rest of line */
break; break;
......
...@@ -48,7 +48,7 @@ typedef struct { ...@@ -48,7 +48,7 @@ typedef struct {
} git_attr_assignment; } git_attr_assignment;
typedef struct { typedef struct {
char *path; /* cache the path this was loaded from */ char *key; /* cache "source#path" this was loaded from */
git_vector rules; /* vector of <rule*> or <fnmatch*> */ git_vector rules; /* vector of <rule*> or <fnmatch*> */
git_pool *pool; git_pool *pool;
bool pool_is_allocated; bool pool_is_allocated;
...@@ -61,20 +61,25 @@ typedef struct { ...@@ -61,20 +61,25 @@ typedef struct {
int is_dir; int is_dir;
} git_attr_path; } git_attr_path;
typedef enum {
GIT_ATTR_FILE_FROM_FILE = 0,
GIT_ATTR_FILE_FROM_INDEX = 1
} git_attr_file_source;
/* /*
* git_attr_file API * git_attr_file API
*/ */
extern int git_attr_file__new(git_attr_file **attrs_ptr, git_pool *pool); extern int git_attr_file__new(
git_attr_file **attrs_ptr, git_attr_file_source src, const char *path, git_pool *pool);
extern int git_attr_file__new_and_load(
git_attr_file **attrs_ptr, const char *path);
extern void git_attr_file__free(git_attr_file *file); extern void git_attr_file__free(git_attr_file *file);
extern int git_attr_file__from_buffer( extern int git_attr_file__parse_buffer(
git_repository *repo, const char *buf, git_attr_file *file); git_repository *repo, const char *buf, git_attr_file *file);
extern int git_attr_file__from_file(
git_repository *repo, const char *path, git_attr_file *file);
extern int git_attr_file__set_path(
git_repository *repo, const char *path, git_attr_file *file);
extern int git_attr_file__lookup_one( extern int git_attr_file__lookup_one(
git_attr_file *file, git_attr_file *file,
......
...@@ -265,6 +265,7 @@ static int config_set(git_config_file *cfg, const char *name, const char *value) ...@@ -265,6 +265,7 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
cvar_free(old_var); cvar_free(old_var);
if (config_write(b, key, NULL, value) < 0) { if (config_write(b, key, NULL, value) < 0) {
git_strmap_delete(b->values, var->key);
cvar_free(var); cvar_free(var);
return -1; return -1;
} }
......
...@@ -82,7 +82,8 @@ static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, con ...@@ -82,7 +82,8 @@ static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, con
const char *attr_vals[NUM_CONV_ATTRS]; const char *attr_vals[NUM_CONV_ATTRS];
int error; int error;
error = git_attr_get_many(repo, path, NUM_CONV_ATTRS, attr_names, attr_vals); error = git_attr_get_many(
repo, 0, path, NUM_CONV_ATTRS, attr_names, attr_vals);
if (error == GIT_ENOTFOUND) { if (error == GIT_ENOTFOUND) {
ca->crlf_action = GIT_CRLF_GUESS; ca->crlf_action = GIT_CRLF_GUESS;
......
...@@ -506,7 +506,7 @@ static int diff_from_iterators( ...@@ -506,7 +506,7 @@ static int diff_from_iterators(
git_diff_list **diff_ptr) git_diff_list **diff_ptr)
{ {
const git_index_entry *oitem, *nitem; const git_index_entry *oitem, *nitem;
char *ignore_prefix = NULL; git_buf ignore_prefix = GIT_BUF_INIT;
git_diff_list *diff = git_diff_list_alloc(repo, opts); git_diff_list *diff = git_diff_list_alloc(repo, opts);
if (!diff) if (!diff)
goto fail; goto fail;
...@@ -536,8 +536,8 @@ static int diff_from_iterators( ...@@ -536,8 +536,8 @@ static int diff_from_iterators(
git_delta_t delta_type = GIT_DELTA_ADDED; git_delta_t delta_type = GIT_DELTA_ADDED;
/* contained in ignored parent directory, so this can be skipped. */ /* contained in ignored parent directory, so this can be skipped. */
if (ignore_prefix != NULL && if (git_buf_len(&ignore_prefix) &&
git__prefixcmp(nitem->path, ignore_prefix) == 0) git__prefixcmp(nitem->path, git_buf_cstr(&ignore_prefix)) == 0)
{ {
if (git_iterator_advance(new_iter, &nitem) < 0) if (git_iterator_advance(new_iter, &nitem) < 0)
goto fail; goto fail;
...@@ -555,7 +555,7 @@ static int diff_from_iterators( ...@@ -555,7 +555,7 @@ static int diff_from_iterators(
(oitem && git__prefixcmp(oitem->path, nitem->path) == 0)) (oitem && git__prefixcmp(oitem->path, nitem->path) == 0))
{ {
if (is_ignored) if (is_ignored)
ignore_prefix = nitem->path; git_buf_sets(&ignore_prefix, nitem->path);
if (git_iterator_advance_into_directory(new_iter, &nitem) < 0) if (git_iterator_advance_into_directory(new_iter, &nitem) < 0)
goto fail; goto fail;
...@@ -589,12 +589,16 @@ static int diff_from_iterators( ...@@ -589,12 +589,16 @@ static int diff_from_iterators(
git_iterator_free(old_iter); git_iterator_free(old_iter);
git_iterator_free(new_iter); git_iterator_free(new_iter);
git_buf_free(&ignore_prefix);
*diff_ptr = diff; *diff_ptr = diff;
return 0; return 0;
fail: fail:
git_iterator_free(old_iter); git_iterator_free(old_iter);
git_iterator_free(new_iter); git_iterator_free(new_iter);
git_buf_free(&ignore_prefix);
git_diff_list_free(diff); git_diff_list_free(diff);
*diff_ptr = NULL; *diff_ptr = NULL;
return -1; return -1;
......
...@@ -103,7 +103,7 @@ static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len) ...@@ -103,7 +103,7 @@ static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len)
static int update_file_is_binary_by_attr(git_repository *repo, git_diff_file *file) static int update_file_is_binary_by_attr(git_repository *repo, git_diff_file *file)
{ {
const char *value; const char *value;
if (git_attr_get(repo, file->path, "diff", &value) < 0) if (git_attr_get(repo, 0, file->path, "diff", &value) < 0)
return -1; return -1;
if (GIT_ATTR_FALSE(value)) if (GIT_ATTR_FALSE(value))
......
...@@ -5,29 +5,22 @@ ...@@ -5,29 +5,22 @@
#define GIT_IGNORE_FILE_INREPO "info/exclude" #define GIT_IGNORE_FILE_INREPO "info/exclude"
#define GIT_IGNORE_FILE ".gitignore" #define GIT_IGNORE_FILE ".gitignore"
static int load_ignore_file( static int parse_ignore_file(
git_repository *repo, const char *path, git_attr_file *ignores) git_repository *repo, const char *buffer, git_attr_file *ignores)
{ {
int error; int error = 0;
git_buf fbuf = GIT_BUF_INIT;
git_attr_fnmatch *match = NULL; git_attr_fnmatch *match = NULL;
const char *scan = NULL; const char *scan = NULL;
char *context = NULL; char *context = NULL;
if (ignores->path == NULL) { GIT_UNUSED(repo);
if (git_attr_file__set_path(repo, path, ignores) < 0)
return -1;
}
if (git__suffixcmp(ignores->path, GIT_IGNORE_FILE) == 0) { if (ignores->key && git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0) {
context = git__strndup(ignores->path, context = ignores->key + 2;
strlen(ignores->path) - strlen(GIT_IGNORE_FILE)); context[strlen(context) - strlen(GIT_IGNORE_FILE)] = '\0';
GITERR_CHECK_ALLOC(context);
} }
error = git_futils_readbuffer(&fbuf, path); scan = buffer;
scan = fbuf.ptr;
while (!error && *scan) { while (!error && *scan) {
if (!match) { if (!match) {
...@@ -54,23 +47,27 @@ static int load_ignore_file( ...@@ -54,23 +47,27 @@ static int load_ignore_file(
} }
} }
git_buf_free(&fbuf);
git__free(match); git__free(match);
git__free(context); /* restore file path used for context */
if (context)
context[strlen(context)] = '.'; /* first char of GIT_IGNORE_FILE */
return error; return error;
} }
#define push_ignore(R,S,B,F) \ #define push_ignore_file(R,S,B,F) \
git_attr_cache__push_file((R),(S),(B),(F),load_ignore_file) git_attr_cache__push_file((R),(B),(F),GIT_ATTR_FILE_FROM_FILE,parse_ignore_file,(S))
static int push_one_ignore(void *ref, git_buf *path) static int push_one_ignore(void *ref, git_buf *path)
{ {
git_ignores *ign = (git_ignores *)ref; git_ignores *ign = (git_ignores *)ref;
return push_ignore(ign->repo, &ign->ign_path, path->ptr, GIT_IGNORE_FILE); return push_ignore_file(ign->repo, &ign->ign_path, path->ptr, GIT_IGNORE_FILE);
} }
int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ignores) int git_ignore__for_path(
git_repository *repo,
const char *path,
git_ignores *ignores)
{ {
int error = 0; int error = 0;
const char *workdir = git_repository_workdir(repo); const char *workdir = git_repository_workdir(repo);
...@@ -86,30 +83,37 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ig ...@@ -86,30 +83,37 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ig
(error = git_attr_cache__init(repo)) < 0) (error = git_attr_cache__init(repo)) < 0)
goto cleanup; goto cleanup;
/* translate path into directory within workdir */ /* given a unrooted path in a non-bare repo, resolve it */
if ((error = git_path_find_dir(&ignores->dir, path, workdir)) < 0) if (workdir && git_path_root(path) < 0)
error = git_path_find_dir(&ignores->dir, path, workdir);
else
error = git_buf_sets(&ignores->dir, path);
if (error < 0)
goto cleanup; goto cleanup;
/* set up internals */ /* set up internals */
error = git_attr_cache__lookup_or_create_file( error = git_attr_cache__internal_file(
repo, GIT_IGNORE_INTERNAL, NULL, NULL, &ignores->ign_internal); repo, GIT_IGNORE_INTERNAL, &ignores->ign_internal);
if (error < 0) if (error < 0)
goto cleanup; goto cleanup;
/* load .gitignore up the path */ /* load .gitignore up the path */
error = git_path_walk_up(&ignores->dir, workdir, push_one_ignore, ignores); if (workdir != NULL) {
if (error < 0) error = git_path_walk_up(
goto cleanup; &ignores->dir, workdir, push_one_ignore, ignores);
if (error < 0)
goto cleanup;
}
/* load .git/info/exclude */ /* load .git/info/exclude */
error = push_ignore(repo, &ignores->ign_global, error = push_ignore_file(repo, &ignores->ign_global,
git_repository_path(repo), GIT_IGNORE_FILE_INREPO); git_repository_path(repo), GIT_IGNORE_FILE_INREPO);
if (error < 0) if (error < 0)
goto cleanup; goto cleanup;
/* load core.excludesfile */ /* load core.excludesfile */
if (git_repository_attr_cache(repo)->cfg_excl_file != NULL) if (git_repository_attr_cache(repo)->cfg_excl_file != NULL)
error = push_ignore(repo, &ignores->ign_global, NULL, error = push_ignore_file(repo, &ignores->ign_global, NULL,
git_repository_attr_cache(repo)->cfg_excl_file); git_repository_attr_cache(repo)->cfg_excl_file);
cleanup: cleanup:
...@@ -124,7 +128,7 @@ int git_ignore__push_dir(git_ignores *ign, const char *dir) ...@@ -124,7 +128,7 @@ int git_ignore__push_dir(git_ignores *ign, const char *dir)
if (git_buf_joinpath(&ign->dir, ign->dir.ptr, dir) < 0) if (git_buf_joinpath(&ign->dir, ign->dir.ptr, dir) < 0)
return -1; return -1;
else else
return push_ignore( return push_ignore_file(
ign->repo, &ign->ign_path, ign->dir.ptr, GIT_IGNORE_FILE); ign->repo, &ign->ign_path, ign->dir.ptr, GIT_IGNORE_FILE);
} }
...@@ -132,7 +136,7 @@ int git_ignore__pop_dir(git_ignores *ign) ...@@ -132,7 +136,7 @@ int git_ignore__pop_dir(git_ignores *ign)
{ {
if (ign->ign_path.length > 0) { if (ign->ign_path.length > 0) {
git_attr_file *file = git_vector_last(&ign->ign_path); git_attr_file *file = git_vector_last(&ign->ign_path);
if (git__suffixcmp(ign->dir.ptr, file->path) == 0) if (git__suffixcmp(ign->dir.ptr, file->key + 2) == 0)
git_vector_pop(&ign->ign_path); git_vector_pop(&ign->ign_path);
git_buf_rtruncate_at_char(&ign->dir, '/'); git_buf_rtruncate_at_char(&ign->dir, '/');
} }
...@@ -163,7 +167,8 @@ static bool ignore_lookup_in_rules( ...@@ -163,7 +167,8 @@ static bool ignore_lookup_in_rules(
return false; return false;
} }
int git_ignore__lookup(git_ignores *ignores, const char *pathname, int *ignored) int git_ignore__lookup(
git_ignores *ignores, const char *pathname, int *ignored)
{ {
unsigned int i; unsigned int i;
git_attr_file *file; git_attr_file *file;
......
...@@ -25,13 +25,14 @@ typedef struct { ...@@ -25,13 +25,14 @@ typedef struct {
git_vector ign_global; git_vector ign_global;
} git_ignores; } git_ignores;
extern int git_ignore__for_path( extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign);
git_repository *repo, const char *path, git_ignores *ign);
extern int git_ignore__push_dir(git_ignores *ign, const char *dir); extern int git_ignore__push_dir(git_ignores *ign, const char *dir);
extern int git_ignore__pop_dir(git_ignores *ign); extern int git_ignore__pop_dir(git_ignores *ign);
extern void git_ignore__free(git_ignores *ign); extern void git_ignore__free(git_ignores *ign);
extern int git_ignore__lookup(git_ignores *ign, const char *path, int *ignored); extern int git_ignore__lookup(git_ignores *ign, const char *path, int *ignored);
#endif #endif
...@@ -146,7 +146,7 @@ int git_object_lookup_prefix( ...@@ -146,7 +146,7 @@ int git_object_lookup_prefix(
} }
if (error < 0) if (error < 0)
return -1; return error;
if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) { if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) {
git_odb_object_free(odb_obj); git_odb_object_free(odb_obj);
...@@ -292,3 +292,42 @@ size_t git_object__size(git_otype type) ...@@ -292,3 +292,42 @@ size_t git_object__size(git_otype type)
return git_objects_table[type].size; return git_objects_table[type].size;
} }
int git_object__resolve_to_type(git_object **obj, git_otype type)
{
int error = 0;
git_object *scan, *next;
if (type == GIT_OBJ_ANY)
return 0;
scan = *obj;
while (!error && scan && git_object_type(scan) != type) {
switch (git_object_type(scan)) {
case GIT_OBJ_COMMIT:
{
git_tree *tree = NULL;
error = git_commit_tree(&tree, (git_commit *)scan);
next = (git_object *)tree;
break;
}
case GIT_OBJ_TAG:
error = git_tag_target(&next, (git_tag *)scan);
break;
default:
giterr_set(GITERR_REFERENCE, "Object does not resolve to type");
error = -1;
next = NULL;
break;
}
git_object_free(scan);
scan = next;
}
*obj = scan;
return error;
}
...@@ -589,7 +589,7 @@ int git_odb_read_prefix( ...@@ -589,7 +589,7 @@ int git_odb_read_prefix(
} }
if (found == 0) if (found == 0)
return git_odb__error_notfound("no match for prefix"); return git_odb__error_notfound("no match for prefix", short_id);
if (found > 1) if (found > 1)
return git_odb__error_ambiguous("multiple matches for prefix"); return git_odb__error_ambiguous("multiple matches for prefix");
...@@ -684,9 +684,15 @@ int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oi ...@@ -684,9 +684,15 @@ int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oi
return error; return error;
} }
int git_odb__error_notfound(const char *message) int git_odb__error_notfound(const char *message, const git_oid *oid)
{ {
giterr_set(GITERR_ODB, "Object not found - %s", message); if (oid != NULL) {
char oid_str[GIT_OID_HEXSZ + 1];
git_oid_tostr(oid_str, sizeof(oid_str), oid);
giterr_set(GITERR_ODB, "Object not found - %s (%s)", message, oid_str);
} else
giterr_set(GITERR_ODB, "Object not found - %s", message);
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
......
...@@ -70,7 +70,7 @@ int git_odb__hashlink(git_oid *out, const char *path); ...@@ -70,7 +70,7 @@ int git_odb__hashlink(git_oid *out, const char *path);
/* /*
* Generate a GIT_ENOTFOUND error for the ODB. * Generate a GIT_ENOTFOUND error for the ODB.
*/ */
int git_odb__error_notfound(const char *message); int git_odb__error_notfound(const char *message, const git_oid *oid);
/* /*
* Generate a GIT_EAMBIGUOUS error for the ODB. * Generate a GIT_EAMBIGUOUS error for the ODB.
......
...@@ -528,7 +528,7 @@ static int locate_object_short_oid( ...@@ -528,7 +528,7 @@ static int locate_object_short_oid(
/* Check that directory exists */ /* Check that directory exists */
if (git_path_isdir(object_location->ptr) == false) if (git_path_isdir(object_location->ptr) == false)
return git_odb__error_notfound("failed to locate from short oid"); return git_odb__error_notfound("no matching loose object for prefix", short_oid);
state.dir_len = git_buf_len(object_location); state.dir_len = git_buf_len(object_location);
state.short_oid_len = len; state.short_oid_len = len;
...@@ -541,7 +541,7 @@ static int locate_object_short_oid( ...@@ -541,7 +541,7 @@ static int locate_object_short_oid(
return error; return error;
if (!state.found) if (!state.found)
return git_odb__error_notfound("failed to locate from short oid"); return git_odb__error_notfound("no matching loose object for prefix", short_oid);
/* Convert obtained hex formatted oid to raw */ /* Convert obtained hex formatted oid to raw */
error = git_oid_fromstr(res_oid, (char *)state.res_oid); error = git_oid_fromstr(res_oid, (char *)state.res_oid);
...@@ -590,7 +590,7 @@ static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_ ...@@ -590,7 +590,7 @@ static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_
raw.type = GIT_OBJ_BAD; raw.type = GIT_OBJ_BAD;
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
error = git_odb__error_notfound("in loose backend"); error = git_odb__error_notfound("no matching loose object", oid);
else if ((error = read_header_loose(&raw, &object_path)) == 0) { else if ((error = read_header_loose(&raw, &object_path)) == 0) {
*len_p = raw.len; *len_p = raw.len;
*type_p = raw.type; *type_p = raw.type;
...@@ -610,7 +610,7 @@ static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p ...@@ -610,7 +610,7 @@ static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p
assert(backend && oid); assert(backend && oid);
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
error = git_odb__error_notfound("in loose backend"); error = git_odb__error_notfound("no matching loose object", oid);
else if ((error = read_loose(&raw, &object_path)) == 0) { else if ((error = read_loose(&raw, &object_path)) == 0) {
*buffer_p = raw.data; *buffer_p = raw.data;
*len_p = raw.len; *len_p = raw.len;
......
...@@ -242,7 +242,7 @@ static int packfile_refresh_all(struct pack_backend *backend) ...@@ -242,7 +242,7 @@ static int packfile_refresh_all(struct pack_backend *backend)
return 0; return 0;
if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode)) if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
return git_odb__error_notfound("failed to refresh packfiles"); return git_odb__error_notfound("failed to refresh packfiles", NULL);
if (st.st_mtime != backend->pack_folder_mtime) { if (st.st_mtime != backend->pack_folder_mtime) {
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
...@@ -288,7 +288,7 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen ...@@ -288,7 +288,7 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
} }
} }
return git_odb__error_notfound("failed to find pack entry"); return git_odb__error_notfound("failed to find pack entry", oid);
} }
static int pack_entry_find_prefix( static int pack_entry_find_prefix(
...@@ -330,7 +330,7 @@ static int pack_entry_find_prefix( ...@@ -330,7 +330,7 @@ static int pack_entry_find_prefix(
} }
if (!found) if (!found)
return git_odb__error_notfound("failed to find pack entry"); return git_odb__error_notfound("no matching pack entry for prefix", short_oid);
else if (found > 1) else if (found > 1)
return git_odb__error_ambiguous("found multiple pack entries"); return git_odb__error_ambiguous("found multiple pack entries");
else else
......
...@@ -375,6 +375,18 @@ int git_packfile_unpack( ...@@ -375,6 +375,18 @@ int git_packfile_unpack(
return error; return error;
} }
static void *use_git_alloc(void *opaq, unsigned int count, unsigned int size)
{
GIT_UNUSED(opaq);
return git__calloc(count, size);
}
static void use_git_free(void *opaq, void *ptr)
{
GIT_UNUSED(opaq);
git__free(ptr);
}
int packfile_unpack_compressed( int packfile_unpack_compressed(
git_rawobj *obj, git_rawobj *obj,
struct git_pack_file *p, struct git_pack_file *p,
...@@ -393,6 +405,8 @@ int packfile_unpack_compressed( ...@@ -393,6 +405,8 @@ int packfile_unpack_compressed(
memset(&stream, 0, sizeof(stream)); memset(&stream, 0, sizeof(stream));
stream.next_out = buffer; stream.next_out = buffer;
stream.avail_out = (uInt)size + 1; stream.avail_out = (uInt)size + 1;
stream.zalloc = use_git_alloc;
stream.zfree = use_git_free;
st = inflateInit(&stream); st = inflateInit(&stream);
if (st != Z_OK) { if (st != Z_OK) {
...@@ -541,7 +555,7 @@ static int packfile_open(struct git_pack_file *p) ...@@ -541,7 +555,7 @@ static int packfile_open(struct git_pack_file *p)
assert(p->index_map.data); assert(p->index_map.data);
if (!p->index_map.data && pack_index_open(p) < 0) if (!p->index_map.data && pack_index_open(p) < 0)
return git_odb__error_notfound("failed to open packfile"); return git_odb__error_notfound("failed to open packfile", NULL);
/* TODO: open with noatime */ /* TODO: open with noatime */
p->mwf.fd = git_futils_open_ro(p->pack_name); p->mwf.fd = git_futils_open_ro(p->pack_name);
...@@ -615,7 +629,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) ...@@ -615,7 +629,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
path_len -= strlen(".idx"); path_len -= strlen(".idx");
if (path_len < 1) { if (path_len < 1) {
git__free(p); git__free(p);
return git_odb__error_notfound("invalid packfile path"); return git_odb__error_notfound("invalid packfile path", NULL);
} }
memcpy(p->pack_name, path, path_len); memcpy(p->pack_name, path, path_len);
...@@ -627,7 +641,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) ...@@ -627,7 +641,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
strcpy(p->pack_name + path_len, ".pack"); strcpy(p->pack_name + path_len, ".pack");
if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) { if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) {
git__free(p); git__free(p);
return git_odb__error_notfound("packfile not found"); return git_odb__error_notfound("packfile not found", NULL);
} }
/* ok, it looks sane as far as we can check without /* ok, it looks sane as far as we can check without
...@@ -733,9 +747,8 @@ static int pack_entry_find_offset( ...@@ -733,9 +747,8 @@ static int pack_entry_find_offset(
if (pos < (int)p->num_objects) { if (pos < (int)p->num_objects) {
current = index + pos * stride; current = index + pos * stride;
if (!git_oid_ncmp(short_oid, (const git_oid *)current, len)) { if (!git_oid_ncmp(short_oid, (const git_oid *)current, len))
found = 1; found = 1;
}
} }
} }
...@@ -749,7 +762,7 @@ static int pack_entry_find_offset( ...@@ -749,7 +762,7 @@ static int pack_entry_find_offset(
} }
if (!found) if (!found)
return git_odb__error_notfound("failed to find offset for pack entry"); return git_odb__error_notfound("failed to find offset for pack entry", short_oid);
if (found > 1) if (found > 1)
return git_odb__error_ambiguous("found multiple offsets for pack entry"); return git_odb__error_ambiguous("found multiple offsets for pack entry");
*offset_out = nth_packed_object_offset(p, pos); *offset_out = nth_packed_object_offset(p, pos);
......
...@@ -862,3 +862,23 @@ int git_repository_is_bare(git_repository *repo) ...@@ -862,3 +862,23 @@ int git_repository_is_bare(git_repository *repo)
assert(repo); assert(repo);
return repo->is_bare; return repo->is_bare;
} }
int git_repository_head_tree(git_tree **tree, git_repository *repo)
{
git_oid head_oid;
git_object *obj = NULL;
if (git_reference_name_to_oid(&head_oid, repo, GIT_HEAD_FILE) < 0) {
/* cannot resolve HEAD - probably brand new repo */
giterr_clear();
*tree = NULL;
return 0;
}
if (git_object_lookup(&obj, repo, &head_oid, GIT_OBJ_ANY) < 0 ||
git_object__resolve_to_type(&obj, GIT_OBJ_TREE) < 0)
return -1;
*tree = (git_tree *)obj;
return 0;
}
...@@ -98,6 +98,8 @@ struct git_repository { ...@@ -98,6 +98,8 @@ struct git_repository {
* export */ * export */
void git_object__free(void *object); void git_object__free(void *object);
int git_object__resolve_to_type(git_object **obj, git_otype type);
int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header); 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); void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid);
...@@ -106,6 +108,8 @@ GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo) ...@@ -106,6 +108,8 @@ GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo)
return &repo->attrcache; return &repo->attrcache;
} }
int git_repository_head_tree(git_tree **tree, git_repository *repo);
/* /*
* Weak pointers to repository internals. * Weak pointers to repository internals.
* *
......
...@@ -18,41 +18,6 @@ ...@@ -18,41 +18,6 @@
#include "git2/diff.h" #include "git2/diff.h"
#include "diff.h" #include "diff.h"
static int resolve_head_to_tree(git_tree **tree, git_repository *repo)
{
git_oid head_oid;
git_object *obj = NULL;
if (git_reference_name_to_oid(&head_oid, repo, GIT_HEAD_FILE) < 0) {
/* cannot resolve HEAD - probably brand new repo */
giterr_clear();
*tree = NULL;
return 0;
}
if (git_object_lookup(&obj, repo, &head_oid, GIT_OBJ_ANY) < 0)
goto fail;
switch (git_object_type(obj)) {
case GIT_OBJ_TREE:
*tree = (git_tree *)obj;
break;
case GIT_OBJ_COMMIT:
if (git_commit_tree(tree, (git_commit *)obj) < 0)
goto fail;
git_object_free(obj);
break;
default:
goto fail;
}
return 0;
fail:
git_object_free(obj);
return -1;
}
static unsigned int index_delta2status(git_delta_t index_status) static unsigned int index_delta2status(git_delta_t index_status)
{ {
unsigned int st = GIT_STATUS_CURRENT; unsigned int st = GIT_STATUS_CURRENT;
...@@ -120,11 +85,8 @@ int git_status_foreach_ext( ...@@ -120,11 +85,8 @@ int git_status_foreach_ext(
assert(show <= GIT_STATUS_SHOW_INDEX_THEN_WORKDIR); assert(show <= GIT_STATUS_SHOW_INDEX_THEN_WORKDIR);
switch (resolve_head_to_tree(&head, repo)) { if ((err = git_repository_head_tree(&head, repo)) < 0)
case 0: break; return err;
case GIT_ENOTFOUND: return 0;
default: return -1;
}
memset(&diffopt, 0, sizeof(diffopt)); memset(&diffopt, 0, sizeof(diffopt));
memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec)); memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec));
...@@ -405,7 +367,7 @@ int git_status_file( ...@@ -405,7 +367,7 @@ int git_status_file(
status_entry_update_from_index(e, index); status_entry_update_from_index(e, index);
/* Try to find file in HEAD */ /* Try to find file in HEAD */
if ((error = resolve_head_to_tree(&tree, repo)) < 0) if ((error = git_repository_head_tree(&tree, repo)) < 0)
goto cleanup; goto cleanup;
if (tree != NULL) { if (tree != NULL) {
......
...@@ -36,18 +36,28 @@ typedef khash_t(str) git_strmap; ...@@ -36,18 +36,28 @@ typedef khash_t(str) git_strmap;
#define git_strmap_set_value_at(h, idx, v) kh_val(h, idx) = v #define git_strmap_set_value_at(h, idx, v) kh_val(h, idx) = v
#define git_strmap_delete_at(h, idx) kh_del(str, h, idx) #define git_strmap_delete_at(h, idx) kh_del(str, h, idx)
#define git_strmap_insert(h, key, val, err) do { \ #define git_strmap_insert(h, key, val, rval) do { \
khiter_t __pos = kh_put(str, h, key, &err); \ khiter_t __pos = kh_put(str, h, key, &rval); \
if (err >= 0) kh_val(h, __pos) = val; \ if (rval >= 0) { \
} while (0) if (rval == 0) kh_key(h, __pos) = key; \
#define git_strmap_insert2(h, key, val, old, err) do { \
khiter_t __pos = kh_put(str, h, key, &err); \
if (err >= 0) { \
old = (err == 0) ? kh_val(h, __pos) : NULL; \
kh_val(h, __pos) = val; \ kh_val(h, __pos) = val; \
} } while (0) } } while (0)
#define git_strmap_insert2(h, key, val, oldv, rval) do { \
khiter_t __pos = kh_put(str, h, key, &rval); \
if (rval >= 0) { \
if (rval == 0) { \
oldv = kh_val(h, __pos); \
kh_key(h, __pos) = key; \
} else { oldv = NULL; } \
kh_val(h, __pos) = val; \
} } while (0)
#define git_strmap_delete(h, key) do { \
khiter_t __pos = git_strmap_lookup_index(h, key); \
if (git_strmap_valid_index(h, __pos)) \
git_strmap_delete_at(h, __pos); } while (0)
#define git_strmap_foreach kh_foreach #define git_strmap_foreach kh_foreach
#define git_strmap_foreach_value kh_foreach_value #define git_strmap_foreach_value kh_foreach_value
......
...@@ -11,9 +11,9 @@ void test_attr_file__simple_read(void) ...@@ -11,9 +11,9 @@ void test_attr_file__simple_read(void)
git_attr_assignment *assign; git_attr_assignment *assign;
git_attr_rule *rule; git_attr_rule *rule;
cl_git_pass(git_attr_file__new(&file, NULL)); cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr0")));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr0"), file));
cl_assert_equal_s(cl_fixture("attr/attr0"), file->path); cl_assert_equal_s(cl_fixture("attr/attr0"), file->key + 2);
cl_assert(file->rules.length == 1); cl_assert(file->rules.length == 1);
rule = get_rule(0); rule = get_rule(0);
...@@ -37,9 +37,9 @@ void test_attr_file__match_variants(void) ...@@ -37,9 +37,9 @@ void test_attr_file__match_variants(void)
git_attr_rule *rule; git_attr_rule *rule;
git_attr_assignment *assign; git_attr_assignment *assign;
cl_git_pass(git_attr_file__new(&file, NULL)); cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr1")));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr1"), file));
cl_assert_equal_s(cl_fixture("attr/attr1"), file->path); cl_assert_equal_s(cl_fixture("attr/attr1"), file->key + 2);
cl_assert(file->rules.length == 10); cl_assert(file->rules.length == 10);
/* let's do a thorough check of this rule, then just verify /* let's do a thorough check of this rule, then just verify
...@@ -123,9 +123,9 @@ void test_attr_file__assign_variants(void) ...@@ -123,9 +123,9 @@ void test_attr_file__assign_variants(void)
git_attr_rule *rule; git_attr_rule *rule;
git_attr_assignment *assign; git_attr_assignment *assign;
cl_git_pass(git_attr_file__new(&file, NULL)); cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr2")));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr2"), file));
cl_assert_equal_s(cl_fixture("attr/attr2"), file->path); cl_assert_equal_s(cl_fixture("attr/attr2"), file->key + 2);
cl_assert(file->rules.length == 11); cl_assert(file->rules.length == 11);
check_one_assign(file, 0, 0, "pat0", "simple", EXPECT_TRUE, NULL); check_one_assign(file, 0, 0, "pat0", "simple", EXPECT_TRUE, NULL);
...@@ -189,9 +189,8 @@ void test_attr_file__check_attr_examples(void) ...@@ -189,9 +189,8 @@ void test_attr_file__check_attr_examples(void)
git_attr_rule *rule; git_attr_rule *rule;
git_attr_assignment *assign; git_attr_assignment *assign;
cl_git_pass(git_attr_file__new(&file, NULL)); cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr3")));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr3"), file)); cl_assert_equal_s(cl_fixture("attr/attr3"), file->key + 2);
cl_assert_equal_s(cl_fixture("attr/attr3"), file->path);
cl_assert(file->rules.length == 3); cl_assert(file->rules.length == 3);
rule = get_rule(0); rule = get_rule(0);
...@@ -214,7 +213,7 @@ void test_attr_file__check_attr_examples(void) ...@@ -214,7 +213,7 @@ void test_attr_file__check_attr_examples(void)
cl_assert(rule->assigns.length == 1); cl_assert(rule->assigns.length == 1);
assign = get_assign(rule, 0); assign = get_assign(rule, 0);
cl_assert_equal_s("myAttr", assign->name); cl_assert_equal_s("myAttr", assign->name);
cl_assert(assign->value == NULL); cl_assert(GIT_ATTR_UNSPECIFIED(assign->value));
rule = get_rule(2); rule = get_rule(2);
cl_assert_equal_s("README", rule->match.pattern); cl_assert_equal_s("README", rule->match.pattern);
......
#include "clar_libgit2.h"
#include "git2/attr.h"
void test_attr_flags__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_attr_flags__bare(void)
{
git_repository *repo = cl_git_sandbox_init("testrepo.git");
const char *value;
cl_assert(git_repository_is_bare(repo));
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM, "README.md", "diff", &value));
cl_assert(GIT_ATTR_UNSPECIFIED(value));
}
void test_attr_flags__index_vs_workdir(void)
{
git_repository *repo = cl_git_sandbox_init("attr_index");
const char *value;
cl_assert(!git_repository_is_bare(repo));
/* wd then index */
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
"README.md", "bar", &value));
cl_assert(GIT_ATTR_FALSE(value));
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
"README.md", "blargh", &value));
cl_assert_equal_s(value, "goop");
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
"README.txt", "foo", &value));
cl_assert(GIT_ATTR_FALSE(value));
/* index then wd */
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
"README.md", "bar", &value));
cl_assert(GIT_ATTR_TRUE(value));
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
"README.md", "blargh", &value));
cl_assert_equal_s(value, "garble");
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
"README.txt", "foo", &value));
cl_assert(GIT_ATTR_TRUE(value));
}
void test_attr_flags__subdir(void)
{
git_repository *repo = cl_git_sandbox_init("attr_index");
const char *value;
/* wd then index */
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
"sub/sub/README.md", "bar", &value));
cl_assert_equal_s(value, "1234");
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
"sub/sub/README.txt", "another", &value));
cl_assert_equal_s(value, "one");
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
"sub/sub/README.txt", "again", &value));
cl_assert(GIT_ATTR_TRUE(value));
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
"sub/sub/README.txt", "beep", &value));
cl_assert_equal_s(value, "10");
/* index then wd */
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
"sub/sub/README.md", "bar", &value));
cl_assert_equal_s(value, "1337");
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
"sub/sub/README.txt", "another", &value));
cl_assert_equal_s(value, "one");
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
"sub/sub/README.txt", "again", &value));
cl_assert(GIT_ATTR_TRUE(value));
cl_git_pass(git_attr_get(
repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
"sub/sub/README.txt", "beep", &value));
cl_assert_equal_s(value, "5");
}
...@@ -9,9 +9,8 @@ void test_attr_lookup__simple(void) ...@@ -9,9 +9,8 @@ void test_attr_lookup__simple(void)
git_attr_path path; git_attr_path path;
const char *value = NULL; const char *value = NULL;
cl_git_pass(git_attr_file__new(&file, NULL)); cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr0")));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr0"), file)); cl_assert_equal_s(cl_fixture("attr/attr0"), file->key + 2);
cl_assert_equal_s(cl_fixture("attr/attr0"), file->path);
cl_assert(file->rules.length == 1); cl_assert(file->rules.length == 1);
cl_git_pass(git_attr_path__init(&path, "test", NULL)); cl_git_pass(git_attr_path__init(&path, "test", NULL));
...@@ -130,9 +129,8 @@ void test_attr_lookup__match_variants(void) ...@@ -130,9 +129,8 @@ void test_attr_lookup__match_variants(void)
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };
cl_git_pass(git_attr_file__new(&file, NULL)); cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr1")));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr1"), file)); cl_assert_equal_s(cl_fixture("attr/attr1"), file->key + 2);
cl_assert_equal_s(cl_fixture("attr/attr1"), file->path);
cl_assert(file->rules.length == 10); cl_assert(file->rules.length == 10);
cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL)); cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL));
...@@ -192,8 +190,7 @@ void test_attr_lookup__assign_variants(void) ...@@ -192,8 +190,7 @@ void test_attr_lookup__assign_variants(void)
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };
cl_git_pass(git_attr_file__new(&file, NULL)); cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr2")));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr2"), file));
cl_assert(file->rules.length == 11); cl_assert(file->rules.length == 11);
run_test_cases(file, cases, 0); run_test_cases(file, cases, 0);
...@@ -228,8 +225,7 @@ void test_attr_lookup__check_attr_examples(void) ...@@ -228,8 +225,7 @@ void test_attr_lookup__check_attr_examples(void)
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };
cl_git_pass(git_attr_file__new(&file, NULL)); cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr3")));
cl_git_pass(git_attr_file__from_file(NULL, cl_fixture("attr/attr3"), file));
cl_assert(file->rules.length == 3); cl_assert(file->rules.length == 3);
run_test_cases(file, cases, 0); run_test_cases(file, cases, 0);
...@@ -254,8 +250,10 @@ void test_attr_lookup__from_buffer(void) ...@@ -254,8 +250,10 @@ void test_attr_lookup__from_buffer(void)
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };
cl_git_pass(git_attr_file__new(&file, NULL)); cl_git_pass(git_attr_file__new(&file, 0, NULL, NULL));
cl_git_pass(git_attr_file__from_buffer(NULL, "a* foo\nabc bar\n* baz", file));
cl_git_pass(git_attr_file__parse_buffer(NULL, "a* foo\nabc bar\n* baz", file));
cl_assert(file->rules.length == 3); cl_assert(file->rules.length == 3);
run_test_cases(file, cases, 0); run_test_cases(file, cases, 0);
......
...@@ -64,13 +64,13 @@ void test_attr_repo__get_one(void) ...@@ -64,13 +64,13 @@ void test_attr_repo__get_one(void)
for (scan = test_cases; scan->path != NULL; scan++) { for (scan = test_cases; scan->path != NULL; scan++) {
const char *value; const char *value;
cl_git_pass(git_attr_get(g_repo, scan->path, scan->attr, &value)); cl_git_pass(git_attr_get(g_repo, 0, scan->path, scan->attr, &value));
attr_check_expected(scan->expected, scan->expected_str, value); attr_check_expected(scan->expected, scan->expected_str, value);
} }
cl_assert(git_attr_cache__is_cached(g_repo, ".git/info/attributes")); cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/attributes"));
cl_assert(git_attr_cache__is_cached(g_repo, ".gitattributes")); cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitattributes"));
cl_assert(git_attr_cache__is_cached(g_repo, "sub/.gitattributes")); cl_assert(git_attr_cache__is_cached(g_repo, 0, "sub/.gitattributes"));
} }
void test_attr_repo__get_many(void) void test_attr_repo__get_many(void)
...@@ -78,21 +78,21 @@ void test_attr_repo__get_many(void) ...@@ -78,21 +78,21 @@ void test_attr_repo__get_many(void)
const char *names[4] = { "repoattr", "rootattr", "missingattr", "subattr" }; const char *names[4] = { "repoattr", "rootattr", "missingattr", "subattr" };
const char *values[4]; const char *values[4];
cl_git_pass(git_attr_get_many(g_repo, "root_test1", 4, names, values)); cl_git_pass(git_attr_get_many(g_repo, 0, "root_test1", 4, names, values));
cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_TRUE(values[1])); cl_assert(GIT_ATTR_TRUE(values[1]));
cl_assert(GIT_ATTR_UNSPECIFIED(values[2])); cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
cl_git_pass(git_attr_get_many(g_repo, "root_test2", 4, names, values)); cl_git_pass(git_attr_get_many(g_repo, 0, "root_test2", 4, names, values));
cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_FALSE(values[1])); cl_assert(GIT_ATTR_FALSE(values[1]));
cl_assert(GIT_ATTR_UNSPECIFIED(values[2])); cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
cl_git_pass(git_attr_get_many(g_repo, "sub/subdir_test1", 4, names, values)); cl_git_pass(git_attr_get_many(g_repo, 0, "sub/subdir_test1", 4, names, values));
cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_TRUE(values[1])); cl_assert(GIT_ATTR_TRUE(values[1]));
...@@ -118,16 +118,17 @@ void test_attr_repo__foreach(void) ...@@ -118,16 +118,17 @@ void test_attr_repo__foreach(void)
int count; int count;
count = 0; count = 0;
cl_git_pass(git_attr_foreach(g_repo, "root_test1", &count_attrs, &count)); cl_git_pass(git_attr_foreach(
g_repo, 0, "root_test1", &count_attrs, &count));
cl_assert(count == 2); cl_assert(count == 2);
count = 0; count = 0;
cl_git_pass(git_attr_foreach(g_repo, "sub/subdir_test1", cl_git_pass(git_attr_foreach(g_repo, 0, "sub/subdir_test1",
&count_attrs, &count)); &count_attrs, &count));
cl_assert(count == 4); /* repoattr, rootattr, subattr, negattr */ cl_assert(count == 4); /* repoattr, rootattr, subattr, negattr */
count = 0; count = 0;
cl_git_pass(git_attr_foreach(g_repo, "sub/subdir_test2.txt", cl_git_pass(git_attr_foreach(g_repo, 0, "sub/subdir_test2.txt",
&count_attrs, &count)); &count_attrs, &count));
cl_assert(count == 6); /* repoattr, rootattr, subattr, reposub, negattr, another */ cl_assert(count == 6); /* repoattr, rootattr, subattr, reposub, negattr, another */
} }
...@@ -136,19 +137,19 @@ void test_attr_repo__manpage_example(void) ...@@ -136,19 +137,19 @@ void test_attr_repo__manpage_example(void)
{ {
const char *value; const char *value;
cl_git_pass(git_attr_get(g_repo, "sub/abc", "foo", &value)); cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "foo", &value));
cl_assert(GIT_ATTR_TRUE(value)); cl_assert(GIT_ATTR_TRUE(value));
cl_git_pass(git_attr_get(g_repo, "sub/abc", "bar", &value)); cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "bar", &value));
cl_assert(GIT_ATTR_UNSPECIFIED(value)); cl_assert(GIT_ATTR_UNSPECIFIED(value));
cl_git_pass(git_attr_get(g_repo, "sub/abc", "baz", &value)); cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "baz", &value));
cl_assert(GIT_ATTR_FALSE(value)); cl_assert(GIT_ATTR_FALSE(value));
cl_git_pass(git_attr_get(g_repo, "sub/abc", "merge", &value)); cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "merge", &value));
cl_assert_equal_s("filfre", value); cl_assert_equal_s("filfre", value);
cl_git_pass(git_attr_get(g_repo, "sub/abc", "frotz", &value)); cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "frotz", &value));
cl_assert(GIT_ATTR_UNSPECIFIED(value)); cl_assert(GIT_ATTR_UNSPECIFIED(value));
} }
...@@ -159,7 +160,7 @@ void test_attr_repo__macros(void) ...@@ -159,7 +160,7 @@ void test_attr_repo__macros(void)
const char *names3[3] = { "macro2", "multi2", "multi3" }; const char *names3[3] = { "macro2", "multi2", "multi3" };
const char *values[5]; const char *values[5];
cl_git_pass(git_attr_get_many(g_repo, "binfile", 5, names, values)); cl_git_pass(git_attr_get_many(g_repo, 0, "binfile", 5, names, values));
cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_TRUE(values[1])); cl_assert(GIT_ATTR_TRUE(values[1]));
...@@ -167,7 +168,7 @@ void test_attr_repo__macros(void) ...@@ -167,7 +168,7 @@ void test_attr_repo__macros(void)
cl_assert(GIT_ATTR_FALSE(values[3])); cl_assert(GIT_ATTR_FALSE(values[3]));
cl_assert(GIT_ATTR_UNSPECIFIED(values[4])); cl_assert(GIT_ATTR_UNSPECIFIED(values[4]));
cl_git_pass(git_attr_get_many(g_repo, "macro_test", 5, names2, values)); cl_git_pass(git_attr_get_many(g_repo, 0, "macro_test", 5, names2, values));
cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_TRUE(values[1])); cl_assert(GIT_ATTR_TRUE(values[1]));
...@@ -175,7 +176,7 @@ void test_attr_repo__macros(void) ...@@ -175,7 +176,7 @@ void test_attr_repo__macros(void)
cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
cl_assert_equal_s("77", values[4]); cl_assert_equal_s("77", values[4]);
cl_git_pass(git_attr_get_many(g_repo, "macro_test", 3, names3, values)); cl_git_pass(git_attr_get_many(g_repo, 0, "macro_test", 3, names3, values));
cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[0]));
cl_assert(GIT_ATTR_FALSE(values[1])); cl_assert(GIT_ATTR_FALSE(values[1]));
...@@ -188,7 +189,7 @@ void test_attr_repo__bad_macros(void) ...@@ -188,7 +189,7 @@ void test_attr_repo__bad_macros(void)
"firstmacro", "secondmacro", "thirdmacro" }; "firstmacro", "secondmacro", "thirdmacro" };
const char *values[6]; const char *values[6];
cl_git_pass(git_attr_get_many(g_repo, "macro_bad", 6, names, values)); cl_git_pass(git_attr_get_many(g_repo, 0, "macro_bad", 6, names, values));
/* these three just confirm that the "mymacro" rule ran */ /* these three just confirm that the "mymacro" rule ran */
cl_assert(GIT_ATTR_UNSPECIFIED(values[0])); cl_assert(GIT_ATTR_UNSPECIFIED(values[0]));
......
...@@ -5,7 +5,6 @@ static git_repository *g_repo = NULL; ...@@ -5,7 +5,6 @@ static git_repository *g_repo = NULL;
void test_diff_tree__initialize(void) void test_diff_tree__initialize(void)
{ {
g_repo = cl_git_sandbox_init("attr");
} }
void test_diff_tree__cleanup(void) void test_diff_tree__cleanup(void)
...@@ -19,15 +18,16 @@ void test_diff_tree__0(void) ...@@ -19,15 +18,16 @@ void test_diff_tree__0(void)
const char *a_commit = "605812a"; const char *a_commit = "605812a";
const char *b_commit = "370fe9ec22"; const char *b_commit = "370fe9ec22";
const char *c_commit = "f5b0af1fb4f5c"; const char *c_commit = "f5b0af1fb4f5c";
git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit); git_tree *a, *b, *c;
git_tree *b = resolve_commit_oid_to_tree(g_repo, b_commit);
git_tree *c = resolve_commit_oid_to_tree(g_repo, c_commit);
git_diff_options opts = {0}; git_diff_options opts = {0};
git_diff_list *diff = NULL; git_diff_list *diff = NULL;
diff_expects exp; diff_expects exp;
cl_assert(a); g_repo = cl_git_sandbox_init("attr");
cl_assert(b);
cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL);
opts.context_lines = 1; opts.context_lines = 1;
opts.interhunk_lines = 1; opts.interhunk_lines = 1;
...@@ -87,12 +87,7 @@ void test_diff_tree__options(void) ...@@ -87,12 +87,7 @@ void test_diff_tree__options(void)
const char *b_commit = "605812ab7fe421fdd"; const char *b_commit = "605812ab7fe421fdd";
const char *c_commit = "f5b0af1fb4f5"; const char *c_commit = "f5b0af1fb4f5";
const char *d_commit = "a97cc019851"; const char *d_commit = "a97cc019851";
git_tree *a, *b, *c, *d;
git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit);
git_tree *b = resolve_commit_oid_to_tree(g_repo, b_commit);
git_tree *c = resolve_commit_oid_to_tree(g_repo, c_commit);
git_tree *d = resolve_commit_oid_to_tree(g_repo, d_commit);
git_diff_options opts = {0}; git_diff_options opts = {0};
git_diff_list *diff = NULL; git_diff_list *diff = NULL;
diff_expects actual; diff_expects actual;
...@@ -133,8 +128,12 @@ void test_diff_tree__options(void) ...@@ -133,8 +128,12 @@ void test_diff_tree__options(void)
diff_expects *expected; diff_expects *expected;
int i; int i;
cl_assert(a); g_repo = cl_git_sandbox_init("attr");
cl_assert(b);
cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL);
cl_assert((d = resolve_commit_oid_to_tree(g_repo, d_commit)) != NULL);
for (i = 0; test_expects[i].files > 0; i++) { for (i = 0; test_expects[i].files > 0; i++) {
memset(&actual, 0, sizeof(actual)); /* clear accumulator */ memset(&actual, 0, sizeof(actual)); /* clear accumulator */
...@@ -168,3 +167,44 @@ void test_diff_tree__options(void) ...@@ -168,3 +167,44 @@ void test_diff_tree__options(void)
git_tree_free(c); git_tree_free(c);
git_tree_free(d); git_tree_free(d);
} }
void test_diff_tree__bare(void)
{
const char *a_commit = "8496071c1b46c85";
const char *b_commit = "be3563ae3f79";
git_tree *a, *b;
git_diff_options opts = {0};
git_diff_list *diff = NULL;
diff_expects exp;
g_repo = cl_git_sandbox_init("testrepo.git");
cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
opts.context_lines = 1;
opts.interhunk_lines = 1;
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_tree_to_tree(g_repo, &opts, a, b, &diff));
cl_git_pass(git_diff_foreach(
diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
cl_assert(exp.files == 3);
cl_assert(exp.file_adds == 2);
cl_assert(exp.file_dels == 0);
cl_assert(exp.file_mods == 1);
cl_assert(exp.hunks == 3);
cl_assert(exp.lines == 4);
cl_assert(exp.line_ctxt == 0);
cl_assert(exp.line_adds == 3);
cl_assert(exp.line_dels == 1);
git_diff_list_free(diff);
git_tree_free(a);
git_tree_free(b);
}
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
Unnamed repository; edit this file 'description' to name the repository.
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 refs/heads/master
0000000000000000000000000000000000000000 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer <rb@github.com> 1335817070 -0700 commit (initial): Initial commit
67c1640e91ccbaf0793591be09bf572cf40c9a53 d441d7d88f52c28c2b23940ce4c33756748425f9 Russell Belfer <rb@github.com> 1335817296 -0700 commit: Adding some files in subtrees
d441d7d88f52c28c2b23940ce4c33756748425f9 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer <rb@github.com> 1335817353 -0700 HEAD^: updating HEAD
67c1640e91ccbaf0793591be09bf572cf40c9a53 58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 Russell Belfer <rb@github.com> 1335817372 -0700 commit: Adding subtree data
0000000000000000000000000000000000000000 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer <rb@github.com> 1335817070 -0700 commit (initial): Initial commit
67c1640e91ccbaf0793591be09bf572cf40c9a53 d441d7d88f52c28c2b23940ce4c33756748425f9 Russell Belfer <rb@github.com> 1335817296 -0700 commit: Adding some files in subtrees
d441d7d88f52c28c2b23940ce4c33756748425f9 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer <rb@github.com> 1335817353 -0700 HEAD^: updating HEAD
67c1640e91ccbaf0793591be09bf572cf40c9a53 58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 Russell Belfer <rb@github.com> 1335817372 -0700 commit: Adding subtree data
P pack-4e6438607204ce78827e3885594b2c0bb4f13895.pack
# pack-refs with: peeled
58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 refs/heads/master
3812cfef36615db1788d4e63f90028007e17a348
This is contains tests for when the index and work dir differ
This contains files for testing when the index and the workdir differ
* bar
*.txt -foo beep=10
*.md blargh=goop -bar
...@@ -47,8 +47,8 @@ void test_status_ignore__0(void) ...@@ -47,8 +47,8 @@ void test_status_ignore__0(void)
} }
/* confirm that ignore files were cached */ /* confirm that ignore files were cached */
cl_assert(git_attr_cache__is_cached(g_repo, ".git/info/exclude")); cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/exclude"));
cl_assert(git_attr_cache__is_cached(g_repo, ".gitignore")); cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitignore"));
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment