Commit 37ab5ecc by Vicent Marti

Merge pull request #2269 from libgit2/rb/fix-leading-slash-ignores

Fix core.excludesfile named .gitignore
parents 0f7aa47d a9528b8f
......@@ -61,8 +61,7 @@ int git_attr_file__parse_buffer(
git_repository *repo, void *parsedata, const char *buffer, git_attr_file *attrs)
{
int error = 0;
const char *scan = NULL;
char *context = NULL;
const char *scan = NULL, *context = NULL;
git_attr_rule *rule = NULL;
GIT_UNUSED(parsedata);
......@@ -72,10 +71,10 @@ int git_attr_file__parse_buffer(
scan = buffer;
/* if subdir file path, convert context for file paths */
if (attrs->key && git__suffixcmp(attrs->key, "/" GIT_ATTR_FILE) == 0) {
if (attrs->key &&
git_path_root(attrs->key + 2) < 0 &&
git__suffixcmp(attrs->key, "/" GIT_ATTR_FILE) == 0)
context = attrs->key + 2;
context[strlen(context) - strlen(GIT_ATTR_FILE)] = '\0';
}
while (!error && *scan) {
/* allocate rule if needed */
......@@ -115,10 +114,6 @@ int git_attr_file__parse_buffer(
git_attr_rule__free(rule);
/* restore file path used for context */
if (context)
context[strlen(context)] = '.'; /* first char of GIT_ATTR_FILE */
return error;
}
......@@ -414,7 +409,10 @@ int git_attr_fnmatch__parse(
if ((spec->flags & GIT_ATTR_FNMATCH_FULLPATH) != 0 &&
source != NULL && git_path_root(pattern) < 0)
{
size_t sourcelen = strlen(source);
/* use context path minus the trailing filename */
char *slash = strrchr(source, '/');
size_t sourcelen = slash ? slash - source + 1 : 0;
/* given an unrooted fullpath match from a file inside a repo,
* prefix the pattern with the relative directory of the source file
*/
......
......@@ -14,8 +14,7 @@ static int parse_ignore_file(
{
int error = 0;
git_attr_fnmatch *match = NULL;
const char *scan = NULL;
char *context = NULL;
const char *scan = NULL, *context = NULL;
int ignore_case = false;
/* Prefer to have the caller pass in a git_ignores as the parsedata
......@@ -25,10 +24,10 @@ static int parse_ignore_file(
else if (git_repository__cvar(&ignore_case, repo, GIT_CVAR_IGNORECASE) < 0)
return error;
if (ignores->key && git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0) {
if (ignores->key &&
git_path_root(ignores->key + 2) < 0 &&
git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0)
context = ignores->key + 2;
context[strlen(context) - strlen(GIT_IGNORE_FILE)] = '\0';
}
scan = buffer;
......@@ -64,9 +63,6 @@ static int parse_ignore_file(
}
git__free(match);
/* restore file path used for context */
if (context)
context[strlen(context)] = '.'; /* first char of GIT_IGNORE_FILE */
return error;
}
......
......@@ -130,22 +130,18 @@ void test_attr_ignore__skip_gitignore_directory(void)
void test_attr_ignore__expand_tilde_to_homedir(void)
{
git_buf path = GIT_BUF_INIT;
git_buf cleanup = GIT_BUF_INIT;
git_config *cfg;
assert_is_ignored(false, "example.global_with_tilde");
/* construct fake home with fake global excludes */
cl_must_pass(p_mkdir("home", 0777));
cl_git_pass(git_path_prettify(&path, "home", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_fake_home(&cleanup);
cl_git_mkfile("home/globalexcludes", "# found me\n*.global_with_tilde\n");
/* construct fake home with fake global excludes */
cl_git_mkfile("home/globalexclude", "# found me\n*.global_with_tilde\n");
cl_git_pass(git_repository_config(&cfg, g_repo));
cl_git_pass(git_config_set_string(cfg, "core.excludesfile", "~/globalexcludes"));
cl_git_pass(git_config_set_string(cfg, "core.excludesfile", "~/globalexclude"));
git_config_free(cfg);
git_attr_cache_flush(g_repo); /* must reset to pick up change */
......@@ -154,8 +150,9 @@ void test_attr_ignore__expand_tilde_to_homedir(void)
cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, NULL));
cl_fake_home_cleanup(&cleanup);
git_buf_free(&path);
git_attr_cache_flush(g_repo); /* must reset to pick up change */
assert_is_ignored(false, "example.global_with_tilde");
}
......@@ -490,3 +490,24 @@ void clar__assert_equal_file(
clar__assert_equal(file, line, "mismatched file length", 1, "%"PRIuZ,
(size_t)expected_bytes, (size_t)total_bytes);
}
void cl_fake_home(git_buf *restore)
{
git_buf path = GIT_BUF_INIT;
cl_git_pass(git_libgit2_opts(
GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, restore));
cl_must_pass(p_mkdir("home", 0777));
cl_git_pass(git_path_prettify(&path, "home", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
git_buf_free(&path);
}
void cl_fake_home_cleanup(git_buf *restore)
{
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, restore->ptr));
git_buf_free(restore);
}
......@@ -120,4 +120,7 @@ int cl_repo_get_bool(git_repository *repo, const char *cfg);
void cl_repo_set_string(git_repository *repo, const char *cfg, const char *value);
void cl_fake_home(git_buf *restore);
void cl_fake_home_cleanup(git_buf *restore);
#endif
......@@ -364,6 +364,62 @@ void test_status_ignore__subdirectories_not_at_root(void)
cl_assert_equal_i(0, counts.wrong_sorted_path);
}
void test_status_ignore__leading_slash_ignores(void)
{
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
status_entry_counts counts;
git_buf home = GIT_BUF_INIT;
static const char *paths_2[] = {
"dir/.gitignore",
"dir/a/ignore_me",
"dir/b/ignore_me",
"dir/ignore_me",
"ignore_also/file",
"ignore_me",
"test/.gitignore",
"test/ignore_me/and_me/file",
"test/ignore_me/file",
"test/ignore_me/file2",
};
static const unsigned int statuses_2[] = {
GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
};
make_test_data();
cl_fake_home(&home);
cl_git_mkfile("home/.gitignore", "/ignore_me\n");
{
git_config *cfg;
cl_git_pass(git_repository_config(&cfg, g_repo));
cl_git_pass(git_config_set_string(
cfg, "core.excludesfile", "~/.gitignore"));
git_config_free(cfg);
}
cl_git_rewritefile("empty_standard_repo/.git/info/exclude", "/ignore_also\n");
cl_git_rewritefile("empty_standard_repo/dir/.gitignore", "/ignore_me\n");
cl_git_rewritefile("empty_standard_repo/test/.gitignore", "/and_me\n");
memset(&counts, 0x0, sizeof(status_entry_counts));
counts.expected_entry_count = 10;
counts.expected_paths = paths_2;
counts.expected_statuses = statuses_2;
opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
cl_git_pass(git_status_foreach_ext(
g_repo, &opts, cb_status__normal, &counts));
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
cl_assert_equal_i(0, counts.wrong_status_flags_count);
cl_assert_equal_i(0, counts.wrong_sorted_path);
cl_fake_home_cleanup(&home);
}
void test_status_ignore__adding_internal_ignores(void)
{
int ignored;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment