Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 Documentation/git-update-index.txt |   6 ++
 builtin/update-index.c             | 146 +++++++++++++++++++++++++++++++++++++
 2 files changed, 152 insertions(+)

diff --git a/Documentation/git-update-index.txt 
b/Documentation/git-update-index.txt
index 16f2686..fab1fea 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -180,6 +180,12 @@ may not support it yet.
        system must change `st_mtime` field of a directory if files
        are added or deleted in that directory.
 
+--force-untracked-cache::
+       For safety, `--untracked-cache` performs tests on the working
+       directory to make sure untracked cache can be used. These
+       tests can take a few seconds. `--force-untracked-cache` can be
+       used to skip the tests.
+
 \--::
        Do not interpret any more arguments as options.
 
diff --git a/builtin/update-index.c b/builtin/update-index.c
index e57e2d7..471c0b4 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -48,6 +48,145 @@ static void report(const char *fmt, ...)
        va_end(vp);
 }
 
+static void remove_test_directory(void)
+{
+       struct strbuf sb = STRBUF_INIT;
+       strbuf_addstr(&sb, "dir-mtime-test");
+       remove_dir_recursively(&sb, 0);
+       strbuf_release(&sb);
+}
+
+static void xmkdir(const char *path)
+{
+       if (mkdir(path, 0700))
+               die_errno(_("failed to create directory %s"), path);
+}
+
+static int xstat(const char *path, struct stat *st)
+{
+       if (stat(path, st))
+               die_errno(_("failed to stat %s"), path);
+       return 0;
+}
+
+static int create_file(const char *path)
+{
+       int fd = open(path, O_CREAT | O_RDWR, 0644);
+       if (fd < 0)
+               die_errno(_("failed to create file %s"), path);
+       return fd;
+}
+
+static void xunlink(const char *path)
+{
+       if (unlink(path))
+               die_errno(_("failed to delete file %s"), path);
+}
+
+static void xrmdir(const char *path)
+{
+       if (rmdir(path))
+               die_errno(_("failed to delete directory %s"), path);
+}
+
+static void avoid_racy(void)
+{
+       /*
+        * not use if we could usleep(10) if USE_NSEC is defined. The
+        * field nsec could be there, but the OS could choose to
+        * ignore it?
+        */
+       sleep(1);
+}
+
+static int test_if_untracked_cache_is_supported(void)
+{
+       struct stat st;
+       struct stat_data base;
+       int fd;
+
+       fprintf(stderr, _("Testing "));
+       xmkdir("dir-mtime-test");
+       atexit(remove_test_directory);
+       xstat("dir-mtime-test", &st);
+       fill_stat_data(&base, &st);
+       fputc('.', stderr);
+
+       avoid_racy();
+       fd = create_file("dir-mtime-test/newfile");
+       xstat("dir-mtime-test", &st);
+       if (!match_stat_data(&base, &st)) {
+               fputc('\n', stderr);
+               fprintf_ln(stderr,_("directory stat info does not "
+                                   "change after adding a new file"));
+               return 0;
+       }
+       fill_stat_data(&base, &st);
+       fputc('.', stderr);
+
+       avoid_racy();
+       xmkdir("dir-mtime-test/new-dir");
+       xstat("dir-mtime-test", &st);
+       if (!match_stat_data(&base, &st)) {
+               fputc('\n', stderr);
+               fprintf_ln(stderr, _("directory stat info does not change "
+                                    "after adding a new directory"));
+               return 0;
+       }
+       fill_stat_data(&base, &st);
+       fputc('.', stderr);
+
+       avoid_racy();
+       write_or_die(fd, "data", 4);
+       close(fd);
+       xstat("dir-mtime-test", &st);
+       if (match_stat_data(&base, &st)) {
+               fputc('\n', stderr);
+               fprintf_ln(stderr, _("directory stat info changes "
+                                    "after updating a file"));
+               return 0;
+       }
+       fputc('.', stderr);
+
+       avoid_racy();
+       close(create_file("dir-mtime-test/new-dir/new"));
+       xstat("dir-mtime-test", &st);
+       if (match_stat_data(&base, &st)) {
+               fputc('\n', stderr);
+               fprintf_ln(stderr, _("directory stat info changes after "
+                                    "adding a file inside subdirectory"));
+               return 0;
+       }
+       fputc('.', stderr);
+
+       avoid_racy();
+       xunlink("dir-mtime-test/newfile");
+       xstat("dir-mtime-test", &st);
+       if (!match_stat_data(&base, &st)) {
+               fputc('\n', stderr);
+               fprintf_ln(stderr, _("directory stat info does not "
+                                    "change after deleting a file"));
+               return 0;
+       }
+       fill_stat_data(&base, &st);
+       fputc('.', stderr);
+
+       avoid_racy();
+       xunlink("dir-mtime-test/new-dir/new");
+       xrmdir("dir-mtime-test/new-dir");
+       xstat("dir-mtime-test", &st);
+       if (!match_stat_data(&base, &st)) {
+               fputc('\n', stderr);
+               fprintf_ln(stderr, _("directory stat info does not "
+                                    "change after deleting a directory"));
+               return 0;
+       }
+
+       xrmdir("dir-mtime-test");
+       fprintf_ln(stderr, _(" OK"));
+       return 1;
+}
+
 static int mark_ce_flags(const char *path, int flag, int mark)
 {
        int namelen = strlen(path);
@@ -835,6 +974,8 @@ int cmd_update_index(int argc, const char **argv, const 
char *prefix)
                        N_("enable or disable split index")),
                OPT_BOOL(0, "untracked-cache", &untracked_cache,
                        N_("enable/disable untracked cache")),
+               OPT_SET_INT(0, "force-untracked-cache", &untracked_cache,
+                           N_("enable untracked cache without testing the 
filesystem"), 2),
                OPT_END()
        };
 
@@ -944,6 +1085,11 @@ int cmd_update_index(int argc, const char **argv, const 
char *prefix)
        if (untracked_cache > 0 && !the_index.untracked) {
                struct untracked_cache *uc;
 
+               if (untracked_cache < 2) {
+                       setup_work_tree();
+                       if (!test_if_untracked_cache_is_supported())
+                               return 1;
+               }
                uc = xcalloc(1, sizeof(*uc));
                uc->exclude_per_dir = ".gitignore";
                /* should be the same flags used by git-status */
-- 
2.1.0.rc0.78.gc0d8480

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to