diff options
| author | Russell Belfer <arrbee@arrbee.com> | 2012-01-09 15:37:19 -0800 |
|---|---|---|
| committer | Russell Belfer <arrbee@arrbee.com> | 2012-01-11 14:39:51 -0800 |
| commit | df743c7d3a04553ffc04ae7cbc64fb300e7f61d2 (patch) | |
| tree | 7f0dfa714ddb292448cbeaa69f2b5d90a3274d85 /src/attr_file.c | |
| parent | 7e443f696068cd8c84a759e532c2845348e5a6ad (diff) | |
| download | libgit2-df743c7d3a04553ffc04ae7cbc64fb300e7f61d2.tar.gz | |
Initial implementation of gitignore support
Adds support for .gitignore files to git_status_foreach() and
git_status_file(). This includes refactoring the gitattributes
code to share logic where possible. The GIT_STATUS_IGNORED flag
will now be passed in for files that are ignored (provided they
are not already in the index or the head of repo).
Diffstat (limited to 'src/attr_file.c')
| -rw-r--r-- | src/attr_file.c | 106 |
1 files changed, 54 insertions, 52 deletions
diff --git a/src/attr_file.c b/src/attr_file.c index fe8844e2d..5ea07c984 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -6,17 +6,29 @@ const char *git_attr__true = "[internal]__TRUE__"; const char *git_attr__false = "[internal]__FALSE__"; -static int git_attr_fnmatch__parse(git_attr_fnmatch *spec, const char **base); 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); -int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro) +int git_attr_file__new(git_attr_file **attrs_ptr) { - if (macro->assigns.length == 0) - return git__throw(GIT_EMISSINGOBJDATA, "git attribute macro with no values"); + int error; + git_attr_file *attrs = NULL; + + attrs = git__calloc(1, sizeof(git_attr_file)); + if (attrs == NULL) + error = GIT_ENOMEM; + else + error = git_vector_init(&attrs->rules, 4, NULL); + + if (error != GIT_SUCCESS) { + git__rethrow(error, "Could not allocate attribute storage"); + git__free(attrs); + attrs = NULL; + } + + *attrs_ptr = attrs; - return git_hashtable_insert( - repo->attrcache.macros, macro->match.pattern, macro); + return error; } int git_attr_file__from_buffer( @@ -29,17 +41,8 @@ int git_attr_file__from_buffer( *out = NULL; - attrs = git__calloc(1, sizeof(git_attr_file)); - if (attrs == NULL) - return git__throw(GIT_ENOMEM, "Could not allocate attribute storage"); - - attrs->path = NULL; - - error = git_vector_init(&attrs->rules, 4, NULL); - if (error != GIT_SUCCESS) { - git__rethrow(error, "Could not initialize attribute storage"); + if ((error = git_attr_file__new(&attrs)) < GIT_SUCCESS) goto cleanup; - } scan = buffer; @@ -166,19 +169,28 @@ int git_attr_file__lookup_one( } -int git_attr_rule__match_path( - git_attr_rule *rule, +int git_attr_fnmatch__match( + git_attr_fnmatch *match, const git_attr_path *path) { int matched = FNM_NOMATCH; - if (rule->match.flags & GIT_ATTR_FNMATCH_DIRECTORY && !path->is_dir) + if (match->flags & GIT_ATTR_FNMATCH_DIRECTORY && !path->is_dir) return matched; - if (rule->match.flags & GIT_ATTR_FNMATCH_FULLPATH) - matched = p_fnmatch(rule->match.pattern, path->path, FNM_PATHNAME); + if (match->flags & GIT_ATTR_FNMATCH_FULLPATH) + matched = p_fnmatch(match->pattern, path->path, FNM_PATHNAME); else - matched = p_fnmatch(rule->match.pattern, path->basename, 0); + matched = p_fnmatch(match->pattern, path->basename, 0); + + return matched; +} + +int git_attr_rule__match( + git_attr_rule *rule, + const git_attr_path *path) +{ + int matched = git_attr_fnmatch__match(&rule->match, path); if (rule->match.flags & GIT_ATTR_FNMATCH_NEGATIVE) matched = (matched == GIT_SUCCESS) ? FNM_NOMATCH : GIT_SUCCESS; @@ -186,6 +198,7 @@ int git_attr_rule__match_path( return matched; } + git_attr_assignment *git_attr_rule__lookup_assignment( git_attr_rule *rule, const char *name) { @@ -203,6 +216,7 @@ git_attr_assignment *git_attr_rule__lookup_assignment( int git_attr_path__init( git_attr_path *info, const char *path) { + assert(info && path); info->path = path; info->basename = strrchr(path, '/'); if (info->basename) @@ -251,23 +265,21 @@ int git_attr_path__init( * GIT_ENOTFOUND if the fnmatch does not require matching, or * another error code there was an actual problem. */ -static int git_attr_fnmatch__parse( +int git_attr_fnmatch__parse( git_attr_fnmatch *spec, const char **base) { - const char *pattern; - const char *scan; + const char *pattern, *scan; int slash_count; - int error = GIT_SUCCESS; - assert(base && *base); + assert(spec && base && *base); pattern = *base; while (isspace(*pattern)) pattern++; if (!*pattern || *pattern == '#') { - error = GIT_ENOTFOUND; - goto skip_to_eol; + *base = git__next_line(pattern); + return GIT_ENOTFOUND; } spec->flags = 0; @@ -276,11 +288,8 @@ static int git_attr_fnmatch__parse( if (strncmp(pattern, "[attr]", 6) == 0) { spec->flags = spec->flags | GIT_ATTR_FNMATCH_MACRO; pattern += 6; - } else { - /* unrecognized meta instructions - skip the line */ - error = GIT_ENOTFOUND; - goto skip_to_eol; } + /* else a character range like [a-e]* which is accepted */ } if (*pattern == '!') { @@ -290,6 +299,7 @@ static int git_attr_fnmatch__parse( slash_count = 0; for (scan = pattern; *scan != '\0'; ++scan) { + /* scan until (non-escaped) white space */ if (isspace(*scan) && *(scan - 1) != '\\') break; @@ -300,13 +310,15 @@ static int git_attr_fnmatch__parse( } *base = scan; + spec->length = scan - pattern; spec->pattern = git__strndup(pattern, spec->length); if (!spec->pattern) { - error = GIT_ENOMEM; - goto skip_to_eol; + *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 == '\\') { @@ -327,14 +339,6 @@ static int git_attr_fnmatch__parse( } return GIT_SUCCESS; - -skip_to_eol: - /* skip to end of line */ - while (*pattern && *pattern != '\n') pattern++; - if (*pattern == '\n') pattern++; - *base = pattern; - - return error; } static int sort_by_hash_and_name(const void *a_raw, const void *b_raw) @@ -494,10 +498,7 @@ int git_attr_assignment__parse( if (assign != NULL) git_attr_assignment__free(assign); - while (*scan && *scan != '\n') scan++; - if (*scan == '\n') scan++; - - *base = scan; + *base = git__next_line(scan); return error; } @@ -510,14 +511,15 @@ static void git_attr_rule__clear(git_attr_rule *rule) if (!rule) return; + if (!(rule->match.flags & GIT_ATTR_FNMATCH_IGNORE)) { + git_vector_foreach(&rule->assigns, i, assign) + GIT_REFCOUNT_DEC(assign, git_attr_assignment__free); + git_vector_free(&rule->assigns); + } + git__free(rule->match.pattern); rule->match.pattern = NULL; rule->match.length = 0; - - git_vector_foreach(&rule->assigns, i, assign) - GIT_REFCOUNT_DEC(assign, git_attr_assignment__free); - - git_vector_free(&rule->assigns); } void git_attr_rule__free(git_attr_rule *rule) |
