fsmonitor--daemon: implement client command options

Implement command options `--stop`, `--is-running`, `--query`,
`--query-index`, and `--flush` to control and query the status of a
`fsmonitor--daemon` server process (and implicitly start a server
process if necessary).

Later commits will implement the actual server and monitor
the file system.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
This commit is contained in:
Jeff Hostetler
2020-12-16 11:02:46 -05:00
committed by Johannes Schindelin
parent ade72692a0
commit c8358a0be8

View File

@@ -7,18 +7,144 @@
#include "khash.h"
static const char * const builtin_fsmonitor__daemon_usage[] = {
N_("git fsmonitor--daemon --stop"),
N_("git fsmonitor--daemon --is-running"),
N_("git fsmonitor--daemon --query <token>"),
N_("git fsmonitor--daemon --query-index"),
N_("git fsmonitor--daemon --flush"),
NULL
};
#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
/*
* Acting as a CLIENT.
*
* Send an IPC query to a `git-fsmonitor--daemon` SERVER process and
* ask for the changes since the given token. This will implicitly
* start a daemon process if necessary. The daemon process will
* persist after we exit.
*
* This feature is primarily used by the test suite.
*/
static int do_as_client__query_token(const char *token)
{
struct strbuf answer = STRBUF_INIT;
int ret;
ret = fsmonitor_ipc__send_query(token, &answer);
if (ret < 0)
die(_("could not query fsmonitor--daemon"));
write_in_full(1, answer.buf, answer.len);
strbuf_release(&answer);
return 0;
}
/*
* Acting as a CLIENT.
*
* Read the `.git/index` to get the last token written to the FSMonitor index
* extension and use that to make a query.
*
* This feature is primarily used by the test suite.
*/
static int do_as_client__query_from_index(void)
{
struct index_state *istate = the_repository->index;
setup_git_directory();
if (do_read_index(istate, the_repository->index_file, 0) < 0)
die("unable to read index file");
if (!istate->fsmonitor_last_update)
die("index file does not have fsmonitor extension");
return do_as_client__query_token(istate->fsmonitor_last_update);
}
/*
* Acting as a CLIENT.
*
* Send a "quit" command to the `git-fsmonitor--daemon` (if running)
* and wait for it to shutdown.
*/
static int do_as_client__send_stop(void)
{
struct strbuf answer = STRBUF_INIT;
int ret;
ret = fsmonitor_ipc__send_command("quit", &answer);
/* The quit command does not return any response data. */
strbuf_release(&answer);
if (ret)
return ret;
trace2_region_enter("fsm_client", "polling-for-daemon-exit", NULL);
while (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
sleep_millisec(50);
trace2_region_leave("fsm_client", "polling-for-daemon-exit", NULL);
return 0;
}
/*
* Acting as a CLIENT.
*
* Send a "flush" command to the `git-fsmonitor--daemon` (if running)
* and tell it to flush its cache.
*
* This feature is primarily used by the test suite to simulate a loss of
* sync with the filesystem where we miss kernel events.
*/
static int do_as_client__send_flush(void)
{
struct strbuf answer = STRBUF_INIT;
int ret;
ret = fsmonitor_ipc__send_command("flush", &answer);
if (ret)
return ret;
write_in_full(1, answer.buf, answer.len);
strbuf_release(&answer);
return 0;
}
static int is_ipc_daemon_listening(void)
{
return fsmonitor_ipc__get_state() == IPC_STATE__LISTENING;
}
int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
{
enum daemon_mode {
UNDEFINED_MODE,
STOP,
IS_RUNNING,
QUERY,
QUERY_INDEX,
FLUSH,
} mode = UNDEFINED_MODE;
struct option options[] = {
OPT_CMDMODE(0, "stop", &mode, N_("stop the running daemon"),
STOP),
OPT_CMDMODE(0, "is-running", &mode,
N_("test whether the daemon is running"),
IS_RUNNING),
OPT_CMDMODE(0, "query", &mode,
N_("query the daemon (starting if necessary)"),
QUERY),
OPT_CMDMODE(0, "query-index", &mode,
N_("query the daemon (starting if necessary) using token from index"),
QUERY_INDEX),
OPT_CMDMODE(0, "flush", &mode, N_("flush cached filesystem events"),
FLUSH),
OPT_END()
};
@@ -31,6 +157,24 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
builtin_fsmonitor__daemon_usage, 0);
switch (mode) {
case STOP:
return !!do_as_client__send_stop();
case IS_RUNNING:
return !is_ipc_daemon_listening();
case QUERY:
if (argc != 1)
usage_with_options(builtin_fsmonitor__daemon_usage,
options);
return !!do_as_client__query_token(argv[0]);
case QUERY_INDEX:
return !!do_as_client__query_from_index();
case FLUSH:
return !!do_as_client__send_flush();
case UNDEFINED_MODE:
default:
die(_("Unhandled command mode %d"), mode);