[PATCH v7 00/29] Builtin FSMonitor Part 2
- From
- Jeff Hostetler via GitGitGadget <gitgitgadget@gmail.com>
- Date
- Mar 22, 2022, 17:59 UTC
- Message-ID
- <pull.1041.v7.git.1647972010.gitgitgadget@gmail.com>
- In-Reply-To
- <pull.1041.v6.git.1646160212.gitgitgadget@gmail.com>
Here is V7 of Part 2 of my builtin FSmonitor series. This version squashes in the fixups from Part 2.5 and any other last minute suggestions. I'll send an updated version of Part 3 that builds upon this version.
Here is a range-diff from V6 to V7 relative to 715d08a9e5 (The eighth batch, 2022-02-25). Changes since V6 can be summarized as: (1) Adding/removing "_()" on die() and error() messages. (2) Splitting GCC-specific declarations for MacOS FSEvents into a separate header file. (3) Enhancing the "start_daemon()" function in t7527 to take keyword args and reduce some code duplication in unit tests. (4) Fixing "&&" chains in the tests. (5) Other minor style cleanups.
$ git range-diff eight..builtin-fsmonitor-part2-v6 eight..builtin-fsmonitor-part2
1: 10a34082fc = 1: e98373f997 fsmonitor: enhance existing comments, clarify trivial response handling
2: e1c946af2c ! 2: ab68b94417 fsmonitor-ipc: create client routines for git-fsmonitor--daemon
@@ fsmonitor-ipc.c (new)
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
+ &connection);
+ if (state != IPC_STATE__LISTENING) {
-+ die("fsmonitor--daemon is not running");
++ die(_("fsmonitor--daemon is not running"));
+ return -1;
+ }
+
@@ fsmonitor-ipc.c (new)
+ ipc_client_close_connection(connection);
+
+ if (ret == -1) {
-+ die("could not send '%s' command to fsmonitor--daemon", c);
++ die(_("could not send '%s' command to fsmonitor--daemon"), c);
+ return -1;
+ }
+
3: ae622a517c ! 3: e04c7301f2 fsmonitor: config settings are repository-specific
@@ fsmonitor-settings.c (new)
+ return;
+
+ CALLOC_ARRAY(s, 1);
++ s->mode = FSMONITOR_MODE_DISABLED;
+
+ r->settings.fsmonitor = s;
+
-+ fsm_settings__set_disabled(r);
-+
+ /*
+ * Overload the existing "core.fsmonitor" config setting (which
+ * has historically been either unset or a hook pathname) to
4: 55974867da = 4: ea02ba25d8 fsmonitor: use IPC to query the builtin FSMonitor daemon
5: ce42d5bbaf = 5: 6ab7db9cb7 fsmonitor: document builtin fsmonitor
6: 9ce938c69b = 6: 0ce8ae3f2c fsmonitor--daemon: add a built-in fsmonitor daemon
7: 3bd7e6a051 = 7: 4624ce2fa4 fsmonitor--daemon: implement 'stop' and 'status' commands
8: 92d3e54da7 = 8: a29fe7266a compat/fsmonitor/fsm-listen-win32: stub in backend for Windows
9: f121922127 = 9: 2f8a42fdb9 compat/fsmonitor/fsm-listen-darwin: stub in backend for Darwin
10: a3f94627cf ! 10: f07800690e fsmonitor--daemon: implement 'run' command
@@ builtin/fsmonitor--daemon.c: static int do_as_client__status(void)
+ * common error case.
+ */
+ if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
-+ die("fsmonitor--daemon is already running '%s'",
++ die(_("fsmonitor--daemon is already running '%s'"),
+ the_repository->worktree);
+
+ if (fsmonitor__announce_startup) {
11: 8de40b0fe8 ! 11: a6a39a3306 fsmonitor--daemon: implement 'start' command
@@ builtin/fsmonitor--daemon.c: static int try_to_run_foreground_daemon(void)
+ * immediately exited).
+ */
+ if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
-+ die("fsmonitor--daemon is already running '%s'",
++ die(_("fsmonitor--daemon is already running '%s'"),
+ the_repository->worktree);
+
+ if (fsmonitor__announce_startup) {
@@ builtin/fsmonitor--daemon.c: static int try_to_run_foreground_daemon(void)
+ default:
+ case SBGR_ERROR:
+ case SBGR_CB_ERROR:
-+ return error("daemon failed to start");
++ return error(_("daemon failed to start"));
+
+ case SBGR_TIMEOUT:
-+ return error("daemon not online yet");
++ return error(_("daemon not online yet"));
+
+ case SBGR_DIED:
-+ return error("daemon terminated");
++ return error(_("daemon terminated"));
+ }
+}
+
12: e5d419b1ea = 12: d62e338d00 fsmonitor--daemon: add pathname classification
13: c2f3668a86 = 13: 53e06b4ae5 fsmonitor--daemon: define token-ids
14: bd492d13fb = 14: 39f43fabe0 fsmonitor--daemon: create token-based changed path cache
15: 6b5b3d0822 ! 15: 239558e34f compat/fsmonitor/fsm-listen-win32: implement FSMonitor backend on Windows
@@ compat/fsmonitor/fsm-listen-win32.c
+ if (len > 0)
+ goto normalize;
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
-+ error("[GLE %ld] could not convert path to UTF-8: '%.*ls'",
++ error(_("[GLE %ld] could not convert path to UTF-8: '%.*ls'"),
+ GetLastError(),
+ (int)(info->FileNameLength / sizeof(WCHAR)),
+ info->FileName);
@@ compat/fsmonitor/fsm-listen-win32.c
+ if (watch->is_active)
+ return 0;
+
-+ error("ReadDirectoryChangedW failed on '%s' [GLE %ld]",
++ error(_("ReadDirectoryChangedW failed on '%s' [GLE %ld]"),
+ watch->path.buf, GetLastError());
+ return -1;
+}
@@ compat/fsmonitor/fsm-listen-win32.c
+ * sure it is worth it.
+ */
+
-+ error("GetOverlappedResult failed on '%s' [GLE %ld]",
++ error(_("GetOverlappedResult failed on '%s' [GLE %ld]"),
+ watch->path.buf, gle);
+ return -1;
+}
16: cdef9730b3 ! 16: 14b775e9d8 compat/fsmonitor/fsm-listen-darwin: add MacOS header files for FSEvent
@@ Commit message
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
- ## compat/fsmonitor/fsm-listen-darwin.c ##
+ ## compat/fsmonitor/fsm-darwin-gcc.h (new) ##
@@
++#ifndef FSM_DARWIN_GCC_H
++#define FSM_DARWIN_GCC_H
++
+#ifndef __clang__
+/*
+ * It is possible to #include CoreFoundation/CoreFoundation.h when compiling
@@ compat/fsmonitor/fsm-listen-darwin.c
+void FSEventStreamStop(FSEventStreamRef stream);
+void FSEventStreamInvalidate(FSEventStreamRef stream);
+void FSEventStreamRelease(FSEventStreamRef stream);
++
++#endif /* !clang */
++#endif /* FSM_DARWIN_GCC_H */
+
+ ## compat/fsmonitor/fsm-listen-darwin.c ##
+@@
++#ifndef __clang__
++#include "fsm-darwin-gcc.h"
+#else
-+/*
-+ * Let Apple's headers declare `isalnum()` first, before
-+ * Git's headers override it via a constant
-+ */
-+#include <string.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
++
++#ifndef AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER
++/*
++ * This enum value was added in 10.13 to:
++ *
++ * /Applications/Xcode.app/Contents/Developer/Platforms/ \
++ * MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/ \
++ * Library/Frameworks/CoreServices.framework/Frameworks/ \
++ * FSEvents.framework/Versions/Current/Headers/FSEvents.h
++ *
++ * If we're compiling against an older SDK, this symbol won't be
++ * present. Silently define it here so that we don't have to ifdef
++ * the logging or masking below. This should be harmless since older
++ * versions of macOS won't ever emit this FS event anyway.
++ */
++#define kFSEventStreamEventFlagItemCloned 0x00400000
++#endif
+#endif
+
#include "cache.h"
17: aabfebd3a4 ! 17: 55bd7aee06 compat/fsmonitor/fsm-listen-darwin: implement FSEvent listener on MacOS
@@ Commit message
Signed-off-by: Junio C Hamano <gitster@pobox.com>
## compat/fsmonitor/fsm-listen-darwin.c ##
-@@ compat/fsmonitor/fsm-listen-darwin.c: void FSEventStreamRelease(FSEventStreamRef stream);
+@@
#include "cache.h"
#include "fsmonitor.h"
#include "fsm-listen.h"
@@ compat/fsmonitor/fsm-listen-darwin.c: void FSEventStreamRelease(FSEventStreamRef
+ return 0;
+
+failed:
-+ error("Unable to create FSEventStream.");
++ error(_("Unable to create FSEventStream."));
+
+ FREE_AND_NULL(state->backend_data);
return -1;
@@ compat/fsmonitor/fsm-listen-darwin.c: void FSEventStreamRelease(FSEventStreamRef
+ data->stream_scheduled = 1;
+
+ if (!FSEventStreamStart(data->stream)) {
-+ error("Failed to start the FSEventStream");
++ error(_("Failed to start the FSEventStream"));
+ goto force_error_stop_without_loop;
+ }
+ data->stream_started = 1;
18: 0896e72e2b = 18: 1f4b5209bf fsmonitor--daemon: implement handle_client callback
19: bc240a9e66 ! 19: 8cf62c9fc6 help: include fsmonitor--daemon feature flag in version info
@@ t/test-lib.sh: test_lazy_prereq SHA1 '
+# Does this platform support `git fsmonitor--daemon`
+#
+test_lazy_prereq FSMONITOR_DAEMON '
-+ git version --build-options | grep "feature:" | grep "fsmonitor--daemon"
++ git version --build-options >output &&
++ grep "feature: fsmonitor--daemon" output
+'
20: 2b563c240e ! 20: 1bd74a8159 t/helper/fsmonitor-client: create IPC client to talk to FSMonitor Daemon
@@ t/helper/test-fsmonitor-client.c (new)
+
+ ret = fsmonitor_ipc__send_query(token, &answer);
+ if (ret < 0)
-+ die(_("could not query fsmonitor--daemon"));
++ die("could not query fsmonitor--daemon");
+
+ write_in_full(1, answer.buf, answer.len);
+ strbuf_release(&answer);
@@ t/helper/test-fsmonitor-client.c (new)
+ const char *token = NULL;
+
+ const char * const fsmonitor_client_usage[] = {
-+ N_("test-helper fsmonitor-client query [<token>]"),
-+ N_("test-helper fsmonitor-client flush"),
++ "test-tool fsmonitor-client query [<token>]",
++ "test-tool fsmonitor-client flush",
+ NULL,
+ };
+
+ struct option options[] = {
-+ OPT_STRING(0, "token", &token, N_("token"),
-+ N_("command token to send to the server")),
++ OPT_STRING(0, "token", &token, "token",
++ "command token to send to the server"),
+ OPT_END()
+ };
+
-+ if (argc < 2)
-+ usage_with_options(fsmonitor_client_usage, options);
++ argc = parse_options(argc, argv, NULL, options, fsmonitor_client_usage, 0);
+
-+ if (argc == 2 && !strcmp(argv[1], "-h"))
++ if (argc != 1)
+ usage_with_options(fsmonitor_client_usage, options);
+
-+ subcmd = argv[1];
-+ argv--;
-+ argc++;
-+
-+ argc = parse_options(argc, argv, NULL, options, fsmonitor_client_usage, 0);
++ subcmd = argv[0];
+
+ setup_git_directory();
+
21: db8809da08 ! 21: 4a920d0b54 t7527: create test for fsmonitor--daemon
@@ t/t7527-builtin-fsmonitor.sh (new)
+fi
+
+stop_daemon_delete_repo () {
-+ r=$1
-+ git -C $r fsmonitor--daemon stop >/dev/null 2>/dev/null
++ r=$1 &&
++ test_might_fail git -C $r fsmonitor--daemon stop &&
+ rm -rf $1
-+ return 0
+}
+
+start_daemon () {
-+ case "$#" in
-+ 1) r="-C $1";;
-+ *) r="";
-+ esac
++ r= &&
++ tf= &&
++ t2= &&
++ tk= &&
++
++ while test "$#" -ne 0
++ do
++ case "$1" in
++ -C)
++ shift;
++ test "$#" -ne 0 || BUG "error: -C requires arg"
++ r="-C $1"
++ shift
++ ;;
++ -tf)
++ shift;
++ test "$#" -ne 0 || BUG "error: -tf requires arg"
++ tf="$1"
++ shift
++ ;;
++ -t2)
++ shift;
++ test "$#" -ne 0 || BUG "error: -t2 requires arg"
++ t2="$1"
++ shift
++ ;;
++ -tk)
++ shift;
++ test "$#" -ne 0 || BUG "error: -tk requires arg"
++ tk="$1"
++ shift
++ ;;
++ *)
++ BUG "error: unknown option: '$1'"
++ ;;
++ esac
++ done &&
+
-+ git $r fsmonitor--daemon start || return $?
-+ git $r fsmonitor--daemon status || return $?
-+
-+ return 0
++ (
++ if test -n "$tf"
++ then
++ GIT_TRACE_FSMONITOR="$tf"
++ export GIT_TRACE_FSMONITOR
++ fi &&
++
++ if test -n "$t2"
++ then
++ GIT_TRACE2_PERF="$t2"
++ export GIT_TRACE2_PERF
++ fi &&
++
++ if test -n "$tk"
++ then
++ GIT_TEST_FSMONITOR_TOKEN="$tk"
++ export GIT_TEST_FSMONITOR_TOKEN
++ fi &&
++
++ git $r fsmonitor--daemon start &&
++ git $r fsmonitor--daemon status
++ )
+}
+
+# Is a Trace2 data event present with the given catetory and key?
+# We do not care what the value is.
+#
+have_t2_data_event () {
-+ c=$1
-+ k=$2
++ c=$1 &&
++ k=$2 &&
+
+ grep -e '"event":"data".*"category":"'"$c"'".*"key":"'"$k"'"'
+}
@@ t/t7527-builtin-fsmonitor.sh (new)
+ test_when_finished "stop_daemon_delete_repo test_explicit" &&
+
+ git init test_explicit &&
-+ start_daemon test_explicit &&
++ start_daemon -C test_explicit &&
+
+ git -C test_explicit fsmonitor--daemon stop &&
+ test_must_fail git -C test_explicit fsmonitor--daemon status
@@ t/t7527-builtin-fsmonitor.sh (new)
+ # but this test case is only concerned with whether the daemon was
+ # implicitly started.)
+
-+ GIT_TRACE2_EVENT="$(pwd)/.git/trace" \
++ GIT_TRACE2_EVENT="$PWD/.git/trace" \
+ test-tool -C test_implicit fsmonitor-client query --token 0 >actual &&
+ nul_to_q <actual >actual.filtered &&
+ grep "builtin:" actual.filtered &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ git init test_implicit_1 &&
+
-+ start_daemon test_implicit_1 &&
++ start_daemon -C test_implicit_1 &&
+
+ # deleting the .git directory will implicitly stop the daemon.
+ rm -rf test_implicit_1/.git &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ git init test_implicit_2 &&
+
-+ start_daemon test_implicit_2 &&
++ start_daemon -C test_implicit_2 &&
+
+ # renaming the .git directory will implicitly stop the daemon.
+ mv test_implicit_2/.git test_implicit_2/.xxx &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ git init test_multiple &&
+
-+ start_daemon test_multiple &&
++ start_daemon -C test_multiple &&
+
+ test_must_fail git -C test_multiple fsmonitor--daemon start 2>actual &&
+ grep "fsmonitor--daemon is already running" actual &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+# This is here in case something else fails first.
+#
+redundant_stop_daemon () {
-+ git fsmonitor--daemon stop
-+ return 0
++ test_might_fail git fsmonitor--daemon stop
+}
+
+test_expect_success 'update-index implicitly starts daemon' '
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ test_must_fail git fsmonitor--daemon status &&
+
-+ GIT_TRACE2_EVENT="$(pwd)/.git/trace_implicit_1" \
++ GIT_TRACE2_EVENT="$PWD/.git/trace_implicit_1" \
+ git update-index --fsmonitor &&
+
+ git fsmonitor--daemon status &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ test_must_fail git fsmonitor--daemon status &&
+
-+ GIT_TRACE2_EVENT="$(pwd)/.git/trace_implicit_2" \
++ GIT_TRACE2_EVENT="$PWD/.git/trace_implicit_2" \
+ git status >actual &&
+
+ git fsmonitor--daemon status &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+'
+
+edit_files () {
-+ echo 1 >modified
-+ echo 2 >dir1/modified
-+ echo 3 >dir2/modified
++ echo 1 >modified &&
++ echo 2 >dir1/modified &&
++ echo 3 >dir2/modified &&
+ >dir1/untracked
+}
+
+delete_files () {
-+ rm -f delete
-+ rm -f dir1/delete
++ rm -f delete &&
++ rm -f dir1/delete &&
+ rm -f dir2/delete
+}
+
+create_files () {
-+ echo 1 >new
-+ echo 2 >dir1/new
++ echo 1 >new &&
++ echo 2 >dir1/new &&
+ echo 3 >dir2/new
+}
+
+rename_files () {
-+ mv rename renamed
-+ mv dir1/rename dir1/renamed
++ mv rename renamed &&
++ mv dir1/rename dir1/renamed &&
+ mv dir2/rename dir2/renamed
+}
+
+file_to_directory () {
-+ rm -f delete
-+ mkdir delete
++ rm -f delete &&
++ mkdir delete &&
+ echo 1 >delete/new
+}
+
+directory_to_file () {
-+ rm -rf dir1
++ rm -rf dir1 &&
+ echo 1 >dir1
+}
+
-+verify_status () {
-+ git status >actual &&
-+ GIT_INDEX_FILE=.git/fresh-index git read-tree master &&
-+ GIT_INDEX_FILE=.git/fresh-index git -c core.fsmonitor=false status >expect &&
-+ test_cmp expect actual &&
-+ echo HELLO AFTER &&
-+ cat .git/trace &&
-+ echo HELLO AFTER
-+}
-+
+# The next few test cases confirm that our fsmonitor daemon sees each type
+# of OS filesystem notification that we care about. At this layer we just
+# ensure we are getting the OS notifications and do not try to confirm what
@@ t/t7527-builtin-fsmonitor.sh (new)
+# daemon) because these commands might implicitly restart the daemon.
+
+clean_up_repo_and_stop_daemon () {
-+ git reset --hard HEAD
-+ git clean -fd
-+ git fsmonitor--daemon stop
++ git reset --hard HEAD &&
++ git clean -fd &&
++ test_might_fail git fsmonitor--daemon stop &&
+ rm -f .git/trace
+}
+
+test_expect_success 'edit some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ edit_files &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/modified$" .git/trace &&
+ grep "^event: dir2/modified$" .git/trace &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'create some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ create_files &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/new$" .git/trace &&
+ grep "^event: dir2/new$" .git/trace &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'delete some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ delete_files &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/delete$" .git/trace &&
+ grep "^event: dir2/delete$" .git/trace &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'rename some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ rename_files &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/rename$" .git/trace &&
+ grep "^event: dir2/rename$" .git/trace &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'rename directory' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ mv dirtorename dirrenamed &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dirtorename/*$" .git/trace &&
+ grep "^event: dirrenamed/*$" .git/trace
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'file changes to directory' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ file_to_directory &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: delete$" .git/trace &&
+ grep "^event: delete/new$" .git/trace
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'directory changes to a file' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ directory_to_file &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1$" .git/trace
+'
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ git init test_flush &&
+
-+ (
-+ GIT_TEST_FSMONITOR_TOKEN=true &&
-+ export GIT_TEST_FSMONITOR_TOKEN &&
-+
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace_daemon" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon test_flush
-+ ) &&
++ start_daemon -C test_flush -tf "$PWD/.git/trace_daemon" -tk true &&
+
+ # The daemon should have an initial token with no events in _0 and
+ # then a few (probably platform-specific number of) events in _1.
@@ t/t7527-builtin-fsmonitor.sh (new)
+ test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000001:0" >actual_0 &&
+ nul_to_q <actual_0 >actual_q0 &&
+
-+ touch test_flush/file_1 &&
-+ touch test_flush/file_2 &&
++ >test_flush/file_1 &&
++ >test_flush/file_2 &&
+
+ test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000001:0" >actual_1 &&
+ nul_to_q <actual_1 >actual_q1 &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ grep "^builtin:test_00000002:0Q$" actual_q2 &&
+
-+ touch test_flush/file_3 &&
++ >test_flush/file_3 &&
+
+ test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000002:0" >actual_3 &&
+ nul_to_q <actual_3 >actual_q3 &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'worktree with .git file' '
+ git -C wt-base worktree add ../wt-secondary &&
+
-+ (
-+ GIT_TRACE2_PERF="$(pwd)/trace2_wt_secondary" &&
-+ export GIT_TRACE2_PERF &&
-+
-+ GIT_TRACE_FSMONITOR="$(pwd)/trace_wt_secondary" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon wt-secondary
-+ ) &&
++ start_daemon -C wt-secondary \
++ -tf "$PWD/trace_wt_secondary" \
++ -t2 "$PWD/trace2_wt_secondary" &&
+
+ git -C wt-secondary fsmonitor--daemon stop &&
+ test_must_fail git -C wt-secondary fsmonitor--daemon status
22: 15bd5aaff3 = 22: c925a9a745 t/perf: avoid copying builtin fsmonitor files into test repo
23: 4cb97918d2 = 23: 5b3381c223 t/helper/test-chmtime: skip directories on Windows
24: a70748b464 ! 24: 803a540cc0 t/perf/p7519: speed up test on Windows
@@ t/perf/p7519-fsmonitor.sh: test_fsmonitor_suite() {
head -100000 | \
grep -v \" | \
- sed '\''s/\(.\)/\\\1/g'\'' | \
-+ egrep -v " ." | \
++ grep -v " ." | \
xargs test-tool chmtime -300 &&
git status
'
25: b0c9c9c7a4 ! 25: d5ca2df31c t/perf/p7519: add fsmonitor--daemon test cases
@@ Commit message
Signed-off-by: Junio C Hamano <gitster@pobox.com>
## t/perf/p7519-fsmonitor.sh ##
+@@ t/perf/p7519-fsmonitor.sh: test_expect_success "one time repo setup" '
+ fi
+ '
+
+-setup_for_fsmonitor () {
++setup_for_fsmonitor_hook () {
+ # set INTEGRATION_SCRIPT depending on the environment
+ if test -n "$INTEGRATION_PATH"
+ then
@@ t/perf/p7519-fsmonitor.sh: test_perf_w_drop_caches () {
}
@@ t/perf/p7519-fsmonitor.sh: test_perf_w_drop_caches () {
+ if test -n "$USE_FSMONITOR_DAEMON"
+ then
+ DESC="builtin fsmonitor--daemon"
-+ elif test -n "$INTEGRATION_SCRIPT"; then
++ elif test -n "$INTEGRATION_SCRIPT"
++ then
DESC="fsmonitor=$(basename $INTEGRATION_SCRIPT)"
else
DESC="fsmonitor=disabled"
+@@ t/perf/p7519-fsmonitor.sh: test_fsmonitor_suite () {
+ trace_start fsmonitor-watchman
+ if test -n "$GIT_PERF_7519_FSMONITOR"; then
+ for INTEGRATION_PATH in $GIT_PERF_7519_FSMONITOR; do
+- test_expect_success "setup for fsmonitor $INTEGRATION_PATH" 'setup_for_fsmonitor'
++ test_expect_success "setup for fsmonitor $INTEGRATION_PATH" 'setup_for_fsmonitor_hook'
+ test_fsmonitor_suite
+ done
+ else
+- test_expect_success "setup for fsmonitor" 'setup_for_fsmonitor'
++ test_expect_success "setup for fsmonitor hook" 'setup_for_fsmonitor_hook'
+ test_fsmonitor_suite
+ fi
+
@@ t/perf/p7519-fsmonitor.sh: test_expect_success "setup without fsmonitor" '
test_fsmonitor_suite
trace_stop
@@ t/perf/p7519-fsmonitor.sh: test_expect_success "setup without fsmonitor" '
+then
+ USE_FSMONITOR_DAEMON=t
+
-+ trace_start fsmonitor--daemon--server
-+ git fsmonitor--daemon start
++ test_expect_success "setup for builtin fsmonitor" '
++ trace_start fsmonitor--daemon--server &&
++ git fsmonitor--daemon start &&
+
-+ trace_start fsmonitor--daemon--client
++ trace_start fsmonitor--daemon--client &&
+
-+ git config core.fsmonitor true
-+ git update-index --fsmonitor
++ git config core.fsmonitor true &&
++ git update-index --fsmonitor
++ '
+
+ test_fsmonitor_suite
+
26: 64a5b74167 = 26: 42631259e8 fsmonitor--daemon: periodically truncate list of modified files
27: 5b06eb5d0e ! 27: f256c3cbe8 fsmonitor--daemon: use a cookie file to sync with file system
@@ builtin/fsmonitor--daemon.c: static int do_as_client__status(void)
+enum fsmonitor_cookie_item_result {
+ FCIR_ERROR = -1, /* could not create cookie file ? */
-+ FCIR_INIT = 0,
++ FCIR_INIT,
+ FCIR_SEEN,
+ FCIR_ABORT,
+};
+
+struct fsmonitor_cookie_item {
+ struct hashmap_entry entry;
-+ const char *name;
++ char *name;
+ enum fsmonitor_cookie_item_result result;
+};
+
@@ builtin/fsmonitor--daemon.c: static int do_as_client__status(void)
+ * that the listener thread has seen it.
+ */
+ fd = open(cookie_pathname.buf, O_WRONLY | O_CREAT | O_EXCL, 0600);
-+ if (fd >= 0) {
-+ close(fd);
-+ unlink(cookie_pathname.buf);
-+
-+ /*
-+ * Technically, this is an infinite wait (well, unless another
-+ * thread sends us an abort). I'd like to change this to
-+ * use `pthread_cond_timedwait()` and return an error/timeout
-+ * and let the caller do the trivial response thing, but we
-+ * don't have that routine in our thread-utils.
-+ *
-+ * After extensive beta testing I'm not really worried about
-+ * this. Also note that the above open() and unlink() calls
-+ * will cause at least two FS events on that path, so the odds
-+ * of getting stuck are pretty slim.
-+ */
-+ while (cookie->result == FCIR_INIT)
-+ pthread_cond_wait(&state->cookies_cond,
-+ &state->main_lock);
-+ } else {
++ if (fd < 0) {
+ error_errno(_("could not create fsmonitor cookie '%s'"),
+ cookie->name);
+
+ cookie->result = FCIR_ERROR;
++ goto done;
+ }
+
++ /*
++ * Technically, close() and unlink() can fail, but we don't
++ * care here. We only created the file to trigger a watch
++ * event from the FS to know that when we're up to date.
++ */
++ close(fd);
++ unlink(cookie_pathname.buf);
++
++ /*
++ * Technically, this is an infinite wait (well, unless another
++ * thread sends us an abort). I'd like to change this to
++ * use `pthread_cond_timedwait()` and return an error/timeout
++ * and let the caller do the trivial response thing, but we
++ * don't have that routine in our thread-utils.
++ *
++ * After extensive beta testing I'm not really worried about
++ * this. Also note that the above open() and unlink() calls
++ * will cause at least two FS events on that path, so the odds
++ * of getting stuck are pretty slim.
++ */
++ while (cookie->result == FCIR_INIT)
++ pthread_cond_wait(&state->cookies_cond,
++ &state->main_lock);
++
++done:
+ hashmap_remove(&state->cookies, &cookie->entry, NULL);
+
+ result = cookie->result;
+
-+ free((char*)cookie->name);
++ free(cookie->name);
+ free(cookie);
+ strbuf_release(&cookie_pathname);
+
28: 1fd5439de0 = 28: 08af8296f9 fsmonitor: force update index after large responses
29: 6fc1430285 ! 29: e6cf84dc8e t7527: test status with untracked-cache and fsmonitor--daemon
@@ t/t7527-builtin-fsmonitor.sh: test_expect_success 'cleanup worktrees' '
+}
+
+matrix_try () {
-+ uc=$1
-+ fsm=$2
-+ fn=$3
++ uc=$1 &&
++ fsm=$2 &&
++ fn=$3 &&
+
+ test_expect_success "Matrix[uc:$uc][fsm:$fsm] $fn" '
+ matrix_clean_up_repo &&
30: b915b95cc2 < -: ---------- update-index: convert fsmonitor warnings to adviseJeff Hostetler (29):
fsmonitor: enhance existing comments, clarify trivial response
handling
fsmonitor-ipc: create client routines for git-fsmonitor--daemon
fsmonitor: config settings are repository-specific
fsmonitor: use IPC to query the builtin FSMonitor daemon
fsmonitor: document builtin fsmonitor
fsmonitor--daemon: add a built-in fsmonitor daemon
fsmonitor--daemon: implement 'stop' and 'status' commands
compat/fsmonitor/fsm-listen-win32: stub in backend for Windows
compat/fsmonitor/fsm-listen-darwin: stub in backend for Darwin
fsmonitor--daemon: implement 'run' command
fsmonitor--daemon: implement 'start' command
fsmonitor--daemon: add pathname classification
fsmonitor--daemon: define token-ids
fsmonitor--daemon: create token-based changed path cache
compat/fsmonitor/fsm-listen-win32: implement FSMonitor backend on
Windows
compat/fsmonitor/fsm-listen-darwin: add MacOS header files for FSEvent
compat/fsmonitor/fsm-listen-darwin: implement FSEvent listener on
MacOS
fsmonitor--daemon: implement handle_client callback
help: include fsmonitor--daemon feature flag in version info
t/helper/fsmonitor-client: create IPC client to talk to FSMonitor
Daemon
t7527: create test for fsmonitor--daemon
t/perf: avoid copying builtin fsmonitor files into test repo
t/helper/test-chmtime: skip directories on Windows
t/perf/p7519: speed up test on Windows
t/perf/p7519: add fsmonitor--daemon test cases
fsmonitor--daemon: periodically truncate list of modified files
fsmonitor--daemon: use a cookie file to sync with file system
fsmonitor: force update index after large responses
t7527: test status with untracked-cache and fsmonitor--daemon.gitignore | 1 + Documentation/config/core.txt | 60 +- Documentation/git-fsmonitor--daemon.txt | 75 ++ Documentation/git-update-index.txt | 8 +- Makefile | 17 + builtin.h | 1 + builtin/fsmonitor--daemon.c | 1480 +++++++++++++++++++++++ builtin/update-index.c | 7 +- cache.h | 1 - compat/fsmonitor/fsm-darwin-gcc.h | 92 ++ compat/fsmonitor/fsm-listen-darwin.c | 427 +++++++ compat/fsmonitor/fsm-listen-win32.c | 586 +++++++++ compat/fsmonitor/fsm-listen.h | 49 + config.c | 14 - config.h | 1 - config.mak.uname | 20 + contrib/buildsystems/CMakeLists.txt | 10 + environment.c | 1 - fsmonitor--daemon.h | 166 +++ fsmonitor-ipc.c | 171 +++ fsmonitor-ipc.h | 48 + fsmonitor-settings.c | 114 ++ fsmonitor-settings.h | 21 + fsmonitor.c | 216 +++- fsmonitor.h | 15 +- git.c | 1 + help.c | 4 + repo-settings.c | 1 + repository.h | 3 + t/README | 4 +- t/helper/test-chmtime.c | 15 + t/helper/test-fsmonitor-client.c | 116 ++ t/helper/test-tool.c | 1 + t/helper/test-tool.h | 1 + t/perf/p7519-fsmonitor.sh | 68 +- t/perf/perf-lib.sh | 2 +- t/t7527-builtin-fsmonitor.sh | 594 +++++++++ t/test-lib.sh | 7 + 38 files changed, 4312 insertions(+), 106 deletions(-) create mode 100644 Documentation/git-fsmonitor--daemon.txt create mode 100644 builtin/fsmonitor--daemon.c create mode 100644 compat/fsmonitor/fsm-darwin-gcc.h create mode 100644 compat/fsmonitor/fsm-listen-darwin.c create mode 100644 compat/fsmonitor/fsm-listen-win32.c create mode 100644 compat/fsmonitor/fsm-listen.h create mode 100644 fsmonitor--daemon.h create mode 100644 fsmonitor-ipc.c create mode 100644 fsmonitor-ipc.h create mode 100644 fsmonitor-settings.c create mode 100644 fsmonitor-settings.h create mode 100644 t/helper/test-fsmonitor-client.c create mode 100755 t/t7527-builtin-fsmonitor.sh
base-commit: 715d08a9e51251ad8290b181b6ac3b9e1f9719d7 Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1041%2Fjeffhostetler%2Fbuiltin-fsmonitor-part2-v7 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1041/jeffhostetler/builtin-fsmonitor-part2-v7 Pull-Request: https://github.com/gitgitgadget/git/pull/1041
Range-diff vs v6:
1: 10a34082fcc = 1: e98373f997f fsmonitor: enhance existing comments, clarify trivial response handling
2: e1c946af2c5 ! 2: ab68b944173 fsmonitor-ipc: create client routines for git-fsmonitor--daemon
@@ fsmonitor-ipc.c (new)
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
+ &connection);
+ if (state != IPC_STATE__LISTENING) {
-+ die("fsmonitor--daemon is not running");
++ die(_("fsmonitor--daemon is not running"));
+ return -1;
+ }
+
@@ fsmonitor-ipc.c (new)
+ ipc_client_close_connection(connection);
+
+ if (ret == -1) {
-+ die("could not send '%s' command to fsmonitor--daemon", c);
++ die(_("could not send '%s' command to fsmonitor--daemon"), c);
+ return -1;
+ }
+
3: ae622a517cf ! 3: e04c7301f24 fsmonitor: config settings are repository-specific
@@ fsmonitor-settings.c (new)
+ return;
+
+ CALLOC_ARRAY(s, 1);
++ s->mode = FSMONITOR_MODE_DISABLED;
+
+ r->settings.fsmonitor = s;
+
-+ fsm_settings__set_disabled(r);
-+
+ /*
+ * Overload the existing "core.fsmonitor" config setting (which
+ * has historically been either unset or a hook pathname) to
4: 55974867da5 = 4: ea02ba25d8f fsmonitor: use IPC to query the builtin FSMonitor daemon
5: ce42d5bbaf6 = 5: 6ab7db9cb76 fsmonitor: document builtin fsmonitor
6: 9ce938c69b5 = 6: 0ce8ae3f2cf fsmonitor--daemon: add a built-in fsmonitor daemon
7: 3bd7e6a051e = 7: 4624ce2fa47 fsmonitor--daemon: implement 'stop' and 'status' commands
8: 92d3e54da7f = 8: a29fe7266a4 compat/fsmonitor/fsm-listen-win32: stub in backend for Windows
9: f1219221270 = 9: 2f8a42fdb93 compat/fsmonitor/fsm-listen-darwin: stub in backend for Darwin
10: a3f94627cf6 ! 10: f07800690ee fsmonitor--daemon: implement 'run' command
@@ builtin/fsmonitor--daemon.c: static int do_as_client__status(void)
+ * common error case.
+ */
+ if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
-+ die("fsmonitor--daemon is already running '%s'",
++ die(_("fsmonitor--daemon is already running '%s'"),
+ the_repository->worktree);
+
+ if (fsmonitor__announce_startup) {
11: 8de40b0fe8b ! 11: a6a39a3306d fsmonitor--daemon: implement 'start' command
@@ builtin/fsmonitor--daemon.c: static int try_to_run_foreground_daemon(void)
+ * immediately exited).
+ */
+ if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
-+ die("fsmonitor--daemon is already running '%s'",
++ die(_("fsmonitor--daemon is already running '%s'"),
+ the_repository->worktree);
+
+ if (fsmonitor__announce_startup) {
@@ builtin/fsmonitor--daemon.c: static int try_to_run_foreground_daemon(void)
+ default:
+ case SBGR_ERROR:
+ case SBGR_CB_ERROR:
-+ return error("daemon failed to start");
++ return error(_("daemon failed to start"));
+
+ case SBGR_TIMEOUT:
-+ return error("daemon not online yet");
++ return error(_("daemon not online yet"));
+
+ case SBGR_DIED:
-+ return error("daemon terminated");
++ return error(_("daemon terminated"));
+ }
+}
+
12: e5d419b1ea0 = 12: d62e338d008 fsmonitor--daemon: add pathname classification
13: c2f3668a866 = 13: 53e06b4ae5d fsmonitor--daemon: define token-ids
14: bd492d13fb1 = 14: 39f43fabe02 fsmonitor--daemon: create token-based changed path cache
15: 6b5b3d08227 ! 15: 239558e34ff compat/fsmonitor/fsm-listen-win32: implement FSMonitor backend on Windows
@@ compat/fsmonitor/fsm-listen-win32.c
+ if (len > 0)
+ goto normalize;
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
-+ error("[GLE %ld] could not convert path to UTF-8: '%.*ls'",
++ error(_("[GLE %ld] could not convert path to UTF-8: '%.*ls'"),
+ GetLastError(),
+ (int)(info->FileNameLength / sizeof(WCHAR)),
+ info->FileName);
@@ compat/fsmonitor/fsm-listen-win32.c
+ if (watch->is_active)
+ return 0;
+
-+ error("ReadDirectoryChangedW failed on '%s' [GLE %ld]",
++ error(_("ReadDirectoryChangedW failed on '%s' [GLE %ld]"),
+ watch->path.buf, GetLastError());
+ return -1;
+}
@@ compat/fsmonitor/fsm-listen-win32.c
+ * sure it is worth it.
+ */
+
-+ error("GetOverlappedResult failed on '%s' [GLE %ld]",
++ error(_("GetOverlappedResult failed on '%s' [GLE %ld]"),
+ watch->path.buf, gle);
+ return -1;
+}
16: cdef9730b3f ! 16: 14b775e9d8b compat/fsmonitor/fsm-listen-darwin: add MacOS header files for FSEvent
@@ Commit message
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
- ## compat/fsmonitor/fsm-listen-darwin.c ##
+ ## compat/fsmonitor/fsm-darwin-gcc.h (new) ##
@@
++#ifndef FSM_DARWIN_GCC_H
++#define FSM_DARWIN_GCC_H
++
+#ifndef __clang__
+/*
+ * It is possible to #include CoreFoundation/CoreFoundation.h when compiling
@@ compat/fsmonitor/fsm-listen-darwin.c
+void FSEventStreamStop(FSEventStreamRef stream);
+void FSEventStreamInvalidate(FSEventStreamRef stream);
+void FSEventStreamRelease(FSEventStreamRef stream);
++
++#endif /* !clang */
++#endif /* FSM_DARWIN_GCC_H */
+
+ ## compat/fsmonitor/fsm-listen-darwin.c ##
+@@
++#ifndef __clang__
++#include "fsm-darwin-gcc.h"
+#else
-+/*
-+ * Let Apple's headers declare `isalnum()` first, before
-+ * Git's headers override it via a constant
-+ */
-+#include <string.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
++
++#ifndef AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER
++/*
++ * This enum value was added in 10.13 to:
++ *
++ * /Applications/Xcode.app/Contents/Developer/Platforms/ \
++ * MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/ \
++ * Library/Frameworks/CoreServices.framework/Frameworks/ \
++ * FSEvents.framework/Versions/Current/Headers/FSEvents.h
++ *
++ * If we're compiling against an older SDK, this symbol won't be
++ * present. Silently define it here so that we don't have to ifdef
++ * the logging or masking below. This should be harmless since older
++ * versions of macOS won't ever emit this FS event anyway.
++ */
++#define kFSEventStreamEventFlagItemCloned 0x00400000
++#endif
+#endif
+
#include "cache.h"
17: aabfebd3a41 ! 17: 55bd7aee06c compat/fsmonitor/fsm-listen-darwin: implement FSEvent listener on MacOS
@@ Commit message
Signed-off-by: Junio C Hamano <gitster@pobox.com>
## compat/fsmonitor/fsm-listen-darwin.c ##
-@@ compat/fsmonitor/fsm-listen-darwin.c: void FSEventStreamRelease(FSEventStreamRef stream);
+@@
#include "cache.h"
#include "fsmonitor.h"
#include "fsm-listen.h"
@@ compat/fsmonitor/fsm-listen-darwin.c: void FSEventStreamRelease(FSEventStreamRef
+ return 0;
+
+failed:
-+ error("Unable to create FSEventStream.");
++ error(_("Unable to create FSEventStream."));
+
+ FREE_AND_NULL(state->backend_data);
return -1;
@@ compat/fsmonitor/fsm-listen-darwin.c: void FSEventStreamRelease(FSEventStreamRef
+ data->stream_scheduled = 1;
+
+ if (!FSEventStreamStart(data->stream)) {
-+ error("Failed to start the FSEventStream");
++ error(_("Failed to start the FSEventStream"));
+ goto force_error_stop_without_loop;
+ }
+ data->stream_started = 1;
18: 0896e72e2b8 = 18: 1f4b5209bf6 fsmonitor--daemon: implement handle_client callback
19: bc240a9e665 ! 19: 8cf62c9fc6f help: include fsmonitor--daemon feature flag in version info
@@ t/test-lib.sh: test_lazy_prereq SHA1 '
+# Does this platform support `git fsmonitor--daemon`
+#
+test_lazy_prereq FSMONITOR_DAEMON '
-+ git version --build-options | grep "feature:" | grep "fsmonitor--daemon"
++ git version --build-options >output &&
++ grep "feature: fsmonitor--daemon" output
+'
20: 2b563c240eb ! 20: 1bd74a81593 t/helper/fsmonitor-client: create IPC client to talk to FSMonitor Daemon
@@ t/helper/test-fsmonitor-client.c (new)
+
+ ret = fsmonitor_ipc__send_query(token, &answer);
+ if (ret < 0)
-+ die(_("could not query fsmonitor--daemon"));
++ die("could not query fsmonitor--daemon");
+
+ write_in_full(1, answer.buf, answer.len);
+ strbuf_release(&answer);
@@ t/helper/test-fsmonitor-client.c (new)
+ const char *token = NULL;
+
+ const char * const fsmonitor_client_usage[] = {
-+ N_("test-helper fsmonitor-client query [<token>]"),
-+ N_("test-helper fsmonitor-client flush"),
++ "test-tool fsmonitor-client query [<token>]",
++ "test-tool fsmonitor-client flush",
+ NULL,
+ };
+
+ struct option options[] = {
-+ OPT_STRING(0, "token", &token, N_("token"),
-+ N_("command token to send to the server")),
++ OPT_STRING(0, "token", &token, "token",
++ "command token to send to the server"),
+ OPT_END()
+ };
+
-+ if (argc < 2)
-+ usage_with_options(fsmonitor_client_usage, options);
++ argc = parse_options(argc, argv, NULL, options, fsmonitor_client_usage, 0);
+
-+ if (argc == 2 && !strcmp(argv[1], "-h"))
++ if (argc != 1)
+ usage_with_options(fsmonitor_client_usage, options);
+
-+ subcmd = argv[1];
-+ argv--;
-+ argc++;
-+
-+ argc = parse_options(argc, argv, NULL, options, fsmonitor_client_usage, 0);
++ subcmd = argv[0];
+
+ setup_git_directory();
+
21: db8809da089 ! 21: 4a920d0b54a t7527: create test for fsmonitor--daemon
@@ t/t7527-builtin-fsmonitor.sh (new)
+fi
+
+stop_daemon_delete_repo () {
-+ r=$1
-+ git -C $r fsmonitor--daemon stop >/dev/null 2>/dev/null
++ r=$1 &&
++ test_might_fail git -C $r fsmonitor--daemon stop &&
+ rm -rf $1
-+ return 0
+}
+
+start_daemon () {
-+ case "$#" in
-+ 1) r="-C $1";;
-+ *) r="";
-+ esac
++ r= &&
++ tf= &&
++ t2= &&
++ tk= &&
++
++ while test "$#" -ne 0
++ do
++ case "$1" in
++ -C)
++ shift;
++ test "$#" -ne 0 || BUG "error: -C requires arg"
++ r="-C $1"
++ shift
++ ;;
++ -tf)
++ shift;
++ test "$#" -ne 0 || BUG "error: -tf requires arg"
++ tf="$1"
++ shift
++ ;;
++ -t2)
++ shift;
++ test "$#" -ne 0 || BUG "error: -t2 requires arg"
++ t2="$1"
++ shift
++ ;;
++ -tk)
++ shift;
++ test "$#" -ne 0 || BUG "error: -tk requires arg"
++ tk="$1"
++ shift
++ ;;
++ *)
++ BUG "error: unknown option: '$1'"
++ ;;
++ esac
++ done &&
+
-+ git $r fsmonitor--daemon start || return $?
-+ git $r fsmonitor--daemon status || return $?
-+
-+ return 0
++ (
++ if test -n "$tf"
++ then
++ GIT_TRACE_FSMONITOR="$tf"
++ export GIT_TRACE_FSMONITOR
++ fi &&
++
++ if test -n "$t2"
++ then
++ GIT_TRACE2_PERF="$t2"
++ export GIT_TRACE2_PERF
++ fi &&
++
++ if test -n "$tk"
++ then
++ GIT_TEST_FSMONITOR_TOKEN="$tk"
++ export GIT_TEST_FSMONITOR_TOKEN
++ fi &&
++
++ git $r fsmonitor--daemon start &&
++ git $r fsmonitor--daemon status
++ )
+}
+
+# Is a Trace2 data event present with the given catetory and key?
+# We do not care what the value is.
+#
+have_t2_data_event () {
-+ c=$1
-+ k=$2
++ c=$1 &&
++ k=$2 &&
+
+ grep -e '"event":"data".*"category":"'"$c"'".*"key":"'"$k"'"'
+}
@@ t/t7527-builtin-fsmonitor.sh (new)
+ test_when_finished "stop_daemon_delete_repo test_explicit" &&
+
+ git init test_explicit &&
-+ start_daemon test_explicit &&
++ start_daemon -C test_explicit &&
+
+ git -C test_explicit fsmonitor--daemon stop &&
+ test_must_fail git -C test_explicit fsmonitor--daemon status
@@ t/t7527-builtin-fsmonitor.sh (new)
+ # but this test case is only concerned with whether the daemon was
+ # implicitly started.)
+
-+ GIT_TRACE2_EVENT="$(pwd)/.git/trace" \
++ GIT_TRACE2_EVENT="$PWD/.git/trace" \
+ test-tool -C test_implicit fsmonitor-client query --token 0 >actual &&
+ nul_to_q <actual >actual.filtered &&
+ grep "builtin:" actual.filtered &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ git init test_implicit_1 &&
+
-+ start_daemon test_implicit_1 &&
++ start_daemon -C test_implicit_1 &&
+
+ # deleting the .git directory will implicitly stop the daemon.
+ rm -rf test_implicit_1/.git &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ git init test_implicit_2 &&
+
-+ start_daemon test_implicit_2 &&
++ start_daemon -C test_implicit_2 &&
+
+ # renaming the .git directory will implicitly stop the daemon.
+ mv test_implicit_2/.git test_implicit_2/.xxx &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ git init test_multiple &&
+
-+ start_daemon test_multiple &&
++ start_daemon -C test_multiple &&
+
+ test_must_fail git -C test_multiple fsmonitor--daemon start 2>actual &&
+ grep "fsmonitor--daemon is already running" actual &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+# This is here in case something else fails first.
+#
+redundant_stop_daemon () {
-+ git fsmonitor--daemon stop
-+ return 0
++ test_might_fail git fsmonitor--daemon stop
+}
+
+test_expect_success 'update-index implicitly starts daemon' '
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ test_must_fail git fsmonitor--daemon status &&
+
-+ GIT_TRACE2_EVENT="$(pwd)/.git/trace_implicit_1" \
++ GIT_TRACE2_EVENT="$PWD/.git/trace_implicit_1" \
+ git update-index --fsmonitor &&
+
+ git fsmonitor--daemon status &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ test_must_fail git fsmonitor--daemon status &&
+
-+ GIT_TRACE2_EVENT="$(pwd)/.git/trace_implicit_2" \
++ GIT_TRACE2_EVENT="$PWD/.git/trace_implicit_2" \
+ git status >actual &&
+
+ git fsmonitor--daemon status &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+'
+
+edit_files () {
-+ echo 1 >modified
-+ echo 2 >dir1/modified
-+ echo 3 >dir2/modified
++ echo 1 >modified &&
++ echo 2 >dir1/modified &&
++ echo 3 >dir2/modified &&
+ >dir1/untracked
+}
+
+delete_files () {
-+ rm -f delete
-+ rm -f dir1/delete
++ rm -f delete &&
++ rm -f dir1/delete &&
+ rm -f dir2/delete
+}
+
+create_files () {
-+ echo 1 >new
-+ echo 2 >dir1/new
++ echo 1 >new &&
++ echo 2 >dir1/new &&
+ echo 3 >dir2/new
+}
+
+rename_files () {
-+ mv rename renamed
-+ mv dir1/rename dir1/renamed
++ mv rename renamed &&
++ mv dir1/rename dir1/renamed &&
+ mv dir2/rename dir2/renamed
+}
+
+file_to_directory () {
-+ rm -f delete
-+ mkdir delete
++ rm -f delete &&
++ mkdir delete &&
+ echo 1 >delete/new
+}
+
+directory_to_file () {
-+ rm -rf dir1
++ rm -rf dir1 &&
+ echo 1 >dir1
+}
+
-+verify_status () {
-+ git status >actual &&
-+ GIT_INDEX_FILE=.git/fresh-index git read-tree master &&
-+ GIT_INDEX_FILE=.git/fresh-index git -c core.fsmonitor=false status >expect &&
-+ test_cmp expect actual &&
-+ echo HELLO AFTER &&
-+ cat .git/trace &&
-+ echo HELLO AFTER
-+}
-+
+# The next few test cases confirm that our fsmonitor daemon sees each type
+# of OS filesystem notification that we care about. At this layer we just
+# ensure we are getting the OS notifications and do not try to confirm what
@@ t/t7527-builtin-fsmonitor.sh (new)
+# daemon) because these commands might implicitly restart the daemon.
+
+clean_up_repo_and_stop_daemon () {
-+ git reset --hard HEAD
-+ git clean -fd
-+ git fsmonitor--daemon stop
++ git reset --hard HEAD &&
++ git clean -fd &&
++ test_might_fail git fsmonitor--daemon stop &&
+ rm -f .git/trace
+}
+
+test_expect_success 'edit some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ edit_files &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/modified$" .git/trace &&
+ grep "^event: dir2/modified$" .git/trace &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'create some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ create_files &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/new$" .git/trace &&
+ grep "^event: dir2/new$" .git/trace &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'delete some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ delete_files &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/delete$" .git/trace &&
+ grep "^event: dir2/delete$" .git/trace &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'rename some files' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ rename_files &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1/rename$" .git/trace &&
+ grep "^event: dir2/rename$" .git/trace &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'rename directory' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ mv dirtorename dirrenamed &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dirtorename/*$" .git/trace &&
+ grep "^event: dirrenamed/*$" .git/trace
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'file changes to directory' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ file_to_directory &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: delete$" .git/trace &&
+ grep "^event: delete/new$" .git/trace
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'directory changes to a file' '
+ test_when_finished clean_up_repo_and_stop_daemon &&
+
-+ (
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon
-+ ) &&
++ start_daemon -tf "$PWD/.git/trace" &&
+
+ directory_to_file &&
+
-+ test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 &&
++ test-tool fsmonitor-client query --token 0 &&
+
+ grep "^event: dir1$" .git/trace
+'
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ git init test_flush &&
+
-+ (
-+ GIT_TEST_FSMONITOR_TOKEN=true &&
-+ export GIT_TEST_FSMONITOR_TOKEN &&
-+
-+ GIT_TRACE_FSMONITOR="$(pwd)/.git/trace_daemon" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon test_flush
-+ ) &&
++ start_daemon -C test_flush -tf "$PWD/.git/trace_daemon" -tk true &&
+
+ # The daemon should have an initial token with no events in _0 and
+ # then a few (probably platform-specific number of) events in _1.
@@ t/t7527-builtin-fsmonitor.sh (new)
+ test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000001:0" >actual_0 &&
+ nul_to_q <actual_0 >actual_q0 &&
+
-+ touch test_flush/file_1 &&
-+ touch test_flush/file_2 &&
++ >test_flush/file_1 &&
++ >test_flush/file_2 &&
+
+ test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000001:0" >actual_1 &&
+ nul_to_q <actual_1 >actual_q1 &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+
+ grep "^builtin:test_00000002:0Q$" actual_q2 &&
+
-+ touch test_flush/file_3 &&
++ >test_flush/file_3 &&
+
+ test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000002:0" >actual_3 &&
+ nul_to_q <actual_3 >actual_q3 &&
@@ t/t7527-builtin-fsmonitor.sh (new)
+test_expect_success 'worktree with .git file' '
+ git -C wt-base worktree add ../wt-secondary &&
+
-+ (
-+ GIT_TRACE2_PERF="$(pwd)/trace2_wt_secondary" &&
-+ export GIT_TRACE2_PERF &&
-+
-+ GIT_TRACE_FSMONITOR="$(pwd)/trace_wt_secondary" &&
-+ export GIT_TRACE_FSMONITOR &&
-+
-+ start_daemon wt-secondary
-+ ) &&
++ start_daemon -C wt-secondary \
++ -tf "$PWD/trace_wt_secondary" \
++ -t2 "$PWD/trace2_wt_secondary" &&
+
+ git -C wt-secondary fsmonitor--daemon stop &&
+ test_must_fail git -C wt-secondary fsmonitor--daemon status
22: 15bd5aaff36 = 22: c925a9a7459 t/perf: avoid copying builtin fsmonitor files into test repo
23: 4cb97918d20 = 23: 5b3381c223e t/helper/test-chmtime: skip directories on Windows
24: a70748b4640 ! 24: 803a540cc00 t/perf/p7519: speed up test on Windows
@@ t/perf/p7519-fsmonitor.sh: test_fsmonitor_suite() {
head -100000 | \
grep -v \" | \
- sed '\''s/\(.\)/\\\1/g'\'' | \
-+ egrep -v " ." | \
++ grep -v " ." | \
xargs test-tool chmtime -300 &&
git status
'
25: b0c9c9c7a40 ! 25: d5ca2df31c8 t/perf/p7519: add fsmonitor--daemon test cases
@@ Commit message
Signed-off-by: Junio C Hamano <gitster@pobox.com>
## t/perf/p7519-fsmonitor.sh ##
+@@ t/perf/p7519-fsmonitor.sh: test_expect_success "one time repo setup" '
+ fi
+ '
+
+-setup_for_fsmonitor () {
++setup_for_fsmonitor_hook () {
+ # set INTEGRATION_SCRIPT depending on the environment
+ if test -n "$INTEGRATION_PATH"
+ then
@@ t/perf/p7519-fsmonitor.sh: test_perf_w_drop_caches () {
}
@@ t/perf/p7519-fsmonitor.sh: test_perf_w_drop_caches () {
+ if test -n "$USE_FSMONITOR_DAEMON"
+ then
+ DESC="builtin fsmonitor--daemon"
-+ elif test -n "$INTEGRATION_SCRIPT"; then
++ elif test -n "$INTEGRATION_SCRIPT"
++ then
DESC="fsmonitor=$(basename $INTEGRATION_SCRIPT)"
else
DESC="fsmonitor=disabled"
+@@ t/perf/p7519-fsmonitor.sh: test_fsmonitor_suite () {
+ trace_start fsmonitor-watchman
+ if test -n "$GIT_PERF_7519_FSMONITOR"; then
+ for INTEGRATION_PATH in $GIT_PERF_7519_FSMONITOR; do
+- test_expect_success "setup for fsmonitor $INTEGRATION_PATH" 'setup_for_fsmonitor'
++ test_expect_success "setup for fsmonitor $INTEGRATION_PATH" 'setup_for_fsmonitor_hook'
+ test_fsmonitor_suite
+ done
+ else
+- test_expect_success "setup for fsmonitor" 'setup_for_fsmonitor'
++ test_expect_success "setup for fsmonitor hook" 'setup_for_fsmonitor_hook'
+ test_fsmonitor_suite
+ fi
+
@@ t/perf/p7519-fsmonitor.sh: test_expect_success "setup without fsmonitor" '
test_fsmonitor_suite
trace_stop
@@ t/perf/p7519-fsmonitor.sh: test_expect_success "setup without fsmonitor" '
+then
+ USE_FSMONITOR_DAEMON=t
+
-+ trace_start fsmonitor--daemon--server
-+ git fsmonitor--daemon start
++ test_expect_success "setup for builtin fsmonitor" '
++ trace_start fsmonitor--daemon--server &&
++ git fsmonitor--daemon start &&
+
-+ trace_start fsmonitor--daemon--client
++ trace_start fsmonitor--daemon--client &&
+
-+ git config core.fsmonitor true
-+ git update-index --fsmonitor
++ git config core.fsmonitor true &&
++ git update-index --fsmonitor
++ '
+
+ test_fsmonitor_suite
+
26: 64a5b741670 = 26: 42631259e89 fsmonitor--daemon: periodically truncate list of modified files
27: 5b06eb5d0e6 ! 27: f256c3cbe8b fsmonitor--daemon: use a cookie file to sync with file system
@@ builtin/fsmonitor--daemon.c: static int do_as_client__status(void)
+enum fsmonitor_cookie_item_result {
+ FCIR_ERROR = -1, /* could not create cookie file ? */
-+ FCIR_INIT = 0,
++ FCIR_INIT,
+ FCIR_SEEN,
+ FCIR_ABORT,
+};
+
+struct fsmonitor_cookie_item {
+ struct hashmap_entry entry;
-+ const char *name;
++ char *name;
+ enum fsmonitor_cookie_item_result result;
+};
+
@@ builtin/fsmonitor--daemon.c: static int do_as_client__status(void)
+ * that the listener thread has seen it.
+ */
+ fd = open(cookie_pathname.buf, O_WRONLY | O_CREAT | O_EXCL, 0600);
-+ if (fd >= 0) {
-+ close(fd);
-+ unlink(cookie_pathname.buf);
-+
-+ /*
-+ * Technically, this is an infinite wait (well, unless another
-+ * thread sends us an abort). I'd like to change this to
-+ * use `pthread_cond_timedwait()` and return an error/timeout
-+ * and let the caller do the trivial response thing, but we
-+ * don't have that routine in our thread-utils.
-+ *
-+ * After extensive beta testing I'm not really worried about
-+ * this. Also note that the above open() and unlink() calls
-+ * will cause at least two FS events on that path, so the odds
-+ * of getting stuck are pretty slim.
-+ */
-+ while (cookie->result == FCIR_INIT)
-+ pthread_cond_wait(&state->cookies_cond,
-+ &state->main_lock);
-+ } else {
++ if (fd < 0) {
+ error_errno(_("could not create fsmonitor cookie '%s'"),
+ cookie->name);
+
+ cookie->result = FCIR_ERROR;
++ goto done;
+ }
+
++ /*
++ * Technically, close() and unlink() can fail, but we don't
++ * care here. We only created the file to trigger a watch
++ * event from the FS to know that when we're up to date.
++ */
++ close(fd);
++ unlink(cookie_pathname.buf);
++
++ /*
++ * Technically, this is an infinite wait (well, unless another
++ * thread sends us an abort). I'd like to change this to
++ * use `pthread_cond_timedwait()` and return an error/timeout
++ * and let the caller do the trivial response thing, but we
++ * don't have that routine in our thread-utils.
++ *
++ * After extensive beta testing I'm not really worried about
++ * this. Also note that the above open() and unlink() calls
++ * will cause at least two FS events on that path, so the odds
++ * of getting stuck are pretty slim.
++ */
++ while (cookie->result == FCIR_INIT)
++ pthread_cond_wait(&state->cookies_cond,
++ &state->main_lock);
++
++done:
+ hashmap_remove(&state->cookies, &cookie->entry, NULL);
+
+ result = cookie->result;
+
-+ free((char*)cookie->name);
++ free(cookie->name);
+ free(cookie);
+ strbuf_release(&cookie_pathname);
+
28: 1fd5439de03 = 28: 08af8296f96 fsmonitor: force update index after large responses
29: 6fc1430285f ! 29: e6cf84dc8eb t7527: test status with untracked-cache and fsmonitor--daemon
@@ t/t7527-builtin-fsmonitor.sh: test_expect_success 'cleanup worktrees' '
+}
+
+matrix_try () {
-+ uc=$1
-+ fsm=$2
-+ fn=$3
++ uc=$1 &&
++ fsm=$2 &&
++ fn=$3 &&
+
+ test_expect_success "Matrix[uc:$uc][fsm:$fsm] $fn" '
+ matrix_clean_up_repo &&
30: b915b95cc2f < -: ----------- update-index: convert fsmonitor warnings to advise-- gitgitgadget