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

diff --git a/Documentation/git-update-index.txt 
b/Documentation/git-update-index.txt
index f9a35cd..ed32bae 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 3d2dedd..f23ec83 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -47,6 +47,147 @@ 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)) {
+               close(fd);
+               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)) {
+               close(fd);
+               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);
@@ -834,6 +975,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()
        };
 
@@ -943,6 +1086,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.2.0.60.gb7b3c64

--
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