Skip to content

Commit 7dec29d

Browse files
jeffhostetlerdscho
authored andcommitted
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 d9fa67f commit 7dec29d

File tree

3 files changed

+225
-0
lines changed

3 files changed

+225
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,7 @@ LIB_OBJS += fetch-pack.o
903903
LIB_OBJS += fmt-merge-msg.o
904904
LIB_OBJS += fsck.o
905905
LIB_OBJS += fsmonitor.o
906+
LIB_OBJS += fsmonitor-ipc.o
906907
LIB_OBJS += gettext.o
907908
LIB_OBJS += gpg-interface.o
908909
LIB_OBJS += graph.o

fsmonitor-ipc.c

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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+
case IPC_STATE__PATH_NOT_FOUND:
70+
if (tried_to_spawn)
71+
goto done;
72+
73+
tried_to_spawn++;
74+
if (spawn_daemon())
75+
goto done;
76+
77+
/*
78+
* Try again, but this time give the daemon a chance to
79+
* actually create the pipe/socket.
80+
*
81+
* Granted, the daemon just started so it can't possibly have
82+
* any FS cached yet, so we'll always get a trivial answer.
83+
* BUT the answer should include a new token that can serve
84+
* as the basis for subsequent requests.
85+
*/
86+
options.wait_if_not_found = 1;
87+
goto try_again;
88+
89+
case IPC_STATE__INVALID_PATH:
90+
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
91+
fsmonitor_ipc__get_path());
92+
goto done;
93+
94+
case IPC_STATE__OTHER_ERROR:
95+
default:
96+
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
97+
fsmonitor_ipc__get_path());
98+
goto done;
99+
}
100+
101+
done:
102+
trace2_region_leave("fsm_client", "query", NULL);
103+
104+
return ret;
105+
}
106+
107+
int fsmonitor_ipc__send_command(const char *command,
108+
struct strbuf *answer)
109+
{
110+
struct ipc_client_connection *connection = NULL;
111+
struct ipc_client_connect_options options
112+
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
113+
int ret;
114+
enum ipc_active_state state;
115+
const char *c = command ? command : "";
116+
size_t c_len = command ? strlen(command) : 0;
117+
118+
strbuf_reset(answer);
119+
120+
options.wait_if_busy = 1;
121+
options.wait_if_not_found = 0;
122+
123+
state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
124+
&connection);
125+
if (state != IPC_STATE__LISTENING) {
126+
die("fsmonitor--daemon is not running");
127+
return -1;
128+
}
129+
130+
ret = ipc_client_send_command_to_connection(connection, c, c_len,
131+
answer);
132+
ipc_client_close_connection(connection);
133+
134+
if (ret == -1) {
135+
die("could not send '%s' command to fsmonitor--daemon", c);
136+
return -1;
137+
}
138+
139+
return 0;
140+
}
141+
142+
#else
143+
144+
/*
145+
* A trivial implementation of the fsmonitor_ipc__ API for unsupported
146+
* platforms.
147+
*/
148+
149+
int fsmonitor_ipc__is_supported(void)
150+
{
151+
return 0;
152+
}
153+
154+
const char *fsmonitor_ipc__get_path(void)
155+
{
156+
return NULL;
157+
}
158+
159+
enum ipc_active_state fsmonitor_ipc__get_state(void)
160+
{
161+
return IPC_STATE__OTHER_ERROR;
162+
}
163+
164+
int fsmonitor_ipc__send_query(const char *since_token,
165+
struct strbuf *answer)
166+
{
167+
return -1;
168+
}
169+
170+
int fsmonitor_ipc__send_command(const char *command,
171+
struct strbuf *answer)
172+
{
173+
return -1;
174+
}
175+
176+
#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+
#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 */

0 commit comments

Comments
 (0)