summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRussell Belfer <arrbee@arrbee.com>2012-01-20 11:13:17 -0800
committerRussell Belfer <arrbee@arrbee.com>2012-01-20 11:13:17 -0800
commit63ab73bec0a54300a48355ee28dd24ebd39e2cd2 (patch)
treeb341b54a3b37d30b799a886f15729f537993e8c7 /src
parent9269ccce143578deec4d4e6e7755068f130abe96 (diff)
parent83bfbdf593a76c591bb9cbd40cec6fca36c81a9c (diff)
downloadlibgit2-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.c7
-rw-r--r--src/attr.h2
-rw-r--r--src/attr_file.c123
-rw-r--r--src/attr_file.h12
-rw-r--r--src/ignore.c28
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;
}