[client] Improve ignore file.

Ignore local changes to ignored files.

Consider the following sequence:
1. a file is committed;
2. this file is added to seafile-ignore.txt so it's ignored from now on;
3. this file is changed;

If we don't ignore changes to this file, the worktree will be left in
an unclean state and pauses sync.

The same rule also applies for files under an ignored folder.

To make it easier to check whether a file is under an ignored folder,
we have to apply a restriction:
If you want to ignore folder 'foo', you write 'foo/' in seafile-ignore.txt.
Writing 'foo' will only ignore regular files or symlinks.
This commit is contained in:
Jiaqiang Xu 2013-06-06 11:50:11 +08:00
parent 66e1657e83
commit ec1b878264
4 changed files with 75 additions and 42 deletions

View File

@ -326,7 +326,7 @@ static gboolean
should_ignore(const char *basepath, const char *filename, void *data)
{
GPatternSpec **spec = ignore_patterns;
GList *p, *ignore_list = (GList *)data;
GList *ignore_list = (GList *)data;
/* Ignore file/dir if its name is too long. */
if (strlen(filename) >= SEAF_DIR_NAME_LEN)
@ -358,9 +358,6 @@ should_ignore(const char *basepath, const char *filename, void *data)
int i;
char c;
char *str;
GPatternSpec *ignore_spec;
SeafStat st;
for (i = 0; i < G_N_ELEMENTS(illegals); i++) {
if (strchr (filename, illegals[i])) {
@ -373,33 +370,14 @@ should_ignore(const char *basepath, const char *filename, void *data)
return TRUE;
}
}
/* Ignore files in ignore.txt */
str = g_build_filename(basepath, filename, NULL);
/* first check the path is a reg file or a dir */
if (seaf_stat(str, &st) < 0) {
g_free(str);
char *fullpath = g_build_path ("/", basepath, filename, NULL);
if (seaf_repo_check_ignore_file (ignore_list, fullpath)) {
g_free (fullpath);
return TRUE;
}
if (S_ISDIR(st.st_mode)) {
g_free(str);
str = g_build_filename(basepath, filename, "/", NULL);
}
g_free (fullpath);
for (p = ignore_list; p != NULL; p = p->next) {
char *pattern = (char *)p->data;
ignore_spec = g_pattern_spec_new(pattern);
if (g_pattern_match_string(ignore_spec, str)) {
g_free(str);
g_pattern_spec_free(ignore_spec);
return TRUE;
}
g_pattern_spec_free(ignore_spec);
}
g_free(str);
return FALSE;
}
@ -689,8 +667,7 @@ seaf_repo_is_worktree_changed (SeafRepo *repo)
}
repo->index_corrupted = FALSE;
wt_status_collect_changes_worktree (&istate, &res,
repo->worktree, should_ignore);
wt_status_collect_changes_worktree (&istate, &res, repo->worktree);
if (res != NULL)
goto changed;
@ -2779,7 +2756,13 @@ GList *seaf_repo_load_ignore_files (const char *worktree)
/* trim the last '\n' character */
path[strlen(path)-1] = '\0';
pattern = g_strdup_printf("%s/%s", worktree, path);
/* Change 'foo/' to 'foo/ *'. */
if (path[strlen(path)-1] == '/')
pattern = g_strdup_printf("%s/%s*", worktree, path);
else
pattern = g_strdup_printf("%s/%s", worktree, path);
list = g_list_prepend(list, g_strdup(pattern));
}
@ -2792,6 +2775,42 @@ error:
return NULL;
}
gboolean
seaf_repo_check_ignore_file (GList *ignore_list, const char *fullpath)
{
char *str;
SeafStat st;
GPatternSpec *ignore_spec;
GList *p;
str = g_strdup(fullpath);
/* first check the path is a reg file or a dir */
if (seaf_stat(str, &st) < 0) {
g_free(str);
return TRUE;
}
if (S_ISDIR(st.st_mode)) {
g_free(str);
str = g_strconcat (fullpath, "/", NULL);
}
for (p = ignore_list; p != NULL; p = p->next) {
char *pattern = (char *)p->data;
ignore_spec = g_pattern_spec_new(pattern);
if (g_pattern_match_string(ignore_spec, str)) {
g_free (str);
g_pattern_spec_free(ignore_spec);
return TRUE;
}
g_pattern_spec_free(ignore_spec);
}
g_free (str);
return FALSE;
}
/*
* Free ignored file list
*/

View File

@ -348,6 +348,13 @@ seaf_repo_manager_update_repo_relay_info (SeafRepoManager *mgr,
const char *new_addr,
const char *new_port);
GList *seaf_repo_load_ignore_files (const char *worktree);
void seaf_repo_free_ignore_files (GList *ignore_list);
GList *
seaf_repo_load_ignore_files (const char *worktree);
gboolean
seaf_repo_check_ignore_file (GList *ignore_list, const char *fullpath);
void
seaf_repo_free_ignore_files (GList *ignore_list);
#endif

View File

@ -230,12 +230,13 @@ is_empty_dir (const char *path, IgnoreFunc should_ignore)
void wt_status_collect_changes_worktree(struct index_state *index,
GList **results,
const char *worktree,
IgnoreFunc ignore_func)
const char *worktree)
{
DiffEntry *de;
int entries, i;
GList *ignore_list = seaf_repo_load_ignore_files (worktree);
entries = index->cache_nr;
for (i = 0; i < entries; i++) {
char *realpath;
@ -301,15 +302,20 @@ void wt_status_collect_changes_worktree(struct index_state *index,
}
if (S_ISDIR (ce->ce_mode)) {
/* if (!S_ISDIR (st.st_mode) || */
/* !is_empty_dir (realpath, ignore_func)) { */
/* de = diff_entry_new (DIFF_TYPE_WORKTREE, DIFF_STATUS_DIR_DELETED, */
/* ce->sha1, ce->name); */
/* *results = g_list_prepend (*results, de); */
/* } */
g_free (realpath);
continue;
}
/* Don't check changes to ignored files.
* This can happen when a file is committed and then added to
* ignore.txt. After that changes to this file will not committed,
* and it should be ignored here.
*/
if (seaf_repo_check_ignore_file (ignore_list, realpath)) {
g_free (realpath);
continue;
}
g_free (realpath);
changed = ie_match_stat (index, ce, &st, 0);
@ -322,6 +328,8 @@ void wt_status_collect_changes_worktree(struct index_state *index,
ce->sha1, ce->name);
*results = g_list_prepend (*results, de);
}
seaf_repo_free_ignore_files (ignore_list);
}
static struct cache_entry *

View File

@ -12,8 +12,7 @@ typedef gboolean (*IgnoreFunc) (const char *basepath, const char *filename, void
void
wt_status_collect_changes_worktree(struct index_state *index,
GList **results,
const char *worktree,
IgnoreFunc ignore_func);
const char *worktree);
void
wt_status_collect_untracked(struct index_state *index,