From ec1b878264679abcfe4d063f23c3c6ab3475ba7f Mon Sep 17 00:00:00 2001 From: Jiaqiang Xu Date: Thu, 6 Jun 2013 11:50:11 +0800 Subject: [PATCH] [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. --- daemon/repo-mgr.c | 79 +++++++++++++++++++++++++++++------------------ daemon/repo-mgr.h | 11 +++++-- daemon/status.c | 24 +++++++++----- daemon/status.h | 3 +- 4 files changed, 75 insertions(+), 42 deletions(-) diff --git a/daemon/repo-mgr.c b/daemon/repo-mgr.c index bf9924b6..25b37982 100644 --- a/daemon/repo-mgr.c +++ b/daemon/repo-mgr.c @@ -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 */ diff --git a/daemon/repo-mgr.h b/daemon/repo-mgr.h index f3820a72..ba1ca962 100644 --- a/daemon/repo-mgr.h +++ b/daemon/repo-mgr.h @@ -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 diff --git a/daemon/status.c b/daemon/status.c index 4c4f5270..f234ff9b 100644 --- a/daemon/status.c +++ b/daemon/status.c @@ -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 * diff --git a/daemon/status.h b/daemon/status.h index bfa33130..f0bf9c43 100644 --- a/daemon/status.h +++ b/daemon/status.h @@ -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,