]> git.ipfire.org Git - thirdparty/git.git/commitdiff
fsmonitor-ipc: create client routines for git-fsmonitor--daemon
authorJeff Hostetler <jeffhost@microsoft.com>
Fri, 25 Mar 2022 18:02:45 +0000 (18:02 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 25 Mar 2022 23:04:15 +0000 (16:04 -0700)
Create fsmonitor_ipc__*() client routines to spawn the built-in file
system monitor daemon and send it an IPC request using the `Simple
IPC` API.

Stub in empty fsmonitor_ipc__*() functions for unsupported platforms.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Makefile
fsmonitor-ipc.c [new file with mode: 0644]
fsmonitor-ipc.h [new file with mode: 0644]

index 6f0b4b775fece6acd20348e318a8cff3e254bcb2..a19d850e716aa7fee7becd34668a6de556044342 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -907,6 +907,7 @@ LIB_OBJS += fetch-pack.o
 LIB_OBJS += fmt-merge-msg.o
 LIB_OBJS += fsck.o
 LIB_OBJS += fsmonitor.o
+LIB_OBJS += fsmonitor-ipc.o
 LIB_OBJS += gettext.o
 LIB_OBJS += gpg-interface.o
 LIB_OBJS += graph.o
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
new file mode 100644 (file)
index 0000000..789e739
--- /dev/null
@@ -0,0 +1,171 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "simple-ipc.h"
+#include "fsmonitor-ipc.h"
+#include "run-command.h"
+#include "strbuf.h"
+#include "trace2.h"
+
+#ifndef HAVE_FSMONITOR_DAEMON_BACKEND
+
+/*
+ * A trivial implementation of the fsmonitor_ipc__ API for unsupported
+ * platforms.
+ */
+
+int fsmonitor_ipc__is_supported(void)
+{
+       return 0;
+}
+
+const char *fsmonitor_ipc__get_path(void)
+{
+       return NULL;
+}
+
+enum ipc_active_state fsmonitor_ipc__get_state(void)
+{
+       return IPC_STATE__OTHER_ERROR;
+}
+
+int fsmonitor_ipc__send_query(const char *since_token,
+                             struct strbuf *answer)
+{
+       return -1;
+}
+
+int fsmonitor_ipc__send_command(const char *command,
+                               struct strbuf *answer)
+{
+       return -1;
+}
+
+#else
+
+int fsmonitor_ipc__is_supported(void)
+{
+       return 1;
+}
+
+GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
+
+enum ipc_active_state fsmonitor_ipc__get_state(void)
+{
+       return ipc_get_active_state(fsmonitor_ipc__get_path());
+}
+
+static int spawn_daemon(void)
+{
+       const char *args[] = { "fsmonitor--daemon", "start", NULL };
+
+       return run_command_v_opt_tr2(args, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD,
+                                   "fsmonitor");
+}
+
+int fsmonitor_ipc__send_query(const char *since_token,
+                             struct strbuf *answer)
+{
+       int ret = -1;
+       int tried_to_spawn = 0;
+       enum ipc_active_state state = IPC_STATE__OTHER_ERROR;
+       struct ipc_client_connection *connection = NULL;
+       struct ipc_client_connect_options options
+               = IPC_CLIENT_CONNECT_OPTIONS_INIT;
+       const char *tok = since_token ? since_token : "";
+       size_t tok_len = since_token ? strlen(since_token) : 0;
+
+       options.wait_if_busy = 1;
+       options.wait_if_not_found = 0;
+
+       trace2_region_enter("fsm_client", "query", NULL);
+       trace2_data_string("fsm_client", NULL, "query/command", tok);
+
+try_again:
+       state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
+                                      &connection);
+
+       switch (state) {
+       case IPC_STATE__LISTENING:
+               ret = ipc_client_send_command_to_connection(
+                       connection, tok, tok_len, answer);
+               ipc_client_close_connection(connection);
+
+               trace2_data_intmax("fsm_client", NULL,
+                                  "query/response-length", answer->len);
+               goto done;
+
+       case IPC_STATE__NOT_LISTENING:
+       case IPC_STATE__PATH_NOT_FOUND:
+               if (tried_to_spawn)
+                       goto done;
+
+               tried_to_spawn++;
+               if (spawn_daemon())
+                       goto done;
+
+               /*
+                * Try again, but this time give the daemon a chance to
+                * actually create the pipe/socket.
+                *
+                * Granted, the daemon just started so it can't possibly have
+                * any FS cached yet, so we'll always get a trivial answer.
+                * BUT the answer should include a new token that can serve
+                * as the basis for subsequent requests.
+                */
+               options.wait_if_not_found = 1;
+               goto try_again;
+
+       case IPC_STATE__INVALID_PATH:
+               ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
+                           fsmonitor_ipc__get_path());
+               goto done;
+
+       case IPC_STATE__OTHER_ERROR:
+       default:
+               ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
+                           fsmonitor_ipc__get_path());
+               goto done;
+       }
+
+done:
+       trace2_region_leave("fsm_client", "query", NULL);
+
+       return ret;
+}
+
+int fsmonitor_ipc__send_command(const char *command,
+                               struct strbuf *answer)
+{
+       struct ipc_client_connection *connection = NULL;
+       struct ipc_client_connect_options options
+               = IPC_CLIENT_CONNECT_OPTIONS_INIT;
+       int ret;
+       enum ipc_active_state state;
+       const char *c = command ? command : "";
+       size_t c_len = command ? strlen(command) : 0;
+
+       strbuf_reset(answer);
+
+       options.wait_if_busy = 1;
+       options.wait_if_not_found = 0;
+
+       state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
+                                      &connection);
+       if (state != IPC_STATE__LISTENING) {
+               die(_("fsmonitor--daemon is not running"));
+               return -1;
+       }
+
+       ret = ipc_client_send_command_to_connection(connection, c, c_len,
+                                                   answer);
+       ipc_client_close_connection(connection);
+
+       if (ret == -1) {
+               die(_("could not send '%s' command to fsmonitor--daemon"), c);
+               return -1;
+       }
+
+       return 0;
+}
+
+#endif
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
new file mode 100644 (file)
index 0000000..b6a7067
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef FSMONITOR_IPC_H
+#define FSMONITOR_IPC_H
+
+#include "simple-ipc.h"
+
+/*
+ * Returns true if built-in file system monitor daemon is defined
+ * for this platform.
+ */
+int fsmonitor_ipc__is_supported(void);
+
+/*
+ * Returns the pathname to the IPC named pipe or Unix domain socket
+ * where a `git-fsmonitor--daemon` process will listen.  This is a
+ * per-worktree value.
+ *
+ * Returns NULL if the daemon is not supported on this platform.
+ */
+const char *fsmonitor_ipc__get_path(void);
+
+/*
+ * Try to determine whether there is a `git-fsmonitor--daemon` process
+ * listening on the IPC pipe/socket.
+ */
+enum ipc_active_state fsmonitor_ipc__get_state(void);
+
+/*
+ * Connect to a `git-fsmonitor--daemon` process via simple-ipc
+ * and ask for the set of changed files since the given token.
+ *
+ * Spawn a daemon process in the background if necessary.
+ *
+ * Returns -1 on error; 0 on success.
+ */
+int fsmonitor_ipc__send_query(const char *since_token,
+                             struct strbuf *answer);
+
+/*
+ * Connect to a `git-fsmonitor--daemon` process via simple-ipc and
+ * send a command verb.  If no daemon is available, we DO NOT try to
+ * start one.
+ *
+ * Returns -1 on error; 0 on success.
+ */
+int fsmonitor_ipc__send_command(const char *command,
+                               struct strbuf *answer);
+
+#endif /* FSMONITOR_IPC_H */