Hash :
1744fafe
Author :
Date :
2012-01-17T15:49:47
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
#include "ignore.h"
#include "path.h"
#include "git2/config.h"
#define GIT_IGNORE_INTERNAL "[internal]exclude"
#define GIT_IGNORE_FILE_INREPO "info/exclude"
#define GIT_IGNORE_FILE ".gitignore"
#define GIT_IGNORE_CONFIG "core.excludesfile"
static int load_ignore_file(
git_repository *GIT_UNUSED(repo), const char *path, git_attr_file **out)
{
int error = GIT_SUCCESS;
git_fbuffer fbuf = GIT_FBUFFER_INIT;
git_attr_file *ignores = NULL;
git_attr_fnmatch *match = NULL;
const char *scan = NULL;
GIT_UNUSED_ARG(repo);
*out = NULL;
if ((error = git_futils_readbuffer(&fbuf, path)) == GIT_SUCCESS)
error = git_attr_file__new(&ignores);
ignores->path = git__strdup(path);
scan = fbuf.data;
while (error == GIT_SUCCESS && *scan) {
if (!match && !(match = git__calloc(1, sizeof(git_attr_fnmatch)))) {
error = GIT_ENOMEM;
break;
}
if (!(error = git_attr_fnmatch__parse(match, &scan))) {
match->flags = match->flags | GIT_ATTR_FNMATCH_IGNORE;
scan = git__next_line(scan);
error = git_vector_insert(&ignores->rules, match);
}
if (error != GIT_SUCCESS) {
git__free(match->pattern);
match->pattern = NULL;
if (error == GIT_ENOTFOUND)
error = GIT_SUCCESS;
} else {
match = NULL; /* vector now "owns" the match */
}
}
git_futils_freebuffer(&fbuf);
git__free(match);
if (error != GIT_SUCCESS) {
git__rethrow(error, "Could not open ignore file '%s'", path);
git_attr_file__free(ignores);
} else {
*out = ignores;
}
return error;
}
#define push_ignore(R,S,B,F) \
git_attr_cache__push_file((R),(S),(B),(F),load_ignore_file)
typedef struct {
git_repository *repo;
git_vector *stack;
} ignore_walk_up_info;
static int push_one_ignore(void *ref, git_buf *path)
{
ignore_walk_up_info *info = (ignore_walk_up_info *)ref;
return push_ignore(info->repo, info->stack, path->ptr, GIT_IGNORE_FILE);
}
int git_ignore__for_path(git_repository *repo, const char *path, git_vector *stack)
{
int error = GIT_SUCCESS;
git_buf dir = GIT_BUF_INIT;
git_config *cfg;
const char *workdir = git_repository_workdir(repo);
ignore_walk_up_info info;
if ((error = git_attr_cache__init(repo)) < GIT_SUCCESS)
goto cleanup;
if ((error = git_path_find_dir(&dir, path, workdir)) < GIT_SUCCESS)
goto cleanup;
/* insert internals */
if ((error = push_ignore(repo, stack, NULL, GIT_IGNORE_INTERNAL)) < GIT_SUCCESS)
goto cleanup;
/* load .gitignore up the path */
info.repo = repo;
info.stack = stack;
if ((error = git_path_walk_up(&dir, workdir, push_one_ignore, &info)) < GIT_SUCCESS)
goto cleanup;
/* load .git/info/exclude */
if ((error = push_ignore(repo, stack, repo->path_repository, GIT_IGNORE_FILE_INREPO)) < GIT_SUCCESS)
goto cleanup;
/* load core.excludesfile */
if ((error = git_repository_config(&cfg, repo)) == GIT_SUCCESS) {
const char *core_ignore;
error = git_config_get_string(cfg, GIT_IGNORE_CONFIG, &core_ignore);
if (error == GIT_SUCCESS && core_ignore != NULL)
error = push_ignore(repo, stack, NULL, core_ignore);
else {
error = GIT_SUCCESS;
git_clearerror(); /* don't care if attributesfile is not set */
}
git_config_free(cfg);
}
cleanup:
if (error < GIT_SUCCESS)
git__rethrow(error, "Could not get ignore files for '%s'", path);
git_buf_free(&dir);
return error;
}
void git_ignore__free(git_vector *stack)
{
git_vector_free(stack);
}
int git_ignore__lookup(git_vector *stack, const char *pathname, int *ignored)
{
int error;
unsigned int i, j;
git_attr_file *file;
git_attr_path path;
git_attr_fnmatch *match;
if ((error = git_attr_path__init(&path, pathname)) < GIT_SUCCESS)
return git__rethrow(error, "Could not get attribute for '%s'", pathname);
*ignored = 0;
git_vector_foreach(stack, i, file) {
git_vector_rforeach(&file->rules, j, match) {
if (git_attr_fnmatch__match(match, &path) == GIT_SUCCESS) {
*ignored = ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0);
goto found;
}
}
}
found:
return error;
}