goto finish;
}
- if (!file &&
- (error = git_attr_file__new(&file, source, relfile, &cache->pool)) < 0)
- goto finish;
+ /* if we got here, we have to parse and/or reparse the file */
+ if (file)
+ git_attr_file__clear_rules(file);
+ else {
+ error = git_attr_file__new(&file, source, relfile, &cache->pool);
+ if (error < 0)
+ goto finish;
+ }
if (parse && (error = parse(repo, content, file)) < 0)
goto finish;
return error;
}
-void git_attr_file__free(git_attr_file *file)
+void git_attr_file__clear_rules(git_attr_file *file)
{
unsigned int i;
git_attr_rule *rule;
- if (!file)
- return;
-
git_vector_foreach(&file->rules, i, rule)
git_attr_rule__free(rule);
git_vector_free(&file->rules);
+}
+
+void git_attr_file__free(git_attr_file *file)
+{
+ if (!file)
+ return;
+
+ git_attr_file__clear_rules(file);
if (file->pool_is_allocated) {
git_pool_clear(file->pool);
const char **base)
{
const char *pattern, *scan;
- int slash_count;
+ int slash_count, allow_space;
assert(spec && base && *base);
+ spec->flags = (spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE);
+ allow_space = (spec->flags != 0);
+
pattern = *base;
while (git__isspace(*pattern)) pattern++;
return GIT_ENOTFOUND;
}
- spec->flags = 0;
-
if (*pattern == '[') {
if (strncmp(pattern, "[attr]", 6) == 0) {
spec->flags = spec->flags | GIT_ATTR_FNMATCH_MACRO;
slash_count = 0;
for (scan = pattern; *scan != '\0'; ++scan) {
/* scan until (non-escaped) white space */
- if (git__isspace(*scan) && *(scan - 1) != '\\')
- break;
+ if (git__isspace(*scan) && *(scan - 1) != '\\') {
+ if (!allow_space || (*scan != ' ' && *scan != '\t'))
+ break;
+ }
if (*scan == '/') {
spec->flags = spec->flags | GIT_ATTR_FNMATCH_FULLPATH;
#define GIT_ATTR_FNMATCH_MACRO (1U << 3)
#define GIT_ATTR_FNMATCH_IGNORE (1U << 4)
#define GIT_ATTR_FNMATCH_HASWILD (1U << 5)
+#define GIT_ATTR_FNMATCH_ALLOWSPACE (1U << 6)
typedef struct {
char *pattern;
extern void git_attr_file__free(git_attr_file *file);
+extern void git_attr_file__clear_rules(git_attr_file *file);
+
extern int git_attr_file__parse_buffer(
git_repository *repo, const char *buf, git_attr_file *file);
git_attr_fnmatch *match = git__calloc(1, sizeof(git_attr_fnmatch));
if (!match)
goto fail;
+ match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE;
ret = git_attr_fnmatch__parse(match, &diff->pool, NULL, &pattern);
if (ret == GIT_ENOTFOUND) {
git__free(match);
GIT_INLINE(void) attr_check_expected(
enum attr_expect_t expected,
const char *expected_str,
+ const char *name,
const char *value)
{
switch (expected) {
case EXPECT_TRUE:
- cl_assert(GIT_ATTR_TRUE(value));
+ cl_assert_(GIT_ATTR_TRUE(value), name);
break;
case EXPECT_FALSE:
- cl_assert(GIT_ATTR_FALSE(value));
+ cl_assert_(GIT_ATTR_FALSE(value), name);
break;
case EXPECT_UNDEFINED:
- cl_assert(GIT_ATTR_UNSPECIFIED(value));
+ cl_assert_(GIT_ATTR_UNSPECIFIED(value), name);
break;
case EXPECT_STRING:
cl_assert_equal_s(name, assign->name);
cl_assert(assign->name_hash == git_attr_file__name_hash(assign->name));
- attr_check_expected(expected, expected_str, assign->value);
+ attr_check_expected(expected, expected_str, assign->name, assign->value);
}
void test_attr_file__assign_variants(void)
error = git_attr_file__lookup_one(file,&path,c->attr,&value);
cl_git_pass(error);
- attr_check_expected(c->expected, c->expected_str, value);
+ attr_check_expected(c->expected, c->expected_str, c->attr, value);
git_attr_path__free(&path);
}
for (scan = test_cases; scan->path != NULL; scan++) {
const char *value;
cl_git_pass(git_attr_get(&value, g_repo, 0, scan->path, scan->attr));
- attr_check_expected(scan->expected, scan->expected_str, value);
+ attr_check_expected(scan->expected, scan->expected_str, scan->attr, value);
}
cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/attributes"));
#endif
-static char *env_home = NULL;
+#ifdef GIT_WIN32
static char *env_userprofile = NULL;
+#else
+static char *env_home = NULL;
+#endif
void test_core_env__initialize(void)
{
cl_git_pass(p_rmdir("wd"));
cl_git_pass(p_unlink("my-index"));
}
+
+
+void test_status_worktree__space_in_filename(void)
+{
+ git_repository *repo;
+ git_index *index;
+ status_entry_single result;
+ unsigned int status_flags;
+
+#define FILE_WITH_SPACE "LICENSE - copy.md"
+
+ cl_git_pass(git_repository_init(&repo, "with_space", 0));
+ cl_git_mkfile("with_space/" FILE_WITH_SPACE, "I have a space in my name\n");
+
+ /* file is new to working directory */
+
+ memset(&result, 0, sizeof(result));
+ cl_git_pass(git_status_foreach(repo, cb_status__single, &result));
+ cl_assert_equal_i(1, result.count);
+ cl_assert(result.status == GIT_STATUS_WT_NEW);
+
+ cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE));
+ cl_assert(status_flags == GIT_STATUS_WT_NEW);
+
+ /* ignore the file */
+
+ cl_git_rewritefile("with_space/.gitignore", "*.md\n.gitignore\n");
+
+ memset(&result, 0, sizeof(result));
+ cl_git_pass(git_status_foreach(repo, cb_status__single, &result));
+ cl_assert_equal_i(2, result.count);
+ cl_assert(result.status == GIT_STATUS_IGNORED);
+
+ cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE));
+ cl_assert(status_flags == GIT_STATUS_IGNORED);
+
+ /* don't ignore the file */
+
+ cl_git_rewritefile("with_space/.gitignore", ".gitignore\n");
+
+ memset(&result, 0, sizeof(result));
+ cl_git_pass(git_status_foreach(repo, cb_status__single, &result));
+ cl_assert_equal_i(2, result.count);
+ cl_assert(result.status == GIT_STATUS_WT_NEW);
+
+ cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE));
+ cl_assert(status_flags == GIT_STATUS_WT_NEW);
+
+ /* add the file to the index */
+
+ cl_git_pass(git_repository_index(&index, repo));
+ cl_git_pass(git_index_add(index, FILE_WITH_SPACE, 0));
+ cl_git_pass(git_index_write(index));
+
+ memset(&result, 0, sizeof(result));
+ cl_git_pass(git_status_foreach(repo, cb_status__single, &result));
+ cl_assert_equal_i(2, result.count);
+ cl_assert(result.status == GIT_STATUS_INDEX_NEW);
+
+ cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE));
+ cl_assert(status_flags == GIT_STATUS_INDEX_NEW);
+
+ git_index_free(index);
+ git_repository_free(repo);
+}