fsmonitor-ipc: create client routines for git-fsmonitor--daemon
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>
Jeff Hostetler committed
Mar 25, 2022 at 18:02 UTC
d2bd862e7a4a791d88740cc81aad14cdcd90dd2c
3 files changed
+220
Makefile
+1
@@ -907,6 +907,7 @@ LIB_OBJS += fetch-pack.o
907
LIB_OBJS += fmt-merge-msg.o
908
LIB_OBJS += fsck.o
909
LIB_OBJS += fsmonitor.o
910
+LIB_OBJS += fsmonitor-ipc.o
911
LIB_OBJS += gettext.o
912
LIB_OBJS += gpg-interface.o
913
LIB_OBJS += graph.o
fsmonitor-ipc.c
new
+171
@@ -0,0 +1,171 @@
1
+#include "cache.h"
2
+#include "fsmonitor.h"
3
+#include "simple-ipc.h"
4
+#include "fsmonitor-ipc.h"
5
+#include "run-command.h"
6
+#include "strbuf.h"
7
+#include "trace2.h"
8
+
9
+#ifndef HAVE_FSMONITOR_DAEMON_BACKEND
10
+
11
+/*
12
+ * A trivial implementation of the fsmonitor_ipc__ API for unsupported
13
+ * platforms.
14
+ */
15
+
16
+int fsmonitor_ipc__is_supported(void)
17
+{
18
+ return 0;
19
+}
20
+
21
+const char *fsmonitor_ipc__get_path(void)
22
+{
23
+ return NULL;
24
+}
25
+
26
+enum ipc_active_state fsmonitor_ipc__get_state(void)
27
+{
28
+ return IPC_STATE__OTHER_ERROR;
29
+}
30
+
31
+int fsmonitor_ipc__send_query(const char *since_token,
32
+ struct strbuf *answer)
33
+{
34
+ return -1;
35
+}
36
+
37
+int fsmonitor_ipc__send_command(const char *command,
38
+ struct strbuf *answer)
39
+{
40
+ return -1;
41
+}
42
+
43
+#else
44
+
45
+int fsmonitor_ipc__is_supported(void)
46
+{
47
+ return 1;
48
+}
49
+
50
+GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
51
+
52
+enum ipc_active_state fsmonitor_ipc__get_state(void)
53
+{
54
+ return ipc_get_active_state(fsmonitor_ipc__get_path());
55
+}
56
+
57
+static int spawn_daemon(void)
58
+{
59
+ const char *args[] = { "fsmonitor--daemon", "start", NULL };
60
+
61
+ return run_command_v_opt_tr2(args, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD,
62
+ "fsmonitor");
63
+}
64
+
65
+int fsmonitor_ipc__send_query(const char *since_token,
66
+ struct strbuf *answer)
67
+{
68
+ int ret = -1;
69
+ int tried_to_spawn = 0;
70
+ enum ipc_active_state state = IPC_STATE__OTHER_ERROR;
71
+ struct ipc_client_connection *connection = NULL;
72
+ struct ipc_client_connect_options options
73
+ = IPC_CLIENT_CONNECT_OPTIONS_INIT;
74
+ const char *tok = since_token ? since_token : "";
75
+ size_t tok_len = since_token ? strlen(since_token) : 0;
76
+
77
+ options.wait_if_busy = 1;
78
+ options.wait_if_not_found = 0;
79
+
80
+ trace2_region_enter("fsm_client", "query", NULL);
81
+ trace2_data_string("fsm_client", NULL, "query/command", tok);
82
+
83
+try_again:
84
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
85
+ &connection);
86
+
87
+ switch (state) {
88
+ case IPC_STATE__LISTENING:
89
+ ret = ipc_client_send_command_to_connection(
90
+ connection, tok, tok_len, answer);
91
+ ipc_client_close_connection(connection);
92
+
93
+ trace2_data_intmax("fsm_client", NULL,
94
+ "query/response-length", answer->len);
95
+ goto done;
96
+
97
+ case IPC_STATE__NOT_LISTENING:
98
+ case IPC_STATE__PATH_NOT_FOUND:
99
+ if (tried_to_spawn)
100
+ goto done;
101
+
102
+ tried_to_spawn++;
103
+ if (spawn_daemon())
104
+ goto done;
105
+
106
+ /*
107
+ * Try again, but this time give the daemon a chance to
108
+ * actually create the pipe/socket.
109
+ *
110
+ * Granted, the daemon just started so it can't possibly have
111
+ * any FS cached yet, so we'll always get a trivial answer.
112
+ * BUT the answer should include a new token that can serve
113
+ * as the basis for subsequent requests.
114
+ */
115
+ options.wait_if_not_found = 1;
116
+ goto try_again;
117
+
118
+ case IPC_STATE__INVALID_PATH:
119
+ ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
120
+ fsmonitor_ipc__get_path());
121
+ goto done;
122
+
123
+ case IPC_STATE__OTHER_ERROR:
124
+ default:
125
+ ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
126
+ fsmonitor_ipc__get_path());
127
+ goto done;
128
+ }
129
+
130
+done:
131
+ trace2_region_leave("fsm_client", "query", NULL);
132
+
133
+ return ret;
134
+}
135
+
136
+int fsmonitor_ipc__send_command(const char *command,
137
+ struct strbuf *answer)
138
+{
139
+ struct ipc_client_connection *connection = NULL;
140
+ struct ipc_client_connect_options options
141
+ = IPC_CLIENT_CONNECT_OPTIONS_INIT;
142
+ int ret;
143
+ enum ipc_active_state state;
144
+ const char *c = command ? command : "";
145
+ size_t c_len = command ? strlen(command) : 0;
146
+
147
+ strbuf_reset(answer);
148
+
149
+ options.wait_if_busy = 1;
150
+ options.wait_if_not_found = 0;
151
+
152
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
153
+ &connection);
154
+ if (state != IPC_STATE__LISTENING) {
155
+ die(_("fsmonitor--daemon is not running"));
156
+ return -1;
157
+ }
158
+
159
+ ret = ipc_client_send_command_to_connection(connection, c, c_len,
160
+ answer);
161
+ ipc_client_close_connection(connection);
162
+
163
+ if (ret == -1) {
164
+ die(_("could not send '%s' command to fsmonitor--daemon"), c);
165
+ return -1;
166
+ }
167
+
168
+ return 0;
169
+}
170
+
171
+#endif
fsmonitor-ipc.h
new
+48
@@ -0,0 +1,48 @@
1
+#ifndef FSMONITOR_IPC_H
2
+#define FSMONITOR_IPC_H
3
+
4
+#include "simple-ipc.h"
5
+
6
+/*
7
+ * Returns true if built-in file system monitor daemon is defined
8
+ * for this platform.
9
+ */
10
+int fsmonitor_ipc__is_supported(void);
11
+
12
+/*
13
+ * Returns the pathname to the IPC named pipe or Unix domain socket
14
+ * where a `git-fsmonitor--daemon` process will listen. This is a
15
+ * per-worktree value.
16
+ *
17
+ * Returns NULL if the daemon is not supported on this platform.
18
+ */
19
+const char *fsmonitor_ipc__get_path(void);
20
+
21
+/*
22
+ * Try to determine whether there is a `git-fsmonitor--daemon` process
23
+ * listening on the IPC pipe/socket.
24
+ */
25
+enum ipc_active_state fsmonitor_ipc__get_state(void);
26
+
27
+/*
28
+ * Connect to a `git-fsmonitor--daemon` process via simple-ipc
29
+ * and ask for the set of changed files since the given token.
30
+ *
31
+ * Spawn a daemon process in the background if necessary.
32
+ *
33
+ * Returns -1 on error; 0 on success.
34
+ */
35
+int fsmonitor_ipc__send_query(const char *since_token,
36
+ struct strbuf *answer);
37
+
38
+/*
39
+ * Connect to a `git-fsmonitor--daemon` process via simple-ipc and
40
+ * send a command verb. If no daemon is available, we DO NOT try to
41
+ * start one.
42
+ *
43
+ * Returns -1 on error; 0 on success.
44
+ */
45
+int fsmonitor_ipc__send_command(const char *command,
46
+ struct strbuf *answer);
47
+
48
+#endif /* FSMONITOR_IPC_H */