Skip to content

Commit dfcd3e5

Browse files
committed
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 <[email protected]>
1 parent 86413bf commit dfcd3e5

File tree

3 files changed

+228
-0
lines changed

3 files changed

+228
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,7 @@ LIB_OBJS += fetch-pack.o
893893
LIB_OBJS += fmt-merge-msg.o
894894
LIB_OBJS += fsck.o
895895
LIB_OBJS += fsmonitor.o
896+
LIB_OBJS += fsmonitor-ipc.o
896897
LIB_OBJS += gettext.o
897898
LIB_OBJS += gpg-interface.o
898899
LIB_OBJS += graph.o

fsmonitor-ipc.c

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
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+
#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
10+
11+
int fsmonitor_ipc__is_supported(void)
12+
{
13+
return 1;
14+
}
15+
16+
GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
17+
18+
enum ipc_active_state fsmonitor_ipc__get_state(void)
19+
{
20+
return ipc_get_active_state(fsmonitor_ipc__get_path());
21+
}
22+
23+
static int spawn_daemon(void)
24+
{
25+
const char *args[] = { "fsmonitor--daemon", "start", NULL };
26+
27+
return run_command_v_opt_tr2(args, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD,
28+
"fsmonitor");
29+
}
30+
31+
int fsmonitor_ipc__send_query(const char *since_token,
32+
struct strbuf *answer)
33+
{
34+
int ret = -1;
35+
int tried_to_spawn = 0;
36+
enum ipc_active_state state = IPC_STATE__OTHER_ERROR;
37+
struct ipc_client_connection *connection = NULL;
38+
struct ipc_client_connect_options options
39+
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
40+
const char *tok = since_token ? since_token : "";
41+
size_t tok_len = since_token ? strlen(since_token) : 0;
42+
43+
options.wait_if_busy = 1;
44+
options.wait_if_not_found = 0;
45+
46+
trace2_region_enter("fsm_client", "query", NULL);
47+
trace2_data_string("fsm_client", NULL, "query/command", tok);
48+
49+
try_again:
50+
state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
51+
&connection);
52+
53+
switch (state) {
54+
case IPC_STATE__LISTENING:
55+
ret = ipc_client_send_command_to_connection(
56+
connection, tok, tok_len, answer);
57+
ipc_client_close_connection(connection);
58+
59+
trace2_data_intmax("fsm_client", NULL,
60+
"query/response-length", answer->len);
61+
62+
if (fsmonitor_is_trivial_response(answer))
63+
trace2_data_intmax("fsm_client", NULL,
64+
"query/trivial-response", 1);
65+
66+
goto done;
67+
68+
case IPC_STATE__NOT_LISTENING:
69+
ret = error(_("fsmonitor_ipc__send_query: daemon not available"));
70+
goto done;
71+
72+
case IPC_STATE__PATH_NOT_FOUND:
73+
if (tried_to_spawn)
74+
goto done;
75+
76+
tried_to_spawn++;
77+
if (spawn_daemon())
78+
goto done;
79+
80+
/*
81+
* Try again, but this time give the daemon a chance to
82+
* actually create the pipe/socket.
83+
*
84+
* Granted, the daemon just started so it can't possibly have
85+
* any FS cached yet, so we'll always get a trivial answer.
86+
* BUT the answer should include a new token that can serve
87+
* as the basis for subsequent requests.
88+
*/
89+
options.wait_if_not_found = 1;
90+
goto try_again;
91+
92+
case IPC_STATE__INVALID_PATH:
93+
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
94+
fsmonitor_ipc__get_path());
95+
goto done;
96+
97+
case IPC_STATE__OTHER_ERROR:
98+
default:
99+
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
100+
fsmonitor_ipc__get_path());
101+
goto done;
102+
}
103+
104+
done:
105+
trace2_region_leave("fsm_client", "query", NULL);
106+
107+
return ret;
108+
}
109+
110+
int fsmonitor_ipc__send_command(const char *command,
111+
struct strbuf *answer)
112+
{
113+
struct ipc_client_connection *connection = NULL;
114+
struct ipc_client_connect_options options
115+
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
116+
int ret;
117+
enum ipc_active_state state;
118+
const char *c = command ? command : "";
119+
size_t c_len = command ? strlen(command) : 0;
120+
121+
strbuf_reset(answer);
122+
123+
options.wait_if_busy = 1;
124+
options.wait_if_not_found = 0;
125+
126+
state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
127+
&connection);
128+
if (state != IPC_STATE__LISTENING) {
129+
die("fsmonitor--daemon is not running");
130+
return -1;
131+
}
132+
133+
ret = ipc_client_send_command_to_connection(connection, c, c_len,
134+
answer);
135+
ipc_client_close_connection(connection);
136+
137+
if (ret == -1) {
138+
die("could not send '%s' command to fsmonitor--daemon", c);
139+
return -1;
140+
}
141+
142+
return 0;
143+
}
144+
145+
#else
146+
147+
/*
148+
* A trivial implementation of the fsmonitor_ipc__ API for unsupported
149+
* platforms.
150+
*/
151+
152+
int fsmonitor_ipc__is_supported(void)
153+
{
154+
return 0;
155+
}
156+
157+
const char *fsmonitor_ipc__get_path(void)
158+
{
159+
return NULL;
160+
}
161+
162+
enum ipc_active_state fsmonitor_ipc__get_state(void)
163+
{
164+
return IPC_STATE__OTHER_ERROR;
165+
}
166+
167+
int fsmonitor_ipc__send_query(const char *since_token,
168+
struct strbuf *answer)
169+
{
170+
return -1;
171+
}
172+
173+
int fsmonitor_ipc__send_command(const char *command,
174+
struct strbuf *answer)
175+
{
176+
return -1;
177+
}
178+
179+
#endif

fsmonitor-ipc.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#ifndef FSMONITOR_IPC_H
2+
#define FSMONITOR_IPC_H
3+
4+
/*
5+
* Returns true if built-in file system monitor daemon is defined
6+
* for this platform.
7+
*/
8+
int fsmonitor_ipc__is_supported(void);
9+
10+
/*
11+
* Returns the pathname to the IPC named pipe or Unix domain socket
12+
* where a `git-fsmonitor--daemon` process will listen. This is a
13+
* per-worktree value.
14+
*
15+
* Returns NULL if the daemon is not supported on this platform.
16+
*/
17+
const char *fsmonitor_ipc__get_path(void);
18+
19+
/*
20+
* Try to determine whether there is a `git-fsmonitor--daemon` process
21+
* listening on the IPC pipe/socket.
22+
*/
23+
enum ipc_active_state fsmonitor_ipc__get_state(void);
24+
25+
/*
26+
* Connect to a `git-fsmonitor--daemon` process via simple-ipc
27+
* and ask for the set of changed files since the given token.
28+
*
29+
* This DOES NOT use the hook interface.
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 */

0 commit comments

Comments
 (0)