diff options
| author | Russell Belfer <arrbee@arrbee.com> | 2012-01-20 11:13:17 -0800 |
|---|---|---|
| committer | Russell Belfer <arrbee@arrbee.com> | 2012-01-20 11:13:17 -0800 |
| commit | 63ab73bec0a54300a48355ee28dd24ebd39e2cd2 (patch) | |
| tree | b341b54a3b37d30b799a886f15729f537993e8c7 /src | |
| parent | 9269ccce143578deec4d4e6e7755068f130abe96 (diff) | |
| parent | 83bfbdf593a76c591bb9cbd40cec6fca36c81a9c (diff) | |
| download | libgit2-63ab73bec0a54300a48355ee28dd24ebd39e2cd2.tar.gz | |
Merge branch 'fix-subdir-attr-paths' into development
This resolves issue #535 and issue #533.
Diffstat (limited to 'src')
| -rw-r--r-- | src/attr.c | 7 | ||||
| -rw-r--r-- | src/attr.h | 2 | ||||
| -rw-r--r-- | src/attr_file.c | 123 | ||||
| -rw-r--r-- | src/attr_file.h | 12 | ||||
| -rw-r--r-- | src/ignore.c | 28 |
5 files changed, 108 insertions, 64 deletions
diff --git a/src/attr.c b/src/attr.c index 984b04ff1..da0f72371 100644 --- a/src/attr.c +++ b/src/attr.c @@ -214,7 +214,7 @@ int git_attr_cache__push_file( git_vector *stack, const char *base, const char *filename, - int (*loader)(git_repository *, const char *, git_attr_file **)) + int (*loader)(git_repository *, const char *, git_attr_file *)) { int error = GIT_SUCCESS; git_attr_cache *cache = &repo->attrcache; @@ -231,11 +231,12 @@ int git_attr_cache__push_file( /* either get attr_file from cache or read from disk */ file = git_hashtable_lookup(cache->files, filename); if (file == NULL && git_path_exists(filename) == GIT_SUCCESS) { - error = (*loader)(repo, filename, &file); + if ((error = git_attr_file__new(&file)) == GIT_SUCCESS) + error = loader(repo, filename, file); add_to_cache = (error == GIT_SUCCESS); } - if (file != NULL) { + if (error == GIT_SUCCESS && file != NULL) { /* add file to vector, if we found it */ error = git_vector_insert(stack, file); diff --git a/src/attr.h b/src/attr.h index 5edff30d1..a758cc4bd 100644 --- a/src/attr.h +++ b/src/attr.h @@ -25,6 +25,6 @@ extern int git_attr_cache__push_file( git_vector *stack, const char *base, const char *filename, - int (*loader)(git_repository *, const char *, git_attr_file **)); + int (*loader)(git_repository *, const char *, git_attr_file *)); #endif diff --git a/src/attr_file.c b/src/attr_file.c index b38b35f01..5fd136c77 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -31,21 +31,46 @@ int git_attr_file__new(git_attr_file **attrs_ptr) return error; } +int git_attr_file__set_path( + 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); + } + + return (file->path == NULL) ? GIT_ENOMEM : GIT_SUCCESS; +} + int git_attr_file__from_buffer( - git_repository *repo, const char *buffer, git_attr_file **out) + git_repository *repo, const char *buffer, git_attr_file *attrs) { int error = GIT_SUCCESS; - git_attr_file *attrs = NULL; const char *scan = NULL; + char *context = NULL; git_attr_rule *rule = NULL; - *out = NULL; - - if ((error = git_attr_file__new(&attrs)) < GIT_SUCCESS) - goto cleanup; + assert(buffer && attrs); scan = buffer; + if (attrs->path && git__suffixcmp(attrs->path, GIT_ATTR_FILE) == 0) { + context = git__strndup(attrs->path, + strlen(attrs->path) - strlen(GIT_ATTR_FILE)); + if (!context) error = GIT_ENOMEM; + } + while (error == GIT_SUCCESS && *scan) { /* allocate rule if needed */ if (!rule && !(rule = git__calloc(1, sizeof(git_attr_rule)))) { @@ -54,7 +79,7 @@ int git_attr_file__from_buffer( } /* parse the next "pattern attr attr attr" line */ - if (!(error = git_attr_fnmatch__parse(&rule->match, &scan)) && + if (!(error = git_attr_fnmatch__parse(&rule->match, context, &scan)) && !(error = git_attr_assignment__parse(repo, &rule->assigns, &scan))) { if (rule->match.flags & GIT_ATTR_FNMATCH_MACRO) @@ -76,35 +101,30 @@ int git_attr_file__from_buffer( } } -cleanup: - if (error != GIT_SUCCESS) { - git_attr_rule__free(rule); - git_attr_file__free(attrs); - } else { - *out = attrs; - } + git_attr_rule__free(rule); + git__free(context); return error; } int git_attr_file__from_file( - git_repository *repo, const char *path, git_attr_file **out) + git_repository *repo, const char *path, git_attr_file *file) { int error = GIT_SUCCESS; git_fbuffer fbuf = GIT_FBUFFER_INIT; - *out = NULL; + assert(path && file); - if ((error = git_futils_readbuffer(&fbuf, path)) < GIT_SUCCESS || - (error = git_attr_file__from_buffer(repo, fbuf.data, out)) < GIT_SUCCESS) - { - git__rethrow(error, "Could not open attribute file '%s'", path); - } else { - /* save path (okay to fail) */ - (*out)->path = git__strdup(path); - } + if (file->path == NULL) + error = git_attr_file__set_path(repo, path, file); + + if (error == GIT_SUCCESS && + (error = git_futils_readbuffer(&fbuf, path)) == GIT_SUCCESS) + error = git_attr_file__from_buffer(repo, fbuf.data, file); git_futils_freebuffer(&fbuf); + if (error != GIT_SUCCESS) + git__rethrow(error, "Could not open attribute file '%s'", path); return error; } @@ -267,6 +287,7 @@ int git_attr_path__init( */ int git_attr_fnmatch__parse( git_attr_fnmatch *spec, + const char *source, const char **base) { const char *pattern, *scan; @@ -312,32 +333,50 @@ int git_attr_fnmatch__parse( *base = scan; spec->length = scan - pattern; - spec->pattern = git__strndup(pattern, spec->length); - - if (!spec->pattern) { - *base = git__next_line(pattern); - return GIT_ENOMEM; - } else { - /* remove '\' that might have be used for internal whitespace */ - char *from = spec->pattern, *to = spec->pattern; - while (*from) { - if (*from == '\\') { - from++; - spec->length--; - } - *to++ = *from++; - } - *to = '\0'; - } if (pattern[spec->length - 1] == '/') { spec->length--; - spec->pattern[spec->length] = '\0'; spec->flags = spec->flags | GIT_ATTR_FNMATCH_DIRECTORY; if (--slash_count <= 0) spec->flags = spec->flags & ~GIT_ATTR_FNMATCH_FULLPATH; } + if ((spec->flags & GIT_ATTR_FNMATCH_FULLPATH) != 0 && + source != NULL && git_path_root(pattern) < 0) + { + size_t sourcelen = strlen(source); + /* given an unrooted fullpath match from a file inside a repo, + * prefix the pattern with the relative directory of the source file + */ + spec->pattern = git__malloc(sourcelen + spec->length + 1); + if (spec->pattern) { + memcpy(spec->pattern, source, sourcelen); + memcpy(spec->pattern + sourcelen, pattern, spec->length); + spec->length += sourcelen; + spec->pattern[spec->length] = '\0'; + } + } else { + spec->pattern = git__strndup(pattern, spec->length); + } + + if (!spec->pattern) { + *base = git__next_line(pattern); + return GIT_ENOMEM; + } else { + /* strip '\' that might have be used for internal whitespace */ + char *to = spec->pattern; + for (scan = spec->pattern; *scan; to++, scan++) { + if (*scan == '\\') + scan++; /* skip '\' but include next char */ + if (to != scan) + *to = *scan; + } + if (to != scan) { + *to = '\0'; + spec->length = (to - spec->pattern); + } + } + return GIT_SUCCESS; } diff --git a/src/attr_file.h b/src/attr_file.h index 7190c4c7b..304c7a854 100644 --- a/src/attr_file.h +++ b/src/attr_file.h @@ -62,13 +62,16 @@ typedef struct { * git_attr_file API */ +extern int git_attr_file__new(git_attr_file **attrs_ptr); +extern void git_attr_file__free(git_attr_file *file); + extern int git_attr_file__from_buffer( - git_repository *repo, const char *buf, git_attr_file **out); + 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 **out); + git_repository *repo, const char *path, git_attr_file *file); -extern int git_attr_file__new(git_attr_file **attrs_ptr); -extern void git_attr_file__free(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( git_attr_file *file, @@ -90,6 +93,7 @@ extern unsigned long git_attr_file__name_hash(const char *name); extern int git_attr_fnmatch__parse( git_attr_fnmatch *spec, + const char *source, const char **base); extern int git_attr_fnmatch__match( diff --git a/src/ignore.c b/src/ignore.c index 8e0b8a0ff..516da645c 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -8,22 +8,25 @@ #define GIT_IGNORE_CONFIG "core.excludesfile" static int load_ignore_file( - git_repository *GIT_UNUSED(repo), const char *path, git_attr_file **out) + git_repository *repo, const char *path, git_attr_file *ignores) { int error = GIT_SUCCESS; git_fbuffer fbuf = GIT_FBUFFER_INIT; - git_attr_file *ignores = NULL; git_attr_fnmatch *match = NULL; const char *scan = NULL; + char *context = NULL; - GIT_UNUSED_ARG(repo); + if (ignores->path == NULL) + error = git_attr_file__set_path(repo, path, ignores); - *out = NULL; - - if ((error = git_futils_readbuffer(&fbuf, path)) == GIT_SUCCESS) - error = git_attr_file__new(&ignores); + if (git__suffixcmp(ignores->path, GIT_IGNORE_FILE) == 0) { + context = git__strndup(ignores->path, + strlen(ignores->path) - strlen(GIT_IGNORE_FILE)); + if (!context) error = GIT_ENOMEM; + } - ignores->path = git__strdup(path); + if (error == GIT_SUCCESS) + error = git_futils_readbuffer(&fbuf, path); scan = fbuf.data; @@ -33,7 +36,7 @@ static int load_ignore_file( break; } - if (!(error = git_attr_fnmatch__parse(match, &scan))) { + if (!(error = git_attr_fnmatch__parse(match, context, &scan))) { match->flags = match->flags | GIT_ATTR_FNMATCH_IGNORE; scan = git__next_line(scan); error = git_vector_insert(&ignores->rules, match); @@ -52,13 +55,10 @@ static int load_ignore_file( git_futils_freebuffer(&fbuf); git__free(match); + git__free(context); - if (error != GIT_SUCCESS) { + if (error != GIT_SUCCESS) git__rethrow(error, "Could not open ignore file '%s'", path); - git_attr_file__free(ignores); - } else { - *out = ignores; - } return error; } |
