Browse Source
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>maint
Jeff Hostetler
3 years ago
committed by
Junio C Hamano
3 changed files with 220 additions and 0 deletions
@ -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 |
@ -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 */ |
Loading…
Reference in new issue